⚙️

TIL: UNIXプログラミング環境 第2章 (2)

2025/02/25に公開
6

UNIXプログラミング環境 第2章 2.4 ~ 2.7

内容はToday I Learnedということで、学びを記す記事です。
 詳しいわけではないので悪しからず。
書籍はこちら
UNIXプログラミング環境

2.4 ファイルの使用許可

全てのファイルは一群の使用許可を持っており、誰が何をして良いか決めている。
ただし、全てのUNIXシステムには、スーパーユーザと呼ばれる特別なユーザがいて、システム上の任意のファイルを読んだり、修正したりできる。rootと呼ばれることが多い。

rootのパスワードを知っていれば、suコマンド(スーパーユーザコマンド)で誰でもスーパーユーザになれ、どのファイルでも自由に閲覧、編集ができてしまう。

もしもっと堅牢なファイルを作成したければ、cryptコマンドを使って、スーパーユーザさえ読めないようにデータを変更することができる。(完全ではない)
具体的にはcryptコマンドの編集(相当な違法行為を覚悟)、cryptコマンドの解読がある(労力がかかる)。まあ諸々踏まえてcryptコマンドはだいぶ安全である。
もっとも気をつけなければいけなないのは、パスワードの盗難である。

システムがユーザを識別する方法は、ユーザに割り振られてたuidで判断していて、付随するグループ識別idでまとめて管理することが多い。root以外はotherグループにあり、その中にuidが多くあるイメージである。

システムが識別している方法はコマンドでも再現できる。
パスワードファイルを探索するコマンドは以下のように行う。

$ grep (ログインid) /etc/passwd
(パスワードなので見せられないよ)

例を示すと

you:gk54lJL2KJ2dlfje:604:1:Y.O.A,People:/usr/you:

のように:区切りで表記され、

(ログインid):(uid):(グループid):(その他):(ログイン・ディレクトリ):(シェル)
と並んでいる。

ちなみにMacOSでは出力できませんでした。

ファイルの権限表示

ls -l で権限一覧が表示可能。

$ ls -l

詳しくは1章のTILにまとめています。

例えば先ほどのパスワードが書かれてファイルは、

$ ls -l passwd
-rw-r--r--  (省略)

となっていて、ユーザはread とwriteが可能だが、sの他のユーザはreadのみであることがわかる。

ディレクトリの場合

ディレクトリの場合は

$ ls -ld .

のようにオプションにdを追加してやれば良い。

ディレクトリへの書き込みは、ファイルの作成権限を示す。

これらの権限を変更するには、chmodコマンド(change mode)を使用すれば良い。

以下のようにすると全てのユーザに実行権限を追加できる

$ chmod +x junk

権限を取り消す場合は、

$ chmod -w junk

のように-で指定すれば良い。

ディレクトリに対して書き込み権限を他のユーザに許可していた場合、そのディレクトリ内のファイルは誰でも削除できてしまう。

防ぐためには、ディレクトリの書き込み権限を削除する必要がある。

$ chmod -w .

.はカレントディレクトリを指定している。

2.5 iノード

ファイルは名前と内容の他に、使用許可や修正時刻といった管理情報がある。
これらはinodeの中に蓄えられている。

inodeの中には3種類の時刻情報がある。

  • ファイルの内容が最後に修正された時刻
  • 最後にファイルが使われた時刻
    • 読み込まれたか実行された
  • inode自身の最後に修正された時刻
    • 使用許可を設定したなど
$ date >junk
$ ls -l
-rwxr-xr-x  1 (ユーザ名)  staff   48  2 23 18:38 junk
$ chmod +x junk
$ ls -lu
-rwxr-xr-x  1 (ユーザ名)  staff   48  2 23 18:38 junk
$ ls -lc
-rwxr-xr-x  1 (ユーザ名)  staff   48  2 23 18:42 junk

このようにjunkに対するchmodコマンドは、ls -l結果(最終更新日)に影響を与えない。
しかしls -lcの結果には影響を与えている。

-luと-lcのコマンド解説
  • -lu オプションは更新日の代わりに最終アクセス日を表示する。
  • -lc オプションは更新の代わりにファイルの属性など変更した時刻
  • -i iノードの番号を10進数で表示できる。ファイルに対して情報をもったiノードが紐づけられている

ディレクトリとファイルの関係はリンクを貼っているに過ぎない

ディレクトリの名前の横に書かれた最初の2バイトがi番号。
MaxOSではできませんでした。(LinuxのVM立てて実験してみたいけど手間なのでまた今度)

リンクの話を書籍通りに解説します。
リンクを貼っているに過ぎないというのは、od -d recipesをした時の結果をみて、先頭の2バイトがファイルの内容が書かれている在処を示すアドレスを格納していることからわかります。

od をディレクトリに対し実行して、文字列で表示させると以下のようにファイル名の前に2バイト分、数値が入っています。

$ od -c .
0000000 4; (省略)
0000020 273; r e c i p e s (省略)

この2バイト分の数値が実際のデータとリンクしている部分です。
そのうち1バイト目の数値はi番号を格納しており、rmコマンドはこのi番号を削除するものだそうです。

実際のデータはどこかに残っていて(今回だと273に残っている)、リンクだけを削除することで、ディレクトリ内から削除したように見せているわけです。

リンクの目的

同一のファイルに二つの名前を与えることがリンクの目的です。

$ ln junk linktojunk
$ ls -l
-rw-r--r--  2 (本名だよ) staff   48  2 23 18:38 junk
-rw-r--r--  2 (本名だよ) staff   48  2 23 18:38 linktojunk
drwxr-xr-x  4 (本名だよ)  staff  128  2 22 18:51 recipes

lnはリンクを貼るコマンドで、(本名だよ)と権限の間にある数値がリンクの数である。

:::messages
recipesディレクトリの中身は2つファイルだが、4つリンクを持っているとわかる。どうしてだろう。
有識者の方コメント待っています。
ls -ld recipesがヒントだそうです。

コメントいただきました。感謝します!
:::

片方を編集しても両方同じになる。

$ echo edit >>junk
$ cat junk
20252月23日 日曜日 18時38分54秒 JST
edit
$ cat  linktojunk
20252月23日 日曜日 18時38分54秒 JST
edit

また二つのファイルはリンクが同じなので、同i番号を持つ。

$ ls -li
141462858 -rw-r--r--  2 (本名だよ)  staff   53  2 25 00:00 junk
141462858 -rw-r--r--  2 (本名だよ)  staff   53  2 25 00:00 linktojunk

linktojunkを削除するとリンクの数が減る。

$ rm linktojunk
$ ls -l
-rw-r--r--  1 (本名だよ) staff   53  2 25 00:00 junk

最後のリンクを削除すると、そのデータは呼び戻せなくなる。

お互いに干渉しない同ファイルが 欲しい場合はcpコマンド

$ cp junk copyofjunk
$ ls -li
141478967 -rw-r--r--  1 (本名だよ)  staff   53  2 25 00:07 copyofjunk
141462858 -rw-r--r--  2 (本名だよ)  staff   53  2 25 00:00 junk

違うi番号を持っていることがわかる。
コピーをとってから権限を変更しておくと、バックアップを誤って消す確率が小さくなる。

mvコマンドはリンクの書き換え

ディレクトリを超えてファイルを移動させるコマンドであるが、これもリンクを元に実現している機能とのこと。

例えば同階層に別名で移動させる(つまりリネーム)と、以下のようになる。

$ ls -li
141462858 -rw-r--r--  2 (本名だよ)  staff   53  2 25 00:00 junk
$ mv junk sameoldjunk
$ ls -li
141462858 -rw-r--r--  2 (本名だよ)  staff   53  2 25 00:00 sameoldjunk

この通りi番号が同じで、ファイル名だけ変わっている。つまりリンクの入り口(ディレクトリ)を変更していることがわかる。

別ディレクトリに移動した場合は、そのディレクトリにリンクを追加しているわけですね。

2.6 階層化ディレクトリ

階層化されている + UNIXの構成を紹介した節でした。

まとめるのは大変で学びがないので書籍をご覧ください。

2.7 デバイスファイル

同じくUNIXの構成の話がメインでした。

UNIX自体を作れるようになりたい人は2.6と2.7を読んで多大な時間をかければ作成できるんじゃないかという内容でした。(ちょっと過言です)

まとめ

いつか本名をうっかりコピペしてしまいそうで怖いです。まあ別に公開してもいいんですけどね。

  • iノードにファイルの情報がまとめられている
  • iノードへのリンクでファイルの階層化を実現している
  • ファイルの操作は実質的にリンクの操作であることが多い。

UNIXシステムの本質がだいぶ見えてきました。
裏側の動きがわかったおかげで、表の動きの不自然さが何ら自然であるという機会が増えると思います。
2章を二つに分けてしまいましたので、前回の記事も併せて読んでいただけると理解が進むかなと思います。

Discussion

ko1nksmko1nksm

現在のシステムでは /etc/passwd にパスワードは記録されていません。
暗号化されたパスワードは : 区切りの2列(gk54lJL2KJ2dlfje の部分)ですが、現在のシステムでは x または * となっています。見せても安全です。

端くれエンジニア端くれエンジニア

勉強になります!

見せても安全です。

判断がつかないものは見せない精神でした。笑
現行のシステムにあった書籍も探してみます!

ko1nksmko1nksm

recipesディレクトリの中身は2つファイルだが、4つリンクを持っているとわかる。どうしてだろう。

recipesディレクトリの中身は2つのディレクトリですが、4つのリンクを持っている理由は次の図のとおりです。

/usr/you       にある  recipes からの参照
└ recipes      にある  . (自分自身)からの参照
    ├ pie      にある .. (親ディレクトリ)からの参照
    └ cookie   にある .. (親ディレクトリ)からの参照

なお、当時の Unix では . と .. は実際にディスク上に作成されている(はずの)リンクですが、現在の Unix/Linux では実際にはディスク上に作成されておらず、互換性を保つためにそこにあるかのように見せかけています。

なお、ヒント($ ls -ld /usr/you を実行してみよ)の意味と、役に立つ情報になるのかの理由は正直よくわかりません。あまり実際の用途で役になった記憶はなく、ファイルシステム上の仕組みの何か(ディレクトリが削除するタイミング?階層構造の実現の仕組み?)の話をしたいのか謎です。

端くれエンジニア端くれエンジニア

コメントありがとうございます!

recipesディレクトリの中身は2つのディレクトリですが、4つのリンクを持っている理由は次の図のとおりです。

勉強になりました。

なお、ヒント($ ls -ld /usr/you を実行してみよ)の意味と、役に立つ情報になるのかの理由は正直よくわかりません。あまり実際の用途で役になった記憶はなく、ファイルシステム上の仕組みの何か(ディレクトリが削除するタイミング?階層構造の実現の仕組み?)の話をしたいのか謎です。

実行した肌感覚があっていて嬉しい反面、書籍を信じて良いのか不安になるのが怖くなりました。笑
歴史を学ぶ意識をしつつ、シェルの基本とかシステムの構成をメインに学んでいきます!

ko1nksmko1nksm

本自体は良い本なのですが、さすがに時間が経ちすぎて現在といろいろと状況が変わっているところがありますからね。とはいうももの40年前の割には現在にも通づるところが多くUnixの設計の素晴らしさも見えてくるわけですが。

問題に対してのアンサーブックとか発売されてないのかな?と思って探したのですが見つかりませんでした。代わりに自分なりの回答を書いている人を見つけたので参考になるかもしれません。
https://github.com/Icermli/the-unix-programming-environment

それと、この本を読んで感想を書こうみたいな2020年のスレッドを見つけたので参考になると思います。
https://nixers.net/Thread-Nixers-Book-Club-Book-1-The-UNIX-Programming-Environment