diff --git a/cmd/rootlesskit/main.go b/cmd/rootlesskit/main.go index 97bf3ecd..ac18ce55 100644 --- a/cmd/rootlesskit/main.go +++ b/cmd/rootlesskit/main.go @@ -373,6 +373,7 @@ func createChildOpt(clicontext *cli.Context, pipeFDEnvKey string, targetCmd []st PipeFDEnvKey: pipeFDEnvKey, TargetCmd: targetCmd, MountProcfs: clicontext.Bool("pidns"), + Reaper: clicontext.Bool("pidns"), } switch s := clicontext.String("net"); s { case "host": diff --git a/pkg/child/child.go b/pkg/child/child.go index d2d942ee..5faf99a6 100644 --- a/pkg/child/child.go +++ b/pkg/child/child.go @@ -4,6 +4,7 @@ import ( "io/ioutil" "os" "os/exec" + "os/signal" "runtime" "strconv" "syscall" @@ -165,6 +166,7 @@ type Opt struct { CopyUpDirs []string PortDriver port.ChildDriver MountProcfs bool // needs to be set if (and only if) parent.Opt.CreatePIDNS is set + Reaper bool } func Child(opt Opt) error { @@ -236,8 +238,14 @@ func Child(opt Opt) error { if err != nil { return err } - if err := cmd.Run(); err != nil { - return errors.Wrapf(err, "command %v exited", opt.TargetCmd) + if opt.Reaper { + if err := runAndReap(cmd); err != nil { + return errors.Wrapf(err, "command %v exited", opt.TargetCmd) + } + } else { + if err := cmd.Run(); err != nil { + return errors.Wrapf(err, "command %v exited", opt.TargetCmd) + } } if opt.PortDriver != nil { portQuitCh <- struct{}{} @@ -245,3 +253,27 @@ func Child(opt Opt) error { } return nil } + +func runAndReap(cmd *exec.Cmd) error { + c := make(chan os.Signal, 32) + signal.Notify(c, syscall.SIGCHLD) + if err := cmd.Start(); err != nil { + return err + } + result := make(chan error) + go func() { + defer close(result) + for range c { + for { + if pid, err := syscall.Wait4(-1, nil, syscall.WNOHANG, nil); err != nil || pid <= 0 { + break + } else { + if pid == cmd.Process.Pid { + result <- cmd.Wait() + } + } + } + } + }() + return <-result +}