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

[インデックス 17758] ファイルの概要

このコミットは、Go言語のos/userパッケージにおけるユーザー情報ルックアップの挙動を、DragonFly BSDオペレーティングシステム上で修正するものです。具体的には、getpwnam_rgetpwuid_rといったPOSIX準拠の関数が内部的に使用するバッファサイズの決定方法に関する問題に対処しています。

コミット

commit fc1bea321de31243c2f68316941e0f99eeb86557
Author: Joel Sing <jsing@google.com>
Date:   Mon Oct 7 09:21:33 2013 -0700

    os/user: fix user lookups on dragonfly
    
    Like FreeBSD, DragonFly does not provide a sysconf value for
    _SC_GETPW_R_SIZE_MAX.
    
    R=golang-dev, iant
    CC=golang-dev
    https://golang.org/cl/14469043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/fc1bea321de31243c2f68316941e0f99eeb86557

元コミット内容

このコミットは、src/pkg/os/user/lookup_unix.goファイルに対して行われた変更です。変更内容は以下の通りです。

--- a/src/pkg/os/user/lookup_unix.go
+++ b/src/pkg/os/user/lookup_unix.go
@@ -50,10 +50,10 @@ func lookupUnix(uid int, username string, lookupByName bool) (*User, error) {\
 	var result *C.struct_passwd
 
 	var bufSize C.long
-	if runtime.GOOS == "freebsd" {
-		// FreeBSD doesn't have _SC_GETPW_R_SIZE_MAX
-		// and just returns -1.  So just use the same
-		// size that Linux returns
+	if runtime.GOOS == "dragonfly" || runtime.GOOS == "freebsd" {
+		// DragonFly and FreeBSD do not have _SC_GETPW_R_SIZE_MAX
+		// and just return -1.  So just use the same
+		// size that Linux returns.
 		bufSize = 1024
 	} else {
 		bufSize = C.sysconf(C._SC_GETPW_R_SIZE_MAX)

変更の背景

Go言語のos/userパッケージは、システム上のユーザー情報を取得するための機能を提供します。Unix系システムでは、ユーザー情報を取得するためにgetpwnam_r(ユーザー名から)やgetpwuid_r(UIDから)といった再入可能な(reentrant)関数が使用されます。これらの関数は、結果を格納するためのバッファを呼び出し元が提供する必要があります。

バッファの適切なサイズを決定するために、POSIX標準では_SC_GETPW_R_SIZE_MAXというsysconf値が定義されています。これは、getpwnam_rgetpwuid_rが要求する可能性のある最大バッファサイズを示します。しかし、一部のUnix系オペレーティングシステム(特にFreeBSD)では、この_SC_GETPW_R_SIZE_MAXが提供されておらず、sysconfを呼び出しても-1が返されることがあります。

このコミット以前は、Goのos/userパッケージはFreeBSDに対してのみ、この_SC_GETPW_R_SIZE_MAXの欠如を特別扱いし、固定のバッファサイズ(1024バイト)を使用していました。しかし、DragonFly BSDも同様に_SC_GETPW_R_SIZE_MAXを提供しないことが判明しました。このため、DragonFly BSD上でユーザー情報のルックアップを行う際に、適切なバッファサイズが確保されず、問題が発生する可能性がありました。

この変更の背景には、Go言語がサポートするオペレーティングシステムの範囲を広げ、それぞれのOSの特性に合わせた堅牢な挙動を保証するという目的があります。

前提知識の解説

os/userパッケージ

Go言語の標準ライブラリの一部で、現在のユーザーや指定されたユーザーの情報を取得するための機能を提供します。例えば、ユーザー名、UID、GID、ホームディレクトリなどの情報を取得できます。

getpwnam_rgetpwuid_r

これらはPOSIX標準で定義されているCライブラリ関数です。

  • getpwnam_r(const char *name, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result): ユーザー名nameに対応するユーザー情報を取得し、pwd構造体とbufバッファに格納します。
  • getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result): ユーザーIDuidに対応するユーザー情報を取得し、pwd構造体とbufバッファに格納します。

これらの関数は、スレッドセーフな再入可能バージョンであり、結果を格納するためのメモリを呼び出し元が提供する必要があります。bufbuflenはそのバッファとそのサイズを指定します。

sysconf_SC_GETPW_R_SIZE_MAX

  • sysconf(int name): システム設定情報を取得するためのPOSIX関数です。様々なシステム制限やオプションの値を問い合わせるために使用されます。
  • _SC_GETPW_R_SIZE_MAX: sysconf関数に渡すことができる定数の一つで、getpwnam_rgetpwuid_r関数がユーザー情報を格納するために必要とする可能性のある最大バッファサイズを返します。この値はシステムによって異なります。

DragonFly BSDとFreeBSD

どちらもUnix系オペレーティングシステムであり、BSD系OSの派生です。FreeBSDは広く使われていますが、DragonFly BSDはFreeBSD 4.8からフォークして開発された、より実験的な側面を持つOSです。両者ともに、一部のPOSIX標準のsysconf値(特に_SC_GETPW_R_SIZE_MAX)の実装が他のUnix系OS(例: Linux)と異なる場合があります。

技術的詳細

このコミットの技術的な核心は、getpwnam_rgetpwuid_r関数に渡すバッファサイズの決定ロジックにあります。

Goのos/userパッケージは、内部的にC言語の関数を呼び出すためにcgoを使用しています。lookup_unix.goファイルは、Unix系システムにおけるユーザー情報のルックアップを担当しています。

元のコードでは、bufSizeを決定する際に、まずruntime.GOOS == "freebsd"という条件でFreeBSDを特別扱いしていました。FreeBSDでは_SC_GETPW_R_SIZE_MAX-1を返すため、固定値の1024バイトをバッファサイズとして使用していました。これは、Linuxが通常返すサイズと同じ値です。

	var bufSize C.long
	if runtime.GOOS == "freebsd" {
		// FreeBSD doesn't have _SC_GETPW_R_SIZE_MAX
		// and just returns -1.  So just use the same
		// size that Linux returns
		bufSize = 1024
	} else {
		bufSize = C.sysconf(C._SC_GETPW_R_SIZE_MAX)
	}

このコミットでは、この条件にruntime.GOOS == "dragonfly"を追加しました。これにより、DragonFly BSDもFreeBSDと同様に_SC_GETPW_R_SIZE_MAXが利用できないシステムとして扱われ、固定の1024バイトのバッファサイズが割り当てられるようになります。

	if runtime.GOOS == "dragonfly" || runtime.GOOS == "freebsd" {
		// DragonFly and FreeBSD do not have _SC_GETPW_R_SIZE_MAX
		// and just return -1.  So just use the same
		// size that Linux returns.
		bufSize = 1024
	} else {
		bufSize = C.sysconf(C._SC_GETPW_R_SIZE_MAX)
	}

この変更により、DragonFly BSD上でもgetpwnam_rgetpwuid_rが適切なサイズのバッファを受け取ることが保証され、ユーザー情報のルックアップが正しく機能するようになります。固定値の1024バイトは、ほとんどのシステムでユーザー情報を格納するのに十分なサイズであり、互換性の問題を引き起こす可能性が低いと判断されたため採用されています。

コアとなるコードの変更箇所

変更はsrc/pkg/os/user/lookup_unix.goファイルの以下の部分です。

--- a/src/pkg/os/user/lookup_unix.go
+++ b/src/pkg/os/user/lookup_unix.go
@@ -50,10 +50,10 @@ func lookupUnix(uid int, username string, lookupByName bool) (*User, error) {\
 	var result *C.struct_passwd
 
 	var bufSize C.long
-	if runtime.GOOS == "freebsd" {
-		// FreeBSD doesn't have _SC_GETPW_R_SIZE_MAX
-		// and just returns -1.  So just use the same
-		// size that Linux returns
+	if runtime.GOOS == "dragonfly" || runtime.GOOS == "freebsd" {
+		// DragonFly and FreeBSD do not have _SC_GETPW_R_SIZE_MAX
+		// and just return -1.  So just use the same
+		// size that Linux returns.
 		bufSize = 1024
 	} else {
 		bufSize = C.sysconf(C._SC_GETPW_R_SIZE_MAX)

コアとなるコードの解説

このコードスニペットは、Unix系システムでユーザー情報をルックアップする際のバッファサイズを決定するロジックを含んでいます。

  1. var bufSize C.long: C言語のlong型に対応するbufSize変数を宣言しています。これは、getpwnam_rgetpwuid_rに渡すバッファのサイズを保持します。
  2. if runtime.GOOS == "dragonfly" || runtime.GOOS == "freebsd": ここが変更された条件分岐です。
    • runtime.GOOSは、Goプログラムが実行されているオペレーティングシステムを示す文字列です。
    • この条件は、現在のOSがDragonFly BSDまたはFreeBSDである場合に真となります。
  3. bufSize = 1024: 上記の条件が真の場合、bufSizeは固定値の1024に設定されます。これは、これらのOSが_SC_GETPW_R_SIZE_MAXを提供しないため、既知の適切なデフォルトサイズを使用するためです。コメントにもあるように、これはLinuxが通常返すサイズと同じです。
  4. else { bufSize = C.sysconf(C._SC_GETPW_R_SIZE_MAX) }: 上記の条件が偽の場合(つまり、DragonFly BSDでもFreeBSDでもないUnix系OSの場合)、sysconf関数を呼び出して_SC_GETPW_R_SIZE_MAXの値を取得し、それをbufSizeに設定します。これにより、システムが推奨する最大バッファサイズが動的に取得されます。

このロジックにより、Goのos/userパッケージは、異なるUnix系OSのsysconf実装の差異を吸収し、ユーザー情報のルックアップを堅牢に行うことができます。

関連リンク

参考にした情報源リンク