122488Sdist /* 266539Sbostic * Copyright (c) 1988, 1993, 1994 361813Sbostic * The Regents of the University of California. All rights reserved. 434039Sbostic * 542792Sbostic * %sccs.include.redist.c% 622488Sdist */ 718450Smckusick 822488Sdist #ifndef lint 961813Sbostic static char copyright[] = 1066539Sbostic "@(#) Copyright (c) 1988, 1993, 1994\n\ 1161813Sbostic The Regents of the University of California. All rights reserved.\n"; 1234039Sbostic #endif /* not lint */ 1322488Sdist 1422488Sdist #ifndef lint 15*66542Sbostic static char sccsid[] = "@(#)chown.c 8.3 (Berkeley) 03/31/94"; 1634039Sbostic #endif /* not lint */ 1722488Sdist 1834039Sbostic #include <sys/param.h> 19975Sbill #include <sys/stat.h> 2066539Sbostic 2166539Sbostic #include <ctype.h> 2238427Sbostic #include <dirent.h> 2366539Sbostic #include <err.h> 2466539Sbostic #include <errno.h> 2545426Sbostic #include <fts.h> 2666539Sbostic #include <grp.h> 27975Sbill #include <pwd.h> 2834039Sbostic #include <stdio.h> 2947178Sbostic #include <stdlib.h> 3045426Sbostic #include <string.h> 3166539Sbostic #include <unistd.h> 32975Sbill 3366539Sbostic void a_gid __P((char *)); 3466539Sbostic void a_uid __P((char *)); 3566539Sbostic void chownerr __P((char *)); 3666539Sbostic u_long id __P((char *, char *)); 3766539Sbostic void usage __P((void)); 3866539Sbostic 3966539Sbostic uid_t uid; 4066539Sbostic gid_t gid; 4166539Sbostic int Rflag, ischown, fflag; 4241090Smarc char *gname, *myname; 43975Sbill 4466539Sbostic int 45975Sbill main(argc, argv) 4634039Sbostic int argc; 4766539Sbostic char *argv[]; 48975Sbill { 4934039Sbostic extern int optind; 5066539Sbostic FTS *ftsp; 5166539Sbostic FTSENT *p; 5266539Sbostic int Hflag, Lflag, Pflag, ch, fts_options, hflag, rval; 5366539Sbostic char *cp; 5453772Selan 5534039Sbostic myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv; 5634039Sbostic ischown = myname[2] == 'o'; 5753772Selan 5866539Sbostic Hflag = Lflag = Pflag = hflag = 0; 5966539Sbostic while ((ch = getopt(argc, argv, "HLPRfh")) != EOF) 6066539Sbostic switch (ch) { 6166539Sbostic case 'H': 6266539Sbostic Hflag = 1; 6366539Sbostic Lflag = Pflag = 0; 6466539Sbostic break; 6566539Sbostic case 'L': 6666539Sbostic Lflag = 1; 6766539Sbostic Hflag = Pflag = 0; 6866539Sbostic break; 6966539Sbostic case 'P': 7066539Sbostic Pflag = 1; 7166539Sbostic Hflag = Lflag = 0; 7266539Sbostic break; 7334039Sbostic case 'R': 7466539Sbostic Rflag = 1; 7534039Sbostic break; 7624505Ssam case 'f': 7745426Sbostic fflag = 1; 7824505Ssam break; 7953713Selan case 'h': 8066539Sbostic /* 8166539Sbostic * In System V (and probably POSIX.2) the -h option 8266539Sbostic * causes chown/chgrp to change the owner/group of 8366539Sbostic * the symbolic link. 4.4BSD's symbolic links don't 8466539Sbostic * have owners/groups, so it's an undocumented noop. 8566539Sbostic * Do syntax checking, though. 8666539Sbostic */ 8753772Selan hflag = 1; 8853713Selan break; 8934039Sbostic case '?': 9034039Sbostic default: 9134039Sbostic usage(); 9234039Sbostic } 9334039Sbostic argv += optind; 9434039Sbostic argc -= optind; 9524505Ssam 9634039Sbostic if (argc < 2) 9734039Sbostic usage(); 9824505Ssam 9966539Sbostic fts_options = FTS_NOSTAT | FTS_PHYSICAL; 10066539Sbostic if (Rflag) { 10166539Sbostic if (hflag) 10266539Sbostic errx(1, 10366539Sbostic "the -R and -h options may not be specified together."); 10466539Sbostic if (Hflag) 10566539Sbostic fts_options |= FTS_COMFOLLOW; 10666539Sbostic if (Lflag) { 10766539Sbostic fts_options &= ~FTS_PHYSICAL; 10866539Sbostic fts_options |= FTS_LOGICAL; 10966539Sbostic } 11066539Sbostic } 11166539Sbostic 11245426Sbostic uid = gid = -1; 11334039Sbostic if (ischown) { 11445426Sbostic #ifdef SUPPORT_DOT 11566539Sbostic if ((cp = strchr(*argv, '.')) != NULL) { 11634039Sbostic *cp++ = '\0'; 11747178Sbostic a_gid(cp); 11845426Sbostic } else 11945426Sbostic #endif 12066539Sbostic if ((cp = strchr(*argv, ':')) != NULL) { 12145426Sbostic *cp++ = '\0'; 12247178Sbostic a_gid(cp); 12345426Sbostic } 12447178Sbostic a_uid(*argv); 12566539Sbostic } else 12647178Sbostic a_gid(*argv); 12734039Sbostic 12866539Sbostic if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) 12966539Sbostic err(1, NULL); 13066539Sbostic 13166539Sbostic for (rval = 0; (p = fts_read(ftsp)) != NULL;) { 13266539Sbostic switch (p->fts_info) { 13366539Sbostic case FTS_D: 13466539Sbostic if (Rflag) /* Change it at FTS_DP. */ 13545426Sbostic continue; 13666539Sbostic fts_set(ftsp, p, FTS_SKIP); 13766539Sbostic break; 138*66542Sbostic case FTS_DC: /* Ignore. */ 13953772Selan continue; 140*66542Sbostic case FTS_DNR: /* Warn, chown, continue. */ 14166539Sbostic errno = p->fts_errno; 14266539Sbostic warn("%s", p->fts_path); 14366539Sbostic rval = 1; 144*66542Sbostic break; 145*66542Sbostic case FTS_ERR: /* Warn, continue. */ 146*66542Sbostic errno = p->fts_errno; 147*66542Sbostic warn("%s", p->fts_path); 148*66542Sbostic rval = 1; 14953713Selan continue; 150*66542Sbostic case FTS_SL: /* Ignore. */ 15166539Sbostic case FTS_SLNONE: 15266539Sbostic /* 15366539Sbostic * The only symlinks that end up here are ones that 15466539Sbostic * don't point to anything and ones that we found 15566539Sbostic * doing a physical walk. 15666539Sbostic */ 15766539Sbostic continue; 158*66542Sbostic default: 159*66542Sbostic break; 16053713Selan } 16166539Sbostic if (chown(p->fts_accpath, uid, gid) && !fflag) { 16253713Selan chownerr(p->fts_path); 16366539Sbostic rval = 1; 16466539Sbostic } 16536959Sbostic } 16666539Sbostic exit(rval); 16734039Sbostic } 16834039Sbostic 16966539Sbostic void 17047178Sbostic a_gid(s) 17166539Sbostic char *s; 17234039Sbostic { 17347178Sbostic struct group *gr; 17434039Sbostic 17566539Sbostic if (*s == '\0') /* Argument was "uid[:.]". */ 17634039Sbostic return; 17747178Sbostic gname = s; 17866539Sbostic gid = ((gr = getgrnam(s)) == NULL) ? id(s, "group") : gr->gr_gid; 179975Sbill } 180975Sbill 18166539Sbostic void 18247178Sbostic a_uid(s) 18366539Sbostic char *s; 184975Sbill { 18547178Sbostic struct passwd *pw; 186975Sbill 18766539Sbostic if (*s == '\0') /* Argument was "[:.]gid". */ 18834039Sbostic return; 18966539Sbostic uid = ((pw = getpwnam(s)) == NULL) ? id(s, "user") : pw->pw_uid; 190975Sbill } 19118450Smckusick 19266539Sbostic u_long 19366539Sbostic id(name, type) 19466539Sbostic char *name, *type; 19566539Sbostic { 19666539Sbostic u_long val; 19766539Sbostic char *ep; 19866539Sbostic 19966539Sbostic /* 20066539Sbostic * XXX 20166539Sbostic * We know that uid_t's and gid_t's are unsigned longs. 20266539Sbostic */ 20366539Sbostic errno = 0; 20466539Sbostic val = strtoul(name, &ep, 10); 20566539Sbostic if (errno) 20666539Sbostic err(1, "%s", name); 20766539Sbostic if (*ep != '\0') 20866539Sbostic errx(1, "%s: illegal %s name", name, type); 20966539Sbostic return (val); 21066539Sbostic } 21166539Sbostic 21266539Sbostic void 21334069Sbostic chownerr(file) 21434069Sbostic char *file; 21534069Sbostic { 21634069Sbostic static int euid = -1, ngroups = -1; 21766539Sbostic int groups[NGROUPS]; 21834069Sbostic 21966539Sbostic /* Check for chown without being root. */ 22066539Sbostic if (errno != EPERM || 22166539Sbostic uid != -1 && euid == -1 && (euid = geteuid()) != 0) { 22234069Sbostic if (fflag) 22334069Sbostic exit(0); 22466539Sbostic err(1, "%s", file); 22534069Sbostic } 22666539Sbostic 22766539Sbostic /* Check group membership; kernel just returns EPERM. */ 22834069Sbostic if (gid != -1 && ngroups == -1) { 22934069Sbostic ngroups = getgroups(NGROUPS, groups); 23034069Sbostic while (--ngroups >= 0 && gid != groups[ngroups]); 23134069Sbostic if (ngroups < 0) { 23234069Sbostic if (fflag) 23334069Sbostic exit(0); 23466539Sbostic errx(1, "you are not a member of group %s", gname); 23534069Sbostic } 23634069Sbostic } 23734069Sbostic 23866539Sbostic if (!fflag) 23966539Sbostic warn("%s", file); 24024505Ssam } 24124505Ssam 24266539Sbostic void 24334039Sbostic usage() 24424505Ssam { 24566539Sbostic (void)fprintf(stderr, 24666539Sbostic "usage: %s [-R [-H | -L | -P]] [-f] %s file ...\n", 24766539Sbostic myname, ischown ? "[owner][:group]" : "group"); 24845426Sbostic exit(1); 24924505Ssam } 250