unix: replace "mksysctl_openbsd.pl" script with a Go program

Port mksysctl_openbsd.pl Perl script to mksysctl_openbsd.go.
mkall.sh script is modified to run mksysctl_openbsd.go. Running
mkall.sh does not generate any git diff besides the command
name in comments of generated files. Any missing build tag is
also added in generated files.

Fixes golang/go#27779

Change-Id: I9f946d2818feb31e710029927f089904c5e272cf
Reviewed-on: https://go-review.googlesource.com/c/sys/+/174127
Reviewed-by: Benny Siegert <bsiegert@gmail.com>
Run-TryBot: Benny Siegert <bsiegert@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/unix/mkall.sh b/unix/mkall.sh
index 8be2f49..c6516f2 100755
--- a/unix/mkall.sh
+++ b/unix/mkall.sh
@@ -149,21 +149,21 @@
 openbsd_386)
 	mkerrors="$mkerrors -m32"
 	mksyscall="go run mksyscall.go -l32 -openbsd"
-	mksysctl="./mksysctl_openbsd.pl"
+	mksysctl="go run mksysctl_openbsd.go"
 	mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
 openbsd_amd64)
 	mkerrors="$mkerrors -m64"
 	mksyscall="go run mksyscall.go -openbsd"
-	mksysctl="./mksysctl_openbsd.pl"
+	mksysctl="go run mksysctl_openbsd.go"
 	mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
 openbsd_arm)
 	mkerrors="$mkerrors"
 	mksyscall="go run mksyscall.go -l32 -openbsd -arm"
-	mksysctl="./mksysctl_openbsd.pl"
+	mksysctl="go run mksysctl_openbsd.go"
 	mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
 	# Let the type of C char be signed for making the bare syscall
 	# API consistent across platforms.
@@ -172,7 +172,7 @@
 openbsd_arm64)
 	mkerrors="$mkerrors -m64"
 	mksyscall="go run mksyscall.go -openbsd"
-	mksysctl="./mksysctl_openbsd.pl"
+	mksysctl="go run mksysctl_openbsd.go"
 	mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
 	# Let the type of C char be signed for making the bare syscall
 	# API consistent across platforms.
diff --git a/unix/mksysctl_openbsd.go b/unix/mksysctl_openbsd.go
new file mode 100644
index 0000000..b6b4099
--- /dev/null
+++ b/unix/mksysctl_openbsd.go
@@ -0,0 +1,355 @@
+// Copyright 2019 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.
+
+// +build ignore
+
+// 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.
+
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"os"
+	"path/filepath"
+	"regexp"
+	"sort"
+	"strings"
+)
+
+var (
+	goos, goarch string
+)
+
+// cmdLine returns this programs's commandline arguments.
+func cmdLine() string {
+	return "go run mksysctl_openbsd.go " + strings.Join(os.Args[1:], " ")
+}
+
+// buildTags returns build tags.
+func buildTags() string {
+	return fmt.Sprintf("%s,%s", goarch, goos)
+}
+
+// reMatch performs regular expression match and stores the substring slice to value pointed by m.
+func reMatch(re *regexp.Regexp, str string, m *[]string) bool {
+	*m = re.FindStringSubmatch(str)
+	if *m != nil {
+		return true
+	}
+	return false
+}
+
+type nodeElement struct {
+	n  int
+	t  string
+	pE *map[string]nodeElement
+}
+
+var (
+	debugEnabled bool
+	mib          map[string]nodeElement
+	node         *map[string]nodeElement
+	nodeMap      map[string]string
+	sysCtl       []string
+)
+
+var (
+	ctlNames1RE = regexp.MustCompile(`^#define\s+(CTL_NAMES)\s+{`)
+	ctlNames2RE = regexp.MustCompile(`^#define\s+(CTL_(.*)_NAMES)\s+{`)
+	ctlNames3RE = regexp.MustCompile(`^#define\s+((.*)CTL_NAMES)\s+{`)
+	netInetRE   = regexp.MustCompile(`^netinet/`)
+	netInet6RE  = regexp.MustCompile(`^netinet6/`)
+	netRE       = regexp.MustCompile(`^net/`)
+	bracesRE    = regexp.MustCompile(`{.*}`)
+	ctlTypeRE   = regexp.MustCompile(`{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}`)
+	fsNetKernRE = regexp.MustCompile(`^(fs|net|kern)_`)
+)
+
+func debug(s string) {
+	if debugEnabled {
+		fmt.Fprintln(os.Stderr, s)
+	}
+}
+
+// Walk the MIB and build a sysctl name to OID mapping.
+func buildSysctl(pNode *map[string]nodeElement, name string, oid []int) {
+	lNode := pNode // local copy of pointer to node
+	var keys []string
+	for k := range *lNode {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+
+	for _, key := range keys {
+		nodename := name
+		if name != "" {
+			nodename += "."
+		}
+		nodename += key
+
+		nodeoid := append(oid, (*pNode)[key].n)
+
+		if (*pNode)[key].t == `CTLTYPE_NODE` {
+			if _, ok := nodeMap[nodename]; ok {
+				lNode = &mib
+				ctlName := nodeMap[nodename]
+				for _, part := range strings.Split(ctlName, ".") {
+					lNode = ((*lNode)[part]).pE
+				}
+			} else {
+				lNode = (*pNode)[key].pE
+			}
+			buildSysctl(lNode, nodename, nodeoid)
+		} else if (*pNode)[key].t != "" {
+			oidStr := []string{}
+			for j := range nodeoid {
+				oidStr = append(oidStr, fmt.Sprintf("%d", nodeoid[j]))
+			}
+			text := "\t{ \"" + nodename + "\", []_C_int{ " + strings.Join(oidStr, ", ") + " } }, \n"
+			sysCtl = append(sysCtl, text)
+		}
+	}
+}
+
+func main() {
+	// Get the OS (using GOOS_TARGET if it exist)
+	goos = os.Getenv("GOOS_TARGET")
+	if goos == "" {
+		goos = os.Getenv("GOOS")
+	}
+	// Get the architecture (using GOARCH_TARGET if it exists)
+	goarch = os.Getenv("GOARCH_TARGET")
+	if goarch == "" {
+		goarch = os.Getenv("GOARCH")
+	}
+	// Check if GOOS and GOARCH environment variables are defined
+	if goarch == "" || goos == "" {
+		fmt.Fprintf(os.Stderr, "GOARCH or GOOS not defined in environment\n")
+		os.Exit(1)
+	}
+
+	mib = make(map[string]nodeElement)
+	headers := [...]string{
+		`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/uvmexp.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`,
+	}
+
+	ctls := [...]string{
+		`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"
+	ctlMap := map[string]string{
+		"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
+	nodeMap = map[string]string{
+		"net.inet.ip.ifq": "net.ifq",
+		"net.inet.pfsync": "net.pfsync",
+		"net.mpls.ifq":    "net.ifq",
+	}
+
+	mCtls := make(map[string]bool)
+	for _, ctl := range ctls {
+		mCtls[ctl] = true
+	}
+
+	for _, header := range headers {
+		debug("Processing " + header)
+		file, err := os.Open(filepath.Join("/usr/include", header))
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "%v\n", err)
+			os.Exit(1)
+		}
+		s := bufio.NewScanner(file)
+		for s.Scan() {
+			var sub []string
+			if reMatch(ctlNames1RE, s.Text(), &sub) ||
+				reMatch(ctlNames2RE, s.Text(), &sub) ||
+				reMatch(ctlNames3RE, s.Text(), &sub) {
+				if sub[1] == `CTL_NAMES` {
+					// Top level.
+					node = &mib
+				} else {
+					// Node.
+					nodename := strings.ToLower(sub[2])
+					ctlName := ""
+					if reMatch(netInetRE, header, &sub) {
+						ctlName = "net.inet." + nodename
+					} else if reMatch(netInet6RE, header, &sub) {
+						ctlName = "net.inet6." + nodename
+					} else if reMatch(netRE, header, &sub) {
+						ctlName = "net." + nodename
+					} else {
+						ctlName = nodename
+						ctlName = fsNetKernRE.ReplaceAllString(ctlName, `$1.`)
+					}
+
+					if val, ok := ctlMap[ctlName]; ok {
+						ctlName = val
+					}
+					if _, ok := mCtls[ctlName]; !ok {
+						debug("Ignoring " + ctlName + "...")
+						continue
+					}
+
+					// Walk down from the top of the MIB.
+					node = &mib
+					for _, part := range strings.Split(ctlName, ".") {
+						if _, ok := (*node)[part]; !ok {
+							debug("Missing node " + part)
+							(*node)[part] = nodeElement{n: 0, t: "", pE: &map[string]nodeElement{}}
+						}
+						node = (*node)[part].pE
+					}
+				}
+
+				// Populate current node with entries.
+				i := -1
+				for !strings.HasPrefix(s.Text(), "}") {
+					s.Scan()
+					if reMatch(bracesRE, s.Text(), &sub) {
+						i++
+					}
+					if !reMatch(ctlTypeRE, s.Text(), &sub) {
+						continue
+					}
+					(*node)[sub[1]] = nodeElement{n: i, t: sub[2], pE: &map[string]nodeElement{}}
+				}
+			}
+		}
+		err = s.Err()
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "%v\n", err)
+			os.Exit(1)
+		}
+		file.Close()
+	}
+	buildSysctl(&mib, "", []int{})
+
+	sort.Strings(sysCtl)
+	text := strings.Join(sysCtl, "")
+
+	fmt.Printf(srcTemplate, cmdLine(), buildTags(), text)
+}
+
+const srcTemplate = `// %s
+// Code generated by the command above; DO NOT EDIT.
+
+// +build %s
+
+package unix
+
+type mibentry struct {
+	ctlname string
+	ctloid []_C_int
+}
+
+var sysctlMib = []mibentry {
+%s
+}
+`
diff --git a/unix/mksysctl_openbsd.pl b/unix/mksysctl_openbsd.pl
deleted file mode 100755
index 20632e1..0000000
--- a/unix/mksysctl_openbsd.pl
+++ /dev/null
@@ -1,265 +0,0 @@
-#!/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/uvmexp.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.
-
-// +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
diff --git a/unix/zsysctl_openbsd_386.go b/unix/zsysctl_openbsd_386.go
index b005031..37dcc74 100644
--- a/unix/zsysctl_openbsd_386.go
+++ b/unix/zsysctl_openbsd_386.go
@@ -1,6 +1,8 @@
 // mksysctl_openbsd.pl
 // Code generated by the command above; DO NOT EDIT.
 
+// +build 386,openbsd
+
 package unix
 
 type mibentry struct {
diff --git a/unix/zsysctl_openbsd_amd64.go b/unix/zsysctl_openbsd_amd64.go
index d014451..fe6caa6 100644
--- a/unix/zsysctl_openbsd_amd64.go
+++ b/unix/zsysctl_openbsd_amd64.go
@@ -1,4 +1,4 @@
-// mksysctl_openbsd.pl
+// go run mksysctl_openbsd.go
 // Code generated by the command above; DO NOT EDIT.
 
 // +build amd64,openbsd
diff --git a/unix/zsysctl_openbsd_arm.go b/unix/zsysctl_openbsd_arm.go
index b005031..6eb8c0b 100644
--- a/unix/zsysctl_openbsd_arm.go
+++ b/unix/zsysctl_openbsd_arm.go
@@ -1,6 +1,8 @@
-// mksysctl_openbsd.pl
+// go run mksysctl_openbsd.go
 // Code generated by the command above; DO NOT EDIT.
 
+// +build arm,openbsd
+
 package unix
 
 type mibentry struct {
diff --git a/unix/zsysctl_openbsd_arm64.go b/unix/zsysctl_openbsd_arm64.go
index bfd21b0..ba4304f 100644
--- a/unix/zsysctl_openbsd_arm64.go
+++ b/unix/zsysctl_openbsd_arm64.go
@@ -1,4 +1,4 @@
-// mksysctl_openbsd.pl
+// go run mksysctl_openbsd.go
 // Code generated by the command above; DO NOT EDIT.
 
 // +build arm64,openbsd