Linuxシステムを組み込みで使うには、通常のLinuxシステムと同様に、その運用、管理方法についても知っておく必要があります。本章では、Linuxシステムの基本的な運用、管理方法について、その背景となる仕組みも交えながら説明していきます。
Linuxシステムには、便利なコマンドが数多く用意されています。ここでは、コマンドの使い方を調べる方法について紹介します。
使い方が分からないコマンドに遭遇したら、まず、コマンド自身のヘルプを見てみましょう。コマンドに--help
オプションをつけて実行すると、多くの場合ヘルプを表示してくれます。
コマンドが--help
オプションをサポートしていない場合でも、使用方法(usage)を表示してくれることが多いでしょう。
より詳しく調べたい場合、オンラインマニュアル(manページ)が参考になります。オンラインマニュアルを表示するコマンドは、manです。manコマンドに引数としてコマンド名を渡すと、指定したコマンドのマニュアルを表示します。
例えば、catコマンドの使い方を調べるには、以下のようにします。
manコマンドは、manページの表示はページャーと呼ばれるテキスト閲覧用の別のプログラムに任せます。ATDE5では、ページャーとしてlessを使用します。lessは、viと同じような操作方法ができるページャーです。閲覧を終了するには、qキーを押してください。lessの使用方法を調べるには、man
lessを実行してください。
manページは、説明している内容によっていくつかのセクションに分かれています。セクションには以下のものがあります[]。
- 実行プログラムまたはシェルのコマンド
- システムコール (カーネルが提供する関数)
- ライブラリコール (システムライブラリに含まれる関数)
- スペシャルファイル (通常
/dev
に置かれている) - ファイルのフォーマットとその約束事。例えば
/etc/passwd
など - ゲーム
- マクロのパッケージとその約束事。例えば man(7), groff(7) など
- システム管理用のコマンド (通常は root 専用)
- カーネルルーチン [非標準]
同じ名前で、複数のセクションに説明があるmanページもあります。例えば、writeという名前のページは、writeコマンドとwriteシステムコールの二つあります。このような場合、man
writeコマンドを実行すると、writeに対応するページを検索し、もっとも適切と判断したページのみを表示します。他のセクションにあるページを見たい場合は、セクション番号を指定してmanコマンドを実行します。writeシステムコールの場合は、man 2
writeとなります。
manコマンドには、内容を検索する機能など様々な機能があります。例えば、man -k writeとすると、manページの要約文とページ名から、writeにマッチするページの一覧をすべて表示します。manコマンドの詳細な使い方を調べるには、man manを実行してください。
| 英語版manページ |
---|
ATDE5では、標準設定では言語設定が日本語になっています。そのため、日本語訳のあるmanページは日本語で表示されます。 しかし、翻訳がいまいちな場合など、英語で記述されたページを見たい場合もあるでしょう。そのような場合、LANG=C man manのように、言語を一時的に設定してmanコマンドを実行することで、英語版のmanページを見ることができます。 |
Linuxシステムは、マルチユーザー、マルチタスクなシステムです。一つのシステムに同時に複数のユーザーがログインすることもできますし、それぞれのユーザーが複数のタスク(プロセス)を実行することもできます。そのため、ユーザーの管理をおこなうことは、Linuxシステム管理の基本といえるでしょう。
ユーザーには、それぞれ一意なユーザー名とユーザーIDが割り当てられます。これらの情報は、/etc
ディレクトリにあるpasswd
ファイルに記述されています。passwd
ファイルには「:」区切りで、ユーザー名、パスワード、ユーザーID、グループID、コメント、ホームディレクトリ、使用するシェルが順番に記述されています。passwd
ファイルについての詳細は、man 5 passwdで参照することができます。
有効なユーザー名の一覧を表示するには、以下のようにします。
[ATDE ~]$
cut -d ':' -f 1 /etc/passwd
root
daemon
(中略)
atmark
sbuild
avahi-autoipd
sshd
| パスワード保存ファイル |
---|
パスワードは、暗号化されてファイルに保存されます。しかし、暗号文は時間をかければ解読可能ですので、すべてのユーザーから見えるpasswd ファイルに暗号化したパスワードを書いておくことは望ましくありません。 そのため、暗号化したパスワードは/etc ディレクトリにあるshadow ファイルに保存されています。shadow ファイルは特権ユーザーしか見ることができないようにパーミッションが設定されています。パーミッションについては、「ファイルの所有権とパーミッション」で説明します。 |
Linuxシステムでは、ユーザーを一般ユーザーと特権ユーザーの2種類に大別します。
特権ユーザーは、システム管理などをおこなうために用意されているユーザーで、一つのシステムに必ず一つ存在します。WindowsでのAdministratorのような役割です。通常、特権ユーザーにはrootという名前を付けることが多いので、rootユーザーと呼ばれることもあります。
一般ユーザーは、特権ユーザー以外のユーザーのことで、ユーザーごとに行える作業(権限)に制限があります。Linuxシステムでは、ユーザーごとに必要最小限の権限を与えることで、システム全体のセキュリティを保ちます。
ATDE5では、特権ユーザーとしてrootユーザー、一般ユーザーとしてatmarkユーザーが用意されています。
特権ユーザーはすべての権限を持っているため、誤った作業をおこなうと、ファイルをすべて消してしまうなど、システムを復旧不可能な状態に破壊してしまう可能性があります。そのため、通常の作業は一般ユーザーでおこないます。しかし、ソフトウェアのインストールなどでは、特権ユーザーの権限が必要になります。そのような場合は、一時的にユーザーを切り替えて作業をおこないます。
一般ユーザーから特権ユーザにユーザーを切り替えるには、以下のようにsuコマンドを使用します。特権ユーザーでの作業が終了したら、exitコマンドを実行し、元のユーザーに戻ることを忘れないでください。
sudoコマンドを使うと、そのコマンドだけ別のユーザーとして実行することができます。どのユーザーが、どのユーザーとして、どのコマンドを実行できるかは、/etc
ディレクトリにあるsudoers
ファイルに記述します。
ATDE5ではatmarkユーザーがrootユーザーとしてすべてのコマンドを実行できるように設定してあります。以下のようにsudoコマンドを実行すると、特権ユーザー権限でsomecommand
を実行します。なお、sudoコマンド実行時に入力するパスワードは、sudoコマンドを実行したユーザー自身(この場合ではatmarkユーザー)のパスワードです。
システムに新しくユーザーを追加するには、useraddコマンドを使用します。
newuserというユーザー名のユーザーを追加するには、以下のようにします。ユーザーの追加には、特権ユーザーの権限が必要なので、sudoコマンドを介してuseraddコマンドを実行します。-m
オプションは、ホームディレクトリを作成するオプションです。
作成したばかりのユーザーは、パスワードが設定されていないため、そのユーザーでログインすることができません。パスワードの設定、変更をおこなうには、passwdコマンドを使用します。
以下の例では、newuserのパスワードをpasswordに設定しています。
ユーザーを削除するには、userdelコマンドを使用します。-r
オプションを付けることで、ユーザーのホームディレクトリも削除することができます。
| ログインできないユーザー |
---|
shadow ファイルの二番目のフィールドには、暗号化したパスワードが記述されています。ここに、*や!と書くと、無効なパスワードになり、そのユーザーでログインすることができなくなります。
ATDEの/etc/shadow を見てみると、有効なパスワードが設定されていて、ログインできるのはrootユーザーとatmarkユーザーだけです。その他のユーザーは、サーバーやシステム管理用のユーザーとして用意されています。例えば、www-dataはWebサーバー用のユーザーです。 suコマンドを使用しても、ログインできないユーザーには切り替えることができません。しかし、sudoコマンドの-u オプションを指定すると、コマンドを実行するユーザーを指定することができます。この機能を使用すると、ログインできないユーザーとしてコマンドを実行することもできます。
|
Linuxシステムでは、ユーザーの集まりをグループという単位で管理することができます。ユーザーとグループという仕組みを使用して、システム(特にファイル)の管理を行う方法は、「ファイルの所有権とパーミッション」で詳しく説明します。
新しくグループを作成するコマンドは、groupaddコマンドです。グループを削除には、groupdelコマンドを使用します。
ユーザーは、少なくとも一つのグループに属します。ユーザーが属する一つ目のグループを、ログイン時初期グループといいます。useraddコマンドを使用して新しくユーザーを追加すると、ユーザー名と同名のグループ名が新規に作成され、ログイン時初期グループに設定されます。また、ユーザーが属しているログイン時初期グループ以外のグループを、補助グループといいます。
ユーザーが所属するグループを変更するには、usermodコマンドを使用します。usermodコマンドの-g
オプションを使うと、ログイン時初期グループを変更することができます。また、-G
オプションを使うと、補助グループを変更することができます。
Linuxシステムを含む、UNIXシステムでは「すべてのものはファイルである(Everything is a file)」という考え方があります。Linuxシステムでは、ディスク上のデータも、動作中のプロセスも、ハードウェアであるデバイスさえも、ファイルとして表現します。基本的なファイルの操作は、すべてのファイルで共通です。テキストファイルの内容を読むのも、プロセスの状態を調べるのも、デバイスからデータを読み出すのも、基本的には同じ操作でできます。
本章では、様々なファイルに対する操作方法について説明していきます。
Linuxシステムで扱えるファイルには、以下のような種類があります。
通常ファイル
いわゆる普通のファイルです。大抵の場合、ハードディスクドライブなどのストレージに記録され、テキストファイル、バイナリファイル、実行ファイル、データファイルなどとして読み書きできます。
ディレクトリ
他のファイルやディレクトリを格納することができるファイルを、ディレクトリといいます。Windowsでのフォルダと同様の概念です。
デバイスファイル
Linuxカーネル内のデバイスドライバ[]とのインターフェースとなるファイルです。スペシャルファイルやデバイスノードという場合もあります。
スペシャルファイルには、キャラクタデバイスファイルとブロックデバイスファイルの2種類があります。キャラクタデバイスファイルへの入出力は、ストリームとして扱われ、一度書き込んだ内容は取り消せず、同じ内容を2回読み出すこともできません。対して、ブロックデバイスはランダムアクセス(任意の位置への読み書き)が可能なので、同じ位置に何度も読み書きすることができます。
シリアルインターフェースや、マウス、キーボードなどはキャラクタデバイスファイルで、ハードディスクなどのストレージやメモリはブロックデバイスファイルとして扱われます。
デバイスファイルは、必ずしも物理的なデバイスと結びついているわけではありません。そのようなデバイスファイルを、疑似デバイスファイルといいます。読み込むと常に0を返す/dev/zero
、ある程度ランダムな値を返す/dev/urandom
、書き込んだ内容を捨てる/dev/null
などがあります。
シンボリックリンク
ファイル名とファイルの実体との関係をリンクといいます。シンボリックリンクは、ファイルのパス名によって別のファイルを参照するリンクです。
シンボリックに対して、ハードリンクというリンクもあります。これについては、「ファイルの属性情報(inode)」で説明します。
その他
その他のファイルの種類として、FIFO(名前付きパイプ)とUNIXドメインソケットがあります。これらは、IPC(InterProcess Communication、プロセス間通信)に使われます。
すべてのファイルはファイルの内容とは別に、ファイルの属性を表すメタデータを持っています。このメタデータのことを、inodeといいます。inodeには、以下の情報が格納されています。
表3.1 inodeが持つ情報
情報 | 説明
|
---|
種類 | 「ファイルの種類」で挙げたファイル種類のどれであるか |
所有者情報 | ファイルを所有するユーザー(所有者)及び所有するグループ(所有グループ)のID |
パーミッション | 所有者、所有グループに所属するユーザー、それら以外のユーザーに対する読み出し、書き込み、実行許可情報 |
ハードリンク数 | ファイルに対するハードリンクの数 |
サイズ | ファイルのサイズ |
時刻情報 | 最終アクセス時刻、最終修正時刻、最終属性状態変更時刻[] |
inodeにはファイル名が含まれていないことに注目してください。Linuxシステムでは、ファイル名を保持しているのはディレクトリです。inodeにはinode番号と呼ばれる一意な数値が割り振られており、ディレクトリはファイル名とinode番号の対応のリストを保持します。この、ファイル名とinodeとの対応をハードリンクといいます。一つのinodeに対し、複数のファイル名を付ける、即ち、複数のハードリンクを張ることも可能です。
このため、Linuxシステムではファイルを削除することをアンリンク(unlink)といいます。複数のハードリンクがある場合、アンリンクはディレクトリからリンクを削除するだけです。ハードリンク数が0になった時に、実際にファイルの内容が削除されます。
inodeが持つ情報は、lsコマンドに-l
オプションをつけて実行することで確認することができます。
最初の一文字は、ファイルの種類を表します。ファイルの種類によって、以下の表記になります。
表3.2 ファイル種類の表記
表記 | ファイル種類 |
---|
- | 通常ファイル |
d | ディレクトリ |
c | キャラクタデバイスファイル |
b | ブロックデバイスファイル |
l | シンボリックリンク |
「rwxr-xr-x」の部分は、ファイルのパーミッションを表します。パーミッションについては、「ファイルの所有権とパーミッション」で説明します。
続く「1」は、ハードリンクの数を表します。
「root root」は、それぞれ、所有者のユーザー名、所有グループのグループ名を表します。これらは、パーミッションの設定と密接に関わっています。
「51856」はバイト単位のファイルサイズです。
「1月 27 2013」は、ファイルの最終修正時刻を表します。
Linuxシステムでは、ファイル同士の位置関係は階層的な木構造として表現されます。ファイルシステムとは、ファイルの木構造をある形式に従って構成したものです。
木構造の最上位に位置するディレクトリをルートディレクトリといいます。全てのファイルはルートディレクトリから辿ることができます。
また、Linuxシステムのファイルシステムでは、木構造の任意の位置にファイルシステムを追加または削除することができます。この操作をそれぞれ、ファイルシステムをマウントする、アンマウントするといいます。
システムに最初にマウントされるファイルシステムをルートファイルシステムといいます。ルートファイルシステムは、システム起動時にルートディレクトリにマウントされます。
木構造の中のファイルの位置は、パスで表します。パスはあるディレクトリからファイルに到達するまでの間にあるディレクトリ名の間にスラッシュ(/
)を挟んだものです。ルートディレクトリは/
一文字で表します。パスの記述方法には二種類あり、/
から始まるルートディレクトリからの位置を表したパスを絶対パスといい、ルートディレクトリ以外からの位置を表したパスを相対パスといいます。パスには、/
以外にもいくつか特殊な意味を持つ文字があります。.
は現在のディレクトリを、..
は一つ上のディレクトリを意味します。また、多くのシェルでは~
は、ホームディレクトリを意味します。
ファイルシステムには、構造を構成する形式が異なるいくつかの種類があります。Linuxで一般的に使用されるファイルシステムには、ext2ファイルシステム、ext3ファイルシステムがあります。Armadilloのルートファイルシステムは、RAMディスク[]上に構成されたext2ファイルシステムです。ext3ファイルシステムは、ext2ファイルシステムにジャーナリング機能[]を追加したもので、耐障害性に優れます。また、Windowsで使用されるVFAT(FAT32)ファイルシステムも扱うことができます。
これらのファイルシステムは物理的なデバイスと結びついているものですが、メモリ上にしか存在しないファイルシステムもあります。その一つである仮想ファイルシステムには、カーネルの内部情報を参照又は設定できるprocfsやsysfsなどがあります。また、疑似ファイルシステム(pseudo filesystem)は、RAM上に直接ファイルシステムを構成します。擬似ファイルシステムには、tmpfsやramfsがあります。
さらに、ネットワークファイルシステム(NFS)を使用すると、ネットワーク越しのコンピューターに存在するデータを扱うことができます。
前章で説明したように、Linuxシステムではすべてのファイルに、そのファイルを所有するユーザー(所有者)とグループ(所有グループ)が設定されています。そして、所有者、所有グループに所属するユーザー、それ以外のユーザーに対して、許可する操作を決めることができます。これを、パーミッションといいます。パーミッションによって、それぞれのユーザーに対して、読み出し、書き込み、実行の可否を設定できます。
| ディレクトリのパーミッション |
---|
ディレクトリもファイルの一種ですので、パーミッションを設定できます。 ディレクトリの読み出し許可がある場合、ディレクトリ内のファイルのリストを取得することができます。 書き込み許可がある場合、ディレクトリの中にファイルを作成したり、ファイルを削除できます。 実行許可がある場合、ディレクトリに中のファイルにアクセスできます。反対にいうと、実行許可がない場合、ディレクトリ内のファイルに対して、それらのファイルのパーミッションに関わらず、読み、書き、実行のすべてを行うことができませんので、注意してください。 |
図3.12「inodeが持つ情報を確認する(ls -lコマンド)」の例では、パーミッションは「rwxr-xr-x」と表示されていました。それぞれのユーザーに対するパーミッションは、三文字ずつで表現されます。順番に、所有者、所有グループに所属するユーザー、その他のユーザーに対するパーミッションを意味します。rが読み出し許可、wが書き込み許可、xが実行許可を意味します。「rwxr-xr-x」の場合、所有者に対しては「rwx」即ち、読み、書き、実行すべてを許可します。所有グループに所属するユーザーとその他のユーザーに対しては、「r-x」即ち読みと実行だけ許可します。
パーミッションは、rwxといったアルファベットでの表記の他に、8進数で表記する場合もあります。r=4、w=2、x=1として[]、その合計で表現します。8進数表記でのパーミッションは、rwxは7、rw-は6、r-xは5、r--は4、---は0となります。そのため、「rwxr-xr-x」を8進数3桁で表記すると、「755」となります。
パーミッションを変更するには、chmodコマンドを使用します。すべてのユーザーに対して実行を許可する(つまり、実行権限を与える)場合、+x
オプションを使用します。
ファイルを新規に作成した場合のパーミッションは、ファイルの種類とumaskと呼ばれる値によって決まります。標準のパーミッションは、ディレクトリの場合rwxrwxrwx(777)、その他のファイルはrw-rw-rw-(666)です。この値からumaskを差し引いた値が、ファイルを新規作成した場合のパーミッションとなります。
umaskは、一般的には022となっています。そのため、ディレクトリを新規作成した場合のパーミッションはrwxr-xr-x(755)、通常ファイルの場合は、rw-r—r--(644)となります。
touchは、引数に指定したファイルの最終修正時刻を更新するコマンドです。存在しないファイルを指定した場合、空のファイルを作成します。
ところで、umaskコマンドを実行した際、4桁で表示されています。この、4桁目の値は、特別なパーミッションを意味します。特別なパーミッションには、SUIDビット(set-uid bit)、SGIDビット(set-gidbit)、スティッキービット(sticky bit) の3種類があります。
8進数で表すと、SUIDビットがセットされている場合4、SGIDビットは2、スティッキービットは1となります。この値は、chmodコマンドやumaskコマンドでパーミッションを8進数で指定する場合の4桁目として使用できます。
SUIDビットが設定されていて実行許可が与えられている場合、そのファイルを実行すると、実行したユーザーに関わらず、ファイル所有者として実行されます。この仕組みは、例えばpasswdコマンドに使用されています。passwdコマンドがアクセスする/etc/shadow
ファイルにはパスワードという重要な情報が記述されているため、特権ユーザーであるrootユーザーにだけ読み書きを許可しています。しかし、一般ユーザーが自分のパスワードを変更できないと不便です。そのため、passwdの実行ファイルにはSUIDビットがセットされており、所有者はrootになっています。すると、一般ユーザーでpasswdを実行した場合でもrootとして実行されるため、/etc/shadow
ファイルにアクセスすることができます。
ls -lでは、SUIDビットがセットされていて所有者の実行が許可されているファイルの場合、所有者の実行許可の表示がxではなくsとなります。
なお、whichコマンドは、引数に指定したコマンドが実際に実行するファイルの絶対パスを表示するコマンドです。
SGIDビットは、SUIDビットと同様の仕組みです。実行したユーザーが所属するグループではなく、所有グループとして実行されます。ls
-lでは、SGIDビットがセットされていて所有グループに所属するユーザーに対する実行が許可されているファイルの場合、所有グループの実行許可の表示がxではなくsとなります。
スティッキービットは、ディレクトリとその他の実行ファイルに指定された時では挙動が異なります。
ディレクトリの場合、ディレクトリ内にあるファイルは、ファイル所有者とディレクトリ所有者のみが削除できます。この仕組みは、/tmp
ディレクトリで使用されています。一時的に使用するファイルを置く/tmp
ディレクトリには、すべてのユーザーに対して読み、書き、実行を許可していますが、ファイルを作成したユーザーか/tmp
ディレクトリの所有者であるrootユーザーしかファイルを削除することができません。ls -lでは、スティッキービットがセットされていてその他のユーザーに対する実行が許可されている場合、その他のユーザーの実行許可の表示がxではなくtとなります。
実行可能ファイルに対してスティッキービットを設定した場合、そのコードをスワップ上に維持します。こちらの機能はあまり使用されていないようです。
デバイスファイルは、メジャー番号とマイナー番号という二つの番号によって、対応するデバイスドライバを識別します。メジャー番号は、デバイスの種類を表します。デバイスの型(キャラクタ型かブロック型)とメジャー番号が同じデバイスファイルは、ほとんどの場合、同じデバイスドライバを使用します。また、マイナー番号によって、同じデバイスの型とメジャー番号を持つデバイスのグループ内のデバイスを識別します。
デバイスファイルは、通常/dev
ディレクトリ以下に配置されます。
ls -lでデバイスファイルを調べた場合、他のファイルとは異なった出力となります。
最初の一文字は、デバイスファイルの型を表します。「c」がキャラクタデバイスファイル、「b」がブロックデバイスファイルを意味します。所有者、所有グループの後に表示されている「4, 64」という番号が、それぞれメジャー番号とマイナー番号を表します。メジャー番号4は、シリアルポートに対応するデバイスファイルを意味します。メジャー番号とデバイスの対応は、Linuxカーネルのドキュメントに記載されています。linux-[version]
-at/Documentation/devices.txt
を参照してください。
デバイスファイルを作成するには、mknodコマンドを使用します。例えば、5個目のシリアルポートに対応するデバイスファイルを作成するには、以下のようにします。
通常は、上記のようにmknodコマンドを使用してデバイスファイルを作成します。しかし、Linuxシステムはデバイスのホットプラグ[]が可能です。システム動作中接続される可能性のあるデバイスに対するデバイスファイルをあらかじめすべて作っておくことは、現実的ではありません。そこで、デバイスが接続された時点でデバイスファイルを作成するudevという仕組みがあります。udevを使用すると、デバイスファイルの自動作成の他、デバイスが接続または切断された時点で任意のコマンドを実行する、といったことが可能になります。
プログラムの実行可能ファイルは、機械語の実行コードとデータから構成されます。多くのLinuxシステムでは、実行可能ファイルはELFと呼ばれる形式で保存されています。
実行可能ファイルは、ローダーと呼ばれるプログラムによってメモリにロードされ、実行が開始されます。この際、ローダーはプログラムの再配置やメモリの初期化などをおこないます。
実行中のプログラムをプロセスといいます。
Linuxシステムは、マルチタスクなので複数のプロセスを同時に実行できます。しかし、CPUは通常1個[]しかありません。そこで、プロセスには仮想的なCPUとメモリ空間が与えられます。カーネルは、各プロセスがCPUを使う時間とメモリ領域を管理します。カーネルは、プロセスがCPUを使ってよい時間が過ぎたら、そのプロセスの実行を停止し別のプロセスの実行を開始します。また、プロセスから見えている仮想的なメモリ空間と物理メモリとの橋渡しをおこないます。そのため、プロセスはあたかもシステム全体を占有しているように振る舞う事ができます。
プロセスが使用するメモリ空間は、いくつかの領域(セクション)に分かれており、それぞれ用途が異なります。セクションには以下のものがあります。
- テキストセクション: 機械語の実行や定数などを収めた、読み取り専用で実行可能な領域。
- データセクション: グローバル変数やスタティック変数のうち初期値が設定されたデータを収めた領域。
- BSSセクション: グローバル変数やスタティック変数のうち初期値が設定されていないデータを収めた領域。0で初期化される。
- スタック: 関数呼び出し時に一時的なデータ用に使用される領域。
- ヒープ: プロセスが要求する動的なメモリ用に使用される領域。
psコマンドを使用すると、現在実行中のプロセスの一覧を見ることができます。
「CMD」の欄に表示されているものが、プロセスを実行したコマンドです。「PID」は、プロセスIDと呼ばれるプロセスを一意に識別する数値です。
プロセスは、プロセスの状態や所有するリソース(タイマー、ファイル、ハードウェア、ネットワーク接続、プロセス間通信で使用するもの)、そのプロセスを実行したプロセスのID(親プロセスID、PPID)などの情報を保持しています。
シグナルとは、カーネル又はプロセスからプロセスに対して送られる非同期なメッセージです。通常、メモリアクセス保護違反(segmentation fault)や特殊なキー入力(例えばCtrl+C)などのイベントが起こったことをプロセスに通知するために使用されます。
プロセスにシグナルが送られた場合、プロセスは以下の挙動のうちいずれかを行います。
- 終了する
- シグナルを無視する
- プロセスのコア[]をダンプ(表示)して終了する
- 一時停止する
- 停止中であれば再開する
- シグナルを捕捉し、プロセス自身で指定したシグナルハンドラーで処理を行う
シグナルは、シグナル名かシグナル番号(整数値)で表されます。
代表的なシグナルを以下に示します。シグナルハンドラーを設定していない場合、標準の挙動をおこないます。捕捉できないシグナルは、必ず標準の挙動をおこないます。
表3.3 代表的なシグナル
シグナル名 | 番号 | 捕捉可能か | 標準の挙動 | 説明 |
---|
SIGHUP | 1 | Yes | 終了 | 制御端末のハングアップ、制御しているプロセスの死 |
SIGINT | 2 | Yes | 終了 | キーボードからの割り込み(Ctrl+C) |
SIGQUIT | 3 | Yes | コアダンプ | キーボードからの割り込み |
SIGABRT | 5 | Yes | コアダンプ | abort関数による終了 |
SIGKILL | 9 | No | 終了 | 強制的な終了 |
SIGSEGV | 11 | Yes | コアダンプ | 不正なメモリ参照 |
SIGTERM | 15 | Yes | 終了 | 終了シグナル |
SIGUSR1 | 10,16,30 | Yes | 終了 | ユーザー定義シグナル1 |
SIGUSR2 | 12,17,31 | Yes | 終了 | ユーザー定義シグナル1 |
SIGSTOP | 17,19,23 | No | 停止 | プロセスの一時停止 |
SIGCONT | 18,20,24 | Yes | 再開 | プロセスの再開 |
killコマンドで、プロセスに任意のシグナルを送ることができます。killコマンドには、シグナルを送るプロセス名とシグナル名(SIGを除いたもの)を指定することができます。killコマンドでシグナル名を指定しない場合、SIGTERMが送られます。
それぞれのプロセスは、独立した仮想的なメモリ空間を与えられて動作するため、基本的に他のプロセスのデータにアクセスすることはできません。この特徴により、あるプロセスが誤って他のプロセスのデータを書き換えるということがないため、セキュリティやシステムの堅牢性を保つことができます。
しかし、場合によっては複数のプロセスが協調動作をしたり、情報のやりとりを行う必要があったりします。そのために、Linuxカーネルはプロセス間通信(Inter Process Communication、IPC)の仕組みを提供しています。
IPCを行う方法には、以下のものがあります。
- パイプ
- 名前付きパイプ(FIFO)
- メッセージキュー
- 共有メモリ
- セマフォ
- インターネットソケット
- 名前付きソケット(UNIXドメインソケット)
端末(ターミナル)とは、ディスプレイと入力装置(キーボード)から構成され、コンピューターの使用者がホストコンピューターとのやりとりを行うために使用される装置です。ホストコンピューターと端末は、シリアル通信線や電話線、Ethernetなどで接続されます。コンピューターが高価で、一つのコンピューターを複数人で共有していた時代は、一つのホストコンピューターに複数の端末を接続して使用していました。コンピューターが十分に安くなり、一人一台の「パーソナルな」コンピューター(PC)を持てるようになった現在では、端末専用装置を見かけることはほとんどありません。
今日では、端末専用装置の代わりに、PC上で動作する端末エミュレーターを使用します。Armadilloと開発用PCをシリアルケーブルで接続し、シリアル通信ソフトウェアで操作をおこなう場合、シリアル通信ソフトウェアを端末エミュレーターとして使用していることになります。大抵の端末エミュレーターでは、端末専用装置として事実上の標準であったVT100の互換機能を持っています。
Linuxシステムでは、様々な装置を端末とみなして、互いに通信することができます。PCに接続されたモニターはコンソール端末、シリアルポートを介して接続されているコンピューターはシリアル端末、ネットワークを介して接続されているコンピューターは擬似端末とみなします。Linuxシステムでは、端末との通信をtty[]という名前のついたデバイスファイル(ttyデバイス)を介しておこないます。
Linuxシステムでは、シリアルポートに対する読み書きは、シリアルポートに対応するttyデバイスへの読み書きとして扱います。つまり、シリアルポートの先にシリアル端末が繋がっているとみなしています。例えば、WindowsではCOM1と表現される、PCの一番目のシリアルポートへの読み書きは、Linuxシステムでは通常、/dev/ttyS0
に対しておこないます。
| 文字列「hello」をシリアルポートから送信します。 |
| file の内容をシリアルポートから送信します。 |
| シリアルポートに受信した内容を表示します。 |
シリアルポートの通信速度等の設定確認や変更は、sttyコマンドで行うことができます。sttyコマンドでは、-F
オプションで設定の確認や変更をおこなうttyデバイスを指定します。詳細は、man 1 sttyを参照してください。
Armadilloでは、シリーズによってシリアルポート(シリアルインターフェース)に割り当てているデバイスファイル名が異なります。Armadillo-400シリーズでは、/dev/ttymxc#
(#は10進数値文字)となり、/dev/ttymxc1
がシリアルインターフェース1に割り当てられています。詳細は、「Armadillo-400 シリーズ ソフトウェアマニュアル」の「Linuxカーネルデバイスドライバ仕様」の「UART」をご参照ください。
USB to シリアル変換ケーブルを使った場合、変換ケーブル内のICによってデバイスファイル名が異なります。通常、/dev/ttyUSB#
や/dev/ttyACM#
になります。
コンソール端末、あるいは単にコンソールとは、システム管理用の端末のことです。通常、ホストコンピューターに接続されたディスプレイとキーボードをコンソールとして使用します[]。Linuxシステムでは、ホストコンピューターに接続されたディスプレイに表示できる、仮想的なコンソールを複数持つことができます。仮想コンソールには、/dev/tty#
を介してアクセスします。/dev/tty0
は特別な意味を持ち、現在の仮想コンソールを意味します。
Debian GNU/Linux 7.0では、Ctrl+Alt+F#
を入力することで、仮想コンソールを切り替えることができます[]。Ctrl+Alt+F1で一番目の仮想コンソール(/dev/tty1
)に切り替えます。Debian GNU/Linux 7.0では、F1からF6までがテキストコンソールに割り当てられています。Ctrl+Alt+F7で元のGUI画面に戻ることができます。
端末が使用しているttyデバイスは、ttyコマンドで調べることができます。Ctrl+Alt+F1で仮想コンソールを切り替え、ログインしてからttyコマンドを実行すると、以下のように表示されます。
/dev/console
は、システムメッセージを表示するコンソール(システムコンソール)用のデバイスファイルです。カーネルメッセージは/dev/console
に送信されます。
どの端末をシステムコンソールとして使用するかは、カーネルの起動時に渡すカーネルパラメーターで指定できます。Armadillo-400シリーズでは、標準状態のカーネルパラメーターとして「console=ttymxc1,115200」を渡しているので、シリアルインターフェース1がシステムコンソールとして使用されます。ATDE5
では「BOOT_IMAGE=/vmlinuz-3.2.0-4-amd64 root=/dev/mapper/atde5-root roquiet」を渡しており、システムコンソールを明示的に指定していません。この場合、カーネルは最初に/dev/tty#
を調べ、次にシリアルデバイスを順番に調べます。そして、最初に使用可能であったものをシステムコンソールとして使用します。
カーネルパラーメーターは、/proc/cmdline
ファイルで調べることができます。
擬似端末は、シリアル端末やコンソール端末のように、必ずしも物理的に接続されているとは限らない端末との通信に使用されます。ATDE5の[アプリケーション]-[アクセサリ]-[端末]メニューで起動できる端末エミュレーター(Gnome端末)でttyコマンドを実行すると、/dev/pts/0
のように表示されます。
擬似端末は、マスターとスレーブがセットになって使用されます。スレーブへ書き込んだデータは、マスターから読み出すことができ、また、マスターへ書き込んだデータはスレーブから読み出すことができます。/dev/pts/#
はスレーブで、マスターは常に/dev/ptmx
です。マスターは/dev/ptmx
一つだけですが、プロセスが/dev/ptmx
をオープンすると、都度/dev/pts
ディレクトリに対応するスレーブ用のデバイスファイルが作成され、以後そのスレーブとやりとりを行うことができるようになっています。このような命名規則をUNIX98 pty namingといいます。詳細は、man 4 ptsを参照してください。
UNIX98 pty namingを採用せずに、スレーブにttypN
(N
は16進数値文字)、マスターにptypN
という名称を使用する場合もあります。例えば、作業用PCから標準イメージで動作するArmadillo-440にtelnetで接続する[]と、ttyコマンドで確認できるttyデバイスは/dev/ttyp0
になります。telnetクライアントが/dev/ttyp0
へ書き込んだデータは、telnetサーバーが/dev/ptyp0
から読み出します。
Linuxシステムでは時間の管理は二つの時計、システムクロックとハードウェアクロックでおこなっています。
システムクロックはLinuxカーネルが管理している時計で、タイマー割り込みによって駆動されます。システムクロックは、UTC(Universal Time, Coordinated、協定世界時) 1970年1月1日 00時00分00秒(紀元、エポック)からの経過秒数で表されます。Linuxシステムでは、システムクロックがすべての動作の基準となります。システムクロックを参照、設定するには、dateコマンドを使用します。
ハードウェアクロックは、CPUとは独立したRTC(リアルタイムクロック)によって管理される時計です。システムに電源が供給されていない間も、バッテリや外部電源などで動作しつづけます。Linuxシステムは、起動時にハードウェアクロックを参照し、システムクロックを設定します。
ATDE5でdateコマンドを実行すると、図3.26「システムクロックの参照(dateコマンド)」で示したようにJST(Japan Standard Time、日本標準時)で表示されます。システムクロックは、カーネル内部では常にUTCを基準としたエポックからの経過秒数で管理されています。しかし、dateコマンドはシステムの設定に従ってローカルタイムでの表示を行います。
dateコマンドなどの時間を扱うコマンドでどのタイムゾーンを使用するか、即ちローカルタイムのタイムゾーンはTZ環境変数で指定することができます。環境変数については、「環境変数」を参照してください。また、TZ環境変数の指定方法については、man 3 tzsetを参照してください。
TZ環境変数が指定されていない場合、/etc/localtime
ファイルで指定されているタイムゾーンが使用されます。ATDE5ではTZ環境変数は設定されていないので、図3.26「システムクロックの参照(dateコマンド)」で表示がJSTになっていたのは、このファイルの設定によるものです。/etc/localtime
ファイルは、タイムゾーンディレクトリ(/usr/share/zoneinfo
)にあるtzfile形式のファイルのコピーとなっています。ATDE5の標準設定では、/usr/share/zoneinfo/Asia/Tokyo
です。Debian GNU/Linux 7.0では、タイムゾーンの設定はdpkg-reconfigure tzdataで変更することができます。
ハードウェアクロックはUTCで保存するかローカルタイムで保存するか、選択することができます。UTCで保存しておけば、タイムゾーンを変更してもハードウェアクロックを変更しなくとも良いので、通常は問題ないでしょう。しかしながら、Windowsではローカルタイムで保存します。そのため、PC Linuxではローカルタイムをハードウェアクロックに保存することが多いようです。
システムクロックとハードウェアクロックは、長期的な視点ではどちらも正確ではありません。通常、二つの時計は異なるクロックソースを元にして動作するので、相対的にずれていきます。また、国際原子時(TAI)と比較すると、どちらの時計も精度が低いので、絶対的な時刻も徐々にずれていきます。
時刻を正しく保つには、いくつかの方法があります。
最も信頼性の高い方法は、NTP(Network Time Protocol)を使用することです。インターネットに接続できるか、信頼できるNTPサーバーを使用できる場合、NTPによりシステムクロックを設定することができます。Debian GNU/Linux 5.0では、ntpd(NTP サーバー)または ntpdateコマンド(NTPクライアント)でNTPによる 時刻設定を行うことができます。
NTPを使用できない場合、クロックの規則的なずれ(ドリフト)を利用して補正を行なうことができます。システムクロックとハードウェアクロックは、時刻が進むか遅れる方向に同じ程度ずれると想定して、定期的にずれた分時刻を設定しなおすという方法です。
hwclockコマンドの時刻合わせ機能を使用すると、ハードウェアクロックのドリフトを補正することができます。hwclockコマンドは、--set
オプションまたは--systohc
オプションを伴って実行されると、ハードウェアクロックを設定します。このとき、/etc/adjtime
ファイルに現在の時刻を最後に時計合わせ(calibration)をした時刻として記録します。ハードウェアクロックがずれた後、再度、--set
オプションまたは--systohc
オプションによりハードウェアクロックが設定されると、hwclockコマンドは/etc/adjtime
ファイルの最後に時計合わせをした時刻を更新するとともに、1日あたりの時刻のずれを記録します。以降は、--adjust
を伴ってhwclockコマンドを実行すると、1日あたりの時刻のずれから補正すべき時刻を計算してハードウェアクロックを設定します。また、/etc/adjtime
ファイルに最後に時刻を補正(adjustment)した時刻を記録します。詳細は、man 8
hwclockを参照してください。
adjtimexコマンドを使用すると、システムクロックのドリフトを徐々に補正することができます。adjtimexコマンドでは、NTPやハードウェアクロックを参照して、システムクロックのドリフトを測定し、それを補正するための値をカーネルに設定します。例として、NTPサーバーを参照する方法を以下に示します。
まず、ntpdが動作している場合、停止してください。adjtimexコマンドでドリフトを測定している途中に、ntpdがシステムクロックを更新してしまうと、正確な測定ができなくなります。
次に、adjtimexをインストールします。NTPの参照にはntpdateコマンドを使用するので、同時にインストールします。
adjtimexコマンドに--host
オプションを指定すると、ntpdateを使用して補正のためのデータを取得します。この例では、NTPサーバーには独立行政法人情報通信研究機構(NICT)のサーバーである、ntp.nict.jpを指定しています。--log
オプションも同時に指定することで、補正のためのデータをログファイル(/var/log/clocks.log
)に書き込みます。ハードウェアクロックやシステムクロックをadjtimex以外で書き換えていない場合は、二つの質問にy
と答えてください。
--print
オプションを指定すると、現在の設定を確認することができます。また、補正のためのデータをカーネルに設定するには、--adjust
オプションを使用します。その際、--review
オプションを付けると、ログファイルに記録したデータをもとに設定します。
システムクロックの分解能は、カーネルコンフィギュレーションで定義されるHZ定数によって決まります。HZが100の場合、タイマー割り込みの間隔(jiffy)は1秒間に100回、つまり、0.01秒(10ミリ秒)に1回です。タイマー割り込みの度に、カーネル内で管理されているjiffiesと呼ばれる値が1ずつ増加していきます。システムクロックはjiffiesを元に計算されます。i386やx86_64アーキテクチャで動作するLinuxでは、HZは100、250(標準の値)、300、1000を選択することができます。Armadillo-400シリーズでは、HZは100です。
Linux 2.6.21より前のカーネルでは、プロセスをスリープさせたりタイマー[]を扱うシステムコールの精度はシステムクロックの分解能に依存していました。そのため、HZが100の場合、10ミリ秒以下の時間スリープするといった動作はできませんでした。
しかし、Linux 2.6.21からハイレゾリューションタイマー(High-Resolusion Timers)がサポートされました。ハイレゾリューションタイマーが有効なシステムでは、スリープやタイマーに関するシステムコールの精度はHZによる制約を受けず、CPUが処理できる限りの短い時間で反応できます。Linux 2.6.21以降のカーネルを採用しているシステムがすべてハイレゾリューションタイマーを使用できるわけではなく、アーキテクチャごとにサポート状況は異なります。i386やx86_64アーキテクチャのPC Linuxでは、通常ハイレゾリューションタイマーが有効になっていますが、VMware Player上で動作するATDE5では無効です。Armadillo-400シリーズではハイレゾリューションタイマーが有効になっています。
ロケールとは、多言語を扱うプログラムがどのようなルールに基づいて処理するべきかを定めたルールの集合です。プログラムは、ロケールに基づいて適切な言語や表記でメッセージを表示したり、文字集合を扱うことができます。
ロケールはいくつかのカテゴリに分かれており、それぞれ個別に設定できます。カテゴリには以下のものがあります。
- LC_COLLATE: アルファベット文字列の比較方法を定義します。
- LC_CTYPE: 文字の判定、変換操作や多バイト文字操作の方法を定義します。
- LC_MONETARY: 小数点やカンマの位置など、通貨に関する数字の表示方法を定義します。
- LC_MESSAGES: メッセージ表示に使用する言語を定義します。
- LC_NUMERIC: 数字の扱いを定義します。
- LC_TIME: 時刻の表示方法を定義します。
ロケールは、LANGUAGEとLC_ALL及び上記のカテゴリに対応する環境変数によって設定できます。複数の環境変数が設定された場合、以下の優先順位に従って反映されます。
- 環境変数LC_ALLが設定されている場合、LC_ALLの値が使用されます。
- LC_ALL以外のLC_で始まる環境変数が設定されている場合、そのカテゴリにはその値が使用されます。
- 環境変数LANGが設定されている場合には、LANGの値が使用されます。
- いずれの環境変数も設定されていない場合、標準のロケール(Cロケール[])が使用されます。
環境変数は端末やプロセスごとに設定できます。そのため、ロケールの設定も端末やプロセスごとに行われることになります。
それぞれの環境変数に設定するロケール名は、language
[_territory
][.codeset
][@modifier
]という書式になります。language
はISO639[]で規程される言語コードです。また、territory
はISO 3166で規程される国名コード[]です。codeset
は、ISO-8859-1やUTF-8のような文字集合や文字符号化識別子です。
localeコマンドに-a
オプションを付けて実行することで、システムでサポートされているすべてのロケールを得ることができます。
また、localeコマンドを引数なしで実行すると、現在の設定を確認することができます。
図3.26「システムクロックの参照(dateコマンド)」で示したように、ATDE5でdateコマンドを実行すると日本語で表示されます。これを、英語で表示するには環境変数LANGを設定してdateコマンドを実行します。
近年の組み込みシステムでは、ネットワークシステムを持つものが増えています。Armadilloシリーズのすべての製品も、ネットワーク機能を有しています。Linuxシステムは様々なネットワーク機能を備えており、このことが組み込みシステムでLinuxを採用する動機となることも多いようです。ここでは、Linuxシステムでネットワークを扱う方法について説明します。
Linuxシステムでは、「すべてのものはファイルである(Everything is a file)」という考え方の元、様々なものをファイルとして扱いますが、ネットワークインターフェースは例外です。ブロックデバイスやキャラクタデバイスの場合、デバイスファイル名を指定してファイルをオープンすることで、カーネル内のデバイスドライバにアクセスすることができます。ネットワークインターフェースの場合、インターフェース名でアクセスするインターフェースを指定します。
ネットワークインターフェースの状態を取得、設定するには、ifconfigコマンドを使用します。ifconfigコマンドを引数を指定せずに実行すると、動作中の(アップ状態の)すべてのインターフェースの状態を表示します。
「eth0」、「lo」がインターフェース名です。Link encapがネットワークインターフェースの種類を示します。「eth0」はEternetに対応したインターフェース名です。Ethenetインターフェースが二つ以上あるときは、「eth1」「eth2」と数値部分が増えていきます。「lo」はローカルループバックインターフェースです。自分自身がサーバーにもクライアントにもなるような場合に使用します。
ハードウェアアドレス(HWaddr)はMACアドレス、inetアドレス(inet addr)はIPv4のIP アドレス、ブロードキャスト(Bcast)はブロードキャストアドレス、マスク(Mask)はサブネットマスク、inet6アドレス(inet6 addr)はIPv6のIPアドレスをそれぞれ示します。それ以外は、ネットワークインターフェースの状態を示しています。
ifconfigコマンドはインターフェース名を指定して実行することで、特定のネットワークインターフェースの状態を取得、設定できます。例えば、eth0のIPアドレスを「192.168.0.2」に変更するには、以下のようにします。
ifconfigコマンドで設定したネットワークインターフェースの状態は、一時的なもので、再起動すると失われてしまいます。恒久的な設定は、/etc/network/interfaces
ファイルに記述します。interfaces
ファイルに記述した設定は、ifupコマンドでネットワークインターフェースをアップしたときに適用されます。
ATDE5の標準設定では、interfaces
ファイルは以下のようになっています。
「auto lo」という行は、ifup --allを実行したときに「lo」をアップするよう指示しています。
「iface lo inet loopback」では、「lo」をTCP/IPネットワークのローカルループバックインターフェースのインターフェース名として指定しています。
「allow-hotplug eth0」は、ホットプラグイベント[]が発生した際に「eth0」をアップするよう指示しています。
「iface eth0 inet dhcp」は、「eth0」をTCP/IPネットワークのインターフェース名として指定しています。また、ネットワーク設定はDHCPによって取得するよう指示しています。
「allow-hotplug usb0」は、ホットプラグイベントが発生した際に「usb0」をアップするよう指示しています。
「iface usb0 inet」は、「usb0」をTCP/IPネットワークのインターフェース名として指定しています。また、ネットワーク設定はIPv4LLという機構によって取得するよう指示しています。
/etc/network/interfaces
ファイルの設定方法の詳細は、man 5 interfacesを参照してください。
ネットワークで結ばれたコンピューター同士で通信を行う場合、実際にはそれぞれのコンピューター上で動作するプロセス間で通信を行うことになります。IPアドレスによって、ネットワーク上にあるコンピューターを識別することができます。しかし、IPアドレスだけでは、コンピューター上で動作するプロセスを識別することはできません。そこで、ポート番号を使用します。
接続を受け付けるプロセスは、ポート番号を指定して他のプロセスからの接続を待ち受けます。接続を行うプロセスは、IPアドレスとポート番号を指定して接続することで、特定のプロセスとの通信を開始することができます。
ポート番号は、0〜65535の範囲内の数値を取ります。このうち、いくつかの番号は用途が決まっています。このようなポート番号をウェルノウンポート(well-known port)と呼びます。どのポート番号がどのような用途に使用されるかは、/etc/services
ファイルに記述されています。また、man 5 servicesにも説明がありますので、参照してください。
netstatコマンドを使用すると、どのポートが現在使用されているか調べることができます。例えば、FTPサーバー(21番ポートを使用)とTelnetサーバー(23番ポートを使用)が動作しており、それぞれにクライアントからのアクセスがある場合、以下のように表示されます。
ネットワークに繋がっているコンピューターのことを、ホストまたはノードと呼びます。クロス開発においては、クロスコンパイルを行う作業用PCをホストと呼び、開発対象をターゲットと呼んでいましたが、ここでは単にネットワークに接続されているコンピューターという意味でホストという言葉を使用します。
IPアドレスを使用すると、ネットワーク上のホストを識別することができます。しかし、IPアドレスは人間にとっては覚えにくいものです。そこで、IPアドレスに対応する名前を付けることができます。この、ホストを識別する名前をホスト名(hostname)といいます。ホスト名は、hostnameコマンドを使用して調べることができます。
ホスト名とIPアドレスの対応は、/etc/hosts
ファイルに記述されています。ATDE5では、以下の内容になっています。
「localhost」というホスト名が「127.0.0.1[]」、「atde5」というホスト名が「127.0.1.1」に対応付けられています。ホスト名からIPアドレスを特定することを、名前解決といいます。
ホスト名はローカルネットワークだけではなく、インターネットでも使用できます。例えば、「www.atmark-techno.com」や「armadillo.atmark-techno.com」はホスト名です。「www.atmark-techno.com」のようなインターネット上にあるホストのIPアドレスをすべてhosts
ファイルに書くわけにはいきませんので、インターネットドメインネームシステム(DNS)という名前解決の仕組みがあります。DNSサーバーにホスト名を問い合わせると、対応するIPアドレスを返してくれます。
DNSへのアクセスに使用する機能は、Cライブラリが提供します。この機能のことをリゾルバ(resolver)といいます。リゾルバの設定ファイルは/etc/resolv.conf
ファイルです。resolv.conf
にDNSサーバーのIPアドレスを指定することができます。詳細は、man 5 resolv.confを参照してください。
ネットワーク設定が正しく行われたことを確認するため、ホスト同士で通信が可能かを調べるには、pingコマンドが使用できます。pingコマンドは、対象のホストへパケットを送信し、対象のホストはパケットを受信すると応答パケットを返信します。対象ホストのパケットのやりとりが正常にできれば、最低限のネットワーク設定は正しいことを確認することができます。
通信可能なホストを指定してpingコマンドを実行すると、以下のようにホストからの応答が表示されます。
ホストとの通信ができなかった場合、以下のような表示になります。