source: trunk/minix/commands/simple/chmod.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 4.9 KB
Line 
1/* chmod - Change file modes Author: V. Archer */
2
3/* Copyright 1991 by Vincent Archer
4 * You may freely redistribute this software, in source or binary
5 * form, provided that you do not alter this copyright mention in any
6 * way.
7 */
8
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <dirent.h>
12#include <errno.h>
13#include <limits.h>
14#include <stdlib.h>
15#include <string.h>
16#include <unistd.h>
17#include <minix/minlib.h>
18#include <stdio.h>
19
20#ifndef S_ISLNK
21#define S_ISLNK(mode) 0
22#define lstat stat
23#endif
24
25#define USR_MODES (S_ISUID|S_IRWXU)
26#define GRP_MODES (S_ISGID|S_IRWXG)
27#define EXE_MODES (S_IXUSR|S_IXGRP|S_IXOTH)
28#ifdef S_ISVTX
29#define ALL_MODES (USR_MODES|GRP_MODES|S_IRWXO|S_ISVTX)
30#else
31#define ALL_MODES (USR_MODES|GRP_MODES|S_IRWXO)
32#endif
33
34
35/* Common variables */
36char *symbolic;
37mode_t new_mode, u_mask;
38int rflag, errors;
39struct stat st;
40char path[PATH_MAX + 1];
41
42_PROTOTYPE(int main, (int argc, char **argv));
43_PROTOTYPE(mode_t parsemode, (char *symbolic, mode_t oldmode));
44_PROTOTYPE(int do_change, (char *name));
45_PROTOTYPE(void usage, (void));
46
47/* Parse a P1003.2 4.7.7-conformant symbolic mode. */
48mode_t parsemode(char *symbolic, mode_t oldmode)
49{
50 mode_t who, mask, newmode, tmpmask;
51 char action;
52
53 newmode = oldmode & ALL_MODES;
54 while (*symbolic) {
55 who = 0;
56 for (; *symbolic; symbolic++) {
57 if (*symbolic == 'a') {
58 who |= ALL_MODES;
59 continue;
60 }
61 if (*symbolic == 'u') {
62 who |= USR_MODES;
63 continue;
64 }
65 if (*symbolic == 'g') {
66 who |= GRP_MODES;
67 continue;
68 }
69 if (*symbolic == 'o') {
70 who |= S_IRWXO;
71 continue;
72 }
73 break;
74 }
75 if (!*symbolic || *symbolic == ',') usage();
76 while (*symbolic) {
77 if (*symbolic == ',') break;
78 switch (*symbolic) {
79 default:
80 usage();
81 case '+':
82 case '-':
83 case '=': action = *symbolic++;
84 }
85 mask = 0;
86 for (; *symbolic; symbolic++) {
87 if (*symbolic == 'u') {
88 tmpmask = newmode & S_IRWXU;
89 mask |= tmpmask | (tmpmask << 3) | (tmpmask << 6);
90 symbolic++;
91 break;
92 }
93 if (*symbolic == 'g') {
94 tmpmask = newmode & S_IRWXG;
95 mask |= tmpmask | (tmpmask >> 3) | (tmpmask << 3);
96 symbolic++;
97 break;
98 }
99 if (*symbolic == 'o') {
100 tmpmask = newmode & S_IRWXO;
101 mask |= tmpmask | (tmpmask >> 3) | (tmpmask >> 6);
102 symbolic++;
103 break;
104 }
105 if (*symbolic == 'r') {
106 mask |= S_IRUSR | S_IRGRP | S_IROTH;
107 continue;
108 }
109 if (*symbolic == 'w') {
110 mask |= S_IWUSR | S_IWGRP | S_IWOTH;
111 continue;
112 }
113 if (*symbolic == 'x') {
114 mask |= EXE_MODES;
115 continue;
116 }
117 if (*symbolic == 's') {
118 mask |= S_ISUID | S_ISGID;
119 continue;
120 }
121 if (*symbolic == 'X') {
122 if (S_ISDIR(oldmode) || (oldmode & EXE_MODES))
123 mask |= EXE_MODES;
124 continue;
125 }
126#ifdef S_ISVTX
127 if (*symbolic == 't') {
128 mask |= S_ISVTX;
129 who |= S_ISVTX;
130 continue;
131 }
132#endif
133 break;
134 }
135 switch (action) {
136 case '=':
137 if (who)
138 newmode &= ~who;
139 else
140 newmode = 0;
141 case '+':
142 if (who)
143 newmode |= who & mask;
144 else
145 newmode |= mask & (~u_mask);
146 break;
147 case '-':
148 if (who)
149 newmode &= ~(who & mask);
150 else
151 newmode &= ~mask | u_mask;
152 }
153 }
154 if (*symbolic) symbolic++;
155 }
156 return(newmode);
157}
158
159
160/* Main module. The single option possible (-R) does not warrant a call to
161 * the getopt() stuff.
162 */
163int main(argc, argv)
164int argc;
165char *argv[];
166{
167 int ex_code = 0;
168
169 argc--;
170 argv++;
171
172 if (argc && strcmp(*argv, "-R") == 0) {
173 argc--;
174 argv++;
175 rflag = 1;
176 } else
177 rflag = 0;
178
179 if (!argc--) usage();
180 if (!strcmp(argv[0], "--")) { /* Allow chmod -- -r, as in Draft11 example */
181 if (!argc--) usage();
182 argv++;
183 }
184 symbolic = *argv++;
185 if (!argc) usage();
186
187 if (*symbolic >= '0' && *symbolic <= '7') {
188 new_mode = 0;
189 while (*symbolic >= '0' && *symbolic <= '7')
190 new_mode = (new_mode << 3) | (*symbolic++ & 07);
191 if (*symbolic) usage();
192 new_mode &= ALL_MODES;
193 symbolic = (char *) 0;
194 } else
195 u_mask = umask(0);
196
197 while (argc--)
198 if (do_change(*argv++)) ex_code = 1;
199 return(ex_code);
200}
201
202
203/* Apply a mode change to a given file system element. */
204int do_change(name)
205char *name;
206{
207 mode_t m;
208 DIR *dirp;
209 struct dirent *entp;
210 char *namp;
211
212 if (lstat(name, &st)) {
213 perror(name);
214 return(1);
215 }
216 if (S_ISLNK(st.st_mode) && rflag) return(0); /* Note: violates POSIX. */
217 if (!symbolic)
218 m = new_mode;
219 else
220 m = parsemode(symbolic, st.st_mode);
221 if (chmod(name, m)) {
222 perror(name);
223 errors = 1;
224 } else
225 errors = 0;
226
227 if (S_ISDIR(st.st_mode) && rflag) {
228 if (!(dirp = opendir(name))) {
229 perror(name);
230 return(1);
231 }
232 if (name != path) strcpy(path, name);
233 namp = path + strlen(path);
234 *namp++ = '/';
235 while (entp = readdir(dirp))
236 if (entp->d_name[0] != '.' ||
237 (entp->d_name[1] &&
238 (entp->d_name[1] != '.' || entp->d_name[2]))) {
239 strcpy(namp, entp->d_name);
240 errors |= do_change(path);
241 }
242 closedir(dirp);
243 *--namp = '\0';
244 }
245 return(errors);
246}
247
248
249/* Display Posix prototype */
250void usage()
251{
252 std_err("Usage: chmod [-R] mode file...\n");
253 exit(1);
254}
Note: See TracBrowser for help on using the repository browser.