|
|
@@ -0,0 +1,355 @@
|
|
|
+// 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
|
|
|
+}
|
|
|
+`
|