- initial import of revision 374 from cnc
[apt.git] / lua / local / modemuncher.c
1 /* 
2         Mode Muncher -- modemuncher.c
3         961110 Claudio Terra
4
5         munch vb
6         [ME monchen, perh. influenced by MF mangier to eat --more at MANGER]
7         :to chew with a crunching sound: eat with relish
8         :to chew food with a crunching sound: eat food with relish
9         --munch-er n
10                 
11         The NeXT Digital Edition of Webster's Ninth New Collegiate Dictionary
12         and Webster's Collegiate Thesaurus
13 */
14
15 /* struct for rwx <-> POSIX constant lookup tables */
16 struct modeLookup
17 {
18         char rwx;
19         mode_t bits;
20 };
21
22 typedef struct modeLookup modeLookup;
23
24 static modeLookup modesel[] =
25 {
26         /* RWX char                             Posix Constant */
27         {'r',                                   S_IRUSR},
28         {'w',                                   S_IWUSR},
29         {'x',                                   S_IXUSR},
30         
31         {'r',                                   S_IRGRP},
32         {'w',                                   S_IWGRP},
33         {'x',                                   S_IXGRP},
34         
35         {'r',                                   S_IROTH},
36         {'w',                                   S_IWOTH},
37         {'x',                                   S_IXOTH},
38         {(char)NULL,                                    (mode_t)-1} /* do not delete this line */
39 };
40
41
42
43 static int rwxrwxrwx(mode_t *mode, const char *p)
44 {
45         int count;
46         mode_t tmp_mode = *mode;
47         
48         tmp_mode &= ~(S_ISUID | S_ISGID); /* turn off suid and sgid flags */
49         for (count=0; count<9; count ++)
50         {
51                 if (*p == modesel[count].rwx) tmp_mode |= modesel[count].bits;  /* set a bit */
52                 else if (*p == '-') tmp_mode &= ~modesel[count].bits;                   /* clear a bit */
53                 else if (*p=='s') switch(count)
54                 {
55                         case 2: /* turn on suid flag */
56                         tmp_mode |= S_ISUID | S_IXUSR;
57                         break;
58                         
59                         case 5: /* turn on sgid flag */
60                         tmp_mode |= S_ISGID | S_IXGRP;
61                         break;
62
63                         default:
64                         return -4; /* failed! -- bad rwxrwxrwx mode change */
65                         break;
66                 }
67                 p++;
68         }
69         *mode = tmp_mode;
70         return 0;
71 }
72
73 static void modechopper(mode_t mode, char *p)
74 {
75         /* requires char p[10] */
76         int count;
77         char *pp;
78         
79         pp=p;
80         
81         for (count=0; count<9; count ++)
82         {
83                 if (mode & modesel[count].bits) *p = modesel[count].rwx;
84                 else *p='-';
85                 
86                 p++;
87         }
88         *p=0; /* to finish the string */
89         
90         /* dealing with suid and sgid flags */
91         if (mode & S_ISUID) pp[2] = (mode & S_IXUSR) ? 's' : 'S';
92         if (mode & S_ISGID) pp[5] = (mode & S_IXGRP) ? 's' : 'S';
93
94 }
95
96 static int mode_munch(mode_t *mode, const char* p)
97 {
98
99         char op=0;
100         mode_t affected_bits, ch_mode;
101         int doneFlag = 0;
102 #ifdef DEBUG
103 char tmp[10];
104 #endif
105
106 #ifdef DEBUG
107 modechopper(*mode, tmp);
108 printf("modemuncher: got base mode = %s\n", tmp);
109 #endif
110
111         while (!doneFlag)
112         {
113                 /* step 0 -- clear temporary variables */
114                 affected_bits=0;
115                 ch_mode=0;
116                 
117                 /* step 1 -- who's affected? */
118
119 #ifdef DEBUG
120 printf("modemuncher step 1\n");
121 #endif
122                 
123                 /* mode string given in rwxrwxrwx format */
124                 if (*p== 'r' || *p == '-') return rwxrwxrwx(mode, p);
125
126                 /* mode string given in 0644 format */
127                 if (*p >= '0' && *p <= '7') {
128                         char *e;
129                         mode_t tmp_mode = strtol(p, &e, 8);
130                         if (*p == 0 || *e != 0)
131                                 return -5;
132                         *mode = tmp_mode; 
133                         return 0;
134                 }
135                 
136                 /* mode string given in ugoa+-=rwx format */
137                 for ( ; ; p++)
138                         switch (*p)
139                         {
140                                 case 'u':
141                                 affected_bits |= 04700;
142                                 break;
143                                 
144                                 case 'g':
145                                 affected_bits |= 02070;
146                                 break;
147                                 
148                                 case 'o':
149                                 affected_bits |= 01007;
150                                 break;
151                                 
152                                 case 'a':
153                                 affected_bits |= 07777;
154                                 break;
155                                 
156                                 /* ignore spaces */
157                                 case ' ':
158                                 break;
159                                 
160                                 
161                                 default:
162                                 goto no_more_affected;
163                         }
164
165                 no_more_affected:
166                 /* If none specified, affect all bits. */
167                 if (affected_bits == 0) affected_bits = 07777;
168
169                 /* step 2 -- how is it changed? */
170                 
171 #ifdef DEBUG
172 printf("modemuncher step 2 (*p='%c')\n", *p);
173 #endif
174
175                 switch (*p)
176                 {
177                         case '+':
178                         case '-':
179                         case '=':
180                         op = *p;
181                         break;
182                         
183                         /* ignore spaces */
184                         case ' ':
185                         break;
186                         
187                         default:
188                         return -1; /* failed! -- bad operator */
189                 }
190                 
191                 
192                 /* step 3 -- what are the changes? */
193                 
194 #ifdef DEBUG
195 printf("modemuncher step 3\n");
196 #endif
197
198                 for (p++ ; *p!=0 ; p++)
199                         switch (*p)
200                         {
201                                 case 'r':
202                                 ch_mode |= 00444;
203                                 break;
204                                 
205                                 case 'w':
206                                 ch_mode |= 00222;
207                                 break;
208                                 
209                                 case 'x':
210                                 ch_mode |= 00111;
211                                 break;
212                                 
213                                 case 's':
214                                 /* Set the setuid/gid bits if `u' or `g' is selected. */
215                                 ch_mode |= 06000;
216                                 break;
217                         
218                                 /* ignore spaces */
219                                 case ' ':
220                                 break;
221                                 
222                                 default:
223                                 goto specs_done;
224                         }
225
226                 specs_done:
227                 /* step 4 -- apply the changes */
228
229 #ifdef DEBUG
230                 printf("modemuncher step 4\n");
231 #endif
232                 if (*p != ',') doneFlag = 1;
233                 if (*p != 0 && *p != ' ' && *p != ',')
234                 {
235                 
236 #ifdef DEBUG
237 printf("modemuncher: comma error!\n");
238 printf("modemuncher: doneflag = %u\n", doneFlag);
239 #endif
240                         return -2; /* failed! -- bad mode change */
241                 
242                 }
243                 p++;
244                 /*if (!ch_mode) return -2;*/ /* failed! -- bad mode change */
245                 if (ch_mode) switch (op)
246                 {
247                         case '+':
248                         *mode = *mode |= ch_mode & affected_bits;
249                         break;
250
251                         case '-':
252                         *mode = *mode &= ~(ch_mode & affected_bits);
253                         break;
254
255                         case '=':
256                         *mode = ch_mode & affected_bits;
257                         break;
258                 
259                         default:
260                         return -3; /* failed! -- unknown error */
261                 }
262         }
263 #ifdef DEBUG
264 modechopper(*mode, tmp);
265 printf("modemuncher: returning mode = %s\n", tmp);
266 #endif
267
268         return 0; /* successful call */
269 }
270
271