Home | History | Annotate | Download | only in unix
      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 if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") {
     18 	print STDERR "GOARCH or GOOS not defined in environment\n";
     19 	exit 1;
     20 }
     21 
     22 my $debug = 0;
     23 my %ctls = ();
     24 
     25 my @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 
     62 my @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"
    122 my %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
    136 my %node_map = (
    137 	"net.inet.ip.ifq" => "net.ifq",
    138 	"net.inet.pfsync" => "net.pfsync",
    139 	"net.mpls.ifq" => "net.ifq"
    140 );
    141 
    142 my $ctlname;
    143 my %mib = ();
    144 my %sysctl = ();
    145 my $node;
    146 
    147 sub debug() {
    148 	print STDERR "$_[0]\n" if $debug;
    149 }
    150 
    151 # Walk the MIB and build a sysctl name to OID mapping.
    152 sub 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 
    178 foreach my $ctl (@ctls) {
    179 	$ctls{$ctl} = $ctl;
    180 }
    181 
    182 # Build MIB
    183 foreach 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 
    241 print <<EOF;
    242 // mksysctl_openbsd.pl
    243 // Code generated by the command above; DO NOT EDIT.
    244 
    245 // +build $ENV{'GOARCH'},$ENV{'GOOS'}
    246 
    247 package unix;
    248 
    249 type mibentry struct {
    250 	ctlname string
    251 	ctloid []_C_int
    252 }
    253 
    254 var sysctlMib = []mibentry {
    255 EOF
    256 
    257 foreach my $name (sort keys %sysctl) {
    258 	my @oid = @{$sysctl{$name}};
    259 	print "\t{ \"$name\", []_C_int{ ", join(', ', @oid), " } }, \n";
    260 }
    261 
    262 print <<EOF;
    263 }
    264 EOF
    265