[インデックス 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
chmodman 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/