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