>From deb0d5a64eef13bdffe9a84f98fc6a5b18805262 Mon Sep 17 00:00:00 2001 From: Assaf Gordon Date: Mon, 25 Feb 2019 15:37:47 -0700 Subject: [PATCH 2/3] env: add --{block,unblock,setmask}-signal=SIG options Suggested by Paul Eggert in http://bugs.gnu.org/34488#71 . * NEWS: Mention new options. * doc/coreutils.texi (env invocation): Document new options. * src/env.c (block_signals, unblock_signals): New global variables. (longopts, usage): Add new options. (parse_block_signal_params): Parse command-line options. (set_signal_proc_mask): Call sigprocmask to block/unblock signals. (main): Handle new command-line options, call set_signal_proc_mask. * man/env.x (SEE ALSO): Mention sigprocmask. --- NEWS | 3 ++ doc/coreutils.texi | 10 +++++ man/env.x | 2 +- src/env.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 125 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index ddbbaf138..cb8aa107f 100644 --- a/NEWS +++ b/NEWS @@ -84,6 +84,9 @@ GNU coreutils NEWS -*- outline -*- env now supports '--default-singal[=SIG]' and '--ignore-signal[=SIG]' options to set signal handlers before executing a program. + env now supports '--{block,unblock,setmask}-singal[=SIG]' to block/unblock + signal delivery before executing a program. + ** New commands basenc is added to complement existing base64,base32 commands, diff --git a/doc/coreutils.texi b/doc/coreutils.texi index c2c202b28..8f5212a72 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -17299,6 +17299,16 @@ set to default while @samp{SIGINT} is ignored: env --default-signal=INT,PIPE --ignore-signal=INT @end example address@hidden address@hidden +Block signal @var{sig} from being delivered. + address@hidden address@hidden +Unblock signal @var{sig}. + address@hidden address@hidden +Set list of blocked signals to @var{sig}. All other signals will be unblocked. + + @item -p Equivalent to @option{--default-signal=PIPE} - sets SIGPIPE to its default diff --git a/man/env.x b/man/env.x index 09c7f0f3a..b787fe3a7 100644 --- a/man/env.x +++ b/man/env.x @@ -105,4 +105,4 @@ cooperating) programs." .RE [SEE ALSO] -sigaction(2), signal(7) +sigaction(2), sigprocmask(2), signal(7) diff --git a/src/env.c b/src/env.c index bd9b68560..4cae7d47f 100644 --- a/src/env.c +++ b/src/env.c @@ -61,6 +61,11 @@ enum SIGNAL_MODE { }; static enum SIGNAL_MODE signals[SIGNUM_BOUND]; +/* Set of signals to block. */ +static sigset_t block_signals; + +/* Set of signals to unblock. */ +static sigset_t unblock_signals; static char const shortopts[] = "+C:ipS:u:v0 \t"; @@ -70,7 +75,10 @@ static char const shortopts[] = "+C:ipS:u:v0 \t"; enum { DEFAULT_SIGNAL_OPTION = CHAR_MAX + 1, - IGNORE_SIGNAL_OPTION + IGNORE_SIGNAL_OPTION, + BLOCK_SIGNAL_OPTION, + UNBLOCK_SIGNAL_OPTION, + SETMASK_SIGNAL_OPTION }; static struct option const longopts[] = @@ -81,6 +89,9 @@ static struct option const longopts[] = {"chdir", required_argument, NULL, 'C'}, {"default-signal", optional_argument, NULL, DEFAULT_SIGNAL_OPTION}, {"ignore-signal", optional_argument, NULL, IGNORE_SIGNAL_OPTION}, + {"block-signal", optional_argument, NULL, BLOCK_SIGNAL_OPTION}, + {"unblock-signal", optional_argument, NULL, UNBLOCK_SIGNAL_OPTION}, + {"setmask-signal", optional_argument, NULL, SETMASK_SIGNAL_OPTION}, {"debug", no_argument, NULL, 'v'}, {"split-string", required_argument, NULL, 'S'}, {GETOPT_HELP_OPTION_DECL}, @@ -110,6 +121,15 @@ Set each NAME to VALUE in the environment and run COMMAND.\n\ -u, --unset=NAME remove variable from the environment\n\ "), stdout); fputs (_("\ + --block-signal[=SIG] block signal SIG.\n\ +"), stdout); + fputs (_("\ + --unblock-signal[=SIG] unblock signal SIG.\n\ +"), stdout); + fputs (_("\ + --setmask-signal[=SIG] set blocked signal(s) mask to SIG.\n\ +"), stdout); + fputs (_("\ -C, --chdir=DIR change working directory to DIR\n\ "), stdout); fputs (_("\ @@ -649,6 +669,84 @@ reset_signal_handlers (void) } } +static void +parse_block_signal_params (const char* optarg, bool block) +{ + char signame[SIG2STR_MAX]; + char *opt_sig; + char *optarg_writable; + + if (! optarg) + { + /* without an argument, reset all signals. */ + sigfillset (block ? &block_signals : &unblock_signals); + sigemptyset (block ? &unblock_signals : &block_signals); + return; + } + + optarg_writable = xstrdup (optarg); + + opt_sig = strtok (optarg_writable, ","); + while (opt_sig) + { + int signum = operand2sig (opt_sig, signame); + /* operand2sig accepts signal 0 (EXIT) - but we reject it. */ + if (signum == 0) + error (0, 0, _("%s: invalid signal"), quote (opt_sig)); + if (signum <= 0) + usage (exit_failure); + + sigaddset (block ? &block_signals : &unblock_signals, signum); + sigdelset (block ? &unblock_signals : &block_signals, signum); + + opt_sig = strtok (NULL, ","); + } + + free (optarg_writable); +} + +static void +set_signal_proc_mask (void) +{ + /* Get the existing signal mask */ + sigset_t set; + const char *debug_act; + + sigemptyset (&set); + + if (sigprocmask (0, NULL, &set)) + die (EXIT_CANCELED, errno, _("failed to get signal process mask")); + + for (int i = 1; i < SIGNUM_BOUND; i++) + { + if (sigismember (&block_signals, i)) + { + sigaddset (&set, i); + debug_act = "BLOCK"; + } + else if (sigismember (&unblock_signals, i)) + { + sigdelset (&set, i); + debug_act = "UNBLOCK"; + } + else + { + debug_act = NULL; + } + + if (dev_debug && debug_act) + { + char signame[SIG2STR_MAX]; + sig2str (i, signame); + devmsg ("signal %s (%d) procmask set to %s\n", + signame, i, debug_act); + } + } + + if (sigprocmask (SIG_SETMASK, &set, NULL)) + die (EXIT_CANCELED, errno, _("failed to set signal process mask")); +} + int main (int argc, char **argv) { @@ -692,6 +790,17 @@ main (int argc, char **argv) case IGNORE_SIGNAL_OPTION: parse_signal_action_params (optarg, false); break; + case BLOCK_SIGNAL_OPTION: + parse_block_signal_params (optarg, true); + break; + case UNBLOCK_SIGNAL_OPTION: + parse_block_signal_params (optarg, false); + break; + case SETMASK_SIGNAL_OPTION: + sigfillset (&unblock_signals); + sigemptyset (&block_signals); + parse_block_signal_params (optarg, true); + break; case 'C': newdir = optarg; break; @@ -768,6 +877,7 @@ main (int argc, char **argv) } reset_signal_handlers (); + set_signal_proc_mask (); if (newdir) { -- 2.11.0