]>
Commit | Line | Data |
---|---|---|
107c1cdb ND |
1 | // Copyright 2018 The Go 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 | // +build ignore | |
6 | ||
7 | // Generate system call table for DragonFly, NetBSD, | |
8 | // FreeBSD, OpenBSD or Darwin from master list | |
9 | // (for example, /usr/src/sys/kern/syscalls.master or | |
10 | // sys/syscall.h). | |
11 | package main | |
12 | ||
13 | import ( | |
14 | "bufio" | |
15 | "fmt" | |
16 | "io" | |
17 | "io/ioutil" | |
18 | "net/http" | |
19 | "os" | |
20 | "regexp" | |
21 | "strings" | |
22 | ) | |
23 | ||
24 | var ( | |
25 | goos, goarch string | |
26 | ) | |
27 | ||
28 | // cmdLine returns this programs's commandline arguments | |
29 | func cmdLine() string { | |
30 | return "go run mksysnum.go " + strings.Join(os.Args[1:], " ") | |
31 | } | |
32 | ||
33 | // buildTags returns build tags | |
34 | func buildTags() string { | |
35 | return fmt.Sprintf("%s,%s", goarch, goos) | |
36 | } | |
37 | ||
38 | func checkErr(err error) { | |
39 | if err != nil { | |
40 | fmt.Fprintf(os.Stderr, "%v\n", err) | |
41 | os.Exit(1) | |
42 | } | |
43 | } | |
44 | ||
45 | // source string and substring slice for regexp | |
46 | type re struct { | |
47 | str string // source string | |
48 | sub []string // matched sub-string | |
49 | } | |
50 | ||
51 | // Match performs regular expression match | |
52 | func (r *re) Match(exp string) bool { | |
53 | r.sub = regexp.MustCompile(exp).FindStringSubmatch(r.str) | |
54 | if r.sub != nil { | |
55 | return true | |
56 | } | |
57 | return false | |
58 | } | |
59 | ||
60 | // fetchFile fetches a text file from URL | |
61 | func fetchFile(URL string) io.Reader { | |
62 | resp, err := http.Get(URL) | |
63 | checkErr(err) | |
64 | defer resp.Body.Close() | |
65 | body, err := ioutil.ReadAll(resp.Body) | |
66 | checkErr(err) | |
67 | return strings.NewReader(string(body)) | |
68 | } | |
69 | ||
70 | // readFile reads a text file from path | |
71 | func readFile(path string) io.Reader { | |
72 | file, err := os.Open(os.Args[1]) | |
73 | checkErr(err) | |
74 | return file | |
75 | } | |
76 | ||
77 | func format(name, num, proto string) string { | |
78 | name = strings.ToUpper(name) | |
79 | // There are multiple entries for enosys and nosys, so comment them out. | |
80 | nm := re{str: name} | |
81 | if nm.Match(`^SYS_E?NOSYS$`) { | |
82 | name = fmt.Sprintf("// %s", name) | |
83 | } | |
84 | if name == `SYS_SYS_EXIT` { | |
85 | name = `SYS_EXIT` | |
86 | } | |
87 | return fmt.Sprintf(" %s = %s; // %s\n", name, num, proto) | |
88 | } | |
89 | ||
90 | func main() { | |
91 | // Get the OS (using GOOS_TARGET if it exist) | |
92 | goos = os.Getenv("GOOS_TARGET") | |
93 | if goos == "" { | |
94 | goos = os.Getenv("GOOS") | |
95 | } | |
96 | // Get the architecture (using GOARCH_TARGET if it exists) | |
97 | goarch = os.Getenv("GOARCH_TARGET") | |
98 | if goarch == "" { | |
99 | goarch = os.Getenv("GOARCH") | |
100 | } | |
101 | // Check if GOOS and GOARCH environment variables are defined | |
102 | if goarch == "" || goos == "" { | |
103 | fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n") | |
104 | os.Exit(1) | |
105 | } | |
106 | ||
107 | file := strings.TrimSpace(os.Args[1]) | |
108 | var syscalls io.Reader | |
109 | if strings.HasPrefix(file, "https://") || strings.HasPrefix(file, "http://") { | |
110 | // Download syscalls.master file | |
111 | syscalls = fetchFile(file) | |
112 | } else { | |
113 | syscalls = readFile(file) | |
114 | } | |
115 | ||
116 | var text, line string | |
117 | s := bufio.NewScanner(syscalls) | |
118 | for s.Scan() { | |
119 | t := re{str: line} | |
120 | if t.Match(`^(.*)\\$`) { | |
121 | // Handle continuation | |
122 | line = t.sub[1] | |
123 | line += strings.TrimLeft(s.Text(), " \t") | |
124 | } else { | |
125 | // New line | |
126 | line = s.Text() | |
127 | } | |
128 | t = re{str: line} | |
129 | if t.Match(`\\$`) { | |
130 | continue | |
131 | } | |
132 | t = re{str: line} | |
133 | ||
134 | switch goos { | |
135 | case "dragonfly": | |
136 | if t.Match(`^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$`) { | |
137 | num, proto := t.sub[1], t.sub[2] | |
138 | name := fmt.Sprintf("SYS_%s", t.sub[3]) | |
139 | text += format(name, num, proto) | |
140 | } | |
141 | case "freebsd": | |
142 | if t.Match(`^([0-9]+)\s+\S+\s+(?:NO)?STD\s+({ \S+\s+(\w+).*)$`) { | |
143 | num, proto := t.sub[1], t.sub[2] | |
144 | name := fmt.Sprintf("SYS_%s", t.sub[3]) | |
145 | text += format(name, num, proto) | |
146 | } | |
147 | case "openbsd": | |
148 | if t.Match(`^([0-9]+)\s+STD\s+(NOLOCK\s+)?({ \S+\s+\*?(\w+).*)$`) { | |
149 | num, proto, name := t.sub[1], t.sub[3], t.sub[4] | |
150 | text += format(name, num, proto) | |
151 | } | |
152 | case "netbsd": | |
153 | if t.Match(`^([0-9]+)\s+((STD)|(NOERR))\s+(RUMP\s+)?({\s+\S+\s*\*?\s*\|(\S+)\|(\S*)\|(\w+).*\s+})(\s+(\S+))?$`) { | |
154 | num, proto, compat := t.sub[1], t.sub[6], t.sub[8] | |
155 | name := t.sub[7] + "_" + t.sub[9] | |
156 | if t.sub[11] != "" { | |
157 | name = t.sub[7] + "_" + t.sub[11] | |
158 | } | |
159 | name = strings.ToUpper(name) | |
160 | if compat == "" || compat == "13" || compat == "30" || compat == "50" { | |
161 | text += fmt.Sprintf(" %s = %s; // %s\n", name, num, proto) | |
162 | } | |
163 | } | |
164 | case "darwin": | |
165 | if t.Match(`^#define\s+SYS_(\w+)\s+([0-9]+)`) { | |
166 | name, num := t.sub[1], t.sub[2] | |
167 | name = strings.ToUpper(name) | |
168 | text += fmt.Sprintf(" SYS_%s = %s;\n", name, num) | |
169 | } | |
170 | default: | |
171 | fmt.Fprintf(os.Stderr, "unrecognized GOOS=%s\n", goos) | |
172 | os.Exit(1) | |
173 | ||
174 | } | |
175 | } | |
176 | err := s.Err() | |
177 | checkErr(err) | |
178 | ||
179 | fmt.Printf(template, cmdLine(), buildTags(), text) | |
180 | } | |
181 | ||
182 | const template = `// %s | |
183 | // Code generated by the command above; see README.md. DO NOT EDIT. | |
184 | ||
185 | // +build %s | |
186 | ||
187 | package unix | |
188 | ||
189 | const( | |
190 | %s)` |