Finally mount works properly. Made debugging work (no more -s ld flag
[oweals/busybox.git] / chmod.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <sys/stat.h>
5 #include "internal.h"
6
7 const 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
31 int
32 parse_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
138 extern int
139 chmod_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 }