1#!/usr/bin/env perl 2 3# Copyright 2011 The Go Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style 5# license that can be found in the LICENSE file. 6 7# 8# Parse the header files for OpenBSD and generate a Go usable sysctl MIB. 9# 10# Build a MIB with each entry being an array containing the level, type and 11# a hash that will contain additional entries if the current entry is a node. 12# We then walk this MIB and create a flattened sysctl name to OID hash. 13# 14 15use strict; 16 17if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { 18 print STDERR "GOARCH or GOOS not defined in environment\n"; 19 exit 1; 20} 21 22my $debug = 0; 23my %ctls = (); 24 25my @headers = qw ( 26 sys/sysctl.h 27 sys/socket.h 28 sys/tty.h 29 sys/malloc.h 30 sys/mount.h 31 sys/namei.h 32 sys/sem.h 33 sys/shm.h 34 sys/vmmeter.h 35 uvm/uvm_param.h 36 uvm/uvm_swap_encrypt.h 37 ddb/db_var.h 38 net/if.h 39 net/if_pfsync.h 40 net/pipex.h 41 netinet/in.h 42 netinet/icmp_var.h 43 netinet/igmp_var.h 44 netinet/ip_ah.h 45 netinet/ip_carp.h 46 netinet/ip_divert.h 47 netinet/ip_esp.h 48 netinet/ip_ether.h 49 netinet/ip_gre.h 50 netinet/ip_ipcomp.h 51 netinet/ip_ipip.h 52 netinet/pim_var.h 53 netinet/tcp_var.h 54 netinet/udp_var.h 55 netinet6/in6.h 56 netinet6/ip6_divert.h 57 netinet6/pim6_var.h 58 netinet/icmp6.h 59 netmpls/mpls.h 60); 61 62my @ctls = qw ( 63 kern 64 vm 65 fs 66 net 67 #debug # Special handling required 68 hw 69 #machdep # Arch specific 70 user 71 ddb 72 #vfs # Special handling required 73 fs.posix 74 kern.forkstat 75 kern.intrcnt 76 kern.malloc 77 kern.nchstats 78 kern.seminfo 79 kern.shminfo 80 kern.timecounter 81 kern.tty 82 kern.watchdog 83 net.bpf 84 net.ifq 85 net.inet 86 net.inet.ah 87 net.inet.carp 88 net.inet.divert 89 net.inet.esp 90 net.inet.etherip 91 net.inet.gre 92 net.inet.icmp 93 net.inet.igmp 94 net.inet.ip 95 net.inet.ip.ifq 96 net.inet.ipcomp 97 net.inet.ipip 98 net.inet.mobileip 99 net.inet.pfsync 100 net.inet.pim 101 net.inet.tcp 102 net.inet.udp 103 net.inet6 104 net.inet6.divert 105 net.inet6.ip6 106 net.inet6.icmp6 107 net.inet6.pim6 108 net.inet6.tcp6 109 net.inet6.udp6 110 net.mpls 111 net.mpls.ifq 112 net.key 113 net.pflow 114 net.pfsync 115 net.pipex 116 net.rt 117 vm.swapencrypt 118 #vfsgenctl # Special handling required 119); 120 121# Node name "fixups" 122my %ctl_map = ( 123 "ipproto" => "net.inet", 124 "net.inet.ipproto" => "net.inet", 125 "net.inet6.ipv6proto" => "net.inet6", 126 "net.inet6.ipv6" => "net.inet6.ip6", 127 "net.inet.icmpv6" => "net.inet6.icmp6", 128 "net.inet6.divert6" => "net.inet6.divert", 129 "net.inet6.tcp6" => "net.inet.tcp", 130 "net.inet6.udp6" => "net.inet.udp", 131 "mpls" => "net.mpls", 132 "swpenc" => "vm.swapencrypt" 133); 134 135# Node mappings 136my %node_map = ( 137 "net.inet.ip.ifq" => "net.ifq", 138 "net.inet.pfsync" => "net.pfsync", 139 "net.mpls.ifq" => "net.ifq" 140); 141 142my $ctlname; 143my %mib = (); 144my %sysctl = (); 145my $node; 146 147sub debug() { 148 print STDERR "$_[0]\n" if $debug; 149} 150 151# Walk the MIB and build a sysctl name to OID mapping. 152sub build_sysctl() { 153 my ($node, $name, $oid) = @_; 154 my %node = %{$node}; 155 my @oid = @{$oid}; 156 157 foreach my $key (sort keys %node) { 158 my @node = @{$node{$key}}; 159 my $nodename = $name.($name ne '' ? '.' : '').$key; 160 my @nodeoid = (@oid, $node[0]); 161 if ($node[1] eq 'CTLTYPE_NODE') { 162 if (exists $node_map{$nodename}) { 163 $node = \%mib; 164 $ctlname = $node_map{$nodename}; 165 foreach my $part (split /\./, $ctlname) { 166 $node = \%{@{$$node{$part}}[2]}; 167 } 168 } else { 169 $node = $node[2]; 170 } 171 &build_sysctl($node, $nodename, \@nodeoid); 172 } elsif ($node[1] ne '') { 173 $sysctl{$nodename} = \@nodeoid; 174 } 175 } 176} 177 178foreach my $ctl (@ctls) { 179 $ctls{$ctl} = $ctl; 180} 181 182# Build MIB 183foreach my $header (@headers) { 184 &debug("Processing $header..."); 185 open HEADER, "/usr/include/$header" || 186 print STDERR "Failed to open $header\n"; 187 while (<HEADER>) { 188 if ($_ =~ /^#define\s+(CTL_NAMES)\s+{/ || 189 $_ =~ /^#define\s+(CTL_(.*)_NAMES)\s+{/ || 190 $_ =~ /^#define\s+((.*)CTL_NAMES)\s+{/) { 191 if ($1 eq 'CTL_NAMES') { 192 # Top level. 193 $node = \%mib; 194 } else { 195 # Node. 196 my $nodename = lc($2); 197 if ($header =~ /^netinet\//) { 198 $ctlname = "net.inet.$nodename"; 199 } elsif ($header =~ /^netinet6\//) { 200 $ctlname = "net.inet6.$nodename"; 201 } elsif ($header =~ /^net\//) { 202 $ctlname = "net.$nodename"; 203 } else { 204 $ctlname = "$nodename"; 205 $ctlname =~ s/^(fs|net|kern)_/$1\./; 206 } 207 if (exists $ctl_map{$ctlname}) { 208 $ctlname = $ctl_map{$ctlname}; 209 } 210 if (not exists $ctls{$ctlname}) { 211 &debug("Ignoring $ctlname..."); 212 next; 213 } 214 215 # Walk down from the top of the MIB. 216 $node = \%mib; 217 foreach my $part (split /\./, $ctlname) { 218 if (not exists $$node{$part}) { 219 &debug("Missing node $part"); 220 $$node{$part} = [ 0, '', {} ]; 221 } 222 $node = \%{@{$$node{$part}}[2]}; 223 } 224 } 225 226 # Populate current node with entries. 227 my $i = -1; 228 while (defined($_) && $_ !~ /^}/) { 229 $_ = <HEADER>; 230 $i++ if $_ =~ /{.*}/; 231 next if $_ !~ /{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}/; 232 $$node{$1} = [ $i, $2, {} ]; 233 } 234 } 235 } 236 close HEADER; 237} 238 239&build_sysctl(\%mib, "", []); 240 241print <<EOF; 242// mksysctl_openbsd.pl 243// Code generated by the command above; DO NOT EDIT. 244 245// +build $ENV{'GOARCH'},$ENV{'GOOS'} 246 247package unix; 248 249type mibentry struct { 250 ctlname string 251 ctloid []_C_int 252} 253 254var sysctlMib = []mibentry { 255EOF 256 257foreach my $name (sort keys %sysctl) { 258 my @oid = @{$sysctl{$name}}; 259 print "\t{ \"$name\", []_C_int{ ", join(', ', @oid), " } }, \n"; 260} 261 262print <<EOF; 263} 264EOF 265