// Run will launch the stage2 binary with the desired settings and execute the // specified command. It will return once the stage2 has been started. func (l *Launcher) Run(cmdargs ...string) (*os.Process, error) { args, extraFiles := l.generateArgs(cmdargs) // get the executable path to ourself self, err := os.Readlink("/proc/self/exe") if err != nil { return nil, err } // Create and initialize the spawnwer. cmd := exec.Command(self, args...) cmd.ExtraFiles = extraFiles if l.Stdin != nil { cmd.Stdin = l.Stdin } if l.Stdout != nil { cmd.Stdout = l.Stdout } if l.Stderr != nil { cmd.Stderr = l.Stderr } // The spawner keys off this environment variable to know when it is supposed // to run and take over execution. cmd.Env = []string{ "SPAWNER_INTERCEPT=1", } // tty handling if str.IsTerminal(l.Stdin) { // Include setting the controlling tty, and close stdin (the slave pty) // after the command is started. cmd.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true} l.postStart = append(l.postStart, func() { l.Stdin.Close() }) } else { cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true} } // Start the container. if err := cmd.Start(); err != nil { return nil, err } // Run any postStart funcs, just to cleanup for _, f := range l.postStart { f() } // Wait for the command to ensure the process is reaped when its done. if l.Detach { go cmd.Wait() } return cmd.Process, nil }
func main() { for _, label := range []string{ "stdin", "stdout", "stderr", } { var fh *os.File switch label { case "stdin": fh = os.Stdin case "stdout": fh = os.Stdout case "stderr": fh = os.Stderr default: panic("unknown label") } if target.IsTerminal(fh) { fmt.Printf("%s is a terminal :)\n", label) } else { fmt.Printf("%s is not a terminal :(\n", label) } } }