指定したプログラムを実行するexec関数メモ
今回は引数によって指定したプログラムを実行するexec関数についてのメモ。今回はexecl関数とexecv関数について書く。
書式
#include <unistd.h> int execl(const char *path, const char *arg0, ... /*, (char *)0 */); int execv(const char *path, char *const argv[]);
概要
exec系関数は、現在のプロセスを指定したプログラムに置き換えて実行する。そのため呼び出し元へ制御が戻ることはない。
関数に渡される第1引数は実行されるプログラムのパスである。それ以降はいわゆるコマンドライン引数を渡す形となる。第2引数に関してexeclは可変長の引数、execvは引数として配列が渡されることになる。また、引数リストの最後はNULLでなければならず、(char *)NULLとすべきである。
返り値
exec関数はエラーが起こった場合のみ呼び出し元に-1を返す。それ以外の場合は復帰せず返り値も存在しない。
実装例
execlを用いてechoを利用する例
#include <stdio.h> #include <unistd.h> #include <errno.h> #include <string.h> int main(){ errno = 0; execl("/bin/echo", "/bin/echo", "hoge", "fuga", NULL); if(errno != 0) perror(strerror(errno)); return -1; }
出力結果は以下のとおり
$ a.out foo bar
execvを用いてechoを利用する例
#include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> int main(int argc, char *argv[]){ char *const str[] = {"/bin/echo", "foo", "bar", NULL}; execv("/bin/echo", str); if(errno != 0) perror(strerror(errno)); return -1; }
出力結果は以下のとおり
$ a.out foo bar
execl関数を用いて任意のプログラムを実行
#include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> int main(){ errno = 0; execl("/foo/bar/hello", "/foo/bar/hello", NULL) ; if(errno != 0) perror(strerror(errno)); return -1; }
今回実行するプログラムはHelloと出力するだけの簡単なプログラム。
#include <stdio.h> int main(){ printf("Hello\n"); return 0; }
出力結果は以下のとおり
$ a.out Hello
execl関数がエラーとなる場合
#include <stdio.h> #include <unistd.h> #include <errno.h> #include <string.h> int main(){ errno = 0; // 第一引数にtypo有 execl("/bin/ech", "/bin/echo", "hoge", "fuga", NULL); if(errno != 0) perror(strerror(errno)); return -1; }
以下の様なメッセージが出力される。
$ a.out No such file or directory: No such file or directory
今まで使ったことない関数もあったのでそれについても併記する。
perror関数
#include <stdio.h> void perror(const char *s);
システムエラーメッセージを出力する関数。
strerror関数
#include <string.h> char *strerror(int errnum);
引数に渡されたエラーコードに対応した文字列の先頭ポインタを返す。大域変数errnoにエラーコードが格納されてるので、その値を使って呼び出すと良い。
forkと組み合わせて使う
前途の通り、execを呼び、かつ元の処理を実行させたい時にはfork関数を活用すると良い。
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> int main(int argc, char *argv[]){ int pid; int code; int status; pid_t result; int i = 0; while(i < 10){ pid = fork(); // fork失敗 if(pid == -1){ fprintf(stderr, "Error\n\n"); } // 子プロセスの処理 if(pid == 0){ execl("/Users/keisuke/program/c/OS1/hello", "/Users/keisuke/program/c/OS1/hello", NULL); }else{ result = wait(&status); if(result < 0){ fprintf(stderr, "Wait Error.\n\n"); exit(-1); } // 終了ステータスのチェック if(WIFEXITED(status)){ printf("子プロセス終了"); code = WEXITSTATUS(status); printf("コード : %d\n", code); }else{ printf("wait失敗"); printf("終了コード : %d\n", status); } i++; } } printf("親プロセス終了\n"); return 0; }
なんかインデントがおかしくなってる
先ほどのHelloと出力するプログラムを10回呼び出すものの例である。