在 Linux 系统上,是否可以仅使用用户空间工具来创建和操作分区映像(可能仅具有 ext2 文件系统),然后使用这些分区映像来创建磁盘映像?
我可以使用genext2fs
它在用户空间中生成 ext2 文件系统的映像,但我找不到任何可以操作磁盘映像(例如创建分区表或从现有分区映像创建磁盘映像等)的工具,而无需 root 访问权限。目前,我使用它kpartx
来挂载磁盘映像中的分区,但由于这需要 root,因此它实际上并不适合编写脚本,并且如果构建脚本中存在未被捕获的错误,则映射器设备仍处于使用状态。
基本上,我有三个目录,我希望每个目录都成为磁盘映像上的一个分区,但我想编写脚本,而且我真的不想使用任何需要 root 访问权限的工具(似乎这个过程中没有任何内容绝对需要具有 root 访问权限)。
答案1
分区创建
要创建分区表,您可以直接在文件而不是设备上使用常用工具。大多数标准工具都应支持这种用法,例如fdisk
和parted
。parted
非常适合集成到脚本中,因为它可以将命令作为参数。
parted -s testing.img mklabel gpt
parted -s -a none testing.img mkpart ESP fat32 0 4M
parted -s -a none testing.img mkpart linux ext4 4M 10M
文件系统创建
我没有一个干净的解决方案来在虚拟分区中安装或创建文件系统。正确的做法可能是fuse
为分区表安装一个(用户空间中的文件系统)驱动程序。但目前我还没有找到。
但是,mke2fs
可以选择在文件内的任意偏移处-E offset=1234
构建ext2
、ext3
或ext4
文件系统。您可以为其指定分区的偏移量。但是,请确保也为其指定文件系统的大小,因为默认行为似乎存在错误,并默认使用虚拟磁盘的大小编写文件系统,并在需要时扩展文件。
mke2fs -E offset=4000256 testing.img 6316k
不幸的是,并非所有的分区mkfs
都有这样的选项。mkfs.vfat
所以另一个解决方案是创建一个与分区大小相同的单独文件,使用mkfs
它然后dd
将内容复制到完整的虚拟磁盘中。
dd if=testing.img of=testing.fat32.img bs=512 skip=34 count=7779
mkfs -t vfat testing.fat32.img
dd if=testing.fat32.img of=testing.img bs=512 seek=34 count=7779 conv=notrunc
虽然不是最干净或最快的解决方案,但它确实有效,非常通用,并且不需要 root 权限。转换选项sparse
还可用于通过不写入长零序列来加快速度。
挂载文件系统
您可以在分区中安装文件系统,前提是fuse
它支持您的文件系统。ext
名称下有对文件系统的标准支持fuse-ext2
,FAT
名称下有对文件系统的标准支持fusefat
。不幸的是,他们目前没有选择offset
。所以我想你只能使用mount
或dd
与之前相同的技巧。
标准方法使用partx
或kpartx
,(或-o offset
选项mount
)需要 root 权限。该dd
解决方案缓慢、复杂且容易出错。
答案2
我使用并推荐guestfish
,它是libguestfs,用于访问和修改虚拟机磁盘映像的库。
我发现 OpenStack 的文档包含不需要权限的工具的有用描述:修改图像 — 虚拟机图像指南文档
请注意,如果您进行许多不相交的更改,您可能会受益于运行guestfish
守护进程并使用其远程控制模式 - 这可以节省(并非微不足道的)启动时间。
看guestfish
通过插座进行远程控制手册guestfish
。
答案3
尝试使用以下组合:
- 保险丝环
- 使用 FUSE 的环回安装实用程序
- https://github.com/jmattsson/fuseloop
- sudo apt-get 安装 fuseloop(Debian/Ubuntu)
和:
- 熔断器
- FAT 文件系统的 FUSE 模块
- https://sourceforge.net/p/fusefat/wiki/Home/
- 目前需要从源代码进行编译
例子:
# Create 1GB sparse file
truncate -s 1G disk1.bin
# Create simple ms-dos partition table an a single partition with maximum free space
echo -e "o\nn\np\n1\n2048\n-1\np\nw\n" | /sbin/fdisk disk1.bin
Welcome to fdisk (util-linux 2.34).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0x4643133c.
Command (m for help): Created a new DOS disklabel with disk identifier 0xff5d1f1e.
Command (m for help): Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): Partition number (1-4, default 1): First sector (2048-2097151, default 2048): Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-2097151, default 2097151):
Created a new partition 1 of type 'Linux' and of size 1023 MiB.
Command (m for help): Disk disk1.bin: 1 GiB, 1073741824 bytes, 2097152 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xff5d1f1e
Device Boot Start End Sectors Size Id Type
disk1.bin 1 2048 2097150 2095103 1023M 83 Linux
Command (m for help): The partition table has been altered.
Syncing disks.
# Check out the offset and size in bytes
$ parted disk1.bin
GNU Parted 3.3
Using /kvm/test2/disk1/disk1.bin
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) unit b
(parted) p
Model: (file)
Disk /kvm/test2/disk1/disk1.bin: 1073741824B
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:
Number Start End Size Type File system Flags
1 1048576B 1073741311B 1072692736B primary fat32
(parted) q
# Create a placeholder file for fuseloop to use
touch disk1.bin.part1
# fuseloop - take a raw disk image and create a "loopback block device file" for a partition within the raw disk image file
# fuseloop -O OFFSET -S SIZE DISKFILE.RAW PARTITIONFILE.RAW
$ fuseloop -O 1048576 -S 1072692736 disk1.bin disk1.bin.part1
$ findmnt $(realpath disk1.bin.part1)
TARGET SOURCE FSTYPE OPTIONS
/kvm/test2/disk1/disk1.bin.part1 /dev/fuse fuse rw,nosuid,nodev,relatime,user_id=0,group_id=0
# Create the filesystem
$ /sbin/mkfs.vfat -n DATA -v disk1.bin.part1
mkfs.fat 4.1 (2017-01-24)
Auto-selecting FAT32 for large filesystem
disk1.bin.part1 has 255 heads and 63 sectors per track,
hidden sectors 0x0000;
logical sector size is 512,
using 0xf8 media descriptor, with 2095103 sectors;
drive number 0x80;
filesystem has 2 32-bit FATs and 8 sectors per cluster.
FAT size is 2048 sectors, and provides 261371 clusters.
There are 32 reserved sectors.
Volume ID is c86be444, volume label DATA .
# Make a mountpoint dir (please don't use /tmp)
mkdir /tmp/mnt
# fusefat - take the "loopback block device file" and mount it (-o ro or -o rw required)
# fusefat -o MODE PARTITIONFILE.RAW /path/to/mountpoint/
$ fusefat -o ro disk1.bin.part1 /tmp/mnt/
fat type: FAT32. Fsi at 1
Fsioff: 512, size: 512
--- nxtfree --- :4
--- freecnt --- :261368
dataclusters :261371
first data byte : 2113536
1st fat off : 16384
2nd fat off : 1064960
fat_eoc_value: 268435448
fat_eoc_value is eoc?: 1
$ findmnt /tmp/mnt/
TARGET SOURCE FSTYPE OPTIONS
/tmp/mnt/ fusefat fuse.fusefat ro,nosuid,nodev,relatime,user_id=0,group_id=0
# Unmount the filesystem (and verify)
$ fusermount -u /tmp/mnt/
$ findmnt /tmp/mnt/
# Unmount the "loopback block device file" (and verify)
$ fusermount -u disk1.bin.part1
$ findmnt $(realpath disk1.bin.part1)