|  | #!/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 | 
|  | // Code generated by the command above; 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 |