113 lines
2.3 KiB
Go
113 lines
2.3 KiB
Go
package lib
|
|
|
|
import (
|
|
"bytes"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
// Spawner forks and execs given program, and also detaches form its control tty.
|
|
func (c *MyConfig) Spawner() {
|
|
for prg := range c.Channels.RunChan {
|
|
time.Sleep(25 * time.Millisecond)
|
|
|
|
devnullR, err := os.Open(os.DevNull)
|
|
if err != nil {
|
|
log.Printf("Unable to open /dev/null for reading: %s", err)
|
|
continue
|
|
}
|
|
defer devnullR.Close()
|
|
|
|
devnullW, err := os.OpenFile(os.DevNull, os.O_WRONLY|os.O_APPEND, 0644)
|
|
if err != nil {
|
|
log.Printf("Unable to open /dev/null for writing: %s", err)
|
|
continue
|
|
}
|
|
defer devnullW.Close()
|
|
|
|
spa := syscall.SysProcAttr{
|
|
Setsid: true,
|
|
Foreground: false,
|
|
}
|
|
|
|
pa := syscall.ProcAttr{
|
|
Dir: os.Getenv(`HOME`),
|
|
Env: os.Environ(),
|
|
Files: []uintptr{devnullR.Fd(), devnullW.Fd(), devnullW.Fd()},
|
|
Sys: &spa,
|
|
}
|
|
|
|
bin, err := exec.LookPath(prg[0])
|
|
|
|
if err != nil {
|
|
log.Printf("Unable to spawn %s: %s", prg[0], err)
|
|
continue
|
|
}
|
|
|
|
_, err = syscall.ForkExec(bin, prg, &pa)
|
|
|
|
if err != nil {
|
|
log.Printf("Unable to spawn %s: %s", prg[0], err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// CleanZombies reaps processes spawned by Spawner() and already exited.
|
|
func (c *MyConfig) CleanZombies() {
|
|
r := syscall.Rusage{}
|
|
|
|
for {
|
|
pid, _ := syscall.Wait4(-1, nil, syscall.WNOHANG, &r)
|
|
|
|
if pid > 0 {
|
|
continue
|
|
}
|
|
|
|
time.Sleep(1 * time.Minute)
|
|
}
|
|
}
|
|
|
|
// RunProcess runs given command and returns contents of command stdout. On error prints error on stderr and returns
|
|
// empty syting.
|
|
func RunProcess(command []string) string {
|
|
var (
|
|
cmd *exec.Cmd
|
|
stdout, stderr bytes.Buffer
|
|
)
|
|
|
|
switch len(command) {
|
|
case 1:
|
|
cmd = exec.Command(command[0], "") //nolint: gosec
|
|
default:
|
|
cmd = exec.Command(command[0], command[1:]...) //nolint: gosec
|
|
}
|
|
|
|
cmd.Dir = "/"
|
|
cmd.Stdout = &stdout
|
|
cmd.Stderr = &stderr
|
|
|
|
err := cmd.Run()
|
|
|
|
if err != nil {
|
|
if stdout.String() != "" {
|
|
log.Printf("Unable to run '%s': %s, %s", strings.Join(command, " "), err, stdout.String())
|
|
} else {
|
|
log.Printf("Unable to run '%s': %s", strings.Join(command, " "), err)
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
if stderr.String() != "" {
|
|
log.Printf("%s: %s", strings.Join(command, " "), stderr.String())
|
|
}
|
|
|
|
return strings.TrimRight(stdout.String(), "\n")
|
|
}
|
|
|
|
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */
|