xref: /csrg-svn/usr.sbin/chown/chown.c (revision 53713)
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