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 | |
3d6dbb93 SL |
8 | static char sccsid[] = "@(#)chmod.c 5.4 (Berkeley) %G%"; |
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 */ |
358d0c96 | 64 | if (stat(p, &st) < 0) { |
3d6dbb93 | 65 | status += error("can't access %s", p); |
473911a1 KL |
66 | continue; |
67 | } | |
3d6dbb93 | 68 | if (rflag && st.st_mode&S_IFDIR) { |
473911a1 | 69 | status += chmodr(p, newmode(st.st_mode)); |
3d6dbb93 SL |
70 | continue; |
71 | } | |
72 | if (chmod(p, newmode(st.st_mode)) < 0) { | |
73 | status += error("can't change %s", p); | |
473911a1 KL |
74 | continue; |
75 | } | |
76 | } | |
77 | exit(status); | |
78 | } | |
79 | ||
80 | chmodr(dir, mode) | |
3d6dbb93 | 81 | char *dir; |
473911a1 | 82 | { |
3d6dbb93 SL |
83 | register DIR *dirp; |
84 | register struct direct *dp; | |
85 | register struct stat st; | |
86 | char savedir[1024]; | |
87 | int ecode; | |
473911a1 | 88 | |
3d6dbb93 SL |
89 | if (getwd(savedir) == 0) |
90 | fatal(255, "%s", savedir); | |
473911a1 | 91 | /* |
3d6dbb93 SL |
92 | * Change what we are given before doing it's contents |
93 | */ | |
94 | if (chmod(dir, newmode(mode)) < 0 && error("can't change %s", dir)) | |
95 | return (1); | |
96 | if (chdir(dir) < 0) | |
97 | return (Perror(dir)); | |
98 | if ((dirp = opendir(".")) == NULL) | |
99 | return (Perror(dir)); | |
473911a1 KL |
100 | dp = readdir(dirp); |
101 | dp = readdir(dirp); /* read "." and ".." */ | |
3d6dbb93 | 102 | ecode = 0; |
473911a1 | 103 | for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { |
3d6dbb93 SL |
104 | if (lstat(dp->d_name, &st) < 0) { |
105 | ecode = error("can't access %s", dp->d_name); | |
106 | if (ecode) | |
107 | break; | |
108 | continue; | |
109 | } | |
110 | if (st.st_mode&S_IFDIR) { | |
111 | ecode = chmodr(dp->d_name, newmode(st.st_mode)); | |
112 | if (ecode) | |
113 | break; | |
114 | continue; | |
e4261a61 | 115 | } |
3d6dbb93 SL |
116 | if (chmod(dp->d_name, newmode(st.st_mode)) < 0 && |
117 | (ecode = error("can't change %s", dp->d_name))) | |
118 | break; | |
473911a1 KL |
119 | } |
120 | closedir(dirp); | |
3d6dbb93 SL |
121 | if (chdir(savedir) < 0) |
122 | fatal(255, "can't change back to %s", savedir); | |
123 | return (ecode); | |
124 | } | |
125 | ||
126 | error(fmt, a) | |
127 | char *fmt, *a; | |
128 | { | |
129 | ||
130 | if (!fflag) { | |
131 | fprintf(stderr, "chmod: "); | |
132 | fprintf(stderr, fmt, a); | |
133 | putc('\n', stderr); | |
134 | } | |
135 | return (!fflag); | |
136 | } | |
137 | ||
138 | fatal(status, fmt, a) | |
139 | int status; | |
140 | char *fmt, *a; | |
141 | { | |
142 | ||
143 | fflag = 0; | |
144 | (void) error(fmt, a); | |
145 | exit(status); | |
146 | } | |
147 | ||
148 | Perror(s) | |
149 | char *s; | |
150 | { | |
151 | ||
152 | fprintf(stderr, "chmod: "); | |
153 | perror(s); | |
154 | return (1); | |
473911a1 KL |
155 | } |
156 | ||
157 | newmode(nm) | |
3d6dbb93 | 158 | unsigned nm; |
473911a1 KL |
159 | { |
160 | register o, m, b; | |
161 | int savem; | |
162 | ||
163 | ms = modestring; | |
164 | savem = nm; | |
165 | m = abs(); | |
3d6dbb93 SL |
166 | if (*ms == '\0') |
167 | return (m); | |
473911a1 KL |
168 | do { |
169 | m = who(); | |
170 | while (o = what()) { | |
171 | b = where(nm); | |
172 | switch (o) { | |
173 | case '+': | |
174 | nm |= b & m; | |
175 | break; | |
176 | case '-': | |
177 | nm &= ~(b & m); | |
178 | break; | |
179 | case '=': | |
180 | nm &= ~m; | |
181 | nm |= b & m; | |
182 | break; | |
183 | } | |
184 | } | |
185 | } while (*ms++ == ','); | |
3d6dbb93 SL |
186 | if (*--ms) |
187 | fatal(255, "invalid mode"); | |
188 | return (nm); | |
473911a1 KL |
189 | } |
190 | ||
191 | abs() | |
192 | { | |
193 | register c, i; | |
194 | ||
195 | i = 0; | |
196 | while ((c = *ms++) >= '0' && c <= '7') | |
197 | i = (i << 3) + (c - '0'); | |
198 | ms--; | |
3d6dbb93 | 199 | return (i); |
473911a1 KL |
200 | } |
201 | ||
3d6dbb93 SL |
202 | #define USER 05700 /* user's bits */ |
203 | #define GROUP 02070 /* group's bits */ | |
204 | #define OTHER 00007 /* other's bits */ | |
205 | #define ALL 01777 /* all (note absence of setuid, etc) */ | |
206 | ||
207 | #define READ 00444 /* read permit */ | |
208 | #define WRITE 00222 /* write permit */ | |
209 | #define EXEC 00111 /* exec permit */ | |
210 | #define SETID 06000 /* set[ug]id */ | |
211 | #define STICKY 01000 /* sticky bit */ | |
212 | ||
473911a1 KL |
213 | who() |
214 | { | |
215 | register m; | |
216 | ||
217 | m = 0; | |
218 | for (;;) switch (*ms++) { | |
219 | case 'u': | |
220 | m |= USER; | |
221 | continue; | |
222 | case 'g': | |
223 | m |= GROUP; | |
224 | continue; | |
225 | case 'o': | |
226 | m |= OTHER; | |
227 | continue; | |
228 | case 'a': | |
229 | m |= ALL; | |
230 | continue; | |
231 | default: | |
232 | ms--; | |
233 | if (m == 0) | |
234 | m = ALL & ~um; | |
3d6dbb93 | 235 | return (m); |
473911a1 KL |
236 | } |
237 | } | |
238 | ||
239 | what() | |
240 | { | |
241 | ||
242 | switch (*ms) { | |
243 | case '+': | |
244 | case '-': | |
245 | case '=': | |
3d6dbb93 | 246 | return (*ms++); |
473911a1 | 247 | } |
3d6dbb93 | 248 | return (0); |
473911a1 KL |
249 | } |
250 | ||
251 | where(om) | |
3d6dbb93 | 252 | register om; |
473911a1 KL |
253 | { |
254 | register m; | |
255 | ||
256 | m = 0; | |
257 | switch (*ms) { | |
258 | case 'u': | |
259 | m = (om & USER) >> 6; | |
260 | goto dup; | |
261 | case 'g': | |
262 | m = (om & GROUP) >> 3; | |
263 | goto dup; | |
264 | case 'o': | |
265 | m = (om & OTHER); | |
266 | dup: | |
267 | m &= (READ|WRITE|EXEC); | |
268 | m |= (m << 3) | (m << 6); | |
269 | ++ms; | |
3d6dbb93 | 270 | return (m); |
473911a1 KL |
271 | } |
272 | for (;;) switch (*ms++) { | |
273 | case 'r': | |
274 | m |= READ; | |
275 | continue; | |
276 | case 'w': | |
277 | m |= WRITE; | |
278 | continue; | |
279 | case 'x': | |
280 | m |= EXEC; | |
281 | continue; | |
358d0c96 | 282 | case 'X': |
e4261a61 KM |
283 | if ((om & S_IFDIR) || (om & EXEC)) |
284 | m |= EXEC; | |
358d0c96 | 285 | continue; |
473911a1 KL |
286 | case 's': |
287 | m |= SETID; | |
288 | continue; | |
289 | case 't': | |
290 | m |= STICKY; | |
291 | continue; | |
292 | default: | |
293 | ms--; | |
3d6dbb93 | 294 | return (m); |
473911a1 KL |
295 | } |
296 | } |