Linuxシステムの仕組みと運用、管理

Linuxシステムを組み込みで使うには、通常のLinuxシステムと同様に、その運用、管理方法についても知っておく必要があります。本章では、Linuxシステムの基本的な運用、管理方法について、その背景となる仕組みも交えながら説明していきます。

3.1. コマンドの使い方を調べる

Linuxシステムには、便利なコマンドが数多く用意されています。ここでは、コマンドの使い方を調べる方法について紹介します。

使い方が分からないコマンドに遭遇したら、まず、コマンド自身のヘルプを見てみましょう。コマンドに--helpオプションをつけて実行すると、多くの場合ヘルプを表示してくれます。

[ATDE ~]$ cat --help
使用法: cat [オプション] [ファイル]...
ファイル、または標準入力を連結し、標準出力に出力します。

  -A, --show-all           -vETと同じ
  -b, --number-nonblank    空行を除いて行番号を付け加える。-n より優先される
  -e                       -vEMと同じ
(後略)

図3.1 --helpオプションでコマンドの使用方法を調べる


コマンドが--helpオプションをサポートしていない場合でも、使用方法(usage)を表示してくれることが多いでしょう。

[ATDE ~]$ cd --help
bash: cd: --: 無効なオプションです
cd: 使用法: cd [-L|[-P [-e]]] [dir]

図3.2 コマンドの使用方法を調べる(--helpオプションをサポートしていない場合)


より詳しく調べたい場合、オンラインマニュアル(manページ)が参考になります。オンラインマニュアルを表示するコマンドは、manです。manコマンドに引数としてコマンド名を渡すと、指定したコマンドのマニュアルを表示します。 

例えば、catコマンドの使い方を調べるには、以下のようにします。

[ATDE ~]$ man cat

図3.3 catコマンドの使用方法を調べる


manコマンドは、manページの表示はページャーと呼ばれるテキスト閲覧用の別のプログラムに任せます。ATDE5では、ページャーとしてlessを使用します。lessは、viと同じような操作方法ができるページャーです。閲覧を終了するには、qキーを押してください。lessの使用方法を調べるには、man lessを実行してください。

manページは、説明している内容によっていくつかのセクションに分かれています。セクションには以下のものがあります[13]

  1. 実行プログラムまたはシェルのコマンド
  2. システムコール (カーネルが提供する関数)
  3. ライブラリコール (システムライブラリに含まれる関数)
  4. スペシャルファイル (通常 /dev に置かれている)
  5. ファイルのフォーマットとその約束事。例えば /etc/passwd など
  6. ゲーム
  7. マクロのパッケージとその約束事。例えば man(7), groff(7) など
  8. システム管理用のコマンド (通常は root 専用)
  9. カーネルルーチン [非標準]

同じ名前で、複数のセクションに説明がある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ページを見ることができます。

3.2. ユーザー管理

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ファイルは特権ユーザーしか見ることができないようにパーミッションが設定されています。パーミッションについては、「ファイルの所有権とパーミッション」で説明します。

3.2.1. 特権ユーザーと一般ユーザー

Linuxシステムでは、ユーザーを一般ユーザーと特権ユーザーの2種類に大別します。

特権ユーザーは、システム管理などをおこなうために用意されているユーザーで、一つのシステムに必ず一つ存在します。WindowsでのAdministratorのような役割です。通常、特権ユーザーにはrootという名前を付けることが多いので、rootユーザーと呼ばれることもあります。

一般ユーザーは、特権ユーザー以外のユーザーのことで、ユーザーごとに行える作業(権限)に制限があります。Linuxシステムでは、ユーザーごとに必要最小限の権限を与えることで、システム全体のセキュリティを保ちます。

ATDE5では、特権ユーザーとしてrootユーザー、一般ユーザーとしてatmarkユーザーが用意されています。

特権ユーザーはすべての権限を持っているため、誤った作業をおこなうと、ファイルをすべて消してしまうなど、システムを復旧不可能な状態に破壊してしまう可能性があります。そのため、通常の作業は一般ユーザーでおこないます。しかし、ソフトウェアのインストールなどでは、特権ユーザーの権限が必要になります。そのような場合は、一時的にユーザーを切り替えて作業をおこないます。

一般ユーザーから特権ユーザにユーザーを切り替えるには、以下のようにsuコマンドを使用します。特権ユーザーでの作業が終了したら、exitコマンドを実行し、元のユーザーに戻ることを忘れないでください。

[ATDE ~]$ su
パスワード: root
[ATDE ~]# 特権ユーザーでの作業
[ATDE ~]# exit
[ATDE ~]$

図3.4 ユーザーの切り替え(suコマンド)


sudoコマンドを使うと、そのコマンドだけ別のユーザーとして実行することができます。どのユーザーが、どのユーザーとして、どのコマンドを実行できるかは、/etcディレクトリにあるsudoersファイルに記述します。

ATDE5ではatmarkユーザーがrootユーザーとしてすべてのコマンドを実行できるように設定してあります。以下のようにsudoコマンドを実行すると、特権ユーザー権限でsomecommandを実行します。なお、sudoコマンド実行時に入力するパスワードは、sudoコマンドを実行したユーザー自身(この場合ではatmarkユーザー)のパスワードです。

[ATDE ~]$ sudo somecommand
パスワード: atmark

図3.5 一時的なユーザーの切り替え(sudoコマンド)


3.2.2. ユーザーの追加と削除

システムに新しくユーザーを追加するには、useraddコマンドを使用します。

newuserというユーザー名のユーザーを追加するには、以下のようにします。ユーザーの追加には、特権ユーザーの権限が必要なので、sudoコマンドを介してuseraddコマンドを実行します。-mオプションは、ホームディレクトリを作成するオプションです。

[ATDE ~]$ sudo useradd -m newuser

図3.6 ユーザーの追加(useraddコマンド)


作成したばかりのユーザーは、パスワードが設定されていないため、そのユーザーでログインすることができません。パスワードの設定、変更をおこなうには、passwdコマンドを使用します。

以下の例では、newuserのパスワードをpasswordに設定しています。

[ATDE ~]$ sudo passwd newuser
新しいUNIXパスワードを入力してください: password
新しいUNIX パスワードを再入力してください: password
passwd: パスワードは正しく更新されました

図3.7 パスワードの設定(passwdコマンド)


ユーザーを削除するには、userdelコマンドを使用します。-rオプションを付けることで、ユーザーのホームディレクトリも削除することができます。

[ATDE ~]$ sudo userdel -r newuser

図3.8 ユーザーの削除(userdelコマンド)


[ティップ]ログインできないユーザー

shadowファイルの二番目のフィールドには、暗号化したパスワードが記述されています。ここに、*や!と書くと、無効なパスワードになり、そのユーザーでログインすることができなくなります。

ATDEの/etc/shadowを見てみると、有効なパスワードが設定されていて、ログインできるのはrootユーザーとatmarkユーザーだけです。その他のユーザーは、サーバーやシステム管理用のユーザーとして用意されています。例えば、www-dataはWebサーバー用のユーザーです。

suコマンドを使用しても、ログインできないユーザーには切り替えることができません。しかし、sudoコマンドの-uオプションを指定すると、コマンドを実行するユーザーを指定することができます。この機能を使用すると、ログインできないユーザーとしてコマンドを実行することもできます。

[ATDE ~]$ sudo -u www-data whoami
www-data

図3.9 ログインできないユーザーとしてコマンドを実行する(sudoコマンド)


3.2.3. ユーザーとグループ

Linuxシステムでは、ユーザーの集まりをグループという単位で管理することができます。ユーザーとグループという仕組みを使用して、システム(特にファイル)の管理を行う方法は、「ファイルの所有権とパーミッション」で詳しく説明します。

新しくグループを作成するコマンドは、groupaddコマンドです。グループを削除には、groupdelコマンドを使用します。

[ATDE ~]$ sudo groupadd newgroup

図3.10 グループを追加する(groupaddコマンド)


ユーザーは、少なくとも一つのグループに属します。ユーザーが属する一つ目のグループを、ログイン時初期グループといいます。useraddコマンドを使用して新しくユーザーを追加すると、ユーザー名と同名のグループ名が新規に作成され、ログイン時初期グループに設定されます。また、ユーザーが属しているログイン時初期グループ以外のグループを、補助グループといいます。

ユーザーが所属するグループを変更するには、usermodコマンドを使用します。usermodコマンドの-gオプションを使うと、ログイン時初期グループを変更することができます。また、-Gオプションを使うと、補助グループを変更することができます。

[ATDE ~]$ sudo usermod -G newgroup newuser

図3.11 ユーザーが所属するグループを変更する(usermodコマンド)


3.3. ファイルの操作

Linuxシステムを含む、UNIXシステムでは「すべてのものはファイルである(Everything is a file)」という考え方があります。Linuxシステムでは、ディスク上のデータも、動作中のプロセスも、ハードウェアであるデバイスさえも、ファイルとして表現します。基本的なファイルの操作は、すべてのファイルで共通です。テキストファイルの内容を読むのも、プロセスの状態を調べるのも、デバイスからデータを読み出すのも、基本的には同じ操作でできます。

本章では、様々なファイルに対する操作方法について説明していきます。

3.3.1. ファイルの種類

Linuxシステムで扱えるファイルには、以下のような種類があります。

  1. 通常ファイル

    いわゆる普通のファイルです。大抵の場合、ハードディスクドライブなどのストレージに記録され、テキストファイル、バイナリファイル、実行ファイル、データファイルなどとして読み書きできます。

  2. ディレクトリ

    他のファイルやディレクトリを格納することができるファイルを、ディレクトリといいます。Windowsでのフォルダと同様の概念です。

  3. デバイスファイル

    Linuxカーネル内のデバイスドライバ[14]とのインターフェースとなるファイルです。スペシャルファイルやデバイスノードという場合もあります。

    スペシャルファイルには、キャラクタデバイスファイルとブロックデバイスファイルの2種類があります。キャラクタデバイスファイルへの入出力は、ストリームとして扱われ、一度書き込んだ内容は取り消せず、同じ内容を2回読み出すこともできません。対して、ブロックデバイスはランダムアクセス(任意の位置への読み書き)が可能なので、同じ位置に何度も読み書きすることができます。

    シリアルインターフェースや、マウス、キーボードなどはキャラクタデバイスファイルで、ハードディスクなどのストレージやメモリはブロックデバイスファイルとして扱われます。

    デバイスファイルは、必ずしも物理的なデバイスと結びついているわけではありません。そのようなデバイスファイルを、疑似デバイスファイルといいます。読み込むと常に0を返す/dev/zero、ある程度ランダムな値を返す/dev/urandom、書き込んだ内容を捨てる/dev/nullなどがあります。

  4. シンボリックリンク

    ファイル名とファイルの実体との関係をリンクといいます。シンボリックリンクは、ファイルのパス名によって別のファイルを参照するリンクです。

    シンボリックに対して、ハードリンクというリンクもあります。これについては、「ファイルの属性情報(inode)」で説明します。

  5. その他

    その他のファイルの種類として、FIFO(名前付きパイプ)とUNIXドメインソケットがあります。これらは、IPC(InterProcess Communication、プロセス間通信)に使われます。

3.3.2. ファイルの属性情報(inode)

すべてのファイルはファイルの内容とは別に、ファイルの属性を表すメタデータを持っています。このメタデータのことを、inodeといいます。inodeには、以下の情報が格納されています。

表3.1 inodeが持つ情報

情報 説明

種類

「ファイルの種類」で挙げたファイル種類のどれであるか

所有者情報

ファイルを所有するユーザー(所有者)及び所有するグループ(所有グループ)のID

パーミッション

所有者、所有グループに所属するユーザー、それら以外のユーザーに対する読み出し、書き込み、実行許可情報

ハードリンク数

ファイルに対するハードリンクの数

サイズ

ファイルのサイズ

時刻情報

最終アクセス時刻、最終修正時刻、最終属性状態変更時刻[a]

[a] Linuxシステムでは、ファイルの作成日時は保存されません。


inodeにはファイル名が含まれていないことに注目してください。Linuxシステムでは、ファイル名を保持しているのはディレクトリです。inodeにはinode番号と呼ばれる一意な数値が割り振られており、ディレクトリはファイル名とinode番号の対応のリストを保持します。この、ファイル名とinodeとの対応をハードリンクといいます。一つのinodeに対し、複数のファイル名を付ける、即ち、複数のハードリンクを張ることも可能です。

このため、Linuxシステムではファイルを削除することをアンリンク(unlink)といいます。複数のハードリンクがある場合、アンリンクはディレクトリからリンクを削除するだけです。ハードリンク数が0になった時に、実際にファイルの内容が削除されます。

inodeが持つ情報は、lsコマンドに-lオプションをつけて実行することで確認することができます。

[ATDE ~]$ ls -l /bin/cat
-rwxr-xr-x 1 root root 51856  1月 27  2013 /bin/cat

図3.12 inodeが持つ情報を確認する(ls -lコマンド)


最初の一文字は、ファイルの種類を表します。ファイルの種類によって、以下の表記になります。

表3.2 ファイル種類の表記

表記 ファイル種類

-

通常ファイル

d

ディレクトリ

c

キャラクタデバイスファイル

b

ブロックデバイスファイル

l

シンボリックリンク


「rwxr-xr-x」の部分は、ファイルのパーミッションを表します。パーミッションについては、「ファイルの所有権とパーミッション」で説明します。

続く「1」は、ハードリンクの数を表します。

「root root」は、それぞれ、所有者のユーザー名、所有グループのグループ名を表します。これらは、パーミッションの設定と密接に関わっています。

「51856」はバイト単位のファイルサイズです。

「1月 27 2013」は、ファイルの最終修正時刻を表します。

3.3.3. ファイルシステムとパス

Linuxシステムでは、ファイル同士の位置関係は階層的な木構造として表現されます。ファイルシステムとは、ファイルの木構造をある形式に従って構成したものです。

木構造の最上位に位置するディレクトリをルートディレクトリといいます。全てのファイルはルートディレクトリから辿ることができます。

また、Linuxシステムのファイルシステムでは、木構造の任意の位置にファイルシステムを追加または削除することができます。この操作をそれぞれ、ファイルシステムをマウントする、アンマウントするといいます。

システムに最初にマウントされるファイルシステムをルートファイルシステムといいます。ルートファイルシステムは、システム起動時にルートディレクトリにマウントされます。

木構造の中のファイルの位置は、パスで表します。パスはあるディレクトリからファイルに到達するまでの間にあるディレクトリ名の間にスラッシュ(/)を挟んだものです。ルートディレクトリは/一文字で表します。パスの記述方法には二種類あり、/から始まるルートディレクトリからの位置を表したパスを絶対パスといい、ルートディレクトリ以外からの位置を表したパスを相対パスといいます。パスには、/以外にもいくつか特殊な意味を持つ文字があります。.は現在のディレクトリを、..は一つ上のディレクトリを意味します。また、多くのシェルでは~は、ホームディレクトリを意味します。

ファイルシステムには、構造を構成する形式が異なるいくつかの種類があります。Linuxで一般的に使用されるファイルシステムには、ext2ファイルシステム、ext3ファイルシステムがあります。Armadilloのルートファイルシステムは、RAMディスク[15]上に構成されたext2ファイルシステムです。ext3ファイルシステムは、ext2ファイルシステムにジャーナリング機能[16]を追加したもので、耐障害性に優れます。また、Windowsで使用されるVFAT(FAT32)ファイルシステムも扱うことができます。

これらのファイルシステムは物理的なデバイスと結びついているものですが、メモリ上にしか存在しないファイルシステムもあります。その一つである仮想ファイルシステムには、カーネルの内部情報を参照又は設定できるprocfsやsysfsなどがあります。また、疑似ファイルシステム(pseudo filesystem)は、RAM上に直接ファイルシステムを構成します。擬似ファイルシステムには、tmpfsやramfsがあります。

さらに、ネットワークファイルシステム(NFS)を使用すると、ネットワーク越しのコンピューターに存在するデータを扱うことができます。

3.3.4. ファイルの所有権とパーミッション

前章で説明したように、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として[17]、その合計で表現します。8進数表記でのパーミッションは、rwxは7、rw-は6、r-xは5、r--は4、---は0となります。そのため、「rwxr-xr-x」を8進数3桁で表記すると、「755」となります。

パーミッションを変更するには、chmodコマンドを使用します。すべてのユーザーに対して実行を許可する(つまり、実行権限を与える)場合、+xオプションを使用します。

[ATDE ~]$ chmod +x ファイル名

図3.13 ファイルのパーミッションを変更する(chmodコマンド)


ファイルを新規に作成した場合のパーミッションは、ファイルの種類とumaskと呼ばれる値によって決まります。標準のパーミッションは、ディレクトリの場合rwxrwxrwx(777)、その他のファイルはrw-rw-rw-(666)です。この値からumaskを差し引いた値が、ファイルを新規作成した場合のパーミッションとなります。

umaskは、一般的には022となっています。そのため、ディレクトリを新規作成した場合のパーミッションはrwxr-xr-x(755)、通常ファイルの場合は、rw-r—r--(644)となります。

[ATDE ~]$ umask
0022
[ATDE ~]$ touch file
[ATDE ~]$ mkdir dir
[ATDE ~]$ ls -l
合計 4
drwxr-xr-x 2 atmark atmark 4096 10月 13 15:34 dir
-rw-r--r-- 1 atmark atmark    0 10月 13 15:34 file

図3.14 umaskと新規作成時のファイルパーミッション


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ファイルにアクセスすることができます。

[ATDE ~]$ ls -l /etc/shadow
-rw-r----- 1 root shadow 1117  9月 22  2014 /etc/shadow
[ATDE ~]$ ls -l $(which passwd)
-rwsr-xr-x 1 root root 51096  5月 26  2012 /usr/bin/passwd

図3.15 etc/shadowファイルとpasswd実行ファイルのパーミッション


ls -lでは、SUIDビットがセットされていて所有者の実行が許可されているファイルの場合、所有者の実行許可の表示がxではなくsとなります。

なお、whichコマンドは、引数に指定したコマンドが実際に実行するファイルの絶対パスを表示するコマンドです。

SGIDビットは、SUIDビットと同様の仕組みです。実行したユーザーが所属するグループではなく、所有グループとして実行されます。ls -lでは、SGIDビットがセットされていて所有グループに所属するユーザーに対する実行が許可されているファイルの場合、所有グループの実行許可の表示がxではなくsとなります。

スティッキービットは、ディレクトリとその他の実行ファイルに指定された時では挙動が異なります。

ディレクトリの場合、ディレクトリ内にあるファイルは、ファイル所有者とディレクトリ所有者のみが削除できます。この仕組みは、/tmpディレクトリで使用されています。一時的に使用するファイルを置く/tmpディレクトリには、すべてのユーザーに対して読み、書き、実行を許可していますが、ファイルを作成したユーザーか/tmpディレクトリの所有者であるrootユーザーしかファイルを削除することができません。ls -lでは、スティッキービットがセットされていてその他のユーザーに対する実行が許可されている場合、その他のユーザーの実行許可の表示がxではなくtとなります。

[ATDE ~]$ ls -ld /tmp
drwxrwxrwt 14 root root 4096 10月 13 15:41 /tmp

図3.16 /tmpディレクトリのパーミッション


実行可能ファイルに対してスティッキービットを設定した場合、そのコードをスワップ上に維持します。こちらの機能はあまり使用されていないようです。

3.3.5. デバイスファイルの管理

デバイスファイルは、メジャー番号とマイナー番号という二つの番号によって、対応するデバイスドライバを識別します。メジャー番号は、デバイスの種類を表します。デバイスの型(キャラクタ型かブロック型)とメジャー番号が同じデバイスファイルは、ほとんどの場合、同じデバイスドライバを使用します。また、マイナー番号によって、同じデバイスの型とメジャー番号を持つデバイスのグループ内のデバイスを識別します。

デバイスファイルは、通常/devディレクトリ以下に配置されます。

ls -lでデバイスファイルを調べた場合、他のファイルとは異なった出力となります。

[ATDE ~]$ $ ls -l /dev/ttyS*
crw-rw---T 1 root dialout 4, 64 10月 13 11:14 /dev/ttyS0
crw-rw---T 1 root dialout 4, 65 10月  9 21:59 /dev/ttyS1
crw-rw---T 1 root dialout 4, 66 10月  9 21:59 /dev/ttyS2
crw-rw---T 1 root dialout 4, 67 10月  9 21:59 /dev/ttyS3

図3.17 デバイスファイルの例


最初の一文字は、デバイスファイルの型を表します。「c」がキャラクタデバイスファイル、「b」がブロックデバイスファイルを意味します。所有者、所有グループの後に表示されている「4, 64」という番号が、それぞれメジャー番号とマイナー番号を表します。メジャー番号4は、シリアルポートに対応するデバイスファイルを意味します。メジャー番号とデバイスの対応は、Linuxカーネルのドキュメントに記載されています。linux-[version]-at/Documentation/devices.txtを参照してください。

デバイスファイルを作成するには、mknodコマンドを使用します。例えば、5個目のシリアルポートに対応するデバイスファイルを作成するには、以下のようにします。

[ATDE ~]$ sudo mknod /dev/ttyS4 c 4 68

図3.18 デバイスファイルの作成(mknodコマンド)


通常は、上記のようにmknodコマンドを使用してデバイスファイルを作成します。しかし、Linuxシステムはデバイスのホットプラグ[18]が可能です。システム動作中接続される可能性のあるデバイスに対するデバイスファイルをあらかじめすべて作っておくことは、現実的ではありません。そこで、デバイスが接続された時点でデバイスファイルを作成するudevという仕組みがあります。udevを使用すると、デバイスファイルの自動作成の他、デバイスが接続または切断された時点で任意のコマンドを実行する、といったことが可能になります。

3.4. プログラムとプロセス

プログラムの実行可能ファイルは、機械語の実行コードとデータから構成されます。多くのLinuxシステムでは、実行可能ファイルはELFと呼ばれる形式で保存されています。

実行可能ファイルは、ローダーと呼ばれるプログラムによってメモリにロードされ、実行が開始されます。この際、ローダーはプログラムの再配置やメモリの初期化などをおこないます。

実行中のプログラムをプロセスといいます。

Linuxシステムは、マルチタスクなので複数のプロセスを同時に実行できます。しかし、CPUは通常1個[19]しかありません。そこで、プロセスには仮想的なCPUとメモリ空間が与えられます。カーネルは、各プロセスがCPUを使う時間とメモリ領域を管理します。カーネルは、プロセスがCPUを使ってよい時間が過ぎたら、そのプロセスの実行を停止し別のプロセスの実行を開始します。また、プロセスから見えている仮想的なメモリ空間と物理メモリとの橋渡しをおこないます。そのため、プロセスはあたかもシステム全体を占有しているように振る舞う事ができます。

プロセスが使用するメモリ空間は、いくつかの領域(セクション)に分かれており、それぞれ用途が異なります。セクションには以下のものがあります。

  1. テキストセクション: 機械語の実行や定数などを収めた、読み取り専用で実行可能な領域。
  2. データセクション: グローバル変数やスタティック変数のうち初期値が設定されたデータを収めた領域。
  3. BSSセクション: グローバル変数やスタティック変数のうち初期値が設定されていないデータを収めた領域。0で初期化される。
  4. スタック: 関数呼び出し時に一時的なデータ用に使用される領域。
  5. ヒープ: プロセスが要求する動的なメモリ用に使用される領域。

psコマンドを使用すると、現在実行中のプロセスの一覧を見ることができます。

[ATDE ~]$ ps
  PID TTY          TIME CMD
 2488 pts/0    00:00:00 bash
18880 pts/0    00:00:00 ps

図3.19 プロセス一覧の確認(psコマンド)


「CMD」の欄に表示されているものが、プロセスを実行したコマンドです。「PID」は、プロセスIDと呼ばれるプロセスを一意に識別する数値です。

プロセスは、プロセスの状態や所有するリソース(タイマー、ファイル、ハードウェア、ネットワーク接続、プロセス間通信で使用するもの)、そのプロセスを実行したプロセスのID(親プロセスID、PPID)などの情報を保持しています。

3.5. シグナル

シグナルとは、カーネル又はプロセスからプロセスに対して送られる非同期なメッセージです。通常、メモリアクセス保護違反(segmentation fault)や特殊なキー入力(例えばCtrl+C)などのイベントが起こったことをプロセスに通知するために使用されます。

プロセスにシグナルが送られた場合、プロセスは以下の挙動のうちいずれかを行います。

  1. 終了する
  2. シグナルを無視する
  3. プロセスのコア[20]をダンプ(表示)して終了する
  4. 一時停止する
  5. 停止中であれば再開する
  6. シグナルを捕捉し、プロセス自身で指定したシグナルハンドラーで処理を行う

シグナルは、シグナル名かシグナル番号(整数値)で表されます。

代表的なシグナルを以下に示します。シグナルハンドラーを設定していない場合、標準の挙動をおこないます。捕捉できないシグナルは、必ず標準の挙動をおこないます。

表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が送られます。

3.6. プロセス間通信

それぞれのプロセスは、独立した仮想的なメモリ空間を与えられて動作するため、基本的に他のプロセスのデータにアクセスすることはできません。この特徴により、あるプロセスが誤って他のプロセスのデータを書き換えるということがないため、セキュリティやシステムの堅牢性を保つことができます。

しかし、場合によっては複数のプロセスが協調動作をしたり、情報のやりとりを行う必要があったりします。そのために、Linuxカーネルはプロセス間通信(Inter Process Communication、IPC)の仕組みを提供しています。

IPCを行う方法には、以下のものがあります。

  1. パイプ
  2. 名前付きパイプ(FIFO)
  3. メッセージキュー
  4. 共有メモリ
  5. セマフォ
  6. インターネットソケット
  7. 名前付きソケット(UNIXドメインソケット)

3.7. 端末

端末(ターミナル)とは、ディスプレイと入力装置(キーボード)から構成され、コンピューターの使用者がホストコンピューターとのやりとりを行うために使用される装置です。ホストコンピューターと端末は、シリアル通信線や電話線、Ethernetなどで接続されます。コンピューターが高価で、一つのコンピューターを複数人で共有していた時代は、一つのホストコンピューターに複数の端末を接続して使用していました。コンピューターが十分に安くなり、一人一台の「パーソナルな」コンピューター(PC)を持てるようになった現在では、端末専用装置を見かけることはほとんどありません。

今日では、端末専用装置の代わりに、PC上で動作する端末エミュレーターを使用します。Armadilloと開発用PCをシリアルケーブルで接続し、シリアル通信ソフトウェアで操作をおこなう場合、シリアル通信ソフトウェアを端末エミュレーターとして使用していることになります。大抵の端末エミュレーターでは、端末専用装置として事実上の標準であったVT100の互換機能を持っています。

Linuxシステムでは、様々な装置を端末とみなして、互いに通信することができます。PCに接続されたモニターはコンソール端末、シリアルポートを介して接続されているコンピューターはシリアル端末、ネットワークを介して接続されているコンピューターは擬似端末とみなします。Linuxシステムでは、端末との通信をtty[21]という名前のついたデバイスファイル(ttyデバイス)を介しておこないます。

3.7.1. シリアル端末

Linuxシステムでは、シリアルポートに対する読み書きは、シリアルポートに対応するttyデバイスへの読み書きとして扱います。つまり、シリアルポートの先にシリアル端末が繋がっているとみなしています。例えば、WindowsではCOM1と表現される、PCの一番目のシリアルポートへの読み書きは、Linuxシステムでは通常、/dev/ttyS0に対しておこないます。

[ATDE ~]$ echo hello > /dev/ttyS0  1
[ATDE ~]$ cat file > /dev/ttyS0  2
[ATDE ~]$ cat /dev/ttyS0  3

図3.20 シリアルポートの読み書き


1

文字列「hello」をシリアルポートから送信します。

2

fileの内容をシリアルポートから送信します。

3

シリアルポートに受信した内容を表示します。

シリアルポートの通信速度等の設定確認や変更は、sttyコマンドで行うことができます。sttyコマンドでは、-Fオプションで設定の確認や変更をおこなうttyデバイスを指定します。詳細は、man 1 sttyを参照してください。

[ATDE ~]$ stty -F /dev/ttyS0
speed 9600 baud; line = 0;
-brkint -imaxbel

図3.21 シリアルポートの設定確認(sttyコマンド)


Armadilloでは、シリーズによってシリアルポート(シリアルインターフェース)に割り当てているデバイスファイル名が異なります。Armadillo-400シリーズでは、/dev/ttymxc#(#は10進数値文字)となり、/dev/ttymxc1がシリアルインターフェース1に割り当てられています。詳細は、「Armadillo-400 シリーズ ソフトウェアマニュアル」の「Linuxカーネルデバイスドライバ仕様」の「UART」をご参照ください。

USB to シリアル変換ケーブルを使った場合、変換ケーブル内のICによってデバイスファイル名が異なります。通常、/dev/ttyUSB#/dev/ttyACM#になります。

3.7.2. コンソール端末

コンソール端末、あるいは単にコンソールとは、システム管理用の端末のことです。通常、ホストコンピューターに接続されたディスプレイとキーボードをコンソールとして使用します[22]。Linuxシステムでは、ホストコンピューターに接続されたディスプレイに表示できる、仮想的なコンソールを複数持つことができます。仮想コンソールには、/dev/tty#を介してアクセスします。/dev/tty0は特別な意味を持ち、現在の仮想コンソールを意味します。

Debian GNU/Linux 7.0では、Ctrl+Alt+F#を入力することで、仮想コンソールを切り替えることができます[23]Ctrl+Alt+F1で一番目の仮想コンソール(/dev/tty1)に切り替えます。Debian GNU/Linux 7.0では、F1からF6までがテキストコンソールに割り当てられています。Ctrl+Alt+F7で元のGUI画面に戻ることができます。

端末が使用しているttyデバイスは、ttyコマンドで調べることができます。Ctrl+Alt+F1で仮想コンソールを切り替え、ログインしてからttyコマンドを実行すると、以下のように表示されます。

[ATDE ~]$ tty
/dev/tty1

図3.22 端末が使用しているttyデバイスの確認(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ファイルで調べることができます。

[ATDE ~]$ cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-3.2.0-4-amd64 root=/dev/mapper/atde5-root ro quiet

図3.23 カーネルパラメーターの確認(proc/cmdlineファイル)


3.7.3. 擬似端末

擬似端末は、シリアル端末やコンソール端末のように、必ずしも物理的に接続されているとは限らない端末との通信に使用されます。ATDE5の[アプリケーション]-[アクセサリ]-[端末]メニューで起動できる端末エミュレーター(Gnome端末)でttyコマンドを実行すると、/dev/pts/0のように表示されます。

[ATDE ~]$ tty
/dev/pts/0

図3.24 Gnome端末でのttyデバイス


擬似端末は、マスターとスレーブがセットになって使用されます。スレーブへ書き込んだデータは、マスターから読み出すことができ、また、マスターへ書き込んだデータはスレーブから読み出すことができます。/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で接続する[24]と、ttyコマンドで確認できるttyデバイスは/dev/ttyp0になります。telnetクライアントが/dev/ttyp0へ書き込んだデータは、telnetサーバーが/dev/ptyp0から読み出します。

[ATDE ~]$ telnet ArmadilloのIPアドレス
Trying ArmadilloのIPアドレス...
Connected to ArmadilloのIPアドレス.
Escape character is '^]'.

atmark-dist v1.45.0 (AtmarkTechno/Armadillo-420)
Linux 3.14.36-at4 [armv5tejl arch]

armadillo420-0 login: guest
[guest@armadillo420-0 (pts/0) ~]$ tty
/dev/pts/0

図3.25 Armadilloにtelnetで接続した場合のttyデバイス


3.8. 時間の管理

Linuxシステムでは時間の管理は二つの時計、システムクロックとハードウェアクロックでおこなっています。

システムクロックはLinuxカーネルが管理している時計で、タイマー割り込みによって駆動されます。システムクロックは、UTC(Universal Time, Coordinated、協定世界時) 1970年1月1日 00時00分00秒(紀元、エポック)からの経過秒数で表されます。Linuxシステムでは、システムクロックがすべての動作の基準となります。システムクロックを参照、設定するには、dateコマンドを使用します。

[ATDE ~]$ date
2015年 10月 13日 火曜日 16:07:53 JST

図3.26 システムクロックの参照(dateコマンド)


ハードウェアクロックは、CPUとは独立したRTC(リアルタイムクロック)によって管理される時計です。システムに電源が供給されていない間も、バッテリや外部電源などで動作しつづけます。Linuxシステムは、起動時にハードウェアクロックを参照し、システムクロックを設定します。

[ATDE ~]$ sudo hwclock
2015年10月13日 16時07分56秒  -1.053183 seconds

図3.27 ハードウェアクロックの参照(hwclockコマンド)


3.8.1. タイムゾーン

ATDE5でdateコマンドを実行すると、図3.26「システムクロックの参照(dateコマンド)」で示したようにJST(Japan Standard Time、日本標準時)で表示されます。システムクロックは、カーネル内部では常にUTCを基準としたエポックからの経過秒数で管理されています。しかし、dateコマンドはシステムの設定に従ってローカルタイムでの表示を行います。

dateコマンドなどの時間を扱うコマンドでどのタイムゾーンを使用するか、即ちローカルタイムのタイムゾーンはTZ環境変数で指定することができます。環境変数については、「環境変数」を参照してください。また、TZ環境変数の指定方法については、man 3 tzsetを参照してください。

[ATDE ~]$ date
2015年 10月 13日 火曜日 16:11:18 JST
[ATDE ~]$ TZ=UTC date
2015年 10月 13日 火曜日 07:11:23 UTC
[ATDE ~]$ TZ=America/New_York date
2015年 10月 13日 火曜日 03:11:27 EDT

図3.28 システムクロックの参照(タイムゾーンを指定)


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ではローカルタイムをハードウェアクロックに保存することが多いようです。

[ATDE ~]$ sudo hwclock --systohc --utc

図3.29 システムクロックをハードウェアクロックに設定する(UTC)


[ATDE ~]$ sudo hwclock --systohc --localtime

図3.30 システムクロックをハードウェアクロックに設定する(ローカルタイム)


3.8.2. 時刻を正確に保つ

システムクロックとハードウェアクロックは、長期的な視点ではどちらも正確ではありません。通常、二つの時計は異なるクロックソースを元にして動作するので、相対的にずれていきます。また、国際原子時(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がシステムクロックを更新してしまうと、正確な測定ができなくなります。

[ATDE ~]$ sudo /etc/init.d/ntp stop
Stopping NTP server: ntpd.

図3.31 adjtimexによるシステムクロックの補正1: ntpdの停止


次に、adjtimexをインストールします。NTPの参照にはntpdateコマンドを使用するので、同時にインストールします。

[ATDE ~]$ sudo apt-get install adjtimex ntpdate

図3.32 adjtimexによるシステムクロックの補正2: adjtimexのインストール


adjtimexコマンドに--hostオプションを指定すると、ntpdateを使用して補正のためのデータを取得します。この例では、NTPサーバーには独立行政法人情報通信研究機構(NICT)のサーバーである、ntp.nict.jpを指定しています。--logオプションも同時に指定することで、補正のためのデータをログファイル(/var/log/clocks.log)に書き込みます。ハードウェアクロックやシステムクロックをadjtimex以外で書き換えていない場合は、二つの質問にyと答えてください。

[ATDE ~]$ sudo adjtimex --log --host ntp.nict.jp
      reference time is Tue Oct  5 08:28:17 2010
reference time - system time = 1286234897.969 - 1286234791.000 = 106.969 sec
Last clock comparison was at Tue Oct  5 08:27:14 2010
Kernel time variables are unchanged - good.
System clock is synchronized (by ntpd?) - bad.
Checking wtmp file...
System has not booted since Tue Oct  5 08:27:14 2010 - good.
System time has not been changed since Tue Oct  5 08:27:14 2010 - good.
Checking /etc/adjtime...
/sbin/hwclock has not set system time and adjusted the cmos clock
since Tue Oct  5 08:27:14 2010 - good.

Are you sure that, since Tue Oct  5 08:27:14 2010,
  the system clock has run continuously,
  it has not been reset with date' or `/sbin/hwclock,
  the kernel time variables have not been changed, and
  the computer has not been suspended? (y/n) [n] y
The estimated error in system time is -19938.344 +- 187.183 ppm

Are you sure that, since Tue Oct  5 08:27:14 2010,
  the real time clock (cmos clock) has run continuously,
  it has not been reset with `/sbin/hwclock',
  no operating system other than Linux has been running, and
  ntpd has not been running? (y/n) [y] y
The estimated error in the cmos clock is -62097 +- 187 ppm

図3.33 adjtimexによるシステムクロックの補正3: ntpdateによる補正データの測定


--printオプションを指定すると、現在の設定を確認することができます。また、補正のためのデータをカーネルに設定するには、--adjustオプションを使用します。その際、--reviewオプションを付けると、ログファイルに記録したデータをもとに設定します。

[ATDE ~]$ sudo adjtimex --print
         mode: 0
       offset: -682
    frequency: 4550171
     maxerror: 2437460
     esterror: 848
       status: 1
time_constant: 10
    precision: 1
    tolerance: 32768000
         tick: 9799
     raw time:  1286234858s 122967us = 1286234858.122967
[ATDE ~]$ sudo adjtimex --adjust --review
start                     finish                    days    sys - cmos (ppm)
start                     finish                    days    cmos_error (ppm)
start                     finish                    days    sys_error (ppm)
Tue Oct  5 08:22:41 2010  Tue Oct  5 08:25:29 2010  0.0020  -209 +- 49
Tue Oct  5 08:25:29 2010  Tue Oct  5 08:26:31 2010  0.0007  -103 +- 134
least-squares solution:
   cmos_error = 0 +- 100000 ppm
      (no suggestion)
        current adjustment = 0.0012 sec/day
   sys_error = -196 +- 46 ppm
      suggested tick = 10002  freq =   -270990
        current tick =  9799  freq =   4550171
note: clock variations and unstated data errors may mean that the
least squares solution has a bigger error than estimated here
new tick = 10002  freq = -270989
[ATDE ~]$ sudo adjtimex --print
         mode: 0
       offset: -675
    frequency: -270989
     maxerror: 2460460
     esterror: 848
       status: 1
time_constant: 10
    precision: 1
    tolerance: 32768000
         tick: 10002
     raw time:  1286234904s 17221us = 1286234904.017221

図3.34 adjtimexによるシステムクロックの補正4: 補正データの設定と確認


3.8.3. タイマーの分解能

システムクロックの分解能は、カーネルコンフィギュレーションで定義される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より前のカーネルでは、プロセスをスリープさせたりタイマー[25]を扱うシステムコールの精度はシステムクロックの分解能に依存していました。そのため、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シリーズではハイレゾリューションタイマーが有効になっています。

3.9. ロケール

ロケールとは、多言語を扱うプログラムがどのようなルールに基づいて処理するべきかを定めたルールの集合です。プログラムは、ロケールに基づいて適切な言語や表記でメッセージを表示したり、文字集合を扱うことができます。

ロケールはいくつかのカテゴリに分かれており、それぞれ個別に設定できます。カテゴリには以下のものがあります。

  1. LC_COLLATE: アルファベット文字列の比較方法を定義します。
  2. LC_CTYPE: 文字の判定、変換操作や多バイト文字操作の方法を定義します。
  3. LC_MONETARY: 小数点やカンマの位置など、通貨に関する数字の表示方法を定義します。
  4. LC_MESSAGES: メッセージ表示に使用する言語を定義します。
  5. LC_NUMERIC: 数字の扱いを定義します。
  6. LC_TIME: 時刻の表示方法を定義します。

ロケールは、LANGUAGEとLC_ALL及び上記のカテゴリに対応する環境変数によって設定できます。複数の環境変数が設定された場合、以下の優先順位に従って反映されます。

  1. 環境変数LC_ALLが設定されている場合、LC_ALLの値が使用されます。
  2. LC_ALL以外のLC_で始まる環境変数が設定されている場合、そのカテゴリにはその値が使用されます。
  3. 環境変数LANGが設定されている場合には、LANGの値が使用されます。
  4. いずれの環境変数も設定されていない場合、標準のロケール(Cロケール[26])が使用されます。

環境変数は端末やプロセスごとに設定できます。そのため、ロケールの設定も端末やプロセスごとに行われることになります。

それぞれの環境変数に設定するロケール名は、language[_territory][.codeset][@modifier]という書式になります。languageはISO639[27]で規程される言語コードです。また、territoryはISO 3166で規程される国名コード[28]です。codesetは、ISO-8859-1やUTF-8のような文字集合や文字符号化識別子です。

localeコマンドに-aオプションを付けて実行することで、システムでサポートされているすべてのロケールを得ることができます。

[ATDE ~]$ locale -a
C
C.UTF-8
POSIX
ja_JP.utf8

図3.35 システムでサポートされているすべてのロケールを得る(locale -aコマンド)


また、localeコマンドを引数なしで実行すると、現在の設定を確認することができます。

[ATDE ~]$ locale
LANG=ja_JP.UTF-8
LANGUAGE=
LC_CTYPE="ja_JP.UTF-8"
LC_NUMERIC="ja_JP.UTF-8"
LC_TIME="ja_JP.UTF-8"
LC_COLLATE="ja_JP.UTF-8"
LC_MONETARY="ja_JP.UTF-8"
LC_MESSAGES="ja_JP.UTF-8"
LC_PAPER="ja_JP.UTF-8"
LC_NAME="ja_JP.UTF-8"
LC_ADDRESS="ja_JP.UTF-8"
LC_TELEPHONE="ja_JP.UTF-8"
LC_MEASUREMENT="ja_JP.UTF-8"
LC_IDENTIFICATION="ja_JP.UTF-8"
LC_ALL=

図3.36 現在のロケールを確認する(localeコマンド)


図3.26「システムクロックの参照(dateコマンド)」で示したように、ATDE5でdateコマンドを実行すると日本語で表示されます。これを、英語で表示するには環境変数LANGを設定してdateコマンドを実行します。

[ATDE ~]$ date
2015年 10月 13日 火曜日 16:07:53 JST
[ATDE ~]$ LANG=en_US date
Tue Oct 13 16:07:53 JST 2015

図3.37 ロケールを指定してdateコマンドを実行


3.10. ネットワーク

近年の組み込みシステムでは、ネットワークシステムを持つものが増えています。Armadilloシリーズのすべての製品も、ネットワーク機能を有しています。Linuxシステムは様々なネットワーク機能を備えており、このことが組み込みシステムでLinuxを採用する動機となることも多いようです。ここでは、Linuxシステムでネットワークを扱う方法について説明します。

3.10.1. ネットワークインターフェース

Linuxシステムでは、「すべてのものはファイルである(Everything is a file)」という考え方の元、様々なものをファイルとして扱いますが、ネットワークインターフェースは例外です。ブロックデバイスやキャラクタデバイスの場合、デバイスファイル名を指定してファイルをオープンすることで、カーネル内のデバイスドライバにアクセスすることができます。ネットワークインターフェースの場合、インターフェース名でアクセスするインターフェースを指定します。

ネットワークインターフェースの状態を取得、設定するには、ifconfigコマンドを使用します。ifconfigコマンドを引数を指定せずに実行すると、動作中の(アップ状態の)すべてのインターフェースの状態を表示します。

[ATDE ~]$ /sbin/ifconfig
eth0      Link encap:イーサネット  ハードウェアアドレス xx:xx:xx:xx:xx:xx
          inetアドレス:192.168.0.1 ブロードキャスト:192.168.0.255  マスク:255.255.255.0
          inet6アドレス: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/64 範囲:リンク
          UP BROADCAST RUNNING MULTICAST  MTU:1500  メトリック:1
          RXパケット:729661 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:180412 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:1000
          RXバイト:283450776 (270.3 MiB)  TXバイト:186863017 (178.2 MiB)
          割り込み:18 ベースアドレス:0x2024

lo        Link encap:ローカルループバック
          inetアドレス:127.0.0.1 マスク:255.0.0.0
          inet6アドレス: ::1/128 範囲:ホスト
          UP LOOPBACK RUNNING  MTU:16436  メトリック:1
          RXパケット:12 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:12 エラー:0 損失:0 オーバラン:0 キャリア:0
      衝突(Collisions):0 TXキュー長:0
          RXバイト:840 (840.0 B)  TXバイト:840 (840.0 B)
[ATDE ~]$ LANG=C /sbin/ifconfig 
eth0      Link encap:Ethernet  HWaddr xx:xx:xx:xx:xx:xx
          inet addr:192.168.0.1  Bcast:192.168.0.255  Mask:255.255.255.0
          inet6 addr: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:730088 errors:0 dropped:0 overruns:0 frame:0
          TX packets:180413 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:283522733 (270.3 MiB)  TX bytes:186863431 (178.2 MiB)
          Interrupt:18 Base address:0x2024

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:12 errors:0 dropped:0 overruns:0 frame:0
          TX packets:12 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:840 (840.0 B)  TX bytes:840 (840.0 B)

図3.38 ネットワークインターフェースの状態を取得する(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」に変更するには、以下のようにします。

[ATDE ~]$ sudo ifconfig eth0 192.168.0.2

図3.39 ネットワークインターフェースの状態を設定する(ifconfigコマンド)


ifconfigコマンドで設定したネットワークインターフェースの状態は、一時的なもので、再起動すると失われてしまいます。恒久的な設定は、/etc/network/interfacesファイルに記述します。interfacesファイルに記述した設定は、ifupコマンドでネットワークインターフェースをアップしたときに適用されます。

ATDE5の標準設定では、interfacesファイルは以下のようになっています。

[ATDE ~]$ cat /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug eth0
iface eth0 inet dhcp

allow-hotplug usb0
iface usb0 inet ipv4ll

図3.40 ATDE5のinterfacesファイル


「auto lo」という行は、ifup --allを実行したときに「lo」をアップするよう指示しています。

「iface lo inet loopback」では、「lo」をTCP/IPネットワークのローカルループバックインターフェースのインターフェース名として指定しています。

「allow-hotplug eth0」は、ホットプラグイベント[29]が発生した際に「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を参照してください。

3.10.2. IPアドレスとポート番号

ネットワークで結ばれたコンピューター同士で通信を行う場合、実際にはそれぞれのコンピューター上で動作するプロセス間で通信を行うことになります。IPアドレスによって、ネットワーク上にあるコンピューターを識別することができます。しかし、IPアドレスだけでは、コンピューター上で動作するプロセスを識別することはできません。そこで、ポート番号を使用します。

接続を受け付けるプロセスは、ポート番号を指定して他のプロセスからの接続を待ち受けます。接続を行うプロセスは、IPアドレスとポート番号を指定して接続することで、特定のプロセスとの通信を開始することができます。

ポート番号は、0〜65535の範囲内の数値を取ります。このうち、いくつかの番号は用途が決まっています。このようなポート番号をウェルノウンポート(well-known port)と呼びます。どのポート番号がどのような用途に使用されるかは、/etc/servicesファイルに記述されています。また、man 5 servicesにも説明がありますので、参照してください。

netstatコマンドを使用すると、どのポートが現在使用されているか調べることができます。例えば、FTPサーバー(21番ポートを使用)とTelnetサーバー(23番ポートを使用)が動作しており、それぞれにクライアントからのアクセスがある場合、以下のように表示されます。

[ATDE ~]$ netstat -tanp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:21              0.0.0.0:*               LISTEN      1284/inetd
tcp        0      0 0.0.0.0:23              0.0.0.0:*               LISTEN      1284/inetd

図3.41 使用中のポート番号を調べる(netstatコマンド)


3.10.3. ホスト名とリゾルバ

ネットワークに繋がっているコンピューターのことを、ホストまたはノードと呼びます。クロス開発においては、クロスコンパイルを行う作業用PCをホストと呼び、開発対象をターゲットと呼んでいましたが、ここでは単にネットワークに接続されているコンピューターという意味でホストという言葉を使用します。

IPアドレスを使用すると、ネットワーク上のホストを識別することができます。しかし、IPアドレスは人間にとっては覚えにくいものです。そこで、IPアドレスに対応する名前を付けることができます。この、ホストを識別する名前をホスト名(hostname)といいます。ホスト名は、hostnameコマンドを使用して調べることができます。

[ATDE ~]$ hostname
atde5

図3.42 ホスト名を調べる(hostnameコマンド)


ホスト名とIPアドレスの対応は、/etc/hostsファイルに記述されています。ATDE5では、以下の内容になっています。

[ATDE ~]$ cat /etc/hosts
127.0.0.1       localhost
127.0.1.1       atde5.local-network     atde5

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
(略)

図3.43 /etc/hostsファイル


「localhost」というホスト名が「127.0.0.1[30]」、「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を参照してください。

3.10.4. ネットワークの状態を調べる

ネットワーク設定が正しく行われたことを確認するため、ホスト同士で通信が可能かを調べるには、pingコマンドが使用できます。pingコマンドは、対象のホストへパケットを送信し、対象のホストはパケットを受信すると応答パケットを返信します。対象ホストのパケットのやりとりが正常にできれば、最低限のネットワーク設定は正しいことを確認することができます。

通信可能なホストを指定してpingコマンドを実行すると、以下のようにホストからの応答が表示されます。

[ATDE ~]$ ping 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
64 bytes from 192.168.0.2: icmp_seq=1 ttl=64 time=3.99 ms
64 bytes from 192.168.0.2: icmp_seq=2 ttl=64 time=0.000 ms
64 bytes from 192.168.0.2: icmp_seq=3 ttl=64 time=0.000 ms
64 bytes from 192.168.0.2: icmp_seq=4 ttl=64 time=0.000 ms
64 bytes from 192.168.0.2: icmp_seq=5 ttl=64 time=0.000 ms
^C
--- 192.168.0.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4004ms

図3.44 ネットワークの到達確認: 成功(pingコマンド)


ホストとの通信ができなかった場合、以下のような表示になります。

[ATDE ~]$ ping 192.168.100.2
PING 192.168.100.2 (192.168.100.2) 56(84) bytes of data.
From 172.16.23.10 icmp_seq=2 Destination Host Unreachable
From 172.16.23.10 icmp_seq=3 Destination Host Unreachable
From 172.16.23.10 icmp_seq=4 Destination Host Unreachable
^C
--- 192.168.100.2 ping statistics ---
5 packets transmitted, 0 received, +3 errors, 100% packet loss, time 4004ms

図3.45 ネットワークの到達確認: 失敗(pingコマンド)




[13] manコマンドのmanページより引用。

[14] 物理的なデバイスを操作するためのプログラム

[15] RAMの一部を仮想的なストレージとして使用する仕組み。

[16] 定期的にファイルシステムの状態を保存しておく機能。不意なシステムシャットダウン時にもファイルシステムの破損を防止し、記録された状態に復旧することが可能となる。

[17] rwxを2進数の各桁に見立てています。

[18] システム動作中にデバイスを追加すること。

[19] 最近は、マルチコアなCPUも当たり前になってきましたが。

[20] プロセスの状態を保存したもの。

[21] ttyは「TeleTYpe」の略です。テレタイプとは電動機械式のタイプライターのことで、初期の端末として使用されていたため、このような名前になっています。

[22] シリアルケーブルで接続された端末をコンソールとして使用することもあります。この場合、シリアルコンソールと呼びます。

[23] ATDEはVMware Player上で動作しているため、ホットキーをそのまま入力することができません。Ctrl+Alt+スペース を入力したあと、Ctrl+Altを押したままで、Ctrl+Alt+F#を入力してください。

[24] この場合、telnetクライアントが端末エミュレーターです。

[25] ここでのタイマーは、プロセスが使用する仮想的なタイマーのことです。

[26] Linuxシステムで互換性のあるロケール。POSIXロケールとも呼ばれます。

[29] システムが動作しているときにデバイスが接続された場合に発生するイベント。

[30] ローカルループバックインターフェースのIPアドレス。