4d62184a71a0f6e61efd9203edd073bc96083b1c
[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 #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               builtin_error ("`%s' is not an octal number from 000 to 777",
111                                 list->word->word);
112               return (EXECUTION_FAILURE);
113             }
114         }
115       else
116         {
117           umask_value = symbolic_umask (list);
118           if (umask_value == -1)
119             return (EXECUTION_FAILURE);
120         }
121       umask_arg = (mode_t)umask_value;
122       umask (umask_arg);
123       if (print_symbolically)
124         print_symbolic_umask (umask_arg);
125     }
126   else                          /* Display the UMASK for this user. */
127     {
128       umask_arg = umask (022);
129       umask (umask_arg);
130
131       if (pflag)
132         printf ("umask%s ", (print_symbolically ? " -S" : ""));
133       if (print_symbolically)
134         print_symbolic_umask (umask_arg);
135       else
136         printf ("%04lo\n", (unsigned long)umask_arg);
137     }
138
139   fflush (stdout);
140   return (EXECUTION_SUCCESS);
141 }
142
143 /* Print the umask in a symbolic form.  In the output, a letter is
144    printed if the corresponding bit is clear in the umask. */
145 static void
146 print_symbolic_umask (um)
147      mode_t um;
148 {
149   char ubits[4], gbits[4], obits[4];            /* u=rwx,g=rwx,o=rwx */
150   int i;
151
152   i = 0;
153   if ((um & S_IRUSR) == 0)
154     ubits[i++] = 'r';
155   if ((um & S_IWUSR) == 0)
156     ubits[i++] = 'w';
157   if ((um & S_IXUSR) == 0)
158     ubits[i++] = 'x';
159   ubits[i] = '\0';
160
161   i = 0;
162   if ((um & S_IRGRP) == 0)
163     gbits[i++] = 'r';
164   if ((um & S_IWGRP) == 0)
165     gbits[i++] = 'w';
166   if ((um & S_IXGRP) == 0)
167     gbits[i++] = 'x';
168   gbits[i] = '\0';
169
170   i = 0;
171   if ((um & S_IROTH) == 0)
172     obits[i++] = 'r';
173   if ((um & S_IWOTH) == 0)
174     obits[i++] = 'w';
175   if ((um & S_IXOTH) == 0)
176     obits[i++] = 'x';
177   obits[i] = '\0';
178
179   printf ("u=%s,g=%s,o=%s\n", ubits, gbits, obits);
180 }
181
182 int
183 parse_symbolic_mode (mode, initial_bits)
184      char *mode;
185      int initial_bits;
186 {
187   int who, op, perm, bits, c;
188   char *s;
189
190   for (s = mode, bits = initial_bits;;)
191     {
192       who = op = perm = 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             case 'w':
240               perm |= S_IWUGO;
241               break;
242             case 'x':
243               perm |= S_IXUGO;
244               break;
245             }
246         }
247
248       /* Now perform the operation or return an error for a
249          bad permission string. */
250       if (!*s || *s == ',')
251         {
252           if (who)
253             perm &= who;
254
255           switch (op)
256             {
257             case '+':
258               bits |= perm;
259               break;
260             case '-':
261               bits &= ~perm;
262               break;
263             case '=':
264               bits &= ~who;
265               bits |= perm;
266               break;
267
268             /* No other values are possible. */
269             }
270
271           if (*s == '\0')
272             break;
273           else
274             s++;        /* skip past ',' */
275         }
276       else
277         {
278           builtin_error ("bad character in symbolic mode: %c", *s);
279           return (-1);
280         }
281     }
282
283   return (bits);
284 }
285
286 /* Set the umask from a symbolic mode string similar to that accepted
287    by chmod.  If the -S argument is given, then print the umask in a
288    symbolic form. */
289 static int
290 symbolic_umask (list)
291      WORD_LIST *list;
292 {
293   int um, bits;
294
295   /* Get the initial umask.  Don't change it yet. */
296   um = umask (022);
297   umask (um);
298
299   /* All work is done with the complement of the umask -- it's
300      more intuitive and easier to deal with.  It is complemented
301      again before being returned. */
302   bits = parse_symbolic_mode (list->word->word, ~um);
303   if (bits == -1)
304     return (-1);
305
306   um = ~bits & 0777;
307   return (um);
308 }