| #!/usr/bin/env perl | 
 |  | 
 | # Copyright 2011 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. | 
 |  | 
 | # | 
 | # 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. | 
 | # | 
 |  | 
 | use strict; | 
 |  | 
 | my $debug = 0; | 
 | my %ctls = (); | 
 |  | 
 | my @headers = qw ( | 
 | 	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/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 | 
 | ); | 
 |  | 
 | my @ctls = qw ( | 
 | 	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" | 
 | my %ctl_map = ( | 
 | 	"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 | 
 | my %node_map = ( | 
 | 	"net.inet.ip.ifq" => "net.ifq", | 
 | 	"net.inet.pfsync" => "net.pfsync", | 
 | 	"net.mpls.ifq" => "net.ifq" | 
 | ); | 
 |  | 
 | my $ctlname; | 
 | my %mib = (); | 
 | my %sysctl = (); | 
 | my $node; | 
 |  | 
 | sub debug() { | 
 | 	print STDERR "$_[0]\n" if $debug; | 
 | } | 
 |  | 
 | # Walk the MIB and build a sysctl name to OID mapping. | 
 | sub build_sysctl() { | 
 | 	my ($node, $name, $oid) = @_; | 
 | 	my %node = %{$node}; | 
 | 	my @oid = @{$oid}; | 
 |  | 
 | 	foreach my $key (sort keys %node) { | 
 | 		my @node = @{$node{$key}}; | 
 | 		my $nodename = $name.($name ne '' ? '.' : '').$key; | 
 | 		my @nodeoid = (@oid, $node[0]); | 
 | 		if ($node[1] eq 'CTLTYPE_NODE') { | 
 | 			if (exists $node_map{$nodename}) { | 
 | 				$node = \%mib; | 
 | 				$ctlname = $node_map{$nodename}; | 
 | 				foreach my $part (split /\./, $ctlname) { | 
 | 					$node = \%{@{$$node{$part}}[2]}; | 
 | 				} | 
 | 			} else { | 
 | 				$node = $node[2]; | 
 | 			} | 
 | 			&build_sysctl($node, $nodename, \@nodeoid); | 
 | 		} elsif ($node[1] ne '') { | 
 | 			$sysctl{$nodename} = \@nodeoid; | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | foreach my $ctl (@ctls) { | 
 | 	$ctls{$ctl} = $ctl; | 
 | } | 
 |  | 
 | # Build MIB | 
 | foreach my $header (@headers) { | 
 | 	&debug("Processing $header..."); | 
 | 	open HEADER, "/usr/include/$header" || | 
 | 	    print STDERR "Failed to open $header\n"; | 
 | 	while (<HEADER>) { | 
 | 		if ($_ =~ /^#define\s+(CTL_NAMES)\s+{/ || | 
 | 		    $_ =~ /^#define\s+(CTL_(.*)_NAMES)\s+{/ || | 
 | 		    $_ =~ /^#define\s+((.*)CTL_NAMES)\s+{/) { | 
 | 			if ($1 eq 'CTL_NAMES') { | 
 | 				# Top level. | 
 | 				$node = \%mib; | 
 | 			} else { | 
 | 				# Node. | 
 | 				my $nodename = lc($2); | 
 | 				if ($header =~ /^netinet\//) { | 
 | 					$ctlname = "net.inet.$nodename"; | 
 | 				} elsif ($header =~ /^netinet6\//) { | 
 | 					$ctlname = "net.inet6.$nodename"; | 
 | 				} elsif ($header =~ /^net\//) { | 
 | 					$ctlname = "net.$nodename"; | 
 | 				} else { | 
 | 					$ctlname = "$nodename"; | 
 | 					$ctlname =~ s/^(fs|net|kern)_/$1\./; | 
 | 				} | 
 | 				if (exists $ctl_map{$ctlname}) { | 
 | 					$ctlname = $ctl_map{$ctlname}; | 
 | 				} | 
 | 				if (not exists $ctls{$ctlname}) { | 
 | 					&debug("Ignoring $ctlname..."); | 
 | 					next; | 
 | 				} | 
 |  | 
 | 				# Walk down from the top of the MIB. | 
 | 				$node = \%mib; | 
 | 				foreach my $part (split /\./, $ctlname) { | 
 | 					if (not exists $$node{$part}) { | 
 | 						&debug("Missing node $part"); | 
 | 						$$node{$part} = [ 0, '', {} ]; | 
 | 					} | 
 | 					$node = \%{@{$$node{$part}}[2]}; | 
 | 				} | 
 | 			} | 
 |  | 
 | 			# Populate current node with entries. | 
 | 			my $i = -1; | 
 | 			while (defined($_) && $_ !~ /^}/) { | 
 | 				$_ = <HEADER>; | 
 | 				$i++ if $_ =~ /{.*}/; | 
 | 				next if $_ !~ /{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}/; | 
 | 				$$node{$1} = [ $i, $2, {} ]; | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	close HEADER; | 
 | } | 
 |  | 
 | &build_sysctl(\%mib, "", []); | 
 |  | 
 | print <<EOF; | 
 | // mksysctl_openbsd.pl | 
 | // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT | 
 |  | 
 | package syscall; | 
 |  | 
 | type mibentry struct { | 
 | 	ctlname string | 
 | 	ctloid []_C_int | 
 | } | 
 |  | 
 | var sysctlMib = []mibentry { | 
 | EOF | 
 |  | 
 | foreach my $name (sort keys %sysctl) { | 
 | 	my @oid = @{$sysctl{$name}}; | 
 | 	print "\t{ \"$name\", []_C_int{ ", join(', ', @oid), " } }, \n"; | 
 | } | 
 |  | 
 | print <<EOF; | 
 | } | 
 | EOF |