🐴

Pipex の実装とエラー処理

2024/03/20に公開

なんでPipex?

同期にオススメされました。
選択課題について、どちらの課題をやるか迷うかもしれません。
難易度では圧倒的にminitalkが簡単だと言われており、実際にminitalkを選択している方のほうが多い印象です。
pipexではminishellの実行部分についての必要な知識がつけられるということで、今回はPipexをやってみることにしました。

実装流れ

Mandatory部分のみの実装をした。
Mandatory部分のみの実装はお勧めできません。
理由は、初めからボーナス要件を満たすように実装をすれば、Mandatory要件は満たされるため実装を分ける必要がないからです。
heardocも複数コマンドの対応もminishellで必要な要件となるようで、ボーナスまでやった方が今後のためにはいいみたいです。

  1. コマンドライン引数の数をチェックします
  2. ファイルをオープンします
  3. パイプを作成します
  4. 最初の子プロセスを作成します(fork関数を使用)
  5. 最初のコマンド実行用の関数を呼び出して最初のコマンドを実行します
  6. 2番目の子プロセスを作成します(fork関数を使用)
  7. 2番目のコマンド実行用の関数を呼び出して最初のコマンドを実行します
  8. パイプをクローズします(close_pipes関数を使用)
  9. 子プロセスの終了を待ちます(waitpid関数を使用)
  10. リソースを解放します

このプログラムは、シェルにおけるpipeコマンドと同様の機能を実装しています。
2つのコマンドを実行し、最初のコマンドの出力を2番目のコマンドの入力としてパイプでつなぎ、最終的な出力を出力ファイルに書き込みます。

エラー処理は、ファイルの操作、パイプの作成、子プロセスの作成などの各段階で行われ、エラーが発生した場合は適切なエラーメッセージを表示してプログラムを終了します。

エラー処理

基本的に、シェルと同じ動作を再現することを目標とします。
以下はレビューで指摘されたところや今までのフィードバックを見て修正した点についてのメモです。

(1)infile、outfileそれぞれread権限、write権限がない場合

本家では、「permission denied」が2回それぞれ出力されます。

bashCopy code
touch infile outfile
chmod 000 infile
chmod 000 outfile
./pipex infile "ls -l" "wc -l" outfile

このコマンドは、infileoutfile を作成し、それぞれに対して全ての権限を削除します。その後、./pipex コマンドを実行して結果を観察します。

◆改善

infile とoutfileの戻り値を判定した後にexitする関数を作成

(2)infileにread権限なし、outfileが存在しない場合

本家はoutfileを作成されるが、「permission denied」が出力されます。

bashCopy code
touch infile
chmod 000 infile
rm -f outfile # outfileが存在しないことを保証
./pipex infile "ls -l" "wc -l" outfile

このコマンドは、infile の読み取り権限を削除し、outfile が存在しない状態を作り出した後に ./pipex コマンドを実行します。

(3)コマンドに空文字を渡した場合

ファイル権限がある状態を前提とします。
本家では「command not found」が出力されます。

◆改善

コマンドを受け取る関数で、空だった場合エラーを出力するように修正

if (pipex.cmd_args == NULL || pipex.cmd_args[0] == NULL || *(pipex.cmd_args[0]) == '\0')
	{
		free_child(&pipex);
		put_error_msg(ERR_CMD, 1);
		exit(EXIT_FAILURE);
	}
  • !pipex.cmd_args[0] は、配列の最初の要素が NULL であるかどうかをチェックします。これは、配列自体が空、または初期化されていないことを示す可能性があります。
  • (pipex.cmd_args[0]) == '\0' は、配列の最初の要素が空文字列であるかどうかをチェックします。これは、文字列が存在するが内容が空であることを示します。

(4)コマンドに存在しないパスを渡した場合

本家では「no such file or directory」が出力されます。

(5)bashでunset PATHをした場合

本家では、セグフォしません。
unset PATH影響下では「command not found」ではなく「no such file or directory」と出力されます。
ただし実行可能な絶対パスを渡した時は実行されます。

ターミナルでシェル自体の動きの確認をする時に、bashを起動して確認すると良いです。
PATHを一時的に削除し、PATHが消えていることを確認します

例)
$ bash
$ echo $PATH  
$ unset PATH

◆改善

  • スラッシュが1つでも含まれている時は、絶対パスの実行可能判定を行う
    実行が可能ならそのまま実行する

  • 実行可能な絶対パスを渡した時は実行できるようにする

例)
/pipex infile "/bin/ls" "/usr/bin/wc" outfile
  • PATHがないときのNULLチェックを追加する

  • F_OKではなく、X_OKを使う

    • X_OKは、実行権限の有無も確認するため
    X_OK ファイルの存在確認と実行権限の有無を確認
    F_OK ファイルの存在確認のみ

終わりに

始めて使用する関数の理解をすることやエラー実装に時間がかかりました。
過去のレビューコメントを参考にさせてもらいながら、エラー処理を追加していきました。
記事書いてみたかったけど、課題の雑記になってしまいました。

Discussion