blob: 07f8960ff38c50eadfe01ae55ba442247f6b9a88 [file] [log] [blame]
Scott Baker2d897982019-09-24 11:50:08 -07001// 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).
11package main
12
13import (
14 "bufio"
15 "fmt"
16 "io"
17 "io/ioutil"
18 "net/http"
19 "os"
20 "regexp"
21 "strings"
22)
23
24var (
25 goos, goarch string
26)
27
28// cmdLine returns this programs's commandline arguments
29func cmdLine() string {
30 return "go run mksysnum.go " + strings.Join(os.Args[1:], " ")
31}
32
33// buildTags returns build tags
34func buildTags() string {
35 return fmt.Sprintf("%s,%s", goarch, goos)
36}
37
38func 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
46type re struct {
47 str string // source string
48 sub []string // matched sub-string
49}
50
51// Match performs regular expression match
52func (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
61func 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
71func readFile(path string) io.Reader {
72 file, err := os.Open(os.Args[1])
73 checkErr(err)
74 return file
75}
76
77func 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
90func 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
182const template = `// %s
183// Code generated by the command above; see README.md. DO NOT EDIT.
184
185// +build %s
186
187package unix
188
189const(
190%s)`