C 言語の execvp 関数

胡金庫 2023年10月12日
  1. C 言語でプロセスイメージを置き換えるために execvp 関数を使用する
  2. 関数呼び出しエラーのシナリオと対応するメッセージの出力を適切に扱う
  3. 子プロセスを作成して異なるプログラムを実行するために fork 関数を用いて execvp を利用する
C 言語の execvp 関数

この記事では、C 言語で execvp 関数を利用する方法について複数の方法を紹介します。

C 言語でプロセスイメージを置き換えるために execvp 関数を使用する

Unix ベースのシステムでは、新しいプロセスを作成するためのシステムコールと、実行中のプロセスに新しいプログラムコードをロードするためのシステムコールがあります。後者は execve システムコールの異なるインターフェースである exec ファミリーのライブラリ関数を使って行われます。関数には 6つの異なるプロトタイプがあります。execlpexecleexecvexecvp そして 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 を利用する

あるいは、ユーザが新しいプロセスを作成し、与えられたプログラムコードを実行する必要があるとします。その場合、forkexecvp を組み合わせた関数呼び出しを利用することができます。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);
}
著者: 胡金庫
胡金庫 avatar 胡金庫 avatar

DelftStack.comの創設者です。Jinku はロボティクスと自動車産業で8年以上働いています。自動テスト、リモートサーバーからのデータ収集、耐久テストからのレポート作成が必要となったとき、彼はコーディングスキルを磨きました。彼は電気/電子工学のバックグラウンドを持っていますが、組み込みエレクトロニクス、組み込みプログラミング、フロントエンド/バックエンドプログラミングへの関心を広げています。

LinkedIn Facebook

関連記事 - C Process