printenv コマンドは,現在のプロセスの環境変数を表示してくれる. 同様の表示をしてくれるコマンドを,Cプログラムとして記述せよ.
メモリマップを確かめるプログラムをコンパイルし,繰り返し実行してみたところ,以下のようにスタックのアドレスが毎回若干変化していることがわかった. これを確かめ,なぜスタックの場所が変わるか,その理由について考えてみなさい.
% ./a.outenviron: 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 %
以下のプログラムをコンパイル,実行すると hello が8回表示される. その理由について考えよ.
1 #include <stdio.h> 2 3 main() 4 { 5 fork(); 6 fork(); 7 fork(); 8 printf("hello\n"); 9 }
system(3) は,シェルによるコマンドの実行を行ってくれるライブラリ関数である. 以下のように,シェル(/bin/sh)のコマンドラインを文字列で渡すと実行してくれる.
1 #include2 #include 3 4 main() 5 { 6 system("ls *.c | wc"); 7 }
fork, execve(又は相当のライブラリ関数),wait などを使用して,system(3)相当の機能を持つ関数 mysystem を作りなさい.
マニュアルページに記述してあるシグナルについては,無視してよい.
標準入力をファイルからリダイレクションするプログラムをもとに,標準出力もファイルに対しての書き込みとなるように変更せよ. 書き込むファイルは,プログラムの第2引数としてとるものとする.
第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
最初に fork で子プロセスを作り,親プロセスと子プロセスが交互に実行を繰り返すプログラムを作りなさい.
出力は以下に示すように,子プロセスは数字を親プロセスはアルファベットの大文字を出力する.
% ./a.out 600A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9T0U1V2W3X4Y5Z6A7B8C9D %
子プロセスが1文字(最初は0)を出力した後,実行を親プロセスに戻し,親プロセスが1文字(最初はA)を出力の後,また実行を子プロセスに移し,子プロセスが1文字(1)を出力し…というように,親と子プロセスの実行を交互に繰り返す.
練習問題(407)のプログラムを変更し,子プロセスの数をプログラムへの引数で与えられるように,即ち任意個の子プロセスに対応したプログラムを作りなさい.
3個のプロセスの標準入出力を2つのパイプで結びなさい.
パイプの作り方は,先にパイプを2つ作ってから2回 fork する方法と,1つパイプを作り fork し,もう1つパイプを作りまた fork する方法があるが,どちらでも良い.
popen(3), pclose(3)は,パイプにより接続された指定されたプログラムを実行するプロセスを生成し,そのプロセスに対する入力又は出力のどちらか一方を提供するライブラリ関数である.
popen(3), pclose(3)相当の機能を持つ関数 mypopen, mypclose を作りなさい. 最初は,popenで実行するプログラムからの出力を受け取る機能だけを実装するところから始めるとよい.
パイプを使用するプログラムを,以下のように,親プロセスからの出力を子プロセスの入力にするように書き換えたところ,終了しなくなってしまった. その理由を考え,プログラムの修正せよ.
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 }