289a0f548e74f244f9fc2b3c5acd1a5b4b92f5df
[platform/upstream/bash.git] / builtins / umask.def
1 This file is umask.def, from which is created umask.c.
2 It implements the builtin "umask" in Bash.
3
4 Copyright (C) 1987-2009 Free Software Foundation, Inc.
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
8 Bash is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 Bash is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Bash.  If not, see <http://www.gnu.org/licenses/>.
20
21 $PRODUCES umask.c
22
23 $BUILTIN umask
24 $FUNCTION umask_builtin
25 $SHORT_DOC umask [-p] [-S] [mode]
26 Display or set file mode mask.
27
28 Sets the user file-creation mask to MODE.  If MODE is omitted, prints
29 the current value of the mask.
30
31 If MODE begins with a digit, it is interpreted as an octal number;
32 otherwise it is a symbolic mode string like that accepted by chmod(1).
33
34 Options:
35   -p    if MODE is omitted, output in a form that may be reused as input
36   -S    makes the output symbolic; otherwise an octal number is output
37
38 Exit Status:
39 Returns success unless MODE is invalid or an invalid option is given.
40 $END
41
42 #include <config.h>
43
44 #include "../bashtypes.h"
45 #include "filecntl.h"
46 #if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
47 #  include <sys/file.h>
48 #endif
49
50 #if defined (HAVE_UNISTD_H)
51 #include <unistd.h>
52 #endif
53
54 #include <stdio.h>
55 #include <chartypes.h>
56
57 #include "../bashintl.h"
58
59 #include "../shell.h"
60 #include "posixstat.h"
61 #include "common.h"
62 #include "bashgetopt.h"
63
64 #ifdef __LCC__
65 #define mode_t int
66 #endif
67
68 /* **************************************************************** */
69 /*                                                                  */
70 /*                     UMASK Builtin and Helpers                    */
71 /*                                                                  */
72 /* **************************************************************** */
73
74 static void print_symbolic_umask __P((mode_t));
75 static int symbolic_umask __P((WORD_LIST *));
76
77 /* Set or display the mask used by the system when creating files.  Flag
78    of -S means display the umask in a symbolic mode. */
79 int
80 umask_builtin (list)
81      WORD_LIST *list;
82 {
83   int print_symbolically, opt, umask_value, pflag;
84   mode_t umask_arg;
85
86   print_symbolically = pflag = 0;
87   reset_internal_getopt ();
88   while ((opt = internal_getopt (list, "Sp")) != -1)
89     {
90       switch (opt)
91         {
92         case 'S':
93           print_symbolically++;
94           break;
95         case 'p':
96           pflag++;
97           break;
98         default:
99           builtin_usage ();
100           return (EX_USAGE);
101         }
102     }
103
104   list = loptend;
105
106   if (list)
107     {
108       if (DIGIT (*list->word->word))
109         {
110           umask_value = read_octal (list->word->word);
111
112           /* Note that other shells just let you set the umask to zero
113              by specifying a number out of range.  This is a problem
114              with those shells.  We don't change the umask if the input
115              is lousy. */
116           if (umask_value == -1)
117             {
118               sh_erange (list->word->word, _("octal number"));
119               return (EXECUTION_FAILURE);
120             }
121         }
122       else
123         {
124           umask_value = symbolic_umask (list);
125           if (umask_value == -1)
126             return (EXECUTION_FAILURE);
127         }
128       umask_arg = (mode_t)umask_value;
129       umask (umask_arg);
130       if (print_symbolically)
131         print_symbolic_umask (umask_arg);
132     }
133   else                          /* Display the UMASK for this user. */
134     {
135       umask_arg = umask (022);
136       umask (umask_arg);
137
138       if (pflag)
139         printf ("umask%s ", (print_symbolically ? " -S" : ""));
140       if (print_symbolically)
141         print_symbolic_umask (umask_arg);
142       else
143         printf ("%04lo\n", (unsigned long)umask_arg);
144     }
145
146   return (sh_chkwrite (EXECUTION_SUCCESS));
147 }
148
149 /* Print the umask in a symbolic form.  In the output, a letter is
150    printed if the corresponding bit is clear in the umask. */
151 static void
152 print_symbolic_umask (um)
153      mode_t um;
154 {
155   char ubits[4], gbits[4], obits[4];            /* u=rwx,g=rwx,o=rwx */
156   int i;
157
158   i = 0;
159   if ((um & S_IRUSR) == 0)
160     ubits[i++] = 'r';
161   if ((um & S_IWUSR) == 0)
162     ubits[i++] = 'w';
163   if ((um & S_IXUSR) == 0)
164     ubits[i++] = 'x';
165   ubits[i] = '\0';
166
167   i = 0;
168   if ((um & S_IRGRP) == 0)
169     gbits[i++] = 'r';
170   if ((um & S_IWGRP) == 0)
171     gbits[i++] = 'w';
172   if ((um & S_IXGRP) == 0)
173     gbits[i++] = 'x';
174   gbits[i] = '\0';
175
176   i = 0;
177   if ((um & S_IROTH) == 0)
178     obits[i++] = 'r';
179   if ((um & S_IWOTH) == 0)
180     obits[i++] = 'w';
181   if ((um & S_IXOTH) == 0)
182     obits[i++] = 'x';
183   obits[i] = '\0';
184
185   printf ("u=%s,g=%s,o=%s\n", ubits, gbits, obits);
186 }
187
188 int
189 parse_symbolic_mode (mode, initial_bits)
190      char *mode;
191      int initial_bits;
192 {
193   int who, op, perm, bits, c;
194   char *s;
195
196   for (s = mode, bits = initial_bits;;)
197     {
198       who = op = perm = 0;
199
200       /* Parse the `who' portion of the symbolic mode clause. */
201       while (member (*s, "agou"))
202         {
203           switch (c = *s++)
204             {
205             case 'u':
206               who |= S_IRWXU;
207               continue;
208             case 'g':
209               who |= S_IRWXG;
210               continue;
211             case 'o':
212               who |= S_IRWXO;
213               continue;
214             case 'a':
215               who |= S_IRWXU | S_IRWXG | S_IRWXO;
216               continue;
217             default:
218               break;
219             }
220         }
221
222       /* The operation is now sitting in *s. */
223       op = *s++;
224       switch (op)
225         {
226         case '+':
227         case '-':
228         case '=':
229           break;
230         default:
231           builtin_error (_("`%c': invalid symbolic mode operator"), op);
232           return (-1);
233         }
234
235       /* Parse out the `perm' section of the symbolic mode clause. */
236       while (member (*s, "rwx"))
237         {
238           c = *s++;
239
240           switch (c)
241             {
242             case 'r':
243               perm |= S_IRUGO;
244               break;
245             case 'w':
246               perm |= S_IWUGO;
247               break;
248             case 'x':
249               perm |= S_IXUGO;
250               break;
251             }
252         }
253
254       /* Now perform the operation or return an error for a
255          bad permission string. */
256       if (!*s || *s == ',')
257         {
258           if (who)
259             perm &= who;
260
261           switch (op)
262             {
263             case '+':
264               bits |= perm;
265               break;
266             case '-':
267               bits &= ~perm;
268               break;
269             case '=':
270               if (who == 0)
271                 who = S_IRWXU | S_IRWXG | S_IRWXO;
272               bits &= ~who;
273               bits |= perm;
274               break;
275
276             /* No other values are possible. */
277             }
278
279           if (*s == '\0')
280             break;
281           else
282             s++;        /* skip past ',' */
283         }
284       else
285         {
286           builtin_error (_("`%c': invalid symbolic mode character"), *s);
287           return (-1);
288         }
289     }
290
291   return (bits);
292 }
293
294 /* Set the umask from a symbolic mode string similar to that accepted
295    by chmod.  If the -S argument is given, then print the umask in a
296    symbolic form. */
297 static int
298 symbolic_umask (list)
299      WORD_LIST *list;
300 {
301   int um, bits;
302
303   /* Get the initial umask.  Don't change it yet. */
304   um = umask (022);
305   umask (um);
306
307   /* All work is done with the complement of the umask -- it's
308      more intuitive and easier to deal with.  It is complemented
309      again before being returned. */
310   bits = parse_symbolic_mode (list->word->word, ~um & 0777);
311   if (bits == -1)
312     return (-1);
313
314   um = ~bits & 0777;
315   return (um);
316 }