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