mksysnum.go 4.3 KB

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