avoid "ln -s nosuchfile non-writeable-dir" give misleading
[unix-history] / usr / src / bin / chmod / chmod.c
CommitLineData
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
8static 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
22char *modestring, *ms;
23int um;
24int status;
3d6dbb93
SL
25int fflag;
26int rflag;
473911a1 27
3d6dbb93
SL
28main(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 57done:
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
80chmodr(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
126error(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
138fatal(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
148Perror(s)
149 char *s;
150{
151
152 fprintf(stderr, "chmod: ");
153 perror(s);
154 return (1);
473911a1
KL
155}
156
157newmode(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
191abs()
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
213who()
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
239what()
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
251where(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}