github.com/Andyfoo/golang/x/sys@v0.0.0-20190901054642-57c1bf301704/unix/mksysnum.go (about) 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)`