-
Notifications
You must be signed in to change notification settings - Fork 0
/
process.go
121 lines (100 loc) · 2.32 KB
/
process.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package main
import (
"errors"
"fmt"
"os"
"os/exec"
"strings"
"syscall"
"github.com/charmbracelet/log"
)
type Process struct {
args []string
env []string
workingDir string
}
func NewProcess(cfg MachineConfig) (*Process, error) {
if len(cfg.ImageConfig.Cmd) < 1 && len(cfg.CmdOverride) < 1 {
return nil, fmt.Errorf("error no cmd provided")
}
args := append(cfg.ImageConfig.Entrypoint, cfg.ImageConfig.Cmd...)
if len(cfg.CmdOverride) > 0 {
args = cfg.CmdOverride
}
envars := append(cfg.ImageConfig.Env, cfg.ExtraEnv...)
if err := populateProcessEnv(envars); err != nil {
return nil, fmt.Errorf("error populating process env: %v", err)
}
return &Process{
args: args,
env: envars,
workingDir: cfg.ImageConfig.WorkingDir,
}, nil
}
func (p *Process) Run() error {
lp, err := exec.LookPath(p.args[0])
if err != nil {
return fmt.Errorf("error searching for process: %v", err)
}
cmd := &exec.Cmd{
Path: lp,
Args: p.args,
Env: p.env,
Dir: p.workingDir,
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
log.Infof("Running %s", cmd.String())
err = Start(cmd)
if err != nil {
return err
}
if err := cmd.Wait(); err != nil {
return err
}
return err
}
func Start(cmd *exec.Cmd) error {
if cmd.SysProcAttr == nil {
cmd.SysProcAttr = &syscall.SysProcAttr{}
}
cmd.SysProcAttr.Setsid = true
cmd.SysProcAttr.Setctty = true
if err := cmd.Start(); err != nil {
return err
}
return nil
}
func parseCmdArgs(cmd []string) (string, []string, error) {
cmdPath, err := exec.LookPath(cmd[0])
if err != nil {
return "", nil, err
}
if len(cmd) == 1 {
return cmdPath, nil, nil
}
return cmdPath, cmd[1:], nil
}
func populateProcessEnv(env []string) error {
for _, pair := range env {
p := strings.SplitN(pair, "=", 2)
if len(p) < 2 {
return errors.New("invalid env var: missing '='")
}
name, val := p[0], p[1]
if name == "" {
return errors.New("invalid env var: name cannot be empty")
}
if strings.IndexByte(name, 0) >= 0 {
return errors.New("invalid env var: name contains null byte")
}
if strings.IndexByte(val, 0) >= 0 {
return errors.New("invalid env var: value contains null byte")
}
if err := os.Setenv(name, val); err != nil {
return fmt.Errorf("could not set env var: system shit: %v", err)
}
}
return nil
}