generated from ContainerSSH/library-template
-
Notifications
You must be signed in to change notification settings - Fork 2
/
console.go
93 lines (83 loc) · 2.26 KB
/
console.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
package main
import (
"encoding/binary"
"fmt"
"io"
"os"
"strings"
)
// execFunc is a function that replaces the current program image with the executed one. If only returns with an error
// if the execution failed
type execFunc func(argv0 string, argv []string, envv []string) (err error)
// exitFunc exits the current program with the specified exit code.
type exitFunc func(code int)
func console(stdin io.Reader, stdout io.Writer, stderr io.Writer, args []string, exec execFunc, exit exitFunc) {
env, program, wait, reportPID := parseConsoleArgs(args, exit)
if wait {
firstByte := make([]byte, 1)
readBytes, err := stdin.Read(firstByte)
if err != nil {
usage(fmt.Sprintf("Failed to read from stdin (%v)", err), true, 2, exit)
}
if readBytes != 1 {
usage("Nothing read from stdin", true, 2, exit)
}
if firstByte[0] != '\000' && firstByte[0] != '\n' {
usage("Unexpected first character. Send either a null or a newline character to start program.", true, 2, exit)
}
}
if reportPID {
pid := uint32(os.Getpid())
b := make([]byte, 4)
binary.LittleEndian.PutUint32(b, pid)
_, err := stdout.Write(b)
if err != nil {
exit(3)
}
}
if err := exec(program[0], program, env); err != nil {
_, _ = stderr.Write([]byte(err.Error()))
exit(127)
}
}
func parseConsoleArgs(args []string, exitFunc func(code int)) ([]string, []string, bool, bool) {
var env = os.Environ()
var program []string
wait := false
reportPID := false
loop:
for {
if len(args) == 0 {
break loop
}
switch args[0] {
case "--":
if len(args) == 1 {
usage("no program to run passed", true, 1, exitFunc)
}
program = args[1:]
args = []string{}
case "--env":
if len(args) == 1 {
usage("--env requires an argument", true, 1, exitFunc)
}
if strings.HasPrefix(args[1], "--") {
usage("--env requires an argument", true, 1, exitFunc)
}
if !strings.Contains(args[1], "=") {
usage("--env requires an argument in the format of NAME=VALUE", true, 1, exitFunc)
}
env = append(env, args[1])
args = args[2:]
case "--wait":
wait = true
args = args[1:]
case "--pid":
reportPID = true
args = args[1:]
default:
usage(fmt.Sprintf("invalid parameter: %s", args[0]), true, 1, exitFunc)
}
}
return env, program, wait, reportPID
}