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 or OpenBSD from master list (for example,
9 // /usr/src/sys/kern/syscalls.master or sys/syscall.h).
27 // cmdLine returns this programs's commandline arguments
28 func cmdLine() string {
29 return "go run mksysnum.go " + strings.Join(os.Args[1:], " ")
32 // buildTags returns build tags
33 func buildTags() string {
34 return fmt.Sprintf("%s,%s", goarch, goos)
37 func checkErr(err error) {
39 fmt.Fprintf(os.Stderr, "%v\n", err)
44 // source string and substring slice for regexp
46 str string // source string
47 sub []string // matched sub-string
50 // Match performs regular expression match
51 func (r *re) Match(exp string) bool {
52 r.sub = regexp.MustCompile(exp).FindStringSubmatch(r.str)
59 // fetchFile fetches a text file from URL
60 func fetchFile(URL string) io.Reader {
61 resp, err := http.Get(URL)
63 defer resp.Body.Close()
64 body, err := ioutil.ReadAll(resp.Body)
66 return strings.NewReader(string(body))
69 // readFile reads a text file from path
70 func readFile(path string) io.Reader {
71 file, err := os.Open(os.Args[1])
76 func format(name, num, proto string) string {
77 name = strings.ToUpper(name)
78 // There are multiple entries for enosys and nosys, so comment them out.
80 if nm.Match(`^SYS_E?NOSYS$`) {
81 name = fmt.Sprintf("// %s", name)
83 if name == `SYS_SYS_EXIT` {
86 return fmt.Sprintf(" %s = %s; // %s\n", name, num, proto)
90 // Get the OS (using GOOS_TARGET if it exist)
91 goos = os.Getenv("GOOS_TARGET")
93 goos = os.Getenv("GOOS")
95 // Get the architecture (using GOARCH_TARGET if it exists)
96 goarch = os.Getenv("GOARCH_TARGET")
98 goarch = os.Getenv("GOARCH")
100 // Check if GOOS and GOARCH environment variables are defined
101 if goarch == "" || goos == "" {
102 fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n")
106 file := strings.TrimSpace(os.Args[1])
107 var syscalls io.Reader
108 if strings.HasPrefix(file, "https://") || strings.HasPrefix(file, "http://") {
109 // Download syscalls.master file
110 syscalls = fetchFile(file)
112 syscalls = readFile(file)
115 var text, line string
116 s := bufio.NewScanner(syscalls)
119 if t.Match(`^(.*)\\$`) {
120 // Handle continuation
122 line += strings.TrimLeft(s.Text(), " \t")
135 if t.Match(`^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$`) {
136 num, proto := t.sub[1], t.sub[2]
137 name := fmt.Sprintf("SYS_%s", t.sub[3])
138 text += format(name, num, proto)
141 if t.Match(`^([0-9]+)\s+\S+\s+(?:(?:NO)?STD|COMPAT10)\s+({ \S+\s+(\w+).*)$`) {
142 num, proto := t.sub[1], t.sub[2]
143 name := fmt.Sprintf("SYS_%s", t.sub[3])
144 text += format(name, num, proto)
147 if t.Match(`^([0-9]+)\s+STD\s+(NOLOCK\s+)?({ \S+\s+\*?(\w+).*)$`) {
148 num, proto, name := t.sub[1], t.sub[3], t.sub[4]
149 text += format(name, num, proto)
152 if t.Match(`^([0-9]+)\s+((STD)|(NOERR))\s+(RUMP\s+)?({\s+\S+\s*\*?\s*\|(\S+)\|(\S*)\|(\w+).*\s+})(\s+(\S+))?$`) {
153 num, proto, compat := t.sub[1], t.sub[6], t.sub[8]
154 name := t.sub[7] + "_" + t.sub[9]
156 name = t.sub[7] + "_" + t.sub[11]
158 name = strings.ToUpper(name)
159 if compat == "" || compat == "13" || compat == "30" || compat == "50" {
160 text += fmt.Sprintf(" %s = %s; // %s\n", name, num, proto)
164 fmt.Fprintf(os.Stderr, "unrecognized GOOS=%s\n", goos)
172 fmt.Printf(template, cmdLine(), buildTags(), text)
175 const template = `// %s
176 // Code generated by the command above; see README.md. DO NOT EDIT.