1/* umask.c, created from umask.def. */ 2#line 23 "umask.def" 3 4#line 35 "umask.def" 5 6#include <config.h> 7 8#include "../bashtypes.h" 9#include "filecntl.h" 10#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H) 11# include <sys/file.h> 12#endif 13 14#if defined (HAVE_UNISTD_H) 15#include <unistd.h> 16#endif 17 18#include <stdio.h> 19#include <chartypes.h> 20 21#include "../bashintl.h" 22 23#include "../shell.h" 24#include "posixstat.h" 25#include "common.h" 26#include "bashgetopt.h" 27 28#ifdef __LCC__ 29#define mode_t int 30#endif 31 32/* **************************************************************** */ 33/* */ 34/* UMASK Builtin and Helpers */ 35/* */ 36/* **************************************************************** */ 37 38static void print_symbolic_umask __P((mode_t)); 39static int symbolic_umask __P((WORD_LIST *)); 40 41/* Set or display the mask used by the system when creating files. Flag 42 of -S means display the umask in a symbolic mode. */ 43int 44umask_builtin (list) 45 WORD_LIST *list; 46{ 47 int print_symbolically, opt, umask_value, pflag; 48 mode_t umask_arg; 49 50 print_symbolically = pflag = 0; 51 reset_internal_getopt (); 52 while ((opt = internal_getopt (list, "Sp")) != -1) 53 { 54 switch (opt) 55 { 56 case 'S': 57 print_symbolically++; 58 break; 59 case 'p': 60 pflag++; 61 break; 62 default: 63 builtin_usage (); 64 return (EX_USAGE); 65 } 66 } 67 68 list = loptend; 69 70 if (list) 71 { 72 if (DIGIT (*list->word->word)) 73 { 74 umask_value = read_octal (list->word->word); 75 76 /* Note that other shells just let you set the umask to zero 77 by specifying a number out of range. This is a problem 78 with those shells. We don't change the umask if the input 79 is lousy. */ 80 if (umask_value == -1) 81 { 82 sh_erange (list->word->word, _("octal number")); 83 return (EXECUTION_FAILURE); 84 } 85 } 86 else 87 { 88 umask_value = symbolic_umask (list); 89 if (umask_value == -1) 90 return (EXECUTION_FAILURE); 91 } 92 umask_arg = (mode_t)umask_value; 93 umask (umask_arg); 94 if (print_symbolically) 95 print_symbolic_umask (umask_arg); 96 } 97 else /* Display the UMASK for this user. */ 98 { 99 umask_arg = umask (022); 100 umask (umask_arg); 101 102 if (pflag) 103 printf ("umask%s ", (print_symbolically ? " -S" : "")); 104 if (print_symbolically) 105 print_symbolic_umask (umask_arg); 106 else 107 printf ("%04lo\n", (unsigned long)umask_arg); 108 } 109 110 fflush (stdout); 111 return (EXECUTION_SUCCESS); 112} 113 114/* Print the umask in a symbolic form. In the output, a letter is 115 printed if the corresponding bit is clear in the umask. */ 116static void 117print_symbolic_umask (um) 118 mode_t um; 119{ 120 char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */ 121 int i; 122 123 i = 0; 124 if ((um & S_IRUSR) == 0) 125 ubits[i++] = 'r'; 126 if ((um & S_IWUSR) == 0) 127 ubits[i++] = 'w'; 128 if ((um & S_IXUSR) == 0) 129 ubits[i++] = 'x'; 130 ubits[i] = '\0'; 131 132 i = 0; 133 if ((um & S_IRGRP) == 0) 134 gbits[i++] = 'r'; 135 if ((um & S_IWGRP) == 0) 136 gbits[i++] = 'w'; 137 if ((um & S_IXGRP) == 0) 138 gbits[i++] = 'x'; 139 gbits[i] = '\0'; 140 141 i = 0; 142 if ((um & S_IROTH) == 0) 143 obits[i++] = 'r'; 144 if ((um & S_IWOTH) == 0) 145 obits[i++] = 'w'; 146 if ((um & S_IXOTH) == 0) 147 obits[i++] = 'x'; 148 obits[i] = '\0'; 149 150 printf ("u=%s,g=%s,o=%s\n", ubits, gbits, obits); 151} 152 153int 154parse_symbolic_mode (mode, initial_bits) 155 char *mode; 156 int initial_bits; 157{ 158 int who, op, perm, bits, c; 159 char *s; 160 161 for (s = mode, bits = initial_bits;;) 162 { 163 who = op = perm = 0; 164 165 /* Parse the `who' portion of the symbolic mode clause. */ 166 while (member (*s, "agou")) 167 { 168 switch (c = *s++) 169 { 170 case 'u': 171 who |= S_IRWXU; 172 continue; 173 case 'g': 174 who |= S_IRWXG; 175 continue; 176 case 'o': 177 who |= S_IRWXO; 178 continue; 179 case 'a': 180 who |= S_IRWXU | S_IRWXG | S_IRWXO; 181 continue; 182 default: 183 break; 184 } 185 } 186 187 /* The operation is now sitting in *s. */ 188 op = *s++; 189 switch (op) 190 { 191 case '+': 192 case '-': 193 case '=': 194 break; 195 default: 196 builtin_error (_("`%c': invalid symbolic mode operator"), op); 197 return (-1); 198 } 199 200 /* Parse out the `perm' section of the symbolic mode clause. */ 201 while (member (*s, "rwx")) 202 { 203 c = *s++; 204 205 switch (c) 206 { 207 case 'r': 208 perm |= S_IRUGO; 209 break; 210 case 'w': 211 perm |= S_IWUGO; 212 break; 213 case 'x': 214 perm |= S_IXUGO; 215 break; 216 } 217 } 218 219 /* Now perform the operation or return an error for a 220 bad permission string. */ 221 if (!*s || *s == ',') 222 { 223 if (who) 224 perm &= who; 225 226 switch (op) 227 { 228 case '+': 229 bits |= perm; 230 break; 231 case '-': 232 bits &= ~perm; 233 break; 234 case '=': 235 if (who == 0) 236 who = S_IRWXU | S_IRWXG | S_IRWXO; 237 bits &= ~who; 238 bits |= perm; 239 break; 240 241 /* No other values are possible. */ 242 } 243 244 if (*s == '\0') 245 break; 246 else 247 s++; /* skip past ',' */ 248 } 249 else 250 { 251 builtin_error (_("`%c': invalid symbolic mode character"), *s); 252 return (-1); 253 } 254 } 255 256 return (bits); 257} 258 259/* Set the umask from a symbolic mode string similar to that accepted 260 by chmod. If the -S argument is given, then print the umask in a 261 symbolic form. */ 262static int 263symbolic_umask (list) 264 WORD_LIST *list; 265{ 266 int um, bits; 267 268 /* Get the initial umask. Don't change it yet. */ 269 um = umask (022); 270 umask (um); 271 272 /* All work is done with the complement of the umask -- it's 273 more intuitive and easier to deal with. It is complemented 274 again before being returned. */ 275 bits = parse_symbolic_mode (list->word->word, ~um & 0777); 276 if (bits == -1) 277 return (-1); 278 279 um = ~bits & 0777; 280 return (um); 281} 282