chown.c revision 1.2 1 /*
2 * Copyright (c) 1988 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 char copyright[] =
36 "@(#) Copyright (c) 1988 Regents of the University of California.\n\
37 All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 /*static char sccsid[] = "from: @(#)chown.c 5.18 (Berkeley) 3/9/91";*/
42 static char rcsid[] = "$Id: chown.c,v 1.2 1993/08/01 18:28:16 mycroft Exp $";
43 #endif /* not lint */
44
45 #include <sys/param.h>
46 #include <sys/stat.h>
47 #include <sys/errno.h>
48 #include <dirent.h>
49 #include <fts.h>
50 #include <pwd.h>
51 #include <grp.h>
52 #include <unistd.h>
53 #include <stdio.h>
54 #include <ctype.h>
55 #include <stdlib.h>
56 #include <string.h>
57
58 int ischown, uid, gid, fflag, rflag, retval;
59 char *gname, *myname;
60
61 main(argc, argv)
62 int argc;
63 char **argv;
64 {
65 extern int optind;
66 register FTS *fts;
67 register FTSENT *p;
68 register char *cp;
69 int ch;
70
71 myname = (cp = rindex(*argv, '/')) ? cp + 1 : *argv;
72 ischown = myname[2] == 'o';
73
74 while ((ch = getopt(argc, argv, "Rf")) != EOF)
75 switch((char)ch) {
76 case 'R':
77 rflag = 1;
78 break;
79 case 'f':
80 fflag = 1;
81 break;
82 case '?':
83 default:
84 usage();
85 }
86 argv += optind;
87 argc -= optind;
88
89 if (argc < 2)
90 usage();
91
92 uid = gid = -1;
93 if (ischown) {
94 #ifdef SUPPORT_DOT
95 if (cp = index(*argv, '.')) {
96 *cp++ = '\0';
97 a_gid(cp);
98 } else
99 #endif
100 if (cp = index(*argv, ':')) {
101 *cp++ = '\0';
102 a_gid(cp);
103 }
104 a_uid(*argv);
105 }
106 else
107 a_gid(*argv);
108
109 if (rflag) {
110 if (!(fts = fts_open(++argv, FTS_NOSTAT|FTS_PHYSICAL, 0))) {
111 (void)fprintf(stderr,
112 "%s: %s.\n", myname, strerror(errno));
113 exit(1);
114 }
115 while (p = fts_read(fts)) {
116 if (p->fts_info == FTS_D)
117 continue;
118 if (p->fts_info == FTS_ERR) {
119 error(p->fts_path);
120 continue;
121 }
122 if (chown(p->fts_accpath, uid, gid) && !fflag)
123 chownerr(p->fts_path);
124 }
125 exit(retval);
126 }
127 while (*++argv)
128 if (chown(*argv, uid, gid) && !fflag)
129 chownerr(*argv);
130 exit(retval);
131 }
132
133 a_gid(s)
134 register char *s;
135 {
136 struct group *gr;
137
138 if (!*s) {
139 gid = -1; /* argument was "uid." */
140 return;
141 }
142 gname = s;
143 if (gr = getgrnam(s))
144 gid = gr->gr_gid;
145 else {
146 for (; *s && isdigit(*s); ++s);
147 if (!*s)
148 gid = atoi(gname);
149 else {
150 (void)fprintf(stderr, "%s: unknown group id: %s\n",
151 myname, gname);
152 exit(1);
153 }
154 }
155 }
156
157 a_uid(s)
158 register char *s;
159 {
160 struct passwd *pw;
161 char *uname;
162
163 if (!*s) {
164 uid = -1; /* argument was ".gid" */
165 return;
166 }
167 if (pw = getpwnam(s))
168 uid = pw->pw_uid;
169 else {
170 for (uname = s; *s && isdigit(*s); ++s);
171 if (!*s)
172 uid = atoi(uname);
173 else {
174 (void)fprintf(stderr,
175 "chown: unknown user id: %s\n", uname);
176 exit(1);
177 }
178 }
179 }
180
181 chownerr(file)
182 char *file;
183 {
184 static int euid = -1, ngroups = -1;
185
186 /* check for chown without being root */
187 if (errno != EPERM || uid != -1 && euid == -1 && (euid = geteuid())) {
188 if (fflag)
189 exit(0);
190 error(file);
191 exit(1);
192 }
193 /* check group membership; kernel just returns EPERM */
194 if (gid != -1 && ngroups == -1) {
195 int groups[NGROUPS];
196
197 ngroups = getgroups(NGROUPS, groups);
198 while (--ngroups >= 0 && gid != groups[ngroups]);
199 if (ngroups < 0) {
200 if (fflag)
201 exit(0);
202 (void)fprintf(stderr,
203 "%s: you are not a member of group %s.\n",
204 myname, gname);
205 exit(1);
206 }
207 }
208 if (!fflag)
209 error(file);
210 }
211
212 error(name)
213 char *name;
214 {
215 (void)fprintf(stderr, "%s: %s: %s\n", myname, name, strerror(errno));
216 retval = 1;
217 }
218
219 usage()
220 {
221 (void)fprintf(stderr, "usage: %s [-Rf] %s file ...\n", myname,
222 ischown ? "[owner][:group]" : "group");
223 exit(1);
224 }
225