Commit | Line | Data |
---|---|---|
bcf1365c | 1 | /* |
8cc66a82 | 2 | * Copyright (c) 1980, 1988 Regents of the University of California. |
bcf1365c DF |
3 | * All rights reserved. The Berkeley software License Agreement |
4 | * specifies the terms and conditions for redistribution. | |
5 | */ | |
6 | ||
7 | #ifndef lint | |
8cc66a82 KB |
8 | char copyright[] = |
9 | "@(#) Copyright (c) 1980, 1988 Regents of the University of California.\n\ | |
10 | All rights reserved.\n"; | |
11 | #endif /* not lint */ | |
12 | ||
13 | #ifndef lint | |
14 | static char sccsid[] = "@(#)chmod.c 5.7 (Berkeley) %G%"; | |
15 | #endif /* not lint */ | |
473911a1 KL |
16 | |
17 | /* | |
18 | * chmod options mode files | |
19 | * where | |
3d6dbb93 SL |
20 | * mode is [ugoa][+-=][rwxXstugo] or an octal number |
21 | * options are -Rf | |
473911a1 KL |
22 | */ |
23 | #include <stdio.h> | |
24 | #include <sys/types.h> | |
25 | #include <sys/stat.h> | |
26 | #include <sys/dir.h> | |
27 | ||
8cc66a82 KB |
28 | static int fflag, rflag, retval, um; |
29 | static char *modestring, *ms; | |
473911a1 | 30 | |
3d6dbb93 | 31 | main(argc, argv) |
8cc66a82 KB |
32 | int argc; |
33 | char **argv; | |
473911a1 | 34 | { |
8cc66a82 KB |
35 | extern char *optarg; |
36 | extern int optind, opterr; | |
37 | int ch; | |
3d6dbb93 | 38 | |
8cc66a82 KB |
39 | /* |
40 | * since "-[rwx]" etc. are valid file modes, we don't let getopt(3) | |
41 | * print error messages, and we mess around with optind as necessary. | |
42 | */ | |
43 | opterr = 0; | |
44 | while ((ch = getopt(argc, argv, "Rf")) != EOF) | |
45 | switch((char)ch) { | |
3d6dbb93 | 46 | case 'R': |
fe196551 | 47 | rflag++; |
3d6dbb93 | 48 | break; |
3d6dbb93 SL |
49 | case 'f': |
50 | fflag++; | |
51 | break; | |
8cc66a82 | 52 | case '?': |
3d6dbb93 | 53 | default: |
8cc66a82 | 54 | --optind; |
3d6dbb93 | 55 | goto done; |
fe196551 | 56 | } |
8cc66a82 KB |
57 | done: argv += optind; |
58 | argc -= optind; | |
59 | ||
60 | if (argc < 2) { | |
61 | fputs("usage: chmod [-Rf] [ugoa][+-=][rwxXstugo] file ...\n", | |
62 | stderr); | |
63 | exit(-1); | |
473911a1 | 64 | } |
8cc66a82 KB |
65 | |
66 | modestring = *argv; | |
473911a1 | 67 | um = umask(0); |
8cc66a82 KB |
68 | (void)newmode((u_short)0); |
69 | ||
70 | while (*++argv) | |
71 | change(*argv); | |
72 | exit(retval); | |
473911a1 KL |
73 | } |
74 | ||
8cc66a82 KB |
75 | change(file) |
76 | char *file; | |
473911a1 | 77 | { |
3d6dbb93 SL |
78 | register DIR *dirp; |
79 | register struct direct *dp; | |
8cc66a82 | 80 | struct stat buf; |
473911a1 | 81 | |
8cc66a82 KB |
82 | if (lstat(file, &buf) || chmod(file, newmode(buf.st_mode))) { |
83 | err(file); | |
84 | return; | |
44de549b | 85 | } |
8cc66a82 KB |
86 | if (rflag && ((buf.st_mode & S_IFMT) == S_IFDIR)) { |
87 | if (chdir(file) < 0 || !(dirp = opendir("."))) { | |
88 | err(file); | |
89 | return; | |
3d6dbb93 | 90 | } |
8cc66a82 KB |
91 | for (dp = readdir(dirp); dp; dp = readdir(dirp)) { |
92 | if (dp->d_name[0] == '.' && (!dp->d_name[1] || | |
93 | dp->d_name[1] == '.' && !dp->d_name[2])) | |
94 | continue; | |
95 | change(dp->d_name); | |
96 | } | |
97 | closedir(dirp); | |
98 | if (chdir("..")) { | |
99 | err(".."); | |
100 | exit(fflag ? 0 : -1); | |
e4261a61 | 101 | } |
3d6dbb93 | 102 | } |
3d6dbb93 SL |
103 | } |
104 | ||
8cc66a82 | 105 | err(s) |
3d6dbb93 SL |
106 | char *s; |
107 | { | |
8cc66a82 KB |
108 | if (fflag) |
109 | return; | |
110 | fputs("chmod: ", stderr); | |
111 | perror(s); | |
112 | retval = -1; | |
473911a1 KL |
113 | } |
114 | ||
115 | newmode(nm) | |
8cc66a82 | 116 | u_short nm; |
473911a1 | 117 | { |
8cc66a82 | 118 | register int o, m, b; |
473911a1 KL |
119 | |
120 | ms = modestring; | |
473911a1 | 121 | m = abs(); |
3d6dbb93 SL |
122 | if (*ms == '\0') |
123 | return (m); | |
473911a1 KL |
124 | do { |
125 | m = who(); | |
126 | while (o = what()) { | |
8cc66a82 | 127 | b = where((int)nm); |
473911a1 KL |
128 | switch (o) { |
129 | case '+': | |
130 | nm |= b & m; | |
131 | break; | |
132 | case '-': | |
133 | nm &= ~(b & m); | |
134 | break; | |
135 | case '=': | |
136 | nm &= ~m; | |
137 | nm |= b & m; | |
138 | break; | |
139 | } | |
140 | } | |
141 | } while (*ms++ == ','); | |
8cc66a82 KB |
142 | if (*--ms) { |
143 | fputs("chmod: invalid mode.\n", stderr); | |
144 | exit(-1); | |
145 | } | |
146 | return ((int)nm); | |
473911a1 KL |
147 | } |
148 | ||
149 | abs() | |
150 | { | |
8cc66a82 | 151 | register int c, i; |
473911a1 KL |
152 | |
153 | i = 0; | |
154 | while ((c = *ms++) >= '0' && c <= '7') | |
155 | i = (i << 3) + (c - '0'); | |
156 | ms--; | |
3d6dbb93 | 157 | return (i); |
473911a1 KL |
158 | } |
159 | ||
3d6dbb93 SL |
160 | #define USER 05700 /* user's bits */ |
161 | #define GROUP 02070 /* group's bits */ | |
162 | #define OTHER 00007 /* other's bits */ | |
163 | #define ALL 01777 /* all (note absence of setuid, etc) */ | |
164 | ||
165 | #define READ 00444 /* read permit */ | |
166 | #define WRITE 00222 /* write permit */ | |
167 | #define EXEC 00111 /* exec permit */ | |
168 | #define SETID 06000 /* set[ug]id */ | |
169 | #define STICKY 01000 /* sticky bit */ | |
170 | ||
473911a1 KL |
171 | who() |
172 | { | |
8cc66a82 | 173 | register int m; |
473911a1 KL |
174 | |
175 | m = 0; | |
176 | for (;;) switch (*ms++) { | |
177 | case 'u': | |
178 | m |= USER; | |
179 | continue; | |
180 | case 'g': | |
181 | m |= GROUP; | |
182 | continue; | |
183 | case 'o': | |
184 | m |= OTHER; | |
185 | continue; | |
186 | case 'a': | |
187 | m |= ALL; | |
188 | continue; | |
189 | default: | |
190 | ms--; | |
191 | if (m == 0) | |
192 | m = ALL & ~um; | |
3d6dbb93 | 193 | return (m); |
473911a1 KL |
194 | } |
195 | } | |
196 | ||
197 | what() | |
198 | { | |
473911a1 KL |
199 | switch (*ms) { |
200 | case '+': | |
201 | case '-': | |
202 | case '=': | |
3d6dbb93 | 203 | return (*ms++); |
473911a1 | 204 | } |
3d6dbb93 | 205 | return (0); |
473911a1 KL |
206 | } |
207 | ||
208 | where(om) | |
8cc66a82 | 209 | register int om; |
473911a1 | 210 | { |
8cc66a82 | 211 | register int m; |
473911a1 KL |
212 | |
213 | m = 0; | |
214 | switch (*ms) { | |
215 | case 'u': | |
216 | m = (om & USER) >> 6; | |
217 | goto dup; | |
218 | case 'g': | |
219 | m = (om & GROUP) >> 3; | |
220 | goto dup; | |
221 | case 'o': | |
222 | m = (om & OTHER); | |
223 | dup: | |
224 | m &= (READ|WRITE|EXEC); | |
225 | m |= (m << 3) | (m << 6); | |
226 | ++ms; | |
3d6dbb93 | 227 | return (m); |
473911a1 KL |
228 | } |
229 | for (;;) switch (*ms++) { | |
230 | case 'r': | |
231 | m |= READ; | |
232 | continue; | |
233 | case 'w': | |
234 | m |= WRITE; | |
235 | continue; | |
236 | case 'x': | |
237 | m |= EXEC; | |
238 | continue; | |
358d0c96 | 239 | case 'X': |
e4261a61 KM |
240 | if ((om & S_IFDIR) || (om & EXEC)) |
241 | m |= EXEC; | |
358d0c96 | 242 | continue; |
473911a1 KL |
243 | case 's': |
244 | m |= SETID; | |
245 | continue; | |
246 | case 't': | |
247 | m |= STICKY; | |
248 | continue; | |
249 | default: | |
250 | ms--; | |
3d6dbb93 | 251 | return (m); |
473911a1 KL |
252 | } |
253 | } |