]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
unshare: Add --kill-child option.
authorNiklas Hambüchen <mail@nh2.me>
Tue, 19 Sep 2017 18:39:00 +0000 (20:39 +0200)
committerNiklas Hambüchen <mail@nh2.me>
Sat, 14 Oct 2017 02:46:13 +0000 (04:46 +0200)
This allows to conveniently kill the entire process tree
below the forked program, a common problem when scripting
tasks that need to reliably fully terminate without leaving
reparented subprocesses behind.

The example added to the man page shows the most common use.

Implemented using prctl(PR_SET_PDEATHSIG, ...).

bash-completion/unshare
sys-utils/unshare.1
sys-utils/unshare.c

index cd73c1d6cf806dfeeec9273173bbc7611dc7c147..3fda4a19440802a40549c582f7e1d047938b587b 100644 (file)
@@ -27,6 +27,7 @@ _unshare_module()
                                --user
                                --cgroup
                                --fork
+                               --kill-child
                                --mount-proc
                                --map-root-user
                                --propagation
index 79ab96a1be9a4eeb28bdc5f22b8348ac29f04112..420b48b73c6d03e025f6515baea27aa78d431454 100644 (file)
@@ -138,6 +138,12 @@ by bind mount.
 Fork the specified \fIprogram\fR as a child process of \fBunshare\fR rather than
 running it directly.  This is useful when creating a new PID namespace.
 .TP
+.BR \-\-kill\-child
+When \fBunshare\fR terminates, have \fBSIGKILL\fR be sent to the forked child process.
+Combined with \fB--pid\fR this allows for an easy and realiable killing of the entire
+process tree below \fBunshare\fR.
+This option implies \fB--fork\fR.
+.TP
 .BR \-\-mount\-proc [ =\fImountpoint ]
 Just before running the program, mount the proc filesystem at \fImountpoint\fP
 (default is /proc).  This is useful when creating a new PID namespace.  It also
@@ -229,6 +235,17 @@ the bind reference.
 Establish a persistent mount namespace referenced by the bind mount
 /root/namespaces/mnt.  This example shows a portable solution, because it
 makes sure that the bind mount is created on a shared filesystem.
+.TP
+.B # unshare -pf --kill-child -- bash -c "(sleep 999 &) && sleep 1000" &
+.TQ
+.B # pid=$!
+.TQ
+.B # kill $pid
+.br
+Reliable killing of subprocesses of the \fIprogram\fR.
+When \fBunshare\fR gets killed, everything below it gets killed as well.
+Without it, the children of \fIprogram\fR would have orphaned and
+been re-parented to PID 1.
 
 .SH SEE ALSO
 .BR clone (2),
index b5e0d6608c8241130a5fa000e7f54b932358bd94..b7448420ba988848c378482cbf051f20cf08a7b0 100644 (file)
@@ -28,6 +28,7 @@
 #include <sys/mount.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/prctl.h>
 
 /* we only need some defines missing in sys/mount.h, no libmount linkage */
 #include <libmount.h>
@@ -258,6 +259,7 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" -U, --user[=<file>]       unshare user namespace\n"), out);
        fputs(_(" -C, --cgroup[=<file>]     unshare cgroup namespace\n"), out);
        fputs(_(" -f, --fork                fork before launching <program>\n"), out);
+       fputs(_("     --kill-child          when dying, kill the forked child (implies --fork)\n"), out);
        fputs(_("     --mount-proc[=<dir>]  mount proc filesystem first (implies --mount)\n"), out);
        fputs(_(" -r, --map-root-user       map current user to root (implies --user)\n"), out);
        fputs(_("     --propagation slave|shared|private|unchanged\n"
@@ -276,7 +278,8 @@ int main(int argc, char *argv[])
        enum {
                OPT_MOUNTPROC = CHAR_MAX + 1,
                OPT_PROPAGATION,
-               OPT_SETGROUPS
+               OPT_SETGROUPS,
+               OPT_KILLCHILD
        };
        static const struct option longopts[] = {
                { "help",          no_argument,       NULL, 'h'             },
@@ -291,6 +294,7 @@ int main(int argc, char *argv[])
                { "cgroup",        optional_argument, NULL, 'C'             },
 
                { "fork",          no_argument,       NULL, 'f'             },
+               { "kill-child",    no_argument,       NULL, OPT_KILLCHILD   },
                { "mount-proc",    optional_argument, NULL, OPT_MOUNTPROC   },
                { "map-root-user", no_argument,       NULL, 'r'             },
                { "propagation",   required_argument, NULL, OPT_PROPAGATION },
@@ -301,6 +305,7 @@ int main(int argc, char *argv[])
        int setgrpcmd = SETGROUPS_NONE;
        int unshare_flags = 0;
        int c, forkit = 0, maproot = 0;
+       int kill_child = 0;
        const char *procmnt = NULL;
        pid_t pid = 0;
        int fds[2];
@@ -373,6 +378,10 @@ int main(int argc, char *argv[])
                case OPT_PROPAGATION:
                        propagation = parse_propagation(optarg);
                        break;
+               case OPT_KILLCHILD:
+                       kill_child = 1;
+                       forkit = 1;
+                       break;
                default:
                        errtryhelp(EXIT_FAILURE);
                }
@@ -430,6 +439,9 @@ int main(int argc, char *argv[])
                }
        }
 
+       if (kill_child)
+               if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0)
+                       err(EXIT_FAILURE, "prctl failed");
 
        if (maproot) {
                if (setgrpcmd == SETGROUPS_ALLOW)