coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] env: add umask support


From: user
Subject: [PATCH] env: add umask support
Date: Sat, 26 Oct 2019 00:00:00 +0000

* src/env.c: add -M/--umask parameter.
* doc/coreutils.texi: add -M/--umask documentation.
* tests/env/umask.sh: add -M/--umask tests.
---
 doc/coreutils.texi | 16 ++++++++++++++++
 src/env.c          | 42 +++++++++++++++++++++++++++++++++++++++++-
 tests/env/umask.sh | 37 +++++++++++++++++++++++++++++++++++++
 3 files changed, 94 insertions(+), 1 deletion(-)
 create mode 100644 tests/env/umask.sh

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index b552cc105..9e2c0f4b0 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -17243,6 +17243,22 @@ chroot /chroot env --chdir=/srv true
 env --chdir=/build FOO=bar timeout 5 true
 @end example
 
+@item -M @var{mask}
+@itemx --umask=@var{mask}
+@opindex -M
+@opindex --umask
+Set the umask used when creating new files or directories to @var{mask}
+before invoking @var{command}.  This differs from the shell built-in
+@command{umask} in that it starts @var{command} as a subprocess rather than
+altering the shell's own umask; this allows it to be chained with other
+commands that run commands in a different context.  For example:
+
+@example
+# Run 'touch' with 0777 as its umask, FOO=bar in its
+# environment, and a time limit of five seconds.
+env --umask=0777 FOO=bar timeout 5 touch a-file
+@end example
+
 @item --default-signal[=@var{sig}]
 Unblock and reset signal @var{sig} to its default signal handler.
 Without @var{sig} all known signals are unblocked and reset to their defaults.
diff --git a/src/env.c b/src/env.c
index c8161356c..b3d6c01bc 100644
--- a/src/env.c
+++ b/src/env.c
@@ -18,7 +18,9 @@
 
 #include <config.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <getopt.h>
 #include <c-ctype.h>
 #include <signal.h>
@@ -73,7 +75,7 @@ static bool sig_mask_changed;
 /* Whether to list non default handling.  */
 static bool report_signal_handling;
 
-static char const shortopts[] = "+C:iS:u:v0 \t";
+static char const shortopts[] = "+C:iS:M:u:v0 \t";
 
 /* For long options that have no equivalent short option, use a
    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
@@ -89,6 +91,7 @@ static struct option const longopts[] =
 {
   {"ignore-environment", no_argument, NULL, 'i'},
   {"null", no_argument, NULL, '0'},
+  {"umask", required_argument, NULL, 'M'},
   {"unset", required_argument, NULL, 'u'},
   {"chdir", required_argument, NULL, 'C'},
   {"default-signal", optional_argument, NULL, DEFAULT_SIGNAL_OPTION},
@@ -129,6 +132,9 @@ Set each NAME to VALUE in the environment and run 
COMMAND.\n\
       fputs (_("\
   -S, --split-string=S  process and split S into separate arguments;\n\
                         used to pass multiple arguments on shebang lines\n\
+"), stdout);
+      fputs (_("\
+  -M, --umask=MASK      set MASK as umask\n\
 "), stdout);
       fputs (_("\
       --block-signal[=SIG]    block delivery of SIG signal(s) to COMMAND\n\
@@ -622,6 +628,23 @@ parse_signal_action_params (const char* optarg, bool 
set_default)
   free (optarg_writable);
 }
 
+static mode_t
+parse_umask_param (char const * optarg)
+{
+  char * end = NULL;
+
+  errno = 0;
+  long int res = strtol (optarg, &end, 8);
+
+  if (errno || *end)
+    die (EXIT_CANCELED, errno, _("unable to parse umask: %s"), optarg);
+
+  if (res > 07777 || res < 0)
+    die (EXIT_CANCELED, 0, _("invalid umask: %s"), optarg);
+
+  return (mode_t)res;
+}
+
 static void
 reset_signal_handlers (void)
 {
@@ -801,6 +824,7 @@ main (int argc, char **argv)
   bool ignore_environment = false;
   bool opt_nul_terminate_output = false;
   char const *newdir = NULL;
+  mode_t program_umask = -1;
 
   initialize_main (&argc, &argv);
   set_program_name (argv[0]);
@@ -820,6 +844,9 @@ main (int argc, char **argv)
         case 'i':
           ignore_environment = true;
           break;
+        case 'M':
+          program_umask = parse_umask_param (optarg);
+          break;
         case 'u':
           append_unset_var (optarg);
           break;
@@ -902,6 +929,12 @@ main (int argc, char **argv)
       usage (EXIT_CANCELED);
     }
 
+  if (program_umask >= 0 && ! program_specified)
+    {
+      error (0, 0, _("must specify command with --umask (-M)"));
+      usage (EXIT_CANCELED);
+    }
+
   if (newdir && ! program_specified)
     {
       error (0, 0, _("must specify command with --chdir (-C)"));
@@ -924,6 +957,13 @@ main (int argc, char **argv)
   if (report_signal_handling)
     list_signal_handling ();
 
+  if (program_umask)
+    {
+      devmsg ("umask:    %o\n", program_umask);
+
+      umask (program_umask);
+    }
+
   if (newdir)
     {
       devmsg ("chdir:    %s\n", quoteaf (newdir));
diff --git a/tests/env/umask.sh b/tests/env/umask.sh
new file mode 100644
index 000000000..b2e48fff2
--- /dev/null
+++ b/tests/env/umask.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Test env's -M/--umask option.
+
+# Copyright (C) 2019 Free Software Foundation, Inc.
+
+# This program 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.
+
+# This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ env
+
+# test getopt setup
+env -M       0777 true      || fail=1
+env --umask  0777 true      || fail=2
+
+# remove read permission
+env -M       0777 touch out || fail=3
+test -r out                 && fail=4
+
+# test param handling
+env -M       0777           && fail=5
+env -M          a touch out && fail=6
+env -M          9 touch out && fail=7
+env -M      17777 touch out && fail=8
+env -M         -1 touch out && fail=9
+
+Exit $fail
-- 
a



reply via email to

[Prev in Thread] Current Thread [Next in Thread]