f73411303c8b31fcbbbfbae2fbb2eafd5d587933
[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 1, 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, 675 Mass Ave, Cambridge, MA 02139, 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 /* Set the umask from a symbolic mode string similar to that accepted
178    by chmod.  If the -S argument is given, then print the umask in a
179    symbolic form. */
180 static int
181 symbolic_umask (list)
182      WORD_LIST *list;
183 {
184   int um, umc, c;
185   int who, op, perm, mask;
186   char *s;
187
188   /* Get the initial umask.  Don't change it yet. */
189   um = umask (022);
190   umask (um);
191
192   /* All work below is done with the complement of the umask -- it's
193      more intuitive and easier to deal with.  It is complemented
194      again before being returned. */
195   umc = ~um;
196
197   s = list->word->word;
198
199   for (;;)
200     {
201       who = op = perm = mask = 0;
202
203       /* Parse the `who' portion of the symbolic mode clause. */
204       while (member (*s, "agou"))
205         {
206           switch (c = *s++)
207             {
208               case 'u':
209                 who |= S_IRWXU;
210                 continue;
211               case 'g':
212                 who |= S_IRWXG;
213                 continue;
214               case 'o':
215                 who |= S_IRWXO;
216                 continue;
217               case 'a':
218                 who |= S_IRWXU | S_IRWXG | S_IRWXO;
219                 continue;
220               default:
221                 break;
222             }
223         }
224
225       /* The operation is now sitting in *s. */
226       op = *s++;
227       switch (op)
228         {
229           case '+':
230           case '-':
231           case '=':
232             break;
233           default:
234             builtin_error ("bad symbolic mode operator: %c", op);
235             return (-1);
236         }
237
238       /* Parse out the `perm' section of the symbolic mode clause. */
239       while (member (*s, "rwx"))
240         {
241           c = *s++;
242
243           switch (c)
244             {
245               case 'r':
246                 perm |= S_IRUGO;
247                 break;
248
249               case 'w':
250                 perm |= S_IWUGO;
251                 break;
252
253               case 'x':
254                 perm |= S_IXUGO;
255                 break;
256             }
257         }
258
259       /* Now perform the operation or return an error for a
260          bad permission string. */
261       if (!*s || *s == ',')
262         {
263           if (who)
264             perm &= who;
265
266           switch (op)
267             {
268               case '+':
269                 umc |= perm;
270                 break;
271
272               case '-':
273                 umc &= ~perm;
274                 break;
275
276               case '=':
277                 umc &= ~who;
278                 umc |= perm;
279                 break;
280
281 #if 0
282               /* No other values are possible. */
283               default:
284                 builtin_error ("bad symbolic mode operator: %c", op);
285                 return (-1);
286 #endif
287             }
288
289           if (!*s)
290             {
291               um = ~umc & 0777;
292               break;
293             }
294           else
295             s++;        /* skip past ',' */
296         }
297       else
298         {
299           builtin_error ("bad character in symbolic mode: %c", *s);
300           return (-1);
301         }
302     }
303   return (um);
304 }