最低限 Unix / Linux [I]

発展. パーミッション付録

必修

  1. アカウント作成とログイン, ログアウトの作法(2020年度は実施しません)
  2. Unix の代表的なコマンド
  3. ファイルとディレクトリ
  4. パーミッション

発展

  1. ユーザ情報に関するファイル
  2. ルートディレクトリにある主なディレクトリ
  3. パーミッション付録

付録

本節では, ファイルモードの詳細や, ls -l コマンドで表示される他の項目について説明します.

・ファイルモード

自分のホームディレクトリで ls コマンドを幾つかのオプションを指定して 実行すると, 例えば以下のような出力が得られます.

$ ls -Flag
total 36
drwxr-xr-x 3 foo      4096 Apr 27 18:45 ./
drwxr-xr-x 3 root     4096 Apr  6 18:47 ../
-rw------- 1 foo       371 Apr 27 11:41 .bash_history
-rw-r--r-- 1 foo       220 Apr  6 18:47 .bash_logout
-rw-r--r-- 1 foo      3198 Apr  7 18:15 .bashrc
-rw-r--r-- 1 foo      3184 Apr  6 18:47 .bashrc~
drwxr-xr-x 3 foo      4096 Apr  7 18:16 .emacs.d/
-rw-r--r-- 1 foo       675 Apr  6 18:47 .profile
-rw-r--r-- 1 foo         9 Apr 27 18:45 hoge.txt
drwxr-xr-x 2 foo      4096 Apr 27 18:49 work/

この出力の下から 2 行目を例に取って, この読み方を解説します. 左から順に,

-rw-r--r-- ファイルモード
1 ファイルへの"リンク数"
foo ファイルの所有者
9 ファイルの大きさ(バイト単位)
Apr 27 18:45 ファイルの最終更新時刻
hoge.txt ファイルの名前

を表しています. これらをファイルの「属性」と呼びます (なお,
$ man ls


としてみるとより詳しいことが分かります).

一番左側の表示の文字列はファイルの「モード」, すなわち ファイルの型 (type) と利用権限 (permission) を表しています. 例えば, hoge.txt のすぐ下の work/ を見ると,

d rwx r-x r-x

と書かれてあります.

左端の 1 文字はファイルの型を示します. 取りうる文字と型は後述します.

続く文字列で利用権限を示しています. 利用権限の許可対象には,

があり, それぞれに対する許可情報を,

と読んでいます.

また利用権限には,


の 3 種類があります. ファイルモードの読み方は,
  d rwx r-x r-x
  ^ ^^^ ^^^ ^^^
  |  |   |   |
  |  |   |   アザーズパーミッション
  |  |   |
  |  |   グループパーミッション
  |  |
  |  ユーザパーミッション
  |
  ファイルの型(type)

となります. 各箇所で取りうる文字は,
  - --- --- ---
  d rwx rwx rwx
  l   s   s   t
  s   S   S
  b
  c
  P

です.

左端の文字とファイルの型は, 次のように対応づけられています.

- 通常のファイル
d ディレクトリ
l シンボリックリンク
s ソケット
b ブロックデバイス
c キャラクタデバイス
P 名前つきパイプ

また, 利用権限は以下の通りです.

- その権限が出ていない
r 読み込み許可
w 書き込み許可
x 実行許可
s s ビットが立っていて, かつ実行許可
S s ビットが立っていて, かつ実行不可
t スティッキー(sticky)

s ビット, スティッキーについては後述します

上の出力結果において, ドット (.) で始まるファイルが存在したと思います. これはユーザの環境を設定する為のファイルで「ドットファイル」と呼ばれます. オプションをつけずに ls コマンドを打っても表示されません. その為隠しファイルと呼ばれることもあります. この実習では特に設定を変えることはありませんので, 詳細については触れないことにします.


※ファイルの所有者, ファイルの属するグループを変更するには chown, chgrp といったコマンドを使用します.

利用権限の設定 (ファイルモードの設定)

ファイルの利用権限を設定するには chmod コマンドを用います. 基本的な使い方は次の通りです(詳しくは man chmod).

$ chmod <mode> file1 [file2 ...]

<mode> の部分には 0 から 7 までの数字を 3 桁並べたものが入ります. 左の桁から順にファイルの所有者, ファイルの所属グループ, その他のユーザに対する利用権限を示します. 各々の読みだし, 書き込み, 実行権限は 4, 2, 1 の数字で表され, 上の <mode> にはこの数字の和が代入されます.

許可 記号 数字
読込 r 4
書込 w 2
実行 x 1

例えば, モードを -rw-rw-r-- と変えたい場合,

-rw-rw-r--	
 42 42 4
 |  |  |
 6  6  4  <mode>
となるので,
$ chmod 664 file
とすれば変更できます.

上では <mode> を数字で与えましたが, 記号で与えることもできます. <mode> の数字列の代わりに,

対象 操作 許可
[ugao] [+-=] [rwxst]

という形式を "," で区切って並べます.

対象と操作の文字は以下の意味を表します.


※許可の所はファイルモードと同じです.
対象   操作
u :所有者
g :グループ
o :その他のユーザ
a :全員(ugo と同じ)
 
+ :許可を与える
- :許可を取り消す
= :許可を設定する

この場合, 先の例と同じ設定にするには次のようにします.

$ chmod u=rw,g=rw,o=r file

グループという概念について

ここまでグループという語が何度か出てきました. グループとは複数のユーザを管理する為の単位で, 共同作業する際に便利です. 例えば, 研究室において複数の人間がファイルを共通で管理したい場合に グループという概念は非常に重要なものとなるでしょう.

ここではグループの作成, ユーザのグループへの追加の方法を学び, グループの有用性を体感してみましょう.

グループを新たに作成する為には, addgroup というコマンドを用います. 但し, アカウントを新たに作成するコマンド adduser 同様, root でなければ addgroup コマンドを実行することは出来ません. VTA の人に addgroup コマンドを実行してもらいましょう (VTA の人は別ターミナルで su を使って一般ユーザになった後, sudo を実行して root になって下さい).

# addgroup inex

これで inex というグループが作成された筈です. 前回のレクチャーで少し触れましたが, グループの基本情報は /etc/group に記述されています. このファイルは一般ユーザでも閲覧できますので, 受講生の皆さんは /etc/group の中身を見てみましょう.

$ less /etc/group

/etc/group の最下行に以下のような記述があると思います. この行は addgroup を実行したことによって加わったものです.

inex:x:1005:

この時点で inex グループに所属するユーザはいません. 再び root である VTA の人の力を借りて, 皆さんと VTA の人をグループに追加してもらいましょう. グループの追加は adduser コマンドで行うことが出来ます.

# adduser foo inex

これで foo というユーザが inex グループに追加された筈です. /etc/group を見ると, 先程の行の一番右のコロン以下にユーザ名が記述されているのが 確認できると思います. 同様の手順で VTA のアカウントもグループに追加しましょう (これ以降 VTA の人のアカウント名が vta であるとして話を進めます).

inex:x:1005:foo, vta

もう 1 つ VTA の人に作業をしてもらいましょう. /home 以下に作業ディレクトリ work を作ります. 更に所有者・所有グループを変更するコマンド chown を用いて, work ディレクトリの所有者を foo, 所有グループを inex とします. またグループの書き込みを許可します.

# cd /home
# mkdir work
# chown foo:inex work
# chmod g+w work

受講生の皆さんは ls -l コマンドを使って work ディレクトリの所有者・所有グループを確認してみてください.

$ ls -l /home/
drwxrwxr-x 2 foo inex      4096 Apr 28 02:28 work

ここで work ディレクトリ内にファイルを作成してみましょう. めでたくファイルが作成出来たと思います.

$ cd /home/work/
$ echo "test" > test.txt
$ ls -l
-rw-r--r-- 1 foo  foo  7 2011-04-28 03:24 test.txt

ところが, 実はこれだとめでたくないのです. vta は inex グループに入っているのですが, この状態では vta が test.txt を編集することは出来ません. つまりこれでは inex グループに入っている foo, vta の 2 人がファイルを編集できる状態にはなっていないのです.

そこで次のコマンドを実行してみましょう.

$ sg inex
$ echo "test" > test2.txt
$ ls -l
-rw-r--r-- 1 foo  foo   7 2011-04-28 03:24 test.txt
-rw-r--r-- 1 foo  inex  7 2011-04-28 03:29 test2.txt

test2.txt の所有グループが inex になりましたね. sg コマンドは, 指定したグループでコマンドを実行する為のコマンドです. この場合 inex グループとして test2.txt を作成したので, 所有グループが inex となっています.

これで一見めでたくなったかに思われるのですが, 当初の目標である 「foo, vta の 2 人がファイルを直接編集できる状態」にはなっていません.


発展問題: text2.txt を foo, vta が直接編集できるようにするには, vta はどうすれば良いか (但し root 権限は使わないものとする).

s ビット

s ビットとは, あるファイルの実行者を「成り変わる」機能のことを言います. s ビットには, SUID ビットと SGID ビットの二種類があります.

具体例で見て行きましょう. SUID の例として /usr/bin/passwd を見てみます.

第二回目の実習で, passwd コマンドが出てきました. この passwd は /usr/bin/ ディレクトリに存在します (前回登場した /etc/passwd とは別物であることに注意しましょう). passwd コマンドを実行してパスワードを変更すると, /etc/shadow が書き変わるのでしたね. そこで, /etc/shadow のパーミッションを見てみると,

$ ls -l /etc/shadow
-rw-r-----    1 root     root        22485 Apr 28 03:52 /etc/shadow

ですから, このファイルの書き込みができるのは, このファイルの持ち主, すなわち root だけです. しかし, 誰もがパスワードを変更したい (/etc/shadow が書き変わって欲しい) と思っています. どうやって /etc/shadow を書き変えることができるのでしょうか?

そこで /usr/bin/passwd のパーミッションを見てみます. すると,

$ ls -l /usr/bin/passwd
-rwsr-xr-x    1 root     root        24680 Apr  1 02:50 /usr/bin/passwd
となっています.

左から 4 番目に s という文字が書かれています. これが SUID ビットで, このファイルが実行されると, プログラムの持ち主がこのファイルを実行したものと解釈されることを表します. つまり, passwd コマンドを実行すると, root が実行したものと解釈される のですから, /etc/shadow を書き換えることができるという訳です.

root が所有者であるファイルやディレクトリに対して, SUID ビットを設定する場合は注意が必要です. 仮の話ですが (実際はそうなっていませんので安心してください), 例えば passwd にバグ (不具合) が含まれていて, 他のユーザのパスワードを変えることができるようになってしまっていたとしたら, SUID ビットを設定することによって大惨事が起こってしまうことになるでしょう (誰かに他のユーザや root のパスワードを変えられたら, 場合によっては恐ろしいことになるわけです).

SGID は上のグループ版です. 似たようなものなので説明は割愛します.

・リンク

リンクとは, あるファイルやディレクトリを, 別のファイルやディレクトリに関連付ける仕組みをいいます.

リンクには,

の2種類があります.

ハードリンク

先に ls コマンドを用いた説明で, その実行結果の左から2番目に表示される数字は, リンク数を表すと述べました.

$ ls -l sample.txt
-rw-r--r--   1 inex     epnetfan      363 Jun 20 12:11 sample.txt

これは正しくは「ハードリンク」の数を表しています. ハードリンクの数は, 簡単に言うとファイルの「名前」の数を表しています.

人間は文字列(上の場合 'sample.txt')でファイルを識別しますが, システムはファイルを「番号」として管理しています. Unix では, この番号を「i-ノード」と呼びます. ファイルと i-ノード番号は1対1に対応(リンク)しています.


※以下, 小文字の箇所は, 最初は読み飛ばして良い.

i-ノードという概念は, そもそも Unix のカーネルが, それぞれのパーティションに, 装置番号 (device number) を割り当て, 「ディスク」ではなく「ファイルシステム」 という論理的なレベルで処理を行うことに由来しています. ファイルシステムは, 論理的なブロックの集まりから構成され, 単位となるブロックの大きさはシステムによって異なります.

ファイルシステムは, 次のような4つの部分に分けられます.

i-ノードには, 次のような情報が含まれています. ここで注意して欲しいことは, i-ノードにはファイル名は含まれていないということです.

ls -i とするとファイルの i-ノード番号を実際に見ることができます.

$ ls -i sample.txt
  31657 sample.txt

ハードリンクの数は, 実はそのファイルの対応している i-ノード番号を 参照しているファイルの数を表しています.

したがって同じ i-ノード番号をもつ別名のファイルを作ること, 即ちファイルに複数の名前をつけることができます. これは "ln" コマンドで実行できます.

touch コマンドで空のファイル file1 を作り試してみましょう. 通常ファイルのリンク数は 1 です.

$ touch file1
$ ls -l file1
-rw-r--r--   1 inex     epnetfan   0 Jun 27 02:39 file1

ここで
$ ln file1 file2
とすると file1 に新しい名前 file2 を加える(リンクを張る)ことができます.
$ ls -l file1 file2
-rw-r--r--   2 inex     epnetfan   0 Jun 27 02:39 file1
-rw-r--r--   2 inex     epnetfan   0 Jun 27 02:39 file2

リンク数が 2 に増えています. 一方ディレクトリのリンク数は必ず 2 以上になります. リンクを消すには rm コマンドを使います.

シンボリックリンク

上の ln コマンドにオプション -s をつけて実行してみます. これは「シンボリックリンク」と呼ばれ, 簡単にいうとファイルの「別名」をつけるようなものです. 類似のものに, Windows では「ショートカット」, Mac では「エイリアス」があります.

$ ln -s file1 file3
$ ls -l file1 file3
-rw-r--r--   2 inex     epnetfan   0 Jun 27 02:39 file1
lrwxrwxrwx   1 inex     epnetfan   5 Jun 27 02:45 file3 -> file1

ハードリンクの場合は i-ノードを直接参照しているのに対し, シンボリックリンクは「ファイル名」を参照しています. 従って、上の例でも file1 のリンク数も増えませんし, file3 のリンク数も 1 のままです.

シンボリックリンクの特徴をみるため, 次のようにコマンドを実行してみましょう.

$ rm file1
$ cat file3
cat: file3: No such file or directory

するとエラーが返されます. しかし,
$ ls file3
file3

となり file3 そのものは存在します.

これはシンボリックリンクでは「ファイル名」を参照しているためです. 参照先のファイル名が消去されてしまうと, 参照していたファイルの i-ノードを見ることができなくなり, 上の例では file3 を表示しようとするとエラーが返るのです.

ハードリンクとは異なり, ディレクトリに対するシンボリックリンクは可能です. シンボリックリンクを消すにはやはり rm コマンドを使います.

・その他の解説

スティッキー(sticky)ビット

スティッキービットとは, ファイルまたはディレクトリの所有者だけが目的のファイルの削除や名前の変更を行えるようにする機能のことです.

s ビットの時と同様に具体例で見て行きましょう. "/" (ルートディレクトリ) の下には tmp というディレクトリがあります. このディレクトリのパーミッションを見ると,

$ ls -l /
drwxrwxrwt   6 root     root    1024 Jul  1 12:16 tmp

となっています.

これによるとこのディレクトリは誰でも読み書きができるようになって いますが, 「アザーズ」の実行許可のところに t と書かれています.

これがスティッキービットで, それによって, このディレクトリの中にあるファイルの消去や名前の変更は, そのファイルの所有者だけが行えるようになるということになります.

デバイスファイル

ls -l /dev としてみると以下のような出力が得られます.

$ ls -l /dev/
total 50
-rwxr-xr-x   1 root     root   14373 Nov 30  1996 MAKEDEV*
-rwxr-xr-x   1 root     root   28676 Nov 30  1996 MAKEDEV-C*
-rw-r--r--   1 root     root    1035 Nov 30  1996 README.MAKEDEV
-rw-r--r--   1 root     root    1434 Nov 30  1996 README.MAKEDEV-C
lrwxrwxrwx   1 root     root       4 Jan 15 21:46 X0R -> null
crw-r--r--   1 root     root 10, 134 Jun  8  1996 apm_bios
crw-------   1 root     root 16,   1 Feb 19  1994 arp
crw-rw-rw-   1 root     sys  10,   3 Jul 18  1994 atibm
crw-rw-rw-   1 root     sys  14,   4 Jul 19  1994 audio
crw-rw-rw-   1 root     sys  14,  20 Jul 19  1994 audio1
brw-r-----   1 root     disk 29,   0 Feb 16  1995 aztcd
crw-r--r--   1 root     root 10, 128 May 25  1996 beep
.
.
.
crw-r-----   1 root     disk 27,  25 Dec  8  1995 zqft1
crw-r-----   1 root     disk 27,  26 Dec  8  1995 zqft2
crw-r-----   1 root     disk 27,  27 Dec  8  1995 zqft3

ファイルモードを見ると, 一番左が見慣れない c や b になっています. このようなファイルは通常のファイルではありません.

Unix では基本的にあらゆる物を抽象化して「ファイル」として扱います. たとえばマウス(/dev/mouse) や画面等もファイルに抽象化して取り扱ってしまいます.

このようなファイルは「デバイスファイル(device file)」と呼ばれます. デバイスファイルには, c で表されるキャラクタデバイスと, b で表されるブロックデバイスがあります.

ソケット

ソケットはプロセス間通信の終端点です. プロセス間通信には, パイプや TCP/IP (第 4 回) などいろいろな方法がありますが, その中に数えられる Unix ドメインのソケット (同一コンピュータの内部で閉じたプロセス間通信で使うソケット) はファイルとして見えます.

代表的なソケットとしては以下の 2 つがあります.

$ ls -l /dev/{log,printer}
srw-rw-rw- 1 root root 0 2011-04-27 06:25 /dev/log
srw-rw---- 1 root lp   0 2011-04-25 06:47 /dev/printer 

ファイルタイプには s と書かれています. これがソケットを表します. /dev/printer はプリンタにつながっているソケットですが, 直接プリンタデバイスにつながっている訳ではありません. lpd (line printer daemon) が中継します. このソケットは, lpr コマンド (印刷するためのコマンド) が lpd デーモンと通信する時に使われます.

名前付きパイプ

その名のとおり, 名前がついたパイプのことです. Unix 内のプロセス間通信を行うために用いられます. 普通のパイプの場合, 親子または兄弟のプロセス間でしか通信できないという制限がありますが, 名前つき パイプの場合, 親子兄弟関係にないプロセスとも通信できます.

$ mknod pipe p
$ ls -l pipe
prw-r--r-- 1 foo foo  0 2011-04-28 22:21 pipe 

ファイルタイプに p と書かれていることが, 名前つきパイプであることを表しています. 実際に名前つきパイプを作ってみましょう.
もう一つ kterm を開きます.

$ xfce4-terminal &

1 つ目のターミナルで cal コマンドを用いて, pipe に書き込みます.

$ cal > pipe

2 つ目のターミナルでカレンダー中の 2015 を抜き出します.

$ grep 2015 pipe
    4月 2015

このように, 名前つきパイプを使うことで「cal | grep 2015」を分けて使うことができます.


情報実験第二回のページへ戻る

最終更新日: 2018/04/16(村橋究理基) copyright © 2000-2018 inex