122488Sdist /* 234039Sbostic * Copyright (c) 1988 Regents of the University of California. 334039Sbostic * All rights reserved. 434039Sbostic * 542792Sbostic * %sccs.include.redist.c% 622488Sdist */ 718450Smckusick 822488Sdist #ifndef lint 922488Sdist char copyright[] = 1034039Sbostic "@(#) Copyright (c) 1988 Regents of the University of California.\n\ 1122488Sdist All rights reserved.\n"; 1234039Sbostic #endif /* not lint */ 1322488Sdist 1422488Sdist #ifndef lint 15*53713Selan static char sccsid[] = "@(#)chown.c 5.19 (Berkeley) 05/28/92"; 1634039Sbostic #endif /* not lint */ 1722488Sdist 1834039Sbostic #include <sys/param.h> 19975Sbill #include <sys/stat.h> 2038427Sbostic #include <sys/errno.h> 2138427Sbostic #include <dirent.h> 2245426Sbostic #include <fts.h> 23975Sbill #include <pwd.h> 2418450Smckusick #include <grp.h> 2547178Sbostic #include <unistd.h> 2634039Sbostic #include <stdio.h> 2734039Sbostic #include <ctype.h> 2847178Sbostic #include <stdlib.h> 2945426Sbostic #include <string.h> 30975Sbill 3141090Smarc int ischown, uid, gid, fflag, rflag, retval; 3241090Smarc char *gname, *myname; 33975Sbill 34975Sbill main(argc, argv) 3534039Sbostic int argc; 3634039Sbostic char **argv; 37975Sbill { 3834039Sbostic extern int optind; 39*53713Selan register FTS *ftsp; 4045426Sbostic register FTSENT *p; 4134039Sbostic register char *cp; 4234039Sbostic int ch; 43*53713Selan int fts_options; 44975Sbill 4534039Sbostic myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv; 4634039Sbostic ischown = myname[2] == 'o'; 4724505Ssam 48*53713Selan fts_options = FTS_NOSTAT | FTS_PHYSICAL; 49*53713Selan while ((ch = getopt(argc, argv, "HRfh")) != EOF) 5034039Sbostic switch((char)ch) { 5134039Sbostic case 'R': 5245426Sbostic rflag = 1; 5334039Sbostic break; 5424505Ssam case 'f': 5545426Sbostic fflag = 1; 5624505Ssam break; 57*53713Selan case 'h': 58*53713Selan fts_options &= ~FTS_PHYSICAL; 59*53713Selan fts_options |= FTS_LOGICAL; 60*53713Selan break; 61*53713Selan case 'H': 62*53713Selan fts_options |= FTS_COMFOLLOW; 63*53713Selan break; 6434039Sbostic case '?': 6534039Sbostic default: 6634039Sbostic usage(); 6734039Sbostic } 6834039Sbostic argv += optind; 6934039Sbostic argc -= optind; 7024505Ssam 7134039Sbostic if (argc < 2) 7234039Sbostic usage(); 7324505Ssam 7445426Sbostic uid = gid = -1; 7534039Sbostic if (ischown) { 7645426Sbostic #ifdef SUPPORT_DOT 7734039Sbostic if (cp = index(*argv, '.')) { 7834039Sbostic *cp++ = '\0'; 7947178Sbostic a_gid(cp); 8045426Sbostic } else 8145426Sbostic #endif 8245426Sbostic if (cp = index(*argv, ':')) { 8345426Sbostic *cp++ = '\0'; 8447178Sbostic a_gid(cp); 8545426Sbostic } 8647178Sbostic a_uid(*argv); 8724505Ssam } 8845426Sbostic else 8947178Sbostic a_gid(*argv); 9034039Sbostic 91*53713Selan if (!(ftsp = fts_open(++argv, fts_options, 0))) { 92*53713Selan (void)fprintf(stderr, 93*53713Selan "%s: %s.\n", myname, strerror(errno)); 94*53713Selan exit(1); 95*53713Selan } 96*53713Selan while (p = fts_read(ftsp)) { 97*53713Selan if (p->fts_info == FTS_D) { 98*53713Selan if (rflag) 9945426Sbostic continue; 100*53713Selan else 101*53713Selan fts_set(ftsp, p, FTS_SKIP); 10245426Sbostic } 103*53713Selan if (p->fts_info == FTS_ERR) { 104*53713Selan error(p->fts_path); 105*53713Selan continue; 106*53713Selan } 107*53713Selan if (chown(p->fts_accpath, uid, gid) && !fflag) 108*53713Selan chownerr(p->fts_path); 10936959Sbostic } 11034039Sbostic exit(retval); 11134039Sbostic } 11234039Sbostic 11347178Sbostic a_gid(s) 11434039Sbostic register char *s; 11534039Sbostic { 11647178Sbostic struct group *gr; 11734039Sbostic 11834039Sbostic if (!*s) { 11934039Sbostic gid = -1; /* argument was "uid." */ 12034039Sbostic return; 12111442Smckusick } 12247178Sbostic gname = s; 12347178Sbostic if (gr = getgrnam(s)) 12447178Sbostic gid = gr->gr_gid; 12534039Sbostic else { 12647178Sbostic for (; *s && isdigit(*s); ++s); 12747178Sbostic if (!*s) 12847178Sbostic gid = atoi(gname); 12947178Sbostic else { 13038427Sbostic (void)fprintf(stderr, "%s: unknown group id: %s\n", 13134056Sbostic myname, gname); 13245426Sbostic exit(1); 13318450Smckusick } 134975Sbill } 135975Sbill } 136975Sbill 13747178Sbostic a_uid(s) 13834039Sbostic register char *s; 139975Sbill { 14047178Sbostic struct passwd *pw; 14147178Sbostic char *uname; 142975Sbill 14334039Sbostic if (!*s) { 14434039Sbostic uid = -1; /* argument was ".gid" */ 14534039Sbostic return; 14634039Sbostic } 14747178Sbostic if (pw = getpwnam(s)) 14847178Sbostic uid = pw->pw_uid; 14934039Sbostic else { 15047178Sbostic for (uname = s; *s && isdigit(*s); ++s); 15147178Sbostic if (!*s) 15247178Sbostic uid = atoi(uname); 15347178Sbostic else { 15438427Sbostic (void)fprintf(stderr, 15547178Sbostic "chown: unknown user id: %s\n", uname); 15645426Sbostic exit(1); 15734039Sbostic } 15834039Sbostic } 159975Sbill } 16018450Smckusick 16134069Sbostic chownerr(file) 16234069Sbostic char *file; 16334069Sbostic { 16434069Sbostic static int euid = -1, ngroups = -1; 16534069Sbostic 16634069Sbostic /* check for chown without being root */ 16738427Sbostic if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) { 16834069Sbostic if (fflag) 16934069Sbostic exit(0); 17045426Sbostic error(file); 17145426Sbostic exit(1); 17234069Sbostic } 17334069Sbostic /* check group membership; kernel just returns EPERM */ 17434069Sbostic if (gid != -1 && ngroups == -1) { 17534069Sbostic int groups[NGROUPS]; 17634069Sbostic 17734069Sbostic ngroups = getgroups(NGROUPS, groups); 17834069Sbostic while (--ngroups >= 0 && gid != groups[ngroups]); 17934069Sbostic if (ngroups < 0) { 18034069Sbostic if (fflag) 18134069Sbostic exit(0); 18238427Sbostic (void)fprintf(stderr, 18334069Sbostic "%s: you are not a member of group %s.\n", 18434069Sbostic myname, gname); 18545426Sbostic exit(1); 18634069Sbostic } 18734069Sbostic } 18845426Sbostic if (!fflag) 18945426Sbostic error(file); 19034069Sbostic } 19134069Sbostic 19245426Sbostic error(name) 19345426Sbostic char *name; 19424505Ssam { 19545426Sbostic (void)fprintf(stderr, "%s: %s: %s\n", myname, name, strerror(errno)); 19645426Sbostic retval = 1; 19724505Ssam } 19824505Ssam 19934039Sbostic usage() 20024505Ssam { 20138427Sbostic (void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname, 20245426Sbostic ischown ? "[owner][:group]" : "group"); 20345426Sbostic exit(1); 20424505Ssam } 205