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 or OpenBSD from master list (for example, 9// /usr/src/sys/kern/syscalls.master or sys/syscall.h). 10package main 11 12import ( 13 "bufio" 14 "fmt" 15 "io" 16 "io/ioutil" 17 "net/http" 18 "os" 19 "regexp" 20 "strings" 21) 22 23var ( 24 goos, goarch string 25) 26 27// cmdLine returns this programs's commandline arguments 28func cmdLine() string { 29 return "go run mksysnum.go " + strings.Join(os.Args[1:], " ") 30} 31 32// buildTags returns build tags 33func buildTags() string { 34 return fmt.Sprintf("%s,%s", goarch, goos) 35} 36 37func checkErr(err error) { 38 if err != nil { 39 fmt.Fprintf(os.Stderr, "%v\n", err) 40 os.Exit(1) 41 } 42} 43 44// source string and substring slice for regexp 45type re struct { 46 str string // source string 47 sub []string // matched sub-string 48} 49 50// Match performs regular expression match 51func (r *re) Match(exp string) bool { 52 r.sub = regexp.MustCompile(exp).FindStringSubmatch(r.str) 53 if r.sub != nil { 54 return true 55 } 56 return false 57} 58 59// fetchFile fetches a text file from URL 60func fetchFile(URL string) io.Reader { 61 resp, err := http.Get(URL) 62 checkErr(err) 63 defer resp.Body.Close() 64 body, err := ioutil.ReadAll(resp.Body) 65 checkErr(err) 66 return strings.NewReader(string(body)) 67} 68 69// readFile reads a text file from path 70func readFile(path string) io.Reader { 71 file, err := os.Open(os.Args[1]) 72 checkErr(err) 73 return file 74} 75 76func format(name, num, proto string) string { 77 name = strings.ToUpper(name) 78 // There are multiple entries for enosys and nosys, so comment them out. 79 nm := re{str: name} 80 if nm.Match(`^SYS_E?NOSYS$`) { 81 name = fmt.Sprintf("// %s", name) 82 } 83 if name == `SYS_SYS_EXIT` { 84 name = `SYS_EXIT` 85 } 86 return fmt.Sprintf(" %s = %s; // %s\n", name, num, proto) 87} 88 89func main() { 90 // Get the OS (using GOOS_TARGET if it exist) 91 goos = os.Getenv("GOOS_TARGET") 92 if goos == "" { 93 goos = os.Getenv("GOOS") 94 } 95 // Get the architecture (using GOARCH_TARGET if it exists) 96 goarch = os.Getenv("GOARCH_TARGET") 97 if goarch == "" { 98 goarch = os.Getenv("GOARCH") 99 } 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") 103 os.Exit(1) 104 } 105 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) 111 } else { 112 syscalls = readFile(file) 113 } 114 115 var text, line string 116 s := bufio.NewScanner(syscalls) 117 for s.Scan() { 118 t := re{str: line} 119 if t.Match(`^(.*)\\$`) { 120 // Handle continuation 121 line = t.sub[1] 122 line += strings.TrimLeft(s.Text(), " \t") 123 } else { 124 // New line 125 line = s.Text() 126 } 127 t = re{str: line} 128 if t.Match(`\\$`) { 129 continue 130 } 131 t = re{str: line} 132 133 switch goos { 134 case "dragonfly": 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) 139 } 140 case "freebsd": 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) 145 } 146 case "openbsd": 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) 150 } 151 case "netbsd": 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] 155 if t.sub[11] != "" { 156 name = t.sub[7] + "_" + t.sub[11] 157 } 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) 161 } 162 } 163 default: 164 fmt.Fprintf(os.Stderr, "unrecognized GOOS=%s\n", goos) 165 os.Exit(1) 166 167 } 168 } 169 err := s.Err() 170 checkErr(err) 171 172 fmt.Printf(template, cmdLine(), buildTags(), text) 173} 174 175const template = `// %s 176// Code generated by the command above; see README.md. DO NOT EDIT. 177 178// +build %s 179 180package unix 181 182const( 183%s)` 184