add Berkeley copyright
[unix-history] / usr / src / bin / chmod / chmod.c
CommitLineData
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
8char 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
14static 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
28static int fflag, rflag, retval, um;
29static char *modestring, *ms;
473911a1 30
3d6dbb93 31main(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
57done: 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
75change(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 105err(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
115newmode(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
149abs()
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
171who()
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
197what()
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
208where(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}