如何在没有 SD 卡的情况下构建 SD 卡映像?

如何在没有 SD 卡的情况下构建 SD 卡映像?

我们有一个脚本流程,用于在 SD 卡上构建嵌入式安装Debian Jesse。脚本的相关部分如下所示:

export DISK=/dev/sdb
umount ${DISK}1   # make sure no partitions mounted at the moment
umount ${DISK}2   # ditto
dd if=/dev/zero of=${DISK} bs=1M count=16   # zero partition table zone, overkill
sfdisk --in-order --Linux --unit M ${DISK} <<-__EOF__    # make partitions
    1,48,0xE,*
    ,,,-
__EOF__

mkfs.vfat -F 16 ${DISK}1 -n boot    # install file systems
mkfs.ext4 ${DISK}2 -L rootfs

此后,自动安装程序似乎启动并重新安装 SD 卡,因此我们可以执行以下操作:

cp -v ${DIR}/u-boot/spl/u-boot-spl.bin /media/$username/boot/BOOT.BIN
cp -v ${DIR}/u-boot/u-boot.img /media/$username/boot/
cp -v ${DIR}/u-boot/uEnv.txt /media/$username/boot/
rsync -axHAX --progress ${DIR}/jessieRoot/ /media/$username/rootfs/

在我们其中一个人完成此操作后,我们便可以使用它dd来复制卡中的内容并相互共享,从而使用它来制作更多的 SD 卡dd

这个问题有两个方面:1)它现在非常特定于 Ubuntu/机器(假设卡在sdb,等等);2)它需要一张真正的卡,因此不适合构建机器。

有没有不用卡就能完成上述操作的方法?

我尝试使用dd它来创建一个 8G 文件,然后sfdisk在其上运行(一切都是文件,对吧?),并且该部分工作正常。但不清楚我如何运行这些mkfs部分,它们似乎想要在块设备文件上工作,而不是在其中嵌入分区表的单个文件的子区域上工作。然后我遇到了安装它的问题。我假设我使用了一些咒语mount -o loop,但同样,不确定如何在虚拟映像文件的子区域上执行此操作,我总是用 .iso 文件来执行此操作。

(请随意吹毛求疵,我显然不是这方面的专家。我明白其中的一些,其他部分似乎有点神奇......)

答案1

我认为这一页有你需要的一切。

  • 使用环回设备代替 sdb

  • 使用虚拟文件系统代替实际的卡

  • 您使用 dd 为虚拟文件系统创建文件的方式正确。

  • 使用环回设备是正确的。诀窍是将环回设备安装在分区所在的偏移处。

这就是文章。

虚拟文件系统是存在于文件中的文件系统,而文件又存在于物理磁盘上。虚拟文件系统可以做很多很棒的事情;我使用虚拟文件系统的原因是为了在 Linux 主机上配置虚拟机。其他用途包括加密文件系统而不加密整个磁盘;Mac OS X 的 File Vault 以这种方式加密用户主目录。也许您先为自己创建了一个大分区,然后出于某种原因意识到您想要多个分区!虚拟文件系统也可以(在一定程度上)帮助实现这一点。

那么如何创建虚拟文件系统呢?很简单。您需要做的第一件事是为文件系统创建一个文件。这就是“dd”的用武之地。例如,请考虑以下命令:

dd if=/dev/zero of=~/myFileSystem.img bs=1024 count=1048576

此命令将从 /dev/zero 读取 1,048,576 个块并将它们写入 ~/myFileSystem.img;每个块为 1024 字节,从而生成一个包含所有零的 1 GB 文件。您用于块大小 (bs) 和计数的实际值并不重要,关键是要正确计算:bs * count = imageSize。

现在您有了文件;太棒了。是时候创建一个文件系统了!这部分甚至更简单……我们将使用以下命令创建一个 EXT2 文件系统:

mke2fs 我的文件系统.img

您可能会注意到一个警告提示,提示 myFileSystem.img 不是块设备,您想继续吗?我们马上就会讲到,现在,请继续并回答是。一切都应该顺利进行,看起来就像您在实际磁盘驱动器上创建了一个文件系统一样。您现在有一个虚拟文件系统!剩下要做的就是挂载您的文件系统,以便您可以访问它……

mkdir /mnt/virtual

mount -o loop ~/myFileSystem.img /mnt/virtual

现在,您放入 /mnt/virtual 的任何文件实际上都直接放入 myFileSystem.img 中!这难道不简单吗?

太棒了。既然您知道了如何制作虚拟文件系统,为什么不制作一个虚拟磁盘映像呢?您可能会问,这有什么区别?磁盘映像将有一个分区表,该分区表定义了一些分区,每个分区都包含自己的文件系统;因此,虚拟文件​​系统本质上是虚拟磁盘映像的“虚拟分区”;虚拟磁盘映像包含多个虚拟文件系统,以及一个描述每个分区边界的虚拟分区表。

创建虚拟磁盘映像的开始方式相同;您首先需要的是一个大的空文件,就是您上面创建的那个。不过,这一次,我们不想创建文件系统,而是想使用 fdisk 对文件进行分区。不过,为了让事情变得更好一点,我们将把回送设备加入其中。您应该确保在内核中启用了回送设备支持(大多数发行版默认启用;但如果您是内核编译 linux 的狂热者,您可能需要检查一下)。因此,我们将创建一个大文件,并将其附加到回送设备,如下所示:

dd if=/dev/zero of=~/myDisk.img bs=1024 count=1048576

losetup /dev/loop0 ~/myDisk.img

通过将磁盘映像附加到环回设备,我们可以像使用 ~/myDisk.img 一样使用 /dev/loop0;主要区别在于 /dev/loop0 是所谓的“块设备”。您必须询问比我更有经验的人这究竟能给您带来什么,但我确实知道的是文件系统实用程序与块设备配合使用比与平面文件配合使用效果更好。此外,它很有趣。

太好了,我们已经将一个大空文件附加到环回设备 (/dev/loop0)...现在是时候在磁盘映像中创建分区了。为此,我们将在环回设备上运行 fdisk:

fdisk /dev/loop0

让我们创建三个分区...如果你按照这个操作,你应该已经熟悉 fdisk,所以继续创建以下内容:设备启动开始结束块 ID 系统

/dev/loop0p1 1 17 136521 83 Linux

/dev/loop0p2 18 80 506047+ 82 Linux 交换

/dev/loop0p3 81 130 401625 83 Linux

创建分区后,写入更改并退出 fdisk。我们接下来需要做的是在每个分区上创建文件系统。还记得以前使用虚拟文件系统时有多容易吗?现在不那么容易了……

不过不要惊慌……问题是“mkfs”无法“进入”我们的虚拟磁盘映像并在单个分区上创建文件系统。事实上,如果你尝试这样做,你可能会最终擦除我们的虚拟磁盘映像并不得不重新运行 fdisk 。那么该怎么办……该怎么办??环回设备来救援。我们要做的是将环回设备连接到 myDisk.img 文件,每个分区开始的特定偏移量。

然后从块的角度来查看分区会很有帮助。执行以下命令:

fdisk -ul /dev/loop0

应该看起来(希望完全)像这样:

磁盘 /dev/loop0:1073 MB,1073741824 字节

255 个磁头,63 个扇区/磁道,130 个磁柱,总共 2097152 个扇区

单位 = 1 * 512 = 512 字节的扇区

  Device Boot      Start         End      Blocks   Id  System

/dev/loop0p1 63 273104 136521 83 Linux

/dev/loop0p2 273105 1285199 506047+ 82 Linux 交换

/dev/loop0p3 1285200 2088449 401625 83 Linux

这些数字对于数学来说很重要……我们将像以前一样使用 losetup 命令,只是这次我们将专门进入三个分区的开头。losetup 将偏移量作为文件开头要跳过的字节数。fdisk -ul /dev/loop0 的输出显示第一个分区从块 63 开始,每个块为 512 字节。因此分区 1 从字节 32,256 开始

losetup -o 32256 /dev/loop1 /dev/loop0

该命令将 32,256 字节写入 /dev/loop0 并将其挂载到 /dev/loop1。请记住,由于 /dev/loop0 附加了 myDisk.img 文件,因此这相当于将 32,256 字节写入该文件...明白了吗?好的。分区 2 和 3 的逻辑相同:

losetup -o 139829760 /dev/loop2 /dev/loop0

losetup -o 658022400 /dev/loop3 /dev/loop0

所以现在我们已经设置了四个环回设备;/dev/loop0 附加到 myDisk.img 文件。/dev/loop1 是 /dev/loop0 所代表的虚拟磁盘的第一个分区;/dev/loop2 是第二个,/dev/loop3 是第三个。

现在终于到了创建这些文件系统的时候了!现在这和创建常规文件系统一样简单,因为这就是我们所做的一切。请记住,mkfs 不知道该设备不是物理设备!我们将创建三种文件系统,分区 1 的 ext2 文件系统、分区 2 的交换文件系统和分区 3 的 XFS 文件系统:

mkfs /dev/loop1

mkswap /dev/loop2

mkfs.xfs /dev/loop3

由于 loop1、loop2 和 loop3 直接与 loop0 绑定,而 loop0 是 ~/myDisk.img,因此我们对 loop1、loop2 和 loop3 所做的一切操作都会直接影响 myDisk.img!我们现在可以将 /dev/loop3 作为 XFS 文件系统挂载到 /mnt/virtual 上,并将其用作常规文件系统!

所以我希望你发现这很有帮助...你可以用虚拟文件系统和虚拟磁盘映像做一些非常巧妙的事情;而环回设备可以使事情进展顺利。

答案2

这个问题公认的答案在事实上是正确的,但是——在我写这篇文章的时候,五年后— 有一种更简单的方法应该适合大多数人。手动调整偏移量并创建多种的一般而言,环回设备不再是必需的。如今,在大多数 Linux 发行版中创建虚拟文件系统映像的“秘密武器”-Plosetup 命令

-P, --partscan
              Force the kernel to scan the partition table on a newly created loop device.

你可以把它想象-P成“假装这个文件是一个磁盘“选项。下面这个例子应该能说明这一点。这个命令创建一个 4GB 的、充满零的映像文件:

$ dd if=/dev/zero of=./sdcard.img bs=1024 count=4194304
4194304+0 records in
4194304+0 records out
4294967296 bytes (4.3 GB, 4.0 GiB) copied, 39.7914 s, 108 MB/s

以下命令将第一个可用的回送设备映射到此文件,并以内核将开头的字节解释为分区表

$ sudo losetup -fP ./sdcard.img

$ losetup --list
NAME       SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE
/dev/loop0         0      0         0  0 /home/evadeflow/Desktop/sdcard.img

这似乎是一件小事,但通过-P意味着您现在可以使用诸如fdisk对通过映射的“磁盘”进行分区的工具/dev/loop0。在这里,我在开始时创建一个 128 MB 的分区,并创建第二个分区来容纳所有剩余空间:

$ sudo fdisk /dev/loop0
GNU Fdisk 1.3.0a
Copyright (C) 1998 - 2006 Free Software Foundation, Inc.
...
Using /dev/loop0
Command (m for help): p

Disk /dev/loop0: 4 GB, 4293596160 bytes
255 heads, 63 sectors/track, 522 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

     Device Boot      Start         End      Blocks   Id  System
Command (m for help): n
Partition type
   e   extended
   p   primary partition (1-4)
p
First cylinder  (default 0cyl):
Last cylinder or +size or +sizeMB or +sizeKB  (default 521cyl): +128M
Command (m for help): n
Partition type
   e   extended
   p   primary partition (1-4)
p
First cylinder  (default 15cyl):
Last cylinder or +size or +sizeMB or +sizeKB  (default 521cyl):
Command (m for help): p

Disk /dev/loop0: 4 GB, 4293596160 bytes
255 heads, 63 sectors/track, 522 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

     Device Boot      Start         End      Blocks   Id  System
/dev/loop0p1               1          16      128488   83  Linux
Warning: Partition 1 does not end on cylinder boundary.
/dev/loop0p2              16         522     4064445   83  Linux
Command (m for help): w
Information: Don't forget to update /etc/fstab, if necessary.


Writing all changes to /dev/loop0.

请注意,Linux 为您分别创建了以下两个分区的新环回设备:/dev/loop0p1/dev/loop0p2。您可以/dev/loop通过运行来查看它们之间的关系lsblk

$ lsblk /dev/loop0
NAME      MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
loop0       7:0    0     4G  0 loop
├─loop0p1 259:2    0 122.1M  0 loop
└─loop0p2 259:3    0   3.9G  0 loop

要填充这些分区,您可以使用回送设备创建文件系统/dev/loop0p1/dev/loop0p2然后简单地并将文件复制到挂载点。这个过程看起来有点像这样:

$ sudo mkfs.ext4 /dev/loop0p1
$ sudo mkfs.ext4 /dev/loop0p2
$ mkdir part1-stuff part2-stuff
$ sudo mount /dev/loop0p1 ./part1-stuff
$ sudo mount /dev/loop0p2 ./part2-stuff
$ cp /stuff-source/part1/* ./part1-stuff
$ cp /stuff-source/part2/* ./part2-stuff
$ sudo umount ./part1-stuff
$ sudo umount ./part2-stuff

一旦分区看起来符合您的要求,只需/dev/loop0使用以下命令从文件中“分离”:

$ sudo losetup -d /dev/loop0

请注意,这也会分离Linux 为您创建的/dev/loop0p1和设备。/dev/loop0p2

因此,总的来说,接受的答案仍然 100% 正确,并提供了有关幕后情况的宝贵见解。但如果您的发行版losetup支持此-P选项,您只需使用标准分区工具并让 Linux 处理创建(和删除) 的每个分区的循环“子设备”。

相关内容