| This file is umask.def, from which is created umask.c. |
| It implements the builtin "umask" in Bash. |
| |
| Copyright (C) 1987-2002 Free Software Foundation, Inc. |
| |
| This file is part of GNU Bash, the Bourne Again SHell. |
| |
| Bash is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 2, or (at your option) any later |
| version. |
| |
| Bash is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License along |
| with Bash; see the file COPYING. If not, write to the Free Software |
| Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. |
| |
| $PRODUCES umask.c |
| |
| $BUILTIN umask |
| $FUNCTION umask_builtin |
| $SHORT_DOC umask [-p] [-S] [mode] |
| The user file-creation mask is set to MODE. If MODE is omitted, or if |
| `-S' is supplied, the current value of the mask is printed. The `-S' |
| option makes the output symbolic; otherwise an octal number is output. |
| If `-p' is supplied, and MODE is omitted, the output is in a form |
| that may be used as input. If MODE begins with a digit, it is |
| interpreted as an octal number, otherwise it is a symbolic mode string |
| like that accepted by chmod(1). |
| $END |
| |
| #include <config.h> |
| |
| #include "../bashtypes.h" |
| #include "filecntl.h" |
| #ifndef _MINIX |
| # include <sys/file.h> |
| #endif |
| |
| #if defined (HAVE_UNISTD_H) |
| #include <unistd.h> |
| #endif |
| |
| #include <stdio.h> |
| #include <chartypes.h> |
| |
| #include "../shell.h" |
| #include "posixstat.h" |
| #include "common.h" |
| #include "bashgetopt.h" |
| |
| #ifdef __LCC__ |
| #define mode_t int |
| #endif |
| |
| /* **************************************************************** */ |
| /* */ |
| /* UMASK Builtin and Helpers */ |
| /* */ |
| /* **************************************************************** */ |
| |
| static void print_symbolic_umask __P((mode_t)); |
| static int symbolic_umask __P((WORD_LIST *)); |
| |
| /* Set or display the mask used by the system when creating files. Flag |
| of -S means display the umask in a symbolic mode. */ |
| int |
| umask_builtin (list) |
| WORD_LIST *list; |
| { |
| int print_symbolically, opt, umask_value, pflag; |
| mode_t umask_arg; |
| |
| print_symbolically = pflag = 0; |
| reset_internal_getopt (); |
| while ((opt = internal_getopt (list, "Sp")) != -1) |
| { |
| switch (opt) |
| { |
| case 'S': |
| print_symbolically++; |
| break; |
| case 'p': |
| pflag++; |
| break; |
| default: |
| builtin_usage (); |
| return (EX_USAGE); |
| } |
| } |
| |
| list = loptend; |
| |
| if (list) |
| { |
| if (DIGIT (*list->word->word)) |
| { |
| umask_value = read_octal (list->word->word); |
| |
| /* Note that other shells just let you set the umask to zero |
| by specifying a number out of range. This is a problem |
| with those shells. We don't change the umask if the input |
| is lousy. */ |
| if (umask_value == -1) |
| { |
| sh_erange (list->word->word, "octal number"); |
| return (EXECUTION_FAILURE); |
| } |
| } |
| else |
| { |
| umask_value = symbolic_umask (list); |
| if (umask_value == -1) |
| return (EXECUTION_FAILURE); |
| } |
| umask_arg = (mode_t)umask_value; |
| umask (umask_arg); |
| if (print_symbolically) |
| print_symbolic_umask (umask_arg); |
| } |
| else /* Display the UMASK for this user. */ |
| { |
| umask_arg = umask (022); |
| umask (umask_arg); |
| |
| if (pflag) |
| printf ("umask%s ", (print_symbolically ? " -S" : "")); |
| if (print_symbolically) |
| print_symbolic_umask (umask_arg); |
| else |
| printf ("%04lo\n", (unsigned long)umask_arg); |
| } |
| |
| fflush (stdout); |
| return (EXECUTION_SUCCESS); |
| } |
| |
| /* Print the umask in a symbolic form. In the output, a letter is |
| printed if the corresponding bit is clear in the umask. */ |
| static void |
| print_symbolic_umask (um) |
| mode_t um; |
| { |
| char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */ |
| int i; |
| |
| i = 0; |
| if ((um & S_IRUSR) == 0) |
| ubits[i++] = 'r'; |
| if ((um & S_IWUSR) == 0) |
| ubits[i++] = 'w'; |
| if ((um & S_IXUSR) == 0) |
| ubits[i++] = 'x'; |
| ubits[i] = '\0'; |
| |
| i = 0; |
| if ((um & S_IRGRP) == 0) |
| gbits[i++] = 'r'; |
| if ((um & S_IWGRP) == 0) |
| gbits[i++] = 'w'; |
| if ((um & S_IXGRP) == 0) |
| gbits[i++] = 'x'; |
| gbits[i] = '\0'; |
| |
| i = 0; |
| if ((um & S_IROTH) == 0) |
| obits[i++] = 'r'; |
| if ((um & S_IWOTH) == 0) |
| obits[i++] = 'w'; |
| if ((um & S_IXOTH) == 0) |
| obits[i++] = 'x'; |
| obits[i] = '\0'; |
| |
| printf ("u=%s,g=%s,o=%s\n", ubits, gbits, obits); |
| } |
| |
| int |
| parse_symbolic_mode (mode, initial_bits) |
| char *mode; |
| int initial_bits; |
| { |
| int who, op, perm, bits, c; |
| char *s; |
| |
| for (s = mode, bits = initial_bits;;) |
| { |
| who = op = perm = 0; |
| |
| /* Parse the `who' portion of the symbolic mode clause. */ |
| while (member (*s, "agou")) |
| { |
| switch (c = *s++) |
| { |
| case 'u': |
| who |= S_IRWXU; |
| continue; |
| case 'g': |
| who |= S_IRWXG; |
| continue; |
| case 'o': |
| who |= S_IRWXO; |
| continue; |
| case 'a': |
| who |= S_IRWXU | S_IRWXG | S_IRWXO; |
| continue; |
| default: |
| break; |
| } |
| } |
| |
| /* The operation is now sitting in *s. */ |
| op = *s++; |
| switch (op) |
| { |
| case '+': |
| case '-': |
| case '=': |
| break; |
| default: |
| builtin_error ("`%c': invalid symbolic mode operator", op); |
| return (-1); |
| } |
| |
| /* Parse out the `perm' section of the symbolic mode clause. */ |
| while (member (*s, "rwx")) |
| { |
| c = *s++; |
| |
| switch (c) |
| { |
| case 'r': |
| perm |= S_IRUGO; |
| break; |
| case 'w': |
| perm |= S_IWUGO; |
| break; |
| case 'x': |
| perm |= S_IXUGO; |
| break; |
| } |
| } |
| |
| /* Now perform the operation or return an error for a |
| bad permission string. */ |
| if (!*s || *s == ',') |
| { |
| if (who) |
| perm &= who; |
| |
| switch (op) |
| { |
| case '+': |
| bits |= perm; |
| break; |
| case '-': |
| bits &= ~perm; |
| break; |
| case '=': |
| bits &= ~who; |
| bits |= perm; |
| break; |
| |
| /* No other values are possible. */ |
| } |
| |
| if (*s == '\0') |
| break; |
| else |
| s++; /* skip past ',' */ |
| } |
| else |
| { |
| builtin_error ("`%c': invalid symbolic mode character", *s); |
| return (-1); |
| } |
| } |
| |
| return (bits); |
| } |
| |
| /* Set the umask from a symbolic mode string similar to that accepted |
| by chmod. If the -S argument is given, then print the umask in a |
| symbolic form. */ |
| static int |
| symbolic_umask (list) |
| WORD_LIST *list; |
| { |
| int um, bits; |
| |
| /* Get the initial umask. Don't change it yet. */ |
| um = umask (022); |
| umask (um); |
| |
| /* All work is done with the complement of the umask -- it's |
| more intuitive and easier to deal with. It is complemented |
| again before being returned. */ |
| bits = parse_symbolic_mode (list->word->word, ~um); |
| if (bits == -1) |
| return (-1); |
| |
| um = ~bits & 0777; |
| return (um); |
| } |