ディレクトリをQEMUのディスクイメージに変換する作業において、ディスクイメージにブートローダーをインストールする必要があったのでやってみた。
まずは、必要なサイズのRAWイメージを作成する。とりあえず、4GBで(1M x 4000)。
# dd if=/dev/null of=raw_disk.img bs=1M seek=4000 0+0 records in 0+0 records out 0 bytes copied, 0.000167545 s, 0.0 kB/s
余談:
dd if=/dev/zero of=raw_disk.img count=1 bs=1000MBというやり方もあるが、実際にディスクにデータを書き込んでいくので時間がかかる。ちなみに、上記のseekオプションは、seekで指定された回数だけブロック(サイズ指定はbs)のコピーをスキップするという動作をするので、上記の例では、1MBのブロックのコピーを4000回スキップした後に、/dev/nullから1回だけ1MBをコピーするという動作をする。(でも、/dev/nullは空なので、0バイトがコピーされることになる。)
スキップされたところはスパースファイル(Sparse file)になっているので、使用されるディスク容量を節約できるし、ddでファイルを作成するスピードを大幅に短縮できる。
作成したRAWイメージをデバイスとして認識させる。--findは/dev/loop[0-9]のうち、空いている番号を見つけるという意味。--showは、選ばれたデバイスパスを表示するという意味。
# losetup --find --show raw_disk.img /dev/loop0
注意:ここでループバックデバイスとしてマウントしているが、
# mount -t ext4 raw_disk.img /mnt/raw_disk/という方法もある。しかし、この方法でマウントして後続処理を行っていくと、grub2-installをする際にブートローダーをインストールする先を指定できない(/dev/ で始まるブロックデバイスを指定する必要があるが、存在しないため。
作成したドライブをフォーマットする。この例は、RAWイメージのファイル自体を初期化する例。
# mkfs.ext4 -F raw_disk.img mke2fs 1.45.6 (20-Mar-2020) Discarding device blocks: done Creating filesystem with 1024000 4k blocks and 256000 inodes Filesystem UUID: 07f46161-9dba-49dd-aad5-0f871d1689d4 Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736 Allocating group tables: done Writing inode tables: done Creating journal (16384 blocks): done Writing superblocks and filesystem accounting information: done
こちらの例は、先程作成したループバックデバイス経由で初期化する例。
# mkfs.ext4 /dev/loop0 mke2fs 1.45.6 (20-Mar-2020) Discarding device blocks: done Creating filesystem with 1024000 4k blocks and 256000 inodes Filesystem UUID: 0c3c3114-74d4-4012-b131-f1dd67d4a4e0 Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736 Allocating group tables: done Writing inode tables: done Creating journal (16384 blocks): done Writing superblocks and filesystem accounting information: done
作成したディスクイメージのマウントと、ディスクイメージへのファイルの書き込み。ここでは、USBブートできるように構築されたイメージ(squashfsに入っていたものを取り出した)を展開したディレクトリの中身をコピーした。
# mkdir /mnt/ram_disk # mount /dev/loop0 /mnt/raw_disk/ # cp -a squashfs-root/. /mnt/raw_disk/
マウントしたディレクトリを/にしてchrootする。
# cd /mnt/raw_disk/
# mount --bind /dev/ dev/
# chroot .
chrooted:/# mount -t proc none /proc
chrooted:/# mount -t sysfs none /sys
chrooted:/# mount -t devpts none /dev/pts
Grub2をインストールする。起動時のbootディレクトリは/bootになるはずなので、--boot-directoryで指定。ブートローダのインストール先はlosetupで作成した/dev/loop0
chrooted:/# grub-install --boot-directory=/boot /dev/loop0 Installing for i386-pc platform. grub-install: warning: File system `ext2' doesn't support embedding. grub-install: warning: Embedding is not possible. GRUB can only be installed in this setup by using blocklists. However, blocklists are UNRELIABLE and their use is discouraged.. grub-install: error: will not proceed with blocklists.
しかし、エラーになる。
これは、インストール先が数字で終わっているため。本来、ブートローダはデバイスの先頭に書き込まれるものであり、例えば/dev/sdaなどを指定する。パーティション(例:/dev/sda0など)の先頭に書くのはあまりないはずであるため、デバイスの指定の末尾が数字になることは通常はありえないため、エラーになっている。しかし、今回やろうとしているのは、末尾が数字になっていても、後々はディスクの先頭になる部分であるため、このエラーは無視して良い。そこで、--forceを指定して、強制的に書き込む。
chrooted:/# grub-install --boot-directory=/boot --force /dev/loop0 Installing for i386-pc platform. grub-install: warning: File system `ext2' doesn't support embedding. grub-install: warning: Embedding is not possible. GRUB can only be installed in this setup by using blocklists. However, blocklists are UNRELIABLE and their use is discouraged.. Installation finished. No error reported.
/boot/grub/grub.cfgがあればよいのだが、ない場合は作成しなければならない。
chrooted:/# grub-mkconfig -o /boot/grub/grub.cfg Generating grub configuration file ... /usr/sbin/grub-probe: error: failed to get canonical path of `/data/hagiwara_usb/extracted_files/raw_disk.img'. No path or device is specified. Usage: grub-probe [OPTION...] [OPTION]... [PATH|DEVICE] Try 'grub-probe --help' or 'grub-probe --usage' for more information.
が、エラー。grub-mkconfigが内部で呼び出しているgrub-probeがエラーを出している。いろいろ調べたが、最終的に別端末から/usr/share/grub/grub-mkconfig_lib をコピーして持ってきてエラーを回避した。(何故か、prepare_grub_to_access_device 関数の中の/dev/loop0の処理において、$@をshiftしていた。これにより、後続のgrub-probeの実行時に、--device の引数が無くなってしまい、エラーになっていた。)
再度grub-mkconfigを実行
chrooted:/etc/grub.d# grub-mkconfig -o /boot/grub/grub.cfg Generating grub configuration file ... Warning: Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported. done
これで起動させたが、grubの対話モードで停止していた。grub.cfgを見るとkernelが見つけられていなかった。
/etc/grub.d/10-linux の中でkernelを見つけているのだが、冒頭で/dev/loop0についての処理をしており、ループバックデバイスのときはexitすることになっていた。
これをコメントアウトして、ループバックデバイスでも処理が継続するように変更。変更点はこんな感じ。なお、ループバックデバイスの元ファイルを特定して、そこを見せようとしているので、それも修正。
chrooted:/etc/grub.d# diff -Naur 10_linux.orig 10_linux --- 10_linux.orig 2020-11-17 20:32:17.000000000 +0900 +++ 10_linux 2021-01-30 20:56:41.093564059 +0900 @@ -52,12 +52,12 @@ # the initrds that Linux uses don't like that. case ${GRUB_DEVICE} in /dev/loop/*|/dev/loop[0-9]) - GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"` + #GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"` # We can't cope with devices loop-mounted from files here. - case ${GRUB_DEVICE} in - /dev/*) ;; - *) exit 0 ;; - esac + #case ${GRUB_DEVICE} in + # /dev/*) ;; + # *) exit 0 ;; + #esac ;; esac
GRUB_DEVICE=の行をコメントアウトしていなかったときは、これまたgrub-probeでエラーが出ていた。
chrooted:/etc/grub.d# grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
Warning: Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported.
/usr/sbin/grub-probe: error: cannot find a GRUB drive for /data/raw_disk.img. Check your device.map.
Found linux image: /boot/vmlinuz-4.15.0-133-generic
Found initrd image: /boot/initrd.img-4.15.0-133-generic
done
いずれにせよ、grub-mkconfigで/boot/grub/grub.cfgを作成する。
chrooted:/etc/grub.d# grub-mkconfig -o /boot/grub/grub.cfg Generating grub configuration file ... Warning: Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported. /etc/grub.d/10_linux: 62: /etc/grub.d/10_linux: Syntax error: newline unexpected (expecting ")") root@edo:/etc/grub.d# grub-mkconfig -o /boot/grub/grub.cfg Generating grub configuration file ... Warning: Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported. Found linux image: /boot/vmlinuz-4.15.0-133-generic Found initrd image: /boot/initrd.img-4.15.0-133-generic done
終わりのコメント
あとは後処理。chootの終了、マウントの解除、ループバックデバイスの解除。
chrooted::/# umount /proc || umount -lf /proc chrooted::/# umount /sys chrooted::/# umount /dev/pts chrooted::/# umount /dev chrooted::/# exit # cd .. # umount /mnt/raw_disk # losetup -d /dev/loop0
以上で終わり。
0 件のコメント:
コメントを投稿