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