| // Copyright 2018 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // +build ignore |
| |
| // Generate system call table for DragonFly, NetBSD, |
| // FreeBSD, OpenBSD or Darwin from master list |
| // (for example, /usr/src/sys/kern/syscalls.master or |
| // sys/syscall.h). |
| package main |
| |
| import ( |
| "bufio" |
| "fmt" |
| "io" |
| "io/ioutil" |
| "net/http" |
| "os" |
| "regexp" |
| "strings" |
| ) |
| |
| var ( |
| goos, goarch string |
| ) |
| |
| // cmdLine returns this programs's commandline arguments |
| func cmdLine() string { |
| return "go run mksysnum.go " + strings.Join(os.Args[1:], " ") |
| } |
| |
| // buildTags returns build tags |
| func buildTags() string { |
| return fmt.Sprintf("%s,%s", goarch, goos) |
| } |
| |
| func checkErr(err error) { |
| if err != nil { |
| fmt.Fprintf(os.Stderr, "%v\n", err) |
| os.Exit(1) |
| } |
| } |
| |
| // source string and substring slice for regexp |
| type re struct { |
| str string // source string |
| sub []string // matched sub-string |
| } |
| |
| // Match performs regular expression match |
| func (r *re) Match(exp string) bool { |
| r.sub = regexp.MustCompile(exp).FindStringSubmatch(r.str) |
| if r.sub != nil { |
| return true |
| } |
| return false |
| } |
| |
| // fetchFile fetches a text file from URL |
| func fetchFile(URL string) io.Reader { |
| resp, err := http.Get(URL) |
| checkErr(err) |
| defer resp.Body.Close() |
| body, err := ioutil.ReadAll(resp.Body) |
| checkErr(err) |
| return strings.NewReader(string(body)) |
| } |
| |
| // readFile reads a text file from path |
| func readFile(path string) io.Reader { |
| file, err := os.Open(os.Args[1]) |
| checkErr(err) |
| return file |
| } |
| |
| func format(name, num, proto string) string { |
| name = strings.ToUpper(name) |
| // There are multiple entries for enosys and nosys, so comment them out. |
| nm := re{str: name} |
| if nm.Match(`^SYS_E?NOSYS$`) { |
| name = fmt.Sprintf("// %s", name) |
| } |
| if name == `SYS_SYS_EXIT` { |
| name = `SYS_EXIT` |
| } |
| return fmt.Sprintf(" %s = %s; // %s\n", name, num, proto) |
| } |
| |
| func main() { |
| // Get the OS (using GOOS_TARGET if it exist) |
| goos = os.Getenv("GOOS_TARGET") |
| if goos == "" { |
| goos = os.Getenv("GOOS") |
| } |
| // Get the architecture (using GOARCH_TARGET if it exists) |
| goarch = os.Getenv("GOARCH_TARGET") |
| if goarch == "" { |
| goarch = os.Getenv("GOARCH") |
| } |
| // Check if GOOS and GOARCH environment variables are defined |
| if goarch == "" || goos == "" { |
| fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n") |
| os.Exit(1) |
| } |
| |
| file := strings.TrimSpace(os.Args[1]) |
| var syscalls io.Reader |
| if strings.HasPrefix(file, "https://") || strings.HasPrefix(file, "http://") { |
| // Download syscalls.master file |
| syscalls = fetchFile(file) |
| } else { |
| syscalls = readFile(file) |
| } |
| |
| var text, line string |
| s := bufio.NewScanner(syscalls) |
| for s.Scan() { |
| t := re{str: line} |
| if t.Match(`^(.*)\\$`) { |
| // Handle continuation |
| line = t.sub[1] |
| line += strings.TrimLeft(s.Text(), " \t") |
| } else { |
| // New line |
| line = s.Text() |
| } |
| t = re{str: line} |
| if t.Match(`\\$`) { |
| continue |
| } |
| t = re{str: line} |
| |
| switch goos { |
| case "dragonfly": |
| if t.Match(`^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$`) { |
| num, proto := t.sub[1], t.sub[2] |
| name := fmt.Sprintf("SYS_%s", t.sub[3]) |
| text += format(name, num, proto) |
| } |
| case "freebsd": |
| if t.Match(`^([0-9]+)\s+\S+\s+(?:NO)?STD\s+({ \S+\s+(\w+).*)$`) { |
| num, proto := t.sub[1], t.sub[2] |
| name := fmt.Sprintf("SYS_%s", t.sub[3]) |
| text += format(name, num, proto) |
| } |
| case "openbsd": |
| if t.Match(`^([0-9]+)\s+STD\s+(NOLOCK\s+)?({ \S+\s+\*?(\w+).*)$`) { |
| num, proto, name := t.sub[1], t.sub[3], t.sub[4] |
| text += format(name, num, proto) |
| } |
| case "netbsd": |
| if t.Match(`^([0-9]+)\s+((STD)|(NOERR))\s+(RUMP\s+)?({\s+\S+\s*\*?\s*\|(\S+)\|(\S*)\|(\w+).*\s+})(\s+(\S+))?$`) { |
| num, proto, compat := t.sub[1], t.sub[6], t.sub[8] |
| name := t.sub[7] + "_" + t.sub[9] |
| if t.sub[11] != "" { |
| name = t.sub[7] + "_" + t.sub[11] |
| } |
| name = strings.ToUpper(name) |
| if compat == "" || compat == "13" || compat == "30" || compat == "50" { |
| text += fmt.Sprintf(" %s = %s; // %s\n", name, num, proto) |
| } |
| } |
| case "darwin": |
| if t.Match(`^#define\s+SYS_(\w+)\s+([0-9]+)`) { |
| name, num := t.sub[1], t.sub[2] |
| name = strings.ToUpper(name) |
| text += fmt.Sprintf(" SYS_%s = %s;\n", name, num) |
| } |
| default: |
| fmt.Fprintf(os.Stderr, "unrecognized GOOS=%s\n", goos) |
| os.Exit(1) |
| |
| } |
| } |
| err := s.Err() |
| checkErr(err) |
| |
| fmt.Printf(template, cmdLine(), buildTags(), text) |
| } |
| |
| const template = `// %s |
| // Code generated by the command above; see README.md. DO NOT EDIT. |
| |
| // +build %s |
| |
| package unix |
| |
| const( |
| %s)` |