xref: /original-bsd/usr.sbin/chown/chown.c (revision 94e7bb75)
1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1988 Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)chown.c	5.20 (Berkeley) 06/01/92";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/stat.h>
20 #include <sys/errno.h>
21 #include <dirent.h>
22 #include <fts.h>
23 #include <pwd.h>
24 #include <grp.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 int ischown, uid, gid, fflag, rflag, retval;
32 char *gname, *myname;
33 
34 main(argc, argv)
35 	int argc;
36 	char **argv;
37 {
38 	extern int optind;
39 	register FTS *ftsp;
40 	register FTSENT *p;
41 	register char *cp;
42 	int ch;
43 	int fts_options;
44 	int hflag, Hflag;
45 
46 	myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
47 	ischown = myname[2] == 'o';
48 
49 	hflag = Hflag = 0;
50 	fts_options = FTS_NOSTAT | FTS_PHYSICAL;
51 	while ((ch = getopt(argc, argv, "HRfh")) != EOF)
52 		switch((char)ch) {
53 		case 'R':
54 			rflag = 1;
55 			break;
56 		case 'f':
57 			fflag = 1;
58 			break;
59 		case 'h':
60 			hflag = 1;
61 			fts_options &= ~FTS_PHYSICAL;
62 			fts_options |= FTS_LOGICAL;
63 			break;
64 		case 'H':
65 			Hflag = 1;
66 			fts_options |= FTS_COMFOLLOW;
67 			break;
68 		case '?':
69 		default:
70 			usage();
71 		}
72 	argv += optind;
73 	argc -= optind;
74 
75 	if (argc < 2)
76 		usage();
77 
78 	uid = gid = -1;
79 	if (ischown) {
80 #ifdef SUPPORT_DOT
81 		if (cp = index(*argv, '.')) {
82 			*cp++ = '\0';
83 			a_gid(cp);
84 		} else
85 #endif
86 		if (cp = index(*argv, ':')) {
87 			*cp++ = '\0';
88 			a_gid(cp);
89 		}
90 		a_uid(*argv);
91 	}
92 	else
93 		a_gid(*argv);
94 
95 	if (!(ftsp = fts_open(++argv, fts_options, 0))) {
96 		(void)fprintf(stderr,
97 		    "%s: %s.\n", myname, strerror(errno));
98 		exit(1);
99 	}
100 	while (p = fts_read(ftsp)) {
101 		if (p->fts_info == FTS_D) {
102 			if (rflag)
103 				continue;
104 			else
105 				fts_set(ftsp, p, FTS_SKIP);
106 		}
107 		if (p->fts_info == FTS_SL &&
108 		    !(hflag || (Hflag && p->fts_level == FTS_ROOTLEVEL)))
109 			continue;
110 		if (p->fts_info == FTS_ERR) {
111 			error(p->fts_path);
112 			continue;
113 		}
114 		if (chown(p->fts_accpath, uid, gid) && !fflag)
115 			chownerr(p->fts_path);
116 	}
117 	exit(retval);
118 }
119 
120 a_gid(s)
121 	register char *s;
122 {
123 	struct group *gr;
124 
125 	if (!*s) {
126 		gid = -1;			/* argument was "uid." */
127 		return;
128 	}
129 	gname = s;
130 	if (gr = getgrnam(s))
131 		gid = gr->gr_gid;
132 	else {
133 		for (; *s && isdigit(*s); ++s);
134 		if (!*s)
135 			gid = atoi(gname);
136 		else {
137 			(void)fprintf(stderr, "%s: unknown group id: %s\n",
138 			    myname, gname);
139 			exit(1);
140 		}
141 	}
142 }
143 
144 a_uid(s)
145 	register char *s;
146 {
147 	struct passwd *pw;
148 	char *uname;
149 
150 	if (!*s) {
151 		uid = -1;			/* argument was ".gid" */
152 		return;
153 	}
154 	if (pw = getpwnam(s))
155 		uid = pw->pw_uid;
156 	else {
157 		for (uname = s; *s && isdigit(*s); ++s);
158 		if (!*s)
159 			uid = atoi(uname);
160 		else {
161 			(void)fprintf(stderr,
162 			    "chown: unknown user id: %s\n", uname);
163 			exit(1);
164 		}
165 	}
166 }
167 
168 chownerr(file)
169 	char *file;
170 {
171 	static int euid = -1, ngroups = -1;
172 
173 	/* check for chown without being root */
174 	if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) {
175 		if (fflag)
176 			exit(0);
177 		error(file);
178 		exit(1);
179 	}
180 	/* check group membership; kernel just returns EPERM */
181 	if (gid != -1 && ngroups == -1) {
182 		int groups[NGROUPS];
183 
184 		ngroups = getgroups(NGROUPS, groups);
185 		while (--ngroups >= 0 && gid != groups[ngroups]);
186 		if (ngroups < 0) {
187 			if (fflag)
188 				exit(0);
189 			(void)fprintf(stderr,
190 			    "%s: you are not a member of group %s.\n",
191 			    myname, gname);
192 			exit(1);
193 		}
194 	}
195 	if (!fflag)
196 		error(file);
197 }
198 
199 error(name)
200 	char *name;
201 {
202 	(void)fprintf(stderr, "%s: %s: %s\n", myname, name, strerror(errno));
203 	retval = 1;
204 }
205 
206 usage()
207 {
208 	(void)fprintf(stderr, "usage: %s [-HRfh] %s file ...\n", myname,
209 	    ischown ? "[owner][:group]" : "group");
210 	exit(1);
211 }
212