@@ -87,6 +87,7 @@ static bool opt_unshare_cgroup_try = FALSE;
8787static bool opt_needs_devpts = FALSE;
8888static bool opt_new_session = FALSE;
8989static bool opt_die_with_parent = FALSE;
90+ static bool opt_forward_signals = FALSE;
9091static uid_t opt_sandbox_uid = -1 ;
9192static gid_t opt_sandbox_gid = -1 ;
9293static int opt_sync_fd = -1 ;
@@ -367,6 +368,7 @@ usage (int ecode, FILE *out)
367368 " --perms OCTAL Set permissions of next argument (--bind-data, --file, etc.)\n"
368369 " --size BYTES Set size of next argument (only for --tmpfs)\n"
369370 " --chmod OCTAL PATH Change permissions of PATH (must already exist)\n"
371+ " --forward-signals Forward various commonly used signals to the child process.\n"
370372 );
371373 exit (ecode );
372374}
@@ -381,22 +383,30 @@ handle_die_with_parent (void)
381383 die_with_error ("prctl" );
382384}
383385
386+ static int forwarded_signals [] =
387+ {
388+ SIGINT ,
389+ SIGTERM ,
390+ SIGCONT ,
391+ SIGHUP ,
392+ SIGQUIT ,
393+ SIGUSR1 ,
394+ SIGUSR2 ,
395+ SIGWINCH ,
396+ };
397+
384398static void
385- gate_signals ( int action , sigset_t * prevmask )
399+ block_forwarded_signals ( sigset_t * prevmask )
386400{
387401 sigset_t mask ;
388-
389- /* When unblocking, only restore if not previously blocked. */
402+ size_t i ;
390403
391404 sigemptyset (& mask );
392405
393- if (action == SIG_BLOCK || !sigismember (prevmask , SIGINT ))
394- sigaddset (& mask , SIGINT );
395-
396- if (action == SIG_BLOCK || !sigismember (prevmask , SIGTERM ))
397- sigaddset (& mask , SIGTERM );
406+ for (i = 0 ; i < N_ELEMENTS (forwarded_signals ); i ++ )
407+ sigaddset (& mask , forwarded_signals [i ]);
398408
399- if (sigprocmask (action , & mask , prevmask ) == -1 )
409+ if (sigprocmask (SIG_BLOCK , & mask , prevmask ) == -1 )
400410 die_with_error ("sigprocmask" );
401411}
402412
@@ -521,6 +531,7 @@ monitor_child (int event_fd, pid_t child_pid, int setup_finished_fd)
521531 int exitc ;
522532 pid_t died_pid ;
523533 int died_status ;
534+ size_t i ;
524535
525536 /* Close all extra fds in the monitoring process.
526537 Any passed in fds have been passed on to the child anyway. */
@@ -535,8 +546,9 @@ monitor_child (int event_fd, pid_t child_pid, int setup_finished_fd)
535546
536547 sigemptyset (& mask );
537548 sigaddset (& mask , SIGCHLD );
538- sigaddset (& mask , SIGINT );
539- sigaddset (& mask , SIGTERM );
549+
550+ for (i = 0 ; i < N_ELEMENTS (forwarded_signals ); i ++ )
551+ sigaddset (& mask , forwarded_signals [i ]);
540552
541553 signal_fd = signalfd (-1 , & mask , SFD_CLOEXEC | SFD_NONBLOCK );
542554 if (signal_fd == -1 )
@@ -584,8 +596,12 @@ monitor_child (int event_fd, pid_t child_pid, int setup_finished_fd)
584596
585597 /* Propagate signal to child so that it will take the correct
586598 * action. This avoids the parent terminating, leaving an orphan. */
587- if (fdsi .ssi_signo != SIGCHLD && kill (child_pid , fdsi .ssi_signo ))
588- die_with_error ("kill child" );
599+ if (fdsi .ssi_signo != SIGCHLD )
600+ {
601+ s = kill (child_pid , fdsi .ssi_signo );
602+ if (s != 0 && s != ESRCH )
603+ die_with_error ("kill child" );
604+ }
589605
590606 /* We may actually get several sigchld compressed into one
591607 SIGCHLD, so we have to handle all of them. */
@@ -2553,6 +2569,10 @@ parse_args_recurse (int *argcp,
25532569 argc -= 1 ;
25542570 break ;
25552571 }
2572+ else if (strcmp (arg , "--forward-signals" ) == 0 )
2573+ {
2574+ opt_forward_signals = TRUE;
2575+ }
25562576 else if (* arg == '-' )
25572577 {
25582578 die ("Unknown option %s" , arg );
@@ -2692,7 +2712,8 @@ main (int argc,
26922712 cleanup_free char * args_data UNUSED = NULL ;
26932713 int intermediate_pids_sockets [2 ] = {-1 , -1 };
26942714 const char * exec_path = NULL ;
2695- sigset_t sigmask ;
2715+ sigset_t sigmask_before_forwarding ;
2716+ sigemptyset (& sigmask_before_forwarding );
26962717
26972718 /* Handle --version early on before we try to acquire/drop
26982719 * any capabilities so it works in a build environment;
@@ -2867,7 +2888,8 @@ main (int argc,
28672888 block_sigchild ();
28682889
28692890 /* We block other signals here to avoid leaving an orphan. */
2870- gate_signals (SIG_BLOCK , & sigmask );
2891+ if (opt_forward_signals )
2892+ block_forwarded_signals (& sigmask_before_forwarding );
28712893
28722894 clone_flags = SIGCHLD | CLONE_NEWNS ;
28732895 if (opt_unshare_user )
@@ -3019,8 +3041,12 @@ main (int argc,
30193041 return monitor_child (event_fd , pid , setup_finished_pipe [0 ]);
30203042 }
30213043
3022- /* Unblock other signals here to receive signals from the parent. */
3023- gate_signals (SIG_UNBLOCK , & sigmask );
3044+ /* Restore the state of sigmask from before the blocking. */
3045+ if (opt_forward_signals )
3046+ {
3047+ if (sigprocmask (SIG_SETMASK , & sigmask_before_forwarding , NULL ) != 0 )
3048+ die_with_error ("sigprocmask" );
3049+ }
30243050
30253051 if (opt_pidns_fd > 0 )
30263052 {
0 commit comments