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