実家なう

「実家に帰ったら教科書でも読んで勉強するかー」
...のつもりが関係無い本(Unix/Linuxプログラミング 理論と実践)を読んでいたの巻*1
この手の本は例解UNIXプログラミング教室以来なので2冊目。前回は手を動かす量が足りておらず、消化不足な気分を味わったので、今回はもうちょっと真面目に読む…のかもしれない。

まぁせっかくなので読書ログでも残すとする。
章末の解答(?)はもちろん正しいか知らないからね!*2

1章

イントロダクション。OSの役割やユーザー空間、システム空間の話のあとは、Unixの基本的な説明等々。
後半ではmore擬きを作る。stdinを読んで出力しようとすると、入力が取れなくなるので、入力は/dev/ttyから取るとかそんくらい。非カノニカルモードにするわけじゃないのでReturn押さんと入力が伝わらん等々、むっちゃくちゃ未完成品だけど。

2章

whoっぽいのを作る。whoのマニュアルからutmpファイルの情報を得て、utmpのマニュアルを読んだりutmp.hを見たりしていく流れ。そのあとはopen,read,write,close等のシステムコールの説明。
その次はcpっぽい何か。openしてreadしてwriteするだけの簡単な例。そしてバッファリングやシステムコールの時間の話。ついでにカーネルバッファリングの話も。
最後はログアウトの話。utmpファイルをいじる…というか要するにlseekを使う例。

章末

2.1

wコマンドはログインしている人に加えて、その人がやっていることを表示。/var/run/utmp以外に/proc以下が情報源。

2.2

システム起動時にutmpファイルをどうするか?
手元のman曰く「最初のエントリは init(8) コマンドが inittab(5) を処理することで作られる」らしい。色々blogに書くのめんどいので他はman見て理解したということにする(おい

2.3

ファイルを/dev/ttyにcpしてみろとかそういう話。

2.4

FILE構造体を調べろとか。
stdio.hで typedef struct _IO_FILE FILE されていて、libio.hの_IO_FILE構造体の宣言が。 読む時は_IO_read_ptrとか見ていく感じなのかな、バッファリングで読んだ奴を。ごめんなさいよくわかりません…。

2.5

カーネルバッファのディスクへの書き込み。fflush(3)のマニュアル曰くsync(2)とかfsync(2)を用いればいいらしい。

2.6

同じファイルの複数回オープンとか。
オフセットはファイルについてじゃなくて、ファイルと接続についての属性だろうから、(f)で20バイト読むと最初の部分は "testing 1 2 3..."に上書きされてる。

2.7

manについて何で学ぶか。

man man
2.8

utmpファイルには現在のログインセッションに対応してないのが云々。
よくわからんのでパスで…。

2.9

末尾移行にseekして書き込みするとholeができる。lseek(2)のマニュアル参照。

2.10-2.15

プログラミング問題。…めんどいし作業っぽいのでパスにしようそうしよう

最後のパズル:tailコマンド

適当にシークして書いてみた。んでBSDのソース見るとmmapとかある…初めて知った…これがゆとり…

3章

まずはls -lを作ってみる話から。opendir(3)とかreaddir(3)で得られる情報だと足りない->statシステムコールで情報を得よう みたいな流れ。そのあとはファイルモードの話とかUID、GIDの話(/etc/passwdとか/etc/groupの紹介とかetc)
suidビットとかsgidビットは知っとったが、stickyビットは勉強不足だった。/tmpってls -lするとモードはdrwxrwxrwtだけど、tってstickyビットのことだったのね。

3.1

dirent構造体のd_nameの長さ。readdir(3)のmanには「最大でNAME_MAX個の文字と、それに続く終端の NULL バイトが格納される。」とあるが、なんで定義が1や255だったりするのかとか、何故char*と定義しないかとかはサッパリだにゃ…。

3.2

chmod 007 filename とするとどうなるか。またパーミッションの組合せを試しopen(2)のロジックを突き止め、実際カーネルのソースを見て確認してみろ、という話。
パーミッションを007にすると他の人は読めても自分が読めない。ということで読みでopenする場合は 所有者ならS_IRUSR、所有グループならS_IRGRP、それ以外はS_IROTHをチェックしてると妄想。
実際カーネルのソース見てみると、open(2)はエントリルーチンがsys_open()で、sys_open()がdo_sys_open()を呼び、do_filp_open()を読んでるっぽい*3
さらにそこからmay_open() inode_permission() generic_permission() acl_permission_check() と行って、その中で以下みたくチェックしてるけど、ここらへん?もう正直さっぱり。
と思ったけどinode->i_op->permissionがNULLじゃなければ generic_permission() の変わりにそっちを呼ぶのか。もう知らん…

static int acl_permission_check(struct inode *inode, int mask,
		int (*check_acl)(struct inode *inode, int mask))
{
	umode_t			mode = inode->i_mode;

	mask &= MAY_READ | MAY_WRITE | MAY_EXEC;

	if (current_fsuid() == inode->i_uid)
		mode >>= 6;
	else {
		if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) {
			int error = check_acl(inode, mask);
			if (error != -EAGAIN)
				return error;
		}

		if (in_group_p(inode->i_gid))
			mode >>= 3;
	}

	/*
	 * If the DACs are ok we don't need any capability check.
	 */
	if ((mask & ~mode) == 0)
		return 0;
	return -EACCES;
}

しかし勢いでソース落としてきたけどほんとサッパリだな。

3.3

異なるユーザーでも同じUIDは持てるか等の話。
man見るとuseradd(8)で-o指定すれば重複したUIDでユーザーの作成ができるらしい。ほえー。hogeさんと同じUIDのfugaさん作って、fugaさんのhomeでls -lすると所有者がhogeさんに見える。rmとかお互い余裕で成功。あとで作ったfugaさんでchshすると自分は変わらず、hogeさんが変わっちゃってる。実際/etc/passwdを見るとそんな記述に変更されてる。/etc/passwdの順番がhoge,fugaの順に書いてあるので、UIDで調べてくとhogeさんが優先されちゃうのかにゃ。…まぁもういいや。
しかし同じIDにする意味ってあるのかな。エイリアスという感じで使うのかしら。。。

3.4

ディレクトリのsgidビットをオンにするとどうなるか。
「ファイルを作成するとその所有グループはディレクトリの所有グループと同じになる 」らしい*4
共同作業とかの場合便利なのかな

3.5

実行可能な内容と実行可能パーミッションは関係あるか?
無い…よね。a.outとかはfile(1)見るに、先頭付近の特定位置に「マジックナンバー」が格納されているので、それで見分けられるっぽい。

3.6

ログイン名とUIDという2つのIDが存在する理由。
ユーザーとしちゃUIDで区別されてもさっぱりだが、システムの方としちゃぁUIDとかの方が便利だから、とかしか思いつかない…。

3.7

getdents(2)は何をする?

これはあなたの関心を引くような関数ではない。 POSIX 準拠の C ライブラリインターフェースについては readdir(3) を見ること。このページは、カーネルシステムコールの生のインターフェースについて記載したものである。

http://www.linux.or.jp/JM/html/LDP_man-pages/man2/getdents.2.html

…そうですか。機能はファイル記述子からdirent構造体を読み出してくるのね。

3.8

ディレクトリの実行可能ビットとは何か。
ここのページが分かりやすかった。実際rだけオンにするとlsで名前は取れるがそれ以上の情報は無理。xだけ立ってるとlsは無理でも中のファイルにcatとかできる。

3.10-3.22

プログラミング課題はもうめんどいしいいや…
3.17ぐらいは暇ならまたやろう。ちょっと気になる。