mksysctl_openbsd.pl

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