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);
}
