X-Git-Url: https://git.saurik.com/apple/file_cmds.git/blobdiff_plain/440bd1982b8e55068af44543d97888092d61feee..refs/heads/master:/chown/chown.c?ds=sidebyside diff --git a/chown/chown.c b/chown/chown.c index 3598ecc..708a6c5 100644 --- a/chown/chown.c +++ b/chown/chown.c @@ -33,26 +33,25 @@ #include #ifndef lint -__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\n\ - The Regents of the University of California. All rights reserved.\n"); +__used static const char copyright[] = +"@(#) Copyright (c) 1988, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)chown.c 8.8 (Berkeley) 4/4/94"; -#else -__RCSID("$NetBSD: chown.c,v 1.15 1998/10/05 21:37:39 kim Exp $"); #endif #endif /* not lint */ +#include +__RCSID("$FreeBSD: src/usr.sbin/chown/chown.c,v 1.24 2002/07/17 16:22:24 dwmalone Exp $"); + #include #include -#include -#include #include #include -#include #include #include #include @@ -60,37 +59,51 @@ __RCSID("$NetBSD: chown.c,v 1.15 1998/10/05 21:37:39 kim Exp $"); #include #include #include +#include -void a_gid __P((char *)); -void a_uid __P((char *)); -void chownerr __P((char *)); -u_long id __P((char *, char *)); -int main __P((int, char **)); -void usage __P((void)); +#ifdef __APPLE__ +#include +#else +#define COMPAT_MODE(a,b) (1) +#endif /* __APPLE__ */ + +void a_gid(const char *); +void a_uid(const char *); +void chownerr(const char *); +static uid_t id(const char *, const char *); +void usage(void); uid_t uid; gid_t gid; -int Rflag, ischown, fflag; -char *gname, *myname; +int ischown; +#ifdef __APPLE__ +int isnumeric = 0; +#endif +const char *gname; int -main(argc, argv) - int argc; - char *argv[]; +main(int argc, char **argv) { FTS *ftsp; FTSENT *p; - int Hflag, Lflag, Pflag, ch, fts_options, hflag, rval; + int Hflag, Lflag, Pflag, Rflag, fflag, hflag, vflag; + int ch, fts_options, rval; char *cp; - int (*change_owner) __P((const char *, uid_t, gid_t)); - - setlocale(LC_ALL, ""); + int unix2003_compat = 0; + int symlink_found = 0; - myname = (cp = strrchr(*argv, '/')) ? cp + 1 : *argv; - ischown = myname[2] == 'o'; - - Hflag = Lflag = Pflag = hflag = 0; - while ((ch = getopt(argc, argv, "HLPRfh")) != -1) + if (argc < 1) + usage(); + cp = strrchr(argv[0], '/'); + cp = (cp != NULL) ? cp + 1 : argv[0]; + ischown = (strcmp(cp, "chown") == 0); + + Hflag = Lflag = Pflag = Rflag = fflag = hflag = vflag = 0; +#ifdef __APPLE__ + while ((ch = getopt(argc, argv, "HLPRfhnv")) != -1) +#else + while ((ch = getopt(argc, argv, "HLPRfhv")) != -1) +#endif switch (ch) { case 'H': Hflag = 1; @@ -111,14 +124,15 @@ main(argc, argv) fflag = 1; break; case 'h': - /* - * In System V the -h option causes chown/chgrp to - * change the owner/group of the symbolic link. - * 4.4BSD's symbolic links didn't have owners/groups, - * so it was an undocumented noop. - * In NetBSD 1.3, lchown(2) is introduced. - */ hflag = 1; + break; +#ifdef __APPLE__ + case 'n': + isnumeric = 1; + break; +#endif + case 'v': + vflag = 1; break; case '?': default: @@ -129,53 +143,55 @@ main(argc, argv) if (argc < 2) usage(); + if (!Rflag && (Hflag || Lflag || Pflag)) + warnx("options -H, -L, -P only useful with -R"); - fts_options = FTS_PHYSICAL; if (Rflag) { + fts_options = FTS_PHYSICAL; + if (hflag && (Hflag || Lflag)) + errx(1, "the -R%c and -h options may not be " + "specified together", Hflag ? 'H' : 'L'); if (Hflag) fts_options |= FTS_COMFOLLOW; - if (Lflag) { - if (hflag) - errx(1, "the -L and -h options may not be specified together."); + else if (Lflag) { fts_options &= ~FTS_PHYSICAL; fts_options |= FTS_LOGICAL; } - } -#ifndef __APPLE__ - if (hflag) - change_owner = lchown; - else - change_owner = chown; -#else - change_owner = chown; -#endif + } else + fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL; - uid = gid = -1; + uid = (uid_t)-1; + gid = (gid_t)-1; if (ischown) { + unix2003_compat = COMPAT_MODE("bin/chown", "Unix2003"); if ((cp = strchr(*argv, ':')) != NULL) { *cp++ = '\0'; a_gid(cp); } #ifdef SUPPORT_DOT else if ((cp = strchr(*argv, '.')) != NULL) { + warnx("separation of user and group with a period is deprecated"); *cp++ = '\0'; a_gid(cp); } #endif a_uid(*argv); - } else + } else { + unix2003_compat = COMPAT_MODE("bin/chgrp", "Unix2003"); a_gid(*argv); + } if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) - err(1, "%s", ""); + err(1, NULL); for (rval = 0; (p = fts_read(ftsp)) != NULL;) { + symlink_found = 0; switch (p->fts_info) { - case FTS_D: - if (!Rflag) /* Change it at FTS_DP. */ + case FTS_D: /* Change it at FTS_DP. */ + if (!Rflag) fts_set(ftsp, p, FTS_SKIP); continue; - case FTS_DNR: /* Warn, chown, continue. */ + case FTS_DNR: /* Warn, chown. */ warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); rval = 1; break; @@ -184,28 +200,49 @@ main(argc, argv) warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); rval = 1; continue; - case FTS_SL: /* Ignore. */ + 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. */ -#ifndef __APPLE__ - if (!hflag) - continue; -#else - continue; -#endif - /* else */ - /* FALLTHROUGH */ + if (hflag) + break; + else { + symlink_found = 1; + if (unix2003_compat) { + if (Hflag || Lflag) { /* -H or -L was specified */ + if (p->fts_errno) { + warnx("%s: %s", p->fts_name, strerror(p->fts_errno)); + rval = 1; + continue; + } + } + break; /* Otherwise symlinks keep going */ + } + continue; + } default: break; } - - if ((*change_owner)(p->fts_accpath, uid, gid) && !fflag) { - warn("%s", p->fts_path); - rval = 1; + if (unix2003_compat) { + /* Can only avoid updating times if both uid and gid are -1 */ + if ((uid == (uid_t)-1) && (gid == (gid_t)-1)) + continue; + } else { + if ((uid == (uid_t)-1 || uid == p->fts_statp->st_uid) && + (gid == (gid_t)-1 || gid == p->fts_statp->st_gid)) + continue; + } + if (((hflag || symlink_found) ? lchown : chown)(p->fts_accpath, uid, gid) == -1) { + if (!fflag) { + chownerr(p->fts_path); + rval = 1; + } + } else { + if (vflag) + printf("%s\n", p->fts_path); } } if (errno) @@ -214,53 +251,95 @@ main(argc, argv) } void -a_gid(s) - char *s; +a_gid(const char *s) { struct group *gr; if (*s == '\0') /* Argument was "uid[:.]". */ return; gname = s; - gid = ((gr = getgrnam(s)) == NULL) ? id(s, "group") : gr->gr_gid; +#ifdef __APPLE__ + gid = (!isnumeric && ((gr = getgrnam(s)) != NULL)) ? gr->gr_gid : id(s, "group"); +#else + gid = ((gr = getgrnam(s)) != NULL) ? gr->gr_gid : id(s, "group"); +#endif } void -a_uid(s) - char *s; +a_uid(const char *s) { struct passwd *pw; if (*s == '\0') /* Argument was "[:.]gid". */ return; - uid = ((pw = getpwnam(s)) == NULL) ? id(s, "user") : pw->pw_uid; +#ifdef __APPLE__ + uid = (!isnumeric && ((pw = getpwnam(s)) != NULL)) ? pw->pw_uid : id(s, "user"); +#else + uid = ((pw = getpwnam(s)) != NULL) ? pw->pw_uid : id(s, "user"); +#endif } -u_long -id(name, type) - char *name, *type; +static uid_t +id(const char *name, const char *type) { - u_long val; + unsigned 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: invalid %s name", name, type); - return (val); + if (errno || *ep != '\0' || val > UID_MAX) + errx(1, "%s: illegal %s name", name, type); + return (uid_t)val; } void -usage() +chownerr(const char *file) { - (void)fprintf(stderr, - "usage: %s [-R [-H | -L | -P]] [-fh] %s file ...\n", - myname, ischown ? "[owner][:group]" : "group"); + static uid_t euid = -1; + static int ngroups = -1; + gid_t groups[NGROUPS_MAX]; + + /* Check for chown without being root. */ + if (errno != EPERM || (uid != (uid_t)-1 && + euid == (uid_t)-1 && (euid = geteuid()) != 0)) { + warn("%s", file); + return; + } + + /* Check group membership; kernel just returns EPERM. */ + if (gid != (gid_t)-1 && ngroups == -1 && + euid == (uid_t)-1 && (euid = geteuid()) != 0) { + ngroups = getgroups(NGROUPS_MAX, groups); + while (--ngroups >= 0 && gid != groups[ngroups]); + if (ngroups < 0) { + warnx("you are not a member of group %s", gname); + return; + } + } + warn("%s", file); +} + +void +usage(void) +{ + + if (ischown) + (void)fprintf(stderr, "%s\n%s\n", +#ifdef __APPLE__ + "usage: chown [-fhnv] [-R [-H | -L | -P]] owner[:group]" + " file ...", + " chown [-fhnv] [-R [-H | -L | -P]] :group file ..."); +#else + "usage: chown [-fhv] [-R [-H | -L | -P]] owner[:group]" + " file ...", + " chown [-fhv] [-R [-H | -L | -P]] :group file ..."); +#endif + else + (void)fprintf(stderr, "%s\n", +#ifdef __APPLE__ + "usage: chgrp [-fhnv] [-R [-H | -L | -P]] group file ..."); +#else + "usage: chgrp [-fhv] [-R [-H | -L | -P]] group file ..."); +#endif exit(1); }