システムプログラム練習問題#4

練習問題(401)

printenv コマンドは,現在のプロセスの環境変数を表示してくれる. 同様の表示をしてくれるコマンドを,Cプログラムとして記述せよ.

練習問題(402)

メモリマップを確かめるプログラムをコンパイルし,繰り返し実行してみたところ,以下のようにスタックのアドレスが毎回若干変化していることがわかった. これを確かめ,なぜスタックの場所が変わるか,その理由について考えてみなさい.

% ./a.out [←]
environ:        0xbfffe8dc
argv:           0xbfffe8d4
stack:          0xbfffe867
bss:            0x080496e8
data:           0x080495f0
% ./a.out [←]
environ:        0xbfffe6dc
argv:           0xbfffe6d4
stack:          0xbfffe667
bss:            0x080496e8
data:           0x080495f0
% ./a.out [←]
environ:        0xbfffe7dc
argv:           0xbfffe7d4
stack:          0xbfffe767
bss:            0x080496e8
data:           0x080495f0
%

練習問題(403)

以下のプログラムをコンパイル,実行すると hello が8回表示される. その理由について考えよ.

     1  #include <stdio.h>
     2
     3  main()
     4  {
     5          fork();
     6          fork();
     7          fork();
     8          printf("hello\n");
     9  }

練習問題(404)

system(3) は,シェルによるコマンドの実行を行ってくれるライブラリ関数である. 以下のように,シェル(/bin/sh)のコマンドラインを文字列で渡すと実行してくれる.

     1  #include 
     2  #include 
     3
     4  main()
     5  {
     6          system("ls *.c | wc");
     7  }

fork, execve(又は相当のライブラリ関数),wait などを使用して,system(3)相当の機能を持つ関数 mysystem を作りなさい.

マニュアルページに記述してあるシグナルについては,無視してよい.

練習問題(405)

標準入力をファイルからリダイレクションするプログラムをもとに,標準出力もファイルに対しての書き込みとなるように変更せよ. 書き込むファイルは,プログラムの第2引数としてとるものとする.

練習問題(406)

第1引数で与えられるコマンドの実行結果(exit status)に応じて,第2引数又は第3引数で与えられるコマンドを実行するプログラム if-then-else を作りなさい.例えば

% ./if-then-else "test 1 -eq 1" "echo yes" "echo no" [←]
yes
% ./if-then-else "test 1 -eq 2" "echo yes" "echo no" [←]
no
%

となるようなものをである.

コマンドの区切りは別のものでも良い. 以下は then, else が区切りになっている. execve を使用する場合は,argv の then, else の部分を NULL にすると execve にそのまま渡せるので,以下のような区切りのほうが,プログラムは作りやすいかもしれない.

% ./if-then-else test 1 -eq 1 then echo yes else echo no

練習問題(407)

最初に fork で子プロセスを作り,親プロセスと子プロセスが交互に実行を繰り返すプログラムを作りなさい.

出力は以下に示すように,子プロセスは数字を親プロセスはアルファベットの大文字を出力する.

% ./a.out 60 [←]
0A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9T0U1V2W3X4Y5Z6A7B8C9D
%

子プロセスが1文字(最初は0)を出力した後,実行を親プロセスに戻し,親プロセスが1文字(最初はA)を出力の後,また実行を子プロセスに移し,子プロセスが1文字(1)を出力し…というように,親と子プロセスの実行を交互に繰り返す.

練習問題(408)

練習問題(407)のプログラムを変更し,子プロセスの数をプログラムへの引数で与えられるように,即ち任意個の子プロセスに対応したプログラムを作りなさい.

練習問題(409)

3個のプロセスの標準入出力を2つのパイプで結びなさい.

パイプの作り方は,先にパイプを2つ作ってから2回 fork する方法と,1つパイプを作り fork し,もう1つパイプを作りまた fork する方法があるが,どちらでも良い.

練習問題(410)

popen(3), pclose(3)は,パイプにより接続された指定されたプログラムを実行するプロセスを生成し,そのプロセスに対する入力又は出力のどちらか一方を提供するライブラリ関数である.

popen(3), pclose(3)相当の機能を持つ関数 mypopen, mypclose を作りなさい. 最初は,popenで実行するプログラムからの出力を受け取る機能だけを実装するところから始めるとよい.

練習問題(411)

パイプを使用するプログラムを,以下のように,親プロセスからの出力を子プロセスの入力にするように書き換えたところ,終了しなくなってしまった. その理由を考え,プログラムの修正せよ.

     1  #include <stdio.h>
     2
     3  int pipe_fd[2];
     4
     5  void
     6  do_parent()
     7  {
     8          char    *p = "Hello, my kid.";
     9          int     status;
    10
    11          printf("this is parent.\n");
    12
    13          close(pipe_fd[0]);
    14
    15          while (*p) {
    16                  if (write(pipe_fd[1], p, 1) < 0) {
    17                          perror("write");
    18                          exit(1);
    19                  }
    20                  p++;
    21          }
    22
    23          if (wait(&status) < 0) {
    24                  perror("wait");
    25                  exit(1);
    26          }
    27  }
    28
    29  void
    30  do_child()
    31  {
    32          char    c;
    33          int     count;
    34
    35          printf("this is child.\n");
    36
    37          close(pipe_fd[1]);
    38
    39          while ((count = read(pipe_fd[0], &c, 1)) > 0) {
    40                  putchar(c);
    41          }
    42          putchar('\n');
    43
    44          if (count < 0) {
    45                  perror("read");
    46                  exit(1);
    47          }
    48  }
    49
    50  main()
    51  {
    52          int child;
    53
    54          if (pipe(pipe_fd) < 0) {
    55                  perror("pipe");
    56                  exit(1);
    57          }
    58
    59          if ((child = fork()) < 0) {
    60                  perror("fork");
    61                  exit(1);
    62          }
    63
    64          if (child)
    65                  do_parent();
    66          else
    67                  do_child();
    68  }