github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/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 "github.com/u-root/u-root/pkg/upath" 14 ) 15 16 // WaitOrphans waits for all remaining processes on the system to exit. 17 func WaitOrphans() uint { 18 var numReaped uint 19 for { 20 var ( 21 s syscall.WaitStatus 22 r syscall.Rusage 23 ) 24 p, err := syscall.Wait4(-1, &s, 0, &r) 25 if p == -1 { 26 break 27 } 28 log.Printf("%v: exited with %v, status %v, rusage %v", p, err, s, r) 29 numReaped++ 30 } 31 return numReaped 32 } 33 34 // RunCommands runs commands in sequence. 35 // 36 // RunCommands returns how many commands existed and were attempted to run. 37 // 38 // commands must refer to absolute paths at the moment. 39 func RunCommands(debug func(string, ...interface{}), commands ...*exec.Cmd) int { 40 var cmdCount int 41 for _, cmd := range commands { 42 if _, err := os.Stat(cmd.Path); os.IsNotExist(err) { 43 debug("%v", err) 44 continue 45 } 46 47 cmdCount++ 48 debug("Trying to run %v", cmd) 49 if err := cmd.Start(); err != nil { 50 log.Printf("Error starting %v: %v", cmd, err) 51 continue 52 } 53 54 for { 55 var s syscall.WaitStatus 56 var r syscall.Rusage 57 if p, err := syscall.Wait4(-1, &s, 0, &r); p == cmd.Process.Pid { 58 debug("Shell exited, exit status %d", s.ExitStatus()) 59 break 60 } else if p != -1 { 61 debug("Reaped PID %d, exit status %d", p, s.ExitStatus()) 62 } else { 63 debug("Error from Wait4 for orphaned child: %v", err) 64 break 65 } 66 } 67 if err := cmd.Process.Release(); err != nil { 68 log.Printf("Error releasing process %v: %v", cmd, err) 69 } 70 } 71 return cmdCount 72 } 73 74 // CommandModifier makes *exec.Cmd construction modular. 75 type CommandModifier func(c *exec.Cmd) 76 77 // WithTTYControl turns on controlling the TTY on this command. 78 func WithTTYControl(ctty bool) CommandModifier { 79 return func(c *exec.Cmd) { 80 if c.SysProcAttr == nil { 81 c.SysProcAttr = &syscall.SysProcAttr{} 82 } 83 c.SysProcAttr.Setctty = ctty 84 c.SysProcAttr.Setsid = ctty 85 } 86 } 87 88 // WithCloneFlags adds clone(2) flags to the *exec.Cmd. 89 func WithCloneFlags(flags uintptr) CommandModifier { 90 return func(c *exec.Cmd) { 91 if c.SysProcAttr == nil { 92 c.SysProcAttr = &syscall.SysProcAttr{} 93 } 94 c.SysProcAttr.Cloneflags = flags 95 } 96 } 97 98 // WithArguments adds command-line arguments to a command. 99 func WithArguments(arg ...string) CommandModifier { 100 return func(c *exec.Cmd) { 101 if len(arg) > 0 { 102 c.Args = append(c.Args, arg...) 103 } 104 } 105 } 106 107 // Command constructs an *exec.Cmd object. 108 func Command(bin string, m ...CommandModifier) *exec.Cmd { 109 bin = upath.UrootPath(bin) 110 cmd := exec.Command(bin) 111 cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr 112 // By default, this stuff is on. 113 cmd.SysProcAttr = &syscall.SysProcAttr{ 114 Setctty: true, 115 Setsid: true, 116 } 117 for _, mod := range m { 118 mod(cmd) 119 } 120 return cmd 121 }