312 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
			
		
		
	
	
			312 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
| This file is umask.def, from which is created umask.c.
 | |
| It implements the builtin "umask" in Bash.
 | |
| 
 | |
| Copyright (C) 1987-2009 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 3 of the License, 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.  If not, see <http://www.gnu.org/licenses/>.
 | |
| 
 | |
| $PRODUCES umask.c
 | |
| 
 | |
| $BUILTIN umask
 | |
| $FUNCTION umask_builtin
 | |
| $SHORT_DOC umask [-p] [-S] [mode]
 | |
| Display or set file mode mask.
 | |
| 
 | |
| Sets the user file-creation mask to MODE.  If MODE is omitted, prints
 | |
| the current value of the mask.
 | |
| 
 | |
| 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).
 | |
| 
 | |
| Options:
 | |
|   -p	if MODE is omitted, output in a form that may be reused as input
 | |
|   -S	makes the output symbolic; otherwise an octal number is output
 | |
| 
 | |
| Exit Status:
 | |
| Returns success unless MODE is invalid or an invalid option is given.
 | |
| $END
 | |
| 
 | |
| #include <config.h>
 | |
| 
 | |
| #include "../bashtypes.h"
 | |
| #include "filecntl.h"
 | |
| #if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
 | |
| #  include <sys/file.h>
 | |
| #endif
 | |
| 
 | |
| #if defined (HAVE_UNISTD_H)
 | |
| #include <unistd.h>
 | |
| #endif
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <chartypes.h>
 | |
| 
 | |
| #include "../bashintl.h"
 | |
| 
 | |
| #include "../shell.h"
 | |
| #include "posixstat.h"
 | |
| #include "common.h"
 | |
| #include "bashgetopt.h"
 | |
| 
 | |
| /* **************************************************************** */
 | |
| /*                                                                  */
 | |
| /*                     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);
 | |
|     }
 | |
| 
 | |
|   return (sh_chkwrite (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 '=':
 | |
| 	      if (who == 0)
 | |
| 		who = S_IRWXU | S_IRWXG | S_IRWXO;
 | |
| 	      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 & 0777);
 | |
|   if (bits == -1)
 | |
|     return (-1);
 | |
| 
 | |
|   um = ~bits & 0777;
 | |
|   return (um);
 | |
| }
 | 
