blob: d9aa041836f64a608cb71f1e0d08f5338bd2e0a4 [file] [log] [blame]
Jari Aalto726f6381996-08-26 18:22:31 +00001This file is umask.def, from which is created umask.c.
2It implements the builtin "umask" in Bash.
3
Jari Aalto31859422009-01-12 13:36:28 +00004Copyright (C) 1987-2009 Free Software Foundation, Inc.
Jari Aalto726f6381996-08-26 18:22:31 +00005
6This file is part of GNU Bash, the Bourne Again SHell.
7
Jari Aalto31859422009-01-12 13:36:28 +00008Bash is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
Jari Aalto726f6381996-08-26 18:22:31 +000012
Jari Aalto31859422009-01-12 13:36:28 +000013Bash is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
Jari Aalto726f6381996-08-26 18:22:31 +000017
Jari Aalto31859422009-01-12 13:36:28 +000018You should have received a copy of the GNU General Public License
19along with Bash. If not, see <http://www.gnu.org/licenses/>.
Jari Aalto726f6381996-08-26 18:22:31 +000020
21$PRODUCES umask.c
22
23$BUILTIN umask
24$FUNCTION umask_builtin
Jari Aaltocce855b1998-04-17 19:52:44 +000025$SHORT_DOC umask [-p] [-S] [mode]
Jari Aalto31859422009-01-12 13:36:28 +000026Display or set file mode mask.
27
28Sets the user file-creation mask to MODE. If MODE is omitted, prints
29the current value of the mask.
30
31If MODE begins with a digit, it is interpreted as an octal number;
32otherwise it is a symbolic mode string like that accepted by chmod(1).
33
34Options:
35 -p if MODE is omitted, output in a form that may be reused as input
36 -S makes the output symbolic; otherwise an octal number is output
37
38Exit Status:
39Returns success unless MODE is invalid or an invalid option is given.
Jari Aalto726f6381996-08-26 18:22:31 +000040$END
41
Jari Aaltoccc6cda1996-12-23 17:02:34 +000042#include <config.h>
43
44#include "../bashtypes.h"
Jari Aaltobb706242000-03-17 21:46:59 +000045#include "filecntl.h"
Jari Aaltob80f6442004-07-27 13:29:18 +000046#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
Jari Aaltocce855b1998-04-17 19:52:44 +000047# include <sys/file.h>
48#endif
Jari Aaltoccc6cda1996-12-23 17:02:34 +000049
50#if defined (HAVE_UNISTD_H)
51#include <unistd.h>
52#endif
53
54#include <stdio.h>
Jari Aaltof73dda02001-11-13 17:56:06 +000055#include <chartypes.h>
Jari Aaltoccc6cda1996-12-23 17:02:34 +000056
Jari Aaltob80f6442004-07-27 13:29:18 +000057#include "../bashintl.h"
58
Jari Aalto726f6381996-08-26 18:22:31 +000059#include "../shell.h"
Jari Aaltobb706242000-03-17 21:46:59 +000060#include "posixstat.h"
Jari Aalto726f6381996-08-26 18:22:31 +000061#include "common.h"
Jari Aaltoccc6cda1996-12-23 17:02:34 +000062#include "bashgetopt.h"
Jari Aalto726f6381996-08-26 18:22:31 +000063
64/* **************************************************************** */
65/* */
66/* UMASK Builtin and Helpers */
67/* */
68/* **************************************************************** */
69
Jari Aaltof73dda02001-11-13 17:56:06 +000070static void print_symbolic_umask __P((mode_t));
71static int symbolic_umask __P((WORD_LIST *));
Jari Aalto726f6381996-08-26 18:22:31 +000072
73/* Set or display the mask used by the system when creating files. Flag
74 of -S means display the umask in a symbolic mode. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +000075int
Jari Aalto726f6381996-08-26 18:22:31 +000076umask_builtin (list)
77 WORD_LIST *list;
78{
Jari Aaltocce855b1998-04-17 19:52:44 +000079 int print_symbolically, opt, umask_value, pflag;
Jari Aaltod166f041997-06-05 14:59:13 +000080 mode_t umask_arg;
Jari Aalto726f6381996-08-26 18:22:31 +000081
Jari Aaltocce855b1998-04-17 19:52:44 +000082 print_symbolically = pflag = 0;
Jari Aaltoccc6cda1996-12-23 17:02:34 +000083 reset_internal_getopt ();
Jari Aaltocce855b1998-04-17 19:52:44 +000084 while ((opt = internal_getopt (list, "Sp")) != -1)
Jari Aalto726f6381996-08-26 18:22:31 +000085 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +000086 switch (opt)
Jari Aalto726f6381996-08-26 18:22:31 +000087 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +000088 case 'S':
Jari Aalto726f6381996-08-26 18:22:31 +000089 print_symbolically++;
Jari Aalto726f6381996-08-26 18:22:31 +000090 break;
Jari Aaltocce855b1998-04-17 19:52:44 +000091 case 'p':
92 pflag++;
93 break;
Jari Aaltoccc6cda1996-12-23 17:02:34 +000094 default:
95 builtin_usage ();
Jari Aalto726f6381996-08-26 18:22:31 +000096 return (EX_USAGE);
97 }
Jari Aalto726f6381996-08-26 18:22:31 +000098 }
99
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000100 list = loptend;
101
Jari Aalto726f6381996-08-26 18:22:31 +0000102 if (list)
103 {
Jari Aaltof73dda02001-11-13 17:56:06 +0000104 if (DIGIT (*list->word->word))
Jari Aalto726f6381996-08-26 18:22:31 +0000105 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000106 umask_value = read_octal (list->word->word);
Jari Aalto726f6381996-08-26 18:22:31 +0000107
108 /* Note that other shells just let you set the umask to zero
109 by specifying a number out of range. This is a problem
110 with those shells. We don't change the umask if the input
111 is lousy. */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000112 if (umask_value == -1)
Jari Aalto726f6381996-08-26 18:22:31 +0000113 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000114 sh_erange (list->word->word, _("octal number"));
Jari Aalto726f6381996-08-26 18:22:31 +0000115 return (EXECUTION_FAILURE);
116 }
117 }
118 else
119 {
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000120 umask_value = symbolic_umask (list);
121 if (umask_value == -1)
Jari Aalto726f6381996-08-26 18:22:31 +0000122 return (EXECUTION_FAILURE);
123 }
Jari Aaltod166f041997-06-05 14:59:13 +0000124 umask_arg = (mode_t)umask_value;
125 umask (umask_arg);
Jari Aalto726f6381996-08-26 18:22:31 +0000126 if (print_symbolically)
Jari Aaltod166f041997-06-05 14:59:13 +0000127 print_symbolic_umask (umask_arg);
Jari Aalto726f6381996-08-26 18:22:31 +0000128 }
129 else /* Display the UMASK for this user. */
130 {
Jari Aaltod166f041997-06-05 14:59:13 +0000131 umask_arg = umask (022);
132 umask (umask_arg);
Jari Aalto726f6381996-08-26 18:22:31 +0000133
Jari Aaltocce855b1998-04-17 19:52:44 +0000134 if (pflag)
135 printf ("umask%s ", (print_symbolically ? " -S" : ""));
Jari Aalto726f6381996-08-26 18:22:31 +0000136 if (print_symbolically)
Jari Aaltod166f041997-06-05 14:59:13 +0000137 print_symbolic_umask (umask_arg);
Jari Aalto726f6381996-08-26 18:22:31 +0000138 else
Jari Aaltof73dda02001-11-13 17:56:06 +0000139 printf ("%04lo\n", (unsigned long)umask_arg);
Jari Aalto726f6381996-08-26 18:22:31 +0000140 }
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000141
Jari Aalto31859422009-01-12 13:36:28 +0000142 return (sh_chkwrite (EXECUTION_SUCCESS));
Jari Aalto726f6381996-08-26 18:22:31 +0000143}
144
145/* Print the umask in a symbolic form. In the output, a letter is
146 printed if the corresponding bit is clear in the umask. */
147static void
148print_symbolic_umask (um)
Jari Aaltod166f041997-06-05 14:59:13 +0000149 mode_t um;
Jari Aalto726f6381996-08-26 18:22:31 +0000150{
151 char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */
152 int i;
153
154 i = 0;
155 if ((um & S_IRUSR) == 0)
156 ubits[i++] = 'r';
157 if ((um & S_IWUSR) == 0)
158 ubits[i++] = 'w';
159 if ((um & S_IXUSR) == 0)
160 ubits[i++] = 'x';
161 ubits[i] = '\0';
162
163 i = 0;
164 if ((um & S_IRGRP) == 0)
165 gbits[i++] = 'r';
166 if ((um & S_IWGRP) == 0)
167 gbits[i++] = 'w';
168 if ((um & S_IXGRP) == 0)
169 gbits[i++] = 'x';
170 gbits[i] = '\0';
171
172 i = 0;
173 if ((um & S_IROTH) == 0)
174 obits[i++] = 'r';
175 if ((um & S_IWOTH) == 0)
176 obits[i++] = 'w';
177 if ((um & S_IXOTH) == 0)
178 obits[i++] = 'x';
179 obits[i] = '\0';
180
181 printf ("u=%s,g=%s,o=%s\n", ubits, gbits, obits);
182}
183
Jari Aaltob72432f1999-02-19 17:11:39 +0000184int
185parse_symbolic_mode (mode, initial_bits)
186 char *mode;
187 int initial_bits;
Jari Aalto726f6381996-08-26 18:22:31 +0000188{
Jari Aaltof73dda02001-11-13 17:56:06 +0000189 int who, op, perm, bits, c;
Jari Aalto726f6381996-08-26 18:22:31 +0000190 char *s;
191
Jari Aaltob72432f1999-02-19 17:11:39 +0000192 for (s = mode, bits = initial_bits;;)
Jari Aalto726f6381996-08-26 18:22:31 +0000193 {
Jari Aaltof73dda02001-11-13 17:56:06 +0000194 who = op = perm = 0;
Jari Aalto726f6381996-08-26 18:22:31 +0000195
196 /* Parse the `who' portion of the symbolic mode clause. */
197 while (member (*s, "agou"))
Jari Aalto28ef6c32001-04-06 19:14:31 +0000198 {
Jari Aalto726f6381996-08-26 18:22:31 +0000199 switch (c = *s++)
200 {
Jari Aaltob72432f1999-02-19 17:11:39 +0000201 case 'u':
202 who |= S_IRWXU;
203 continue;
204 case 'g':
205 who |= S_IRWXG;
206 continue;
207 case 'o':
208 who |= S_IRWXO;
209 continue;
210 case 'a':
211 who |= S_IRWXU | S_IRWXG | S_IRWXO;
212 continue;
213 default:
214 break;
Jari Aalto726f6381996-08-26 18:22:31 +0000215 }
216 }
217
218 /* The operation is now sitting in *s. */
219 op = *s++;
220 switch (op)
221 {
Jari Aaltob72432f1999-02-19 17:11:39 +0000222 case '+':
223 case '-':
224 case '=':
225 break;
226 default:
Jari Aaltob80f6442004-07-27 13:29:18 +0000227 builtin_error (_("`%c': invalid symbolic mode operator"), op);
Jari Aaltob72432f1999-02-19 17:11:39 +0000228 return (-1);
Jari Aalto726f6381996-08-26 18:22:31 +0000229 }
230
231 /* Parse out the `perm' section of the symbolic mode clause. */
232 while (member (*s, "rwx"))
233 {
234 c = *s++;
235
236 switch (c)
237 {
Jari Aaltob72432f1999-02-19 17:11:39 +0000238 case 'r':
239 perm |= S_IRUGO;
240 break;
241 case 'w':
242 perm |= S_IWUGO;
243 break;
244 case 'x':
245 perm |= S_IXUGO;
246 break;
Jari Aalto726f6381996-08-26 18:22:31 +0000247 }
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 {
Jari Aaltob72432f1999-02-19 17:11:39 +0000259 case '+':
260 bits |= perm;
Jari Aalto726f6381996-08-26 18:22:31 +0000261 break;
Jari Aaltob72432f1999-02-19 17:11:39 +0000262 case '-':
263 bits &= ~perm;
264 break;
265 case '=':
Jari Aaltob80f6442004-07-27 13:29:18 +0000266 if (who == 0)
267 who = S_IRWXU | S_IRWXG | S_IRWXO;
Jari Aaltob72432f1999-02-19 17:11:39 +0000268 bits &= ~who;
269 bits |= perm;
270 break;
271
272 /* No other values are possible. */
Jari Aalto726f6381996-08-26 18:22:31 +0000273 }
Jari Aaltob72432f1999-02-19 17:11:39 +0000274
275 if (*s == '\0')
276 break;
Jari Aalto726f6381996-08-26 18:22:31 +0000277 else
278 s++; /* skip past ',' */
279 }
280 else
281 {
Jari Aaltob80f6442004-07-27 13:29:18 +0000282 builtin_error (_("`%c': invalid symbolic mode character"), *s);
Jari Aalto726f6381996-08-26 18:22:31 +0000283 return (-1);
284 }
285 }
Jari Aaltob72432f1999-02-19 17:11:39 +0000286
287 return (bits);
288}
289
290/* Set the umask from a symbolic mode string similar to that accepted
291 by chmod. If the -S argument is given, then print the umask in a
292 symbolic form. */
293static int
294symbolic_umask (list)
295 WORD_LIST *list;
296{
297 int um, bits;
298
299 /* Get the initial umask. Don't change it yet. */
300 um = umask (022);
301 umask (um);
302
303 /* All work is done with the complement of the umask -- it's
304 more intuitive and easier to deal with. It is complemented
305 again before being returned. */
Jari Aaltob80f6442004-07-27 13:29:18 +0000306 bits = parse_symbolic_mode (list->word->word, ~um & 0777);
Jari Aaltobb706242000-03-17 21:46:59 +0000307 if (bits == -1)
308 return (-1);
Jari Aaltob72432f1999-02-19 17:11:39 +0000309
310 um = ~bits & 0777;
Jari Aalto726f6381996-08-26 18:22:31 +0000311 return (um);
312}