C 言語で execlp 関数を使用する

胡金庫 2023年10月12日
C 言語で execlp 関数を使用する

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

C で execlp を使用してファイル名を使用して新しいプログラムを実行する

関数 exec ファミリーは、プロセスメモリへの新しいプログラムのロードを管理するために、下位レベルの execve システムコールに代わる API として提供されます。このファミリには 6つの独立した関数があり、ほとんどの場合、結果というよりもパラメータが異なります。execlp 関数はユーザにファイル名を指定するオプションを与えるもので、プログラムは現在の環境変数 PATH にリストされているディレクトリ内で検索されます。

ファイル名にスラッシュが含まれている場合は、相対パス名か絶対パス名として扱われます。次の例では、シェルと同様の動作をするプログラムを実装します。すなわち、このプログラムはユーザからプログラム名を受け取り、子プロセスとして実行します。親プロセスは待機し、子プロセスが戻ると、制御はユーザ入力の次の反復処理に進みます。プログラムはユーザがCtrl+Dのようなキーストロークで終了させる必要があります(OS に依存します)。シェルコマンドの中には実行できないものもあること、そして最も重要なことは、コマンドラインの引数が渡されず、代わりに couldn't execute と表示されることです。

#include <sys/wait.h>

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"

enum { MAXLINE = 256, MAXARGS = 48 };

int main(int argc, char *argv[]) {
  char buf[MAXLINE];
  pid_t pid;
  int status;

  char *str1, *token;

  printf("%% ");
  while (fgets(buf, MAXLINE, stdin) != NULL) {
    if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = 0;

    if ((pid = fork()) < 0) {
      perror("fork");
    } else if (pid == 0) {
      execlp(buf, buf, (char *)NULL);
      printf("couldn't execute: %s", buf);
      exit(127);
    }

    if (waitpid(pid, &status, 0) < 0) perror("waitpid");
    printf("%% ");
  }

  exit(EXIT_SUCCESS);
}

execlp は可変関数であり、可変数の引数を取ることができます。しかし、最初と最後の引数は固定されており、ファイル名へのポインタを表し、それに対応して char*NULL をキャストします。NULL ポインタをキャストすることは、関数が動作するために必須であり、可変数の引数の終わりを示すことにも注意してください。要するに、2 番目の位置の引数はプログラムのコマンドライン引数を指定しなければならず、そのうちの最初の引数はファイル名そのものでなければならません。

あるいは、前の例を実装して、引数を使ってコマンドを実行できるようにすることもできます。この場合、引数リストを配列として受け取る execvp 関数を利用しました。また、strtok を用いてユーザ入力を解析し、スペースで区切られた各文字列を引数として渡しました。その結果、よりシェルプログラムに近いエミュレーションが可能となった。

#include <sys/wait.h>

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "unistd.h"

enum { MAXLINE = 256, MAXARGS = 48 };

int main(int argc, char *argv[]) {
  char buf[MAXLINE];
  char *args[MAXARGS];
  pid_t pid;
  int status, args_num = 0;

  char *str1, *token;

  printf("%% ");
  while (fgets(buf, MAXLINE, stdin) != NULL) {
    if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = 0;

    str1 = strdup(buf);
    for (int j = 0;; j++, str1 = NULL) {
      token = strtok(str1, " ");
      if (token == NULL) break;
      args[j] = token;
      args_num += 1;
      printf("%d: %s\n", j + 1, args[j]);
    }
    free(str1);
    args[args_num] = (char *)NULL;

    if ((pid = fork()) < 0) {
      perror("fork");
    } else if (pid == 0) {
      execvp(args[0], &args[0]);
      printf("couldn't execute: %s", buf);
      exit(127);
    }

    if (waitpid(pid, &status, 0) < 0) perror("waitpid");
    printf("%% ");
  }

  exit(EXIT_SUCCESS);
}
著者: 胡金庫
胡金庫 avatar 胡金庫 avatar

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

LinkedIn Facebook

関連記事 - C Process