minor cleanups, clarify -f flag
[unix-history] / usr / src / bin / chmod / chmod.c
CommitLineData
bcf1365c
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
eb1c99ef 8static char sccsid[] = "@(#)chmod.c 5.6 (Berkeley) %G%";
3d6dbb93 9#endif
473911a1
KL
10
11/*
12 * chmod options mode files
13 * where
3d6dbb93
SL
14 * mode is [ugoa][+-=][rwxXstugo] or an octal number
15 * options are -Rf
473911a1
KL
16 */
17#include <stdio.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <sys/dir.h>
21
473911a1
KL
22char *modestring, *ms;
23int um;
24int status;
3d6dbb93
SL
25int fflag;
26int rflag;
473911a1 27
3d6dbb93
SL
28main(argc, argv)
29 char *argv[];
473911a1 30{
8e2196fc 31 register char *p, *flags;
3d6dbb93
SL
32 register int i;
33 struct stat st;
473911a1
KL
34
35 if (argc < 3) {
3d6dbb93
SL
36 fprintf(stderr,
37 "Usage: chmod [-Rf] [ugoa][+-=][rwxXstugo] file ...\n");
473911a1
KL
38 exit(-1);
39 }
40 argv++, --argc;
3d6dbb93
SL
41 while (argc > 0 && argv[0][0] == '-') {
42 for (p = &argv[0][1]; *p; p++) switch (*p) {
43
44 case 'R':
fe196551 45 rflag++;
3d6dbb93
SL
46 break;
47
48 case 'f':
49 fflag++;
50 break;
51
52 default:
53 goto done;
fe196551 54 }
3d6dbb93 55 argc--, argv++;
473911a1 56 }
3d6dbb93 57done:
473911a1 58 modestring = argv[0];
473911a1
KL
59 um = umask(0);
60 (void) newmode(0);
61 for (i = 1; i < argc; i++) {
62 p = argv[i];
3d6dbb93 63 /* do stat for directory arguments */
44de549b
KM
64 if (lstat(p, &st) < 0) {
65 status += Perror(p);
473911a1
KL
66 continue;
67 }
44de549b 68 if (rflag && (st.st_mode&S_IFMT) == S_IFDIR) {
473911a1 69 status += chmodr(p, newmode(st.st_mode));
3d6dbb93
SL
70 continue;
71 }
44de549b
KM
72 if ((st.st_mode&S_IFMT) == S_IFLNK && stat(p, &st) < 0) {
73 status += Perror(p);
74 continue;
75 }
3d6dbb93 76 if (chmod(p, newmode(st.st_mode)) < 0) {
44de549b 77 status += Perror(p);
473911a1
KL
78 continue;
79 }
80 }
81 exit(status);
82}
83
84chmodr(dir, mode)
3d6dbb93 85 char *dir;
473911a1 86{
3d6dbb93
SL
87 register DIR *dirp;
88 register struct direct *dp;
eb1c99ef 89 struct stat st;
3d6dbb93
SL
90 char savedir[1024];
91 int ecode;
473911a1 92
3d6dbb93
SL
93 if (getwd(savedir) == 0)
94 fatal(255, "%s", savedir);
473911a1 95 /*
3d6dbb93
SL
96 * Change what we are given before doing it's contents
97 */
44de549b
KM
98 if (chmod(dir, newmode(mode)) < 0 && Perror(dir))
99 return (1);
100 if (chdir(dir) < 0) {
101 Perror(dir);
3d6dbb93 102 return (1);
44de549b
KM
103 }
104 if ((dirp = opendir(".")) == NULL) {
105 Perror(dir);
106 return (1);
107 }
473911a1
KL
108 dp = readdir(dirp);
109 dp = readdir(dirp); /* read "." and ".." */
3d6dbb93 110 ecode = 0;
473911a1 111 for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
3d6dbb93 112 if (lstat(dp->d_name, &st) < 0) {
44de549b 113 ecode = Perror(dp->d_name);
3d6dbb93
SL
114 if (ecode)
115 break;
116 continue;
117 }
44de549b 118 if ((st.st_mode&S_IFMT) == S_IFDIR) {
3d6dbb93
SL
119 ecode = chmodr(dp->d_name, newmode(st.st_mode));
120 if (ecode)
121 break;
122 continue;
e4261a61 123 }
44de549b
KM
124 if ((st.st_mode&S_IFMT) == S_IFLNK)
125 continue;
3d6dbb93 126 if (chmod(dp->d_name, newmode(st.st_mode)) < 0 &&
44de549b 127 (ecode = Perror(dp->d_name)))
3d6dbb93 128 break;
473911a1
KL
129 }
130 closedir(dirp);
3d6dbb93
SL
131 if (chdir(savedir) < 0)
132 fatal(255, "can't change back to %s", savedir);
133 return (ecode);
134}
135
136error(fmt, a)
137 char *fmt, *a;
138{
139
140 if (!fflag) {
141 fprintf(stderr, "chmod: ");
142 fprintf(stderr, fmt, a);
143 putc('\n', stderr);
144 }
145 return (!fflag);
146}
147
148fatal(status, fmt, a)
149 int status;
150 char *fmt, *a;
151{
152
153 fflag = 0;
154 (void) error(fmt, a);
155 exit(status);
156}
157
158Perror(s)
159 char *s;
160{
161
44de549b
KM
162 if (!fflag) {
163 fprintf(stderr, "chmod: ");
164 perror(s);
165 }
166 return (!fflag);
473911a1
KL
167}
168
169newmode(nm)
3d6dbb93 170 unsigned nm;
473911a1
KL
171{
172 register o, m, b;
173 int savem;
174
175 ms = modestring;
176 savem = nm;
177 m = abs();
3d6dbb93
SL
178 if (*ms == '\0')
179 return (m);
473911a1
KL
180 do {
181 m = who();
182 while (o = what()) {
183 b = where(nm);
184 switch (o) {
185 case '+':
186 nm |= b & m;
187 break;
188 case '-':
189 nm &= ~(b & m);
190 break;
191 case '=':
192 nm &= ~m;
193 nm |= b & m;
194 break;
195 }
196 }
197 } while (*ms++ == ',');
3d6dbb93
SL
198 if (*--ms)
199 fatal(255, "invalid mode");
200 return (nm);
473911a1
KL
201}
202
203abs()
204{
205 register c, i;
206
207 i = 0;
208 while ((c = *ms++) >= '0' && c <= '7')
209 i = (i << 3) + (c - '0');
210 ms--;
3d6dbb93 211 return (i);
473911a1
KL
212}
213
3d6dbb93
SL
214#define USER 05700 /* user's bits */
215#define GROUP 02070 /* group's bits */
216#define OTHER 00007 /* other's bits */
217#define ALL 01777 /* all (note absence of setuid, etc) */
218
219#define READ 00444 /* read permit */
220#define WRITE 00222 /* write permit */
221#define EXEC 00111 /* exec permit */
222#define SETID 06000 /* set[ug]id */
223#define STICKY 01000 /* sticky bit */
224
473911a1
KL
225who()
226{
227 register m;
228
229 m = 0;
230 for (;;) switch (*ms++) {
231 case 'u':
232 m |= USER;
233 continue;
234 case 'g':
235 m |= GROUP;
236 continue;
237 case 'o':
238 m |= OTHER;
239 continue;
240 case 'a':
241 m |= ALL;
242 continue;
243 default:
244 ms--;
245 if (m == 0)
246 m = ALL & ~um;
3d6dbb93 247 return (m);
473911a1
KL
248 }
249}
250
251what()
252{
253
254 switch (*ms) {
255 case '+':
256 case '-':
257 case '=':
3d6dbb93 258 return (*ms++);
473911a1 259 }
3d6dbb93 260 return (0);
473911a1
KL
261}
262
263where(om)
3d6dbb93 264 register om;
473911a1
KL
265{
266 register m;
267
268 m = 0;
269 switch (*ms) {
270 case 'u':
271 m = (om & USER) >> 6;
272 goto dup;
273 case 'g':
274 m = (om & GROUP) >> 3;
275 goto dup;
276 case 'o':
277 m = (om & OTHER);
278 dup:
279 m &= (READ|WRITE|EXEC);
280 m |= (m << 3) | (m << 6);
281 ++ms;
3d6dbb93 282 return (m);
473911a1
KL
283 }
284 for (;;) switch (*ms++) {
285 case 'r':
286 m |= READ;
287 continue;
288 case 'w':
289 m |= WRITE;
290 continue;
291 case 'x':
292 m |= EXEC;
293 continue;
358d0c96 294 case 'X':
e4261a61
KM
295 if ((om & S_IFDIR) || (om & EXEC))
296 m |= EXEC;
358d0c96 297 continue;
473911a1
KL
298 case 's':
299 m |= SETID;
300 continue;
301 case 't':
302 m |= STICKY;
303 continue;
304 default:
305 ms--;
3d6dbb93 306 return (m);
473911a1
KL
307 }
308}