$search
00001 /* 00002 Mode Muncher -- modemuncher.c 00003 961110 Claudio Terra 00004 00005 munch vb 00006 [ME monchen, perh. influenced by MF mangier to eat --more at MANGER] 00007 :to chew with a crunching sound: eat with relish 00008 :to chew food with a crunching sound: eat food with relish 00009 --munch-er n 00010 00011 The NeXT Digital Edition of Webster's Ninth New Collegiate Dictionary 00012 and Webster's Collegiate Thesaurus 00013 */ 00014 00015 /* struct for rwx <-> POSIX constant lookup tables */ 00016 struct modeLookup 00017 { 00018 char rwx; 00019 mode_t bits; 00020 }; 00021 00022 typedef struct modeLookup modeLookup; 00023 00024 static modeLookup modesel[] = 00025 { 00026 /* RWX char Posix Constant */ 00027 {'r', S_IRUSR}, 00028 {'w', S_IWUSR}, 00029 {'x', S_IXUSR}, 00030 00031 {'r', S_IRGRP}, 00032 {'w', S_IWGRP}, 00033 {'x', S_IXGRP}, 00034 00035 {'r', S_IROTH}, 00036 {'w', S_IWOTH}, 00037 {'x', S_IXOTH}, 00038 {0, (mode_t)-1} /* do not delete this line */ 00039 }; 00040 00041 00042 00043 static int rwxrwxrwx(mode_t *mode, const char *p) 00044 { 00045 int count; 00046 mode_t tmp_mode = *mode; 00047 00048 tmp_mode &= ~(S_ISUID | S_ISGID); /* turn off suid and sgid flags */ 00049 for (count=0; count<9; count ++) 00050 { 00051 if (*p == modesel[count].rwx) tmp_mode |= modesel[count].bits; /* set a bit */ 00052 else if (*p == '-') tmp_mode &= ~modesel[count].bits; /* clear a bit */ 00053 else if (*p=='s') switch(count) 00054 { 00055 case 2: /* turn on suid flag */ 00056 tmp_mode |= S_ISUID | S_IXUSR; 00057 break; 00058 00059 case 5: /* turn on sgid flag */ 00060 tmp_mode |= S_ISGID | S_IXGRP; 00061 break; 00062 00063 default: 00064 return -4; /* failed! -- bad rwxrwxrwx mode change */ 00065 break; 00066 } 00067 p++; 00068 } 00069 *mode = tmp_mode; 00070 return 0; 00071 } 00072 00073 static void modechopper(mode_t mode, char *p) 00074 { 00075 /* requires char p[10] */ 00076 int count; 00077 char *pp; 00078 00079 pp=p; 00080 00081 for (count=0; count<9; count ++) 00082 { 00083 if (mode & modesel[count].bits) *p = modesel[count].rwx; 00084 else *p='-'; 00085 00086 p++; 00087 } 00088 *p=0; /* to finish the string */ 00089 00090 /* dealing with suid and sgid flags */ 00091 if (mode & S_ISUID) pp[2] = (mode & S_IXUSR) ? 's' : 'S'; 00092 if (mode & S_ISGID) pp[5] = (mode & S_IXGRP) ? 's' : 'S'; 00093 00094 } 00095 00096 static int mode_munch(mode_t *mode, const char* p) 00097 { 00098 char op=0; 00099 mode_t affected_bits, ch_mode; 00100 int doneFlag = 0; 00101 #ifdef DEBUG 00102 char tmp[10]; 00103 #endif 00104 00105 #ifdef DEBUG 00106 modechopper(*mode, tmp); 00107 printf("modemuncher: got base mode = %s\n", tmp); 00108 #endif 00109 00110 while (!doneFlag) 00111 { 00112 /* step 0 -- clear temporary variables */ 00113 affected_bits=0; 00114 ch_mode=0; 00115 00116 /* step 1 -- who's affected? */ 00117 00118 #ifdef DEBUG 00119 printf("modemuncher step 1\n"); 00120 #endif 00121 00122 /* mode string given in rwxrwxrwx format */ 00123 if (*p== 'r' || *p == '-') return rwxrwxrwx(mode, p); 00124 00125 /* mode string given in ugoa+-=rwx format */ 00126 for ( ; ; p++) 00127 switch (*p) 00128 { 00129 case 'u': 00130 affected_bits |= 04700; 00131 break; 00132 00133 case 'g': 00134 affected_bits |= 02070; 00135 break; 00136 00137 case 'o': 00138 affected_bits |= 01007; 00139 break; 00140 00141 case 'a': 00142 affected_bits |= 07777; 00143 break; 00144 00145 /* ignore spaces */ 00146 case ' ': 00147 break; 00148 00149 00150 default: 00151 goto no_more_affected; 00152 } 00153 00154 no_more_affected: 00155 /* If none specified, affect all bits. */ 00156 if (affected_bits == 0) affected_bits = 07777; 00157 00158 /* step 2 -- how is it changed? */ 00159 00160 #ifdef DEBUG 00161 printf("modemuncher step 2 (*p='%c')\n", *p); 00162 #endif 00163 00164 switch (*p) 00165 { 00166 case '+': 00167 case '-': 00168 case '=': 00169 op = *p; 00170 break; 00171 00172 /* ignore spaces */ 00173 case ' ': 00174 break; 00175 00176 default: 00177 return -1; /* failed! -- bad operator */ 00178 } 00179 00180 00181 /* step 3 -- what are the changes? */ 00182 00183 #ifdef DEBUG 00184 printf("modemuncher step 3\n"); 00185 #endif 00186 00187 for (p++ ; *p!=0 ; p++) 00188 switch (*p) 00189 { 00190 case 'r': 00191 ch_mode |= 00444; 00192 break; 00193 00194 case 'w': 00195 ch_mode |= 00222; 00196 break; 00197 00198 case 'x': 00199 ch_mode |= 00111; 00200 break; 00201 00202 case 's': 00203 /* Set the setuid/gid bits if `u' or `g' is selected. */ 00204 ch_mode |= 06000; 00205 break; 00206 00207 /* ignore spaces */ 00208 case ' ': 00209 break; 00210 00211 default: 00212 goto specs_done; 00213 } 00214 00215 specs_done: 00216 /* step 4 -- apply the changes */ 00217 00218 #ifdef DEBUG 00219 printf("modemuncher step 4\n"); 00220 #endif 00221 if (*p != ',') doneFlag = 1; 00222 if (*p != 0 && *p != ' ' && *p != ',') 00223 { 00224 00225 #ifdef DEBUG 00226 printf("modemuncher: comma error!\n"); 00227 printf("modemuncher: doneflag = %u\n", doneFlag); 00228 #endif 00229 return -2; /* failed! -- bad mode change */ 00230 00231 } 00232 p++; 00233 /*if (!ch_mode) return -2;*/ /* failed! -- bad mode change */ 00234 if (ch_mode) switch (op) 00235 { 00236 case '+': 00237 *mode |= ch_mode & affected_bits; 00238 break; 00239 00240 case '-': 00241 *mode &= ~(ch_mode & affected_bits); 00242 break; 00243 00244 case '=': 00245 *mode = ch_mode & affected_bits; 00246 break; 00247 00248 default: 00249 return -3; /* failed! -- unknown error */ 00250 } 00251 } 00252 #ifdef DEBUG 00253 modechopper(*mode, tmp); 00254 printf("modemuncher: returning mode = %s\n", tmp); 00255 #endif 00256 00257 return 0; /* successful call */ 00258 } 00259 00260