fsck
boot系
以前やった、kernel以前について、どんな舞台裏になってるか探る。cd arch/i386/stand して、そこで make -n なんて言うドライ・ランしても、難読化されたシェルスクリプトが出力されるだけだった。
じゃ、本物のmakeはどうだ?
qm# make ===> mbr sh /usr/src/sys/arch/i386/stand/mbr/../../../../kern/genassym.sh cc -no-integrat ed-as -Oz -Wall -Werror -ffreestanding -fno-stack-protector -DMDRANDOM -MD -M P -I/usr/src/sys/arch/i386/stand/mbr/../../../.. -I/usr/src/sys/arch/i386/stand /mbr/../libsa -I. -I/usr/src/sys/arch/i386/stand/mbr < /usr/src/sys/arch/i386/ stand/mbr/../etc/genassym.cf > assym.h.tmp && mv -f assym.h.tmp assym.h cc -I/usr/src/sys/arch/i386/stand/mbr -I/usr/src/sys/arch/i386/stand/mbr/../../ .. -fno-pie -I/usr/src/sys/arch/i386/stand/mbr/../../../.. -I/usr/src/sys/arch /i386/stand/mbr/../libsa -I. -I/usr/src/sys/arch/i386/stand/mbr -c -MD -MF mbr.d -o mbr.o mbr.S ld -nostdlib -Ttext 0 -x -N -s -Bstatic -e start -nopie -znorelro -o mbr mbr.o text data bss dec hex 512 0 0 512 200 -rwxr-xr-x 1 root wsrc 512 Oct 20 05:32 /usr/src/sys/arch/i386/stand/mbr/mbr ===> cdbr : ===> biosboot sh /usr/src/sys/arch/i386/stand/biosboot/../../../../kern/genassym.sh cc -no-int egrated-as -Oz -Wall -Werror -ffreestanding -fno-stack-protector -DMDRANDOM - MD -MP -DLOADADDR=0x40000 -DLINKADDR=0x40120 -DBOOTMAGIC=0xc001d00d -I/usr/src /sys/arch/i386/stand/biosboot/../../../.. -I/usr/src/sys/arch/i386/stand/biosboo t/../libsa -I. -I/usr/src/sys/arch/i386/stand/biosboot < /usr/src/sys/arch/i38 6/stand/biosboot/../etc/genassym.cf > assym.h.tmp && mv -f assym.h.tmp assym.h cc -no-integrated-as -fno-pie -DLOADADDR=0x40000 -DLINKADDR=0x40120 -DBOOTMAGI C=0xc001d00d -I/usr/src/sys/arch/i386/stand/biosboot/../../../.. -I/usr/src/sys /arch/i386/stand/biosboot/../libsa -I. -I/usr/src/sys/arch/i386/stand/biosboot - c -MD -MF biosboot.d -o biosboot.o biosboot.S ld -nostdlib -Ttext 0 -N -x -Bstatic -nopie -znorelro -T /usr/src/sys/arch/i386/ stand/biosboot/ld.script -o biosboot biosboot.o text data bss dec hex 512 0 0 512 200 ===> boot sh /usr/src/sys/arch/i386/stand/boot/../../../../kern/genassym.sh cc -no-integra ted-as -Oz -Wall -Werror -ffreestanding -fno-stack-protector -DMDRANDOM -MD - MP -m32 -D_STANDALONE -nostdinc -fno-builtin -fpack-struct -D__INTERNAL_LIBSA_CR EAD -fno-pie -I/usr/src/sys/arch/i386/stand/boot/../../../.. -I/usr/src/sys/arc h/i386/stand/boot/../libsa -I. -I/usr/src/sys/arch/i386/stand/boot -DSOFTRAID -D BOOTMAGIC=0xc001d00d -DLINKADDR=0x40120 -DSLOW -DSMALL -DNOBYFOUR -DNO_GZIP -DD YNAMIC_CRC_TABLE -DBUILDFIXED -DHIBERNATE -DHEAP_LIMIT=0xA0000 -I/usr/src/sys/ar ch/i386/stand/boot/../../../../stand/boot < /usr/src/sys/arch/i386/stand/boot /../etc/genassym.cf > assym.h.tmp && mv -f assym.h.tmp assym.h cc -no-integrated-as -m32 -fno-pie -I/usr/src/sys/arch/i386/stand/boot/../../ ../.. -I/usr/src/sys/arch/i386/stand/boot/../libsa -I. -I/usr/src/sys/arch/i386/ stand/boot -DSOFTRAID -DBOOTMAGIC=0xc001d00d -DLINKADDR=0x40120 -DSLOW -DSMALL -DNOBYFOUR -DNO_GZIP -DDYNAMIC_CRC_TABLE -DBUILDFIXED -DHIBERNATE -DHEAP_LIMIT=0 xA0000 -I/usr/src/sys/arch/i386/stand/boot/../../../../stand/boot -c -MD -MF sr t0.d -o srt0.o srt0.S : ld -nostdlib -Bstatic -nopie -znorelro -Ttext 0x40120 -N -x -o boot.new srt0.o conf.o boot.o bootarg.o cmd.o vars.o debug_i386.o gidt.o pslid.o mdrandom.o apmp robe.o debug.o pciprobe.o ps2probe.o cmd_i386.o dev_i386.o exec_i386.o gateA20.o machdep.o bioscons.o biosdev.o diskprobe.o memprobe.o time.o softraid_i386.o al loc.o ctime.o exit.o getchar.o hexdump.o memcmp.o memcpy.o memmove.o memset.o pr intf.o putchar.o snprintf.o strcmp.o strerror.o strlen.o strncmp.o strncpy.o str tol.o strtoll.o close.o closeall.o cons.o cread.o dev.o disklabel.o dkcksum.o fc hmod.o fstat.o lseek.o open.o read.o readdir.o stat.o elf32.o elf64.o loadfile.o arc4.o ufs.o ufs2.o aes_xts.o bcrypt_pbkdf.o blowfish.o explicit_bzero.o hmac_s ha1.o pkcs5_pbkdf2.o rijndael.o sha1.o sha2.o softraid.o ashldi3.o ashrdi3.o div di3.o lshrdi3.o moddi3.o qdivrem.o strlcpy.o adler32.o crc32.o inflate.o inftree s.o text data bss dec hex 87357 308 9456 97121 17b61 ===> cdboot sh /usr/src/sys/arch/i386/stand/cdboot/../../../../kern/genassym.sh cc -no-integ rated-as -Oz -Wall -Werror -ffreestanding -fno-stack-protector -DMDRANDOM -MD -MP -D_STANDALONE -nostdinc -fno-builtin -fpack-struct -D__INTERNAL_LIBSA_CREAD -DOSREV=\"7.1\" -DMACHINE=\"i386\" -DKERNEL=\"/7.1/i386/bsd.rd\" -fno-pie -I/u sr/src/sys/arch/i386/stand/cdboot/../../../.. -I/usr/src/sys/arch/i386/stand/cdb oot/../libsa -I. -I/usr/src/sys/arch/i386/stand/cdboot -DSOFTRAID -DBOOTMAGIC=0x c001d00d -DLINKADDR=0x40120 -DSLOW -DSMALL -DNOBYFOUR -DNO_GZIP -DDYNAMIC_CRC_T ABLE -DBUILDFIXED -I/usr/src/sys/arch/i386/stand/cdboot/../../../../stand/boot < /usr/src/sys/arch/i386/stand/cdboot/../etc/genassym.cf > assym.h.tmp && mv - f assym.h.tmp assym.h :
のんびり進むので、途中で中断した。bootって、結構大掛かりなアプリなんだね。それからcdbootって、bsd.rdっていうミニカーネルのお世話になってるのかな。後なじっくりオプションを見ていくと参考になるだろう。
たとえばオプチマイザーの -Oz なんて初めて御目にかかった。 かつかつの所に押し込める為に苦労してるのね。perlまで動員して、サイズチェックしてるよ。 これじゃgdbで調べようにも、手が出ないな。
qm# ls -l mbr total 52 -rw-r--r-- 1 root wsrc 665 Oct 18 2017 Makefile -rw-r--r-- 1 root wsrc 459 Oct 20 05:32 assym.h lrwxr-xr-x 1 root wsrc 62 Oct 20 05:31 machine@ -> /usr/src/sys/arch/i386/stand/mbr/../../../../arch/i386/include :
assym.hに大事なdefineが有る。includeファイルもマシンに合わせて用意してるのが特徴か。
boot
bootのソースを見ていたら、多分いけるんじゃないかってのを見付たので試してみる。
machine diskinfo
それは、ddbの machine diskinfo で表示されるDISK名前を無視してもよかろうって穴だ。
[sakae@fb ~/QEMU]$ ./boot -S -E & [1] 1228 [sakae@fb ~/QEMU]$ char device redirected to /dev/pts/3 (label serial0) VNC server running on ::1:5900 [sakae@fb ~/QEMU]$ cu -l /dev/pts/3 Connected >> OpenBSD/i386 BOOT 3.44 boot> help commands: # boot echo env help hexdump ls machine reboot set stty time machine: boot comaddr diskinfo memory boot> machine diskinfo Disk BIOS# Type Cyls Heads Secs Flags Checksum fd0 0x0 *none* 80 2 36 0x4 0x0 hd0 0x80 label 779 128 63 0x2 0xc26c94d7 hd1 0x81 label 811 64 63 0x0 0x0
FreeBSDのqemuでは、bootメニューに入るチャンスが無いので、cu -l して接続しておいてから、emacs側で cont すれば良い。で、こんな風になった。
boot> boot wd0:/bsd.org cannot open wd0:/etc/random.seed: No such file or directory booting wd0:/bsd.org: open wd0:/bsd.org: No such file or directory failed(2). will try /bsd boot> boot wd0a:/bsd.org booting wd0a:/bsd.org: 10349079+2479108+241672+0+1130496 [709328+107+585136+629189]=0xf62cf0 : OpenBSD 7.1 (GENERIC) #151: Mon Apr 11 18:57:52 MDT 2022
hd0aを指定しなくても、wd0aの指定でいけた。sd0aとかも候補になるんで、総称してhd0とかって表現してるって事かな。
で、カーネルをオリジナルな奴に切り換え。そうしておいてbsd,gdbをgeneric以外なものにしてして、gdbを起動。この状態でBPはおけるが、ヒットはしない。アドレスが全く違う所にBPがセットされるんで、ヒットしないんだな。当たりまえの事を確認してみたのさ。
(gdb) b sys_gettimeofday Breakpoint 1 at 0xd03b38b0: file /usr/src/sys/kern/kern_time.c, line 331.
ちょっと確認って事で、現有のものと、違う条件で作ったやつとの比較。
[sakae@fb /sys/arch/i386/compile/SEE]$ nm bsd | grep sys_gettimeofday d03b38b0 T sys_gettimeofday [sakae@fb /sys/arch/i386/compile/SEE]$ nm 02P/bsd | grep sys_gettimeofday d07db9a0 T sys_gettimeofday
関数名前をキーに、値はアドレスって言うDBがカーネルには内蔵されてるんだね。
boot crash
bootにBPを置いて起動したら、ddbに落ちたので、boot crashしてみた。なお、再現性は無い。 たまたまなのか。それから、ddbで、boot sync とか boot dump すると、何故か刺さる(永久ロープに陥る)。
Automatic boot in progress: starting file system checks. /dev/wd0a (f1bc5dab4c1884ce.a): INCORRECT BLOCK COUNT I=155524 (4 should be 0) ) fd0 at fdc0 drive 1: density unknown /dev/wd0a (f1bc5dab4c1884ce.a): UNREF FILE I=155524 OWNER=root MODE=100600 /dev/wd0a: SIZE=0 MTIME=Oct 23 08:37 2022 (CLEARED) /dev/wd0a (f1bc5dab4c1884ce.a): FREE BLK COUNT(S) WRONG IN SUPERBLK (SALVAGED) /dev/wd0a (f1bc5dab4c1884ce.a): SUMMARY INFORMATION BAD (SALVAGED) /dev/wd0a (f1bc5dab4c1884ce.a): BLK(S) MISSING IN BIT MAPS (SALVAGED) /dev/wd0a (f1bc5dab4c1884ce.a): 17891 files, 407480 used, 929855 free (367 frag) /dev/wd0a (f1bc5dab4c1884ce.a): MARKING FILE SYSTEM CLEAN : savecore: reboot after panic: uvm_fault(0xd1770460, 0x0, 0, 1) -> e savecore: system went down at Sun Oct 23 08:37:45 2022 savecore: /var/crash/bounds: No such file or directory savecore: writing core to /var/crash/bsd.0.core savecore: writing kernel to /var/crash/bsd.0
こんなに綺麗なfsckの魚拓が取れたので、これを肴に一献傾むけよう。日本酒が美味しい秋ですからら。
fsck
/etc/rcから呼び出されるfsckの挙動を追ってみるかな。綺麗なログが出てますからねぇ。 まずは軽くmanします。そしたら、DISK毎に、プロセスを走らせて並列チェックしてますなんて説明。
そして、
SEE ALSO fs(5), fstab(5), fsck_ext2fs(8), fsck_ffs(8), fsck_msdos(8), fsdb(8), growfs(8), mount(8), newfs(8), rc(8), scan_ffs(8)
ファイルシステムの性格によって、下請けを呼び出しているっぽい。そんな観点でsrc/sbin/fsck/fsck.cを観察すると、
static int checkfs(const char *vfstype, const char *spec, const char *mntpt, void *auxarg, pid_t *pidp) { switch (pid = fork()) { case 0: /* Child. */ if (flags & CHECK_DEBUG) _exit(0); /* Go find an executable. */ edir = edirs; do { (void)snprintf(execname, sizeof(execname), "%s/fsck_%s", *edir, vfstype); execv(execname, (char * const *)argv);
どうやらNTFSは怖いんで手を出さないようにしてるっぽい。で、今回は、 fsck_ffs
が主舞台になりそう。
解説書もそれに併せて読んでおく。
fsck by hand
自動でやらせるのはもったいないので手動でも。ちょっと舞台設定って事で、newfsした2ndDISKを用意。それに併せて、fstabも用意。但し、目的DISKはコメントアウトしとく。
qm# cat /etc/fstab f1bc5dab4c1884ce.b none swap sw f1bc5dab4c1884ce.a / ffs rw,wxallowed 1 1 # /dev/wd1c /mnt ffs rw,wxallowed 0 0
その状態でfsckすると、どんな代物か解らないって言ってきた。AIっぽく、自動判定なんて器用な真似はしないのさ。
qm# fsck /dev/wd1c fsck: /dev/wd1c: unknown special file or file system.
じゃ、次にコメントを外してからfsck。マウントはしていない。
qm# fsck /dev/wd1c ** /dev/rwd1c ** File system is clean; not checking
次は、マウントしてから実行。
qm# mount -a qm# fsck /dev/wd1c ** /dev/rwd1c (NO WRITE) ** Last Mounted on /mnt ** Phase 1 - Check Blocks and Sizes ** Phase 2 - Check Pathnames ** Phase 3 - Check Connectivity ** Phase 4 - Check Reference Counts ** Phase 5 - Check Cyl groups 1 files, 1 used, 793110 free (14 frags, 99137 blocks, 0.0% fragmentation)
mountの可否で、挙動が違うね。
それから、プチ面白いコマンドを発見。
qm# touch /mnt/hogefuga qm# echo hello > /mnt/hello qm# ncheck /dev/wd1c /dev/rwd1c: 3 /hogefuga 4 /hello qm# df Filesystem 512-blocks Used Avail Capacity Mounted on /dev/wd0a 5349340 1795968 3285908 35% / /dev/wd1c 3172444 8 3013816 0% /mnt
ncheckってのを使うと、inodeとファイル名前の対応が得られるのか。これを発展させると、fsdbとかになるんだな。
qm# fsdb -d -f wd1c ** /dev/wd1c (wd1c) (NO WRITE) clean = 0 Editing file system `wd1c' Last Mounted on /mnt current inode: directory I=2 MODE=40755 SIZE=512 MTIME=Oct 23 15:11:03 2022 [758500778 nsec] CTIME=Oct 23 15:11:03 2022 [758500778 nsec] ATIME=Oct 23 15:18:34 2022 [475688605 nsec] OWNER=root GRP=wheel LINKCNT=2 FLAGS=0 BLKCNT=4 GEN=e8be5db5 No entry for terminal type "vt220"; using dumb terminal settings. fsdb (inum: 2)> ls command `' slot 0 ino 2 reclen 12: directory, `.' slot 1 ino 2 reclen 12: directory, `..' slot 2 ino 3 reclen 20: regular, `hogefuga' slot 3 ino 4 reclen 468: regular, `hello'
fsck-ffs
mainを見ていくと、主は、checkfilesysって関数で実行されてる。指定したファイルシステムがどんな状況だったかに続いて、Phase1-6 の詳細がチェックされる。そして最後にサマリーが報告されるって流れだ。
super blockってのが頻出してるけど、それって、/sys/ufs/ffs/fs.h に定義されてるやつかな。普通の人は、/usr/include/ufs/ffs/fs.h を見るんだな。
まずはスーパー・ブロックの攻略だな。それにはファイルシステムを作るコマンドを実行してみる事だな。
newfs
と言う事で、3番目のDISKを作った。そしてそれを -hdc test.img で組込もうとしたけど、そんな事はqemuが許してくれなかった。qemuがどうやらハングしてしまうんだ。
ならば別の手段を考える。思い出したのは、vnconfigで、普通のファイルをDISKと見做してしまうスペシャルな奴。
qm# dd if=/dev/zero of=test.img bs=1M count=500 500+0 records in 500+0 records out 524288000 bytes transferred in 50.847 secs (10310981 bytes/sec) qm# vnconfig vnd0 /tmp/test.img qm# disklabel -E vnd0 Label editor (enter '?' for help at any prompt) vnd0> p OpenBSD area: 0-1024000; size: 1024000; free: 1024000 # size offset fstype [fsize bsize cpg] c: 1024000 0 unused vnd0> a a offset: [0] size: [1024000] FS type: [4.2BSD] vnd0*> w vnd0> q
ZEROクリアした普通のファイルをddを使って作成。それをvnconfigでDISKに見立てる。後は、disklabelでOpenBSD用にする。これで、vnd0ってDISKを捏ち上げられた。
次は目当てのnewfsを実行。
qm# newfs /dev/vnd0a newfs: /dev/vnd0a: block device qm# qm# newfs /dev/rvnd0a /dev/rvnd0a: 500.0MB in 1024000 sectors of 512 bytes 4 cylinder groups of 125.00MB, 8000 blocks, 16000 inodes each super-block backups (for fsck -b #) at: 160, 256160, 512160, 768160,
が、普通にやるとエラーだ。newfs.cのこんな所で引掛っている。でも、キャラクターデバイスなら、まあまあOKよってヒントを貰ったので、その通りに裸のデバイスを指定。何だか動いているっぽい。
if (!mfs) { if (S_ISBLK(st.st_mode)) fatal("%s: block device", special); if (!S_ISCHR(st.st_mode)) warnx("%s: not a character-special device", special);
ああ、事前に、/etc/fstabに設定しといたよ。勿論、事前に/tst って言うマウントポイントを用意しておく事。
/dev/vnd0a /tst ffs rw,wxallowed 0 0
マウントしてみるぞ。
qm# df Filesystem 512-blocks Used Avail Capacity Mounted on /dev/wd0a 5349340 3735056 1346820 73% / /dev/wd1a 3172444 1921368 1092456 64% /mnt /dev/vnd0a 991580 4 942000 0% /tst
qm# hexdump -C test.img 00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00000200 57 45 56 82 0c 00 00 00 76 6e 64 20 64 65 76 69 |WEV.....vnd devi| 00000210 63 65 00 00 00 00 00 00 66 69 63 74 69 74 69 6f |ce......fictitio| 00000220 75 73 00 00 00 00 00 00 00 02 00 00 64 00 00 00 |us..........d...| 00000230 01 00 00 00 00 28 00 00 64 00 00 00 00 a0 0f 00 |.....(..d.......| 00000240 ba 4f 61 0d 92 52 12 b4 00 00 00 00 00 00 00 00 |.Oa..R..........| 00000250 00 00 00 00 00 a0 0f 00 00 00 00 00 00 00 00 00 |................| 00000260 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000270 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000280 00 00 00 00 57 45 56 82 12 f7 10 00 00 20 00 00 |....WEV...... ..| 00000290 00 00 01 00 00 a0 0f 00 00 00 00 00 00 00 00 00 |................| 000002a0 07 14 40 1f 00 00 00 00 00 00 00 00 00 00 00 00 |..@.............| 000002b0 00 00 00 00 00 a0 0f 00 00 00 00 00 00 00 00 00 |................| 000002c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00010000 00 00 00 00 00 00 00 00 28 00 00 00 30 00 00 00 |........(...0...| 00010010 38 00 00 00 08 08 00 00 00 00 00 00 00 00 00 00 |8...............| 00010020 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 |................| 00010030 00 40 00 00 00 08 00 00 08 00 00 00 05 00 00 00 |.@..............| 00010040 00 00 00 00 00 00 00 00 00 c0 ff ff 00 f8 ff ff |................| :
次はnewfsの挙動観察だな。その前に、お隣様の事情を観察。
fsck for debian
なんとminixのファイルシステムの修復出来るのか、Linuxの出身の元だから、リナの世界では、世界遺産に問答無用で登録されてるんだな。そして、それに対して誰も異をとなえない。リナス神には逆らうなですかね。
SEE ALSO fstab(5), mkfs(8), fsck.ext2(8) or fsck.ext3(8) or e2fsck(8), fsck.cramfs(8), fsck.jfs(8), fsck.nfs(8), fsck.minix(8), fsck.msdos(8), fsck.vfat(8), fsck.xfs(8), reiserfsck(8)
それから、山のようにファイルシステムが登録されてる。みんな足掻いているのね。
長くなってきたので次回に持ち越し。