Linuxのユーザランドに関する世界観です。
Linuxのユーザランドは、主に、コマンドプログラム、デーモン、設定ファイルやその他のデータファイルによって構成されている。
まず、コマンドは、多くの場合C言語によって記述されたソースファイル(*.c)あるいはヘッダファイル(*.h)に、main()関数から始まり、シェルのコマンドライン引数をmain()関数の引数として、多くの場合コマンドラインオプションをgetopt()やgetopt_long()で解析する形で、C言語の文法や関数を使って記述されている。
プログラムが小さい場合は、ひとつのプロセスとして動くひとつのプログラムがひとつあるいは数個の*.cファイルで記述されていることが多いが、大規模なプログラムでは、*.cファイルが数十以上になることもある。それぞれのソースファイルには関数の形でプログラムを記述し、ヘッダファイルがそれぞれのソースファイルの中で関数のシンボル名を共有する。
C言語では、main()関数からプログラムが始まり、if文やfor文で条件に応じて分岐・反復し、演算結果を変数に格納したり、独自に実装した関数に数値や文字列を引数として与えながらサブルーチンを実行したり、文字列やのファイル入出力やシステムコールなどのシステム関数・APIを使うことで、プログラムを*.cファイルに記述する。*.hファイルには、多くのソースファイルから呼び出される関数のプロトタイプ宣言や、共有されるグローバル変数や構造体のデータ型定義などを記述する。小さな処理であれば*.hファイルの中に関数の実体を記述することもある。
Cのソースファイルでは、他にも、必要な型や定数の宣言を行ったり、条件分岐によって違う値を返したり違う関数を実行したり、あるいは変数の中身によって違う値を関数に与えたりする。他にも、算術演算子、代入演算子、論理演算子などを使う。たとえば、フラグのようなものを設定する時は、あらかじめ定数を宣言した上で、その値をシフト演算子や論理演算子で比較する形で(たとえばFLAG_ONE | FLAG_TWOのように)、分岐を変えたり違う値を返したり与えたりする。三項演算子(~ ? ~ : ~)もよく使われる。また、ヘルプ文字列などは多くの行に渡って記述されることもある。ファイル処理を行う場合はエラー処理もする必要がある。
これらのソースファイルは、ビルドする際にひとつひとつGCCなどのCコンパイラによってコンパイルされ、アセンブルされて機械語のオブジェクトファイル*.oに変換され、リンクされて実行ファイルに変換される。C言語のソースファイルは必ず暗黙的にlibc.so.6とリンクされる。また、ダイナミックリンクの際にはリンクローダである/lib/ld-linux.so.2とリンクされる。それらが終わって、実行可能なバイナリが作成される。
ビルドは、多くの場合直接gccコマンドによってコンパイルされることはなく、MakeやAutotoolsなどのビルドシステムを使う。MakeはMakefileに従って、既にコンパイルされていて新しく再コンパイルする必要のないファイルを無視し、必要なファイルだけをコンパイルする。また、Autotoolsはシステムの環境全てをチェックしてMakefileを自動作成するconfigureスクリプトを作成することで、UNIXプログラムの移植性を高めるGNUの自動ビルドシステムで、GNU製ソフトウェアの配布に標準的に使われている。
インストールは、tarball(tar.gz)からのインストールであれば、make installでprefix(インストール対象となるシステムのバイナリの場所で、ソースtarballならば/usr/local/bin)にファイルがコピーされてインストールされる。
パッケージ管理システムからのインストールであれば、バイナリを一度作成した段階で、RPMならばspecファイルと呼ばれるシステム情報や依存するパッケージの情報などと一緒にファイルをパッケージングし、リポジトリに配布する。ユーザはリポジトリからパッケージ管理ツールを用いてこのパッケージをダウンロードし、システムのprefix(パッケージならば/usr/bin)にファイルをコピーすることでインストールする。
こうしたバイナリは、多くの場合/usr/binあるいは/binに存在する。Bashのようなシェルを使う時、これらのprefixはPATHと呼ばれる環境変数に格納される。コマンドラインシェルでコマンド名を実行すると、シェルの内部コマンドである場合を除いて、シェルはPATHの中のディレクトリからプログラムを探し、コマンドラインオプションをそれらのプログラムに渡して、プログラムを実行する。
UNIXのプログラムは、ユーザーランドだけで完結するプログラムもあれば、カーネルに処理や機能を要求する場合もある。この場合、カーネルにシステムコールを呼び出すことで、カーネルに「お願い」をする。あるいは、Cの標準ライブラリを使う場合は、libcにある関数やAPIを呼び出すこともある。この場合、標準入出力関数であればシステムのstdio.hをincludeしなければならない。他にも、socketを使ったり、あるいは標準Cライブラリに存在しない別のライブラリを呼ぶこともある(zlibやgtkなど)。このプログラムをコンパイルするためにはそのヘッダファイルが必要となり、実行するためには何らかの形でライブラリとリンクする必要がある(共有ライブラリとのダイナミックリンクなど)。また、このプログラムを再配布する場合にパッケージ化する場合は、依存関係にそのライブラリの記述をしておくことが必要となる。ソースからインストールする場合は、自分でパッケージ管理システムと同じことをする、すなわちライブラリとヘッダも何らかの方法で自分で導入・管理する必要がある。
UNIXシステム管理(コンパイラ)やUNIXシステム管理(シェル)を参照のこと。
こうしたコマンド実行のプログラムはUNIXにおいて一般的なプログラムだが、一部コマンド実行ではなく、システムが稼働している間常にサービスを提供する形で実行されるプログラムがある。それがデーモンであり、Apacheなどの「サーバーソフトウェア」は多くの場合デーモンとして実行される。
デーモンは普通のコマンドプログラムと変わらないが、永続的に実行される形式で記述され、起動スクリプトから並列起動されることで、システムにおいて常に実行される。サービスとしてイベント駆動で実行されるため、何らかの外部的なイベントがなければ処理を行わないプログラムが多い。
デーモンは、自動起動の設定がされている時は、システムの起動時にinitやsystemdから実行され、システムの終了時に停止される。その実行は、initならばシェルスクリプトによる起動スクリプトで、systemdであれば並列起動が可能なUnitファイルをsystemdが読み込む形で行われる。管理者が必要とする場合は、起動・停止・再起動や状態の確認は起動スクリプトあるいはsystemdの管理コマンドの実行によって行われる。
デーモンに限っての話ではないが、システム管理者は今のプロセスがどのように稼働しているかを監視(モニタリング)し、異常があった場合は何が起きたのかをログを取って確認すること(ロギング)を行わなければならない。このためにtopコマンドやsyslogdなどのシステムロガーなどが利用できる。
Linux initとデーモンやsystemdやUNIXシステム管理(システムロガー)やモニタリングも参照のこと。
コマンドとデーモン以外に、UNIXのファイルシステムには設定ファイルやデータファイルがある。
たとえば、/etcには設定ファイルが置かれる。多くのプログラムの設定ファイルがここに置かれるため、形式は多数の種類があるが、UNIXではシステムの設定ファイルはシンプルなプレーンテキストのファイルを用いることが多く、タブや空白を使って一行にひとつの設定を行う。あるいは、Bashのシェルスクリプトを使って、環境変数を設定したり(PATHなど)、ログイン時に必要なユーザー独自の自動起動の処理を行ったりすることができる。システムの標準設定は/etcに、一般ユーザーの設定は/home/username以下のドットファイル(.から始まるファイル)に記述されることが多い。ドットファイルは通常隠しファイルとして扱われるが、ls -alなどのオプションをつけることで表示できる。
また、/varには運用していてサイズやファイル数が変化することのあるデータファイルを設置する。ログやメール・印刷のスプールファイルが置かれるほか、HTTPサーバーのHTMLファイルもここに置かれることが多い。
他には、/mntにはマウントポイントが置かれる。新しいハードディスクやUSBメモリースティックなどをシステムに接続した時、こうしたファイルはUNIXでは適切にマウントしなければ使うことができない。明示的にマウントポイントを作る場合は/mntにサブディレクトリを作る。あるいは、USBのホットプラグなどで自動的にマウントされる場合、最近のLinuxではudevという仕組みを用いて/mediaなどに自動マウントされる。
他にも、プログラムでないデータファイルとして、フォントやドキュメントなどがあるが、こうしたアーキテクチャに依存しないファイル(Intelでも他のCPUでも動くファイル)は/usr/shareに置かれる。
設定ファイルに限らず、システムのファイルはパーミッションによって読み書き実行の適切な権限の許諾が行われる。一般ユーザーがシステムのファイルを破壊することはできない。また、別のユーザーや別のグループのファイルにアクセスすることも制限できる。設定ファイルを読んだり、プログラムを実行することはできても、それを変更することは管理者権限がなければできない。
UNIXシステム管理(システム情報と設定)やファイルシステム階層を参照のこと。
カーネルは、ブートローダによってシステムの起動時に実行され、システムにおいて常にCPUやメモリやデバイスを管理しているが、自分から何かを行うことは基本的になく、プログラムがシステムコールなどで要求した時に常にサービスを提供することができるように準備し、システムコールがあった時に適切にCPUのカーネルモードとユーザーモードを切り替えてサービスをプログラムに提供する。ファイルシステムやネットワーク接続は、プログラムが必要となった段階でカーネルにシステムコールを要求し、それに対してカーネルがデバイスへと接続して処理を行い、その結果をポインタやディスクリプタなどの形でプログラムに返すことで行われる。
また、カーネルはプログラムの実行を行う。そのため、プログラムを複数実行しようとするとカーネルがシステムを仮想化することで、CPUやメモリがそれぞれのプロセスに「占有されているかのような幻想を与える」ことで並列実行する。CPUは短いタイムスライスでプロセスをコンテキスト切り替えすることで、CPUレジスタの値を退避したり読み込んだりすることで並列実行を可能とする。またメモリは物理アドレス空間と論理アドレス空間を翻訳しながらページングすることで、アドレス空間を分割して複数作り出す。
また、カーネルはCPU、メモリ、ストレージ、ネットワーク、入出力などのデバイスを支配している。
Linuxのカーネル入門やLinuxカーネルを参照のこと。
これに対して、ウィンドウシステムであるX11では、グラフィックドライバを使ってグラフィックボードにアクセスすることで、モニターに操作画面を表示し、マウスやキーボードを管理し、ウィンドウとハードウェアデバイスとの間でメッセージがやり取りできるようにする。コマンドプログラムではない、GUIのプログラムは、カーネルの上にウィンドウシステムが君臨し、そのウィンドウシステムのサーバーにアクセスすることで、グラフィックスフォームの表示が行われる。
ボタンやメニューなどのツールキットはこのX11の仕組みを利用しており、ボタンクリックなどのウィジェット上のイベントに応じてコールバック関数を実行する。
X11におけるプログラムは、コマンドラインシェルから実行することもできるが、多くの場合ウィンドマネージャと呼ばれるプログラムから実行し、ウィンドウの終了や移動やサイズ変更や重ね合わせなどの手法はウィンドウマネージャに委ねられる。GUIからX11アプリケーションを使う場合、このウィンドウマネージャが操作環境の主となる。
ウィンドウマネージャは、多くの共通のルック・フィールや開発するためのライブラリ・フレームワークと合わせて「デスクトップ環境」と呼ばれることも多く、GNOMEやKDEやXfceがデスクトップ環境として知られているが、実際にはもっとたくさんの多くのウィンドウマネージャが存在し、好きなものを使用することができる。ただし、自分のウィンドウマネージャの使い方が分からない場合には自分で習熟する必要があるし、iBusなどの日本語入力エンジンを使う場合にはiBusと統合されているGNOMEを使うのが多くの場合良い選択である。
X11やデスクトップ環境/ウィンドウマネージャを参照のこと。