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