カーネルとシェル
カーネルとは
オペレーティングシステム (OS) としての中心的な機能を担うプログラムです。中心的な機能とは例えば以下の通りです。
- メモリ管理
- プロセス管理
- スケジューリングと割り込み
- デバイス(HDD , NIC 等) 管理
細かく見ると差は出てきますが、Windows でも Linux でも基本的な考え方は同じです。OS の役割については以下をご参照下さい。
シェルとは
人間が OS 上でプログラムを呼び出すための対話式プログラムのことです。
シェルは『貝』という意味で、カーネルを保護する役割と説明されることもありますが、個人的にこの説明は違和感を覚えます。
シェルがやっていることは単に、人間がキーボードを使ってプログラムを呼び出し、ディスプレイに結果が表示されることを想定した、『プログラムの呼び出しと動作確認に特化したプログラム』なのです。
シェルがプログラムを呼び出す際には (シェル以外のプログラムがそうするのと同じように) カーネルへ依頼します。具体的には後述する『システムコール』を使って依頼します。
なのでカーネルからして見れば、シェルはカーネルが管理する数あるプログラム (プロセス※) の 1 つに過ぎません。(※ プログラムはファイルとしてディスク上に配置されますが、実行されるとメモリに展開され、『プロセス』としてカーネルによって管理されます。)
補足ですが一般に、主にネットワークからのリクエストを待ち、リクエストが来た時に応答するような永続的に起動されたプログラムを『サービス』と呼び、シェル等から一時的に呼び出されて起動し、処理が終わったらすぐ終了するプログラムを『コマンド』と呼びますが、カーネルから見ればどちらも 1 つのプログラムであり、起動中は 1 つのプロセスです。それらの関係は並列です。
シェルにはいくつか種類があり、動作が若干違いますが、今は bash (読み方 : ばっしゅ) がよく使われていますので、まずはこれだけでも覚えれば OK です。
カーネルとシェルの視点の違い
カーネルはコンピュータの各コンポーネント (CPU, Memory, Disk, NIC, 等) を制御する、つまり機械を制御するために動作します。なので人間の視点は主眼ではありません。
一方シェルは、人間が使うことが前提のアプリケーションであり、人間の視点が主眼です。
カーネル空間とユーザ空間とシステムコール
カーネルは OS 起動時にメモリ上の『カーネル空間』と呼ばれる領域に展開され動作しますが、その他のプログラムは『ユーザ空間』と呼ばれるメモリ領域で動作します。
シェルも『ユーザ空間』で動作しますし、シェルから呼び出されるプログラム (コマンド) も『ユーザ空間』で動作します。このように分離することでカーネルを保護する構造となっているのです。そしてユーザ空間上のプロセスがカーネル空間にアクセスするための手段が『システムコール』です。
この辺りの詳細は以下をご参照下さい。
実行中のプログラム (=プロセス) は自分のメモリ領域内に関しては (カーネルを介することなく) 自由に使うことができますが、HDD への書き込みや NIC でネットワーク通信をするなど、自分のメモリの外に情報を送るときはカーネルに依頼します。
ですがプロセスがカーネルへの依頼内容を好き勝手にできてしまうとセキュリティ的に問題が出てきます。そのためシステムコールにはいくつかの種類が用意され、種類によって依頼できる内容が決まっています。
例えばファイルからの読み込みは read というシステムコールを使います。
同様に、ファイルへの書き込みは write、メモリの要求は malloc、新たなプロセス生成は fork や clone といった感じです。
いずれもカーネルへの働きかけが必要な処理ですが、このような定型の依頼を使わせることで、好き勝手な依頼を出せないように制限し、カーネルを保護しているのです。
つまり、カーネルはそもそも構造的に保護されていて、定型の抜け道『システムコール』により安全にカーネルの機能を利用できるようにしているのです。
一般ユーザとシステムユーザ(サービスユーザ)
一般ユーザ
ユーザ空間のプログラムには必ず『実行ユーザ』が付与されます。
例えばマルチユーザ環境の Linux の場合、一般ユーザはログインの際にシェルが起動し、一般ユーザ (人間) はそのシェルを使って操作を行います。
シェルの実行ユーザはログインユーザであり、そのシェルから呼び出されるプログラムも基本的にはそのログインユーザです。
このような人間に紐付くユーザを『一般ユーザ』と呼びます。
例えば『鈴木一郎』が Linux アカウント i.suzuki にログインして bash が起動された場合、bash の実行ユーザは i.suzuki です。
以下は一般ユーザがシェル経由で cat コマンドを使うときのイメージです。
システムユーザ (サービスユーザ)
一方、Linux サーバ等では人間が手動でログインせずともプログラムが自動で起動し、ネットワークからの要求に対して自動で応答処理を行うものもあります。
例えば DNS サーバの bind (読み方 : ばいんど) というプログラムやメールサーバの postfix (読み方 : ぽすとふぃっくす) というプログラムが有名です。
bind の実行ユーザは named (読み方 : ねいむでぃー)、postfix の実行ユーザは postfix となるのが一般的ですが、これらのユーザではログインできません。ログインシェル (ログイン成功後に操作できるようになるシェル) が設定されていないからです。(逆に言うとログインシェルを設定すればログインできますが。)
このような、ログインが許可されず、自動起動するプログラムの実行に使われるユーザを『システムユーザ (サービスユーザ)』と呼びます。
プログラムは実行ユーザ権限内でできることが限られています。例えばファイルシステムへのアクセス可否は、プログラムの実行ユーザによって判断されます。
一般ユーザはシェルを通してその場で自分で考えながら非定型処理を行います。一方、システムユーザのプログラムはあらかじめ決められた (プログラミングされた) 通りの定型処理を行います。その際シェルは使いません。
この考え方は GUI 環境の Linux や Windows においても同じです。
ログイン時にはシェルではなくデスクトップ環境を提供するための各種プログラムが起動しますが、実行ユーザはログインユーザになりますし、ファイルシステムへのアクセスもその実行ユーザによって制限されます。
おまけ 冒頭のシェルの説明に関する考察
冒頭にシェルの『カーネルを保護する役割』という説明に違和感を覚える、と申した要因の 1 つとしては、シェルに包まれてしまうとカーネルへアクセスする手段がシェル以外に無いように見えることがあります。
私が初めて Linux を学習した時、イメージがつかずに悶々としたことをよく覚えています。
UNIX が出来たのは 1960 年代、インターネット (IPv4) が一般的になったのは 1980 年代です。また、1960 年代では TSS (タイムシェアリングシステム) といった 1 台のコンピュータを複数ユーザで同時利用する仕組みができたそうです。
このような背景を考えると、UNIX が出来た当初はネットワーク経由での汎用的なサービスの概念は一般的ではなかったのでしょう。そうなるとカーネルに依頼するのはほぼ一般ユーザのシェル経由のみです。この時代においては、カーネルを保護する役目を果たしていた、というのも頷けます。
コメント
> 冒頭にシェルの『カーネルを保護する役割』という説明に違和感を覚える、と申した要因の
> 1 つとしては、シェルに包まれてしまうとカーネルへアクセスする手段がシェル以外に無いように見えることがあります。
私も同様のことを考えており、改めて調べてみると技術者視点で明らかにおかしいと思えるものが多数あったので記事を書きました。nesuke さんにとっては十分承知のことかと思いますが、ここで紹介させてください。
初学者のための正しいシェルとカーネルの概念 ~ 大学も技術者認定機関も間違いだらけ
https://qiita.com/ko1nksm/items/935be63e940f00e4c228
コメントおよびご紹介ありがとうございます。
初学者向けとのことでライトな感じを想像してたら思いの外ガチ勢でビックリしました(笑)
そして色々と勉強させていただきました。
今後も本サイトをどうぞ宜しくお願いいたします。