blob: 225c92d105de16a603ea75190adc748290a37292 [file] [log] [blame]
Eric Andersencc8ed391999-10-05 16:24:54 +00001#include <stdlib.h>
2#include <stdio.h>
3#include <unistd.h>
4#include <sys/stat.h>
5#include "internal.h"
6
7const char chmod_usage[] = "chmod [-R] mode file [file ...]\n"
8"\nmode may be an octal integer representing the bit pattern for the\n"
9"\tnew mode, or a symbolic value matching the pattern\n"
10"\t[ugoa]{+|-|=}[rwxst] .\n"
11"\t\tu:\tUser\n"
12"\t\tg:\tGroup\n"
13"\t\to:\tOthers\n"
14"\t\ta:\tAll\n"
15"\n"
16"\n+:\tAdd privilege\n"
17"\n-:\tRemove privilege\n"
18"\n=:\tSet privilege\n"
19"\n"
20"\t\tr:\tRead\n"
21"\t\tw:\tWrite\n"
22"\t\tx:\tExecute\n"
23"\t\ts:\tSet User ID\n"
24"\t\tt:\t\"Sticky\" Text\n"
25"\n"
26"\tModes may be concatenated, as in \"u=rwx,g=rx,o=rx,-t,-s\n"
27"\n"
28"\t-R:\tRecursively change the mode of all files and directories\n"
29"\t\tunder the argument directory.";
30
31int
32parse_mode(
33 const char * s
34,mode_t * or
35,mode_t * and
36,int * group_execute)
37{
38 /* [ugoa]{+|-|=}[rwxstl] */
39 mode_t mode = 0;
40 mode_t groups = S_ISVTX;
41 char type;
42 char c;
43
44 do {
45 for ( ; ; ) {
46 switch ( c = *s++ ) {
47 case '\0':
48 return -1;
49 case 'u':
50 groups |= S_ISUID|S_IRWXU;
51 continue;
52 case 'g':
53 groups |= S_ISGID|S_IRWXG;
54 continue;
55 case 'o':
56 groups |= S_IRWXO;
57 continue;
58 case 'a':
59 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
60 continue;
61 case '+':
62 case '=':
63 case '-':
64 type = c;
65 if ( groups == S_ISVTX ) /* The default is "all" */
66 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
67 break;
68 default:
69 if ( c >= '0' && c <= '7' && mode == 0 && groups == S_ISVTX ) {
70 *and = 0;
71 *or = strtol(--s, 0, 010);
72 return 0;
73 }
74 else
75 return -1;
76 }
77 break;
78 }
79
80 while ( (c = *s++) != '\0' ) {
81 switch ( c ) {
82 case ',':
83 break;
84 case 'r':
85 mode |= S_IRUSR|S_IRGRP|S_IROTH;
86 continue;
87 case 'w':
88 mode |= S_IWUSR|S_IWGRP|S_IWOTH;
89 continue;
90 case 'x':
91 mode |= S_IXUSR|S_IXGRP|S_IXOTH;
92 continue;
93 case 's':
94 if ( group_execute != 0 && (groups & S_IRWXG) ) {
95 if ( *group_execute < 0 )
96 return -1;
97 if ( type != '-' ) {
98 mode |= S_IXGRP;
99 *group_execute = 1;
100 }
101 }
102 mode |= S_ISUID|S_ISGID;
103 continue;
104 case 'l':
105 if ( *group_execute > 0 )
106 return -1;
107 if ( type != '-' ) {
108 *and &= ~S_IXGRP;
109 *group_execute = -1;
110 }
111 mode |= S_ISGID;
112 groups |= S_ISGID;
113 continue;
114 case 't':
115 mode |= S_ISVTX;
116 continue;
117 default:
118 return -1;
119 }
120 break;
121 }
122 switch ( type ) {
123 case '=':
124 *and &= ~(groups);
125 /* fall through */
126 case '+':
127 *or |= mode & groups;
128 break;
129 case '-':
130 *and &= ~(mode & groups);
131 *or &= *and;
132 break;
133 }
134 } while ( c == ',' );
135 return 0;
136}
137
138extern int
139chmod_main(struct FileInfo * i, int argc, char * * argv)
140{
141 i->andWithMode = S_ISVTX|S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
142 i->orWithMode = 0;
143
144 while ( argc >= 3 ) {
145 if ( parse_mode(argv[1], &i->orWithMode, &i->andWithMode, 0)
146 == 0 ) {
147 argc--;
148 argv++;
149 }
150 else if ( strcmp(argv[1], "-R") == 0 ) {
151 i->recursive = 1;
152 argc--;
153 argv++;
154 }
155 else
156 break;
157 }
158
159 i->changeMode = 1;
160 i->complainInPostProcess = 1;
161
162 return monadic_main(i, argc, argv);
163}