いますぐ実践! Linuxシステム管理

Last-Modified: 2013/6/2

いますぐ実践! Linux システム管理 / Vol.242 / 読者数:2403名

こんばんは、うすだです。

先日、会社のインターネット接続が、ADSL から光に変わりました。

ADSL でも遅いということはなかったのですが、速ければ速いほ…いえ、 将来のことを考えてということで、変えることになりました。

当日の工事は、慣れた兄ちゃんがテキパキと作業して、なんの問題もなく 滞りなく、なめらかに移行できました。

…ですが、なぜか、速いという実感を感じることができません。
逆に、画像などが読み込めない頻度が上がっている気がします。

手前が光でも、その先を多くのユーザで共有しているとか、ADSL の方が 実は少ないユーザで共有していて速いとか、疑惑が頭の中を駆けめぐって います。

そんなことないよ光の方が速いんだよと、もっともらしい技術的な説明を 誰かがしてくれるのを待っている、今日この頃です。

いつか原因究明しようと思いますが、と言うときは絶対しないことが明白 だとわかっていつつ、今回もはりきってまいります。

今回のお題 - ハードリンクとシンボリックリンクを理解する

月に2回、ゆるゆるとはいえ、発行し続けるというのは、自分で言うのも なんですが、思った以上の時間と労力を必要としています。

その中でも一番悩ましいのが、ネタです。カラカラに乾いた雑巾を絞って 探していますので、ときにはすごくニッチなお題になってしまうことも、 少なからずございます。

たとえば、前回の FS-Cache などは、NFS を使われていない方にとって、 ものすごくどうでもいいネタだった…かもしれません。

かたや、システム管理屋さんは、一見するとシステム管理に関係ないよう に思われる知識も、いろいろ知っておく必要があります。

カーネルやネットワーク、プログラミング、データベース、UI、などなど の幅広い知識を持っていますと、思わぬところで役に立ったりするのでは ないかと思います。

そして、その知識が、基礎的なものであればあるほど、役に立つ可能性が 高いのではないでしょうか。

…という言い訳めいた前フリをしたところで、今回は、だれもがお世話に なっている「リンク」について、おさらいしたいと思います。

ハードリンクやシンボリックリンクがどういうものか、具体的にイメージ できていれば、なにか問題が起こったとき、役に立つ…かもしれません。
(ハードリンクにしておいてよかった! とか。あ、ありますかね…。)

まずはざっくりと基本をおさらい

普段、何気なくファイルやディレクトリなどと戯れていますが、これらが どういうモノなのか、意識することはないんじゃないかと思います。

ですので、リンク云々の話に入る前に、ファイルやディレクトリについて さらっとご説明したいと思います。

ご存じの方、文字ばっかりだとアナフィラキシーの症状が出る恐れのある 方は、次まですっ飛ばしていただいて構いません。

ファイルは、ドキュメントだったり画像だったり動画だったりしますが、 ようは、なにかのデータのまとまりを表す単位です。

ディレクトリは、ファイルを格納するための保管場所です。もし世の中に ファイルしか存在しなかったら、同じファイル名をつけられなかったり、 つけたファイル名を忘れて途方に暮れてしまったりしてしまいます。です が、ディレクトリを使ってファイルを分類すると、整理できて超便利! に なるわけですね。

そして、ディレクトリにはディレクトリを含められるので、階層的な構造 に仕立て上げることができます。これがファイルシステムです。

では、ファイルやディレクトリが、具体的にどうなっているかといいます と、実際のファイルシステムを斜め読めば、それとなく感じられます。

ここでは例として、EXT2(あるいは EXT3、EXT4)ファイルシステムの中を 覗き見してみたいと思います。
Linuxカーネルのソースコードをお持ちの方は、fs/ext[234]/ext[234].h か include/linux/fs.h あたりをご参照いただくと、よいかもです。

まず、ファイルは、「iノード」と呼ばれるモノで管理されています。
(inode か ext2_inode 構造体を眺めると、具体的な構造が分かります。)

iノードには、ファイルの属性(種類やモード(i_mode)、所有者(i_uid)、 サイズ(i_size)、各種日時(i_atime, i_ctime, ...)など)と、ファイルの 中身の情報(i_block)が格納されています。

ここでポイントなのは、iノードにはファイル名の情報が含まれない、と いうことでしょうか。

さて次に、ディレクトリです。ディレクトリもファイルの一種です。
ディレクトリの中身は、「ディレクトリエントリ」です。
(ext2_dir_entry 構造体を眺めると、具体的な構造が分かります。)

ディレクトリエントリには、ファイルの実体であるiノードと、ファイル 名が格納されています。ここに格納されているiノードとは、32bit長の値 で、ファイルシステム内で一意なモノです。

ユーザがパス名でアクセスすると、ディレクトリエントリの中から、一致 するファイル名を探し出し、それに対応するiノードをもとに、いろいろ な情報をユーザに提供する、という芸当が可能になるわけです。

ちなみに、この32bitの値を「iノード番号」と呼びます。
iノード番号を知るには、「-i」オプションを指定してlsコマンドを実行 します。

$ ls -i1 /   

7340033 bin/
45875201 boot/
19398657 cdrom/
3 dev/
35127297 etc/
50069505 home/
17 initrd.img@
13 initrd.img.old@
...中略...
1 proc/
...中略...
1 sys/
...後略...

/proc や /sys が 1 なのは、それぞれ procfs や sysfs をマウントして いるためだと思われます。

また、「stat」コマンドでも、iノードの情報を確認できます。

$ stat /etc/hosts   
File: `/etc/hosts'   
Size: 2562        Blocks: 8        IO Block: 4096  通常ファイル 
Device: 805h/2053d  Inode: 35132117  Links: 1   
Access: (0644/-rw-r--r--)  Uid: (  0/  root) Gid: (  0/  root)   
Access: 2013-06-01 12:55:02.009358371 +0900   
Modify: 2013-05-27 12:50:35.151572836 +0900   
Change: 2013-05-27 12:50:35.207573114 +0900   

Birth: -

というわけで、ハードリンクとは?

文章ばっかりでクラクラしてきました…が、気を取り直して進めます。

「ハードリンク」とは、すでにあるファイルを、別のファイル名(パス名) で参照できるようにするモノです。

ハードリンクを作成するには、「ln」コマンドを使います。元のファイル 名と、新たに作成するファイル名を引数に指定して実行します。
たとえば、foo.txt の別名で bar.txt というハードリンクを作成するに は、以下のように実行します。

$ ln -s foo.txt bar.txt   

別ディレクトリにあるファイルと同じ名前ハードリンクを作成するには、 元だけを指定します。

$ ls   
$ ln -s foo/bar.txt   
$ ls   
bar.txt   

もう少し具体的に説明すると、ハードリンクとは、既存のiノードを参照 するディレクトリエントリを1つ追加すること、とも言えます。

たとえば、さきほど作成した bar.txt と、その元の foo.txt のiノード を確認してみると、同じiノードであることが分かります。

$ ls -i1 foo.txt bar.txt   
32256332 bar.txt   
32256332 foo.txt   

iノードにファイル名の情報が含まれない理由は、ここにあります。

そして、別のファイルシステムにあるファイルに対して、ハードリンクを 作成することができません。iノード番号が、ファイルシステム内でのみ 一意だからです。

また、iノードには、リンク数(i_nlink か i_links_count)という情報が 含まれています。通常は、あるディレクトリのディレクトリエントリから 参照されているため、リンク数は 1 です。

$ echo test > foo.txt   
$ ls -li foo.txt   
32256333 -rw-r--r-- 1 usu usu 5  6  1 18:00 foo.txt 

上記の場合、32256333 が iノード番号、その後の 1 がリンク数です。
ここでハードリンクを作成すると、2つのディレクトリエントリから参照 されることになるため、リンク数は 2 になります。

$ ln foo.txt bar.txt   
$ ls -li foo.txt bar.txt   
32256333 -rw-r--r-- 2 usu usu 5  6  1 18:00 bar.txt 
32256333 -rw-r--r-- 2 usu usu 5  6  1 18:00 foo.txt 

そして、ファイルを削除するコマンドといえば「rm」ですが、rmコマンド の役割は、厳密には、ディレクトリエントリを削除し、iノードのリンク 数を1つ減らすこと、だと言えます。

たとえば、ここで foo.txt を rm コマンドで削除すると、foo.txt だけ がなくなり、bar.txt は残ります。もちろん、中身は foo.txt のときの ままです。(リンク数は 1つ減って 1 になります。)

$ rm foo.txt   
$ ls -li foo.txt bar.txt    
ls: foo.txt にアクセスできません: そのようなファイルやディレクトリ\ 
はありません 
32256333 -rw-r--r-- 1 usu usu 5  6  1 18:00 bar.txt 

つまり、foo.txt のディレクトリエントリはなくなりますが、32256333番 のiノードと、そのiノードを参照する bar.txt のディレクトリエントリ は存在するので、削除されずにすみます。

もちろん、ここでさらに bar.txt を削除すると、32256333番のiノードを 参照するディレクトリエントリがなくなる(リンク数が 0 になる)ため、 今度こそ(?)削除されることになります。

ちなみに、元のファイルを移動させても、iノードで参照しているため、 問題なく参照できます。

$ cat foo.txt   
I am a foo.txt   
$ ln foo.txt bar.txt   
$ mv foo.txt foo2.txt   
$ ls -li foo2.txt bar.txt   
$ cat bar.txt   
I am a foo.txt   
32256335 -rw-r--r-- 2 usu usu 15  6  1 18:00 bar.txt 
32256335 -rw-r--r-- 2 usu usu 15  6  1 18:00 foo2.txt 

それから、ディレクトリに対するハードリンクは、root の権限があり、 ファイルシステムが対応している場合のみ、可能です。
(残念ながら、EXT2(EXT3,EXT4)では、対応していないようです。)

それじゃあ、シンボリックリンクって?

リンクには、前述のハードリンクの他に、「シンボリックリンク」という モノがあります。

シンボリックリンクも、すでにあるファイルに別名をつけて、その名前で 参照できるようにするモノです。

ハードリンクとは違い、元のファイルをiノードではなくパスで指定する ため、別のファイルシステムのファイルを参照できます。

シンボリックリンクの作成にも、ln コマンドを使います。
「-s」オプションと、元のファイルのパス、それを参照するシンボリック リンクとなるファイル名を指定して ln コマンドを実行します。

たとえば、foo.txt のシンボリックリンク bar.txt を作成したい場合、 以下のように実行します。

$ ln -s foo.txt bar.txt   
$ ls -li foo.txt bar.txt    
32256334 lrwxrwxrwx 1 usu usu 7  6  1 22:01 bar.txt -> foo.txt 
32256333 -rw-r--r-- 1 usu usu 5  6  1 18:00 foo.txt 

ハードリンクとは違い、元のファイルのリンク数は増えません。
ですが、もちろん、元のファイルと同じようにアクセスできます。

$ cat foo.txt   
test   
$ cat bar.txt   
test   
$ echo test from bar.txt > bar.txt   
$ cat foo.txt   
test from bar.txt   

また、引数に元のファイルのパスだけを指定すれば、同名のシンボリック リンクが作成されます。
たとえば、/etc/passwd のシンボリックリンクをカレントディレクトリに 作成するには、以下のように実行します。

$ ln -s /etc/passwd   
$ ls -l passwd   
lrwxrwxrwx 1 usu usu 11  6  1 21:58 passwd -> /etc/passwd 

では、シンボリックリンクを削除するとどうなるか、といいますと、元の ファイルはどうもならず、シンボリックリンクが削除されるだけです。

$ rm bar.txt   
$ ls -li foo.txt bar.txt   
ls: bar.txt にアクセスできません: そのようなファイルやディレクトリ\ 
はありません 
32256333 -rw-r--r-- 1 usu usu 5  6  1 18:00 foo.txt 

では逆に、元のファイルを消すとどうなるかといいますと、シンボリック リンクは残りますが、ファイル自体は失われてしまいます。

$ rm foo.txt   
$ ls -li foo.txt bar.txt   
ls: foo.txt にアクセスできません: そのようなファイルやディレクトリ\ 
はありません 
32256334 lrwxrwxrwx 1 usu usu 7  6  1 22:01 bar.txt -> foo.txt 
$ cat bar.txt   
cat: bar.txt: そのようなファイルやディレクトリはありません 

…ひゃー、悲しいですね。

それから、ハードリンクでは、元のファイルを移動させても問題なく参照 できましたが、シンボリックリンクでは参照できなくなります。

$ echo test > foo.txt   
$ ln -s foo.txt bar.txt   
$ mv foo.txt foo2.txt   
$ cat bar.txt   
cat: bar.txt: そのようなファイルやディレクトリはありません 

さらにそれから、ディレクトリに対するシンボリックリンクは、問題なく 作成できます。

$ ln -s /etc etc_link   
$ ls etc_link/   
...後略... 

その他注意するところ

それぞれ特性や制約はありますが、どちらも、別名でのアクセスができる という点で、とっても便利な仕組みです。

以上で…と終わりにしたいところですが、あとひとつだけ、注意すべき点 がありますので、記します。

それは、アーカイブにしたときの扱いです。
ここでは、tar と zip でどうなのか、確認しておこうと思います。

まずは tar ですが、ハードリンクには気づいていただけるようです。

$ tar cfz test.tgz foo.txt bar.txt   
$ tar tvfz test.tgz   
-rw-r--r-- usu/usu   5 2013-06-02 00:20 foo.txt   
hrw-r--r-- usu/usu   0 2013-06-02 00:20 bar.txt foo.txt へのリンク 

ただ、どちらが元かというのは、作ったひとにしかわからないので、先に 指定した方がオリジナルだと判断されるようです。

$ tar cfz test2.tgz bar.txt foo.txt   
$ tar tvfz test2.tgz   
-rw-r--r-- usu/usu   5 2013-06-02 00:20 bar.txt   
hrw-r--r-- usu/usu   0 2013-06-02 00:20 foo.txt bar.txt へのリンク 

といっても、どちらも展開したら同じ結果になるんですけどね。

シンボリックリンクの場合も、問題なく扱えます。

$ tar cfz test.tgz foo.txt bar.txt   
$ tar tvfz test.tgz   
-rw-r--r-- usu/usu   5 2013-06-02 00:27 foo.txt   
lrwxrwxrwx usu/usu   0 2013-06-02 00:27 bar.txt -> foo.txt   

元がアーカイブに含まれないときなど、シンボリックリンクではなく実体 として取り込みたいときは、「h」オプションを指定します。
以下の場合は、オリジナルが含まれるため、ハードリンクとして含められ ました。なんだかカシコイですね。

$ tar cfzh test2.tgz foo.txt bar.txt   
$ tar tvfz test2.tgz   
-rw-r--r-- usu/usu   5 2013-06-02 00:27 foo.txt   
hrw-r--r-- usu/usu   0 2013-06-02 00:27 bar.txt foo.txt へのリンク 

お次は zip です。
残念ながら、ハードリンクは考慮していただけないようです。

$ zip -r test.zip foo.txt bar.txt   
$ unzip -l test.zip   
Archive:  test.zip   
Length     Date   Time    Name   

      5  06-02-13 00:20   foo.txt   
      5  06-02-13 00:20   bar.txt   

     10                   2 files   
$ unzip test.zip   
$ ls -li foo.txt bar.txt    
32256336 -rw-r--r-- 1 usu usu 5  6  2 00:20 bar.txt 
32256335 -rw-r--r-- 1 usu usu 5  6  2 00:20 foo.txt 

シンボリックリンクも、そのままだと、上記と同様です。
ですが、「-y」オプションを指定すると、シンボリックリンクを考慮して くださいます。

$ zip -yr test.zip foo.txt bar.txt   
$ unzip test.zip   
Archive:  test.zip   

extracting: foo.txt
linking: bar.txt -> foo.txt
finishing deferred symbolic links:
bar.txt -> foo.txt
$ ls -li foo.txt bar.txt
32256339 lrwxrwxrwx 1 usu usu 7 6月 2 00:34 bar.txt -> foo.txt 32256338 -rw-r--r-- 1 usu usu 5 6月 2 00:20 foo.txt

おわりに

以上、ハードリンクとシンボリックリンクについて、おさらい的にさらり とご紹介しました。

それぞれの特徴をざっくりまとめますと、以下のようになります。

[ハードリンク]

  • iノードで参照
  • 同一ファイルシステム内に限られる
  • ファイルのみ(と思っておいた方がいい)
  • 元のファイルを移動しても問題ない
  • 元のファイルを削除しても消えない

[シンボリックリンク]

  • パスで参照
  • 別のファイルシステムでもいける
  • ディレクトリに対してもいける
  • 元のファイルを移動すると参照できなくなる
  • 元のファイルを削除すると消える

個人的には、tar コマンドはいろいろ考えているなあ、と思いました。

宿題の答え

前回の宿題は、

NFSマウント中にcachefilesdを停止・起動するとどうなるでしょうか。   

でした。

というわけで、試してみましょう。
cachefilesd が動いていることを確認して、NFSマウントします。

# service cachefilesd status   
cachefilesd (pid  2200) を実行中... 
# mount -o fsc 192.168.1.1:/export/home/nfs /home/nfs   
# du -sk /var/cache/fscache   
692     /var/cache/fscache   

アクセス前の、キャッシュディレクトリのサイズも、確認しておきます。
で、NFSマウントした中のファイルに、どーんとアクセスしてみます。

$ tar tvfz /home/nfs/foo/bar-0.0.1.tgz   

…これは、単なる例なので、自由に、適当なアクセスをしてください。
そうすると、当然ですが、キャッシュサイズは増えていきます。

# du -sk /var/cache/fscache   
80184   /var/cache/fscache   
# du -sk /var/cache/fscache   
353596  /var/cache/fscache   
...後略... 

では、アクセスさせたままの状態で、cachefilesd を止めてみましょう。

# service cachefilesd stop   
cachefilesd を終了中:                                  [  OK  ] 

すると、アクセスできなくなるか…というと、そんなことはありません。
その後も問題なくアクセスできます。

ちなみに、cachefilesd が動いていない状態でマウントすると、どうなる でしょうか。

# umount /home/nfs   
# mount -o fsc 192.168.1.1:/export/home/nfs /home/nfs   
# du -sk /var/cache/fscache   
676156   /var/cache/fscache   
(何かアクセス) 
# du -sk /var/cache/fscache   
676156   /var/cache/fscache   

ご想像通り、問題なくアクセスできます。
キャッシュのサイズも、使われていないから当然ですが、変わりません。

もし、マウント後にサービスを開始しても、ちゃんとキャッシュされて、 キャッシュが使われるようになります。

# service cachefilesd start   
cachefilesd を起動中:                                  [  OK  ] 
# du -sk /var/cache/fscache   
48      /var/cache/fscache   
(何かアクセス) 
# du -sk /var/cache/fscache   
1824    /var/cache/fscache   

ユーザ空間で動作するプロセスのせいでアクセスできなくなったりする、 というのは困りますので、当たり前なのかもしれませんね。

今回の宿題

今回の宿題は、

シンボリックリンクの場合ディレクトリエントリにどう記録されるか、 
確認してみましょう。   

です。

フツーに readdir() で読んだら…ということではなく、EXT2 などでベタ にどう記録されているのか、ということを調べてください。

検索すればわかると思いますので、宿題の答えでは、実際に生で読んで、 その通りだった! というところまでたどり着きたいです。

あとがき

某新聞で、能楽師の務めは、過去から未来へと芸を運ぶこと、という文章 を読みました。

その中の一文、「自分という存在は、長い線上の一点にすぎない。」に、 なんだか、ぐぐっと来るものがありました。

みなさんはまだお若いと思いますが、それとなく年を食ってくると、夢や 目標があいまいになり、それに向かってがんばることより、目の前のこと だけで限界だと思い込んだり、酒を飲んでくだを巻いたりしがちではない かと、勝手ながら思っています。

ですが、夢に向かって突き進むことだけでなく、後からくる人のために、 きちんと何かを残していくことも大事なのではないかということに、その 文章を読んで気づくことができました。

このメルマガをはじめたきっかけも、小銭稼ぎになるといいなあ…という 邪心だけでなく、わからなくて途方に暮れている若い管理者さんの助けに なりたい、という考えが、少なからずありました。

…あ、いえ、あります、です。現在進行形ですよ…。

というわけで、今後は、長い線上の一点として、未来のひとに何か残せる ようなことを考えてやっていこうと、強く思いました。

…いやいや、まだまだ、栗で世界征服の野望は、諦めていませんけどね。
小遣い稼ぎという邪心が、そこそこ達成できたとはいえ…。(^ε^;

今回も、ここまで読んでいただき、誠にありがとうございました。
次回は、6月16日(日) の未明にお会いしましょう!

 

「いますぐ実践! Linux システム管理」はこちらです。
メルマガの解除、バックナンバーなども、以下からどうぞ。
https://www.usupi.org/sysad/ (まぐまぐ ID:149633)

その他、作者に関するページは、概ね以下にございます。
https://www.usupi.org/kuri/ (まぐまぐ ID:126454)
http://usupi.seesaa.net/ (栗日記ブログ)
https://twitter.com/kuriking/ (twitter)
https://facebook.com/kuriking3 (facebook)
https://jp.pinterest.com/kuriking/pinterest)
https://www.instagram.com/kuri_king_/ (instagram)


[バックナンバーのトップへ] [Linux システム管理のトップへ]


トップ

バックナンバー
    [日付順] [目的別]

プロフィール

▼ 本が出ますよ(栗イラストも!)
   

▼ リンク

Server World
各種ディストリビューションの設定例がてんこ盛りです。
日経Linux
今や数少なくなってしまったLinuxの雑誌。
Linux & OSS − @IT
@ITが提供する、Linux の情報が満載。 載っていない設定方法はないんじゃないでしょうか。
gihyo.jp…技術評論社
Linuxに限らず様々な技術情報が満載のサイト。 SoftwareDesign誌も、 ソフトウェア技術者は必見です。
OSDN Magazine
Linux に限らず、オープンソース関連の記事が網羅されています。
ITmediaエンタープライズ:Linux Tips 一覧
Tips というより FAQ 集でしょうか。わからないことがあれば覗きましょう。
Linux Development - IBM Developer
開発者向けですが、勉強になりますよ。
栗日記
システム管理とかと全然関係ありませんが、毎日栗の絵を描いています。
システム管理につかれちゃったとき、癒されたいときに、ご覧ください。:-)

▼ 作ってみました

▼ 最近読んだ本

輪廻転生を信じると人生が変わる
山川紘矢
  こう言われると信じたくなる。
 
生きのびるための事務
坂口恭平 道草晴子
  思ったよりピンと来なかったかも。
 
幸福論
Hermann Hesse
  後半難しかったです。
 
最後はなぜかうまくいくイタリア人
宮嶋勲
  さらっと読めます。(この後God Father観ました)
 
ボクはやっと認知症のことがわかった
長谷川和夫
  母が長谷川式を受けたのでなお一層。
 
家族で「軽度の認知症」の進行を少しでも遅らせる本
内門大丈
  前もって知っておくのが大事。
 
なぜ、これがアートなの?
Amelia Arenas
  25年前の本なのに色褪せないなあ。
 
ソフトウェア・ファースト
及川卓也
  DXわかってないけどがんばろう。
 
李陵・山月記
中島敦
  やばい めちゃくちゃ面白い。
 
WIRED VOL.54
WIRED編集部
  なんかピンとこないなあ。
 

▼ 気に入ってる本

Ship It! ソフトウェアプロジェクト成功のための達人式ガイドブック
Jared Richardson, William Gwaltney Jr.
  いろんな分野に適用したい
 
Java並行処理プログラミング
Brian Goetz, Joshua Bloch, Doug Lea
  Javaや並行処理を甘く見てました
 
ビジュアライジング・データ - Processingによる情報視覚化手法
Ben Fry
  Processingすごくよいです
 
センネン画報その2
今日マチ子
  前作もよいがもっといい!
 
出現する未来
Peter Senge, C. Otto Scharmer, Joseph Jaworski, Betty Sue Flowers
  難しいけど到達したいです
 
図解 実戦マーケティング戦略
佐藤 義典
  栗日記も戦略的に行こう!
 
百日紅(上)(下)
杉浦日向子
  どう書けばいいかわからないけどすばらしい!
 
アルケミスト
パウロ・コエーリョ
  擦り切れるほど読んでます
 
X51.ORG THE ODYSSEY
佐藤 健寿
  X51.ORGの集大成
 
影響力の武器
ロバート・B・チャルディーニ
  思わず納得します
 

▼ せんでん