9:21 2006/01/26 file ldd コマンド --------------------------------------- 15.デバッグコードの含まれたファイルのシュリンク RedHatのディストリビューションファイルの中にはデバッグコードの含まれているBinaryファイルが多く存在します 。 デバッグコードが含まれるとサイズが大きくなり無駄な部分が多いということです。 そこでファイルをダイエットしてしまいましょう! 調べ方:fileコマンドを使います  $file libpcre.so.0.0.1  libpcre.so.0.0.1: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), not stripped このように「not stripped」と表示されたものはデバッグコードが含まれています。 早速ダイエットしましょう。 ファイルの場合:  $objcopy --strip-all ファイル名 ライブラリーの場合:  $objcopy -S ライブラリー名 ライブラリー名 中には動かなくなるファイルもあるみたいだワン! http://www.pochinet.org/linux0A015.htm ------------------------------------------------------------- 16.スタティック/ダイナミック・リンク コマンドがどのライブラリーと紐つけられているかを調べる方法 lddコマンドを使います  $ldd /usr/bin/make  libc.so.6 => /lib/libc.so.6 (0x4001a000)  /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) このようにライブラリー名が出るものはダイナミック・リンクされたコマンドです。  fileコマンドではどちらかということまで表示されます。  $file /usr/bin/make make: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), not stripped  $ldd /usr/bin/make  not a dynamic executable このように表示されるものはスタティックなコマンドです。  fileコマンドでは  $file /usr/bin/make make: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped コマンドのサイズも10倍くらい違うのである程度予測がつきます。 ダイナミック・リンク make・・・144887バイト スタティック・リンク make・・・1097156バイト http://www.pochinet.org/linux0A016.htm -------------------------------------------------------------------------------- /lib /lib には必要な共有ライブラリとローダを置きます.必要な共有ライブラリが /lib になければシステムを ブートすることができません.運が良ければエラーメッセージで何が足りないかがわかるでしょうが. ほとんど全てのプログラムは,少なくとも libc ライブラリである libc.so.N を必要とします.ここで, N は現在のバージョン番号です.読者のみなさんの /lib をチェックしてみてください. libc.so.N は通常,完全なバージョン番号を持つファイルへのシンボリックリンクです: % ls -l /lib/libc* -rwxr-xr-x 1 root root 4016683 Apr 16 18:48 libc-2.1.1.so* lrwxrwxrwx 1 root root 13 Apr 10 12:25 libc.so.6 -> libc-2.1.1.so* この場合には libc-2.1.1.so が必要となります.コピーすべき他のライブラリを見つけるには, 入れようとするバイナリを全て調べ, ldd コマンドを使って依存関係をチェックします.例を示します: % ldd /sbin/mke2fs libext2fs.so.2 => /lib/libext2fs.so.2 (0x40014000) libcom_err.so.2 => /lib/libcom_err.so.2 (0x40026000) libuuid.so.1 => /lib/libuuid.so.1 (0x40028000) libc.so.6 => /lib/libc.so.6 (0x4002c000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) 右側にあるファイルが必要なものです.ファイルはシンボリックリンクであることもあります. 一部のライブラリは非常に大きく,容易にはルートファイルシステムに入れられないこともあります. 例えば,先に挙げた libc.so のサイズは約 4 メガバイトです.このファイルをルートファイルシステムに コピーする際には,ライブラリを strip する必要があるかもしれません.この手順については, ファイルシステムのサイズの削減 の節を参照してください. /lib にはライブラリをロードするためのローダも入れる必要があります.ローダのファイルの名前は ld.so (a.out ライブラリ用) または ld-linux.so (ELF ライブラリ用) です. 新しいバージョンの ldd を使えば,(先に示した例のように)どのローダが必要なのかが正確に分かりますが, 古いバージョンの ldd ではこれが分からないことがあります.どちらが必要なのかが確かでなければ, ライブラリに対して file コマンドを実行してください.実行例を示します: % file/lib/libc.so.4.7.2 /lib/libc.so.5.4.33 /lib/libc-2.1.1.so /lib/libc.so.4.7.2: Linux/i386 demand-paged executable (QMAGIC), stripped /lib/libc.so.5.4.33: ELF 32-bit LSB shared object, Intel 80386, version 1, stripped /lib/libc-2.1.1.so: ELF 32-bit LSB shared object, Intel 80386, version 1, not stripped QMAGIC は 4.7.2 は a.out 用ライブラリであることを示し, ELF は 5.4.33 と 2.1.1 が ELF 用ライブラリ であることを示します. 作ろうとしているルートファイルシステムに必要なローダをコピーしてください.両方とも必要な場合も あるかもしれません.入れるバイナリに対して,ライブラリとローダは慎重にチェックしなければなりません. カーネルが必要なライブラリをロードできない場合,普通カーネルはエラーメッセージも出さずに止まって しまうでしょう. http://www.linux.or.jp/JF/JFdocs/Bootdisk-HOWTO-4.html -------------------------------------------------------------------------------- 簡単なプログラム "hello, world" がどのように起動され、どのように処理されて動くのかを 無意味に詳しく解説してみよう。 #include int main(int argc, char *argv[]) { printf("hello, world\n"); exit(0); } この hello.c をコンパイルすると次のようなhelloというバイナリができる % cc -g -o hello hello.c この hello というバイナリは % file hello hello: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.0, dynamically linked (uses shared libs), not stripped のように ELFというフォーマットのバイナリである。 dynamically linked なので ldd をつかうと % ldd hello libc.so.6 => /lib/libc.so.6 (0x4001c000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) のようにどの shared libs を使っているのかを見ることができる。 より詳しくは objdump をつかうとELFバイナリの中身をみることができる。たとえば -x (--all-headers) で このバイナリの実行コードではない情報、つまりどのアーキテクチャむけのバイナリか、どのshared libsを 必要としているか、どういったsymbolがなかで使われているか/使おうとしているかなどといった情報を見る ことができる。 % objdump -x hello hello: ファイル形式 elf32-i386 hello アーキテクチャ: i386, フラグ 0x00000112: EXEC_P, HAS_SYMS, D_PAGED 開始アドレス 0x08048340 プログラムヘッダ: PHDR off 0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2 filesz 0x000000c0 memsz 0x000000c0 flags r-x INTERP off 0x000000f4 vaddr 0x080480f4 paddr 0x080480f4 align 2**0 filesz 0x00000013 memsz 0x00000013 flags r-- LOAD off 0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12 filesz 0x000004b2 memsz 0x000004b2 flags r-x LOAD off 0x000004b4 vaddr 0x080494b4 paddr 0x080494b4 align 2**12 filesz 0x00000110 memsz 0x00000128 flags rw- DYNAMIC off 0x000004c8 vaddr 0x080494c8 paddr 0x080494c8 align 2**2 filesz 0x000000c8 memsz 0x000000c8 flags rw- NOTE off 0x00000108 vaddr 0x08048108 paddr 0x08048108 align 2**2 filesz 0x00000020 memsz 0x00000020 flags r-- (以下略) また -d (--disassemble) で逆アセンブルが、バイナリが-gオプションでビルドされていれば-S(--source) で ソースコードとの対応も見ることができる。 % objdump -d hello hello: ファイル形式 elf32-i386 セクション .init の逆アセンブル: 80482bc: 55 push %ebp 80482bd: 89 e5 mov %esp,%ebp 80482bf: 83 ec 08 sub $0x8,%esp 80482c2: e8 9d 00 00 00 call 8048364 80482c7: 90 nop 80482c8: e8 1b 01 00 00 call 80483e8 80482cd: e8 7e 01 00 00 call 8048450 <__do_global_ctors_aux> 80482d2: c9 leave 80482d3: c3 ret セクション .plt の逆アセンブル: (以下略) % objdump -S hello hello: ファイル形式 elf32-i386 セクション .init の逆アセンブル: 080482bc <_init>: (略) 08048420
: #include int main(int argc, char *argv[]) { 8048420: 55 push %ebp 8048421: 89 e5 mov %esp,%ebp 8048423: 83 ec 08 sub $0x8,%esp printf("hello, world\n"); 8048426: 83 c4 f4 add $0xfffffff4,%esp 8048429: 68 a4 84 04 08 push $0x80484a4 804842e: e8 e1 fe ff ff call 8048314 <_init+0x58> 8048433: 83 c4 10 add $0x10,%esp exit(0); 8048436: 83 c4 f4 add $0xfffffff4,%esp 8048439: 6a 00 push $0x0 804843b: e8 e4 fe ff ff call 8048324 <_init+0x68> 8048440: 83 c4 10 add $0x10,%esp } 8048443: c9 leave 8048444: c3 ret (以下略) さて、これをshell(例えばbash)から起動する場合をおいかけてみよう。bashにhelloプログラムの実行を指示すると、 fork(2)してstdin,stdout,stderrなどのリダイレクトの処理などをしてから、exec(2)でfork(2)されたbashから プログラム(この場合はhello)におきかわって実行が開始される。これを順をおってみていってみよう。 まず、bashのexecute_cmd.cのshell_execve()の中でexecve(2)が呼ばれる。 このexecve(2)はglibcのsysdeps/unix/sysv/linux/execve.cであり、そこでの return INLINE_SYSCALL (execve, 3, file, argv, envp); によりexecveというsystem callのよびだしが行なわれる。 これはglibcのsysdeps/unix/sysv/linux/i386/sysdep.h で #defineされており以下のようなかんじのasmを 実行することになる。 movl ,%edi movl ,%ecx movl ,%edx movl $11, %eax # execve int $0x80 このように %eaxにsystemcall番号、%edx、%ecx,%ediあたりに引数がセットされて、int $0x80が実行される。 int命令はソフトウェア割り込みで、この時点でkernel modeに移行する。kernelのブート時の初期化段階に arch/i386//kernel/traps.cのtrap_init()で set_system_gate(SYSCALL_VECTOR,&system_call); # SYSCALL_VECTOR = 0x80 と設定されているので、int $0x80が呼ばれるとsystem_callへやってくる。このsystem_callというのは arch/i386/kernel/entry.Sにある ENTRY(system_call)である。ここでは基本的にレジスタをスタックに つんで%eaxの内容に従ってsys_call_tableに設定されているアドレスをcallすることになる。 call *SYMBOL_NAME(sys_call_table)(,%eax,4) sys_call_tableもおなじくentry.Sにあり11番目がsys_execve である ENTRY(sys_call_table) 略 .long SYMBOL_NAME(sys_unlink) /* 10 */ .long SYMBOL_NAME(sys_execve) .long SYMBOL_NAME(sys_chdir) 略 sys_execveは arch/i386/kernel/process.cの asmlinkage int sys_execve(struct pt_regs regs)である。 asmlinkage int sys_execve(struct pt_regs regs) { int error; char * filename; filename = getname((char *) regs.ebx); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, ®s); if (error == 0) current->ptrace &= ~PT_DTRACE; putname(filename); out: return error; } このように%ebxに設定されているファイル名をチェックしたあと、do_execve()を読んでいる。system callを 読んだ時に%ecxにはargvを%edxにはenvpを設定してあるのでここは do_execve(filename, argv, envp, ...) のようによびだしていることになる。ここまでがarch依存なコードでありあとは非依存なコードに移行する。 do_execve()はfs/exec.cにある。 do_execve()ではまずfilenameで指定されたファイルをファイルシステムからopen_exec()をつかって読みこん でいる。ここでパーミッションのチェックなども行なっている。openに成功すればstruct linux_binprmの情報を 設定していく。struct linux_binprmにはargvやenvp,uid,gidなどの情報が保持されている。 そしてexecしようとしているファイルの最初のBINPRM_BUF_SIZE (128byte)を読みこむ。 search_binary_handler()でfile headerのmagic numberなどをチェックし、そのbinary formatをあつかう handlerをstruct linux_binfmt *formatsのなかから探しだしている。ELFに関してはfs/binfmt_elf.cの elf_formatの中のload_elf_binary()でELFヘッダのチェックがおこなわれている。 ここでmagic numberなど必要な情報のチェックにクリアすればELF headerをkernel_read()をつかって 読みこみをする。 ここで elf_ppnt->p_type == PT_INTERP で.interp sectionをみつけるとこの内容を読みとる。この内容は % objdump -s -j .interp hello hello: ファイル形式 elf32-i386 セクション .interp の内容: 80480f4 2f6c6962 2f6c642d 6c696e75 782e736f /lib/ld-linux.so 8048104 2e3200 .2. である。つまり elf_interpreter = "/lib/ld-linux.so.2" というのが読みこまれる。 ここで再び elf_interpreter を open_exec()して BINPRM_BUF_SIZE分だけよみこんでいる。 symbolic linkをたどって、これは/lib/ld-2.3.1.soという shared objectを実行することになる。 % file /lib/ld-linux.so.2 /lib/ld-linux.so.2: symbolic link to ld-2.3.1.so % file /lib/ld-2.3.1.so /lib/ld-2.3.1.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), not stripped flush_old_exec()で現在のprogramの情報を消し、新しいprogramのための情報にcurrentの情報をいれかえていく。 memory mapが初期化されプログラムヘッダでLOADのところがmapされる。fileszよりmemszがおおきい場合は その分のmemoryがこのあたりで 0 に fillされるように設定される。 最後に elf_interpreter "/lib/ld-2.3.1.so" がload_elf_interp()によってmemory上にmapされる。 % objdump -x /lib/ld-2.3.1.so /lib/ld-2.3.1.so: ファイル形式 elf32-i386 /lib/ld-2.3.1.so アーキテクチャ: i386, フラグ 0x00000150: HAS_SYMS, DYNAMIC, D_PAGED 開始アドレス 0x00000b50 プログラムヘッダ: LOAD off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**12 filesz 0x00010e00 memsz 0x00010e00 flags r-x LOAD off 0x00011000 vaddr 0x00011000 paddr 0x00011000 align 2**12 filesz 0x00000554 memsz 0x00000700 flags rw- DYNAMIC off 0x000113f8 vaddr 0x000113f8 paddr 0x000113f8 align 2**2 filesz 0x000000b0 memsz 0x000000b0 flags rw- (略) その後、currentの情報をさらに設定していって start_thread(regs, elf_entry, bprm->p); で elf_entry から実行を開始する。elf_entryは /lib/ld-2.3.1.so の entry(開始アドレス)からとなる。 start_threadは include/asm-i386/processor.h で次のように #define されている。 #define start_thread(regs, new_eip, new_esp) do { \ __asm__("movl %0,%%fs ; movl %0,%%gs": :"r" (0)); \ set_fs(USER_DS); \ regs->xds = __USER_DS; \ regs->xes = __USER_DS; \ regs->xss = __USER_DS; \ regs->xcs = __USER_CS; \ regs->eip = new_eip; \ regs->esp = new_esp; \ } while (0) つまり elf_entry を次の %eip として設定している。これで search_binary_handler()からreturnして do_execve()がおわり、sys_execve()からreturnする。 で、arch/i386/kernel/entry.S の call *SYMBOL_NAME(sys_call_table)(,%eax,4) から戻ってきて以下が実行される。 movl %eax,EAX(%esp) # save the return value ENTRY(ret_from_sys_call) cli # need_resched and signals atomic test cmpl $0,need_resched(%ebx) jne reschedule cmpl $0,sigpending(%ebx) jne signal_return restore_all: RESTORE_ALL rescheduleがよびだされて、kernel/sched.cのasmlinkage void schedule(void)のなかから include/asm-i386/system.hのswitch_to()からarch/i386/kernel/process.cの__switch_to()にきて %esp, %fs, %gs がいれかえられる。 そうしてexecされたプロセスに制御がまわってくると、このprocessの%eip、つまりelf_interpreterの entry addressから実行を開始することになる。 % objdump -f /lib/ld-2.3.1.so /lib/ld-2.3.1.so: ファイル形式 elf32-i386 アーキテクチャ: i386, フラグ 0x00000150: HAS_SYMS, DYNAMIC, D_PAGED 開始アドレス 0x00000b50 % objdump -d /lib/ld-2.3.1.so (略) 00000b50 <_start>: b50: 89 e0 mov %esp,%eax b52: e8 03 01 00 00 call c5a <_dl_start> ということで /lib/ld-2.3.1.so の _start から実行を開始する。これはglibcのsysdeps/i386/dl-machine.hの #define RTLD_STARTのコードである。 まず_dl_start()がよばれる。この_dl_start()はglibcのelf/rtld.cの_dl_start()である。 まずbootstrap_map.l_infoを0で初期化している。次にsysdeps/i386/dl_machine.hに定義されて いるelf_machine_load_address()をつかってdynamic linker自体がどのアドレスにあるかを調べている。 でsysdeps/generic/dl-sysdep.cの_dl_sysdep_start()からelf/rtld.cのdl_main()がよばれてくる。 まずここでprocess_envvars()がよばれ、環境変数のチェックがおこなわれている。このコードをみると 以下の環境変数が /lib/ld-2.3.1.soでつかわれていることがわかる。 LD_WARN - Warning level, verbose or not LD_DEBUG - Debugging of the dynamic linker? LD_VERBOSE - Print information about versions. LD_PRELOAD - List of objects to be preloaded. LD_PROFILE - Which shared object shall be profiled. LD_BIND_NOW - Do we bind early? LD_BIND_NOT - ? LD_SHOW_AUXV - Test whether we want to see the content of the auxiliary array passed up from the kernel. LD_HWCAP_MASK - Mask for the important hardware capabilities. LD_ORIGIN_PATH - Path where the binary is found. LD_LIBRARY_PATH - The library search path. LD_DEBUG_OUTPUT - Where to place the profiling data file. LD_DYNAMIC_WEAK - ? LD_PROFILE_OUTPUT - Where to place the profiling data file. LD_TRACE_PRELINKING - The mode of the dynamic linker can be set. LD_TRACE_LOADED_OBJECTS - The mode of the dynamic linker can be set. LD_PRELOADやLD_LIBRARY_PATHはよく使われるが、他はあまりつかったことがないことだろう。 とりあえずいくつかを簡単に紹介しよう。 % LD_DEBUG=help /lib/ld-2.3.1.so Valid options for the LD_DEBUG environment variable are: libs display library search paths reloc display relocation processing files display progress for input file symbols display symbol table processing bindings display information about symbol binding versions display version dependencies all all previous options combined statistics display relocation statistics help display this help message and exit To direct the debugging output into a file instead of standard output a filename can be specified using the LD_DEBUG_OUTPUT environment variable. たとえば 以下のような結果を得ることができる。 % LD_DEBUG=libs ./hello 04836: find library=libc.so.6; searching 04836: search cache=/etc/ld.so.cache 04836: trying file=/lib/libc.so.6 04836: 04836: 04836: calling init: /lib/libc.so.6 04836: 04836: 04836: initialize program: ./hello 04836: 04836: 04836: transferring control: ./hello 04836: hello, world 04836: 04836: calling fini: /lib/libc.so.6 04836: % LD_DEBUG=reloc ./hello 04837: 04837: relocation processing: /lib/libc.so.6 (lazy) 04837: 04837: relocation processing: ./hello (lazy) 04837: 04837: relocation processing: /lib/ld-linux.so.2 04837: 04837: calling init: /lib/libc.so.6 04837: 04837: 04837: initialize program: ./hello 04837: 04837: 04837: transferring control: ./hello 04837: hello, world 04837: 04837: calling fini: /lib/libc.so.6 04837: % LD_DEBUG=files ./hello 04839: 04839: file=libc.so.6; needed by ./hello 04839: file=libc.so.6; generating link map 04839: dynamic: 0x40129618 base: 0x4001c000 size: 0x00112184 04839: entry: 0x40031a40 phdr: 0x4001c034 phnum: 7 04839: 04839: 04839: calling init: /lib/libc.so.6 04839: 04839: 04839: initialize program: ./hello 04839: 04839: 04839: transferring control: ./hello 04839: hello, world 04839: 04839: calling fini: /lib/libc.so.6 04839: % LD_DEBUG=symbols ./hello 04845: symbol=_IO_file_close; lookup in file=./hello 04845: symbol=_IO_file_close; lookup in file=/lib/libc.so.6 04845: symbol=_IO_2_1_stdin_; lookup in file=./hello 04845: symbol=_IO_2_1_stdin_; lookup in file=/lib/libc.so.6 04845: symbol=_IO_2_1_stdout_; lookup in file=./hello 04845: symbol=_IO_2_1_stdout_; lookup in file=/lib/libc.so.6 04845: symbol=_IO_2_1_stderr_; lookup in file=./hello 04845: symbol=_IO_2_1_stderr_; lookup in file=/lib/libc.so.6 (略) % LD_DEBUG=bindings ./hello 4849: binding file /lib/libc.so.6 to /lib/libc.so.6: normal symbol `_IO_file_close' [GLIBC_2.0] 04849: binding file /lib/libc.so.6 to /lib/libc.so.6: normal symbol `_IO_2_1_stdin_' [GLIBC_2.1] 04849: binding file /lib/libc.so.6 to /lib/libc.so.6: normal symbol `_IO_2_1_stdout_' [GLIBC_2.1] 04849: binding file /lib/libc.so.6 to /lib/libc.so.6: normal symbol `_IO_2_1_stderr_' [GLIBC_2.1] (略) % LD_DEBUG=versions ./hello 04852: checking for version `GLIBC_2.0' in file /lib/libc.so.6 required by file ./hello 04852: checking for version `GLIBC_2.1' in file /lib/ld-linux.so.2 required by file /lib/libc.so.6 04852: checking for version `GLIBC_2.0' in file /lib/ld-linux.so.2 required by file /lib/libc.so.6 04852: checking for version `GLIBC_PRIVATE' in file /lib/ld-linux.so.2 required by file /lib/libc.so.6 04852: (略) % LD_DEBUG=statistics ./hello 04854: number of relocations: 119 04854: number of relocations from cache: 5 hello, world 04854: 04854: runtime linker statistics: 04854: final number of relocations: 126 04854: final number of relocations from cache: 5 LD_DEBUG=all とすればすべてが出力される。またLD_DEBUG=helpで書いてある通り、LD_DEBUG_OUTPUTも 指定すればそのファイルに出力される。 LD_SHOW_AUXVを使うとおもしろい情報をみることができる。 % LD_SHOW_AUXV=1 /lib/ld-2.3.1.so ./hello AT_HWCAP: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 mmx fxsr sse AT_PAGESZ: 4096 AT_CLKTCK: 100 AT_PHDR: 0x80000034 AT_PHENT: 32 AT_PHNUM: 3 AT_BASE: 0x0 AT_FLAGS: 0x0 AT_ENTRY: 0x80000b50 AT_UID: 1000 AT_EUID: 1000 AT_GID: 1000 AT_EGID: 1000 AT_PLATFORM: i686 hello, world これは sysdeps/generic/dl-sysdep.cの_dl_show_auxv()で処理している。AT_HWCAPに関しては sysdeps/unix/sysv/linux/i386/dl-procinfo.hの dl_procinfo()で処理している。どの bit が どの文字列になるかは sysdeps/unix/sysv/linux/i386/dl-procinfo.cの_dl_x86_cap_flags[][]である。 前から順に 1, 2, 4, ... に対応している。 LD_TRACE_PRELINKINGでどうリンクされるかを確認できる % LD_TRACE_PRELINKING=1 ./hello ./hello => ./hello (0x08048000, 0x00000000) libc.so.6 => /lib/libc.so.6 (0x4001c000, 0x4001c000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000, 0x40000000) lookup 0x4001c000 0x000053a0 -> 0x4001c000 0x00064dfc /0 _IO_file_close lookup 0x4001c000 0x00005530 -> 0x4001c000 0x0010a1e0 /0 _IO_2_1_stdin_ lookup 0x4001c000 0x00004a50 -> 0x4001c000 0x0010a340 /0 _IO_2_1_stdout_ lookup 0x4001c000 0x0000b7e0 -> 0x4001c000 0x0010a4a0 /0 _IO_2_1_stderr_ LD_TRACE_LOADED_OBJECTSはどのshared libsをloadするかを見ることができる。つまり ldd を同じような 動作をする。 % LD_TRACE_LOADED_OBJECTS=1 ./hello libc.so.6 => /lib/libc.so.6 (0x4001c000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) process_envvars()の処理の後は /lib/ld-2.3.1.soを直接呼びだした時の処理がされている。 % /lib/ld-2.3.1.so Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...] You have invoked `ld.so', the helper program for shared library executables. This program usually lives in the file `/lib/ld.so', and special directives in executable files using ELF shared libraries tell the system's program loader to load the helper program from this file. This helper program loads the shared libraries needed by the program executable, prepares the program to run, and runs it. You may invoke this helper program directly from the command line to load and run an ELF executable file; this is like executing that file itself, but always uses this helper program from the file you specified, instead of the helper program file specified in the executable file you run. This is mostly of use for maintainers to test new versions of this helper program; chances are you did not intend to run this program. --list list all dependencies and how they are resolved --verify verify that given object really is a dynamically linked object we can handle --library-path PATH use given PATH instead of content of the environment variable LD_LIBRARY_PATH --inhibit-rpath LIST ignore RUNPATH and RPATH information in object names in LIST たとえば --list オプションは ldd のような動作をする。 % /lib/ld-2.3.1.so --list ./hello libc.so.6 => /lib/libc.so.6 (0x4000a000) /lib/ld-linux.so.2 => /lib/ld-2.3.1.so (0x80000000) もしくは次のようにすると普通に実行することもできる。 % /lib/ld-2.3.1.so ./hello hello, world preloadlist != NULL のチェックをして LD_PRELOADの処理をしている。その次に/etc/ld.so.preloadを見て おなじくpreloadの処理をする。 preloadのを処理をしてからDT_NEEDEDとされているshared libsの処理をおこなう。objdump -p で Dynamic Secion (動的セクション)で NEEDED になっている shared libs である。 % objdump -p ./hello (略) 動的セクション: NEEDED libc.so.6 INIT 0x80482bc FINI 0x804847c (略) つまりこの場合は libc.so.6 をリンクする。 最終的に dl_main で user_entry にプログラムの開始アドレスが設定され、それが _dl_sysdep_start()の return valueとなって start_addr になり start_addr = _dl_sysdep_start (arg, &dl_main); これが _dl_start_final()の return value となる。 ElfW(Addr) entry = _dl_start_final (arg, &info); この後 ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0); で_GLOBAL_OFFSET_TABLE_に対して設定をしている。これはelf/dynamic-link.hで#defineされており、 この中でsysdeps/i386/dl-machine.hのelf_machine_runtime_setup()がそれをしている。 これについては後に説明する。 さて entry はその後 return ELF_MACHINE_START_ADDRESS (GL(dl_loaded), entry); でさらに _dl_start()のreturn valueとなって sysdeps/i386/dl-machine.h のRTLD_STARTのコードに続き、 _dl_start_user()にくる。GOTなどを設定し、最終的に call _dl_start\n\ _dl_start_user:\n\ # Save the user entry point address in %edi.\n\ movl %eax, %edi\n\ (略) # Jump to the user's entry point.\n\ jmp *%edi\n\ で _dl_start()からのreturn valueのアドレスへjumpしユーザのプログラムの実行が開始される。 hello: ファイル形式 elf32-i386 hello アーキテクチャ: i386, フラグ 0x00000112: EXEC_P, HAS_SYMS, D_PAGED 開始アドレス 0x08048340 ELFヘッダからわかる通り、開始アドレスが 0x08048340 なので 08048340 g F .text 00000000 _start そのアドレスに配置されている_startから実行が開始される。 08048340 <_start>: 8048340: 31 ed xor %ebp,%ebp 8048342: 5e pop %esi 8048343: 89 e1 mov %esp,%ecx 8048345: 83 e4 f0 and $0xfffffff0,%esp 8048348: 50 push %eax 8048349: 54 push %esp 804834a: 52 push %edx 804834b: 68 7c 84 04 08 push $0x804847c 8048350: 68 bc 82 04 08 push $0x80482bc 8048355: 51 push %ecx 8048356: 56 push %esi 8048357: 68 20 84 04 08 push $0x8048420 804835c: e8 a3 ff ff ff call 8048304 <_init+0x48> 8048361: f4 hlt 8048362: 90 nop 8048363: 90 nop stackに引数をpushしていって 804835c: e8 a3 ff ff ff call 8048304 <_init+0x48> で次のコードをcallする 8048304: ff 25 b4 95 04 08 jmp *0x80495b4 ここで、0x80485a0〜が _GLOBAL_OFFSET_TABLE_ である。 080495a0 <_GLOBAL_OFFSET_TABLE_>: これを参照してみると 080495b4 には 0a 83 04 08 というバイト列がはいっているので、 その32bit little endianの値である 0804830a に jmp することになる 804830a: 68 10 00 00 00 push $0x10 804830f: e9 c0 ff ff ff jmp 80482d4 <_init+0x18> ちなみにこのあたりは gdb をつかってみると (gdb) disassemble 0x804830a Dump of assembler code for function __libc_start_main: 0x8048304 <__libc_start_main>: jmp *0x80495b4 0x804830a <__libc_start_main+6>: push $0x10 0x804830f <__libc_start_main+11>: jmp 0x80482d4 <_init+24> End of assembler dump. と __libc_start_main である。ちなみにこのあたりはセクション.pltで、ここを disassemble してみると 0x80482e4 <__register_frame_info>: jmp *0x80495ac 0x80482ea <__register_frame_info+6>: push $0x0 0x80482ef <__register_frame_info+11>: jmp 0x80482d4 <_init+24> 0x80482f4 <__deregister_frame_info>: jmp *0x80495b0 0x80482fa <__deregister_frame_info+6>: push $0x8 0x80482ff <__deregister_frame_info+11>: jmp 0x80482d4 <_init+24> 0x8048304 <__libc_start_main>: jmp *0x80495b4 0x804830a <__libc_start_main+6>: push $0x10 0x804830f <__libc_start_main+11>: jmp 0x80482d4 <_init+24> 0x8048314 : jmp *0x80495b8 0x804831a : push $0x18 0x804831f : jmp 0x80482d4 <_init+24> 0x8048324 : jmp *0x80495bc 0x804832a : push $0x20 0x804832f : jmp 0x80482d4 <_init+24> のようになっている。ここはどうなっているかを簡単に説明しよう。 まず_GLOBAL_OFFSET_TABLE_ (0x80495a0〜)にsymbolがresolvされたアドレスがはいることになっている。 0x80495b4(_GLOBAL_OFFSET_TABLE_の中の20バイト名、つまり_GLOBAL_OFFSET_TABLE_[8]に相当)に格納される アドレスがさしているのが __libc_start_mainの実体となる。ただし最初はまだマップされていないので、 その場合は 0x804830a をさしている。ここにくると push $0x10 して jmp 0x80482d4 である。 0x80482d4ではなにをしているかというと 80482d4: ff 35 a4 95 04 08 pushl 0x80495a4 80482da: ff 25 a8 95 04 08 jmp *0x80495a8 である。ここで 0x80495a8 は _GLOBAL_OFFSET_TABLE_ が 080495a0 なので _GLOBAL_OFFSET_TABLE_[2] に 相当している。この_GLOBAL_OFFSET_TABLE_には実はsysdeps/i386/dl-machine.hの elf_machine_runtime_setup()により got[1] = (Elf32_Addr) l; /* Identify this shared object. */ got[2] = (Elf32_Addr) &_dl_runtime_resolve; のような値が代入される。つまりjmp *0x80495a8で_dl_runtime_resolve()を呼ぶことになる。 _dl_runtime_resolv は sysdeps/i386/dl-machine.h にあり elf/dl-runtime.c の fixup()を呼ぶ。 fixup()がshared libsとのsymbolのresolveをおこなっていて、この場合は __libc_start_main() を libc.so.6 の中のルーチンを差すようにアドレスを_GLOBAL_OFFSET_TABLE_のエントリ (つまり_GLOBAL_OFFSET_TABLE_[8])に登録する。そうすることでまた同じルーチンを呼ぶときは 0x8048304 <__libc_start_main>: jmp *0x80495b4 というjumpをするわけであるが、一度fixup()を実行すると、0x80495b4(つまり_GLOBAL_OFFSET_TABLE_[8])に 書かれているアドレスが本当のルーチンへのアドレスになっているのでresolveする必要もなく そこにjmpするようになる。__libc_start_main()の実体はlibc.so.6で これはsysdeps/generic/libc-start.cの中にある。そしていろいろ処理をした後、最終的に result = main (argc, argv, __environ); で main()を呼ぶことになる。これでようやく int main(int argc, char *argv[]) { printf("hello, world\n"); exit(0); } まできたことになる。あとはこれを実行である。もちろん printf や exit などは__libc_start_main()で 説明したようなfixupがおこなわれてlibc.so.6とlinkされてそれらが実行されるという処理がおこなわれる。 最後に exit (result); で exit処理をする。 exit()もsystem callであるからexecve()の時のようにglibcのsysdeps/unix/sysv/linux/_exit.cの INLINE_SYSCALL (exit, 1, status); により system call 1 (__NR_exit) がよびだされ ENTRY(sys_call_table) .long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system ca ll*/ .long SYMBOL_NAME(sys_exit) から kernel/exit.c の asmlinkage long sys_exit(int error_code)がよびだされることになる。 この関数を実行していくと、processがもっていたresourceの解放をしてreschedule()して他のプロセスに 処理をわたしておわりである。あとは親プロセスが waitで tsk->exit_code にのこっている終了コードを ひろってもらえるまで zombie 状態となっているのである。これでプロセスの一生がおわりである。 この原稿もここでおしまい。 おまけ: yaegashi先生からreadelf(1)は使わないのか という指摘があったけれども、もう遅いのでかきなおすのは やめておきます。readelf(1)もつかっていろいろ遊んでみるのは宿題にしておきましょう:-) これは「でぶあん2002年冬号」の原稿を若干修正してHTML化したものです。(2005/11/03) Copyright c 2002,2005 Fumitoshi UKAI http://ukai.jp/debuan/2002w/elf.html -------------------------------------------------------------------------------- The Linux Bootdisk HOWTO Tom Fawcett (fawcett@croftj.net) 3.6, January 2000 The Linux Japanese FAQ Project (JF@linux.or.jp) v3.6j, 20 January 2000 この文書は Linux 用のブートディスク/ルートディスクを独自に設計・作成す る方法について述べたものです.これらのディスクはレスキューディスクとし て使ったり,システムの新しいコンポーネントをテストする時に使えます.こ れらのディスクを作る前に, Linux Installation HOWTO や Linux Install Guide などの FAQ や関連文書を読んでください.読んでいない方はブート ディスクを作るべきではありません.単に緊急用のレスキューディスクが欲し いだけならば,付録 A ``既製のブートディスクの入手''をご覧ください. ______________________________________________________________________ 目次 1. 前書き 1.1 バージョンに関する注意 1.2 まだできていないこと 1.3 フィードバックとクレジット 1.4 配布の方針 2. はじめに 3. ブートディスクとブートのプロセス 3.1 ブートのプロセス 3.2 ディスクの種類 4. ルートファイルシステムの作成 4.1 概要 4.2 ファイルシステムの作成 4.3 ファイルシステムの移植 4.3.1 /dev 4.3.2 /etc 4.3.3 /bin と /sbin 4.3.4 /lib 4.4 PAM と NSS の設定 4.4.1 PAM (差し替え可能な認証モジュール) 4.4.2 NSS (ネームサービス切り替え) 4.5 モジュール 4.6 その他の細かい事項 4.7 仕上げ 5. カーネルの選択 6. 全部をまとめる: フロッピーの作成 6.1 LILO を使ったカーネルの転送(NCDXLILO)NCDX 6.2 LILO を使わないカーネルの転送 6.3 ramdisk 変数の設定 6.4 ルートファイルシステムの転送 7. トラブルシューティング,または挫折の苦しみ 8. その他のトピックス 8.1 ファイルシステムのサイズの削減 8.2 非 RAM ディスクのルートファイルシステム 8.3 ユーティリティディスクの作成 9. プロが使う方法 10. FAQ(よくある質問)リスト A. 関連情報 A.1 既製のブートディスクの入手 A.2 レスキューパッケージ A.3 Graham Chapman さんのシェルスクリプト A.4 LILO -- Linux ローダ A.5 Linux FAQ と HOWTO 文書 A.6 RAM ディスクの使い方 A.7 Linux のブートプロセス B. LILO のブート時のエラーコード C. ルートディスクのサンプルのディレクトリ一覧 D. ユーティリティディスクのサンプルのディレクトリ一覧 E. 日本語訳について ______________________________________________________________________ 1. 前書き 注意: この文書の内容は古いかもしれません.表紙の日付が 6 ヵ月以上古け れば,Linux Documentation Project のホームページ をチェックして,もっと 新しい版が出ていないかどうか確認してください. この文書はテキスト形式でも読めないことはないと思いますが, Postscript (.ps)や HTML のほうがずっと読みやすいでしょう.用途に応じて様々なフォ ントが使えますから.これらの形式のいずれかを選ぶのがよいと思いま す.Info 形式のものは,現時点ではまともな変換ができていないので採録し ていません. 1.1. バージョンに関する注意 Graham Chapman さん(grahamc@zeta.org.au)がオリジナルの Bootdisk-HOWTO を作成し,バージョン 3.1 まで管理していました.私 Tom Fawcett (fawcett@croftj.net)がカーネル 2.0 に合わせてかなりの量を書き足し,バ ージョン 3.2 以降を管理しています.Chapman さんのオリジナルの内容もま だたくさん残っています. この文書はLinux カーネル 2.0 以降を想定しています.古いカーネル (1.2.xx 以前)を使っている人は, Graham Chapman さんのホームページ にアーカイブされている古い バージョンの Bootdisk-HOWTO をご覧ください. 本文書の情報は Intel プラットフォーム上で動作する Linux を想定していま す.多くの情報は他のプロセッサで動く Linux でも使えると思いますが,著 者らはこれらに直接触れた経験がありませんし,あまり詳しくありません。他 のプラットフォームでブートディスクを作成した経験をお持ちの方は,ぜひご 連絡ください. 1.2. まだできていないこと 手伝ってくださる方はいませんか? 1. 例えば CD-ROM や ZIP ディスク,LS110 ディスクなど,起動ディスクのよ うに使える別のメディアの作り方を説明する(あるいは説明している他の文 書へのリンクを用意する). 2. 巨大な libc.so 共有ライブラリの扱い方を説明する.選択肢は基本的に, 古くて小さいライブラリを入手するか,または既存のライブラリを切り詰 めるかのどちらかでしょう. 3. ディストリビューションの起動ディスクの分析をやり直す.「プロが使う 方法」の章を更新する. 4. ディストリビューションに用意されている起動ディスクのアップグレード の方法を説明している章を削除する.この章は役に立つよりも問題のもと になっているほうが多いようです. 5. トラブルシューティングの章を書き直すか,整理する. 1.3. フィードバックとクレジット いい知らせであれ悪い知らせであれ,本文書の内容に対してのフィードバック は歓迎です.文書中では操作手順や情報はできるだけ正確かつ信頼できるもの にしたつもりですが,誤りや抜けがあればぜひお知らせください. 訂正や提案の形で本文書をサポートしてくれた多くの方々に感謝します.この ような貢献のおかげで,自分達だけで作業した場合よりもずっとよい文書にな りました. コメントや訂正,疑問点などは前述のメールアドレスまで送ってください.筆 者もできるだけ質問に答えるつもりですが,質問の前にはまず ``トラブル シューティング''の章を読んでください. 1.4. 配布の方針 Copyright (C) 1995,1996,1997,1998,1999,2000 by Tom Fawcett and Graham Chapman. This document may be distributed under the terms set forth in the Linux Documentation Project License at . Please contact the authors if you are unable to get the license. This is free documentation. It is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. 日本語訳: Copyright (C) 1995,1996,1997,1998,1999,2000 by Tom Fawcett and Graham この文書は で入手できる Linux Documentation Project License の条項に基づいて配布できます.ライセンス を入手できない場合には,著者までご連絡ください. この文書はフリーです.この文書は有用であることを期待して配布しています が,いかなる保証も行いません.また,商業利用や特定目的への適合性に関し ても,暗黙の保証も含めていかなる保証も行いません. 訳注: この翻訳文書の著作権条項および免責事項に関しては,オリジナルに準 ずるものとします. 2. はじめに Linux のブートディスクは色々な場面で役に立ちます.例えば: o 新しいカーネルのテスト. o ディスク障害からの復旧.このような障害の原因にはブートセクタの消失 やディスクヘッドのクラッシュなど様々なものがあります. o 壊れたシステムの修復.root ユーザがちょっとミスをしただけでもシステ ムは使えなくなってしまいます.このような場合はフロッピーディスクか らブートして復旧しなければならないでしょう. o libc.so等,クリティカルなシステムファイルの更新. ブートディスクを作成する方法はいくつかあります: o Slackware のようなディストリビューションのものを用いる.ディストリ ビューションに含まれているブートディスクを用いれば,少なくともブー トはできます. o レスキューディスク作成ソフトを用いる. o ブートディスクを作成するのに何が必要かを学び,自分自身でブートディ スクを作成する. 最後の方法を選ぶ人もいます.自力でできるようにするのですね.これなら何 かが壊れた場合でも自力で修復手段を考え出すことができますし,おまけに Linux の動作に関する深い理解が得られます. この文書では読者の皆さんは Linux のシステム管理の基本概念を理解してい るものとします.例えば,ディレクトリやファイルシステム,フロッピーディ スクについては知っていることとします.mount や df コマンドの使い方, /etc/passwd ファイルや fstabファイルの目的や内容も知っている必要があり ます.また,この HOWTO で使うコマンドの大部分は root で実行しなければ ならない点についても理解していることとします. ゼロから独自のブートディスクを作ることは難しいかもしれません.これらの ディスクを作る前に, Linux Installation HOWTO や Linux Installation Guide などの FAQ, 関連文書を読んでください.読んでいない方はブート ディスクを作るべきではありません.単に緊急時に使えるブートディスクが必 要なだけなら,出来合いのものをダウンロードしてくるほうがずっと簡単で す.このようなブートディスクを入手するには,後述の付録 ``既製のブート ディスクの入手''をご覧ください. 3. ブートディスクとブートのプロセス ブートディスクは基本的にはシステムのミニチュアであり,必要なものが全て 揃った Linux システムを1枚のフロッピーディスクに収めたものです.このミ ニチュアシステムは,完全なフルサイズの Linux システムの機能の多くを実 行できなければなりません.したがって,ブートフロッピーを作る前には Linux のブートのプロセスの基本を理解しておくべきです.ここで基礎知識を 説明しますが,これを理解できていれば本書の残りの部分もわかると思いま す.ただし,詳しい部分や変更可能なオプションについては省略している部分 も多くあります. 3.1. ブートのプロセス 全ての PC システムのブート処理では,まず ROM のコード(特に BIOS)が実行 されます.このコードはブートドライブのシリンダ 0,セクタ 0 にあるセク タを読み込んで実行します.ブートドライブは普通はフロッピーディスクドラ イブ (DOS ではA:,Linux では /dev/fd0) です.BIOS は次にこのセクタを実 行しようとします.ブート可能なディスクのシリンダ 0,セクタ 0 には,た いてい以下のどちらかが入っています: o LILO のようなブートローダのコード.ブートローダはカーネルの位置を見 つけてそれをロード・実行してブートを適切に開始します. o Linux のような OS のカーネルの先頭部分. Linux カーネルがフロッピーに生書きされている(raw デバイスとして書き込 まれている)場合,フロッピーの最初のセクタは Linux カーネルそのものにな ります.この最初のセクタはブートデバイスからカーネルの残りの部分をロー ドしてブート処理を続けます. カーネルのロードが完全に終了すると,ロードされたカーネルは基本デバイス を初期化します.次にデバイスのどれかをルートファイルシステムとしてロー ド・マウントします.ルートファイルシステムはごく普通のファイルシステム で、``/'' としてマウントされます。カーネルにはルートファイルシステムの 場所を指示してやらなければなりません.この場所にロードできるイメージが 無ければ,カーネルは停止してしまいます. 状況によっては -- フロッピーからブートする場合にはしばしば -- ルート ファイルシステムは RAM ディスク にロードされます.これはシステムから ディスクのようにアクセスできる RAM です.システムを RAM ディスクにロー ドする理由は 2 つあります.まず RAM はフロッピーディスクよりも桁違いに 速く,システムを速く操作できるからです.またカーネルは圧縮されたファイ ルシステム をフロッピーから読み込んで,これを RAM ディスクに展開するこ とができるからです.これを使えばフロッピーにずっと多くのファイルを入れ ることができます. ルートファイルシステムがロード,マウントされると,次のようなメッセージ が表示されます: VFS: Mounted root (ext2 filesystem) readonly. 次にシステムはルートファイルシステム(の /bin または /sbinディレクト リ)でinitプログラムを見つけ,これを実行します.init は設定ファイ ル/etc/inittabを読み込み, sysinit と書いてある行を探し,そこで指定さ れているスクリプトを実行します.sysinitスクリプトは通常は /etc/rc や /etc/init.d/boot 等です.このスクリプトはいろいろなシェルコマンドが書 かれたものであり,以下のような基本的なシステムサービスの設定を行いま す: o 全てのディスクに対して fsck を実行. o 必要なカーネルモジュールのロード. o スワップの開始. o ネットワークの設定. o fstabに記述されたディスクのマウント. システムの初期化をモジュール化するため,このスクリプトから別のスクリプ トを複数個起動することもよく行われます.例えば標準的な SysVinit の構造 では,/etc/rc.d/ ディレクトリに複雑なサブディレクトリがあり,それぞれ のサブディレクトリにはシステムサービスの起動と停止の方法を指定している ファイルがあります.ですが,ブートディスクの sysinit スクリプトは普通 はとてもシンプルなものになるでしょう. sysinit スクリプトが終了すると,制御は init に返されます. init は続い てデフォルトの実行レベルに入ります(これは inittab の initdefault の項 目で指定します).実行レベルの行では普通は getty のようなプログラムを指 定します.ここで指定したプログラムはコンソールや tty 経由の通信を処理 します.おなじみの ``login:'' というプロンプトを出しているのも getty プログラムです.getty プログラムは続いて login プログラムを実行し,こ れがログイン認証やユーザセッションの設定を行います. 3.2. ディスクの種類 これまで説明した基本的なブート処理を理解していれば,ブートに必要となる 色々な種類のディスクを定義することができます.ここではディスクを4つに 分類します.特に断らない限り,これ以降の議論では「ディスク」という言葉 はフロッピーディスクを指すものとします.ただし,議論の大部分はハード ディスクにも同様に適用できるだろうと思います. ブート ブート可能なカーネルを含むディスク.このディスクを使えばカーネル をブートすることができます.この時,他のディスクにあるルートファ イルシステムを使うこともできます.通常ブートディスクに入っている カーネルには,ルートファイルシステムの場所を教えてやらなければな りません. ブートディスクは他のフロッピーにあるルートファイルシステムをロー ドすることが多いですが,ハードディスク上のルートファイルシステム をロードするようにブートディスクを設定することもできます.この方 法は新しいカーネルのテストをする時によく使います(実は,``make zdisk'' とすれば,カーネルのソースコードから自動的にこのようなブ ートディスクを作成することができます). ルート Linux のシステムを動作させるために必要なファイルが入っているファ イルシステムを持つディスクです.カーネルやブートローダは含まれな くてもかまいません. 一旦カーネルがブートすれば,他のディスクなしに,ルートディスクだ けでシステムを動作させることができます.普通はルートディスクは自 動的に RAM ディスクにコピーされます.こうすればずっと速くルート ディスクにアクセスできますし,ディスクドライブが空くのでユーティ リティディスクを利用することもできます. ブート/ルート カーネルとルートファイルシステムが両方入っているディスクです.言 い換えれば,ハードディスク無しで Linux システムの起動と実行を行 うために必要なものが全て入っているディスクです.このようなディス クの利点はコンパクトである -- 1 枚のディスクの中に必要なもの全て が納められている -- ことです.しかし昨今では色々なもののサイズが 大きくなってきていますので, 1 枚のディスクに必要なもの全てを収 めることは(圧縮を使っても)難しくなりつつあります. ユーティリティ ファイルシステムを含みますが,ルートファイルシステムとしてマウン トするために作られたのではないディスク. ユーティリティディスク は付加的なデータディスクです.このタイプのディスクはルートディス クに入り切らない復旧用のユーティリティなどを別に入れておくために 使います. 一般に「ブートディスクの作成」という時は,ブート(カーネル)とルー ト(ファイル)の部分を両方作成することを指します.これらは同じディスクに なること(1 枚のブート/ルートディスク)も,別のディスクになること(ブート ディスク + ルートディスク)もあります.レスキューディスクの用途には,別 々のブートディスクとルートディスクを組み合わせて使えばとても柔軟に運用 できるでしょう.そして,入りきらない分に対してユーティリティディスクを 別に用意するとよいでしょう. 4. ルートファイルシステムの作成 ルートファイルシステムを作る際には,システムを実行するために必要なファ イルを選択する必要があります.この章では,圧縮形式のルートファイルシス テムの作り方を説明します.あまり行われませんが、直接ルートファイルシス テムとしてマウントされる,圧縮形式でないファイルシステムをフロッピー上 に作る方法もあります.この方法は``非 RAM ディスクのルートファイルシス テム'' の章で説明します. 4.1. 概要 root ファイルシステムには,完全に動作する Linux システムに必要なファイ ル全てが入っていなければなりません.そのためディスクには Linux システ ムにとって必要最小限のファイルが入っていなければなりません: o 基本的なファイルシステム構造 o 最低限必要なディレクトリ: /dev, /proc, /bin, /etc, /lib, /usr, /tmp o 基本的なユーティリティ: sh, ls, cp, mv等 o 最低限必要な設定ファイル: rc, inittab, fstab等 o デバイス: /dev/hd*, /dev/tty*, /dev/fd0等 o ユーティリティが使う実行時ライブラリ もちろん何かがその上で動かなければシステムは役に立ちません.以下のよう なことができなければ,ルートディスクは役に立つとは言えません: o 他のドライブにあるファイルシステム(例えばハードディスク上のルート ファイルシステム)の検査.これを行なうには,検査したいディスクとは別 のドライブ(例えばルートディスク)で Linux を立ち上げ,検査したいディ スクをマウントしていない状態で fsck を実行する必要があります. o バックアップから元のルートドライブの全部または一部を cpio, tar, gzip, ftape 等のアーカイブや圧縮用のユーティリティを用いて復元する 作業. ここで圧縮形式のファイルシステムの作り方を説明します.このファイルシス テムはディスク上では圧縮されていて,起動時に RAM ディスク上に展開され ます.圧縮形式のファイルシステムを使うと,標準の 1.44M のフロッピーに たくさんのファイル(約 6 メガバイト)を入れることができます.このファイ ルシステムはフロッピーよりもずっと大きいため,フロッピー上で作ることは できません.したがって,他の場所で作成して圧縮をしてからフロッピーに書 き込まなければなりません. 4.2. ファイルシステムの作成 このようなルートファイルシステムを作成するには,圧縮前のファイル全てを 格納できる大きさを持つデバイスが必要になります.およそ 4 メガバイト程 度の容量を持つデバイスが必要になるでしょう.いくつかの候補を以下に挙げ ます: o ramdisk (DEVICE = /dev/ram0)を用いる方法.この場合はメモリ上に仮想 的なディスクドライブが作成されます. RAM ディスクは適切なサイズの ファイルシステムを納めるのに十分な容量を持っていなければなりませ ん. LILO を使っているならば,設定ファイル (/etc/lilo.conf)に以下の ような行を記述してください: RAMDISK_SIZE = nnn これによって,RAM ディスクに割り当てることができる最大の RAM 容量を指 定します.デフォルト値は 4096K です.たぶんこの大きさで十分でしょう. メモリが 8M より少ないマシンでは,このような設定で RAM ディスクを使う のは避けたほうがよいでしょう. /dev/ram0や/dev/ram, /dev/ramdiskといったデバイスファイルがあることを 確認しましょう.もしなければ, mknod を使って /dev/ram0 を作りましょ う(メジャー番号は 1, マイナー番号は 0 です). o 十分な容量(数メガバイト程度)のある未使用のハードディスクパーティ ションがあれば,これを使うと良いでしょう. o ループバックデバイスの利用.これを使うとディスク上のファイルをデバ イスとして扱うことができます.ループバックデバイスを使うと,3 メガ バイトのファイルをハードディスク上に用意し,その上にファイルシステ ムを作ることができます. ループバックデバイスの使い方は man losetup で調べてください. losetup がなければ, にある util-linux パッケージに含まれている,対応版 mount と unmount でも同じことができます. システム上にループバックデバイス(/dev/loop0, /dev/loop1等)が無けれ ば,コマンド ``mknod /dev/loop0 b 7 0'' を実行して作成しましょう. 既に対応版の mount と umount のバイナリをインストール済みなら,十分 な大きさを持つハードディスクに一時ファイルを作成します(ここでは /tmp/fsfile とします).次のようなコマンドを使います: dd if=/dev/zero of=/tmp/fsfile bs=1k count=nnn これにより,nnn ブロックのファイルが作成されます. 以下の手順でデバイス名を指定するところでは, DEVICE の代わりにこの作成 したファイルの名前を使ってください. mount をループバックデバイスに対 して使うには ``-o loop'' オプションを用います.以下に例を示します: mount -o loop -t ext2 /tmp/fsfile /mnt このようにすればファイル /tmp/fsfile が /mntに (ループバックデバイス経 由で)マウントされます. df コマンドを使って確認してください. 以上のどれかを用いてデバイスを作ったら,まず次のようなコマンドを実行し ます. dd if=/dev/zero of=DEVICE bs=1k count=3000 このコマンドによってデバイスの中身が 0 で埋め尽くされます.圧縮ファイ ルシステムを作成するにあたってはこの作業は重要です.未使用の部分を全て 0 にしておくと圧縮率を最大にできるからです. 次にファイルシステムを作成します. RAM ディスクに自動コピーされるルー トディスクとして Linux カーネルが認識できるファイルシステムには, minix と ext2 があります.ext2 の方がお勧めです.ext2 を使っている場合 は -i オプションを指定してデフォルトより多くの i-ノードを作っておくと よいでしょう. -i 2000 としておけば i-ノードを使い切る心配はしなくてよ いでしょう.あるいは /dev から不必要なファイルを消して i-ノードを節約 してもいいでしょう.デフォルトでは mke2fs は 1.44 メガのフロッピーに 360 個の i-ノードを作ります.さっき筆者のレスキューディスクを見てみた ら 120 個の i-ノードが余っていました.しかし /dev ディレクトリのファイ ルを全て含めると 360 個を簡単に越えてしまうでしょう.圧縮形式のルート ファイルシステムを用いるとファイルシステムの大きさが増えますから,デ フォルトの i-ノードの数も 360 以上になります.しかしそれでもファイルを 減らすか i-ノードを増やすかする必要があるでしょう. i-ノードを増やすには,次のようなコマンドを使います: mke2fs -m 0 -i 2000 DEVICE (ループバックデバイスを使うときは,上記の DEVICE の部分を使用するファ イルに置き換えてください.この場合,mke2fs は実行の確認をしてくると思 います.) mke2fs コマンドは利用可能な容量を自動的に検知し,ファイルシステムを適 切に設定してくれます.-m 0 パラメータを利用するとスーパーユーザ専用の 予約領域を作らなくなるので,利用できるディスク領域が増えます. 次にデバイスをマウントします: mount -t ext2 DEVICE /mnt (まだ作っていなければ,マウントポイント /mnt を用意しなければなりませ ん.)以降の章では,対象となるディレクトリ名は /mntからの相対パスで表す ものとします. 4.3. ファイルシステムの移植 ルートファイルシステム用の現実的な最小のディレクトリ構成は以下のように なります: o /dev -- デバイス,I/O の実行に必要 o /proc -- proc ファイルシステムに必要なディレクトリ o /etc -- システム設定ファイル o /sbin -- 必須のシステムバイナリ o /bin -- システムの一部とみなされる基本バイナリ o /lib -- プログラム実行に使う共有ライブラリ o /mnt -- 他のディスクを扱うためのマウントポイント o /usr -- その他のユーティリティやアプリケーション (ここで示したディレクトリ構造はルートフロッピー用のものです.実際の Linux システムではもっと複雑ですし,ちゃんとした方針に従っています.こ の方針は Filesystem Hierarchy Standard と呼ばれるもので,ファイルを置 くべき場所を決める規則です.) このディレクトリのうち 3 つは空ディレクトリなので,単にmkdirコマンドで 作成するだけでかまいません./procディレクトリは proc ファイルシステム を配置するための単なる器です./mntと/usrは,ブート/ルートシステムが起 動した後に使うただのマウントポイントです.というわけで,繰り返しになり ますが,この 3 つのディレクトリは作成するだけでかまいません. 残りの 4 つのディレクトリについては以降の章で説明します. 4.3.1. /dev /dev ディレクトリは全ての Linux システムに必須のディレクトリで,システ ムが使う全てのデバイスに対するスペシャルファイルがここにあります./dev 自身は普通のディレクトリで,ごく普通に mkdir コマンドで作成できます. しかしデバイスのスペシャルファイルは特別な方法 (mknodコマンド)を用いて 作成しなければなりません. もっと楽な方法もあります.既に存在する /dev ディレクトリの内容をコピー して,それから不要なものを消去するのです.注意しなければいけない点は, デバイスのスペシャルファイルをコピーする場合には -R オプションが必要な ことくらいです.-R オプションを指定すると,ファイルの内容はコピーせず にディレクトリがコピーされます.R は必ず大文字にします.小文字の -r オ プションを使うと全く異なった動作となります.ハードディスクの内容が(少 なくともフロッピーが一杯になるまで)全部コピーされてしまうのです! です から次のコマンドを使うときはオプションに注意してください: cp -dpR /dev /mnt ここでフロッピーは /mnt にマウントされているものとします. d オプショ ンはシンボリックリンクをコピーする際に,リンク先の実体ではなくリンクそ のものをコピーするための指定です. p オプションは元のファイルの属性を 保存します(したがって所有者情報も保存されます). あえて手間のかかる方法でやりたい場合は, コピーしたいデバイスのメジャ ー番号とマイナー番号を ls -l で調べ, mknod コマンドでフロッピー上にそ れらを作成します. デバイスをコピーしたあと,必要なデバイスが全部ちゃんとレスキューディス クにあるかどうかを確認しましょう.例えば,ftape はテープデバイスを使い ますから,ブートディスクからテープデバイスにアクセスする予定があるな ら,テープのデバイスファイルは全てコピーしておく必要があります. それぞれのデバイスファイルにひとつづつ i-ノードが必要です.フロッピー のファイルシステムでは i-ノードは不足しがちですから,必要でないデバイ スファイルをフロッピーの /devディレクトリから消しておくと良いでしょ う.明らかに不必要なデバイスが結構あるはずです.例えば SCSI ディスクを 持っていないのなら sd ではじまる名前のファイルは全て消してしまえます. 同様にシリアルポートを使わないつもりなら cuaで始まるファイルも消せま す. 次のファイルはこのディレクトリに必ずなければなりません: console, kmem, mem, null, ram, tty1 4.3.2. /etc このディレクトリには多くの設定ファイルが置かれます.大抵のシステムでは 設定ファイルは以下の 3 つに分類できます: 1. 絶対に必要なもの.例えば rc, fstab, passwd など. 2. 必要かもしれないけれど,よくわからないもの. 3. 勝手にできてしまうゴミ. 必要でないファイルは以下のコマンドで見つけることができます: ls -ltru このコマンドを使うと,ファイルは最後にアクセスされた日が古い順に一覧表 示されるので,アクセスされていないファイルがあれば,ルートフロッピーか ら取り除いてしまいましょう. 私の場合ルートフロッピーに入れる設定ファイルの数は下記の 15 個にまで減 らしています.これにより,以下の 3 種類のファイルを扱えばよいように なっています: 1. ブート/ルートシステムに設定しなければならないファイル: a. rc.d/* -- システムの起動と実行レベル変更のスクリプト b. fstab -- マウントするファイルシステムのリスト c. inittab -- init プロセス (起動時の最初のプロセス)のパラメータ. 2. ブート/ルートシステム用に短くしておいた方が良いファイル: a. passwd -- ユーザ,ホームディレクトリのリスト b. group -- ユーザグループ c. shadow -- ユーザのパスワード.このファイルは無いかもしれない. d. termcap -- 端末機能データベース セキュリティが重要な場合は,passwd と shadow を整理して,システムの 外にユーザのパスワードがコピーされないようにすべきです.またこうす れば,フロッピーからブートしたとき,予定外のログインを拒否できま す. passwd には少なくともrootユーザを入れてください.他にログインさせる つもりのユーザがいるなら,ホームディレクトリやシェルも確認しましょ う. termcap (端末データベース) のサイズは,通常数百キロバイト程度です. 起動ディスクやルートディスクに入れる termcap ファイルには,使用する 端末の項目だけを入れるようにしましょう.普通は linux-console の項目 だけになります. 3. 残り.現時点でこれらのファイルを置いたままでシステムはちゃんと働い ているので,そのままにしてあります. この中で本当に設定しなければならないのは 2 個のファイルだけです.その 中身は驚くほど小さいものです. o rc は以下のようになっています: #!/bin/sh /bin/mount -av /bin/hostname Kangaroo ディレクトリが正しいことを必ず確かめてください. hostname は特に実行す る必要はありません.単に見栄えを良くするためのものです. o fstab の内容は以下の通りです: /dev/ram0 / ext2 defaults /dev/fd0 / ext2 defaults /proc /proc proc defaults 既に存在する fstab のエントリーをコピーしてもかまいませんが,ハード ディスクのパーティションが自動的にはマウントされないようにすべきです. noauto オプションを使えば,そのような設定にできます.こうしておけば, ハードディスクが壊れた時にもこのブートディスクを使用できます. inittabの sysinit 行は変更して, rc 等の基本的となる起動スクリプトを実 行するようにしておかなければなりません.シリアルポートからのログインを 禁止するならば, inittab に含まれる getty のエントリのうち,行末が ttys または ttyS デバイスになっているものを全部コメントアウトします. コンソールからはログインできるようにtty のエントリは残しておきましょ う. 最小限の inittab は次のようになるでしょう: id:2:initdefault: si::sysinit:/etc/rc 1:2345:respawn:/sbin/getty 9600 tty1 2:23:respawn:/sbin/getty 9600 tty2 inittab ファイルは,起動時やマルチユーザモードへの移行時,電源断のとき などにシステムが起動(あるいは再起動)するものを定義します.ここで特に注 意しておきたい点は, inittab に記述されているファイル名を注意深く確認 することです.記述されているプログラムを init が見つけられないと,起動 ディスクはハングします.このような場合にはエラーメッセージさえ表示され ないかもしれません. プログラムによっては,他の場所には移動させられないこともあります.他の プログラムに位置がハードコード (直接記述) されている場合などがこれにあ たります. /etc/reboot の場所は /etc/shutdown でハードコードされていま す.もし reboot を /bin/reboot に移動させると, shutdown は reboot ファイルを見つけられないので,実行できなくなってしまいます. 残りのファイルについては /etc ディレクトリにある全てのテキストファイル を単にフロッピーにコピーするだけです.加えて /etc ディレクトリにある実 行ファイルのうち,不要だという自信の無いものを全てコピーします. ``ル ートディスクのサンプルのディレクトリ一覧'' の章が役に立つでしょう.こ のようなファイルをコピーするだけでうまく行くこともありますが,システム はそれぞれ大きく異なるのが普通ですから,当然うまく行かない場合もありえ ます.絶対確実と言える方法は,inittab からたどって必要なファイルを全部 確認することだけです. 現在ほとんどのシステムでは,実行レベルごとに異なるシェルスクリプトの置 き場所として /etc/rc.d ディレクトリを使っています.とにかく小さくした い場合には rc スクリプトひとつだけにすることもできますが,実際には今の システムから inittab と /etc/rc.d ディレクトリをコピーして,フロッピー ベースのシステムに不要なものを削っていく方がずっと簡単でしょう. 4.3.3. /bin と /sbin /bin ディレクトリには ls や mv, cat, dd などの基本的な操作を行うときに 必要なコマンドを置いておくと良いでしょう.付録の ``ルートディスクのサ ンプルのディレクトリ一覧'' で,/bin ディレクトリや /sbinディレクトリに 置いたファイルの例を見てください.この例では cpio, tar, gzip といった バックアップの復元に必要なプログラムはありません.これはブート/ルート フロッピーの空き領域を増やすために,別のフロッピー(ユーティリティディ スク)に入れてあるからです.いったんブート/ルートフロッピーを使ってブー トすると,このフロッピーの内容は自動的に RAM ディスクにコピーされま す.すると,フロッピーディスクドライブは空いて他のディスクをマウントで きるようになるので,ユーティリティディスクをマウントして使います.筆者 はユーティリティディスクを普通 /usr にマウントしています. ユーティリティフロッピーの作成方法は後述の ``ユーティリティディスクの 作成''の節で説明しています.バックアップの作成に使ったのと同じバージョ ンのバックアップユーティリティを保存しておく方がたぶんよいでしょう.そ うすればバックアップテープを読めないバージョンのものをインストールして 時間を無駄にすることもないでしょう. 次のプログラムは確実に入れましょう: init, getty(または同等品), login, mount, rc スクリプトを実行できるシェル, sh からそのシェルへのリンク. 4.3.4. /lib /lib には必要な共有ライブラリとローダを置きます.必要な共有ライブラリ が /lib になければシステムをブートすることができません.運が良ければエ ラーメッセージで何が足りないかがわかるでしょうが. ほとんど全てのプログラムは,少なくとも libc ライブラリである libc.so.N を必要とします.ここで,N は現在のバージョン番号です.読者のみなさんの /lib をチェックしてみてください. libc.so.N は通常,完全なバージョン番 号を持つファイルへのシンボリックリンクです: % ls -l /lib/libc* -rwxr-xr-x 1 root root 4016683 Apr 16 18:48 libc-2.1.1.so* lrwxrwxrwx 1 root root 13 Apr 10 12:25 libc.so.6 -> libc-2.1.1.so* この場合には libc-2.1.1.so が必要となります.コピーすべき他のライブラ リを見つけるには,入れようとするバイナリを全て調べ, ldd コマンドを 使って依存関係をチェックします.例を示します: % ldd /sbin/mke2fs libext2fs.so.2 => /lib/libext2fs.so.2 (0x40014000) libcom_err.so.2 => /lib/libcom_err.so.2 (0x40026000) libuuid.so.1 => /lib/libuuid.so.1 (0x40028000) libc.so.6 => /lib/libc.so.6 (0x4002c000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) 右側にあるファイルが必要なものです.ファイルはシンボリックリンクである こともあります. 一部のライブラリは非常に大きく,容易にはルートファイルシステムに入れら れないこともあります.例えば,先に挙げた libc.so のサイズは約 4 メガバ イトです.このファイルをルートファイルシステムにコピーする際には,ライ ブラリを strip する必要があるかもしれません.この手順について は,``ファイルシステムのサイズの削減'' の節を参照してください. /lib にはライブラリをロードするためのローダも入れる必要があります.ロ ーダのファイルの名前は ld.so (a.out ライブラリ用) または ld-linux.so (ELF ライブラリ用) です.新しいバージョンの ldd を使えば,(先に示した 例のように)どのローダが必要なのかが正確に分かりますが,古いバージョン の ldd ではこれが分からないことがあります.どちらが必要なのかが確かで なければ,ライブラリに対して file コマンドを実行してください.実行例を 示します: % file/lib/libc.so.4.7.2 /lib/libc.so.5.4.33 /lib/libc-2.1.1.so /lib/libc.so.4.7.2: Linux/i386 demand-paged executable (QMAGIC), stripped /lib/libc.so.5.4.33: ELF 32-bit LSB shared object, Intel 80386, version 1, stripped /lib/libc-2.1.1.so: ELF 32-bit LSB shared object, Intel 80386, version 1, not stripped QMAGIC は 4.7.2 は a.out 用ライブラリであることを示し, ELF は 5.4.33 と 2.1.1 が ELF 用ライブラリであることを示します. 作ろうとしているルートファイルシステムに必要なローダをコピーしてくださ い.両方とも必要な場合もあるかもしれません.入れるバイナリに対して,ラ イブラリとローダは慎重にチェックしなければなりません.カーネルが必要な ライブラリをロードできない場合,普通カーネルはエラーメッセージも出さず に止まってしまうでしょう. 4.4. PAM と NSS の設定 ldd では見えない,動的にロードされるライブラリがシステムに必要とされる かもしれません. 4.4.1. PAM (差し替え可能な認証モジュール) システムが PAM (差し替え可能な認証モジュール)を使っている場合,ブート ディスクにいくらか手を加えないとログインできなくなってしまいます.PAM とはユーザの認証とサービスへのユーザアクセスとを制御するための手法で, きれいにモジュール化されているものです.システムが PAM を使っているか どうかを簡単に調べるには,ハードディスクの /etc ディレクトリに pam.conf ファイルか pam.d ディレクトリがあるかどうか確認することです. このどちらかが存在する場合,最低限の PAM サポートを準備しなければなり ません.(調べるための別の方法としては, ldd を login の実行ファイルに 対して使ってみる方法もあります.出力に libpam.so が含まれる場合には, PAM が必要です.) 好運なことに,ブートディスクでは通常,セキュリティを考える必要は全くあ りません.なぜなら,マシンに物理的にアクセスできるならば,いずれにせよ どんなことでもできるからです.よって,事実上は PAM を無効化しても構い ません.これは次のような内容の簡単な /etc/pam.conf を作成するだけで OK です: ______________________________________________________________________ OTHER auth optional /lib/security/pam_permit.so OTHER account optional /lib/security/pam_permit.so OTHER password optional /lib/security/pam_permit.so OTHER session optional /lib/security/pam_permit.so ______________________________________________________________________ /lib/security/pam_permit.so ファイルもルートファイルシステムにコピーし ます.このライブラリは 8K 程度しかないので,負担は最小限で済みます. この設定にすると,そのマシンのファイルやサービスには誰でも完全なアクセ スができるようになります.何らかの理由でブートディスクでもセキュリティ に注意したい場合には,ハードディスクの PAM の設定の一部あるいは全部を ルートファイルシステム上にコピーしなければなりません.PAM の文書をよく 読んで,/lib/security にあるライブラリのうち必要なものをルートファイル システムにコピーしてください. また,ブートディスクには /lib/libpam.so を入れる必要がありますが,既に 読者のみなさんはこれは知っているはずです.なぜなら, /bin/login に ldd を実行したときに,このファイルが依存関係で表示されたからです. 4.4.2. NSS (ネームサービス切り替え) glibc(別名 libc6)を使っている場合,ネームサービスに手を加えなければロ グインできません.NSS ではファイル /etc/nsswitch.conf を使って様々なサ ービスへのデータベース参照を制御します.ネットワークのサービス(DNS や NIS の参照等)にアクセスするつもりがなければ,以下のような簡単な nsswitch.conf を準備するだけです: ______________________________________________________________________ passwd: files shadow: files group: files hosts: files services: files networks: files protocols: files rpc: files ethers: files netmasks: files bootparams: files automount: files aliases: files netgroup: files publickey: files ______________________________________________________________________ この指定では全てのサービスをローカルファイルだけから受けるようになりま す.また,/lib/libnss_files.so.1 ファイルも必要になるでしょう.この ファイルはファイルの参照を扱うために動的にロードされます. ブートディスクからネットワークにアクセスすることを考えているならば, もっとちゃんとした nsswitch.conf を書こうと思うかもしれません.指定し ようとするサービスごとに /lib/libnss_サービス.so.1を組み込む必要がある ことを忘れないでください. 4.5. モジュール モジュール化したカーネルを使っている場合,起動後にブートディスクからど のモジュールをロードしたいのかを考えなければなりません.バックアップテ ープがフロッピーテープにある場合はftape モジュールや zftapeモジュール が必要でしょうし,SCSI 機器があるなら SCSI デバイス用のモジュールが必 要でしょう.また,緊急時にネットにアクセスしたければ PPP や SLIP をサ ポートするためのモジュールも必要になるでしょう. このようなモジュールは /lib/modules に置きます.また, insmod, rmmod, lsmod も入れなければなりません.モジュールを自動的にロードするかどうか によって,modprobe, depmod, swapout が必要になるかどうかも決まりま す.kerneld を使うならば /etc/conf.modules も一緒に入れましょう. しかし,モジュールを使う最大の利点は,必須でないモジュールをユーティリ ティディスクに移しておいて必要な時にロードできる点です.これにより,ル ートディスクで使う容量が減ります.異なる種類のデバイスを多く扱わなけれ ばならないかもしれない場合,たくさんのドライバを組み込んだ巨大なカーネ ルを1つ作るよりもこのアプローチの方が好ましいでしょう. 圧縮形式の ext2 ファイルシステムを使う時には RAM ディスクと ext2 のサ ポートはカーネルに組み込まなければなりません.これらをモジュールとして 使うことはできません. 4.6. その他の細かい事項 /var/run/utmp ファイルや /var/log ディレクトリが存在しない場合,一部の システムプログラム(login 等)は文句を言ってきます.そこで次のようにして おきます: mkdir -p /mnt/var/{log,run} touch /mnt/var/run/utmp 必要なライブラリを設定したら,最後に ldconfig を実行してルートファイル システムの /etc/ld.so.cache を作り直します.このキャッシュがローダにラ イブラリの場所を教えます.ld.so.cache を作り直すには次のコマンドを実行 します: chdir /mnt; chroot /mnt /sbin/ldconfig chroot が必要なのは,ldconfig が常にルートファイルシステムのキャッシュ を作り直すからです. 4.7. 仕上げ ルートファイルシステムの作成が終わったら,このファイルシステムをアンマ ウントし,ファイルにコピーして,圧縮します: umount /mnt dd if=DEVICE bs=1k | gzip -v9 > rootfs.gz これが終わったら圧縮形式のルートファイルシステムである rootfs.gz がで きるはずです.この大きさを調べ,フロッピーに収まることを確かめましょ う.収まり切らない場合には,ファイルをいくつか消しましょう.ルートファ イルシステムのサイズを小さくする場合, ``ルートファイルシステムのサイ ズの削減''セクションが参考になるでしょう. 5. カーネルの選択 この時点で圧縮形式のルートファイルシステムは完成しています.次のステッ プはカーネルを構築または選択することです.ほとんどの場合は現在使ってい るカーネルをコピーし,それで作ったフロッピーからブートすればよいでしょ う.それでも別のカーネルを作りたい場合もあることでしょう. 理由の1つは大きさです.1枚のブート/ルートディスクを作る場合,カーネル はフロッピー中で最大に近いファイルになるはずです.そこで,カーネルのサ イズをできるだけ小さくしておく必要があります.カーネルのサイズを小さく するには,サポートする機能をシステムに必要な最小限のものに絞ってカーネ ルを構築します.つまり,不要なものを全て外すのです.ネットワーク機能は 外してよいでしょうし,ブート/ルートシステムでは不必要なディスクやその 他のデバイスも外せるでしょう.ただし,既に述べたように RAM ディスクと ext2 はカーネルに組み込んでおかなければなりません. カーネルに持たせる最低限の機能が決まったら,次はカーネルに戻すものを決 める必要があります.ブート/ルートフロッピーのシステムを使う一般的なユ ーザの多くは多分壊れたルートファイルシステムの検査と復旧を行おうとして いるのでしょうから,これを行うためのカーネルのサポートが必要でしょう. 例えば,バックアップが全て ftape を使ってテープに入れられており,かつ 現在ルートにしているドライブと ftape が入っているドライブが壊れてし まった場合,バックアップテープから復旧を行なうことはできません.こう なってしまったら,Linux を再インストールして ftape を入手・インストー ルし,それからバックアップの読み出しを行わなければなりません. つまり重要なのは,通常のカーネルに組み込んでいるバックアップ用の I/O サポートは,ブート/ルートのカーネルにも組み込んでおくべきだということ です. 実際にカーネルを構築するための手順は,カーネルに付属の文書で説明されて います.これはとても簡単なので,まずは /usr/src/linux をご覧ください. カーネルもちゃんと作れないようならば,ブート/ルートディスクを作ろうと 考えるのはやめた方がいいでしょう.``make zImage'' でカーネルを圧縮する ことを忘れないでください. 6. 全部をまとめる: フロッピーの作成 これでカーネルと圧縮形式のルートファイルシステムができました.1枚のブ ート/ルートディスクを作るならば,両方のサイズを合わせても1枚のディスク に収まることを確認します.ブート+ルートを2枚組で作るならば,ルートファ イルシステムが1枚のフロッピーに収まることを確認します. 次にブートディスクのカーネルを LILO で起動するかどうかを決めます.別の 方法としては,カーネルを直接フロッピーに書き込んで LILO 無しで起動させ ることもできます.LILO を使う利点は,システム上のハードウェアの初期化 に必要なパラメータを指定できる点です.(システムの /etc/lilo.conf を見 てください.このファイルがあって, ``append=...'' といった記述があれ ば,たぶんこの機能が必要です.) LILO を使う欠点はブートディスクを作る のが面倒な点と,ディスクの使用量が少し増えてしまう点です.また,小さな 別のファイルシステム(いわばカーネルファイルシステム)も設定しなければな らないでしょう.ここに LILO が必要とする他のファイルとカーネルを転送す ることになります. LILO を使うことにした人はこのまま読み続けてください.カーネルを直接転 送することにした人は, ``LILO を使わない場合''の節へ進んでください. 6.1. LILO を使ったカーネルの転送 最初にすべきことは,LILO のための簡単な設定ファイルを作ることです.こ れは次のようになります: ______________________________________________________________________ boot =/dev/fd0 install =/boot/boot.b map =/boot/map read-write backup =/dev/null compact image = KERNEL label = Bootdisk root =/dev/fd0 ______________________________________________________________________ パラメータの詳細については LILO のユーザ文書をご覧ください.このファイ ルにはハードディスクの /etc/lilo.conf ファイルから抜き出した append=... の行を追加しておくべきかもしれません. このファイルは bdlilo.conf として保存します. ここで小さいファイルシステムを作らなければなりません.ルートファイルシ ステムと区別するため,このファイルシステムはカーネルファイルシステムと 呼びます. まず,このファイルシステムの大きさを決めます.カーネルのサイズをブロッ ク数で求め(``ls -l KERNEL'' で得られるサイズを 1024 で割り,端数を切り 上げます),これに 50 ブロックを加えます.50 ブロックというのは,i-ノー ドや他のファイルの分のおよそのサイズです.この数値を正確に求めてもかま いませんが,単に50を使ってもかまいません.2枚組のディスクを作る場合に は,このサイズはもっと大きく見積もっても大丈夫でしょう.どうせ最初の ディスクにはカーネルしか入れないのですから.この数字を KERNEL_BLOCKS とします. ドライブにフロッピーを入れて,このフロッピーに ext2 カーネルファイルシ ステムを作成します(表記を簡単にするため,ドライブは /dev/fd0 であるも のとします): mke2fs -i 8192 -m 0 /dev/fd0 KERNEL_BLOCKS ``-i 8192'' オプションは,1つのi-ノードで8192バイトを使うことを指定し ます.次にファイルシステムをマウントし,lost+found ディレクトリを消 し,LILO 用に dev ディレクトリと boot ディレクトリを作ります. mount /dev/fd0 /mnt rm -rf /mnt/lost+found mkdir /mnt/{boot,dev} 次に /dev/nullデバイスと /dev/fd0デバイスを作ります.デバイス番号を調 べなくても,-R オプションを使えばハードディスクからそのままコピーでき ます. cp -R /dev/{null,fd0} /mnt/dev LILO にはブートローダのコピー(boot.b)が必要です.これはハードディスク から持ってくることができます.通常これは /boot ディレクトリに置かれま す. cp /boot/boot.b /mnt/boot 最後に,先程の節で用意した LILO の設定ファイルをカーネルと一緒にコピー します.両方ともルートディレクトリに置くことができます. cp bdlilo.conf KERNEL /mnt 以上の手順で,LILO が必要とするものは全てカーネルファイルシステムに準 備できましたので,LILO を実行します.LILO の -r オプションを使うと,ブ ートローダは他の場所をルートにしてインストールされます. lilo -v -C bdlilo.conf -r /mnt LILO はエラーを起こさないはずです.そして LILO の実行後には,カーネル ファイルシステムは以下のようになっているはずです: ______________________________________________________________________ total 361 1 -rw-r--r-- 1 root root 176 Jan 10 07:22 bdlilo.conf 1 drwxr-xr-x 2 root root 1024 Jan 10 07:23 boot/ 1 drwxr-xr-x 2 root root 1024 Jan 10 07:22 dev/ 358 -rw-r--r-- 1 root root 362707 Jan 10 07:23 vmlinuz boot: total 8 4 -rw-r--r-- 1 root root 3708 Jan 10 07:22 boot.b 4 -rw------- 1 root root 3584 Jan 10 07:23 map dev: total 0 0 brw-r----- 1 root root 2, 0 Jan 10 07:22 fd0 0 crw-r--r-- 1 root root 1, 3 Jan 10 07:22 null ______________________________________________________________________ ファイルサイズが少しくらい違っていても気にする必要はありません. ドライブからディスクを抜き, ``ramdisk 変数の設定''の節に進みましょ う. 6.2. LILO を使わないカーネルの転送 LILO を使わない場合には,dd コマンドを使ってカーネルをブートディスクに 転送します. % dd if=KERNEL of=/dev/fd0 bs=1k 353+1 records in 353+1 records out この例では,dd は 353 レコード(の全体)と1レコード(の一部)を書き込んで います.したがって,カーネルはディスク先頭の 354 ブロックを使っていま す.この数字を KERNEL_BLOCKS とします.これは次のセクションで使うの で,覚えておいてください. 最後に,ルートデバイスをフロッピーに設定し,ルートを読み書き可能でロー ドできるように設定します. rdev /dev/fd0 /dev/fd0 rdev -R /dev/fd0 0 後の方の rdev では必ず -R を大文字にしましょう. 6.3. ramdisk 変数の設定 カーネルイメージの ramdisk 変数にはルートファイルシステムの位置に関係 するオプション等が指定されています.この変数には rdev コマンドでアクセ スすることができ,変数の内容は以下のようになっています: 第 0-10ビット: RAM ディスク先頭位置へのオフセットアドレス. 1024 バイトのブロックが単位になります. 第11-13ビット: 未使用です. 第 14ビット: RAM ディスクをロードするかどうかのフラグです. 第 15 ビット: ルートファイルシステムをロードする前にフロッピー 交換のプロンプトを出すかどうかのフラグです. 第 15 ビットがセットされていると,ブート時に 2 枚目のフロッピーをドラ イブに入れるようにというプロンプトが出ます.ディスク 2 枚からなるブー トシステムではこのフラグが必要になります. 1枚のブート/ルートディスクを作るか,2枚組の「ブート+ルート」ディスクを 作るかによって,手順は2つに分かれます. 1. 1 枚のディスクで作る場合,圧縮形式のルートファイルシステムをカーネ ルの直後に置きます.つまり,オフセット位置は最初の空きブロックで す(これは KERNEL_BLOCKS に等しいはずです).第14ビットに1を, 第15ビットに0をセットします. 例えば,1 枚組のディスクを構築しようとしていて,ルートファイルシス テムをブロック 253 (10 進値)から始めようとしているとします.ramdisk 変数の値は 253 (10 進値)のはずであり,ビット 14 に 1 がセットされ, ビット 15 に 0 がセットされています.この値を計算するには,単に 10 進値を足し合わせてください.すなわち「253 + (2^14) = 253 + 16384 = 16637」です.この数値の由来が良く分からなければ,この値を関数電卓に 入れて 2 進値に変換してみてください. 2. 2 枚組のディスクを作る場合,ルートファイルシステムは 2 枚目のディス クの第 0 ブロックから始まります.つまり,オフセット位置は 0 です. 第 14, 15 ビットにはそれぞれ 1 をセットします.この場合,10 進値は 2^14 + 2^15 = 49152 となります. ramdisk 変数がしっかりと計算できたら,rdev -r コマンドを使って設定しま す.設定の際には 10 進数を使ってください.LILO を使っている場合に は,rdev に渡す引き数はマウントされるカーネルのパス(例: /mnt/vmlinuz)でなければなりません.カーネルを dd でコピーした場合は, この代わりにフロッピーのデバイス名(例: /dev/fd0) を使います. rdev -r KERNEL_OR_FLOPPY_DRIVE VALUE LILO を使っている場合には,フロッピーをアンマウントします. 6.4. ルートファイルシステムの転送 最後のステップはルートファイルシステムの転送です. o ルートファイルシステムをカーネルと同じディスクに置く場合, dd コマ ンドに seek オプションを付けてファイルシステムを転送します.このオ プションは先頭からスキップするブロック数を指定するものです. dd if=rootfs.gz of=/dev/fd0 bs=1k seek=KERNEL_BLOCKS o ルートファイルシステムを2番目のディスクに置く場合,最初のフロッピー を抜いて2番目のフロッピーを入れ,これにルートファイルシステムを転送 します. dd if=rootfs.gz of=/dev/fd0 bs=1k お疲れさま,これで作業終了です! 緊急用のディスクとして保管する前には必 ずテストをしましょう.このディスクで起動できなければ,トラブルシュー ティングがあるので,この先を読んでみましょう. 7. トラブルシューティング,または挫折の苦しみ ブートディスクを作ろうとする場合,最初の何回かが失敗するのはよくあるこ とです.ルートディスクを作成する際によく用いられる方針は,手持ちのシス テムから部品を取り出してフロッピーベースのシステムに詰め込み,コンソー ルにメッセージが出るまで試行錯誤を繰り返すことです.メッセージさえ出れ ば半分勝ったも同然です.後はシステムが文句を言わなくなるまで,一つ一つ 問題を解決していけばよいのです.システムが何のメッセージも出さずにハン グする場合は,その理由を調べるのは大変です.何とか表示が出る段階に達す るには,いくつかの部品がちゃんと揃っていて,正しく設定されている必要が あるのです.システムが何も言ってくれないような問題を見つけるためのお勧 めの手順を以下に示します: o 以下のようなメッセージが出力されるかもしれません: Kernel panic: VFS: Unable to mount root fs on XX:YY これはありがちな問題ですし,原因もごく限られています.まずデバイス XX:YY をデバイスコードのリストで確認してください.これが正しいルートデ バイスですか? 正しくなければ,rdev -R の実行を忘れたか,間違ったイメー ジに対して rdev -R を実行したと思われます.デバイスコードが正しけれ ば,次にデバイスドライバがカーネルに組み込まれているかどうかをしっかり 調べてください.フロッピーディスク,RAM ディスク,ext2 ファイルシステ ムのサポートがカーネルに組み込まれていることを確かめてください. o ルートディスクに意図したディレクトリが本当に含まれているか,しっか り確認します./bin でなく /rootdisk/bin のような間違ったディレクト リにコピーしてしまうということなどがありがちです. o /lib/libc.so があることと,/lib ディレクトリのリンクがハードディス クと同じになっていることを確認します. o 現在のシステムの /dev ディレクトリにおけるシンボリックリンクがルー トディスクのファイルシステムにも存在していることを確認します.また リンク先がちゃんとあることも確認します.特に /dev/console を忘れが ちなので気を付けてください. o ルートディスクに /dev/tty1, /dev/null, /dev/zero, /dev/mem, /dev/ram, /dev/kmem があることを確認します. o カーネルの設定を確認してください. ログインするまでに必要なシステム リソースのドライバが全て組み込まれているでしょうか(モジュールではだ め). RAM ディスクのドライバはカーネル組み込みでなければなりませ ん. o カーネルのルートデバイスと RAM ディスクの設定が正しいかどうか確認し ます. 以上のような一般的な点が確認できたら,次に示すようなファイルをチェック してみましょう: 1. init が /sbin/init または /bin/init として存在しており,実行可能に なっていることを確認する. 2. ldd init を実行して, init の使うライブラリを確認してください.通常 は libc.so だけでしょうが,それでもチェックしてください.必要なライ ブラリやローダがディスクに入っていることも確認します. 使っているライブラリに合ったローダがあることを確認します. a.out 形 式ならば ld.so ですし,ELF 形式ならば ld-linux.so です. 3. ブートディスクの /etc/inittab を見て, getty (あるいは agetty, mgetty, getty_ps 等の getty と同等のプログラム) の呼び出し方を調べ てください.と念入りに比べてください.ちゃんと意味を持った記述に なっているか,お使いのプログラムのマニュアルページも参照してくださ い.inittab はおそらく最も難しい部分です.なぜなら文法や内容が, 使っている init プログラムやシステムの作りによって変わってしまうか らです.inittab を正しく書くための手段はただ一つ,init と inittab のマニュアルページを読んで,現在のシステムがブート時にやっているこ とを解き明かすことです. /etc/inittab を見て,そこにシステムの初期 化を行っているエントリがあることを確認してください.このファイルに はシステム初期化のために実行するスクリプトが書かれているはずです. ここで指定されているファイルは存在していなければなりません. 4. init に行ったのと同じように, getty に対しても ldd を実行し,必要な ライブラリを表示させます.そしてそのライブラリのファイルとローダが ルートファイルシステムに入っていることを確認します. 5. rc スクリプトを全て実行できるシェルプログラム(例: bash や ash)があ ることを確認します. 6. レスキューディスクに /etc/ld.so.chace がすでに存在しているようでし たら,作り直してください. init が起動しても次のようなメッセージが出力されることがあります: Id xxx respawning too fast: disabled for 5 minutes これは init が出すもので,お使いの getty または login が起動してすぐに 異常終了したことを示しています. getty や login の実行ファイル,そして それらが依存しているライブラリをチェックしてください. ま た,/etc/inittab からの呼び出し方が正しいかどうかも調べてください. getty がおかしなメッセージを出力する場合は,おそらく /etc/inittab から の呼び出し方が間違っています.getty のオプションはプログラムによって違 います.また agetty ではバージョンによって互換性がない場合さえあるそう です. ログインプロンプトが現われ,正しいログイン名を入力したのに,即座に次の ログインプロンプトをシステムが出す場合には,PAM か NSS に問題があると 思われます.``PAM と NSS'' の節をご覧ください.シャドウパスワードを 使っているのに /etc/shadow をブートディスクにコピーしていない場合に も,この問題が出ることがあります. 何かの実行ファイル(例えば df)をレスキューディスクから起動したときに, df: not found のようなメッセージが出る場合には,次の 2 点を確認してく ださい: (1) バイナリがあるディレクトリが PATH に含まれているか. (2) プログラムが必要とするライブラリ(とローダ)があるか. 8. その他のトピックス 8.1. ファイルシステムのサイズの削減 ファイルシステムが大きすぎて,圧縮してもフロッピーに入らないことがあり ます.そこで,ファイルシステムのサイズを減らす方法をいくつか紹介しま す.有効なものから順に紹介します: ディスクの密度を上げる デフォルトでは,フロッピーディスクは 1440K でフォーマットされて います.しかし,もっと高い密度で使うこともできます.fdformat は 次のサイズでディスクをフォーマットできます: 1600, 1680, 1722, 1743, 1760, 1840, 1920. 1440K 対応ドライブの大部分は 1722K にも 対応しているので,筆者はいつもこのサイズをブートディスクで使って います.fdformat のマニュアルページと /usr/src/linux/Documentation/devices.txt を参照してください. シェルを変える Linux で良く使われるシェル(bash や tcsh 等)は大きい上に色々なラ イブラリを必要とします.これらの代用として使える ash, lsh, kiss , smash のような軽量のシェルがあります.これらは小さいですし,必 要なライブラリも少ないです(あるいは全くありません).このような シェルのほとんどは で入手できま す.ただし,このようなシェルを使う場合には,ブートディスクに組み 込んだ rc ファイルで実行するコマンドを全て実行できることを確認し ておいてください. ライブラリやバイナリをストリップする バイナリやライブラリの多くは普通はストリップされていません(つま り,デバッグ用のシンボルが含まれています).このようなファイルに 'file' を行うと 'not stripped' と表示されます.バイナリをルート ファイルシステムにコピーするときには,次のようにするとよいでしょ う: objcopy --strip-all FROM TO ライブラリをコピーするときには次のようにします: objcopy --strip-debug FROM TO 必須でないファイルをユーティリティディスクに移す ブートやログインには直接必要がないバイナリは,ユーティリティディ スクに移すことができます.詳しくは ``ユーティリティディスク作 成''の節をご覧ください.モジュールをユーティリティディスクに移す ことを考えてもよいかもしれません. 8.2. 非 RAM ディスクのルートファイルシステム ``ルートファイルシステム作成''の章では,圧縮形式のルートファイルシステ ムの作成方法を説明しました.これはシステムの起動時に ramkdisk へのロー ドを行うものです.この方法には利点が多いので,一般的に使われています. ですがシステムによっては,メモリが少なくて RAM ディスクを用意できない こともあります.このような場合には,フロッピーディスクから直接ルート ファイルシステムをマウントしなければなりません. 圧縮形式のファイルシステムを作るよりも,このようなファイルシステムを作 る方が実は簡単です.なぜなら,何か別のデバイスではなく直接フロッピー上 に作成することができるし,圧縮する必要もないからです.ここでは前の説明 との相違点の形で作成方法の概略を示します.この方法を使う場合には,使え る容量はずっと小さくなってしまう点を忘れないようにしましょう. 1. ルートに置くファイルに使える容量を計算します. 1枚のブート/ルートディスクを作る場合,カーネル分のブロックとルート ファイルシステム分のブロックが全て1枚のディスクに収まるようにしなけ ればなりません. 2. mke2fs を用い,適切なサイズのルートファイルシステムをフロッピー上に 作成します. 3. 先に述べた手順でファイルシステムを移します. 4. これが終わったら,ファイルシステムをアンマウントし,これをディスク のファイルに転送します.ただし圧縮してはいけません. 5. 先に述べた手順でカーネルをフロッピーに転送します.ramdisk 変数を求 めるときには,第14ビットは0にしてルートファイルシステムが RAM ディ スクにロードされないことを指示します.前に説明したように rdev を実 行します. 6. 先の説明と同じようにルートファイルシステムを転送します. もうちょっと簡単な方法もいくつかあります.2枚組のディスクセットを作る 場合,最終的なルートファイルシステムを直接2枚目のディスクに作れば,一 度ハードディスクのファイルに移してから再び書き戻す必要はありません.ま た,LILO を使って1枚のブート/ルートディスクを作る場合,ディスク全体を 1つのファイルシステムにし,カーネル,LILO 関連ファイル,ルートに置く ファイルを全て置くことができます.この場合も前に述べたように LILO を実 行するだけです. 8.3. ユーティリティディスクの作成 前の説明には,ユーティリティディスクは /usrにマウントすることができる と書きました.この場合にはバイナリをユーティリティディスクの /bin に置 きます.こうすると,パスを /usr/bin に通せばアクセスできるようになりま す.バイナリが必要とする追加のライブラリはユーティリティディスクの /lib に置きます. ユーティリティディスク作成の際には注意すべき点がいくつかあります: 1. システムに必須のバイナリやライブラリをユーティリティディスクに置い てはなりません.このディスクはシステムが起動するまではマウントする ことができないからです. 2. フロッピーディスクドライブとフロッピーテープドライブに同時にアクセ スすることはできません.つまりユーティリティディスクのマウント中 は,フロッピーテープドライブにはアクセスできないということです. 3. ユーティリティディスク上のファイルへのアクセスは遅くなります. ユーティリティディスクに置くファイルの例を,付録の ``ユーティリティ ディスクのサンプルのディレクトリ一覧'' に載せています.ここでは便利と 思われるものをいくつか挙げておきます: ディスクの検査・操作用のプログラ ム(format, fdisk),ファイルシステムの検査・操作用のプログラム(mke2fs, fsck, debugfs, isofs.o),軽量テキストエディタ(elvis, jove),圧縮・アー カイブのユーティリティ (gzip, tar, cpio, afio),テープ用ユーティリ ティ(mt, tob, taper),通信ユーティリティ(ppp.o, slip.o, minicom),デバ イス用のユーティリティ(setserial, mknod). 9. プロが使う方法 本文書で説明したブートディスクよりも,メジャーなディストリビューション (Slackware, RedHat, Debian 等)で使われているブートディスクの方がよくで きていることに読者の皆さんも気づかれるかもしれません.このようなディス トリビューションのブートディスクも基本的なところは同じなのですが,他に も色々なテクニックが使われています.というのも,このようなブートディス クには,必要条件がより多くあるからです.まず,このようなブートディスク は色々なハードウェアで動作しなければならないので,ユーザが指定した各種 デバイスドライバをロードできなければなりません.次に,色々なインストー ルオプションで動作しなければなりません (これはインストールの自動化の度 合いによって変わりますが).さらに,ディストリビューションのブートディ スクはインストールとレスキューの機能を合わせ持っています. ブートディスクによっては initrd (初期 RAM ディスク (initial ramdisk)) という機能を使っているものもあります.この機能はカーネル 2.0.x あたり で導入されたもので,2 つのフェーズに分けてカーネルを起動できるようにし ます.最初にカーネルを起動するとき, initrd は初期 RAM ディスクのイメ ージをブートディスクからロードします.この初期 RAM ディスクはルート ファイルシステムであり,実際のルートファイルシステムのロードの前に実行 するプログラムが入っています.通常,このプログラムはシステム環境を調べ たり,ユーザに起動オプション(実際のルートディスクをロードするデバイス 等)を問い合わせたりします.また initrd は,カーネルに組み込まれていな い追加モジュールのロードも行います.この初期プログラムが終了すると,カ ーネルは実際のルートイメージをロードして通常通りに起動を続行しま す.initrd に関する詳しい情報については, /usr/src/linux/Documentation/initrd.txtや を ご覧ください. 訳注: JF には initrd.txt の翻訳 があります.また, Ext-Rootfs-mini- HOWTO という関連文書があります. 以下では各ディストリビューションのインストールディスクがどのように動作 するのかを簡単に説明します.これはそれぞれのファイルシステムやソースコ ードを調べた結果に基づいたものです.この情報が正しい保証はありません し,本文書に書いてあるバージョン以降で変更されていない保証もありませ ん. Slackware (バージョン 3.1)は ``LILO を使ったカーネルの転送''の節で述べ たような,素直な方法を使っています.Slackware のブートディスクは LILO の message パラメータを使って,起動メッセージ (``Welcome to the Slackware Linux bootkernel disk!'')を表示します.このメッセージを使 い,ユーザの必要に応じて起動パラメータ行を入力させます.起動の後 に,2枚目のディスクからルートファイルシステムがロードされます.それか らユーザは setup スクリプトを実行して,インストールを開始しま す.Slackware では,カーネルをモジュール化しないで,色々な種類のカーネ ル(ブートディスク)を用意しています.ユーザは自分のハードウェアに合うも のを選択します. RedHat(バージョン 4.0)も LILO による起動を行います.LILO は圧縮形式の RAM ディスクを最初のディスクからロードし,この ramdisk でカスタマイズ された init プログラムが実行されます.このプログラムはドライバの問い合 わせを行い,それから必要に応じて追加ディスクから追加のファイルをロード します. Debian (バージョン 1.3)のインストールディスクは多分もっとも凝っている ものでしょう.このディスクは SYSLINUX というローダを使って各種ロードオ プションを整理し,initrd イメージを使ってインストールの間ユーザのガイ ドを行います.Debian ではカスタマイズした init とカスタマイズしたシェ ルを使っているようです. 10. FAQ(よくある質問)リスト Q. boot/root ディスクからブートさせたのですが,何も起こりません.どう すればよいでしょう? 本文書の``トラブルシューティング''の章をご覧ください. Q. Slackware や Debian, RedHat のブートディスクはどのようにして動いて いるのですか? ``プロが使う方法''の章をご覧ください. Q. XYZ ドライバが入ったブートディスクを作るには? 最も簡単な方法は Slackware のカーネルを最寄りの Slackware のミラーサイ トから取ってくることです. Slackware のカーネルは可能な限りたくさんの ドライバを詰め込んだ汎用のカーネルですから, SCSI か IDE のコントロー ラがすでに存在するなら,そのドライバが Slackware のカーネルに含まれて いる可能性は高いでしょう. 手持ちのコントローラに合うように a1 ディレクトリから IDE または SCSI のカーネルを選びます. xxxxkern.cfg ファイルを見て,選んだカーネルに必 要なドライバが含まれているかどうか確認してください.もし必要なデバイス がリストにあればそのカーネルであなたのコンピュータをブートできるはずで す. xxxxkern.tgz をダウンロードし,ブートディスクの作成方法の章で説明 したやり方でディスクにコピーしてください. 次に以下の rdev コマンドを実行してカーネルのルートデバイスを確認してく ださい: rdev zImage rdev は現在のカーネルに設定されているルートデバイスを表示します.もし 希望するデバイスと異なる場合は再び rdev を使って変更します.例えば私が 試したカーネルでは /dev/sda2 が設定されていましたが,私のルートになる SCSI パーティションは /dev/sda8 です. root ディスクを使うには,以下の コマンドを実行する必要があるでしょう. rdev zImage /dev/fd0 Slackware の root と同じようなディスクを作りたい,という質問はこの HOWTO の範囲を越えています. Linux Install Guide を見るか,実際に Slackware のパッケージを手に入れてください.入手方法はこの HOWTO の参 考文献の章に書いてあります. Q. カーネルを新しくしたらブートフロッピーはどのように変更すればよいで しょう? 新しいカーネルをブートさせるディスクにコピーするだけです.ブートディス クの場合は dd コマンドを, ブート/ルートディスクの場合は cp コマンドを 使います. ブートディスクの作成に関しては,``Boot'' の章を参照してくだ さい.ここに書いてある方法はブートディスクのカーネルを更新する場合にも 使えます. 訳注: ブート/ルートディスクの場合は LILO を実行しておく必要がありま す. Q. どうすればルートディスクのファイルを新しくできるでしょう? 最も楽な方法は,ファイルシステムをルートディスクから自分が使っているデ バイスにコピーすることです(前述の ``ファイルシステムの作成'' の節を参 照してください).次にファイルシステムをマウントし,変更を行います.こ のとき,ルートファイルシステムが始まる位置と使用するブロック数はメモし ておきましょう. dd if=/dev/fd0 bs=1k skip=ROOTBEGIN count=BLOCKS | gunzip > DEVICE mount -t ext2 DEVICE /mnt 変更が終わったら,前述(``仕上げ'' の節)の手順でルートファイルシステム をディスクに書き戻します.新しいルートファイルシステムの開始位置を変更 しない限り,カーネルの転送し直しや,ramdisk 変数の再計算の必要はありま せん. Q. DOS をブートさせるために LILO を削除したいのですが. 本当はブートディスクとは関係ない話なんですが,非常によく聞かれる質問で す.Linux では次のコマンドを実行してください: /sbin/lilo -u LILO が保存したバックアップを dd コマンドを使ってブートセクタにコピー することもできます.この方法については LILO の文書を参照してください. DOS や Windows では次のコマンドを使います: FDISK /MBR MBR は Master Boot Record の略です.このコマンドによってブートセクタが DOS のものに置き変わります.このときパーティションテーブルは変わりませ ん.この方法に反対するコチコチの Linux 教徒もいますが, LILO の作者で ある Werner Almesberger は賛成派です.簡単ですし,ちゃんと機能します. Q. カーネルもブートディスクもまとめて無くしてしまいました.どうしま しょう? ブートディスクを用意していなかった場合には,おそらく Slackware のカー ネルを利用するのが一番簡単でしょう.お使いのディスクコントローラのタイ プ(IDE か SCSI)に合う方を使ってください.内容に関しては「XYZ ドライバ が入ったブートディスクを作るには?」のQ&Aに書いてあります.このカーネル でコンピュータがブートできたら障害を直してください. 取ってきたカーネルでは,ルートデバイスが希望のディスクやパーティション になっていないかもしれません.例えば Slackware の SCSI カーネルではル ートのデバイスは /dev/sda2 になっています.しかし例えば私の Linux パー ティションは /dev/sda8 です.このような場合にはカーネルのルートデバイ ス設定を変更しなければなりません. Linux のシステムがなくても,カーネルのルートデバイスや RAM ディスクの 設定は変更することができます. DOS などの OS があれば OK です. rdev はカーネルファイルの決まったオフセットアドレスの部分の値を書き換 えています.ですから,どんなシステム上のものでもバイナリエディタさえあ れば同じことができます.例えば DOS なら,ノートンユーティリティのディ スクエディタなどが使えます.カーネルの以下のオフセットアドレスの値を調 べて,必要に応じて変更します: 16進 10進 説明 0x01F8 504 ramdisk 変数の下位バイト 0x01F9 505 ramdisk 変数の上位バイト 0x01FC 508 ルートデバイスのマイナー番号 -- 以下で説明します 0X01FD 509 ルートデバイスのメジャー番号 -- 以下で説明します ramdisk 変数の意味は ``ramdisk 変数の設定'' の節で既に説明しています. メジャー番号とマイナー番号はルートファイルシステムをマウントするデバイ スの番号にセットします.良く使われる番号を以下に挙げておきます: デバイス メジャー マイナー /dev/fd0 2 0 最初のフロッピードライブ /dev/hda1 3 1 最初の IDE ドライブのパーティション1 /dev/sda1 8 1 最初の SCSI ドライブのパーティション1 /dev/sda8 8 8 最初の SCSI ドライブのパーティション8 これらの値を設定したら,カーネルファイルをフロッピーに書き込みます.ノ ートンユーティリティのディスクエディタや, rawrite.exe と呼ばれる DOS コマンドが使えます.このプログラムはほとんどのディストリビューションに 入っています.ディスクを raw デバイスとみなしてブートセクタからファイ ルを書き込みます.ファイルシステムとしては扱いません.ノートンユーティ リティを使う場合にはファイルを物理ディスクの先頭から書き込む必要があり ます. Q. ブート/ルートディスクをコピーする方法を教えてください. 磁気メディアは経時劣化しますから,オリジナルが壊れたときのために予備の レスキューディスクを何枚か欲しいところです. ブートディスクやユーティリティのフロッピーをコピーする最も簡単な方法 は, dd コマンドを使ってオリジナルのフロッピーの内容をハードディスクの ファイルにコピーし,それをまた dd コマンドで別のフロッピーに書き戻すや り方です. dd コマンドは raw デバイスへの書き込みができますからフロッ ピーをマウントする必要はありません(逆にマウントしてはいけません). オリジナルをコピーするには次のコマンドを用います: dd if=DEVICENAME of=FILENAME ここで DEVICENAME はディスクドライブのデバイス名であり, FILENAME は(ハードディスク上の)出力ファイル名です このように count パラメータを省略すると,ディスク全体である2880 ブロッ ク(高密度フロッピーの場合)がコピーされます. 一時ファイルを新しいフロッピーに書き戻すには,新しいフロッピーを入れて 次のコマンドを実行します: dd if=FILENAME of=DEVICENAME ここまで述べてきた内容はフロッピードライブがひとつしかない場合です.も し同じドライブが 2 つある場合には,次のようなコマンドを使えば直接フ ロッピー間でコピーができます: dd if=/dev/fd0 of=/dev/fd1 Q. ブートのたびに "ahaxxxx=nn,nn,nn" と打ち込むのは面倒です. 例えば SCSI デバイスが自動的に検出されないような場合には,カーネルに以 下のようなパラメータ文字列を与えてやる必要があります: aha152x=0x340,11,3,1 LILO を用いてこのパラメータ文字列をカーネルに渡すにはいくつかの方法が あります: o システムが LILO によって起動されるたびにコマンドラインからパラメー タを打ち込む.しかしこれは面倒なんですよね? o LILO の ``lock'' キーワードを用いて,コマンドラインから打ち込んだパ ラメータをデフォルトにする.次からのブートでは LILO は毎回同じオプ ションを使うようになります. o LILO の設定ファイルで append= 宣言を使う.パラメータ文字列は引用符 で囲む必要があることに注意してください. コマンドラインからパラメータ文字列を打ち込む場合は以下のようになるで しょう: zImage aha152x=0x340,11,3,1 root=/dev/sda1 lock これはデバイスのパラメータ文字列を渡し,カーネルにルートデバイスを /dev/sda1 にするよう指示し,さらにこのコマンドライン全体を保存して次か らのブートで再び用いるようにしています. APPEND 宣言の例を以下に示します: APPEND = "aha152x=0x340,11,3,1" コマンドラインではパラメータ文字列は引用符で囲ってはいけません.逆に APPEND 宣言では引用符で囲わなければいけません.間違えないように. パラメータ文字列を機能させるにはカーネルにドライバが含まれていなければ なりません.含まれていなければそもそもパラメータを受け取るものがないの ですから,必要なドライバを含んだカーネルを再構築する必要があります.カ ーネル再構築の詳細については /usr/src/linux ディレクトリの README や, Linux FAQ, Installation HOWTO などをお読みください.または必要なドラ イバを含んだ汎用のカーネルを手に入れ,それを使ってください. LILO をインストールする前に LILO の付属文書を読んでおくことを強くお薦 めします.不用意に BOOT 宣言を使うと,パーティションを壊すこともありえ ます. Q. ブート時に A: cannot execute B といったエラーが出ます. あるユーティリティが他のプログラムを起動する場合,そのプログラムの名前 がユーティリティの内部にハードコードされていることがあります.このよう な場合は,実際にプログラムがあってもユーティリティには見えないというこ とが起こります. strings コマンドを用いた出力をパイプで grep につなげ ば,問題を起こすユーティリティがどんな名前で他のプログラムを使っている かがわかります. ハードコードの例として以下のようなものが知られています: o 特定のバージョンの shutdown は /etc/reboot を直接プログラム中に書い ています.従って reboot は /etc に置く必要があります. o カーネルが init を見付けられないという問題が起こったことがありま す. これらの問題を解決するにはプログラムを正しいディレクトリに移動するか, もしくは inittab のような設定ファイルの方を変更する必要があります.も し疑わしい場合には現在ハードディスクで使っているのと同じディレクトリ構 成, inittab, /etc/rc.d を使ってみることです. Q. 私のカーネルは RAM ディスク機能をサポートしているのに RAM ディスク のサイズが 0K になってしまいます. このようなことが起こる場合は,カーネルの起動時に次のようなメッセージが 表示されます: Ramdisk driver initialized : 16 ramdisks of 0K size これはおそらくブート時にこのサイズがカーネルパラメータで 0 に設定され ているためでしょう. LILO の設定ファイルに以下のような行がありません か? ramdisk= 0 古いディストリビューションの一部では LILO の設定ファイルのサンプルにこ の行が入っていることがあります.この行はカーネルでの設定より優先されて しまいます.このような行があれば削除しましょう. サイズ 0 の RAM ディスクを使用した場合の結果は予測できません.カーネル パニックが起こることもありえます. A. 関連情報 パッケージを入手するときには,特別な理由がない限りはできるだけ新しいも のを入手しましょう. A.1. 既製のブートディスクの入手 ここで挙げるのはディストリビューションのブートディスクの配布元です.マ シンに負荷をかけないために,ミラーサイトを使うようにしましょう. o Slackware のブートディスク , ルートディスク , Slackware のミラーサイト o RedHat のブートディスク ,RedHat のミラーサイト o Debian のブートディスク , Debian のミラーサイト ディストリビューションのブートディスク以外にも,以下のようなレスキュー ディスクのイメージが入手可能です.特に指定しない限りは ディレ クトリにあります. o tomsrtbt, 作者は Tom Oehser さん.カーネル 2.0 ベースの 1 枚のブー ト/ルートディスク.たくさんの機能とサポートプログラムが付いていま す.IDE, SCSI, テープ,ネットワークカード,PCMCIA 等をサポート. ディスクの修復とデータ書き戻しのためのユーティリティプログラムが約 100 個入っている.このパッケージには,必要に応じて新しいものを追加 できるように,イメージの分解と再構成のためのスクリプトも入ってい る. o rescue02, 作者は John Comyns さん.カーネル 1.3.86 ベースのレスキュ ーディスク.IDE, Adaptec 1542, NCR53C7,8xx をサポート.ELF バイナリ を使っているが,どんなシステムにでも使えるだけのコマンドが入ってい る.他の SCSI カードのサポート用に起動後にロードできるモジュールが ある.RAM ディスクが 3M 必要なので,メモリが 4M のマシンでは動作し ないと思われる. o resque_disk-2.0.22, 作者は Sergei Viznyuk さん.必要な機能が全部 揃っている,カーネル 2.0.22 ベースの1枚のブート/ルートディスク.IDE と多数の SCSI コントローラ,ELF, a.out を組み込んである.多数のモ ジュールや,ディスク修復・データ復旧用のユーティリティが入ってい る. o cramdisk イメージ,カーネル 2.0.33 ベース.メモリが 4M や 8M のマシ ンでも利用可能.math エミュレーションとネットワーク(PPP, dialin ス クリプト,NE2000, 3C509),パラレルポート用 ZIP ドライブをサポート. このディスクイメージは RAM が 4M の 386 も起動できる.ネットワーク から DOS パーティションまでダウンロードに利用できるように,MSDOS サ ポートも入っている. A.2. レスキューパッケージ レスキューディスクを作るためのパッケージは metalab.unc.edu でいくつか 入手することができます.こうしたパッケージを使うと,入れるファイルを セットでまとめて指定したり,ブートディスクの作成を(程度はいろいろあり ますが)ソフトウェアで自動化することができます.詳しくは をご覧 ください.ファイルの日付はよく確認してください.というのも,一部のパッ ケージは何年間も更新されておらず,RAM ディスクにロードする圧縮形式のル ートファイルシステムの作成もサポートしていません.筆者が知る限りでは, このような古いパッケージは Yard だけですが. A.3. Graham Chapman さんのシェルスクリプト Graham Chapman さんはブートディスクの作り方の例として,便利なスクリプ トのセットを作成しています.この HOWTO の前のバージョンではこのスクリ プトを付録として入れていましたが,現在は文書に載せるのはやめてウェブペ ージに置いています: このスクリプトを使えば便利さが分かると思いますが,説明はよく読んでくだ さい.例えば,スワップデバイスを間違えて指定すると,ルートファイルシス テムが跡形もなく消去されてしまいます.使う前にはちゃんと設定されている か確かめましょう. A.4. LILO -- Linux ローダ 作者は Werner Almesberger さんです.優れたブートローダですし,ドキュメ ントにはブートセクタの内容やブートプロセスの初期段階に関する情報が書か れています. から ftp で入手するこ とができます.metalab やそのミラーからも入手することができます. A.5. Linux FAQ と HOWTO 文書 色々なところに置いてあります. usenet のニュースグループ news.answers や comp.os.linux.answers を見てください. FAQ は で入手できます し,HOWTO 文書は で入手で きます. Linux 関連の文書のほとんどは Linux Documentation Project のホ ームページ で入手できます. A.6. RAM ディスクの使い方 新しくなった RAM ディスクの動作に関する優れた文書が Linux カーネルに付 属しています. /usr/src/linux/Documentation/ramdisk.txt を見てくださ い.これは Paul Gortmaker さんが書いたもので,圧縮ファイルシステムの作 り方が書いてあります. A.7. Linux のブートプロセス Linux のブートプロセスの関する情報へのポインタをいくつか示しておきま す: o 「The Linux System Administrators' Guide」にはブートについての章が あります. をご覧くださ い. o LILO の ``Technical overview'' は,カーネルがスタートするまでのブートプロセスを下位レベルから記述 した技術的文書として,非常に優れたものです. o ソースコードは究極のガイドです.ブートに関連するカーネルのファイル をいくつか挙げます.Linux カーネルのソースコードを持っていれば,マ シンの /usr/src/linux にあると思います.これ以外にも, Shigio Yamaguchi さん(shigio@tamacom.com) が作成された素晴らしいハイパーテ キストカーネルブラウザが にあります.以下に関 連ファイルを示します: arch/i386/boot/bootsect.S,setup.S ブートセクタに関するアセンブリコードがある. arch/i386/boot/compressed/misc.c 圧縮されたカーネルの展開に関するコードがある. arch/i386/kernel/ カーネルの初期化のコードがある.setup.c に ramdisk 変数がある. drivers/block/rd.c RAM ディスクドライバがある.rd_load 手続きと rd_load_image 手続 きはデバイスから RAM ディスクにブロックをロードす る.identify_ramdisk_image はファイルシステムの種類を判別し,展 開するかどうかを決める. B. LILO のブート時のエラーコード Usenet でも LILO に関する質問が多いので,公的なサービスのつもりで説明 を入れました.この説明は Werner Almsberger さんが書いた LILO のユーザ 向け文書から抜粋したものです.この文書は で 入手できます. LILO 自身のロードが終了すると,``LILO'' と表示されます.それぞれの文字 は何らかの操作を行う前後に表示されます.どこかで LILO が止まった場合, それまでに表示された文字を見れば問題点がわかります. (空) LILO は全くロードされていません.原因は LILO がインストールされ ていないか,ブートセクタが参照されているパーティションがアクティ ブでないかのどちらかでしょう. L 最初のステージのブートローダはロード・起動されましたが,2 番目の ステージのブートローダがロードできませんでした.2桁のエラーコー ドが表示されるので問題の種類がわかります.(``Disk error codes'' の章をご覧ください.) この状態の場合は通常,メディア異常かジオメ トリの不一致 (例: ディスクのパラメータの誤り)が起こっています. LI 最初のステージのブートローダが2番目のステージのブートローダをロ ードすることはできましたが,実行させることはできませんでした.こ の原因は,ジオメトリの不一致か /boot/boot.b を動かしたのにマップ インストーラを実行しなかったのかのどちらかでしょう. LIL 2番目のステージのブートローダは起動されましたが,マップファイル から記述テーブルを読み出すことができませんでした.この原因は普 通,メディアの異常かジオメトリの不一致のどちらかです. LIL? 2番目のステージのブートローダが間違ったアドレスで起動されまし た.この原因は通常,ジオメトリが微妙にずれているか, /boot/boot.b を動かしたのにマップインストーラを実行しなかったか です. LIL- 記述テーブルが壊れています.この原因はジオメトリの不一致 か,/boot/boot.b を動かしたのにマップインストーラを実行しなかっ たかです. LILO LILO の全ての部分を正常にロードできました. LILO がブートイメージをロードしようとした時に BIOS がエラーを出した場 合,それに対応するエラーコードが表示されます.このエラーコードの範囲は 0x00 から 0xbb です.その内容については LILO のユーザガイドを参照して ください. C. ルートディスクのサンプルのディレクトリ一覧 ルートファイルシステムとユーティリティディスクのサンプルの内容を示しま す: ルートディレクトリ: drwx--x--x 2 root root 1024 Nov 1 15:39 bin drwx--x--x 2 root root 4096 Nov 1 15:39 dev drwx--x--x 3 root root 1024 Nov 1 15:39 etc drwx--x--x 4 root root 1024 Nov 1 15:39 lib drwx--x--x 5 root root 1024 Nov 1 15:39 mnt drwx--x--x 2 root root 1024 Nov 1 15:39 proc drwx--x--x 2 root root 1024 Nov 1 15:39 root drwx--x--x 2 root root 1024 Nov 1 15:39 sbin drwx--x--x 2 root root 1024 Nov 1 15:39 tmp drwx--x--x 7 root root 1024 Nov 1 15:39 usr drwx--x--x 5 root root 1024 Nov 1 15:39 var /bin: -rwx--x--x 1 root root 62660 Nov 1 15:39 ash -rwx--x--x 1 root root 9032 Nov 1 15:39 cat -rwx--x--x 1 root root 10276 Nov 1 15:39 chmod -rwx--x--x 1 root root 9592 Nov 1 15:39 chown -rwx--x--x 1 root root 23124 Nov 1 15:39 cp -rwx--x--x 1 root root 23028 Nov 1 15:39 date -rwx--x--x 1 root root 14052 Nov 1 15:39 dd -rwx--x--x 1 root root 14144 Nov 1 15:39 df -rwx--x--x 1 root root 69444 Nov 1 15:39 egrep -rwx--x--x 1 root root 395 Nov 1 15:39 false -rwx--x--x 1 root root 69444 Nov 1 15:39 fgrep -rwx--x--x 1 root root 69444 Nov 1 15:39 grep -rwx--x--x 3 root root 45436 Nov 1 15:39 gunzip -rwx--x--x 3 root root 45436 Nov 1 15:39 gzip -rwx--x--x 1 root root 8008 Nov 1 15:39 hostname -rwx--x--x 1 root root 12736 Nov 1 15:39 ln -rws--x--x 1 root root 15284 Nov 1 15:39 login -rwx--x--x 1 root root 29308 Nov 1 15:39 ls -rwx--x--x 1 root root 8268 Nov 1 15:39 mkdir -rwx--x--x 1 root root 8920 Nov 1 15:39 mknod -rwx--x--x 1 root root 24836 Nov 1 15:39 more -rws--x--x 1 root root 37640 Nov 1 15:39 mount -rwx--x--x 1 root root 12240 Nov 1 15:39 mt -rwx--x--x 1 root root 12932 Nov 1 15:39 mv -r-x--x--x 1 root root 12324 Nov 1 15:39 ps -rwx--x--x 1 root root 5388 Nov 1 15:39 pwd -rwx--x--x 1 root root 10092 Nov 1 15:39 rm lrwxrwxrwx 1 root root 3 Nov 1 15:39 sh -> ash -rwx--x--x 1 root root 25296 Nov 1 15:39 stty -rws--x--x 1 root root 12648 Nov 1 15:39 su -rwx--x--x 1 root root 4444 Nov 1 15:39 sync -rwx--x--x 1 root root 110668 Nov 1 15:39 tar -rwx--x--x 1 root root 19712 Nov 1 15:39 touch -rwx--x--x 1 root root 395 Nov 1 15:39 true -rws--x--x 1 root root 19084 Nov 1 15:39 umount -rwx--x--x 1 root root 5368 Nov 1 15:39 uname -rwx--x--x 3 root root 45436 Nov 1 15:39 zcat /dev: lrwxrwxrwx 1 root root 6 Nov 1 15:39 cdrom -> cdu31a brw-rw-r-- 1 root root 15, 0 May 5 1998 cdu31a crw------- 1 root root 4, 0 Nov 1 15:29 console crw-rw-rw- 1 root uucp 5, 64 Sep 9 19:46 cua0 crw-rw-rw- 1 root uucp 5, 65 May 5 1998 cua1 crw-rw-rw- 1 root uucp 5, 66 May 5 1998 cua2 crw-rw-rw- 1 root uucp 5, 67 May 5 1998 cua3 brw-rw---- 1 root floppy 2, 0 Aug 8 13:54 fd0 brw-rw---- 1 root floppy 2, 36 Aug 8 13:54 fd0CompaQ brw-rw---- 1 root floppy 2, 84 Aug 8 13:55 fd0D1040 brw-rw---- 1 root floppy 2, 88 Aug 8 13:55 fd0D1120 brw-rw---- 1 root floppy 2, 12 Aug 8 13:54 fd0D360 brw-rw---- 1 root floppy 2, 16 Aug 8 13:54 fd0D720 brw-rw---- 1 root floppy 2, 120 Aug 8 13:55 fd0D800 brw-rw---- 1 root floppy 2, 32 Aug 8 13:54 fd0E2880 brw-rw---- 1 root floppy 2, 104 Aug 8 13:55 fd0E3200 brw-rw---- 1 root floppy 2, 108 Aug 8 13:55 fd0E3520 brw-rw---- 1 root floppy 2, 112 Aug 8 13:55 fd0E3840 brw-rw---- 1 root floppy 2, 28 Aug 8 13:54 fd0H1440 brw-rw---- 1 root floppy 2, 124 Aug 8 13:55 fd0H1600 brw-rw---- 1 root floppy 2, 44 Aug 8 13:55 fd0H1680 brw-rw---- 1 root floppy 2, 60 Aug 8 13:55 fd0H1722 brw-rw---- 1 root floppy 2, 76 Aug 8 13:55 fd0H1743 brw-rw---- 1 root floppy 2, 96 Aug 8 13:55 fd0H1760 brw-rw---- 1 root floppy 2, 116 Aug 8 13:55 fd0H1840 brw-rw---- 1 root floppy 2, 100 Aug 8 13:55 fd0H1920 lrwxrwxrwx 1 root root 7 Nov 1 15:39 fd0H360 -> fd0D360 lrwxrwxrwx 1 root root 7 Nov 1 15:39 fd0H720 -> fd0D720 brw-rw---- 1 root floppy 2, 52 Aug 8 13:55 fd0H820 brw-rw---- 1 root floppy 2, 68 Aug 8 13:55 fd0H830 brw-rw---- 1 root floppy 2, 4 Aug 8 13:54 fd0d360 brw-rw---- 1 root floppy 2, 8 Aug 8 13:54 fd0h1200 brw-rw---- 1 root floppy 2, 40 Aug 8 13:54 fd0h1440 brw-rw---- 1 root floppy 2, 56 Aug 8 13:55 fd0h1476 brw-rw---- 1 root floppy 2, 72 Aug 8 13:55 fd0h1494 brw-rw---- 1 root floppy 2, 92 Aug 8 13:55 fd0h1600 brw-rw---- 1 root floppy 2, 20 Aug 8 13:54 fd0h360 brw-rw---- 1 root floppy 2, 48 Aug 8 13:55 fd0h410 brw-rw---- 1 root floppy 2, 64 Aug 8 13:55 fd0h420 brw-rw---- 1 root floppy 2, 24 Aug 8 13:54 fd0h720 brw-rw---- 1 root floppy 2, 80 Aug 8 13:55 fd0h880 brw-rw---- 1 root disk 3, 0 May 5 1998 hda brw-rw---- 1 root disk 3, 1 May 5 1998 hda1 brw-rw---- 1 root disk 3, 2 May 5 1998 hda2 brw-rw---- 1 root disk 3, 3 May 5 1998 hda3 brw-rw---- 1 root disk 3, 4 May 5 1998 hda4 brw-rw---- 1 root disk 3, 5 May 5 1998 hda5 brw-rw---- 1 root disk 3, 6 May 5 1998 hda6 brw-rw---- 1 root disk 3, 64 May 5 1998 hdb brw-rw---- 1 root disk 3, 65 May 5 1998 hdb1 brw-rw---- 1 root disk 3, 66 May 5 1998 hdb2 brw-rw---- 1 root disk 3, 67 May 5 1998 hdb3 brw-rw---- 1 root disk 3, 68 May 5 1998 hdb4 brw-rw---- 1 root disk 3, 69 May 5 1998 hdb5 brw-rw---- 1 root disk 3, 70 May 5 1998 hdb6 crw-r----- 1 root kmem 1, 2 May 5 1998 kmem crw-r----- 1 root kmem 1, 1 May 5 1998 mem lrwxrwxrwx 1 root root 12 Nov 1 15:39 modem -> ../dev/ttyS1 lrwxrwxrwx 1 root root 12 Nov 1 15:39 mouse -> ../dev/psaux crw-rw-rw- 1 root root 1, 3 May 5 1998 null crwxrwxrwx 1 root root 10, 1 Oct 5 20:22 psaux brw-r----- 1 root disk 1, 1 May 5 1998 ram brw-rw---- 1 root disk 1, 0 May 5 1998 ram0 brw-rw---- 1 root disk 1, 1 May 5 1998 ram1 brw-rw---- 1 root disk 1, 2 May 5 1998 ram2 brw-rw---- 1 root disk 1, 3 May 5 1998 ram3 brw-rw---- 1 root disk 1, 4 May 5 1998 ram4 brw-rw---- 1 root disk 1, 5 May 5 1998 ram5 brw-rw---- 1 root disk 1, 6 May 5 1998 ram6 brw-rw---- 1 root disk 1, 7 May 5 1998 ram7 brw-rw---- 1 root disk 1, 8 May 5 1998 ram8 brw-rw---- 1 root disk 1, 9 May 5 1998 ram9 lrwxrwxrwx 1 root root 4 Nov 1 15:39 ramdisk -> ram0 *** 筆者が使っている IDE パーティション用のデバイスだけを入れています. *** SCSI を使う場合には,代わりに /dev/sdXX デバイスを使います. crw------- 1 root root 4, 0 May 5 1998 tty0 crw--w---- 1 root tty 4, 1 Nov 1 15:39 tty1 crw------- 1 root root 4, 2 Nov 1 15:29 tty2 crw------- 1 root root 4, 3 Nov 1 15:29 tty3 crw------- 1 root root 4, 4 Nov 1 15:29 tty4 crw------- 1 root root 4, 5 Nov 1 15:29 tty5 crw------- 1 root root 4, 6 Nov 1 15:29 tty6 crw------- 1 root root 4, 7 May 5 1998 tty7 crw------- 1 root tty 4, 8 May 5 1998 tty8 crw------- 1 root tty 4, 9 May 8 12:57 tty9 crw-rw-rw- 1 root root 4, 65 Nov 1 12:17 ttyS1 crw-rw-rw- 1 root root 1, 5 May 5 1998 zero /etc: -rw------- 1 root root 164 Nov 1 15:39 conf.modules -rw------- 1 root root 668 Nov 1 15:39 fstab -rw------- 1 root root 71 Nov 1 15:39 gettydefs -rw------- 1 root root 389 Nov 1 15:39 group -rw------- 1 root root 413 Nov 1 15:39 inittab -rw------- 1 root root 65 Nov 1 15:39 issue -rw-r--r-- 1 root root 746 Nov 1 15:39 ld.so.cache *** ld.so.cache は ldconfig が生成するファイルで,ライブラリの位置をキャッ *** シュします.起動時に ld.so.cache が無いと動かないものはたくさんあ *** ります.ブートディスクを作った後に ld.so.cache を作り直すか,ブー *** トディスクに ldconfig を入れ,rc.x スクリプトから ldconfig を実行 *** してキャッシュを更新しましょう. -rw------- 1 root root 32 Nov 1 15:39 motd -rw------- 1 root root 949 Nov 1 15:39 nsswitch.conf drwx--x--x 2 root root 1024 Nov 1 15:39 pam.d -rw------- 1 root root 139 Nov 1 15:39 passwd -rw------- 1 root root 516 Nov 1 15:39 profile -rwx--x--x 1 root root 387 Nov 1 15:39 rc -rw------- 1 root root 55 Nov 1 15:39 shells -rw------- 1 root root 774 Nov 1 15:39 termcap -rw------- 1 root root 78 Nov 1 15:39 ttytype lrwxrwxrwx 1 root root 15 Nov 1 15:39 utmp -> ../var/run/utmp lrwxrwxrwx 1 root root 15 Nov 1 15:39 wtmp -> ../var/log/wtmp /etc/pam.d: -rw------- 1 root root 356 Nov 1 15:39 other /lib: *** 筆者のシステムは glibc を使った ELF システムなので,ld-2.so ローダ *** が必要です. -rwxr-xr-x 1 root root 45415 Nov 1 15:39 ld-2.0.7.so lrwxrwxrwx 1 root root 11 Nov 1 15:39 ld-linux.so.2 -> ld-2.0.7.so -rwxr-xr-x 1 root root 731548 Nov 1 15:39 libc-2.0.7.so lrwxrwxrwx 1 root root 13 Nov 1 15:39 libc.so.6 -> libc-2.0.7.so lrwxrwxrwx 1 root root 17 Nov 1 15:39 libcom_err.so.2 -> libcom_err.so.2.0 -rwxr-xr-x 1 root root 6209 Nov 1 15:39 libcom_err.so.2.0 -rwxr-xr-x 1 root root 153881 Nov 1 15:39 libcrypt-2.0.7.so lrwxrwxrwx 1 root root 17 Nov 1 15:39 libcrypt.so.1 -> libcrypt-2.0.7.so -rwxr-xr-x 1 root root 12962 Nov 1 15:39 libdl-2.0.7.so lrwxrwxrwx 1 root root 14 Nov 1 15:39 libdl.so.2 -> libdl-2.0.7.so lrwxrwxrwx 1 root root 16 Nov 1 15:39 libext2fs.so.2 -> libext2fs.so.2.4 -rwxr-xr-x 1 root root 81382 Nov 1 15:39 libext2fs.so.2.4 -rwxr-xr-x 1 root root 25222 Nov 1 15:39 libnsl-2.0.7.so lrwxrwxrwx 1 root root 15 Nov 1 15:39 libnsl.so.1 -> libnsl-2.0.7.so -rwx--x--x 1 root root 178336 Nov 1 15:39 libnss_files-2.0.7.so lrwxrwxrwx 1 root root 21 Nov 1 15:39 libnss_files.so.1 -> libnss_files-2.0.7.so lrwxrwxrwx 1 root root 14 Nov 1 15:39 libpam.so.0 -> libpam.so.0.64 -rwxr-xr-x 1 root root 26906 Nov 1 15:39 libpam.so.0.64 lrwxrwxrwx 1 root root 19 Nov 1 15:39 libpam_misc.so.0 -> libpam_misc.so.0.64 -rwxr-xr-x 1 root root 7086 Nov 1 15:39 libpam_misc.so.0.64 -r-xr-xr-x 1 root root 35615 Nov 1 15:39 libproc.so.1.2.6 lrwxrwxrwx 1 root root 15 Nov 1 15:39 libpwdb.so.0 -> libpwdb.so.0.54 -rw-r--r-- 1 root root 121899 Nov 1 15:39 libpwdb.so.0.54 lrwxrwxrwx 1 root root 19 Nov 1 15:39 libtermcap.so.2 -> libtermcap.so.2.0.8 -rwxr-xr-x 1 root root 12041 Nov 1 15:39 libtermcap.so.2.0.8 -rwxr-xr-x 1 root root 12874 Nov 1 15:39 libutil-2.0.7.so lrwxrwxrwx 1 root root 16 Nov 1 15:39 libutil.so.1 -> libutil-2.0.7.so lrwxrwxrwx 1 root root 14 Nov 1 15:39 libuuid.so.1 -> libuuid.so.1.1 -rwxr-xr-x 1 root root 8039 Nov 1 15:39 libuuid.so.1.1 drwx--x--x 3 root root 1024 Nov 1 15:39 modules drwx--x--x 2 root root 1024 Nov 1 15:39 security /lib/modules: drwx--x--x 4 root root 1024 Nov 1 15:39 2.0.35 /lib/modules/2.0.35: drwx--x--x 2 root root 1024 Nov 1 15:39 block drwx--x--x 2 root root 1024 Nov 1 15:39 cdrom /lib/modules/2.0.35/block: -rw------- 1 root root 7156 Nov 1 15:39 loop.o /lib/modules/2.0.35/cdrom: -rw------- 1 root root 24108 Nov 1 15:39 cdu31a.o /lib/security: -rwx--x--x 1 root root 8771 Nov 1 15:39 pam_permit.so マウント用のディレクトリスタブ /mnt: drwx--x--x 2 root root 1024 Nov 1 15:39 SparQ drwx--x--x 2 root root 1024 Nov 1 15:39 cdrom drwx--x--x 2 root root 1024 Nov 1 15:39 floppy /proc: /root: -rw------- 1 root root 176 Nov 1 15:39 .bashrc -rw------- 1 root root 182 Nov 1 15:39 .cshrc -rw------- 1 root root 47 Nov 1 15:39 .glintrc -rwx--x--x 1 root root 455 Nov 1 15:39 .profile -rw------- 1 root root 4014 Nov 1 15:39 .tcshrc /sbin: -rwx--x--x 1 root root 23976 Nov 1 15:39 depmod -rwx--x--x 2 root root 274600 Nov 1 15:39 e2fsck -rwx--x--x 1 root root 41268 Nov 1 15:39 fdisk -rwx--x--x 1 root root 9396 Nov 1 15:39 fsck -rwx--x--x 2 root root 274600 Nov 1 15:39 fsck.ext2 -rwx--x--x 1 root root 29556 Nov 1 15:39 getty -rwx--x--x 1 root root 6620 Nov 1 15:39 halt -rwx--x--x 1 root root 23116 Nov 1 15:39 init -rwx--x--x 1 root root 25612 Nov 1 15:39 insmod -rwx--x--x 1 root root 10368 Nov 1 15:39 kerneld -rwx--x--x 1 root root 110400 Nov 1 15:39 ldconfig -rwx--x--x 1 root root 6108 Nov 1 15:39 lsmod -rwx--x--x 2 root root 17400 Nov 1 15:39 mke2fs -rwx--x--x 1 root root 4072 Nov 1 15:39 mkfs -rwx--x--x 2 root root 17400 Nov 1 15:39 mkfs.ext2 -rwx--x--x 1 root root 5664 Nov 1 15:39 mkswap -rwx--x--x 1 root root 22032 Nov 1 15:39 modprobe lrwxrwxrwx 1 root root 4 Nov 1 15:39 reboot -> halt -rwx--x--x 1 root root 7492 Nov 1 15:39 rmmod -rwx--x--x 1 root root 12932 Nov 1 15:39 shutdown lrwxrwxrwx 1 root root 6 Nov 1 15:39 swapoff -> swapon -rwx--x--x 1 root root 5124 Nov 1 15:39 swapon lrwxrwxrwx 1 root root 4 Nov 1 15:39 telinit -> init -rwx--x--x 1 root root 6944 Nov 1 15:39 update /tmp: /usr: drwx--x--x 2 root root 1024 Nov 1 15:39 bin drwx--x--x 2 root root 1024 Nov 1 15:39 lib drwx--x--x 3 root root 1024 Nov 1 15:39 man drwx--x--x 2 root root 1024 Nov 1 15:39 sbin drwx--x--x 3 root root 1024 Nov 1 15:39 share lrwxrwxrwx 1 root root 10 Nov 1 15:39 tmp -> ../var/tmp /usr/bin: -rwx--x--x 1 root root 37164 Nov 1 15:39 afio -rwx--x--x 1 root root 5044 Nov 1 15:39 chroot -rwx--x--x 1 root root 10656 Nov 1 15:39 cut -rwx--x--x 1 root root 63652 Nov 1 15:39 diff -rwx--x--x 1 root root 12972 Nov 1 15:39 du -rwx--x--x 1 root root 56552 Nov 1 15:39 find -r-x--x--x 1 root root 6280 Nov 1 15:39 free -rwx--x--x 1 root root 7680 Nov 1 15:39 head -rwx--x--x 1 root root 8504 Nov 1 15:39 id -r-sr-xr-x 1 root bin 4200 Nov 1 15:39 passwd -rwx--x--x 1 root root 14856 Nov 1 15:39 tail -rwx--x--x 1 root root 19008 Nov 1 15:39 tr -rwx--x--x 1 root root 7160 Nov 1 15:39 wc -rwx--x--x 1 root root 4412 Nov 1 15:39 whoami /usr/lib: lrwxrwxrwx 1 root root 17 Nov 1 15:39 libncurses.so.4 -> libncurses.so.4.2 -rw-r--r-- 1 root root 260474 Nov 1 15:39 libncurses.so.4.2 /usr/sbin: -r-x--x--x 1 root root 13684 Nov 1 15:39 fuser -rwx--x--x 1 root root 3876 Nov 1 15:39 mklost+found /usr/share: drwx--x--x 4 root root 1024 Nov 1 15:39 terminfo /usr/share/terminfo: drwx--x--x 2 root root 1024 Nov 1 15:39 l drwx--x--x 2 root root 1024 Nov 1 15:39 v /usr/share/terminfo/l: -rw------- 1 root root 1552 Nov 1 15:39 linux -rw------- 1 root root 1516 Nov 1 15:39 linux-m -rw------- 1 root root 1583 Nov 1 15:39 linux-nic /usr/share/terminfo/v: -rw------- 2 root root 1143 Nov 1 15:39 vt100 -rw------- 2 root root 1143 Nov 1 15:39 vt100-am /var: drwx--x--x 2 root root 1024 Nov 1 15:39 log drwx--x--x 2 root root 1024 Nov 1 15:39 run drwx--x--x 2 root root 1024 Nov 1 15:39 tmp /var/log: -rw------- 1 root root 0 Nov 1 15:39 wtmp /var/run: -rw------- 1 root root 0 Nov 1 15:39 utmp /var/tmp: D. ユーティリティディスクのサンプルのディレクトリ一覧 total 579 -rwxr-xr-x 1 root root 42333 Jul 28 19:05 cpio* -rwxr-xr-x 1 root root 32844 Aug 28 19:50 debugfs* -rwxr-xr-x 1 root root 103560 Jul 29 21:31 elvis* -rwxr-xr-x 1 root root 29536 Jul 28 19:04 fdisk* -rw-r--r-- 1 root root 128254 Jul 28 19:03 ftape.o -rwxr-xr-x 1 root root 17564 Jul 25 03:21 ftmt* -rwxr-xr-x 1 root root 64161 Jul 29 20:47 grep* -rwxr-xr-x 1 root root 45309 Jul 29 20:48 gzip* -rwxr-xr-x 1 root root 23560 Jul 28 19:04 insmod* -rwxr-xr-x 1 root root 118 Jul 28 19:04 lsmod* lrwxrwxrwx 1 root root 5 Jul 28 19:04 mt -> mt-st* -rwxr-xr-x 1 root root 9573 Jul 28 19:03 mt-st* lrwxrwxrwx 1 root root 6 Jul 28 19:05 rmmod -> insmod* -rwxr-xr-x 1 root root 104085 Jul 28 19:05 tar* lrwxrwxrwx 1 root root 5 Jul 29 21:35 vi -> elvis* E. 日本語訳について 日本語訳は Linux Japanese FAQ Project が行いました。翻訳に関するご意見 は JF プロジェクト 宛に連絡してください。 改訂履歴を以下に示します。 v1.01 (翻訳は非公開) 翻訳: 播口陽一さん v2.0-2.3 翻訳: 中野武雄 v3.3-3.5 翻訳: 藤原輝嘉 校正: 長谷川靖 武井伸光 中野武雄 http://www.linux.or.jp/JF/JFdocs/Bootdisk-HOWTO.txt --------------------------------------------------------------------------------