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