最終更新: 2003/09/03 20:09:14
このページは、筑波大学
情報学類
3年生を対象とした
情報学類主専攻実験の、
テーマ K-3 (システム・プログラム)
のためのページ(新城担当部分)です。この実験には、課題が2つあります。
- シェル、または、ディレクトリ・ブラウザ(どちらか1つ選択)
- mini ftp
このページでは、シェル、または、ディレクトリ・ブラウザに関連した追加情
報を掲載します。
実験テキスト:
2003年度2学期は、最初の時間、9月3日水曜日に、説明をやります。
3C113端末室に集まって下さい。
実験を取っている人のメーリング・リストを作りました。最初のメールは送り
ました。届いていない人は、新城まで連絡してください。
この課題では、何回か中間報告を出してもらいます。
2003年2学期では、次の日時までに課題を仕上げて指定された方法で提出
してください。
- 9月10日水曜日 17:00
- シェルの課題1−1、または、ディレトクリ・ブラウザの課題2−1を
行い、電子メールで新城まで提出する。ただし、図については、付けなくても
よい。テキスト部分だけでよい。(最終的なレポートには必ず図を付けるこ
と。)
- 10月1日水曜日 17:00
- 残り課題1−2、1−3、または、2−2、2−3を行い、課題1−1、
または、2−1も「含めて」全てを紙に印刷してレポート提出箱(C棟1階の
予定)に提出する。
利用者が打ち込んだ行を、シェルの構文に従って解析し、解析木を出力するよ
うなプログラムを用意しました。この実験では、シェルの構文解析の部分につ
いては、このプログラムを利用してください。
プログラムは、次の場所にあります。
~yas/slab-syspro-2003/myshparse4/
cp -rp などでコピーして使ってください。必要な部分は、次のファイルです。
command.c
- command構造体操作
command.h
- command構造体データ構造
lexer.c
- 字句解析器
lexer.h
- 字句解析器データ構造
parser.c
- 構文解析器
parser.h
- 構文解析器データ構造
executer.c
- プログラムの実行(画面に表示)
executer.h
- そのインタフェース
mysh.c
- シェルのmainプログラム
mysh.c では、1行読み込み、parse() を読んで解析しています。
関数は、parse()
構文解析器で、引数で与えられた1行を解析
し、pl_list, pipe_line, single_command という構造体からなる木構造を返
します。
parse() が返した木構造を解析して実行(画面に表示)するものが、
executer.c に含まれている関数です。
このサンプルは、木構造の内容を画面に表示するようになっています。
次のような手順で、executer.c を書き換えていくとよいでしょう。
- 1行として簡単なもの(パイプも入出力の切り替えもなし)を与えたと
きに、どのような木構造になるか調べる。id がどうなるか、argc, argv がど
うなるか、sinfile, soutfile, out_mode がどうなるかを調べる。
- execute_single_command() でコマンドを実行する。fork()システムコー
ルと execve() システムコール(またはexecv() や execvp() )を使って実行す
る。リターンバリューとして、PID を返す。
- fork() した場合、親プロセス側は、親は、wait(0), wait3() などで子
供が終了することを待たなければならない。どこで wait すべきかをよく考え
る。必ずしも fork() をした関数で wait しなければならいことはない。
- 標準入力の切り替え(<)を与えた時に command 構造体が
どうなるかを調べる。
- 標準入力を切り替えを実現する。open() システム・コールとdup() (ま
たは、dup2())システム・コール、close() システム・コールを用いる。
- 標準出力の切り替え(>)、標準エラーの切り替え
(>&)について、標準入力の切り替えと同様のことを行う。
out_mode にも注意する。
- パイプ(|)が打ち込まれた時に command 構造体がどうなるかを調べる。
- パイプ(|)を実現する。まず、pipe() システム・コールでパイプを作成
し、fork() してから親子で左右の枝を分担して再起、または、ループする。
fork() した後、パ
イプの不要な口を閉じることを忘れないようにする。
- パイプラインでは、一番最後のコマンドだけを wait すればよい。
これらの関数には、引数を追加する必要がでてくるでしょう。ファイル記述子
(標準入力、標準出力など)を付け加えたり、fork すべきかどうかのフラグ
を付け加えたりする必要がでてくるでしょう。
fork() のタイミングには注意してください。内部コマンドの場合、fork() を
してはいけません。ただし、標準出力がパイプの場合、まずパイプを作成して
からfork() する必要があります。fork() すべきかどうかを、木を先読みして
調べる方法もあります。
配列と木構造の探索については、2年生の教科書を読み返して復習して下さい。
配列の場合には、「ループ」することが基本です。パイプラインは、再帰では
なくループを使った方が簡単に実現できるようになっています。
構造体の場合には、
関数呼び出し(場合によっては再帰呼び出し)を使います。
fork() する時には、2重に検索実行しないように気をつける必要があります。
課題1−1では、プロセスの親子関係を中心に調べなさい。これを調べるには、
自分が作成するシェルの参考にするためです。同じ方法を使ってもよいし、独
自の方法を使ってもかまいません。
親子関係を調べるには、ps コマンドを使います。この時、意味はありません
が、ps コマンドには、X ウインドウ関係のプログラム(すぐには終了しない)
を使うとよいようです。
% csh
% emacs | ps -l
% emacs | kterm | ps -l
% sh
$ emacs | ps -l
$ emacs | kterm | ps -l
$
本格的に調べるには、strace コマンドを使います。
% strace -f -o sh.log sh
$ ls
$ ls | head
$ exit
% less sh.log
% egrep 'fork|dup|exec|close|wait' sh.log | less
%
プロセスが実行していく過程でどのようにシステムコールを発行していったか
の「足跡」をプロセスのトレース(trace)といいます。
strace (Linux) は、プロセスのトレースを表示するコマンドです。-f で、
fork() を越えて子プロセスまで追跡します。-o file で、画面(標準エラー)
の代りに、ファイルに結果を落とすことができます。
詳しくは、man strace を見てください。
この課題は、Ruby/GTK を使って記述することを奨めます。C言語で GTK+
(Gimp ToolKit) を直接使っても似たような外観になります。GTK+ 以外の
Tool Kit を使ってもかまいません。
Ruby/GTK で途中まで記述したものが、次の場所にあります。
~yas/slab-syspro-2003/dir-browse4/dir-browse4.rb
- class DirListLongClist < Gtk::CList
- Gtk::CList を継承して、ls -l 風の内容を保存するための Clist をつくる。
- Dir.new(".")
- ディレクトリを開く
- dir.each
- ディレクトリの各内容についての処理
- File.lstat
- lstat() システムコール。リンクの先をたどらない。ls -l で lrwxrwxrwx と
表示するには、必要。
- clist.signal_connect
- クリックされた時の処理を記述する。set_text で、
テキストを設定している。
- ok_button.signal_connect
- OK ボタンが押された時の処理。ここで新しいディレクトリを
開くようにすればよい。
Ruby/GTK については、次の本に詳しく記述されています。
三並 慶佐: Ruby/GTKプログラミング入門,技術評論社 (2002年). ISBN:
4774114685
この本のサンプル・プログラムが次の場所にあります。
~yas/ruby/gtk/book/program/
7_8_2.rb と fileselection.rb が参考になります。
Last updated: 2003/09/03 20:09:14
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>