github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/libinit/proc_plan9.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 w syscall.Waitmsg
    19  		err := syscall.Await(&w)
    20  		if err != nil {
    21  			break
    22  		}
    23  		log.Printf("Exited with %v", w)
    24  		numReaped++
    25  	}
    26  	return numReaped
    27  }
    28  
    29  // WithRforkFlags adds rfork flags to the *exec.Cmd.
    30  func WithRforkFlags(flags uintptr) CommandModifier {
    31  	return func(c *exec.Cmd) {
    32  		if c.SysProcAttr == nil {
    33  			c.SysProcAttr = &syscall.SysProcAttr{}
    34  		}
    35  		c.SysProcAttr.Rfork = int(flags)
    36  	}
    37  }
    38  
    39  func init() {
    40  	osDefault = plan9Default
    41  }
    42  
    43  func plan9Default(c *exec.Cmd) {
    44  	c.SysProcAttr = &syscall.SysProcAttr{}
    45  }
    46  
    47  // FIX ME: make it not linux-specific
    48  // RunCommands runs commands in sequence.
    49  //
    50  // RunCommands returns how many commands existed and were attempted to run.
    51  //
    52  // commands must refer to absolute paths at the moment.
    53  func RunCommands(debug func(string, ...interface{}), commands ...*exec.Cmd) int {
    54  	var cmdCount int
    55  	for _, cmd := range commands {
    56  		if _, err := os.Stat(cmd.Path); os.IsNotExist(err) {
    57  			debug("%v", err)
    58  			continue
    59  		}
    60  
    61  		cmdCount++
    62  		debug("Trying to run %v", cmd)
    63  		if err := cmd.Start(); err != nil {
    64  			log.Printf("Error starting %v: %v", cmd, err)
    65  			continue
    66  		}
    67  
    68  		for {
    69  			var w syscall.Waitmsg
    70  			if err := syscall.Await(&w); err != nil {
    71  				debug("Error from Await: %v", err)
    72  				break
    73  			}
    74  			if w.Pid == cmd.Process.Pid {
    75  				debug("Shell exited, exit status %v", w)
    76  				break
    77  			}
    78  			debug("Reaped PID %d, exit status %v", w.Pid, w)
    79  		}
    80  		if err := cmd.Process.Release(); err != nil {
    81  			log.Printf("Error releasing process %v: %v", cmd, err)
    82  		}
    83  	}
    84  	return cmdCount
    85  }