| #!/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; |
| |
| if($ENV{'GOARCH'} eq "" || $ENV{'GOOS'} eq "") { |
| print STDERR "GOARCH or GOOS not defined in environment\n"; |
| exit 1; |
| } |
| |
| 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 |
| |
| // +build $ENV{'GOARCH'},$ENV{'GOOS'} |
| |
| package unix; |
| |
| 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 |