情報学類主専攻実験/システムプログラム (2003年)

最終更新: 2003/09/03 20:09:14

このページは、筑波大学 情報学類 3年生を対象とした 情報学類主専攻実験の、 テーマ K-3 (システム・プログラム) のためのページ(新城担当部分)です。この実験には、課題が2つあります。

  1. シェル、または、ディレクトリ・ブラウザ(どちらか1つ選択)
  2. 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. 1行として簡単なもの(パイプも入出力の切り替えもなし)を与えたと きに、どのような木構造になるか調べる。id がどうなるか、argc, argv がど うなるか、sinfile, soutfile, out_mode がどうなるかを調べる。
  2. execute_single_command() でコマンドを実行する。fork()システムコー ルと execve() システムコール(またはexecv() や execvp() )を使って実行す る。リターンバリューとして、PID を返す。
  3. fork() した場合、親プロセス側は、親は、wait(0), wait3() などで子 供が終了することを待たなければならない。どこで wait すべきかをよく考え る。必ずしも fork() をした関数で wait しなければならいことはない。
  4. 標準入力の切り替え(<)を与えた時に command 構造体が どうなるかを調べる。
  5. 標準入力を切り替えを実現する。open() システム・コールとdup() (ま たは、dup2())システム・コール、close() システム・コールを用いる。
  6. 標準出力の切り替え(>)、標準エラーの切り替え (>&)について、標準入力の切り替えと同様のことを行う。 out_mode にも注意する。
  7. パイプ(|)が打ち込まれた時に command 構造体がどうなるかを調べる。
  8. パイプ(|)を実現する。まず、pipe() システム・コールでパイプを作成 し、fork() してから親子で左右の枝を分担して再起、または、ループする。 fork() した後、パ イプの不要な口を閉じることを忘れないようにする。
  9. パイプラインでは、一番最後のコマンドだけを 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>