mksysctl_openbsd.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. // Copyright 2019 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. // Parse the header files for OpenBSD and generate a Go usable sysctl MIB.
  6. //
  7. // Build a MIB with each entry being an array containing the level, type and
  8. // a hash that will contain additional entries if the current entry is a node.
  9. // We then walk this MIB and create a flattened sysctl name to OID hash.
  10. package main
  11. import (
  12. "bufio"
  13. "fmt"
  14. "os"
  15. "path/filepath"
  16. "regexp"
  17. "sort"
  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 mksysctl_openbsd.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. // reMatch performs regular expression match and stores the substring slice to value pointed by m.
  32. func reMatch(re *regexp.Regexp, str string, m *[]string) bool {
  33. *m = re.FindStringSubmatch(str)
  34. if *m != nil {
  35. return true
  36. }
  37. return false
  38. }
  39. type nodeElement struct {
  40. n int
  41. t string
  42. pE *map[string]nodeElement
  43. }
  44. var (
  45. debugEnabled bool
  46. mib map[string]nodeElement
  47. node *map[string]nodeElement
  48. nodeMap map[string]string
  49. sysCtl []string
  50. )
  51. var (
  52. ctlNames1RE = regexp.MustCompile(`^#define\s+(CTL_NAMES)\s+{`)
  53. ctlNames2RE = regexp.MustCompile(`^#define\s+(CTL_(.*)_NAMES)\s+{`)
  54. ctlNames3RE = regexp.MustCompile(`^#define\s+((.*)CTL_NAMES)\s+{`)
  55. netInetRE = regexp.MustCompile(`^netinet/`)
  56. netInet6RE = regexp.MustCompile(`^netinet6/`)
  57. netRE = regexp.MustCompile(`^net/`)
  58. bracesRE = regexp.MustCompile(`{.*}`)
  59. ctlTypeRE = regexp.MustCompile(`{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}`)
  60. fsNetKernRE = regexp.MustCompile(`^(fs|net|kern)_`)
  61. )
  62. func debug(s string) {
  63. if debugEnabled {
  64. fmt.Fprintln(os.Stderr, s)
  65. }
  66. }
  67. // Walk the MIB and build a sysctl name to OID mapping.
  68. func buildSysctl(pNode *map[string]nodeElement, name string, oid []int) {
  69. lNode := pNode // local copy of pointer to node
  70. var keys []string
  71. for k := range *lNode {
  72. keys = append(keys, k)
  73. }
  74. sort.Strings(keys)
  75. for _, key := range keys {
  76. nodename := name
  77. if name != "" {
  78. nodename += "."
  79. }
  80. nodename += key
  81. nodeoid := append(oid, (*pNode)[key].n)
  82. if (*pNode)[key].t == `CTLTYPE_NODE` {
  83. if _, ok := nodeMap[nodename]; ok {
  84. lNode = &mib
  85. ctlName := nodeMap[nodename]
  86. for _, part := range strings.Split(ctlName, ".") {
  87. lNode = ((*lNode)[part]).pE
  88. }
  89. } else {
  90. lNode = (*pNode)[key].pE
  91. }
  92. buildSysctl(lNode, nodename, nodeoid)
  93. } else if (*pNode)[key].t != "" {
  94. oidStr := []string{}
  95. for j := range nodeoid {
  96. oidStr = append(oidStr, fmt.Sprintf("%d", nodeoid[j]))
  97. }
  98. text := "\t{ \"" + nodename + "\", []_C_int{ " + strings.Join(oidStr, ", ") + " } }, \n"
  99. sysCtl = append(sysCtl, text)
  100. }
  101. }
  102. }
  103. func main() {
  104. // Get the OS (using GOOS_TARGET if it exist)
  105. goos = os.Getenv("GOOS_TARGET")
  106. if goos == "" {
  107. goos = os.Getenv("GOOS")
  108. }
  109. // Get the architecture (using GOARCH_TARGET if it exists)
  110. goarch = os.Getenv("GOARCH_TARGET")
  111. if goarch == "" {
  112. goarch = os.Getenv("GOARCH")
  113. }
  114. // Check if GOOS and GOARCH environment variables are defined
  115. if goarch == "" || goos == "" {
  116. fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n")
  117. os.Exit(1)
  118. }
  119. mib = make(map[string]nodeElement)
  120. headers := [...]string{
  121. `sys/sysctl.h`,
  122. `sys/socket.h`,
  123. `sys/tty.h`,
  124. `sys/malloc.h`,
  125. `sys/mount.h`,
  126. `sys/namei.h`,
  127. `sys/sem.h`,
  128. `sys/shm.h`,
  129. `sys/vmmeter.h`,
  130. `uvm/uvmexp.h`,
  131. `uvm/uvm_param.h`,
  132. `uvm/uvm_swap_encrypt.h`,
  133. `ddb/db_var.h`,
  134. `net/if.h`,
  135. `net/if_pfsync.h`,
  136. `net/pipex.h`,
  137. `netinet/in.h`,
  138. `netinet/icmp_var.h`,
  139. `netinet/igmp_var.h`,
  140. `netinet/ip_ah.h`,
  141. `netinet/ip_carp.h`,
  142. `netinet/ip_divert.h`,
  143. `netinet/ip_esp.h`,
  144. `netinet/ip_ether.h`,
  145. `netinet/ip_gre.h`,
  146. `netinet/ip_ipcomp.h`,
  147. `netinet/ip_ipip.h`,
  148. `netinet/pim_var.h`,
  149. `netinet/tcp_var.h`,
  150. `netinet/udp_var.h`,
  151. `netinet6/in6.h`,
  152. `netinet6/ip6_divert.h`,
  153. `netinet6/pim6_var.h`,
  154. `netinet/icmp6.h`,
  155. `netmpls/mpls.h`,
  156. }
  157. ctls := [...]string{
  158. `kern`,
  159. `vm`,
  160. `fs`,
  161. `net`,
  162. //debug /* Special handling required */
  163. `hw`,
  164. //machdep /* Arch specific */
  165. `user`,
  166. `ddb`,
  167. //vfs /* Special handling required */
  168. `fs.posix`,
  169. `kern.forkstat`,
  170. `kern.intrcnt`,
  171. `kern.malloc`,
  172. `kern.nchstats`,
  173. `kern.seminfo`,
  174. `kern.shminfo`,
  175. `kern.timecounter`,
  176. `kern.tty`,
  177. `kern.watchdog`,
  178. `net.bpf`,
  179. `net.ifq`,
  180. `net.inet`,
  181. `net.inet.ah`,
  182. `net.inet.carp`,
  183. `net.inet.divert`,
  184. `net.inet.esp`,
  185. `net.inet.etherip`,
  186. `net.inet.gre`,
  187. `net.inet.icmp`,
  188. `net.inet.igmp`,
  189. `net.inet.ip`,
  190. `net.inet.ip.ifq`,
  191. `net.inet.ipcomp`,
  192. `net.inet.ipip`,
  193. `net.inet.mobileip`,
  194. `net.inet.pfsync`,
  195. `net.inet.pim`,
  196. `net.inet.tcp`,
  197. `net.inet.udp`,
  198. `net.inet6`,
  199. `net.inet6.divert`,
  200. `net.inet6.ip6`,
  201. `net.inet6.icmp6`,
  202. `net.inet6.pim6`,
  203. `net.inet6.tcp6`,
  204. `net.inet6.udp6`,
  205. `net.mpls`,
  206. `net.mpls.ifq`,
  207. `net.key`,
  208. `net.pflow`,
  209. `net.pfsync`,
  210. `net.pipex`,
  211. `net.rt`,
  212. `vm.swapencrypt`,
  213. //vfsgenctl /* Special handling required */
  214. }
  215. // Node name "fixups"
  216. ctlMap := map[string]string{
  217. "ipproto": "net.inet",
  218. "net.inet.ipproto": "net.inet",
  219. "net.inet6.ipv6proto": "net.inet6",
  220. "net.inet6.ipv6": "net.inet6.ip6",
  221. "net.inet.icmpv6": "net.inet6.icmp6",
  222. "net.inet6.divert6": "net.inet6.divert",
  223. "net.inet6.tcp6": "net.inet.tcp",
  224. "net.inet6.udp6": "net.inet.udp",
  225. "mpls": "net.mpls",
  226. "swpenc": "vm.swapencrypt",
  227. }
  228. // Node mappings
  229. nodeMap = map[string]string{
  230. "net.inet.ip.ifq": "net.ifq",
  231. "net.inet.pfsync": "net.pfsync",
  232. "net.mpls.ifq": "net.ifq",
  233. }
  234. mCtls := make(map[string]bool)
  235. for _, ctl := range ctls {
  236. mCtls[ctl] = true
  237. }
  238. for _, header := range headers {
  239. debug("Processing " + header)
  240. file, err := os.Open(filepath.Join("/usr/include", header))
  241. if err != nil {
  242. fmt.Fprintf(os.Stderr, "%v\n", err)
  243. os.Exit(1)
  244. }
  245. s := bufio.NewScanner(file)
  246. for s.Scan() {
  247. var sub []string
  248. if reMatch(ctlNames1RE, s.Text(), &sub) ||
  249. reMatch(ctlNames2RE, s.Text(), &sub) ||
  250. reMatch(ctlNames3RE, s.Text(), &sub) {
  251. if sub[1] == `CTL_NAMES` {
  252. // Top level.
  253. node = &mib
  254. } else {
  255. // Node.
  256. nodename := strings.ToLower(sub[2])
  257. ctlName := ""
  258. if reMatch(netInetRE, header, &sub) {
  259. ctlName = "net.inet." + nodename
  260. } else if reMatch(netInet6RE, header, &sub) {
  261. ctlName = "net.inet6." + nodename
  262. } else if reMatch(netRE, header, &sub) {
  263. ctlName = "net." + nodename
  264. } else {
  265. ctlName = nodename
  266. ctlName = fsNetKernRE.ReplaceAllString(ctlName, `$1.`)
  267. }
  268. if val, ok := ctlMap[ctlName]; ok {
  269. ctlName = val
  270. }
  271. if _, ok := mCtls[ctlName]; !ok {
  272. debug("Ignoring " + ctlName + "...")
  273. continue
  274. }
  275. // Walk down from the top of the MIB.
  276. node = &mib
  277. for _, part := range strings.Split(ctlName, ".") {
  278. if _, ok := (*node)[part]; !ok {
  279. debug("Missing node " + part)
  280. (*node)[part] = nodeElement{n: 0, t: "", pE: &map[string]nodeElement{}}
  281. }
  282. node = (*node)[part].pE
  283. }
  284. }
  285. // Populate current node with entries.
  286. i := -1
  287. for !strings.HasPrefix(s.Text(), "}") {
  288. s.Scan()
  289. if reMatch(bracesRE, s.Text(), &sub) {
  290. i++
  291. }
  292. if !reMatch(ctlTypeRE, s.Text(), &sub) {
  293. continue
  294. }
  295. (*node)[sub[1]] = nodeElement{n: i, t: sub[2], pE: &map[string]nodeElement{}}
  296. }
  297. }
  298. }
  299. err = s.Err()
  300. if err != nil {
  301. fmt.Fprintf(os.Stderr, "%v\n", err)
  302. os.Exit(1)
  303. }
  304. file.Close()
  305. }
  306. buildSysctl(&mib, "", []int{})
  307. sort.Strings(sysCtl)
  308. text := strings.Join(sysCtl, "")
  309. fmt.Printf(srcTemplate, cmdLine(), buildTags(), text)
  310. }
  311. const srcTemplate = `// %s
  312. // Code generated by the command above; DO NOT EDIT.
  313. // +build %s
  314. package unix
  315. type mibentry struct {
  316. ctlname string
  317. ctloid []_C_int
  318. }
  319. var sysctlMib = []mibentry {
  320. %s
  321. }
  322. `