github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/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 12 "golang.org/x/sys/unix" 13 ) 14 15 // WaitOrphans waits for all remaining processes on the system to exit. 16 func WaitOrphans() uint { 17 var numReaped uint 18 for { 19 var ( 20 s unix.WaitStatus 21 r unix.Rusage 22 ) 23 p, err := unix.Wait4(-1, &s, 0, &r) 24 if p == -1 { 25 break 26 } 27 log.Printf("%v: exited with %v, status %v, rusage %v", p, err, s, r) 28 numReaped++ 29 } 30 return numReaped 31 } 32 33 // WithTTYControl turns on controlling the TTY on this command. 34 func WithTTYControl(ctty bool) CommandModifier { 35 return func(c *exec.Cmd) { 36 if c.SysProcAttr == nil { 37 c.SysProcAttr = &unix.SysProcAttr{} 38 } 39 c.SysProcAttr.Setctty = ctty 40 c.SysProcAttr.Setsid = ctty 41 } 42 } 43 44 // WithCloneFlags adds clone(2) flags to the *exec.Cmd. 45 func WithCloneFlags(flags uintptr) CommandModifier { 46 return func(c *exec.Cmd) { 47 if c.SysProcAttr == nil { 48 c.SysProcAttr = &unix.SysProcAttr{} 49 } 50 c.SysProcAttr.Cloneflags = flags 51 } 52 } 53 54 func init() { 55 osDefault = linuxDefault 56 } 57 58 func linuxDefault(c *exec.Cmd) { 59 c.SysProcAttr = &unix.SysProcAttr{ 60 Setctty: true, 61 Setsid: true, 62 } 63 } 64 65 // FIX ME: make it not linux-specific 66 // RunCommands runs commands in sequence. 67 // 68 // RunCommands returns how many commands existed and were attempted to run. 69 // 70 // commands must refer to absolute paths at the moment. 71 func RunCommands(debug func(string, ...interface{}), commands ...*exec.Cmd) int { 72 var cmdCount int 73 for _, cmd := range commands { 74 if _, err := os.Stat(cmd.Path); os.IsNotExist(err) { 75 debug("%v", err) 76 continue 77 } 78 79 cmdCount++ 80 debug("Trying to run %v", cmd) 81 if err := cmd.Start(); err != nil { 82 log.Printf("Error starting %v: %v", cmd, err) 83 continue 84 } 85 86 for { 87 var s unix.WaitStatus 88 var r unix.Rusage 89 if p, err := unix.Wait4(-1, &s, 0, &r); p == cmd.Process.Pid { 90 debug("Shell exited, exit status %d", s.ExitStatus()) 91 break 92 } else if p != -1 { 93 debug("Reaped PID %d, exit status %d", p, s.ExitStatus()) 94 } else { 95 debug("Error from Wait4 for orphaned child: %v", err) 96 break 97 } 98 } 99 if err := cmd.Process.Release(); err != nil { 100 log.Printf("Error releasing process %v: %v", cmd, err) 101 } 102 } 103 return cmdCount 104 }