LoginSignup
2
2

More than 5 years have passed since last update.

Cで作るコンテナもどき #1

Last updated at Posted at 2018-12-24

はじめに

この記事はFuraITアドベントカレンダー22日の記事になります。
遅れてごめんなさい。昨日が22日だと思っていました。

またこちらで発表した内容と近いものになります。多分発表したときのほうが面白いので、気になる方はどうぞご参加ください。

まったくFuraITとは関係ありませんが気にしないで続けていきます。

環境

  • debian 9
  • kernel 4.9.0-8-amd64

作っていく

"#1"ということで、今回はC言語でforkとexec、waitを扱う部分までやりたいと思います。続けていくのかはわかりません。

fork

まずはプロセスをforkしてあげる必要があります。
Linux特有のライブラリもあるのでWindowsの方は自分でなんとかしてください。

#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>

int main(){
  pid_t pid;

  if ((pid = fork()) < 0){
    perror("fork");
    return 1;
  } 
  //子プロセス側の処理
  else if (pid == 0) {
    printf("child process:%d\n",(int)getpid());
    _exit(0);
  }
  printf("parent proces:%d\n",(int)getpid());
  return 0;
}

実行結果

parent proces:28540
child process:28541

こんな感じでした。ちゃんと親プロセス側の処理が先に実行されてますね。

Man page of FORKを見ればだいたいわかるんですが、
forkの返り値は正の値であれば子のプロセスID。0であればforkの成功として、子プロセスに返されます。
なので、pid == 0と指定してあげることで、子プロセス独自の処理をすることができます。


exec

子プロセスを呼び出すことに成功したので、次は実際に子プロセス内部で外部プログラムを実行します。
外部のプログラムを実行するには、exec系のシステムコールを呼び出す必要があります。
今回はexeclを使うことにしました。

#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>

int main(){
  pid_t pid;

  if ((pid = fork()) < 0){
    perror("fork");
    return 1;
  } 
  //child process
  else if (pid == 0) {
    printf("child process:%d\n",(int)getpid());
    execl("/bin/bash","",NULL);
    _exit(0);
  }
  printf("parrent proces:%d\n",(int)getpid());
  return 0;
}

Man page of EXEC 
exec系の説明は長くなるので割愛します。

子プロセスから/bin/bashを実行しましたが何も起きません。子プロセスは親プロセスが終了すると、死んでしまうからです。
そのため、子プロセスの終了を親プロセスが待ってあげる必要があります。


wait

wait系のシステムコールを用いて子プロセスの終了を待つことができます。今回はwaitpidを使用しました。
sys/wait.hをincludeするのを忘れないようにしましょう。

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

int main(){
  pid_t pid;
  int status;

  if ((pid = fork()) < 0) {
    perror("fork");
    return 1;
  } 
  //child process
  else if (pid == 0) {
    printf("child process:%d\n",(int)getpid());
    execl("/bin/bash","",NULL);
    perror("bash");
    _exit(1);
  }

  printf("parrent proces:%d\n",(int)getpid());
  if ((pid = waitpid(pid,&status,0)) < 0) {
    perror("wait");
    return 1;
  }
  if (WIFEXITED(status)) {
    printf("pid:%d status:%d\n",(int)getpid(),WEXITSTATUS(status));
  }
  return 0;
}

Man page of WAITを見れば全部わかります。
waitpidは、終了を待つプロセスID、終了ステータスを入れる変数、3つ目はoptionとなっていますが(今は関係ない)を引数にします。
WIFEXITED()は子プロセスがexitで終了した際に真となり、WEXITSTATUS()でその終了ステータスを取り出すことができます。
実行結果ですが、psコマンドで親プロセスのID、子プロセスのIDがあることを確認してください。一応この時点でchrootコマンドを用いての動作確認もできるのですが、それは'#2'できっと紹介されるはずなので待っててください。

 終わり!

'#1'はここで終わりです。気が向いたら'#2'を書きたいと思います。
間違っているところやわかりにくいところがあれば気軽に連絡してください。

 参考にしたところ

2
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2