| // Copyright 2019 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // +build ignore |
| |
| // Parse the header files for OpenBSD and generate a Go usable sysctl MIB. |
| // |
| // Build a MIB with each entry being an array containing the level, type and |
| // a hash that will contain additional entries if the current entry is a node. |
| // We then walk this MIB and create a flattened sysctl name to OID hash. |
| |
| package main |
| |
| import ( |
| "bufio" |
| "fmt" |
| "os" |
| "path/filepath" |
| "regexp" |
| "sort" |
| "strings" |
| ) |
| |
| var ( |
| goos, goarch string |
| ) |
| |
| // cmdLine returns this programs's commandline arguments. |
| func cmdLine() string { |
| return "go run mksysctl_openbsd.go " + strings.Join(os.Args[1:], " ") |
| } |
| |
| // buildTags returns build tags. |
| func buildTags() string { |
| return fmt.Sprintf("%s,%s", goarch, goos) |
| } |
| |
| // reMatch performs regular expression match and stores the substring slice to value pointed by m. |
| func reMatch(re *regexp.Regexp, str string, m *[]string) bool { |
| *m = re.FindStringSubmatch(str) |
| if *m != nil { |
| return true |
| } |
| return false |
| } |
| |
| type nodeElement struct { |
| n int |
| t string |
| pE *map[string]nodeElement |
| } |
| |
| var ( |
| debugEnabled bool |
| mib map[string]nodeElement |
| node *map[string]nodeElement |
| nodeMap map[string]string |
| sysCtl []string |
| ) |
| |
| var ( |
| ctlNames1RE = regexp.MustCompile(`^#define\s+(CTL_NAMES)\s+{`) |
| ctlNames2RE = regexp.MustCompile(`^#define\s+(CTL_(.*)_NAMES)\s+{`) |
| ctlNames3RE = regexp.MustCompile(`^#define\s+((.*)CTL_NAMES)\s+{`) |
| netInetRE = regexp.MustCompile(`^netinet/`) |
| netInet6RE = regexp.MustCompile(`^netinet6/`) |
| netRE = regexp.MustCompile(`^net/`) |
| bracesRE = regexp.MustCompile(`{.*}`) |
| ctlTypeRE = regexp.MustCompile(`{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}`) |
| fsNetKernRE = regexp.MustCompile(`^(fs|net|kern)_`) |
| ) |
| |
| func debug(s string) { |
| if debugEnabled { |
| fmt.Fprintln(os.Stderr, s) |
| } |
| } |
| |
| // Walk the MIB and build a sysctl name to OID mapping. |
| func buildSysctl(pNode *map[string]nodeElement, name string, oid []int) { |
| lNode := pNode // local copy of pointer to node |
| var keys []string |
| for k := range *lNode { |
| keys = append(keys, k) |
| } |
| sort.Strings(keys) |
| |
| for _, key := range keys { |
| nodename := name |
| if name != "" { |
| nodename += "." |
| } |
| nodename += key |
| |
| nodeoid := append(oid, (*pNode)[key].n) |
| |
| if (*pNode)[key].t == `CTLTYPE_NODE` { |
| if _, ok := nodeMap[nodename]; ok { |
| lNode = &mib |
| ctlName := nodeMap[nodename] |
| for _, part := range strings.Split(ctlName, ".") { |
| lNode = ((*lNode)[part]).pE |
| } |
| } else { |
| lNode = (*pNode)[key].pE |
| } |
| buildSysctl(lNode, nodename, nodeoid) |
| } else if (*pNode)[key].t != "" { |
| oidStr := []string{} |
| for j := range nodeoid { |
| oidStr = append(oidStr, fmt.Sprintf("%d", nodeoid[j])) |
| } |
| text := "\t{ \"" + nodename + "\", []_C_int{ " + strings.Join(oidStr, ", ") + " } }, \n" |
| sysCtl = append(sysCtl, text) |
| } |
| } |
| } |
| |
| func main() { |
| // Get the OS (using GOOS_TARGET if it exist) |
| goos = os.Getenv("GOOS_TARGET") |
| if goos == "" { |
| goos = os.Getenv("GOOS") |
| } |
| // Get the architecture (using GOARCH_TARGET if it exists) |
| goarch = os.Getenv("GOARCH_TARGET") |
| if goarch == "" { |
| goarch = os.Getenv("GOARCH") |
| } |
| // Check if GOOS and GOARCH environment variables are defined |
| if goarch == "" || goos == "" { |
| fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n") |
| os.Exit(1) |
| } |
| |
| mib = make(map[string]nodeElement) |
| headers := [...]string{ |
| `sys/sysctl.h`, |
| `sys/socket.h`, |
| `sys/tty.h`, |
| `sys/malloc.h`, |
| `sys/mount.h`, |
| `sys/namei.h`, |
| `sys/sem.h`, |
| `sys/shm.h`, |
| `sys/vmmeter.h`, |
| `uvm/uvmexp.h`, |
| `uvm/uvm_param.h`, |
| `uvm/uvm_swap_encrypt.h`, |
| `ddb/db_var.h`, |
| `net/if.h`, |
| `net/if_pfsync.h`, |
| `net/pipex.h`, |
| `netinet/in.h`, |
| `netinet/icmp_var.h`, |
| `netinet/igmp_var.h`, |
| `netinet/ip_ah.h`, |
| `netinet/ip_carp.h`, |
| `netinet/ip_divert.h`, |
| `netinet/ip_esp.h`, |
| `netinet/ip_ether.h`, |
| `netinet/ip_gre.h`, |
| `netinet/ip_ipcomp.h`, |
| `netinet/ip_ipip.h`, |
| `netinet/pim_var.h`, |
| `netinet/tcp_var.h`, |
| `netinet/udp_var.h`, |
| `netinet6/in6.h`, |
| `netinet6/ip6_divert.h`, |
| `netinet6/pim6_var.h`, |
| `netinet/icmp6.h`, |
| `netmpls/mpls.h`, |
| } |
| |
| ctls := [...]string{ |
| `kern`, |
| `vm`, |
| `fs`, |
| `net`, |
| //debug /* Special handling required */ |
| `hw`, |
| //machdep /* Arch specific */ |
| `user`, |
| `ddb`, |
| //vfs /* Special handling required */ |
| `fs.posix`, |
| `kern.forkstat`, |
| `kern.intrcnt`, |
| `kern.malloc`, |
| `kern.nchstats`, |
| `kern.seminfo`, |
| `kern.shminfo`, |
| `kern.timecounter`, |
| `kern.tty`, |
| `kern.watchdog`, |
| `net.bpf`, |
| `net.ifq`, |
| `net.inet`, |
| `net.inet.ah`, |
| `net.inet.carp`, |
| `net.inet.divert`, |
| `net.inet.esp`, |
| `net.inet.etherip`, |
| `net.inet.gre`, |
| `net.inet.icmp`, |
| `net.inet.igmp`, |
| `net.inet.ip`, |
| `net.inet.ip.ifq`, |
| `net.inet.ipcomp`, |
| `net.inet.ipip`, |
| `net.inet.mobileip`, |
| `net.inet.pfsync`, |
| `net.inet.pim`, |
| `net.inet.tcp`, |
| `net.inet.udp`, |
| `net.inet6`, |
| `net.inet6.divert`, |
| `net.inet6.ip6`, |
| `net.inet6.icmp6`, |
| `net.inet6.pim6`, |
| `net.inet6.tcp6`, |
| `net.inet6.udp6`, |
| `net.mpls`, |
| `net.mpls.ifq`, |
| `net.key`, |
| `net.pflow`, |
| `net.pfsync`, |
| `net.pipex`, |
| `net.rt`, |
| `vm.swapencrypt`, |
| //vfsgenctl /* Special handling required */ |
| } |
| |
| // Node name "fixups" |
| ctlMap := map[string]string{ |
| "ipproto": "net.inet", |
| "net.inet.ipproto": "net.inet", |
| "net.inet6.ipv6proto": "net.inet6", |
| "net.inet6.ipv6": "net.inet6.ip6", |
| "net.inet.icmpv6": "net.inet6.icmp6", |
| "net.inet6.divert6": "net.inet6.divert", |
| "net.inet6.tcp6": "net.inet.tcp", |
| "net.inet6.udp6": "net.inet.udp", |
| "mpls": "net.mpls", |
| "swpenc": "vm.swapencrypt", |
| } |
| |
| // Node mappings |
| nodeMap = map[string]string{ |
| "net.inet.ip.ifq": "net.ifq", |
| "net.inet.pfsync": "net.pfsync", |
| "net.mpls.ifq": "net.ifq", |
| } |
| |
| mCtls := make(map[string]bool) |
| for _, ctl := range ctls { |
| mCtls[ctl] = true |
| } |
| |
| for _, header := range headers { |
| debug("Processing " + header) |
| file, err := os.Open(filepath.Join("/usr/include", header)) |
| if err != nil { |
| fmt.Fprintf(os.Stderr, "%v\n", err) |
| os.Exit(1) |
| } |
| s := bufio.NewScanner(file) |
| for s.Scan() { |
| var sub []string |
| if reMatch(ctlNames1RE, s.Text(), &sub) || |
| reMatch(ctlNames2RE, s.Text(), &sub) || |
| reMatch(ctlNames3RE, s.Text(), &sub) { |
| if sub[1] == `CTL_NAMES` { |
| // Top level. |
| node = &mib |
| } else { |
| // Node. |
| nodename := strings.ToLower(sub[2]) |
| ctlName := "" |
| if reMatch(netInetRE, header, &sub) { |
| ctlName = "net.inet." + nodename |
| } else if reMatch(netInet6RE, header, &sub) { |
| ctlName = "net.inet6." + nodename |
| } else if reMatch(netRE, header, &sub) { |
| ctlName = "net." + nodename |
| } else { |
| ctlName = nodename |
| ctlName = fsNetKernRE.ReplaceAllString(ctlName, `$1.`) |
| } |
| |
| if val, ok := ctlMap[ctlName]; ok { |
| ctlName = val |
| } |
| if _, ok := mCtls[ctlName]; !ok { |
| debug("Ignoring " + ctlName + "...") |
| continue |
| } |
| |
| // Walk down from the top of the MIB. |
| node = &mib |
| for _, part := range strings.Split(ctlName, ".") { |
| if _, ok := (*node)[part]; !ok { |
| debug("Missing node " + part) |
| (*node)[part] = nodeElement{n: 0, t: "", pE: &map[string]nodeElement{}} |
| } |
| node = (*node)[part].pE |
| } |
| } |
| |
| // Populate current node with entries. |
| i := -1 |
| for !strings.HasPrefix(s.Text(), "}") { |
| s.Scan() |
| if reMatch(bracesRE, s.Text(), &sub) { |
| i++ |
| } |
| if !reMatch(ctlTypeRE, s.Text(), &sub) { |
| continue |
| } |
| (*node)[sub[1]] = nodeElement{n: i, t: sub[2], pE: &map[string]nodeElement{}} |
| } |
| } |
| } |
| err = s.Err() |
| if err != nil { |
| fmt.Fprintf(os.Stderr, "%v\n", err) |
| os.Exit(1) |
| } |
| file.Close() |
| } |
| buildSysctl(&mib, "", []int{}) |
| |
| sort.Strings(sysCtl) |
| text := strings.Join(sysCtl, "") |
| |
| fmt.Printf(srcTemplate, cmdLine(), buildTags(), text) |
| } |
| |
| const srcTemplate = `// %s |
| // Code generated by the command above; DO NOT EDIT. |
| |
| // +build %s |
| |
| package unix |
| |
| type mibentry struct { |
| ctlname string |
| ctloid []_C_int |
| } |
| |
| var sysctlMib = []mibentry { |
| %s |
| } |
| ` |