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.
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
28 // cmdLine returns this programs's commandline arguments
29 func cmdLine() string {
30 return "go run mksysnum.go " + strings.Join(os.Args[1:], " ")
33 // buildTags returns build tags
34 func buildTags() string {
35 return fmt.Sprintf("%s,%s", goarch, goos)
38 func checkErr(err error) {
40 fmt.Fprintf(os.Stderr, "%v\n", err)
45 // source string and substring slice for regexp
47 str string // source string
48 sub []string // matched sub-string
51 // Match performs regular expression match
52 func (r *re) Match(exp string) bool {
53 r.sub = regexp.MustCompile(exp).FindStringSubmatch(r.str)
60 // fetchFile fetches a text file from URL
61 func fetchFile(URL string) io.Reader {
62 resp, err := http.Get(URL)
64 defer resp.Body.Close()
65 body, err := ioutil.ReadAll(resp.Body)
67 return strings.NewReader(string(body))
70 // readFile reads a text file from path
71 func readFile(path string) io.Reader {
72 file, err := os.Open(os.Args[1])
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.
81 if nm.Match(`^SYS_E?NOSYS$`) {
82 name = fmt.Sprintf("// %s", name)
84 if name == `SYS_SYS_EXIT` {
87 return fmt.Sprintf(" %s = %s; // %s\n", name, num, proto)
91 // Get the OS (using GOOS_TARGET if it exist)
92 goos = os.Getenv("GOOS_TARGET")
94 goos = os.Getenv("GOOS")
96 // Get the architecture (using GOARCH_TARGET if it exists)
97 goarch = os.Getenv("GOARCH_TARGET")
99 goarch = os.Getenv("GOARCH")
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")
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)
113 syscalls = readFile(file)
116 var text, line string
117 s := bufio.NewScanner(syscalls)
120 if t.Match(`^(.*)\\$`) {
121 // Handle continuation
123 line += strings.TrimLeft(s.Text(), " \t")
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)
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)
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)
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]
157 name = t.sub[7] + "_" + t.sub[11]
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)
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)
171 fmt.Fprintf(os.Stderr, "unrecognized GOOS=%s\n", goos)
179 fmt.Printf(template, cmdLine(), buildTags(), text)
182 const template = `// %s
183 // Code generated by the command above; see README.md. DO NOT EDIT.