[インデックス 18200] ファイルの概要
このコミットは、Go言語の標準ライブラリであるos
、os/exec
、os/user
パッケージに、Solarisオペレーティングシステム(GOOS=solaris)のサポートを追加するものです。これにより、GoプログラムがSolaris環境でより適切に動作し、Solaris固有のシステムコールやファイルシステム操作を扱えるようになります。
コミット
commit 6d0d08b8495efc033ede78370941e566e45eb7c8
Author: Aram Hăvărneanu <aram@mgk.ro>
Date: Fri Jan 10 02:49:37 2014 +1100
os, os/exec, os/user: add support for GOOS=solaris
R=golang-codereviews, dave, minux.ma, gobot, jsing
CC=golang-codereviews
https://golang.org/cl/36020043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6d0d08b8495efc033ede78370941e566e45eb7c8
元コミット内容
os, os/exec, os/user: add support for GOOS=solaris
変更の背景
Go言語はクロスプラットフォーム対応を重視しており、様々なオペレーティングシステム上で動作するように設計されています。このコミットが作成された2014年当時、Goは既にLinux、macOS (darwin)、FreeBSD、OpenBSD、NetBSDなどのUnix系OSをサポートしていましたが、Solarisに対する公式なサポートは限定的でした。
Solarisは、特にエンタープライズ環境で利用されることの多いUNIX系OSであり、Goプログラムをこれらの環境でネイティブに実行できるようにすることは、Go言語の適用範囲を広げ、より多くの開発者や企業がGoを採用する上で重要なステップでした。このコミットは、Goの標準ライブラリがSolarisのシステムコールやファイルシステム構造に適切に対応するための基盤を整備することを目的としています。
前提知識の解説
GOOSとビルドタグ
Go言語には、特定のオペレーティングシステム(OS)やアーキテクチャ(ARCH)向けにコードを条件付きでコンパイルするためのメカニズムがあります。これは「ビルドタグ(build tags)」と呼ばれ、ソースファイルの先頭に// +build <tag>
形式のコメントとして記述されます。
- GOOS: GoプログラムをビルドするターゲットOSを指定する環境変数です。例えば、
GOOS=linux
はLinux向け、GOOS=darwin
はmacOS向け、そしてこのコミットで追加されたGOOS=solaris
はSolaris向けにビルドすることを意味します。 - ビルドタグの役割: ビルドタグは、コンパイラが特定のOSやアーキテクチャに特化したコードを含めるか除外するかを決定するために使用されます。例えば、
// +build darwin dragonfly freebsd linux netbsd openbsd
というタグを持つファイルは、これらのOSのいずれかでビルドされる場合にのみコンパイル対象となります。このコミットでは、既存のUnix系OS向けのファイルにsolaris
タグを追加することで、Solaris環境でもこれらの共通コードが利用されるようにしています。
Unix系OSにおけるファイルシステムとシステムコール
Goのos
パッケージは、ファイルシステム操作やプロセス管理など、OSレベルの機能を提供します。Unix系OS(Linux, macOS, FreeBSD, Solarisなど)は、POSIX標準に準拠した共通のシステムコールインターフェースを多く持っていますが、OSごとに細かな違いや独自の機能も存在します。
stat
システムコール: ファイルやディレクトリのメタデータ(サイズ、パーミッション、更新日時、inode番号など)を取得するためのシステムコールです。OSによってstat
構造体の定義や、タイムスタンプの表現方法(Timespec
構造体など)が異なる場合があります。syscall
パッケージ: Goのsyscall
パッケージは、低レベルのOSプリミティブ(システムコール)への直接的なアクセスを提供します。これにより、GoはOS固有の機能を利用したり、パフォーマンスが重要な処理を行ったりすることができます。FileInfo
インターフェース:os
パッケージで定義されているインターフェースで、ファイルに関する抽象的な情報(名前、サイズ、モード、更新日時など)を提供します。異なるOSのstat
構造体からこのFileInfo
インターフェースへの変換ロジックが必要になります。
技術的詳細
このコミットの主要な技術的変更点は以下の通りです。
-
ビルドタグへの
solaris
の追加:src/pkg/os/
、src/pkg/os/exec/
、src/pkg/os/user/
内の多くの既存のUnix系OS向けファイル(例:dir_unix.go
,env_unix_test.go
,error_unix.go
,lp_unix.go
,exec_posix.go
,file_posix.go
,file_unix.go
,os_unix_test.go
,path_unix.go
,pipe_bsd.go
,signal_test.go
,signal_unix.go
,lookup_unix.go
)のビルドタグにsolaris
が追加されています。これにより、これらの共通のUnix系OS向け実装がSolarisでもコンパイル・利用されるようになります。pipe_bsd.go
は元々BSD系のOS(darwin, dragonfly, freebsd, netbsd, openbsd)向けでしたが、Solarisも同様のパイプ実装を利用できるため、ここにもsolaris
が追加されています。
-
Solaris固有のファイル情報取得 (
stat_solaris.go
) の追加:src/pkg/os/stat_solaris.go
が新規に作成されました。このファイルは、Solarisのsyscall.Stat_t
構造体からGoのos.FileInfo
インターフェースへの変換ロジックを提供します。fileInfoFromStat
関数は、syscall.Stat_t
からファイル名と組み合わせてos.FileInfo
を生成します。ここでは、Solarisのst.Mode
フィールドからファイルの種類(ブロックデバイス、キャラクタデバイス、ディレクトリ、FIFO、シンボリックリンク、ソケット、通常ファイル)や特殊なパーミッション(SetGID, SetUID, Stickyビット)を抽出し、GoのFileMode
にマッピングしています。sameFile
関数は、2つのファイルが同じデバイス上の同じinodeを参照しているかどうかを比較することで、それらが同じファイルであるかを判断します。これはUnix系OSでファイルを一意に識別する一般的な方法です。timespecToTime
関数は、Solarisのsyscall.Timespec
構造体(秒とナノ秒で時間を表現)をGoのtime.Time
型に変換します。これは、stat
情報からファイルの更新日時などを取得する際に必要となります。atime
関数はテスト用に、FileInfo
からアクセス時刻(atime)を取得するヘルパー関数です。
-
Solaris固有のシステム情報取得 (
sys_solaris.go
) の追加:src/pkg/os/sys_solaris.go
が新規に作成されました。このファイルは、Solaris固有のシステム情報取得関数を提供します。hostname()
関数は、Solarisのsyscall.Gethostname()
を呼び出すことで、システムのホスト名を取得します。これはos
パッケージのHostname()
関数が内部的に利用する可能性があります。
-
os/exec/exec_test.go
のSolaris固有のテスト調整:TestHelperProcess
関数内で、Solaris環境におけるファイルディスクリプタのテストに関するコメントが追加されています。これは、Solarisのlibc
が独自のファイルをオープンする挙動(Darwinと同様の問題)により、テストが失敗する可能性があることを示唆しています。これは、Goのプロセスが起動する際に、OSのCライブラリが内部的にファイルを開くことがあり、それがGoのファイルディスクリプタの管理と競合するケースがあるためです。
これらの変更により、GoコンパイラはGOOS=solaris
が設定された際に、Solaris固有のシステムコール定義やファイル情報構造体を利用して、GoプログラムをSolaris上で正しく動作させることができるようになります。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は、主に以下の2つの新規ファイルと、既存ファイルへのビルドタグの追加です。
-
src/pkg/os/stat_solaris.go
(新規追加):// Copyright 2009 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. package os import ( "syscall" "time" ) func sameFile(fs1, fs2 *fileStat) bool { stat1 := fs1.sys.(*syscall.Stat_t) stat2 := fs2.sys.(*syscall.Stat_t) return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino } func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo { fs := &fileStat{ name: basename(name), size: int64(st.Size), modTime: timespecToTime(st.Mtim), sys: st, } fs.mode = FileMode(st.Mode & 0777) switch st.Mode & syscall.S_IFMT { case syscall.S_IFBLK: fs.mode |= ModeDevice case syscall.S_IFCHR: fs.mode |= ModeDevice | ModeCharDevice case syscall.S_IFDIR: fs.mode |= ModeDir case syscall.S_IFIFO: fs.mode |= ModeNamedPipe case syscall.S_IFLNK: fs.mode |= ModeSymlink case syscall.S_IFREG: // nothing to do case syscall.S_IFSOCK: fs.mode |= ModeSocket } if st.Mode&syscall.S_ISGID != 0 { fs.mode |= ModeSetgid } if st.Mode&syscall.S_ISUID != 0 { fs.mode |= ModeSetuid } if st.Mode&syscall.S_ISVTX != 0 { fs.mode |= ModeSticky } return fs } func timespecToTime(ts syscall.Timespec) time.Time { return time.Unix(int64(ts.Sec), int64(ts.Nsec)) } // For testing. func atime(fi FileInfo) time.Time { return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim) }
-
src/pkg/os/sys_solaris.go
(新規追加):// Copyright 2013 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. package os import "syscall" func hostname() (name string, err error) { return syscall.Gethostname() }
-
既存ファイルへのビルドタグの追加: 例:
src/pkg/os/dir_unix.go
--- a/src/pkg/os/dir_unix.go +++ b/src/pkg/os/dir_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd linux netbsd openbsd +// +build darwin dragonfly freebsd linux netbsd openbsd solaris package os
同様の変更が、
src/pkg/os/env_unix_test.go
,src/pkg/os/error_unix.go
,src/pkg/os/exec/lp_unix.go
,src/pkg/os/exec/lp_unix_test.go
,src/pkg/os/exec_posix.go
,src/pkg/os/exec_unix.go
,src/pkg/os/file_posix.go
,src/pkg/os/file_unix.go
,src/pkg/os/os_unix_test.go
,src/pkg/os/path_unix.go
,src/pkg/os/pipe_bsd.go
,src/pkg/os/signal/signal_test.go
,src/pkg/os/signal/signal_unix.go
,src/pkg/os/user/lookup_unix.go
など、多数のファイルに対して行われています。
コアとなるコードの解説
src/pkg/os/stat_solaris.go
このファイルは、Solarisシステムにおけるファイルやディレクトリのメタデータ(統計情報)をGoのos
パッケージが扱える形式に変換するための中心的なロジックを含んでいます。
-
sameFile
関数:- Goの
os
パッケージの内部で、2つのFileInfo
が同じ物理ファイルを参照しているかを比較するために使用されます。 - Solarisでは、
syscall.Stat_t
構造体のDev
(デバイスID)とIno
(inode番号)の組み合わせがファイルを一意に識別します。この関数は、これら2つのフィールドが一致するかどうかを確認することで、同じファイルであるかを判断します。
- Goの
-
fileInfoFromStat
関数:- Solarisの
stat
システムコールから返されるsyscall.Stat_t
構造体とファイル名を受け取り、Goのos.FileInfo
インターフェースを実装するfileStat
構造体のインスタンスを生成します。 name
、size
、modTime
(最終更新日時)などの基本的な情報を設定します。modTime
の変換には後述のtimespecToTime
が使われます。st.Mode
フィールドは、ファイルのパーミッションと種類(ファイルタイプ)をビットマスクで表現しています。st.Mode & 0777
: ファイルのパーミッションビット(rwx)を抽出します。st.Mode & syscall.S_IFMT
: ファイルタイプを示すビットを抽出し、switch
文でGoのos.FileMode
の対応するフラグ(ModeDevice
,ModeCharDevice
,ModeDir
,ModeNamedPipe
,ModeSymlink
,ModeSocket
)を設定します。S_IFREG
(通常ファイル)の場合は特別なフラグは不要です。syscall.S_ISGID
,syscall.S_ISUID
,syscall.S_ISVTX
: それぞれSetGID、SetUID、Stickyビットといった特殊なパーミッションフラグをチェックし、対応するGoのFileMode
フラグ(ModeSetgid
,ModeSetuid
,ModeSticky
)を設定します。
- Solarisの
-
timespecToTime
関数:- Solarisの
syscall.Timespec
構造体は、秒(Sec
)とナノ秒(Nsec
)で時間を表現します。 - この関数は、これらの値を使用してGoの
time.Unix
関数を呼び出し、Unixエポックからの秒数とナノ秒数に基づいてtime.Time
オブジェクトを生成します。これにより、SolarisのタイムスタンプがGoの標準的な時間表現に変換されます。
- Solarisの
src/pkg/os/sys_solaris.go
このファイルは、Solarisシステム固有の低レベルなシステム情報取得機能を提供します。
hostname()
関数:- Goの
os.Hostname()
関数が内部的に呼び出す可能性のある、システムホスト名を取得するためのSolaris固有の実装です。 - Solarisの
syscall.Gethostname()
システムコールを直接呼び出すことで、ホスト名を取得します。
- Goの
ビルドタグの追加
既存のUnix系OS向けファイルに// +build solaris
タグを追加することは、Goのクロスコンパイル戦略において非常に重要です。これにより、GoコンパイラはGOOS=solaris
が設定された際に、これらの共通のUnix系OS向けコードをSolaris環境でも利用できると認識します。これは、多くのUnix系OSがPOSIX標準に準拠しており、ファイル操作やプロセス管理の基本的なインターフェースが共通しているため可能です。Solaris固有の挙動やシステムコールが必要な場合にのみ、stat_solaris.go
やsys_solaris.go
のような専用ファイルが用意されます。
関連リンク
- Go言語のビルドタグに関する公式ドキュメント: https://pkg.go.dev/cmd/go#hdr-Build_constraints
- Go言語の
os
パッケージ: https://pkg.go.dev/os - Go言語の
syscall
パッケージ: https://pkg.go.dev/syscall - Solarisオペレーティングシステム (Wikipedia): https://ja.wikipedia.org/wiki/Solaris
参考にした情報源リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- Gerrit Code Review (Goプロジェクト): https://go-review.googlesource.com/
- Go issue 3955:
os/exec
:ExtraFiles
on Darwin can fail iflibc
opens files: https://golang.org/issue/3955 (コミットメッセージ内の参照) - Go issue 2603:
os/exec
:ExtraFiles
on Darwin can fail iflibc
opens files: https://golang.org/issue/2603 (コミットメッセージ内の参照) - POSIX
stat
関数: https://pubs.opengroup.org/onlinepubs/9699919799/functions/stat.html Timespec
構造体 (Wikipedia): https://en.wikipedia.org/wiki/Timespec