Commit | Line | Data |
---|---|---|
358d0c96 | 1 | static char *sccsid = "@(#)chmod.c 4.4 %G%"; |
473911a1 KL |
2 | |
3 | /* | |
4 | * chmod options mode files | |
5 | * where | |
6 | * mode is [ugoa][+-=][rwxstugo] or a octal number | |
7 | * options are -R | |
8 | */ | |
9 | #include <stdio.h> | |
10 | #include <sys/types.h> | |
11 | #include <sys/stat.h> | |
12 | #include <sys/dir.h> | |
13 | ||
14 | #define USER 05700 /* user's bits */ | |
15 | #define GROUP 02070 /* group's bits */ | |
16 | #define OTHER 00007 /* other's bits */ | |
17 | #define ALL 01777 /* all (note absence of setuid, etc) */ | |
18 | ||
19 | #define READ 00444 /* read permit */ | |
20 | #define WRITE 00222 /* write permit */ | |
21 | #define EXEC 00111 /* exec permit */ | |
22 | #define SETID 06000 /* set[ug]id */ | |
23 | #define STICKY 01000 /* sticky bit */ | |
24 | ||
25 | char *modestring, *ms; | |
26 | int um; | |
27 | int status; | |
8e2196fc | 28 | int rflag, debug, Xflag; |
473911a1 KL |
29 | |
30 | main(argc,argv) | |
31 | char **argv; | |
32 | { | |
33 | register i; | |
8e2196fc | 34 | register char *p, *flags; |
473911a1 KL |
35 | struct stat st; |
36 | ||
37 | if (argc < 3) { | |
38 | fprintf(stderr | |
8e2196fc | 39 | ,"Usage: chmod [-RX] [ugoa][+-=][rwxstugo] file ...\n"); |
473911a1 KL |
40 | exit(-1); |
41 | } | |
8e2196fc | 42 | |
473911a1 | 43 | argv++, --argc; |
8e2196fc KL |
44 | if (*argv[0] == '-') { |
45 | for (flags = argv[0]; *flags; ++flags) | |
46 | switch (*flags) { | |
47 | case '-': break; | |
48 | case 'R': rflag++; break; | |
49 | case 'X': Xflag++; break; | |
50 | } | |
51 | argv++, argc--; | |
473911a1 | 52 | } |
8e2196fc | 53 | |
473911a1 KL |
54 | modestring = argv[0]; |
55 | ||
56 | um = umask(0); | |
57 | (void) newmode(0); | |
58 | for (i = 1; i < argc; i++) { | |
59 | p = argv[i]; | |
358d0c96 | 60 | if (stat(p, &st) < 0) { |
473911a1 KL |
61 | fprintf(stderr, "chmod: can't access %s\n", p); |
62 | ++status; | |
63 | continue; | |
64 | } | |
65 | if (rflag && st.st_mode & S_IFDIR) { | |
66 | status += chmodr(p, newmode(st.st_mode)); | |
67 | } else if (chmod(p, newmode(st.st_mode)) < 0) { | |
68 | fprintf(stderr, "chmod: can't change %s\n", p); | |
69 | ++status; | |
70 | continue; | |
71 | } | |
72 | } | |
73 | exit(status); | |
74 | } | |
75 | ||
76 | chmodr(dir, mode) | |
77 | char *dir; | |
78 | { | |
79 | #define CHECK(name,sbuf)\ | |
358d0c96 | 80 | if (stat(name, sbuf) < 0) {\ |
473911a1 KL |
81 | fprintf(stderr, "chmod: can't access %s\n", dp->d_name);\ |
82 | return(1);\ | |
83 | } | |
84 | ||
85 | register DIR *dirp; | |
86 | register struct direct *dp; | |
87 | register struct stat st; | |
88 | char savedir[1024]; | |
89 | ||
90 | if (getwd(savedir) == 0) { | |
91 | fprintf(stderr, "chmod: %s\n", savedir); | |
92 | exit(255); | |
93 | } | |
94 | ||
95 | /* | |
96 | ** chmod what we are given before doing it's contents | |
97 | */ | |
98 | chmod(dir, newmode(mode)); | |
99 | ||
100 | chdir(dir); | |
101 | if ((dirp = opendir(".")) == NULL) { | |
102 | perror(dir); | |
103 | return(1); | |
104 | } | |
105 | dp = readdir(dirp); | |
106 | dp = readdir(dirp); /* read "." and ".." */ | |
107 | for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { | |
108 | CHECK(dp->d_name, &st); | |
109 | chmod(dp->d_name, newmode(st.st_mode)); | |
110 | if (st.st_mode & S_IFDIR) | |
111 | chmodr(dp->d_name, mode); | |
112 | } | |
113 | closedir(dirp); | |
114 | chdir(savedir); | |
115 | return(0); | |
116 | } | |
117 | ||
118 | newmode(nm) | |
119 | unsigned nm; | |
120 | { | |
121 | register o, m, b; | |
122 | int savem; | |
123 | ||
124 | ms = modestring; | |
125 | savem = nm; | |
126 | m = abs(); | |
127 | if (!*ms) { | |
128 | nm = m; | |
129 | goto ret; | |
130 | } | |
131 | do { | |
132 | m = who(); | |
133 | while (o = what()) { | |
134 | b = where(nm); | |
135 | switch (o) { | |
136 | case '+': | |
137 | nm |= b & m; | |
138 | break; | |
139 | case '-': | |
140 | nm &= ~(b & m); | |
141 | break; | |
142 | case '=': | |
143 | nm &= ~m; | |
144 | nm |= b & m; | |
145 | break; | |
146 | } | |
147 | } | |
148 | } while (*ms++ == ','); | |
149 | if (*--ms) { | |
150 | fprintf(stderr, "chmod: invalid mode\n"); | |
151 | exit(255); | |
152 | } | |
153 | ret: | |
8e2196fc KL |
154 | if (Xflag && ((savem & S_IFDIR) || (savem & S_IEXEC))) |
155 | nm = nm | ((nm & 0444) >> 2); | |
473911a1 KL |
156 | return(nm); |
157 | } | |
158 | ||
159 | abs() | |
160 | { | |
161 | register c, i; | |
162 | ||
163 | i = 0; | |
164 | while ((c = *ms++) >= '0' && c <= '7') | |
165 | i = (i << 3) + (c - '0'); | |
166 | ms--; | |
167 | return(i); | |
168 | } | |
169 | ||
170 | who() | |
171 | { | |
172 | register m; | |
173 | ||
174 | m = 0; | |
175 | for (;;) switch (*ms++) { | |
176 | case 'u': | |
177 | m |= USER; | |
178 | continue; | |
179 | case 'g': | |
180 | m |= GROUP; | |
181 | continue; | |
182 | case 'o': | |
183 | m |= OTHER; | |
184 | continue; | |
185 | case 'a': | |
186 | m |= ALL; | |
187 | continue; | |
188 | default: | |
189 | ms--; | |
190 | if (m == 0) | |
191 | m = ALL & ~um; | |
192 | return m; | |
193 | } | |
194 | } | |
195 | ||
196 | what() | |
197 | { | |
198 | ||
199 | switch (*ms) { | |
200 | case '+': | |
201 | case '-': | |
202 | case '=': | |
203 | return *ms++; | |
204 | } | |
205 | return(0); | |
206 | } | |
207 | ||
208 | where(om) | |
209 | register om; | |
210 | { | |
211 | register m; | |
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; | |
227 | return m; | |
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 RC |
239 | case 'X': |
240 | Xflag++; | |
241 | continue; | |
473911a1 KL |
242 | case 's': |
243 | m |= SETID; | |
244 | continue; | |
245 | case 't': | |
246 | m |= STICKY; | |
247 | continue; | |
248 | default: | |
249 | ms--; | |
250 | return m; | |
251 | } | |
252 | } |