1package main
2
3import (
4 "fmt"
5 "os"
6 "path/filepath"
7 "strconv"
8 "syscall"
9 "time"
10)
11//this is a replacement for GNU's thelp.pl from their test suite.
12
13func main() {
14 args := os.Args[1:]
15 quiet := false
16 timeout := 10 * time.Second
17
18 if len(args) > 0 && args[0] == "-q" {
19 quiet = true
20 args = args[1:]
21 }
22
23 for len(args) > 0 {
24 if len(args) < 2 {
25 die("Missing value for " + args[0])
26 }
27 op, arg := args[0], args[1]
28 args = args[2:]
29
30 nextTimeout, handled := runOp(quiet, timeout, op, arg)
31 timeout = nextTimeout
32 if handled {
33 continue
34 }
35 die(fmt.Sprintf("Invalid command: %s %s", op, arg))
36 }
37}
38
39func runOp(quiet bool, timeout time.Duration, op, arg string) (time.Duration, bool) {
40 switch op {
41 case "out":
42 fmt.Println(arg)
43 case "raw":
44 fmt.Print(arg)
45 case "env":
46 if !quiet {
47 fmt.Printf("%s=", arg)
48 }
49 if value, ok := os.LookupEnv(arg); ok {
50 fmt.Println(value)
51 } else {
52 fmt.Println("<unset>")
53 }
54 case "file":
55 if !quiet {
56 fmt.Printf("file %s\n", arg)
57 }
58 f, err := os.Create(arg)
59 if err != nil {
60 die(fmt.Sprintf("%s: open: %v", arg, err))
61 }
62 if err := f.Close(); err != nil {
63 die(fmt.Sprintf("%s: close: %v", arg, err))
64 }
65 case "exist":
66 if _, err := os.Stat(arg); err != nil {
67 die(fmt.Sprintf("%s: file should exist: %v", arg, err))
68 }
69 if !quiet {
70 fmt.Printf("exist %s\n", arg)
71 }
72 case "noexist":
73 if _, err := os.Stat(arg); err == nil {
74 die(fmt.Sprintf("%s: file exists", arg))
75 } else if !os.IsNotExist(err) {
76 die(fmt.Sprintf("%s: stat: %v", arg, err))
77 }
78 if !quiet {
79 fmt.Printf("noexist %s\n", arg)
80 }
81 case "dir":
82 if !quiet {
83 fmt.Printf("dir %s\n", arg)
84 }
85 if err := os.Mkdir(arg, 0o755); err != nil {
86 die(fmt.Sprintf("%s: mkdir: %v", arg, err))
87 }
88 case "rm":
89 info, err := os.Stat(arg)
90 if err != nil {
91 die(fmt.Sprintf("%s: not file or directory: %v", arg, err))
92 }
93 if info.IsDir() {
94 if err := os.Remove(arg); err != nil {
95 die(fmt.Sprintf("%s: rmdir: %v", arg, err))
96 }
97 } else {
98 if err := os.Remove(arg); err != nil {
99 die(fmt.Sprintf("%s: unlink: %v", arg, err))
100 }
101 }
102 if !quiet {
103 fmt.Printf("rm %s\n", arg)
104 }
105 case "tmout":
106 secs, err := strconv.Atoi(arg)
107 if err != nil {
108 die(fmt.Sprintf("tmout %s: %v", arg, err))
109 }
110 if !quiet {
111 fmt.Printf("tmout %s\n", arg)
112 }
113 return time.Duration(secs) * time.Second, true
114 case "wait":
115 deadline := time.Now().Add(timeout)
116 for {
117 if _, err := os.Stat(arg); err == nil {
118 if !quiet {
119 fmt.Printf("wait %s\n", arg)
120 }
121 return timeout, true
122 }
123 if time.Now().After(deadline) {
124 die(fmt.Sprintf("wait %s: timeout after %d seconds", arg, int(timeout/time.Second)-1))
125 }
126 time.Sleep(100 * time.Millisecond)
127 }
128 case "sleep":
129 secs, err := strconv.Atoi(arg)
130 if err != nil {
131 die(fmt.Sprintf("sleep %s: %v", arg, err))
132 }
133 time.Sleep(time.Duration(secs) * time.Second)
134 if !quiet {
135 fmt.Printf("sleep %s\n", arg)
136 }
137 case "term":
138 pid, err := strconv.Atoi(arg)
139 if err != nil {
140 die(fmt.Sprintf("term %s: %v", arg, err))
141 }
142 if !quiet {
143 fmt.Printf("term %s\n", arg)
144 }
145 proc, err := os.FindProcess(pid)
146 if err != nil {
147 die(fmt.Sprintf("term %s: %v", arg, err))
148 }
149 if err := proc.Signal(syscall.SIGTERM); err != nil {
150 die(fmt.Sprintf("term %s: %v", arg, err))
151 }
152 case "fail":
153 code, err := strconv.Atoi(arg)
154 if err != nil {
155 die(fmt.Sprintf("fail %s: %v", arg, err))
156 }
157 if !quiet {
158 fmt.Printf("fail %s\n", arg)
159 }
160 os.Exit(code)
161 default:
162 return timeout, false
163 }
164 return timeout, true
165}
166
167func die(message string) {
168 fmt.Fprintln(os.Stderr, filepath.ToSlash(message))
169 os.Exit(1)
170}