| // 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|COMPAT10)\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)` |