C 言語の execvp 関数
-
C 言語でプロセスイメージを置き換えるために
execvp
関数を使用する - 関数呼び出しエラーのシナリオと対応するメッセージの出力を適切に扱う
-
子プロセスを作成して異なるプログラムを実行するために
fork
関数を用いてexecvp
を利用する
この記事では、C 言語で execvp
関数を利用する方法について複数の方法を紹介します。
C 言語でプロセスイメージを置き換えるために execvp
関数を使用する
Unix ベースのシステムでは、新しいプロセスを作成するためのシステムコールと、実行中のプロセスに新しいプログラムコードをロードするためのシステムコールがあります。後者は execve
システムコールの異なるインターフェースである exec
ファミリーのライブラリ関数を使って行われます。関数には 6つの異なるプロトタイプがあります。execlp
、execle
、execv
、execvp
そして execvpe
です。これらの関数は、ロードして実行する新しいプログラムファイルのファイル名かパス名を第一引数にとります。execvp
はまた、2 番目の引数としてプログラム引数の配列を受け取ります。
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void) {
const char *args[] = {"vim", "/home/ben/tmp3.txt", NULL};
execvp("vim", args);
exit(EXIT_SUCCESS);
}
関数呼び出しエラーのシナリオと対応するメッセージの出力を適切に扱う
なお、exec
系の関数はエラーが発生した場合にのみ返すので、必要に応じてエラーチェックルーチンを実装し、対応するコードパスを処理することが重要です。
中でも execvp
は失敗した場合に -1
を返し、変数 errno
を設定します。ただし、errno
は関数呼び出しの前に明示的に 0 を設定し、呼び出しが戻ってきたときにのみ値をチェックすることに注意してください。関数 execvp
はスラッシュを含まないファイル名を受け取ることができ、環境変数 PATH
で指定されたディレクトリでファイルが検索されることを意味します。
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void) {
const char *args[] = {"vim", "/home/ben/tmp3.txt", NULL};
errno = 0;
if (execvp("vim", args) == -1) {
if (errno == EACCES)
printf("[ERROR] permission is denied for a file\n");
else
perror("execvp");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
子プロセスを作成して異なるプログラムを実行するために fork
関数を用いて execvp
を利用する
あるいは、ユーザが新しいプロセスを作成し、与えられたプログラムコードを実行する必要があるとします。その場合、fork
と execvp
を組み合わせた関数呼び出しを利用することができます。fork
は呼び出したプロセスを複製し、子プロセスと呼ばれる新しいプロセスを作成します。次の例では、新しいプロセスを作成し、与えられたプログラムコードをロード/実行するためのカスタム関数ラッパーを実装しています。子プロセスが作成されると、子プロセスは別のコードを実行し、親プロセスは子プロセスが終了するまで待機することに注意してください。
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
pid_t spawnChild(const char* program, char** arg_list) {
pid_t ch_pid = fork();
if (ch_pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (ch_pid > 0) {
printf("spawn child with pid - %d\n", ch_pid);
return ch_pid;
} else {
execvp(program, arg_list);
perror("execve");
exit(EXIT_FAILURE);
}
}
int main(void) {
const char* args[] = {"vim", "/home/ben/tmp3.txt", NULL};
pid_t child;
int wstatus;
child = spawnChild("vim", args);
if (waitpid(child, &wstatus, WUNTRACED | WCONTINUED) == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}