[インデックス 10433] ファイルの概要
このコミットは、Go言語の syscall
パッケージにおいて、OpenBSDオペレーティングシステム向けの nametomib
関数の実装を追加するものです。nametomib
関数は、"kern.hostname"
のような人間が読める形式のシステム制御情報(sysctl)の名前を、カーネルが理解できる数値の識別子(MIB: Management Information Base)の配列に変換する役割を担います。
既存のDarwin(macOS)およびFreeBSD向けの nametomib
実装は、それぞれのOS固有のファイルに移動され、OpenBSD向けには、システムヘッダーから事前に生成されたsysctl MIBに基づいて動作する新しい実装が提供されます。この事前生成は mksysctl_openbsd.pl
というPerlスクリプトによって行われます。
コミット
- コミットハッシュ:
773a921ccbb26324db1161edceb38507ab0c96b6
- 作者: Joel Sing jsing@google.com
- 日付: 2011年11月17日 木曜日 23:13:49 +1100
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/773a921ccbb26324db1161edceb38507ab0c96b6
元コミット内容
syscall: implement nametomib for openbsd.
Move the existing darwin/freebsd specific nametomib implementation
into the respective operating system dependent files.
Provide a nametomib implementation for openbsd, which operates on a
sysctl MIB that has been pre-generated from the various system headers
by mksysctl_openbsd.pl.
R=rsc
CC=golang-dev
https://golang.org/cl/4935044
変更の背景
Go言語の syscall
パッケージは、オペレーティングシステム(OS)の低レベルな機能にアクセスするためのインターフェースを提供します。sysctl
は、Unix系OS(特にBSD系)において、カーネルの様々な設定や統計情報を動的に参照・変更するためのメカニズムです。これらの情報は、通常、人間が読める文字列(例: "kern.hostname"
)で識別されますが、カーネル内部では数値の配列(MIB)として扱われます。
以前は、DarwinとFreeBSDの nametomib
実装が syscall_bsd.go
という共通のファイルに存在していました。しかし、OpenBSDの sysctl
の動作が他のBSD系OSと異なるため、共通の実装では対応できませんでした。OpenBSDでは、sysctl
の名前とMIBの対応関係を事前に生成しておく必要がありました。
このコミットの背景には、Go言語がサポートするOSの範囲を広げ、OpenBSD環境でも sysctl
機能を適切に利用できるようにするという目的があります。これにより、GoプログラムがOpenBSDのシステム情報を取得したり、設定を変更したりする際に、OS固有の sysctl
インターフェースを透過的に利用できるようになります。
前提知識の解説
sysctl
sysctl
は、Unix系オペレーティングシステム、特にBSD系OSで広く使われているシステムコールおよびコマンドラインユーティリティです。カーネルの実行時パラメータを照会したり、設定したりするために使用されます。これらのパラメータは、システムの状態、ネットワーク設定、セキュリティポリシーなど、多岐にわたります。
sysctl
のパラメータは階層構造になっており、ドットで区切られた文字列(例: kern.hostname
, net.inet.ip.forwarding
)で表現されます。カーネル内部では、これらの文字列は数値の配列(MIB)に変換されて処理されます。
MIB (Management Information Base)
MIBは、sysctl
において、カーネルパラメータを識別するための数値の配列です。例えば、"kern.hostname"
は []_C_int{1, 10}
のような数値の配列に対応します(実際の値はOSやバージョンによって異なります)。sysctl
システムコールは、この数値の配列を引数として受け取り、対応するカーネルパラメータにアクセスします。
nametomib
関数
nametomib
関数は、sysctl
の文字列名(例: "kern.hostname"
)を、カーネルが認識する数値のMIB配列に変換するユーティリティ関数です。Go言語の syscall
パッケージでは、この変換を行うことで、Goプログラムから sysctl
システムコールを呼び出す際に、文字列名を直接使用できるようにします。
Go言語の syscall
パッケージ
Go言語の syscall
パッケージは、OS固有のシステムコールや低レベルなプリミティブへのアクセスを提供します。これにより、Goプログラムはファイルシステム、ネットワーク、プロセス管理など、OSの基本的な機能と直接対話できます。このパッケージは、OS間の差異を吸収し、クロスプラットフォームな開発を可能にするための重要な役割を担っています。
mksysctl_openbsd.pl
このコミットで導入された mksysctl_openbsd.pl
は、OpenBSDのシステムヘッダーファイル(例: /usr/include/sys/sysctl.h
など)を解析し、sysctl
の文字列名と対応するMIB配列の対応関係をGo言語のソースコードとして生成するためのPerlスクリプトです。OpenBSDの sysctl
は、他のBSD系OSのように動的に文字列名をMIBに変換する「マジックsysctl」のような機能を持たないため、このような事前生成が必要となります。
技術的詳細
このコミットの主要な技術的変更点は、OpenBSDにおける nametomib
の実装戦略です。
Darwin/FreeBSDの nametomib
実装
コミット前のDarwinおよびFreeBSDの nametomib
実装(元々は syscall_bsd.go
にあり、後にそれぞれのOS固有ファイルに移動)は、sysctl([]_C_int{0, 3}, ...)
という「マジックsysctl」呼び出しを利用していました。これは、sysctl
システムコール自体に、文字列名をMIB配列に変換する機能が組み込まれていることを意味します。具体的には、0.3
というMIBは、文字列名を引数として受け取り、対応するMIB配列を返す特殊な機能を提供します。
// syscall_darwin.go および syscall_freebsd.go に移動されたコードの抜粋
func nametomib(name string) (mib []_C_int, err error) {
// ...
// Magic sysctl: "setting" 0.3 to a string name
// lets you read back the array of integers form.
if err = sysctl([]_C_int{0, 3}, p, &n, &bytes[0], uintptr(len(name))); err != nil {
return nil, err
}
return buf[0 : n/siz], nil
}
OpenBSDの nametomib
実装
OpenBSDには、上記のような「マジックsysctl」機能がありません。そのため、nametomib
関数は、事前に生成された sysctlMib
というGoのデータ構造を利用して、文字列名からMIB配列へのマッピングを行います。
-
mksysctl_openbsd.pl
によるzsysctl_openbsd.go
の生成: このPerlスクリプトは、OpenBSDの様々なシステムヘッダーファイル(sys/sysctl.h
,net/if.h
など)を読み込み、#define
されているCTL_NAMES
やCTL_XXX_NAMES
の定義を解析します。これにより、"kern.hostname"
のような文字列名と、それに対応する数値のMIB配列(例:[]_C_int{1, 10}
)のペアを抽出し、zsysctl_openbsd.go
というGoのソースファイルとして出力します。このファイルには、mibentry
構造体のスライスであるsysctlMib
変数が定義されます。// zsysctl_openbsd.go の抜粋 (mksysctl_openbsd.pl によって生成される) package syscall type mibentry struct { ctlname string ctloid []_C_int } var sysctlMib = []mibentry{ {"ddb.console", []_C_int{9, 6}}, {"ddb.log", []_C_int{9, 7}}, // ... 多数のエントリ ... {"vm.vtextmin", []_C_int{2, 8}}, }
-
syscall_openbsd.go
のnametomib
実装: OpenBSDのnametomib
関数は、このsysctlMib
スライスに対して二分探索(バイナリサーチ)を実行します。sysctlMib
はctlname
フィールドでソートされているため、効率的に目的のMIB配列を検索できます。// syscall_openbsd.go の nametomib 実装 func nametomib(name string) (mib []_C_int, err error) { // Perform lookup via a binary search left := 0 right := len(sysctlMib) - 1 for { idx := left + (right-left)/2 switch { case name == sysctlMib[idx].ctlname: return sysctlMib[idx].ctloid, nil case name > sysctlMib[idx].ctlname: left = idx + 1 default: right = idx - 1 } if left > right { break } } return nil, EINVAL // 見つからなかった場合 }
このアプローチにより、OpenBSDの sysctl
の特性に合わせた nametomib
の実装が実現されています。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルと内容は以下の通りです。
src/pkg/syscall/Makefile
:- OpenBSD向けのビルドに
zsysctl_openbsd.go
を含めるように変更されました。
- OpenBSD向けのビルドに
src/pkg/syscall/mkall.sh
:- ビルドスクリプトに
mksysctl_openbsd.pl
の実行ロジックが追加され、zsysctl_openbsd.go
が生成されるようになりました。
- ビルドスクリプトに
src/pkg/syscall/mksysctl_openbsd.pl
(新規ファイル):- OpenBSDのシステムヘッダーを解析し、
sysctl
の名前とMIB配列の対応関係をGoのコードとして生成するPerlスクリプトです。
- OpenBSDのシステムヘッダーを解析し、
src/pkg/syscall/syscall_bsd.go
:- 共通の
syscall_bsd.go
からnametomib
関数が削除されました。この関数は、OS固有のファイルに移動されます。
- 共通の
src/pkg/syscall/syscall_darwin.go
:- Darwin(macOS)固有の
nametomib
実装がここに追加されました。これは、元のsyscall_bsd.go
にあった「マジックsysctl」を利用する実装です。
- Darwin(macOS)固有の
src/pkg/syscall/syscall_freebsd.go
:- FreeBSD固有の
nametomib
実装がここに追加されました。これも、元のsyscall_bsd.go
にあった「マジックsysctl」を利用する実装です。
- FreeBSD固有の
src/pkg/syscall/syscall_openbsd.go
:- OpenBSD固有の
nametomib
実装がここに追加されました。これは、zsysctl_openbsd.go
で定義されたsysctlMib
を二分探索する実装です。
- OpenBSD固有の
src/pkg/syscall/zsysctl_openbsd.go
(新規ファイル):mksysctl_openbsd.pl
によって生成されるファイルで、OpenBSDのsysctl
名とMIB配列の静的なマッピングがGoのデータ構造として定義されています。
コアとなるコードの解説
mksysctl_openbsd.pl
このPerlスクリプトは、OpenBSDの /usr/include
ディレクトリにある複数のヘッダーファイル(sys/sysctl.h
, net/if.h
など)を読み込みます。スクリプトは、これらのファイル内で定義されている CTL_NAMES
や CTL_XXX_NAMES
のようなマクロを正規表現でパターンマッチングし、sysctl
の階層構造と各エントリの数値識別子(MIB)を抽出します。
抽出された情報に基づいて、スクリプトは内部的にMIBのツリー構造を構築し、最終的にそれをフラットな名前-OID(MIB配列)のハッシュマップに変換します。このハッシュマップは、Go言語の mibentry
構造体のスライスとして整形され、zsysctl_openbsd.go
ファイルに出力されます。出力されるGoコードは、sysctlMib
というグローバル変数として、すべての sysctl
名と対応するMIB配列のペアを静的に保持します。
syscall_openbsd.go
の nametomib
OpenBSDの nametomib
関数は、引数として与えられた sysctl
名(文字列)を、zsysctl_openbsd.go
で定義された sysctlMib
スライス内で検索します。この検索には二分探索アルゴリズムが使用されます。
- 初期化:
left
はスライスの先頭インデックス (0)、right
は末尾インデックス (len(sysctlMib) - 1
) に設定されます。 - ループ:
left
がright
を超えるまでループが続きます。 - 中間点の計算:
idx
はleft
とright
の中間点として計算されます。 - 比較:
- もし
name
がsysctlMib[idx].ctlname
と完全に一致すれば、対応するctloid
が見つかったとして返されます。 - もし
name
がsysctlMib[idx].ctlname
よりも辞書順で大きい場合、検索範囲はidx + 1
からright
までに絞られます(left = idx + 1
)。 - それ以外の場合(
name
がsysctlMib[idx].ctlname
よりも小さい場合)、検索範囲はleft
からidx - 1
までに絞られます(right = idx - 1
)。
- もし
- 終了: ループが終了してもMIBが見つからなかった場合(
left > right
)、EINVAL
エラー(無効な引数)が返されます。
この二分探索により、大量の sysctl
エントリの中から効率的に目的のMIB配列を特定することが可能になります。
関連リンク
- Go CL 4935044: https://golang.org/cl/4935044
参考にした情報源リンク
- OpenBSD sysctl(3) man page: https://man.openbsd.org/sysctl.3
- Go
syscall
package documentation: https://pkg.go.dev/syscall - BSD
sysctl
mechanism (general information): https://en.wikipedia.org/wiki/Sysctl - Go
unsafe
package documentation (forunsafe.Sizeof
andunsafe.Pointer
context): https://pkg.go.dev/unsafe - Perl
strict
andwarnings
pragmas: https://perldoc.perl.org/strict - Binary search algorithm: https://en.wikipedia.org/wiki/Binary_search_algorithm