Commit | Line | Data |
---|---|---|
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 | 8 | static 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 |
22 | char *modestring, *ms; |
23 | int um; | |
24 | int status; | |
3d6dbb93 SL |
25 | int fflag; |
26 | int rflag; | |
473911a1 | 27 | |
3d6dbb93 SL |
28 | main(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 | 57 | done: |
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 | ||
84 | chmodr(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 | ||
136 | error(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 | ||
148 | fatal(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 | ||
158 | Perror(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 | ||
169 | newmode(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 | ||
203 | abs() | |
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 |
225 | who() |
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 | ||
251 | what() | |
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 | ||
263 | where(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 | } |