授業資料/第05回 の変更点

Top / 授業資料 / 第05回

#contents

* 授業内容 [#c1b47873]

これからの内容を理解するために,unix の動作の基本について説明する.

* Unix が動いているということ [#k2d47764]

unix という OS が動いているということは,ユーザに対してさまざまな直接に応答をするだけではない.
さまざまな応答を「サービス」するために,背後で常に動いているソフトウェアがあったり,要求に応じてソフトウェアが自動的に立ち上がったり,定期的に起動したりするソフトウェアがある.

希望通りのサービスを行わせるためだけではなく,動作の効率化の面からもセキュリティの面からもこうしたソフトウェアの在り方と設定を知ることが必要である.
今回はそうした「自動的に起動するソフトウェア」について学ぶ.

* 常に動いているソフトウェア [#c173086c]

unix に限らず,ある程度の規模の OS ではさまざまなサービスを提供するために常に動いているソフトウェアが存在する.

** まずは今動いているソフトウェアを見てみる [#ldc50d53]

ps というコマンドがまずは基本.

  jman ps

もしくは

  man ps

として,まずはこのコマンドについて調べよう. なんとなくわかった気になったら,その後,

 ps -axu 

としてみよう((画面に入りきらない場合は,ps -axu | less などとしよう)). こうすると全てのプロセスが見える. ある程度の文字数で表示が切られてしまい良く読めないという場合は,

  ps -axuww

などとすればよい.

次に,実際に動いている各々のプロセスがどれくらいの負荷をかけているのか調べてみよう.
この目的には top というコマンドが適している. これもマニュアルをひいてから,実際に

  top

としてみよう. プロセスの状況が動的にみえ,かつ,cpu やメモリの状況などがみられることがわかるだろう.

次に,様々なファイルを開いているプロセスの状況をみるためのコマンド,lsof を使ってみよう.
ただし,lsof はインストールされていないかもしれない. その場合は,ports からさくっとインストールしておこう.
(インストール後),まずはマニュアルをひいてから,

  lsof | less

としてみよう. たぶんよくわからないだろうから,今度は

 lsof -i4
 lsof -i4 -P

としてみよう. こうするとネットワーク port の状況(待ち受け含む)を知ることができる.
これらはネットワークサービスをする際に非常に重要な情報であり,このために lsof は重宝する.

*** 実習 [#v1cd6814]
もしインストールされていなければ,lsof を以下のようにしてインストールしておけ((時計が狂っていると portsnap の作業が蹴られることがある.その場合は,ntpdate というコマンドで時計あわせをしよう.  ntp サーバは適宜検索しよう.)).

  portsnap fetch ← こういう時はまずは ports データを取ってきて… 
  portsnap update ← 更新しておくのを癖にしておこう. 古いものだと何かと問題が.
  portinstall lsof ← それからインストール.

** kernel [#s5edfdb6]

Unix OS そのもの,中核であるソフトウェアは通常 kernel と呼ばれ,これは常に動作している.
kernel の役目はその OS 上で動くソフトウェアの制御と,各ソフトウェアに資源(メモリ,ハードディスク,各 I/O 等々)を提供することにある.
具体的には,CPU やメモリなどのハードウェアの基本的な制御,その上での抽象的な資源(仮想メモリなど)の構築, 各ソフトウェアへの資源割り当て((マルチタスクはCPUなどの資源を順番に割り当て直すことで実現される))などであり, unix OS のソフトウェアの中で「もっとも重要なソフトウェアの一つ」である.

kernel および kernel に組込むモジュールは現在の FreeBSD では /boot/kernel ディレクトリにある. 

kernel の動作を変えるには,設定を変える方法と kernel 自身をコンパイルして作り直す方法がある((なんと OS の中核そのものを自分で作り直すことができるのだ)).
詳しく書くと以下の通りである.

- 起動時に設定を変える方法 
-- ブート時に,ローダ(loader)に「入って」そこで手動で設定を書き換えるという手法がある. 
新しいカーネルを作ったがうまく動かないなどという時には重要な手段だ((そのときは,loader 上で boot コマンドで古いカーネルから起動すればよい. もちろん,古いカーネルをバックアップしてなければそれまでだが…)).
具体的には,マシンを起動して,起動時のメニュー
&ref(./01.png);
が出た時にスペースキーを押していったん停めてから, 6 キーを押して選ぶ. すると
&ref(./02.png);
というプロンプトがでてローダに入れたことがわかる.
//
ローダの上では ? を押せば使えるコマンドが出る. ローダの中で困ったら,autoboot とすれば通常通り起動するのでこれを使おう.
ちなみに,ローダ上で使えるコマンドは,(FreeBSD が普通に動いているときに) jman loader とすればマニュアルがひける.

-- /boot/loader.conf を書き換えておいてから(再)起動する. この設定ファイルのデフォルト設定は /boot/defaults/loader.conf にあるのでみてみよう(この設定をいじると,商用 OS のように起動時に画像を出すこともできる).

- 動作中に設定を変える方法.
-- sysctl を使う. まずはマニュアルを簡単に読もう. それから,(情報をみるだけなら問題ないので) root で
  sysctl -a -h | less
などとしてみよう. 丁寧に見ていくと,なんとなくわかる項目もあるだろう. 
ちなみに,書き換えてみたければ sysctl 変数名=設定値 で書き換えが可能だが,慣れていないうちはあまりお勧めしない(^-^)

-- カーネルモジュールのロード,アンロードを行う. コマンドは kldload と kldunload だ. デバイスドライバの設定をあれこれ変える場合などにお世話になるだろう.
これら2コマンドのマニュアルをひき,おおよそ理解しておこう. 
特殊なハードウェアを使う際などにはお世話になる.

- カーネルをコンパイルして作ってしまう(かなり細かいカスタマイズが可能)
普通は,/usr/src/sys/i386/conf にある GENERIC ファイルをコピーして書き換えてからコンパイルし直すという手順を踏む.
さすがにここで書ききれないので,FreeBSD の公的資料である [[ハンドブック(FreeBSDカーネルのコンフィグレーション)>http://www.jp.freebsd.org/www.FreeBSD.org/doc/ja_JP.eucJP/books/handbook/kernelconfig.html]] を紹介しておく.
この手法でFreeBSD の「性能」を大きく変えることができるので,マシンの用途によってはカーネルの再コンパイルを検討した方がよいだろう.

*** 実習 [#h4f4dc5f]
マシンを再起動させ,ローダ(loader)に入ってみよう.
試しに,loader 上で lsmod として,どんなモジュールが読み込まれているかみてみよう.
意外にみるだけでわかるものもあるはずだ.
また,heap としてみて,メモリの使用状況を見てみよう.
それが終わったら,autoboot として,通常のブートをさせよう.

次に,(以降は通常の FreeBSD 上で) sysctl の設定表を眺めて,分かる部分がないか探してみよ.

** init [#j25d1344]

unix では全てのプログラムには,親から起動される子という「親子関係」がある.
そして,unix OS の中で「プログラム」として意識されるプログラム/プロセス全ての「始祖」プログラムが init である.
通常は pid 1 である((さらに nest して init を起動することが可能な環境が存在する. 詳しくは jman jail などとしてみよ.)).

もうちょっと細かく解説すると,unix では init を除いてあらゆるプロセスは「親プロセス」をもっており,親プロセスが死んだときにはその子プロセスも死ぬことになっている.
であるので,全てのプロセスの遠い親にあたる init が死ぬとシステムがリブートするなど,init の挙動はシステム全体に大きな影響を与える.
init は起動後,/etc/rc, /etc/rc.subr, /etc/rc.conf などを読み,その設定に従って主に /etc/rc.d/以下にあるさまざまな daemon を起動するという流れで様々なソフトウェアを起動する.
より詳しくは,init のマニュアルを参照されたい.

*** 実習 [#x7427d7c]

まず,ps -axu を使って,init が確かに pid 1 で動いているのを確認しよう.

init のマニュアルを読むとカーネルのセキュリティレベルについての記述がある.
先の sysctl の出力でこれに相当するのはどこか調べよ((マニュアルをよく読むか,sysctl -a -h の結果の中から例えば secure という文字列を含んでいるところを grep すればよいよね)).
そして,その値が今どうなっているか調べよ.

また,init のマニュアルを読むと,kill ほげほげ 1 についていくつか解説が載っている.
それらを理解した上で,
  kill -INT 1
を行ってみよ(ただし,root でないと出来ないと思うよ).

** Daemon [#ma990afc]

なんらかのサービスを提供するためにバックグラウンドで常時動いている(もしくは呼び出されたら即時起動するも)ソフトウェアは一般に daemon (ダイモン,デーモン)((daemon は守護神とか,ギリシャ神話に出てくる半神半人のことで,悪魔(demon)ではないことに注意せよ. 綴りが違う. まあアメリカ人でもよく誤解するわけだが. なお,BSD 系 unix では daemon はマスコットとしての重要な役割がある. 詳しくは http://www.freebsd.org/ja/copyright/daemon.html を見よ. ))と呼ばれる.
いずれ細かく示すが,その unix で何ができるのかは daemon をみれば大体分かる.
まずはどんな daemon が今動いているのか,名前だけでもみてみよう.

*** 実習 [#pdf3306d]
ps, top, lsof についての操作をしてみて,今現在どのようなソフトウェア(daemon)が動いていて,どういう「待ち受け」をしているか推測してみよ.

* サービス要求があったときに起動されるソフトウェア [#p652d11b]
常にバックグラウンドでソフトを動かしていることには次のような利点と欠点がある.
-- すぐ反応できる(利点)
-- メモリや CPU をそれなりに消費する(欠点)

そこで,「たまに必要な時があるが特に迅速なレスポンスがなくともよい」というサービスについては「呼ばれてから起動する」というように設定しておくと無駄がない.
こうした用途に使われるのが「スーパサーバ」"inetd" ((知らない? ならばすぐマニュアルをみよう. マニュアルをすぐ見ることは unix では「よいこと」とされる))である.
inetd だけを立ち上げておけば,必要に応じて呼ばれたソフトウェアを起動して接続してくれるのだ.
ただし,inetd はその「便利さ」ゆえにセキュリティ的な緩さをもたらしやすいため,最近はデフォルトでは動いていないことが多いので,動かす際には明示的に設定しないといけないことに注意しよう.

** inetd を使うには [#t5804c2f]

inetd を使うには,
++ /etc/inetd.conf で呼ばれたら立ち上がるソフトウェアの設定をする.
++ inetd がそもそも立ち上がっていないならば立ち上げる.
++ 外から接続が必要なソフトの場合は,接続許可を出しておく.

という段階を踏めばよい.
以下,説明しよう.

** inetd を使うには: /etc/inetd.conf の書き換え [#x0d01acf]
// 黒本の p.400- を見ると丁寧に書いてある.

/etc/inetd.conf を見ると実例が書かれコメントアウトされているので,おおよそはわかるだろう.
7項目ある内容を大ざっぱに述べると,左から
++ サービス名:  /etc/services に書かれているものと一致しないといけない. inetd はservices の情報を使う.
++ ソケットタイプ: 通常は TCP ならば stream, UDP ならば dgram だ.
++ プロトコル: 通常は TCP か UDP だ. TCP はやり取りをする通信に,UDP は繋ぎっ放しの通信に向いているぞ.
++ 接続してからの inetd の挙動: 通常は TCP ならば nowait で UDP ならば wait だ. nowait には nowait/5 などとすると同時接続数を(例えばこの場合は 5までに)制限できる.
++ 立ち上げる deamon の実行権限: セキュリティを考えて特殊なユーザの権限にすることが最近は流行りだ.とりあえず root にしておけばセキュリティ以外の問題はあまり起らないが…
++ 立ち上げる deamon のpath: ソフトの在処. internal というのは inetd 自身が提供できるサービスだ.
++ 立ち上げる deamon のコマンド: コマンドラインオプションなんかも書ける.

となっている.

なお,既に inetd が動いている状態で /etc/inetd.conf を書き換えた場合は,
  kill -HUP (inetd のpid)
とすれば inetd.conf を読み直してくれる.

*** 実習 [#l3956fab]
試しに,ネットワークで接続して「今日の名言を聞せてくれる」サービスを実現してみよう(^-^)
それには,サービスを要求されたら「名言を出力する」プログラムを立ち上げるだけで良い.
そうしたプログラムには fortune というものが知られているので,これがコマンドとしてがインストールされている((インストールされていなければ,sysinstall → Configure → Distributions → games でインストールせよ))ことを確認しよう.
試しに fortune を動かしてみよう. 
&ref(./03.png);
のように,ランダムに選ばれた格言? が出力されるはずだ.

その後,/etc/inetd.conf に
  qotd stream tcp nowait root /usr/games/fortune fortune
(全部で 7項目. 項目間はタブで区切る)
と書き加えれば最初の準備は終り.

** inetd を使うには: inetd の立ち上げ [#l4fc30eb]

起動時にいつも動くようにしておくには, /etc/rc.conf に
  inetd_enable="YES"
と書いておけばよい.
//手動で立ち上げるには,root で
//  /etc/rc.d/inetd start
//とすればよい.

*** 実習 [#a18246b1]
上の通りに /etc/rc.conf に追記して再起動し,inetd が動くようにしよう.
確かに inetd が動いているか,
  lsof -i4 -P
として,上で設定したとおり port 17 で inetd が聞耳を立てていることを確認しよう.

** inetd を使うには: 外からの接続許可 [#pec750f8]

セキュリティ対策として,TCP wrappers による「接続許可」制度が FreeBSD には導入されている.
inetd はデフォルトではこの接続許可制度を利用する((利用しないようにもできる)).

具体的には,この許可がどうなっているかは /etc/hosts.allow で記述される.
記述は見れば分かるが,
  プログラム名 : 接続してくるマシン名 : 許可/不許可
というようになっており,上の行から「該当するかどうか」を調べていくようになっている.
そして,「最初に該当した設定」が有効になる仕組みだ((より詳しくは "jman hosts_access" としてマニュアルを参照せよ)).

たぶん,皆の初期設定では最初の方に
  ALL : ALL : allow
と書いてあるだろうから,まずはいじらないでおこう.
この場合,何でも無制限で接続されることになるので,計算機室では問題ないが,外部向けサーバでは注意すべき点の一つである.

*** 実習 [#q64dd1f6]
  telnet localhost 17
と自分のマシンに接続してみて,今日の名言が出力されるか見よ.
次に,少なくとも自分でない他二人のマシンに対して同様に
 telnet (相手マシン名) 17
として
&ref(./04.png);
のようにきちんと名言が出力されるか見よ.

次に,/etc/hosts.allow の ALL : ALL : allow よりも前に
  ALL : localhost : allow
  fortune : ALL : deny
という二行を書き込んでから((fortune ではなくて qotd と書きそうになるがそうではないので注意すること)),inetd を一旦止めて,そして動かそう(("kill -HUP  (inetd の pid)" でも良さそうだが,念の為)).
それには
//  /etc/rc.d/inetd stop; /etc/rc.d/inetd start
  /etc/rc.d/inetd restart
とすればよい.

それから,自分のマシンに接続してみて名言が出力されること,他のマシンから接続して貰って確かにサービスが外からは受けられないことを確認せよ.

* 定期的に起動されるソフトウェア [#h393fd3f]

上に述べた「いつも動いている」「呼ばれたら動くように待機している」というソフトウェアの他に,「定期的に動く」ソフトウェアがある.
システムの調査や update など,定期的に実行した方が良いものが相当する.

具体的な仕組みとしては inetd に良く似ており,定期的にそれらのソフトを起動する "cron" daemon があり, cron が設定に従って様々なソフトウェアを起動するようになっている.

** cron [#de5e4575]

起動後は cron は一分毎に目覚め,その度に設定ファイルをチェックしてから設定に従って条件にあうソフトウェアを動かすようになっている.
よって,設定ファイルを書き換えた後にその結果を反映させるための特別な操作は必要ない…はずだが,そうでない場合もあるようだ((つまり, 設定ファイルを書き換えたらやっぱり "kill -HUP (cron の pid)" としたほうがよい)).

cron に作業をさせるための設定ファイルは一般に crontab と呼ばれ,次のような二種類がある.
++ /var/cron/tabs/ユーザ名 … 直接エディタでいじらずに,"crontab -e" とコマンドを起動して編集する.
このコマンド "crontab" ((混同しやすいが,crontab というコマンドもあるのだ))については "jman crontab" でマニュアルを読むことができる.
また,ファイル形式については((/etc/crontab が良いサンプルになる.ただし,ユーザ名(第6項目)は不要.)) "jman 5 crontab" とするとマニュアルがひける. 
ただし,この設定ファイルに書いた内容が実行されるかどうかはそのユーザに cron の実行権限があるかどうかに依存する.
おおざっぱには,/var/cron/allow ファイルにそのユーザ名が書いてあり,/var/cron/deny ファイルにそのユーザ名が無ければよい.
++ /etc/crontab … システム用. 直接エディタで編集する.

*** 実習 [#v92a2c90]
cron を使ってみよう.

まず,通常ユーザでも cron が使えるように,/var/cron/allow を設定せよ.
具体的には,ユーザ名のみを書いた行が /var/cron/allow にあればよい(その行にスペースやタブなど,ユーザ名以外の文字が入っていてはいけない).

そうしたら通常ユーザで cron を使ってみよう.
  crontab -e 
として,適当な内容を登録してみるということだ. 例えば,
  */1 * * * * tail /var/log/messages >> 適当なファイル名
(全部で6項目. 項目間はタブで区切る. 最後の項目 "tail ... " は "tail" コマンドを使ったコマンド文なので,この中身の要素間はスペースで区切っている)
などと登録しておけば,messages の最後の 10行が 1分毎に追加され記録されることになる.
登録できたかどうか
  crontab -l 
とすればわかる.

で,実際に動いているかどうかは,(rootで) /var/log/cron を読めば cron のログが分かるので判定できる.
うまくいかない場合は,ログをみて登録に問題がないかよくみよう.
また,登録が有効になっていないというような場合は,cron に対して kill -HUP をかけよう.

(うまくいったあとは再び crontab -e などを使って登録を外し, 念の為に cron に対して kill -HUP をかけておくこと)

** periodic [#mf8f3a3d]

定期的に行われるシステム作業のうち特に典型的なものは /etc/periodic 以下におかれ,periodic コマンドで動かされる.
この periodic コマンドは cron でよばれるようになっている((/etc/crontab にperiodic を呼んでいる部分があるはずだ)).
periodic コマンドの設定は /etc/periodic.conf でなされる(特に変わった設定をしていない場合はこのファイルはなくてもよい). 
そのデフォルト値は /etc/defaults/periodic.conf に書かれている.

** newsyslog [#g64e6727]

newsyslog も cron から呼び出されることを想定しているソフトウェアで,様々なソフトウェアのログファイルの保全を行うものである.
具体的には,現在のログファイルを名前を変えて保存して,新しいファイルを用意する作業を行う.
設定は /etc/newsyslog.conf で行われる.
この設定を適切に行なっておかないと,ログファイルが大きくなりすぎてハードディスクが溢れたりする.

*** 実習 [#waeedc41]
/etc/newsyslog.conf を読んで,今の時点でどのようなログファイルがどのように保全されているか調べよ.

* レポート [#i0fd4f17]
本日行った作業について furihata あっと cmc.osaka-u.ac.jp にメールで報告せよ.
もちろん各自の
+ 所属(学部,学科)
+ 学籍番号
+ 学年
+ 氏名
+ 日時
+ 肝心のレポート内容(得た知見,作業について気づいたこと等)

を書くのを忘れないように.


* おまけ [#zfed5918]
昔使われていた 文字terminal(端末) とは,以下のようなものである.
&ref(./terminal-01.jpg,50%);
見た目は,モニタとキーボードにしか見えない.
&ref(./terminal-04.jpg,50%);
背面にネットワークへの接続コネクタがある. 右側の馬鹿でかい縦に並んだ黒いのがそれだ. 
ただし,この場合のネットワークとはせいぜい 9600bps (しょぼい Ethernetの速度の 10Mbps の約 1/1000 の速度!)でしかなく,文字の書き換えが目視できるレベルだった.
&ref(./terminal-02.jpg,50%);
当然? 画面はモノクロだ. 色は多くが(目に優しいとされる)グリーンかアンバーだった.
&ref(./terminal-03.jpg,50%);
良くみると "VT100モード" という文字が見えるだろう.
これは,文字端末のデファクトスタンダードである DEC 社の VT100 端末と互換性のあるモードで動く状態を意味している.
今でもこの vt100 モードは使われていて,
  grep vt100 /etc/termcap
などとするとそうした設定をみることができる.