実家なう
「実家に帰ったら教科書でも読んで勉強するかー」
...のつもりが関係無い本(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
プログラミング問題。…めんどいし作業っぽいのでパスにしようそうしよう
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.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ぐらいは暇ならまたやろう。ちょっと気になる。