From c6bbda50dc1f0bc15dc3c569da6694a5851af3f8 Mon Sep 17 00:00:00 2001 From: Keith Bostic Date: Thu, 31 Mar 1994 23:04:07 -0800 Subject: [PATCH] POSIX 1003.2b/D9 symbolic links SCCS-vsn: usr.sbin/chown/chgrp.1 8.2 SCCS-vsn: usr.sbin/chown/chown.8 8.2 SCCS-vsn: usr.sbin/chown/chown.c 8.2 --- usr/src/usr.sbin/chown/chgrp.1 | 82 +++++++----- usr/src/usr.sbin/chown/chown.8 | 56 ++++++-- usr/src/usr.sbin/chown/chown.c | 235 +++++++++++++++++++-------------- 3 files changed, 228 insertions(+), 145 deletions(-) diff --git a/usr/src/usr.sbin/chown/chgrp.1 b/usr/src/usr.sbin/chown/chgrp.1 index e2166bd0e2..99fe57f71c 100644 --- a/usr/src/usr.sbin/chown/chgrp.1 +++ b/usr/src/usr.sbin/chown/chgrp.1 @@ -1,4 +1,4 @@ -.\" Copyright (c) 1983, 1990, 1993 +.\" Copyright (c) 1983, 1990, 1993, 1994 .\" The Regents of the University of California. All rights reserved. .\" .\" This code is derived from software contributed to Berkeley by @@ -6,7 +6,7 @@ .\" .\" %sccs.include.redist.man% .\" -.\" @(#)chgrp.1 8.1 (Berkeley) %G% +.\" @(#)chgrp.1 8.2 (Berkeley) %G% .\" .Dd .Dt CHGRP 1 @@ -16,7 +16,11 @@ .Nd change group .Sh SYNOPSIS .Nm chgrp -.Op Fl HRfh +.Oo +.Fl R +.Op Fl H | Fl L | Fl P +.Oc +.Op Fl f .Ar group .Ar files ... .Sh DESCRIPTION @@ -29,50 +33,65 @@ ID specified by the group operand. Options: .Bl -tag -width Ds .It Fl H -When encountering a symbolic link on the command line, follow it. All other -symbolic links encountered in the traversal are not followed. +If the +.Fl R +option is specified, symbolic links on the command line are followed. +(Symbolic links encountered in the tree traversal are not followed.) +.It Fl L +If the +.Fl R +option is specified, all symbolic links are followed. +.It Fl P +If the +.Fl R +option is specified, no symbolic links are followed. .It Fl R -Recursively change file group IDs. -For each -.Ar file -operand that names a directory, chgrp changes the -group of the directory and all files in the file -hierarchy below it. -When symbolic links are encountered, their group is changed, -but they are not traversed. +Change the group ID for the file hierarchies rooted +in the files instead of just the files themselves. .It Fl f The force option ignores errors, except for usage errors and doesn't query about strange modes (unless the user does not have proper permissions). -.It Fl h -When encountering a symbolic link anywhere in the traversal, follow it. .El .Pp -The group of a symbolic link is immutable, so unless the -.Fl h -or +Symbolic links don't have groups, so unless the .Fl H -flag is set, +or +.Fl L +option is set, .Nm chgrp on a symbolic link is a no-op. +The +.Fl H , +.Fl L +and +.Fl P +options are ignored unless the +.Fl R +option is specified. +In addition, these options override each other and the +command's actions are determined by the last one specified. .Pp -Operands: -.Bl -tag -width group -.It Ar group The .Ar group -can be either a group name from the group database, or a numeric -group ID. -.It Ar file -A pathname of a file whose group ID is to be modified. -.El +operand can be either a group name from the group database, +or a numeric group ID. +If a group name is also a numeric group ID, the operand is used as a +group name. .Pp The user invoking -must belong -to the specified group and be the owner of the file, or be the super-user. +.Nm chgrp +must belong to the specified group and be the owner of the file, +or be the super-user. .Pp The .Nm chgrp utility exits 0 on success, and >0 if an error occurs. +.Sh COMPATIBILITY +Previous versions of the +.Nm chgrp +utility changed the group of symbolic links specified on the command +line. +In this system, symbolic links do not have groups. .Sh FILES .Bl -tag -width /etc/group -compact .It Pa /etc/group @@ -80,13 +99,12 @@ Group ID file .El .Sh SEE ALSO .Xr chown 2 , -.Xr chown 8 , .Xr group 5 , .Xr passwd 5 , .Xr fts 3 , -.Xr symlink 7 +.Xr symlink 7 , +.Xr chown 8 .Sh STANDARDS The .Nm chgrp utility is expected to be POSIX 1003.2 compatible. -This manual page is derived from the POSIX 1003.2 manual page. diff --git a/usr/src/usr.sbin/chown/chown.8 b/usr/src/usr.sbin/chown/chown.8 index b70cf381f8..7cf292a07c 100644 --- a/usr/src/usr.sbin/chown/chown.8 +++ b/usr/src/usr.sbin/chown/chown.8 @@ -1,9 +1,9 @@ -.\" Copyright (c) 1990, 1991, 1993 +.\" Copyright (c) 1990, 1991, 1993, 1994 .\" The Regents of the University of California. All rights reserved. .\" .\" %sccs.include.redist.man% .\" -.\" @(#)chown.8 8.1 (Berkeley) %G% +.\" @(#)chown.8 8.2 (Berkeley) %G% .\" .Dd .Dt CHOWN 8 @@ -13,11 +13,19 @@ .Nd change file owner and group .Sh SYNOPSIS .Nm chown -.Op Fl HRfh +.Oo +.Fl R +.Op Fl H | Fl L | Fl P +.Oc +.Op Fl f .Ar owner Op Ar :group .Ar file ... .Nm chown -.Op Fl HRfh +.Oo +.Fl R +.Op Fl H | Fl L | Fl P +.Oc +.Op Fl f .Ar :group .Ar file ... .Sh DESCRIPTION @@ -27,25 +35,43 @@ sets the user ID and/or the group ID of the specified files. The options are as follows: .Bl -tag -width Ds .It Fl H -When encountering a symbolic link on the command line, follow it. All other -symbolic links encountered in the traversal are not followed. +If the +.Fl R +option is specified, symbolic links on the command line are followed. +(Symbolic links encountered in the tree traversal are not followed.) +.It Fl L +If the +.Fl R +option is specified, all symbolic links are followed. +.It Fl P +If the +.Fl R +option is specified, no symbolic links are followed. .It Fl R Change the user ID and/or the group ID for the file hierarchies rooted in the files instead of just the files themselves. .It Fl f Don't report any failure to change file owner or group, nor modify the exit status to reflect such failures. -.It Fl h -When encountering a symbolic link anywhere in the traversal, follow it. .El .Pp -The ownership of a symbolic link is immutable, so unless the -.Fl h +Symbolic links don't have owners, so unless the +.Fl H or -.Fl H -flag is set, +.Fl L +option is set, .Nm chown on a symbolic link is a no-op. +The +.Fl H , +.Fl L +and +.Fl P +options are ignored unless the +.Fl R +option is specified. +In addition, these options override each other and the +command's actions are determined by the last one specified. .Pp The .Ar owner @@ -79,6 +105,12 @@ Previous versions of the utility used the dot (``.'') character to distinguish the group name. This has been changed to be a colon (``:'') character so that user and group names may contain the dot character. +.Pp +Previous versions of the +.Nm chown +utility changed the owner of symbolic links specified on the command +line. +In this system, symbolic links do not have owners. .Sh SEE ALSO .Xr chgrp 1 , .Xr find 1 , diff --git a/usr/src/usr.sbin/chown/chown.c b/usr/src/usr.sbin/chown/chown.c index ad7d0e5a79..330d46b102 100644 --- a/usr/src/usr.sbin/chown/chown.c +++ b/usr/src/usr.sbin/chown/chown.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1988, 1993 + * Copyright (c) 1988, 1993, 1994 * The Regents of the University of California. All rights reserved. * * %sccs.include.redist.c% @@ -7,63 +7,84 @@ #ifndef lint static char copyright[] = -"@(#) Copyright (c) 1988, 1993\n\ +"@(#) Copyright (c) 1988, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)chown.c 8.1 (Berkeley) %G%"; +static char sccsid[] = "@(#)chown.c 8.2 (Berkeley) %G%"; #endif /* not lint */ #include #include -#include + +#include #include +#include +#include #include -#include #include -#include +#include #include -#include #include #include +#include + +void a_gid __P((char *)); +void a_uid __P((char *)); +void chownerr __P((char *)); +u_long id __P((char *, char *)); +void usage __P((void)); -int ischown, uid, gid, fflag, rflag, retval; +uid_t uid; +gid_t gid; +int Rflag, ischown, fflag; char *gname, *myname; +int main(argc, argv) int argc; - char **argv; + char *argv[]; { extern int optind; - register FTS *ftsp; - register FTSENT *p; - register char *cp; - int ch; - int fts_options; - int hflag, Hflag; + FTS *ftsp; + FTSENT *p; + int Hflag, Lflag, Pflag, ch, fts_options, hflag, rval; + char *cp; myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv; ischown = myname[2] == 'o'; - hflag = Hflag = 0; - fts_options = FTS_NOSTAT | FTS_PHYSICAL; - while ((ch = getopt(argc, argv, "HRfh")) != EOF) - switch((char)ch) { + Hflag = Lflag = Pflag = hflag = 0; + while ((ch = getopt(argc, argv, "HLPRfh")) != EOF) + switch (ch) { + case 'H': + Hflag = 1; + Lflag = Pflag = 0; + break; + case 'L': + Lflag = 1; + Hflag = Pflag = 0; + break; + case 'P': + Pflag = 1; + Hflag = Lflag = 0; + break; case 'R': - rflag = 1; + Rflag = 1; break; case 'f': fflag = 1; break; case 'h': + /* + * In System V (and probably POSIX.2) the -h option + * causes chown/chgrp to change the owner/group of + * the symbolic link. 4.4BSD's symbolic links don't + * have owners/groups, so it's an undocumented noop. + * Do syntax checking, though. + */ hflag = 1; - fts_options &= ~FTS_PHYSICAL; - fts_options |= FTS_LOGICAL; - break; - case 'H': - Hflag = 1; - fts_options |= FTS_COMFOLLOW; break; case '?': default: @@ -75,137 +96,149 @@ main(argc, argv) if (argc < 2) usage(); + fts_options = FTS_NOSTAT | FTS_PHYSICAL; + if (Rflag) { + if (hflag) + errx(1, + "the -R and -h options may not be specified together."); + if (Hflag) + fts_options |= FTS_COMFOLLOW; + if (Lflag) { + fts_options &= ~FTS_PHYSICAL; + fts_options |= FTS_LOGICAL; + } + } + uid = gid = -1; if (ischown) { #ifdef SUPPORT_DOT - if (cp = index(*argv, '.')) { + if ((cp = strchr(*argv, '.')) != NULL) { *cp++ = '\0'; a_gid(cp); } else #endif - if (cp = index(*argv, ':')) { + if ((cp = strchr(*argv, ':')) != NULL) { *cp++ = '\0'; a_gid(cp); } a_uid(*argv); - } - else + } else a_gid(*argv); - if (!(ftsp = fts_open(++argv, fts_options, 0))) { - (void)fprintf(stderr, - "%s: %s.\n", myname, strerror(errno)); - exit(1); - } - while (p = fts_read(ftsp)) { - if (p->fts_info == FTS_D) { - if (rflag) + if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) + err(1, NULL); + + for (rval = 0; (p = fts_read(ftsp)) != NULL;) { + switch (p->fts_info) { + case FTS_D: + if (Rflag) /* Change it at FTS_DP. */ continue; - else - fts_set(ftsp, p, FTS_SKIP); - } - if (p->fts_info == FTS_SL && - !(hflag || (Hflag && p->fts_level == FTS_ROOTLEVEL))) + fts_set(ftsp, p, FTS_SKIP); + break; + case FTS_DC: + warnx("tree cycle: %s", p->fts_path); + rval = 1; + continue; + case FTS_ERR: + errno = p->fts_errno; + warn("%s", p->fts_path); + rval = 1; continue; - if (p->fts_info == FTS_ERR) { - error(p->fts_path); + case FTS_SL: + case FTS_SLNONE: + /* + * The only symlinks that end up here are ones that + * don't point to anything and ones that we found + * doing a physical walk. + */ continue; } - if (chown(p->fts_accpath, uid, gid) && !fflag) + if (chown(p->fts_accpath, uid, gid) && !fflag) { chownerr(p->fts_path); + rval = 1; + } } - exit(retval); + exit(rval); } +void a_gid(s) - register char *s; + char *s; { struct group *gr; - if (!*s) { - gid = -1; /* argument was "uid." */ + if (*s == '\0') /* Argument was "uid[:.]". */ return; - } gname = s; - if (gr = getgrnam(s)) - gid = gr->gr_gid; - else { - for (; *s && isdigit(*s); ++s); - if (!*s) - gid = atoi(gname); - else { - (void)fprintf(stderr, "%s: unknown group id: %s\n", - myname, gname); - exit(1); - } - } + gid = ((gr = getgrnam(s)) == NULL) ? id(s, "group") : gr->gr_gid; } +void a_uid(s) - register char *s; + char *s; { struct passwd *pw; - char *uname; - if (!*s) { - uid = -1; /* argument was ".gid" */ + if (*s == '\0') /* Argument was "[:.]gid". */ return; - } - if (pw = getpwnam(s)) - uid = pw->pw_uid; - else { - for (uname = s; *s && isdigit(*s); ++s); - if (!*s) - uid = atoi(uname); - else { - (void)fprintf(stderr, - "chown: unknown user id: %s\n", uname); - exit(1); - } - } + uid = ((pw = getpwnam(s)) == NULL) ? id(s, "user") : pw->pw_uid; } +u_long +id(name, type) + char *name, *type; +{ + u_long val; + char *ep; + + /* + * XXX + * We know that uid_t's and gid_t's are unsigned longs. + */ + errno = 0; + val = strtoul(name, &ep, 10); + if (errno) + err(1, "%s", name); + if (*ep != '\0') + errx(1, "%s: illegal %s name", name, type); + return (val); +} + +void chownerr(file) char *file; { static int euid = -1, ngroups = -1; + int groups[NGROUPS]; - /* check for chown without being root */ - if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) { + /* Check for chown without being root. */ + if (errno != EPERM || + uid != -1 && euid == -1 && (euid = geteuid()) != 0) { if (fflag) exit(0); - error(file); - exit(1); + err(1, "%s", file); } - /* check group membership; kernel just returns EPERM */ - if (gid != -1 && ngroups == -1) { - int groups[NGROUPS]; + /* Check group membership; kernel just returns EPERM. */ + if (gid != -1 && ngroups == -1) { ngroups = getgroups(NGROUPS, groups); while (--ngroups >= 0 && gid != groups[ngroups]); if (ngroups < 0) { if (fflag) exit(0); - (void)fprintf(stderr, - "%s: you are not a member of group %s.\n", - myname, gname); - exit(1); + errx(1, "you are not a member of group %s", gname); } } - if (!fflag) - error(file); -} -error(name) - char *name; -{ - (void)fprintf(stderr, "%s: %s: %s\n", myname, name, strerror(errno)); - retval = 1; + if (!fflag) + warn("%s", file); } +void usage() { - (void)fprintf(stderr, "usage: %s [-HRfh] %s file ...\n", myname, - ischown ? "[owner][:group]" : "group"); + (void)fprintf(stderr, + "usage: %s [-R [-H | -L | -P]] [-f] %s file ...\n", + myname, ischown ? "[owner][:group]" : "group"); exit(1); } -- 2.20.1