mksysnum.go 4.5 KB

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