UNIXプログラミング入門~プロセス編(2/4)~

c/c++でunix系osプログラミングを行うときに使うunistd.hやその周辺のライブラリのお話その4です。
このメモでは、プロセス周りのシステムコールAPIに関して取り上げます。

プロセスを別のプロセスに置き換える-execvp(3)-

execvpのプロトタイプはunistd.hに以下のように定義されています。

int execvp(const char *file, char *const argv[]);

第一引数、fileに指定したプログラムを第二引数argv[]で実行する。

argv[]の最後にはNULLを入れる必要があります。
NULLターミネート

新たなプロセスを作成するのではなく、現在のプロセスを指定したプログラムに置き換える点に注意してください。

つまり新しいプロセスを作る訳ではないのでプロセスIDは変化しません。

#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
    if (argc < 1) {
        return 0;
    }
    execvp(argv[1], &argv[2]);
    return 0;
}

引数に与えられたコマンドを実行するプログラムです。 このままでは、あまり意味のあるようには思えませんが、前回紹介したfork関数と組み合わせると面白いことが出来そうです。

自作bash風プログラム

まずは、プロセス編で紹介した関数を簡単におさらいします。

  • fork(2)現在のプロセスを複製して新しいプロセスを作成する
  • waitpid(2)子プロセスの完了を待つ
  • execvp(3)現在のプロセスを別のプログラムに置きかえる

前回とここまでの内容を踏まえて自作のbash風プログラムを作ってみたいと思います。

#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <stdio.h>

#define BUF_LEN 1024
int main(int argc, char const *argv[])
{
    printf("welcome to my bash!\n");
    for(;;)
    {
        fprintf(stderr, ">>");
        char buf[BUF_LEN];
        fgets(buf, BUF_LEN, stdin);
        char *sep = " \n";
        char *exec = strtok(buf, sep);

        if(exec == NULL)
            continue;

        char *tkn[BUF_LEN];
        for(int i = 0;;++i)
        {
            tkn[i] = strtok(NULL, sep);
            if (tkn[i] == NULL) break;
        }
        pid_t pid = fork();
        
        if (pid < 0) {
            fprintf(stderr, "fork failed\n");
        }
        else if (pid > 0)
        {
            int stat;
            waitpid(pid, &stat, 0);
        }
        else
        {
            execvp(exec, tkn);
        }

    }
    return 0;
}

パイプやリダイレクトなどもともとのbashにある機能はありませんが、とりあえずそれっぽいプログラムが出来ました。

次回以降パイプやリダイレクトに関して話を進めていこうと思います。