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