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