Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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配列へのマッピングを行います。

  1. mksysctl_openbsd.pl による zsysctl_openbsd.go の生成: このPerlスクリプトは、OpenBSDの様々なシステムヘッダーファイル(sys/sysctl.h, net/if.h など)を読み込み、#define されている CTL_NAMESCTL_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}},
    }
    
  2. syscall_openbsd.gonametomib 実装: OpenBSDの nametomib 関数は、この sysctlMib スライスに対して二分探索(バイナリサーチ)を実行します。sysctlMibctlname フィールドでソートされているため、効率的に目的の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 を含めるように変更されました。
  • src/pkg/syscall/mkall.sh:
    • ビルドスクリプトに mksysctl_openbsd.pl の実行ロジックが追加され、zsysctl_openbsd.go が生成されるようになりました。
  • src/pkg/syscall/mksysctl_openbsd.pl (新規ファイル):
    • OpenBSDのシステムヘッダーを解析し、sysctl の名前とMIB配列の対応関係をGoのコードとして生成するPerlスクリプトです。
  • src/pkg/syscall/syscall_bsd.go:
    • 共通の syscall_bsd.go から nametomib 関数が削除されました。この関数は、OS固有のファイルに移動されます。
  • src/pkg/syscall/syscall_darwin.go:
    • Darwin(macOS)固有の nametomib 実装がここに追加されました。これは、元の syscall_bsd.go にあった「マジックsysctl」を利用する実装です。
  • src/pkg/syscall/syscall_freebsd.go:
    • FreeBSD固有の nametomib 実装がここに追加されました。これも、元の syscall_bsd.go にあった「マジックsysctl」を利用する実装です。
  • src/pkg/syscall/syscall_openbsd.go:
    • OpenBSD固有の nametomib 実装がここに追加されました。これは、zsysctl_openbsd.go で定義された sysctlMib を二分探索する実装です。
  • 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_NAMESCTL_XXX_NAMES のようなマクロを正規表現でパターンマッチングし、sysctl の階層構造と各エントリの数値識別子(MIB)を抽出します。

抽出された情報に基づいて、スクリプトは内部的にMIBのツリー構造を構築し、最終的にそれをフラットな名前-OID(MIB配列)のハッシュマップに変換します。このハッシュマップは、Go言語の mibentry 構造体のスライスとして整形され、zsysctl_openbsd.go ファイルに出力されます。出力されるGoコードは、sysctlMib というグローバル変数として、すべての sysctl 名と対応するMIB配列のペアを静的に保持します。

syscall_openbsd.gonametomib

OpenBSDの nametomib 関数は、引数として与えられた sysctl 名(文字列)を、zsysctl_openbsd.go で定義された sysctlMib スライス内で検索します。この検索には二分探索アルゴリズムが使用されます。

  1. 初期化: left はスライスの先頭インデックス (0)、right は末尾インデックス (len(sysctlMib) - 1) に設定されます。
  2. ループ: leftright を超えるまでループが続きます。
  3. 中間点の計算: idxleftright の中間点として計算されます。
  4. 比較:
    • もし namesysctlMib[idx].ctlname と完全に一致すれば、対応する ctloid が見つかったとして返されます。
    • もし namesysctlMib[idx].ctlname よりも辞書順で大きい場合、検索範囲は idx + 1 から right までに絞られます(left = idx + 1)。
    • それ以外の場合(namesysctlMib[idx].ctlname よりも小さい場合)、検索範囲は left から idx - 1 までに絞られます(right = idx - 1)。
  5. 終了: ループが終了してもMIBが見つからなかった場合(left > right)、EINVAL エラー(無効な引数)が返されます。

この二分探索により、大量の sysctl エントリの中から効率的に目的のMIB配列を特定することが可能になります。

関連リンク

参考にした情報源リンク