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

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

コミット

commit 7fb121aa479c96e32c1178d4c65e865ae5cb5144
Author: Rob Pike <r@golang.org>
Date:   Mon Aug 19 08:29:43 2013 +1000

    cmd/dist: more informative error for mkdtemp failing
    The Darwin builders are all failing here but strerror doesn't provide context.
    
    R=golang-dev, bradfitz, adg
    CC=golang-dev
    https://golang.org/cl/13095043

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

https://github.com/golang/go/commit/7fb121aa479c96e32c1178d4c65e865ae5cb5144

元コミット内容

cmd/dist: mkdtempの失敗時により詳細なエラーメッセージを出力 Darwinのビルダがここで全て失敗しているが、strerrorはコンテキストを提供しない。

変更の背景

このコミットは、Go言語のビルドシステムの一部であるcmd/distツールにおいて、一時ディレクトリの作成に失敗した場合のエラーメッセージを改善することを目的としています。コミットメッセージによると、特にmacOS (Darwin) 環境のビルドマシンでmkdtemp関数が失敗する問題が発生しており、その際に出力されるエラーメッセージが不十分であったことが示唆されています。

従来のfatal("mkdtemp: %s", strerror(errno))というエラー出力では、mkdtempが失敗した際に、その原因を示すシステムエラーメッセージ(strerror(errno))のみが表示されていました。しかし、どのパスに対してmkdtempが呼び出されたのかという重要なコンテキスト情報が欠落していたため、デバッグが困難でした。

開発者は、mkdtempが失敗した具体的なパスを知ることで、問題の特定と解決をより迅速に行えるようになります。例えば、パスの権限問題、ディスク容量不足、無効なパス形式など、様々な原因が考えられますが、パス情報がなければそれらを切り分けることができません。この変更は、ビルドの安定性とデバッグの効率性を向上させるためのものです。

前提知識の解説

1. cmd/dist

cmd/distは、Go言語のソースコードからGoツールチェイン自体をビルドするために使用される内部ツールです。Goのビルドプロセスは複雑であり、クロスコンパイルや様々な環境への対応を考慮して設計されています。cmd/distは、Goのソースコードをコンパイルし、標準ライブラリを構築し、最終的なGoバイナリ(goコマンドなど)を生成する一連のタスクをオーケストレーションします。これはGoのブートストラッププロセスにおいて非常に重要な役割を担っています。

2. mkdtemp関数

mkdtempは、Unix系システムで一時的なディレクトリを安全に作成するためのC標準ライブラリ関数です。この関数は、指定されたテンプレート文字列(例: /tmp/myprog-XXXXXX)に基づいて一意なディレクトリ名を作成し、そのディレクトリを作成します。XXXXXXの部分は、関数が呼び出されるたびに異なるランダムな文字列に置き換えられ、名前の衝突を防ぎます。成功すると、作成されたディレクトリのパスへのポインタを返します。失敗した場合はNULLを返し、エラーの原因はグローバル変数errnoに設定されます。

3. errnostrerror

  • errno: errnoは、C言語の標準ライブラリ関数がシステムコールやライブラリ関数の実行中に発生したエラーを示すために使用するグローバル変数(またはマクロ)です。通常、#include <errno.h>で利用できます。関数がエラーを返した場合(例: mkdtempNULLを返した場合)、errnoには特定のエラーコードが設定されます。このエラーコードは、例えばEACCES(パーミッション拒否)、ENOSPC(ディスク容量不足)、EINVAL(無効な引数)など、システムが定義する様々なエラー条件に対応します。
  • strerror: strerror関数は、errnoに設定された数値のエラーコードを、人間が読めるエラーメッセージ文字列に変換するために使用されます。例えば、errnoEACCESの場合、strerror(errno)は「Permission denied」のような文字列を返します。これにより、プログラムはユーザーやログに対して、より分かりやすいエラー情報を提供できます。

このコミットの文脈では、strerror(errno)だけでは、どのパスに対してエラーが発生したのかという情報が不足していたため、デバッグが困難だったという問題が指摘されています。

技術的詳細

このコミットの技術的な変更は非常にシンプルですが、デバッグの観点からは大きな改善をもたらします。

変更前は、mkdtempの呼び出しとエラーハンドリングが以下のようになっていました。

if(mkdtemp(bstr(&b)) == nil)
    fatal("mkdtemp: %s", strerror(errno));

ここで、bstr(&b)mkdtempに渡される一時ディレクトリのパス文字列を生成する関数呼び出しです。mkdtempnil(C言語のNULLに相当)を返した場合、fatal関数が呼び出され、エラーメッセージが出力されます。このメッセージは「mkdtemp: 」という固定文字列に続いて、strerror(errno)が返すシステムエラーメッセージが表示されます。

変更後は、mkdtempに渡されるパス文字列を一時変数pに格納し、そのpをエラーメッセージに含めるように修正されました。

p = bstr(&b);
if(mkdtemp(p) == nil)
    fatal("mkdtemp(%s): %s", p, strerror(errno));

この変更により、fatal関数に渡されるフォーマット文字列が"mkdtemp(%s): %s"となり、最初の%sにはmkdtempが試行した具体的なパスpが、2番目の%sにはstrerror(errno)によるシステムエラーメッセージが挿入されるようになりました。

例えば、変更前は「mkdtemp: Permission denied」のようなメッセージだったものが、変更後は「mkdtemp(/var/tmp/go-cbuild-XXXXXX): Permission denied」のようになることで、どのパスの作成に失敗したのかが一目瞭然になります。これは、特にビルド環境のセットアップや権限問題のトラブルシューティングにおいて、非常に価値のある情報となります。

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

変更はsrc/cmd/dist/unix.cファイル内のxworkdir関数にあります。

--- a/src/cmd/dist/unix.c
+++ b/src/cmd/dist/unix.c
@@ -467,8 +467,9 @@ xworkdir(void)
  	if(b.len == 0)
  	\tbwritestr(&b, "/var/tmp");
  	\tbwritestr(&b, "/go-cbuild-XXXXXX");
-\tif(mkdtemp(bstr(&b)) == nil)
-\t\tfatal("mkdtemp: %s", strerror(errno));
+\tp = bstr(&b);\n+\tif(mkdtemp(p) == nil)\n+\t\tfatal("mkdtemp(%s): %s", p, strerror(errno));
  \tp = btake(&b);
  
  \tbfree(&b);

コアとなるコードの解説

xworkdir関数は、Goのビルドプロセス中に使用される一時作業ディレクトリを作成する役割を担っています。

  1. b.len == 0の条件は、一時ディレクトリのベースパスがまだ設定されていない場合に、デフォルトとして/var/tmpを使用することを示しています。
  2. bwritestr(&b, "/go-cbuild-XXXXXX");は、一時ディレクトリ名のテンプレートをバッファbに追加しています。XXXXXXmkdtempによって一意な文字列に置き換えられます。
  3. 変更点:
    • 変更前は、mkdtemp(bstr(&b))の戻り値が直接nilと比較され、エラー時にはfatal("mkdtemp: %s", strerror(errno))が呼び出されていました。
    • 変更後は、まずp = bstr(&b);によって、mkdtempに渡される完全なパス文字列が変数pに格納されます。
    • 次に、mkdtemp(p)が呼び出され、その結果がnilと比較されます。
    • エラーが発生した場合、fatal("mkdtemp(%s): %s", p, strerror(errno));が呼び出されます。これにより、エラーメッセージにmkdtempが試行した具体的なパスpが含まれるようになり、デバッグ情報が大幅に強化されます。
  4. p = btake(&b);は、作成された一時ディレクトリのパスをバッファbから取得し、その所有権を移譲しています。
  5. bfree(&b);は、バッファbを解放しています。

この変更は、mkdtempの呼び出し自体を変更するものではなく、そのエラーハンドリングとメッセージングを改善するものです。これにより、ビルドシステムが一時ディレクトリの作成に失敗した際に、開発者がより迅速に問題の原因を特定できるようになります。

関連リンク

  • Go言語のcmd/distに関する公式ドキュメントや詳細な説明は、Goのソースコードリポジトリ内や、Goのビルドプロセスに関する記事で確認できます。
  • mkdtemp関数のmanページ (例: man 3 mkdtemp)
  • strerror関数のmanページ (例: man 3 strerror)
  • Go言語のブートストラッププロセスに関する記事やGoの内部構造に関するブログ記事。

参考にした情報源リンク

  • Go言語のGitHubリポジトリ: https://github.com/golang/go
  • Goのコードレビューシステム (Gerrit): https://go-review.googlesource.com/ (コミットメッセージに記載されているhttps://golang.org/cl/13095043はこのGerritのリンクです)
  • Unix/Linuxのmanページ (mkdtemp, strerror, errno)
  • C言語の標準ライブラリに関する一般的な知識。
  • Go言語のビルドシステムに関する一般的な知識。```

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

コミット

commit 7fb121aa479c96e32c1178d4c65e865ae5cb5144
Author: Rob Pike <r@golang.org>
Date:   Mon Aug 19 08:29:43 2013 +1000

    cmd/dist: more informative error for mkdtemp failing
    The Darwin builders are all failing here but strerror doesn't provide context.
    
    R=golang-dev, bradfitz, adg
    CC=golang-dev
    https://golang.org/cl/13095043

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

https://github.com/golang/go/commit/7fb121aa479c96e32c1178d4c65e865ae5cb5144

元コミット内容

cmd/dist: mkdtempの失敗時により詳細なエラーメッセージを出力 Darwinのビルダがここで全て失敗しているが、strerrorはコンテキストを提供しない。

変更の背景

このコミットは、Go言語のビルドシステムの一部であるcmd/distツールにおいて、一時ディレクトリの作成に失敗した場合のエラーメッセージを改善することを目的としています。コミットメッセージによると、特にmacOS (Darwin) 環境のビルドマシンでmkdtemp関数が失敗する問題が発生しており、その際に出力されるエラーメッセージが不十分であったことが示唆されています。

従来のfatal("mkdtemp: %s", strerror(errno))というエラー出力では、mkdtempが失敗した際に、その原因を示すシステムエラーメッセージ(strerror(errno))のみが表示されていました。しかし、どのパスに対してmkdtempが呼び出されたのかという重要なコンテキスト情報が欠落していたため、デバッグが困難でした。

開発者は、mkdtempが失敗した具体的なパスを知ることで、問題の特定と解決をより迅速に行えるようになります。例えば、パスの権限問題、ディスク容量不足、無効なパス形式など、様々な原因が考えられますが、パス情報がなければそれらを切り分けることができません。この変更は、ビルドの安定性とデバッグの効率性を向上させるためのものです。

前提知識の解説

1. cmd/dist

cmd/distは、Go言語のソースコードからGoツールチェイン自体をビルドするために使用される内部ツールです。Goのビルドプロセスは複雑であり、クロスコンパイルや様々な環境への対応を考慮して設計されています。cmd/distは、Goのソースコードをコンパイルし、標準ライブラリを構築し、最終的なGoバイナリ(goコマンドなど)を生成する一連のタスクをオーケストレーションします。これはGoのブートストラッププロセスにおいて非常に重要な役割を担っています。

2. mkdtemp関数

mkdtempは、Unix系システムで一時的なディレクトリを安全に作成するためのC標準ライブラリ関数です。この関数は、指定されたテンプレート文字列(例: /tmp/myprog-XXXXXX)に基づいて一意なディレクトリ名を作成し、そのディレクトリを作成します。XXXXXXの部分は、関数が呼び出されるたびに異なるランダムな文字列に置き換えられ、名前の衝突を防ぎます。成功すると、作成されたディレクトリのパスへのポインタを返します。失敗した場合はNULLを返し、エラーの原因はグローバル変数errnoに設定されます。

3. errnostrerror

  • errno: errnoは、C言語の標準ライブラリ関数がシステムコールやライブラリ関数の実行中に発生したエラーを示すために使用するグローバル変数(またはマクロ)です。通常、#include <errno.h>で利用できます。関数がエラーを返した場合(例: mkdtempNULLを返した場合)、errnoには特定のエラーコードが設定されます。このエラーコードは、例えばEACCES(パーミッション拒否)、ENOSPC(ディスク容量不足)、EINVAL(無効な引数)など、システムが定義する様々なエラー条件に対応します。
  • strerror: strerror関数は、errnoに設定された数値のエラーコードを、人間が読めるエラーメッセージ文字列に変換するために使用されます。例えば、errnoEACCESの場合、strerror(errno)は「Permission denied」のような文字列を返します。これにより、プログラムはユーザーやログに対して、より分かりやすいエラー情報を提供できます。

このコミットの文脈では、strerror(errno)だけでは、どのパスに対してエラーが発生したのかという情報が不足していたため、デバッグが困難だったという問題が指摘されています。

技術的詳細

このコミットの技術的な変更は非常にシンプルですが、デバッグの観点からは大きな改善をもたらします。

変更前は、mkdtempの呼び出しとエラーハンドリングが以下のようになっていました。

if(mkdtemp(bstr(&b)) == nil)
    fatal("mkdtemp: %s", strerror(errno));

ここで、bstr(&b)mkdtempに渡される一時ディレクトリのパス文字列を生成する関数呼び出しです。mkdtempnil(C言語のNULLに相当)を返した場合、fatal関数が呼び出され、エラーメッセージが出力されます。このメッセージは「mkdtemp: 」という固定文字列に続いて、strerror(errno)が返すシステムエラーメッセージが表示されます。

変更後は、mkdtempに渡されるパス文字列を一時変数pに格納し、そのpをエラーメッセージに含めるように修正されました。

p = bstr(&b);
if(mkdtemp(p) == nil)
    fatal("mkdtemp(%s): %s", p, strerror(errno));

この変更により、fatal関数に渡されるフォーマット文字列が"mkdtemp(%s): %s"となり、最初の%sにはmkdtempが試行した具体的なパスpが、2番目の%sにはstrerror(errno)によるシステムエラーメッセージが挿入されるようになりました。

例えば、変更前は「mkdtemp: Permission denied」のようなメッセージだったものが、変更後は「mkdtemp(/var/tmp/go-cbuild-XXXXXX): Permission denied」のようになることで、どのパスの作成に失敗したのかが一目瞭然になります。これは、特にビルド環境のセットアップや権限問題のトラブルシューティングにおいて、非常に価値のある情報となります。

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

変更はsrc/cmd/dist/unix.cファイル内のxworkdir関数にあります。

--- a/src/cmd/dist/unix.c
+++ b/src/cmd/dist/unix.c
@@ -467,8 +467,9 @@ xworkdir(void)
  	if(b.len == 0)
  	\tbwritestr(&b, "/var/tmp");
  	\tbwritestr(&b, "/go-cbuild-XXXXXX");
-\tif(mkdtemp(bstr(&b)) == nil)
-\t\tfatal("mkdtemp: %s", strerror(errno));
+\tp = bstr(&b);\n+\tif(mkdtemp(p) == nil)\n+\t\tfatal("mkdtemp(%s): %s", p, strerror(errno));
  \tp = btake(&b);
  
  \tbfree(&b);

コアとなるコードの解説

xworkdir関数は、Goのビルドプロセス中に使用される一時作業ディレクトリを作成する役割を担っています。

  1. b.len == 0の条件は、一時ディレクトリのベースパスがまだ設定されていない場合に、デフォルトとして/var/tmpを使用することを示しています。
  2. bwritestr(&b, "/go-cbuild-XXXXXX");は、一時ディレクトリ名のテンプレートをバッファbに追加しています。XXXXXXmkdtempによって一意な文字列に置き換えられます。
  3. 変更点:
    • 変更前は、mkdtemp(bstr(&b))の戻り値が直接nilと比較され、エラー時にはfatal("mkdtemp: %s", strerror(errno))が呼び出されていました。
    • 変更後は、まずp = bstr(&b);によって、mkdtempに渡される完全なパス文字列が変数pに格納されます。
    • 次に、mkdtemp(p)が呼び出され、その結果がnilと比較されます。
    • エラーが発生した場合、fatal("mkdtemp(%s): %s", p, strerror(errno));が呼び出されます。これにより、エラーメッセージにmkdtempが試行した具体的なパスpが含まれるようになり、デバッグ情報が大幅に強化されます。
  4. p = btake(&b);は、作成された一時ディレクトリのパスをバッファbから取得し、その所有権を移譲しています。
  5. bfree(&b);は、バッファbを解放しています。

この変更は、mkdtempの呼び出し自体を変更するものではなく、そのエラーハンドリングとメッセージングを改善するものです。これにより、ビルドシステムが一時ディレクトリの作成に失敗した際に、開発者がより迅速に問題の原因を特定できるようになります。

関連リンク

  • Go言語のcmd/distに関する公式ドキュメントや詳細な説明は、Goのソースコードリポジトリ内や、Goのビルドプロセスに関する記事で確認できます。
  • mkdtemp関数のmanページ (例: man 3 mkdtemp)
  • strerror関数のmanページ (例: man 3 strerror)
  • Go言語のブートストラッププロセスに関する記事やGoの内部構造に関するブログ記事。

参考にした情報源リンク

  • Go言語のGitHubリポジトリ: https://github.com/golang/go
  • Goのコードレビューシステム (Gerrit): https://go-review.googlesource.com/ (コミットメッセージに記載されているhttps://golang.org/cl/13095043はこのGerritのリンクです)
  • Unix/Linuxのmanページ (mkdtemp, strerror, errno)
  • C言語の標準ライブラリに関する一般的な知識。
  • Go言語のビルドシステムに関する一般的な知識。