diff --git a/usr.sbin/chown/Makefile b/usr.sbin/chown/Makefile index ab3c733460ba..9984445b04b2 100644 --- a/usr.sbin/chown/Makefile +++ b/usr.sbin/chown/Makefile @@ -1,10 +1,10 @@ -# from: @(#)Makefile 5.4 (Berkeley) 10/26/90 -# $Id: Makefile,v 1.3 1993/08/01 05:38:29 mycroft Exp $ +# from: @(#)Makefile 8.1 (Berkeley) 6/6/93 +# $Id: Makefile,v 1.4 1994/06/18 20:55:54 cgd Exp $ PROG= chown CFLAGS+=-DSUPPORT_DOT MAN1= chgrp.0 MAN8= chown.0 -LINKS= ${BINDIR}/chown ${BINDIR}/../bin/chgrp +LINKS= ${BINDIR}/chown /usr/bin/chgrp .include diff --git a/usr.sbin/chown/chgrp.1 b/usr.sbin/chown/chgrp.1 index b8bd28415d0e..546f5bed952a 100644 --- a/usr.sbin/chown/chgrp.1 +++ b/usr.sbin/chown/chgrp.1 @@ -1,5 +1,5 @@ -.\" Copyright (c) 1983, 1990 The Regents of the University of California. -.\" All rights reserved. +.\" 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 .\" the Institute of Electrical and Electronics Engineers, Inc. @@ -32,10 +32,10 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" from: @(#)chgrp.1 6.7 (Berkeley) 6/27/91 -.\" $Id: chgrp.1,v 1.3 1993/11/30 00:38:53 jtc Exp $ +.\" from: @(#)chgrp.1 8.3 (Berkeley) 3/31/94 +.\" $Id: chgrp.1,v 1.4 1994/06/18 20:55:56 cgd Exp $ .\" -.Dd June 27, 1991 +.Dd March 31, 1994 .Dt CHGRP 1 .Os BSD 4.2 .Sh NAME @@ -43,7 +43,11 @@ .Nd change group .Sh SYNOPSIS .Nm chgrp -.Op Fl Rf +.Oo +.Fl R +.Op Fl H | Fl L | Fl P +.Oc +.Op Fl f .Ar group .Ar files ... .Sh DESCRIPTION @@ -55,38 +59,66 @@ ID specified by the group operand. .Pp Options: .Bl -tag -width Ds +.It Fl H +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 user does not have proper permissions). +query about strange modes (unless the user does not have proper permissions). .El .Pp -Operands: -.Bl -tag -width group -.It Ar group +Symbolic links don't have groups, so unless the +.Fl H +or +.Fl L +option is set, +.Nm chgrp +on a symbolic link always succeeds and has no effect. +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 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 @@ -94,11 +126,12 @@ Group ID file .El .Sh SEE ALSO .Xr chown 2 , -.Xr chown 8 , .Xr group 5 , -.Xr passwd 5 +.Xr passwd 5 , +.Xr fts 3 , +.Xr symlink 7 , +.Xr chown 8 .Sh STANDARDS The .Nm chgrp -function is expected to conform to -.St -p1003.2-92 . +utility is expected to be POSIX 1003.2 compatible. diff --git a/usr.sbin/chown/chown.8 b/usr.sbin/chown/chown.8 index 8a79288428e4..ddf43f1ad48f 100644 --- a/usr.sbin/chown/chown.8 +++ b/usr.sbin/chown/chown.8 @@ -1,5 +1,5 @@ -.\" Copyright (c) 1990, 1991 The Regents of the University of California. -.\" All rights reserved. +.\" Copyright (c) 1990, 1991, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions @@ -29,10 +29,10 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" from: @(#)chown.8 6.6 (Berkeley) 6/17/91 -.\" $Id: chown.8,v 1.3 1993/11/30 00:38:54 jtc Exp $ +.\" from: @(#)chown.8 8.3 (Berkeley) 3/31/94 +.\" $Id: chown.8,v 1.4 1994/06/18 20:55:57 cgd Exp $ .\" -.Dd June 17, 1991 +.Dd March 31, 1994 .Dt CHOWN 8 .Os BSD 4 .Sh NAME @@ -40,11 +40,19 @@ .Nd change file owner and group .Sh SYNOPSIS .Nm chown -.Op Fl Rf +.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 Rf +.Oo +.Fl R +.Op Fl H | Fl L | Fl P +.Oc +.Op Fl f .Ar :group .Ar file ... .Sh DESCRIPTION @@ -53,6 +61,19 @@ sets the user ID and/or the group ID of the specified files. .Pp The options are as follows: .Bl -tag -width Ds +.It Fl H +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. @@ -61,6 +82,24 @@ Don't report any failure to change file owner or group, nor modify the exit status to reflect such failures. .El .Pp +Symbolic links don't have owners, so unless the +.Fl H +or +.Fl L +option is set, +.Nm chown +on a symbolic link always succeeds and has no effect. +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 and @@ -84,9 +123,6 @@ group name. The ownership of a file may only be altered by a super-user for obvious security reasons. .Pp -The owner and group of symbolic links are themselves changed instead -of the file to which the link points. -.Pp The .Nm chown utility exits 0 on success, and >0 if an error occurs. @@ -96,12 +132,19 @@ 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 , -.Xr chown 2 +.Xr chown 2 , +.Xr fts 3 , +.Xr symlink 7 .Sh STANDARDS The .Nm chown -command is expected to conform to -.St -p1003.2-92 . +command is expected to be POSIX 1003.2 compliant. diff --git a/usr.sbin/chown/chown.c b/usr.sbin/chown/chown.c index 40952c3d5d6b..171dc0bd9133 100644 --- a/usr.sbin/chown/chown.c +++ b/usr.sbin/chown/chown.c @@ -1,6 +1,6 @@ /* - * Copyright (c) 1988 Regents of the University of California. - * All rights reserved. + * Copyright (c) 1988, 1993, 1994 + * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,53 +32,86 @@ */ #ifndef lint -char copyright[] = -"@(#) Copyright (c) 1988 Regents of the University of California.\n\ - All rights reserved.\n"; +static char copyright[] = +"@(#) 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[] = "from: @(#)chown.c 5.18 (Berkeley) 3/9/91";*/ -static char rcsid[] = "$Id: chown.c,v 1.4 1994/04/01 01:19:08 jtc Exp $"; +/* from: static char sccsid[] = "@(#)chown.c 8.8 (Berkeley) 4/4/94"; */ +static char *rcsid = "$Id: chown.c,v 1.5 1994/06/18 20:55:58 cgd Exp $"; #endif /* not lint */ #include #include -#include -#include -#include -#include -#include -#include -#include + #include +#include +#include +#include +#include +#include +#include +#include #include #include +#include -int ischown, uid, gid, fflag, rflag, retval; +void a_gid __P((char *)); +void a_uid __P((char *)); +void chownerr __P((char *)); +u_long id __P((char *, char *)); +void usage __P((void)); + +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 *fts; - register FTSENT *p; - register char *cp; - int ch; - + 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'; - - while ((ch = getopt(argc, argv, "Rf")) != -1) - 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; + break; case '?': default: usage(); @@ -89,136 +122,153 @@ main(argc, argv) if (argc < 2) usage(); + fts_options = 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 (rflag) { - if (!(fts = fts_open(++argv, FTS_NOSTAT|FTS_PHYSICAL, 0))) { - (void)fprintf(stderr, - "%s: %s.\n", myname, strerror(errno)); - exit(1); - } - while (p = fts_read(fts)) { - if (p->fts_info == FTS_D) + 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; - if (p->fts_info == FTS_ERR) { - error(p->fts_path); - continue; - } - if (chown(p->fts_accpath, uid, gid) && !fflag) - chownerr(p->fts_path); + fts_set(ftsp, p, FTS_SKIP); + break; + case FTS_DNR: /* Warn, chown, continue. */ + warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); + rval = 1; + break; + case FTS_ERR: /* Warn, continue. */ + case FTS_NS: + warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); + rval = 1; + continue; + case FTS_SL: /* Ignore. */ + 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; + default: + break; + } + if (chown(p->fts_accpath, uid, gid) && !fflag) { + chownerr(p->fts_path); + rval = 1; } - exit(retval); } - while (*++argv) - if (chown(*argv, uid, gid) && !fflag) - chownerr(*argv); - exit(retval); + if (errno) + err(1, "fts_read"); + 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; + gid_t 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) { - gid_t 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 [-Rf] %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); }