Bash-4.3 distribution sources and documentation
[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 /* **************************************************************** */
65 /*                                                                  */
66 /*                     UMASK Builtin and Helpers                    */
67 /*                                                                  */
68 /* **************************************************************** */
69
70 static void print_symbolic_umask __P((mode_t));
71 static int symbolic_umask __P((WORD_LIST *));
72
73 /* Set or display the mask used by the system when creating files.  Flag
74    of -S means display the umask in a symbolic mode. */
75 int
76 umask_builtin (list)
77      WORD_LIST *list;
78 {
79   int print_symbolically, opt, umask_value, pflag;
80   mode_t umask_arg;
81
82   print_symbolically = pflag = 0;
83   reset_internal_getopt ();
84   while ((opt = internal_getopt (list, "Sp")) != -1)
85     {
86       switch (opt)
87         {
88         case 'S':
89           print_symbolically++;
90           break;
91         case 'p':
92           pflag++;
93           break;
94         default:
95           builtin_usage ();
96           return (EX_USAGE);
97         }
98     }
99
100   list = loptend;
101
102   if (list)
103     {
104       if (DIGIT (*list->word->word))
105         {
106           umask_value = read_octal (list->word->word);
107
108           /* Note that other shells just let you set the umask to zero
109              by specifying a number out of range.  This is a problem
110              with those shells.  We don't change the umask if the input
111              is lousy. */
112           if (umask_value == -1)
113             {
114               sh_erange (list->word->word, _("octal number"));
115               return (EXECUTION_FAILURE);
116             }
117         }
118       else
119         {
120           umask_value = symbolic_umask (list);
121           if (umask_value == -1)
122             return (EXECUTION_FAILURE);
123         }
124       umask_arg = (mode_t)umask_value;
125       umask (umask_arg);
126       if (print_symbolically)
127         print_symbolic_umask (umask_arg);
128     }
129   else                          /* Display the UMASK for this user. */
130     {
131       umask_arg = umask (022);
132       umask (umask_arg);
133
134       if (pflag)
135         printf ("umask%s ", (print_symbolically ? " -S" : ""));
136       if (print_symbolically)
137         print_symbolic_umask (umask_arg);
138       else
139         printf ("%04lo\n", (unsigned long)umask_arg);
140     }
141
142   return (sh_chkwrite (EXECUTION_SUCCESS));
143 }
144
145 /* Print the umask in a symbolic form.  In the output, a letter is
146    printed if the corresponding bit is clear in the umask. */
147 static void
148 print_symbolic_umask (um)
149      mode_t um;
150 {
151   char ubits[4], gbits[4], obits[4];            /* u=rwx,g=rwx,o=rwx */
152   int i;
153
154   i = 0;
155   if ((um & S_IRUSR) == 0)
156     ubits[i++] = 'r';
157   if ((um & S_IWUSR) == 0)
158     ubits[i++] = 'w';
159   if ((um & S_IXUSR) == 0)
160     ubits[i++] = 'x';
161   ubits[i] = '\0';
162
163   i = 0;
164   if ((um & S_IRGRP) == 0)
165     gbits[i++] = 'r';
166   if ((um & S_IWGRP) == 0)
167     gbits[i++] = 'w';
168   if ((um & S_IXGRP) == 0)
169     gbits[i++] = 'x';
170   gbits[i] = '\0';
171
172   i = 0;
173   if ((um & S_IROTH) == 0)
174     obits[i++] = 'r';
175   if ((um & S_IWOTH) == 0)
176     obits[i++] = 'w';
177   if ((um & S_IXOTH) == 0)
178     obits[i++] = 'x';
179   obits[i] = '\0';
180
181   printf ("u=%s,g=%s,o=%s\n", ubits, gbits, obits);
182 }
183
184 int
185 parse_symbolic_mode (mode, initial_bits)
186      char *mode;
187      int initial_bits;
188 {
189   int who, op, perm, bits, c;
190   char *s;
191
192   for (s = mode, bits = initial_bits;;)
193     {
194       who = op = perm = 0;
195
196       /* Parse the `who' portion of the symbolic mode clause. */
197       while (member (*s, "agou"))
198         {
199           switch (c = *s++)
200             {
201             case 'u':
202               who |= S_IRWXU;
203               continue;
204             case 'g':
205               who |= S_IRWXG;
206               continue;
207             case 'o':
208               who |= S_IRWXO;
209               continue;
210             case 'a':
211               who |= S_IRWXU | S_IRWXG | S_IRWXO;
212               continue;
213             default:
214               break;
215             }
216         }
217
218       /* The operation is now sitting in *s. */
219       op = *s++;
220       switch (op)
221         {
222         case '+':
223         case '-':
224         case '=':
225           break;
226         default:
227           builtin_error (_("`%c': invalid symbolic mode operator"), op);
228           return (-1);
229         }
230
231       /* Parse out the `perm' section of the symbolic mode clause. */
232       while (member (*s, "rwx"))
233         {
234           c = *s++;
235
236           switch (c)
237             {
238             case 'r':
239               perm |= S_IRUGO;
240               break;
241             case 'w':
242               perm |= S_IWUGO;
243               break;
244             case 'x':
245               perm |= S_IXUGO;
246               break;
247             }
248         }
249
250       /* Now perform the operation or return an error for a
251          bad permission string. */
252       if (!*s || *s == ',')
253         {
254           if (who)
255             perm &= who;
256
257           switch (op)
258             {
259             case '+':
260               bits |= perm;
261               break;
262             case '-':
263               bits &= ~perm;
264               break;
265             case '=':
266               if (who == 0)
267                 who = S_IRWXU | S_IRWXG | S_IRWXO;
268               bits &= ~who;
269               bits |= perm;
270               break;
271
272             /* No other values are possible. */
273             }
274
275           if (*s == '\0')
276             break;
277           else
278             s++;        /* skip past ',' */
279         }
280       else
281         {
282           builtin_error (_("`%c': invalid symbolic mode character"), *s);
283           return (-1);
284         }
285     }
286
287   return (bits);
288 }
289
290 /* Set the umask from a symbolic mode string similar to that accepted
291    by chmod.  If the -S argument is given, then print the umask in a
292    symbolic form. */
293 static int
294 symbolic_umask (list)
295      WORD_LIST *list;
296 {
297   int um, bits;
298
299   /* Get the initial umask.  Don't change it yet. */
300   um = umask (022);
301   umask (um);
302
303   /* All work is done with the complement of the umask -- it's
304      more intuitive and easier to deal with.  It is complemented
305      again before being returned. */
306   bits = parse_symbolic_mode (list->word->word, ~um & 0777);
307   if (bits == -1)
308     return (-1);
309
310   um = ~bits & 0777;
311   return (um);
312 }