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.
7 // Parse the header files for OpenBSD and generate a Go usable sysctl MIB.
9 // Build a MIB with each entry being an array containing the level, type and
10 // a hash that will contain additional entries if the current entry is a node.
11 // We then walk this MIB and create a flattened sysctl name to OID hash.
29 // cmdLine returns this programs's commandline arguments.
30 func cmdLine() string {
31 return "go run mksysctl_openbsd.go " + strings.Join(os.Args[1:], " ")
34 // buildTags returns build tags.
35 func buildTags() string {
36 return fmt.Sprintf("%s,%s", goarch, goos)
39 // reMatch performs regular expression match and stores the substring slice to value pointed by m.
40 func reMatch(re *regexp.Regexp, str string, m *[]string) bool {
41 *m = re.FindStringSubmatch(str)
48 type nodeElement struct {
51 pE *map[string]nodeElement
56 mib map[string]nodeElement
57 node *map[string]nodeElement
58 nodeMap map[string]string
63 ctlNames1RE = regexp.MustCompile(`^#define\s+(CTL_NAMES)\s+{`)
64 ctlNames2RE = regexp.MustCompile(`^#define\s+(CTL_(.*)_NAMES)\s+{`)
65 ctlNames3RE = regexp.MustCompile(`^#define\s+((.*)CTL_NAMES)\s+{`)
66 netInetRE = regexp.MustCompile(`^netinet/`)
67 netInet6RE = regexp.MustCompile(`^netinet6/`)
68 netRE = regexp.MustCompile(`^net/`)
69 bracesRE = regexp.MustCompile(`{.*}`)
70 ctlTypeRE = regexp.MustCompile(`{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}`)
71 fsNetKernRE = regexp.MustCompile(`^(fs|net|kern)_`)
74 func debug(s string) {
76 fmt.Fprintln(os.Stderr, s)
80 // Walk the MIB and build a sysctl name to OID mapping.
81 func buildSysctl(pNode *map[string]nodeElement, name string, oid []int) {
82 lNode := pNode // local copy of pointer to node
84 for k := range *lNode {
85 keys = append(keys, k)
89 for _, key := range keys {
96 nodeoid := append(oid, (*pNode)[key].n)
98 if (*pNode)[key].t == `CTLTYPE_NODE` {
99 if _, ok := nodeMap[nodename]; ok {
101 ctlName := nodeMap[nodename]
102 for _, part := range strings.Split(ctlName, ".") {
103 lNode = ((*lNode)[part]).pE
106 lNode = (*pNode)[key].pE
108 buildSysctl(lNode, nodename, nodeoid)
109 } else if (*pNode)[key].t != "" {
111 for j := range nodeoid {
112 oidStr = append(oidStr, fmt.Sprintf("%d", nodeoid[j]))
114 text := "\t{ \"" + nodename + "\", []_C_int{ " + strings.Join(oidStr, ", ") + " } }, \n"
115 sysCtl = append(sysCtl, text)
121 // Get the OS (using GOOS_TARGET if it exist)
122 goos = os.Getenv("GOOS_TARGET")
124 goos = os.Getenv("GOOS")
126 // Get the architecture (using GOARCH_TARGET if it exists)
127 goarch = os.Getenv("GOARCH_TARGET")
129 goarch = os.Getenv("GOARCH")
131 // Check if GOOS and GOARCH environment variables are defined
132 if goarch == "" || goos == "" {
133 fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n")
137 mib = make(map[string]nodeElement)
138 headers := [...]string{
150 `uvm/uvm_swap_encrypt.h`,
156 `netinet/icmp_var.h`,
157 `netinet/igmp_var.h`,
160 `netinet/ip_divert.h`,
162 `netinet/ip_ether.h`,
164 `netinet/ip_ipcomp.h`,
169 `netinet6/ip6_divert.h`,
179 //debug /* Special handling required */
181 //machdep /* Arch specific */
184 //vfs /* Special handling required */
228 //vfsgenctl /* Special handling required */
231 // Node name "fixups"
232 ctlMap := map[string]string{
233 "ipproto": "net.inet",
234 "net.inet.ipproto": "net.inet",
235 "net.inet6.ipv6proto": "net.inet6",
236 "net.inet6.ipv6": "net.inet6.ip6",
237 "net.inet.icmpv6": "net.inet6.icmp6",
238 "net.inet6.divert6": "net.inet6.divert",
239 "net.inet6.tcp6": "net.inet.tcp",
240 "net.inet6.udp6": "net.inet.udp",
242 "swpenc": "vm.swapencrypt",
246 nodeMap = map[string]string{
247 "net.inet.ip.ifq": "net.ifq",
248 "net.inet.pfsync": "net.pfsync",
249 "net.mpls.ifq": "net.ifq",
252 mCtls := make(map[string]bool)
253 for _, ctl := range ctls {
257 for _, header := range headers {
258 debug("Processing " + header)
259 file, err := os.Open(filepath.Join("/usr/include", header))
261 fmt.Fprintf(os.Stderr, "%v\n", err)
264 s := bufio.NewScanner(file)
267 if reMatch(ctlNames1RE, s.Text(), &sub) ||
268 reMatch(ctlNames2RE, s.Text(), &sub) ||
269 reMatch(ctlNames3RE, s.Text(), &sub) {
270 if sub[1] == `CTL_NAMES` {
275 nodename := strings.ToLower(sub[2])
277 if reMatch(netInetRE, header, &sub) {
278 ctlName = "net.inet." + nodename
279 } else if reMatch(netInet6RE, header, &sub) {
280 ctlName = "net.inet6." + nodename
281 } else if reMatch(netRE, header, &sub) {
282 ctlName = "net." + nodename
285 ctlName = fsNetKernRE.ReplaceAllString(ctlName, `$1.`)
288 if val, ok := ctlMap[ctlName]; ok {
291 if _, ok := mCtls[ctlName]; !ok {
292 debug("Ignoring " + ctlName + "...")
296 // Walk down from the top of the MIB.
298 for _, part := range strings.Split(ctlName, ".") {
299 if _, ok := (*node)[part]; !ok {
300 debug("Missing node " + part)
301 (*node)[part] = nodeElement{n: 0, t: "", pE: &map[string]nodeElement{}}
303 node = (*node)[part].pE
307 // Populate current node with entries.
309 for !strings.HasPrefix(s.Text(), "}") {
311 if reMatch(bracesRE, s.Text(), &sub) {
314 if !reMatch(ctlTypeRE, s.Text(), &sub) {
317 (*node)[sub[1]] = nodeElement{n: i, t: sub[2], pE: &map[string]nodeElement{}}
323 fmt.Fprintf(os.Stderr, "%v\n", err)
328 buildSysctl(&mib, "", []int{})
331 text := strings.Join(sysCtl, "")
333 fmt.Printf(srcTemplate, cmdLine(), buildTags(), text)
336 const srcTemplate = `// %s
337 // Code generated by the command above; DO NOT EDIT.
343 type mibentry struct {
348 var sysctlMib = []mibentry {