github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/libinit/proc_linux.go (about) 1 // Copyright 2014-2019 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package libinit 6 7 import ( 8 "log" 9 "os" 10 "os/exec" 11 "syscall" 12 ) 13 14 // WaitOrphans waits for all remaining processes on the system to exit. 15 func WaitOrphans() uint { 16 var numReaped uint 17 for { 18 var ( 19 s syscall.WaitStatus 20 r syscall.Rusage 21 ) 22 p, err := syscall.Wait4(-1, &s, 0, &r) 23 if p == -1 { 24 break 25 } 26 log.Printf("%v: exited with %v, status %v, rusage %v", p, err, s, r) 27 numReaped++ 28 } 29 return numReaped 30 } 31 32 // WithTTYControl turns on controlling the TTY on this command. 33 func WithTTYControl(ctty bool) CommandModifier { 34 return func(c *exec.Cmd) { 35 if c.SysProcAttr == nil { 36 c.SysProcAttr = &syscall.SysProcAttr{} 37 } 38 c.SysProcAttr.Setctty = ctty 39 c.SysProcAttr.Setsid = ctty 40 } 41 } 42 43 // WithCloneFlags adds clone(2) flags to the *exec.Cmd. 44 func WithCloneFlags(flags uintptr) CommandModifier { 45 return func(c *exec.Cmd) { 46 if c.SysProcAttr == nil { 47 c.SysProcAttr = &syscall.SysProcAttr{} 48 } 49 c.SysProcAttr.Cloneflags = flags 50 } 51 } 52 53 func init() { 54 osDefault = linuxDefault 55 } 56 57 func linuxDefault(c *exec.Cmd) { 58 c.SysProcAttr = &syscall.SysProcAttr{ 59 Setctty: true, 60 Setsid: true, 61 } 62 } 63 64 // FIX ME: make it not linux-specific 65 // RunCommands runs commands in sequence. 66 // 67 // RunCommands returns how many commands existed and were attempted to run. 68 // 69 // commands must refer to absolute paths at the moment. 70 func RunCommands(debug func(string, ...interface{}), commands ...*exec.Cmd) int { 71 var cmdCount int 72 for _, cmd := range commands { 73 if _, err := os.Stat(cmd.Path); os.IsNotExist(err) { 74 debug("%v", err) 75 continue 76 } 77 78 cmdCount++ 79 debug("Trying to run %v", cmd) 80 if err := cmd.Start(); err != nil { 81 log.Printf("Error starting %v: %v", cmd, err) 82 continue 83 } 84 85 for { 86 var s syscall.WaitStatus 87 var r syscall.Rusage 88 if p, err := syscall.Wait4(-1, &s, 0, &r); p == cmd.Process.Pid { 89 debug("Shell exited, exit status %d", s.ExitStatus()) 90 break 91 } else if p != -1 { 92 debug("Reaped PID %d, exit status %d", p, s.ExitStatus()) 93 } else { 94 debug("Error from Wait4 for orphaned child: %v", err) 95 break 96 } 97 } 98 if err := cmd.Process.Release(); err != nil { 99 log.Printf("Error releasing process %v: %v", cmd, err) 100 } 101 } 102 return cmdCount 103 }