[インデックス 12113] ファイルの概要
このコミットは、Go言語のツールチェインにおける cmd/dist
コマンドの修正に関するものです。具体的には、pprof
ツールがインストールされる際に、Unix系システム上で実行権限が正しく設定されるように変更が加えられています。これにより、pprof
がツールディレクトリにインストールされた後、ユーザーが直接実行できるようになります。
コミット
commit d36426995a3919cb8d6ebd8fac502e764f6e28ed
Author: Bobby Powers <bobbypowers@gmail.com>
Date: Tue Feb 21 16:49:30 2012 -0500
cmd/dist: fix pprof permissions
When installing pprof into the tools directory, it needs to
have execute permissions on unix-like systems.
Fixes issues 3077.
R=golang-dev, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/5675095
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d36426995a3919cb8d6ebd8fac502e764f6e28ed
元コミット内容
cmd/dist: fix pprof permissions
pprof
をツールディレクトリにインストールする際、Unix系システムでは実行権限が必要となる。
Issue 3077 を修正。
変更の背景
この変更は、Go言語のビルドシステムの一部である cmd/dist
が pprof
ツールをインストールする際に発生していた問題に対処するものです。具体的には、Unix系オペレーティングシステム(Linux, macOSなど)において、ファイルが実行可能であるためには、そのファイルに実行権限(executable permission)が付与されている必要があります。
以前の cmd/dist
の実装では、pprof
がツールディレクトリにコピーされる際に、この実行権限が適切に設定されていませんでした。その結果、ユーザーが pprof
を実行しようとすると、「Permission denied」(アクセス拒否)エラーが発生し、ツールが利用できないという問題(Issue 3077)が報告されていました。
このコミットは、pprof
のインストールプロセスにおいて、ファイルコピー時に明示的に実行権限を付与することで、この問題を解決することを目的としています。これにより、ビルド後に pprof
がすぐに利用できるようになります。
前提知識の解説
1. pprof
pprof
は、Go言語のプログラムのプロファイリングデータを視覚化するためのツールです。CPU使用率、メモリ割り当て、ゴルーチン(goroutine)のスタックトレースなど、様々なパフォーマンスメトリクスを収集し、グラフやテキスト形式で表示することができます。これにより、開発者はアプリケーションのパフォーマンスボトルネックを特定し、最適化を行うことができます。pprof
はGoの標準ツールの一部として提供されており、Goのビルドシステムによってインストールされます。
2. ファイルの実行権限 (Executable Permissions)
Unix系オペレーティングシステムでは、ファイルには所有者、グループ、その他のユーザーに対して読み取り(read)、書き込み(write)、実行(execute)の3種類の権限が設定されます。実行権限は、そのファイルがプログラムとして実行可能であるかどうかを決定します。例えば、シェルスクリプトやコンパイルされたバイナリファイルを実行するには、実行権限が必要です。
権限は通常、数値(例: 755
)または記号(例: rwxr-xr-x
)で表現されます。
r
(read): 読み取り権限w
(write): 書き込み権限x
(execute): 実行権限
0755
という数値は、以下を意味します。
- 最初の
0
: 特殊権限(ここでは無視) 7
(111): 所有者に読み取り、書き込み、実行権限5
(101): グループに読み取り、実行権限5
(101): その他のユーザーに読み取り、実行権限
3. cmd/dist
cmd/dist
は、Go言語のソースコードからGoツールチェイン全体をビルドするための内部コマンドです。Goのコンパイラ、リンカ、標準ライブラリ、各種ツール(go fmt
, go vet
, pprof
など)のビルドとインストールをオーケストレーションします。これはGoの自己ホスト型(self-hosting)ビルドプロセスの中核をなす部分であり、GoのソースコードからGoのバイナリを生成するために使用されます。
4. Goのビルドプロセス
Goのビルドプロセスは、make.bash
(Unix系) や make.bat
(Windows) といったスクリプトによって開始されます。これらのスクリプトは内部的に cmd/dist
を呼び出し、Goのソースコードをコンパイルし、必要なバイナリやライブラリを適切なディレクトリ(通常は $GOROOT/bin
や $GOROOT/pkg
など)に配置します。このプロセス中に、pprof
のようなツールもビルドされ、インストールされます。
技術的詳細
このコミットの技術的な核心は、ファイル書き込み関数 writefile
に新しい引数 exec
を追加し、ファイルコピー関数 copy
を介して、特定のファイル(特に pprof
のような実行可能ファイル)が書き込まれる際に実行権限を付与できるようにした点です。
writefile
関数の変更
元の writefile
関数は、単にバッファの内容をファイルに書き込むだけでした。この変更により、writefile
は3番目の引数 int exec
を受け取るようになりました。
exec
が非ゼロの場合、ファイルが書き込まれた後にchmod(fd, 0755)
が呼び出され、そのファイルに実行権限が付与されます。exec
がゼロの場合、権限は変更されません。
これは、Unix系システム (src/cmd/dist/unix.c
) の実装に chmod
システムコールを追加することで実現されています。Windowsシステム (src/cmd/dist/windows.c
) の writefile
関数にも exec
引数が追加されていますが、WindowsのファイルシステムはUnixのような実行権限の概念を持たないため、USED(exec)
マクロを使って引数が未使用であることを示し、実際の権限変更は行われません。
copy
関数の変更
copy
関数は、ソースファイルの内容を読み取り、デスティネーションファイルに書き込む役割を担っています。この変更により、copy
関数も3番目の引数 int exec
を受け取るようになりました。そして、この exec
引数をそのまま内部で呼び出す writefile
関数に渡すように修正されました。
install
関数の変更
install
関数は、Goツールチェインの様々なコンポーネントをインストールする際に copy
関数を呼び出します。このコミットでは、install
関数内で pprof
をツールディレクトリにコピーする箇所 (if(hasprefix(dir, "misc/"))
) で、copy
関数を呼び出す際に exec
引数に 1
を渡すように変更されました。これにより、pprof
がコピーされる際に実行権限が付与されるようになります。
他のファイル(例えば、pkg/runtime
関連のヘッダーファイルなど)をコピーする際には、exec
引数に 0
が渡されており、これらのファイルには実行権限が付与されないようになっています。これは、ヘッダーファイルが実行可能である必要がないため、適切な権限管理が行われていることを示します。
この修正により、cmd/dist
は pprof
のような実行可能ファイルを正しくインストールし、ユーザーが追加の手順なしにそれらを実行できるようになります。
コアとなるコードの変更箇所
src/cmd/dist/a.h
(ヘッダーファイルの変更)
--- a/src/cmd/dist/a.h
+++ b/src/cmd/dist/a.h
@@ -120,7 +120,7 @@ void runv(Buf *b, char *dir, int mode, Vec *argv);
void bgrunv(char *dir, int mode, Vec *argv);
void bgwait(void);
bool streq(char*, char*);
-void writefile(Buf*, char*);
+void writefile(Buf*, char*, int);
void xatexit(void (*f)(void));
void xexit(int);
void xfree(void*);
src/cmd/dist/build.c
(主要な変更箇所)
--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -27,7 +27,7 @@ char *slash; // / for unix, \ for windows
bool rebuildall = 0;
static bool shouldbuild(char*, char*);
-static void copy(char*, char*);
+static void copy(char*, char*, int);
static char *findgoversion(void);
// The known architecture letters.
@@ -567,7 +567,7 @@ install(char *dir)\
// For misc/prof, copy into the tool directory and we're done.
if(hasprefix(dir, "misc/")) {
copy(bpathf(&b, "%s/%s", tooldir, name),
-\t\t\tbpathf(&b1, "%s/misc/%s", goroot, name));
+\t\t\tbpathf(&b1, "%s/misc/%s", goroot, name), 1);\
goto out;
}
@@ -1051,7 +1051,7 @@ out:
// copy copies the file src to dst, via memory (so only good for small files).
static void
-copy(char *dst, char *src)\
+copy(char *dst, char *src, int exec)\
{\
Buf b;\
\
@@ -1060,7 +1060,7 @@ copy(char *dst, char *src)\
binit(&b);\
readfile(&b, src);\
-\twritefile(&b, dst);\
+\twritefile(&b, dst, exec);\
bfree(&b);\
}
src/cmd/dist/unix.c
(Unix系システムでの writefile
の実装)
--- a/src/cmd/dist/unix.c
+++ b/src/cmd/dist/unix.c
@@ -351,9 +351,10 @@ readfile(Buf *b, char *file)\
close(fd);\
}\
-// writefile writes b to the named file, creating it if needed.\
+// writefile writes b to the named file, creating it if needed. if\
+// exec is non-zero, marks the file as executable.\
void\
-writefile(Buf *b, char *file)\
+writefile(Buf *b, char *file, int exec)\
{\
int fd;\
\
@@ -362,9 +363,11 @@ writefile(Buf *b, char *file)\
\tfatal("create %s: %s", file, strerror(errno));\
if(write(fd, b->p, b->len) != b->len)\
\tfatal("short write: %s", strerror(errno));\
+\tif(exec)\
+\t\tfchmod(fd, 0755);\
close(fd);\
}\
-\t\
+\
// xmkdir creates the directory p.\
void\
xmkdir(char *p)\
src/cmd/dist/windows.c
(Windows系システムでの writefile
の実装)
--- a/src/cmd/dist/windows.c
+++ b/src/cmd/dist/windows.c
@@ -539,12 +539,14 @@ readfile(Buf *b, char *file)\
}\
void\
-writefile(Buf *b, char *file)\
+writefile(Buf *b, char *file, int exec)\
{\
HANDLE h;\
Rune *r;\
DWORD n;\
\
+\tUSED(exec);\
+\
if(vflag > 2)\
\txprintf("write %s\\n", file);\
torune(&r, file);\
コアとなるコードの解説
このコミットの主要な変更は、ファイル書き込み関数 writefile
とファイルコピー関数 copy
に exec
という新しい整数型引数を導入したことです。
-
writefile
関数のシグネチャ変更:- 元の
void writefile(Buf *b, char *file)
からvoid writefile(Buf *b, char *file, int exec)
へと変更されました。 - この
exec
引数は、書き込むファイルに実行権限を付与するかどうかを制御します。 src/cmd/dist/unix.c
の実装では、exec
が非ゼロの場合、chmod(fd, 0755)
が呼び出されます。chmod
はUnix系システムでファイルのパーミッションを変更するためのシステムコールです。0755
は、所有者に読み書き実行、グループとその他に読み取り実行の権限を与えます。src/cmd/dist/windows.c
の実装では、exec
引数はUSED(exec);
とマークされており、WindowsのファイルシステムではUnixのような実行権限の概念がないため、実際には何も行われません。これはクロスプラットフォーム対応のための適切な処理です。
- 元の
-
copy
関数のシグネチャ変更と伝播:- 元の
static void copy(char *dst, char *src)
からstatic void copy(char *dst, char *src, int exec)
へと変更されました。 copy
関数は、ソースファイルの内容を読み込み、それをwritefile
を使ってデスティネーションファイルに書き込みます。この変更により、copy
関数が受け取ったexec
引数をそのままwritefile
に渡すようになりました。これにより、copy
を呼び出す側が、コピー先のファイルに実行権限を付与するかどうかを制御できるようになります。
- 元の
-
install
関数でのpprof
の権限設定:src/cmd/dist/build.c
内のinstall
関数は、Goツールチェインの様々なコンポーネントをインストールする役割を担っています。- 特に
misc/
ディレクトリにあるツール(この場合はpprof
)をコピーする際に、copy
関数を呼び出す箇所がcopy(..., 1)
と変更されました。 1
を渡すことで、pprof
がツールディレクトリにコピーされる際に、writefile
関数を通じて実行権限0755
が付与されるようになります。- 他のファイル(例えば、
pkg/runtime
関連のヘッダーファイルなど)をコピーする際には、copy(..., 0)
と0
が渡されており、これらのファイルには実行権限が付与されないようになっています。これは、ヘッダーファイルが実行可能である必要がないため、適切な権限管理が行われていることを示します。
これらの変更により、Goのビルドプロセスにおいて pprof
のような実行可能ファイルが正しく実行権限を持ってインストールされるようになり、ユーザーがビルド後にすぐにこれらのツールを利用できるようになりました。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/d36426995a3919cb8d6ebd8fac502e764f6e28ed
- Go Issue 3077: https://golang.org/issue/3077 (このコミットによって修正された問題)
- Go CL 5675095: https://golang.org/cl/5675095 (このコミットに対応するGoのコードレビュー)
参考にした情報源リンク
- Go pprof documentation: https://pkg.go.dev/runtime/pprof
- Unix file permissions: https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%91%E3%83%BC%E3%83%9F%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3
chmod
man page (Unix/Linux):man chmod
(ローカル環境で実行)- Go source code structure (general understanding of
cmd/dist
): https://go.dev/doc/contribute#source_code - Go issue tracker: https://go.dev/issue
- Go code review system (Gerrit): https://go-review.googlesource.com/