limitusus’s diary

主に技術のことを書きます

fork(2)とexecve(2)を使ってみた

OSの授業で扱っていたfork(2)とexecve(2)ですが,実際に使ってみたことがなかったので実際に試しに使ってみました.
別に特別なことをしたかったわけではないので,とりあえずシェルと同じように動いてくれればいいかなーという設計になっています.

暇な時間に大学で作ったのでMac OS Xでしか動作確認をしていません.多分大丈夫だと思いますが,具体的にはerrnoまわりで何かあるかもしれません.

ではソースコードをいつものように追記に置いておきます.

  • switchでbreakし忘れてたので修正(erマクロ)
  • id:showyou の指摘により実行結果も追記に書きました
  • 動いたからそのままにしてあるけどargv[argc]は必ずNULLって決まってるのかな?
サンプルプログラム
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

#define er(mes) fprintf(stderr, mes);break

int main(int argc, char** argv) {
  if(argc < 2) {
    fprintf(stderr, "Please Specify command\n");
    return 1;
  }
  pid_t pid = fork();
  if(pid == 0) {
    int i;
    for (i = 0; i <= argc; i++) {
      fprintf(stderr, "argv[%d] = \"%s\"\n", i, argv[i]);
    }
    int e = execve(argv[1], &argv[1], 0);
    fprintf(stderr, "Error Occurred\n");
    switch(errno) {
    case E2BIG:
      er("Too much arguments\n");
    case EACCES:
      er("Exec Access Error\n");
    case EFAULT:
      er("Illegal Path or Arguments\n");
    case EIO:
      er("I/O Error\n");
    case ELOOP:
      er("Too Many Symbolic Links\n");
    case ENAMETOOLONG:
      er("Specified Path name is too long\n");
    case ENOENT:
      er("File does not exist\n");
    case ENOEXEC:
      er("Specified program has appropreate permission but has invalid header to execute\n");
    case ENOMEM:
      er("Memory size exceeded\n");
    case ENOTDIR:
      er("A component of the path prefix is not a directory\n");
    case ETXTBSY:
      er("File is currently used by another process\n");
    }
  } else {
    int a;
    wait(&a);
    //fprintf(stderr, "Parent\n");
  }
  return 0;
}
実行結果
limit@mkl ~/prog/c/sample
$ gcc -o execve execve.c
  • /bin/lsを呼び出してみる
limit@mkl ~/prog/c/sample
$ ./execve /bin/ls
argv[0] = "./execve"
argv[1] = "/bin/ls"
argv[2] = "(null)"
execve	execve.c
  • 自分自身を呼び出してみる
limit@mkl ~/prog/c/sample
$ ./execve ./execve /bin/ls
argv[0] = "./execve"
argv[1] = "./execve"
argv[2] = "/bin/ls"
argv[3] = "(null)"
argv[0] = "./execve"
argv[1] = "/bin/ls"
argv[2] = "(null)"
execve	execve.c
  • 存在しない/usr/bin/lsを呼び出してみる
limit@mkl ~/prog/c/sample
$ ./execve /usr/bin/ls
argv[0] = "./execve"
argv[1] = "/usr/bin/ls"
argv[2] = "(null)"
Error Occurred
File does not exist
  • 実行できないファイルを実行しようとしてみる
limit@mkl ~/prog/c/sample
$ ./execve /etc/fstab 
argv[0] = "./execve"
argv[1] = "/etc/fstab"
argv[2] = "(null)"
Error Occurred
Exec Access Error
  • オプションを渡してみる
limit@mkl ~/prog/c/sample
$ ./execve /bin/ls -l
argv[0] = "./execve"
argv[1] = "/bin/ls"
argv[2] = "-l"
argv[3] = "(null)"
total 16
-rwxr-xr-x 1 limit limit 8184 Feb  7 15:19 execve
-rw-r--r-- 1 limit limit 1264 Feb  7 15:19 execve.c
-rw-r--r-- 1 limit limit 1258 Feb  7 15:15 execve.c.~1~
  • 引数とオプションを同時に渡してみる
limit@mkl ~/prog/c/sample
$ ./execve /bin/uname -a
argv[0] = "./execve"
argv[1] = "/bin/uname"
argv[2] = "-a"
argv[3] = "(null)"
Linux mkl 2.6.24-23-generic #1 SMP Mon Jan 26 00:13:11 UTC 2009 i686 GNU/Linux