从磁盘映像中挂载或提取指定的 LVM 逻辑卷

2009/10/19 | 13:40 | 分类:Linux与开源 | 标签: | 813次阅读

  前面提到了如何从磁盘映像中挂载或提取指定分区,现在我们再看看如何从含有 LVM 分区的映像中挂载或提取指定的逻辑卷(LV)。由于 LVM 分区内部有自己的盘区(PE)分配方法,因此逻辑卷在映像中并不一定是物理连续的,不能通过找到其偏移地址直接挂载。不过只要本地系统安装了 LVM 支持,就可以使用 LVM 自带的实用工具完成硬盘映像中逻辑卷的挂载。
  首先查看一下本地系统已经挂载过的物理卷(PV)、卷组(VG)和逻辑卷。我们看到,系统已经安装并激活了 VolGroup01 卷组。事实上 VolGroup01 中的 LogVol00 是本地系统的根分区,LogVol01 是交换分区。

  1. [root@centos CentOS]# pvscan
  2.   PV /dev/sda2   VG VolGroup01   lvm2 [136.00 GB / 0    free]
  3.   Total: 1 [136.00 GB] / in use: 1 [136.00 GB] / in no VG: 0 [0   ]
  4. [root@centos CentOS]# vgscan
  5.   Reading all physical volumes.  This may take a while...
  6.   Found volume group "VolGroup01" using metadata type lvm2
  7. [root@centos CentOS]# lvscan
  8.   ACTIVE            '/dev/VolGroup01/LogVol00' [134.06 GB] inherit
  9.   ACTIVE            '/dev/VolGroup01/LogVol01' [1.94 GB] inherit

  实验使用的 centos5-2-gnome.img 是一个安装了 CentOS 并通过 LVM 管理磁盘的映像文件。使用 fdisk 命令查看其分区结构,其中 centos5-2-gnome.img2 是 LVM 分区,fdisk 不能提供 LVM 的详细信息。

  1. [root@centos CentOS]# fdisk -l -u centos5-2-gnome.img
  2. last_lba(): I don't know how to handle files with mode 81a4
  3. You must set cylinders.
  4. You can do this from the extra functions menu.
  5.  
  6. Disk centos5-2-gnome.img: 0 MB, 0 bytes
  7. 255 heads, 63 sectors/track, 0 cylinders, total 0 sectors
  8. Units = sectors of 1 * 512 = 512 bytes
  9.  
  10.               Device Boot      Start         End      Blocks   Id  System
  11. centos5-2-gnome.img1   *          63      208844      104391   83  Linux
  12. centos5-2-gnome.img2          208845     8385929     4088542+  8e  Linux LVM

  使用 Linux 的 loop 设备控制命令——losetup:首先用 -f 参数查找一个空闲的 loop 节点;然后通过 -o 参数指定 LVM 分区在映像中的偏移量(参考 fdisk 的输出),将其挂载在空闲的 loop 节点上;最后使用 -a 参数确认挂载成功。

  1. [root@centos CentOS]# losetup -f
  2. /dev/loop4
  3. [root@centos CentOS]# losetup -o $((208845*512)) /dev/loop4 centos5-2-gnome.img
  4. [root@centos CentOS]# losetup -a
  5. ...
  6. /dev/loop4: [fd00]:26706086 (centos5-2-gnome.img), offset 106928640

  再一次查看系统中存在的 LVM 设施。我们看到,映像中的 VolGroup00 卷组已被扫描到,其中有 LogVol00、LogVol01 两个未激活的分区。

  1. [root@centos CentOS]# pvscan
  2.   PV /dev/loop4   VG VolGroup00   lvm2 [3.88 GB / 0    free]
  3.   PV /dev/sda2    VG VolGroup01   lvm2 [136.00 GB / 0    free]
  4.   Total: 2 [139.88 GB] / in use: 2 [139.88 GB] / in no VG: 0 [0   ]
  5. [root@centos CentOS]# vgscan
  6.   Reading all physical volumes.  This may take a while...
  7.   Found volume group "VolGroup00" using metadata type lvm2
  8.   Found volume group "VolGroup01" using metadata type lvm2
  9. [root@centos CentOS]# lvscan
  10.   inactive          '/dev/VolGroup00/LogVol00' [2.91 GB] inherit
  11.   inactive          '/dev/VolGroup00/LogVol01' [992.00 MB] inherit
  12.   ACTIVE            '/dev/VolGroup01/LogVol00' [134.06 GB] inherit
  13.   ACTIVE            '/dev/VolGroup01/LogVol01' [1.94 GB] inherit

  这个例子中,映像中的卷组与本地已挂载的卷组名称不同,不会出现歧义。但如果映像中的卷组恰与本地已挂载的卷组重名,则可以使用 vgrename 命令修改映像中的卷组名称。

  1. [root@centos CentOS]# vgrename --help
  2.   vgrename: Rename a volume group
  3.  
  4. vgrename
  5.         [-A|--autobackup y|n]
  6.         [-d|--debug]
  7.         [-h|--help]
  8.         [-t|--test]
  9.         [-v|--verbose]
  10.         [--version]
  11.         OldVolumeGroupPath NewVolumeGroupPath |
  12.         OldVolumeGroupName NewVolumeGroupName

  使用 vgchange 命令激活 VolGroup00 卷组,再次查看逻辑卷的状态,LogVol00、LogVol01 已经可用。

  1. [root@centos CentOS]# vgchange -ay VolGroup00
  2.   2 logical volume(s) in volume group "VolGroup00" now active
  3. [root@centos CentOS]# lvscan
  4.   ACTIVE            '/dev/VolGroup00/LogVol00' [2.91 GB] inherit
  5.   ACTIVE            '/dev/VolGroup00/LogVol01' [992.00 MB] inherit
  6.   ACTIVE            '/dev/VolGroup01/LogVol00' [134.06 GB] inherit
  7.   ACTIVE            '/dev/VolGroup01/LogVol01' [1.94 GB] inherit

  现在便可以使用 lvscan 输出的逻辑卷设备文件名来挂载对应的文件系统了。

  1. [root@centos CentOS]# mount /dev/VolGroup00/LogVol00 ./part/
  2. [root@centos CentOS]# ls ./part/
  3. bin  boot  dev  etc  home  lib  lost+found  media  misc  mnt
  4. net  opt  proc  root  sbin  selinux  srv  sys  tmp  usr  var
  5. [root@centos CentOS]# umount ./part/

  如果要提取其中的分区,也可以直接对逻辑卷设备文件或 /dev/mapper/ 下对应的设备文件操作。

  1. [root@centos CentOS]# dd if=/dev/VolGroup00/LogVol00 of=LogVol00.img
  2. 6094848+0 records in
  3. 6094848+0 records out
  4. 3120562176 bytes (3.1 GB) copied, 113.93 seconds, 27.4 MB/s

  试挂载提取出来的分区。

  1. [root@centos CentOS]# mount -o loop LogVol00.img ./part/
  2. [root@centos CentOS]# ls ./part/
  3. bin  boot  dev  etc  home  lib  lost+found  media  misc  mnt
  4. net  opt  proc  root  sbin  selinux  srv  sys  tmp  usr  var
  5. [root@centos CentOS]# umount ./part/

  卸载文件系统之后,别忘了卸载卷组和 loop 节点。

  1. [root@centos CentOS]# vgchange -an VolGroup00
  2.   0 logical volume(s) in volume group "VolGroup00" now active
  3. [root@centos CentOS]# losetup -d /dev/loop4

从磁盘映像中挂载或提取指定分区

2009/10/11 | 22:48 | 分类:Linux与开源 | 标签: | 383次阅读

  最近在做虚拟机相关的事,需要处理一些磁盘和分区的映像文件。如何从一个磁盘映像中挂载指定的分区到本地 Linux 文件系统呢?理论上说,可以用 dd 把该分区从磁盘映像中提取出来再挂载,不过 mount 提供了针对 loop 设备的偏移量参数,方便直接从磁盘映像中挂载指定分区。笔记如下:
  演示用的磁盘映像使用 qemu-img 制作。我们使用原生的 raw 格式,等价于磁盘上的原始数据流,保证它在任何 Linux 系统上都可以直接挂载。使用 Windows PE 工具盘启动该 qemu 虚拟机,创建一系列不同格式的分区并在其中建立几个文件。

  1. root@lj-laptop:/opt/vm# qemu-img create -f raw vmtest.img 5G
  2. root@lj-laptop:/opt/vm# qemu -hda ./vmtest.img -cdrom /dev/cdrom -boot d -m 256M -localtime

  磁盘分区结构如截图:
从磁盘映像中挂载或提取指定分区
  回到宿主系统,使用 fdisk 的 -l、-u 参数查看磁盘映像。其中 -u 表示以扇区为单位显示分区起止位置,方便后续计算。

  1. root@lj-laptop:/opt/vm# fdisk -l -u vmtest.img
  2. You must set cylinders.
  3. You can do this from the extra functions menu.
  4.  
  5. Disk vmtest.img: 0 MB, 0 bytes
  6. 255 heads, 63 sectors/track, 0 cylinders, total 0 sectors
  7. Units = sectors of 1 * 512 = 512 bytes
  8. Disk identifier: 0xbd86bd86
  9.  
  10.      Device Boot      Start         End      Blocks   Id  System
  11. vmtest.img1              63     8193149     4096543+  83  Linux
  12. vmtest.img2         8193150    10249469     1028160    5  Extended
  13. vmtest.img3        10249470    10474379      112455    6  FAT16
  14. vmtest.img5         8193213     8610839      208813+  83  Linux
  15. vmtest.img6         8610903     9028529      208813+  82  Linux swap / Solaris
  16. vmtest.img7         9028593    10249469      610438+   b  W95 FAT32

  这时我们只需要为 mount 添加 offset 参数,指定分区在磁盘映像中的逻辑地址,即可挂载这一分区。注意 offset 的单位是字节,通常一个扇区是 512 字节,因此需要用 fdisk 输出的 Start 乘以 512。以 vmtest.img3 分区为例。

  1. root@lj-laptop:/opt/vm# mount -o loop,offset=$((10249470*512)) vmtest.img ./part/
  2. root@lj-laptop:/opt/vm# ls ./part/
  3. InFAT16.txt
  4. root@lj-laptop:/opt/vm# umount ./part/

  如果有必要,我们可以将特定的分区从硬盘映像中提取出来,方便单独使用。通过 dd 可以完成提取,简便起见使用扇区大小 512 字节作为 bs 参数,这样 skip、count 参数很容易从 fdisk 的输出中计算出来。下面提取 vmtest.img5。

  1. root@lj-laptop:/opt/vm# dd if=vmtest.img of=linux2.img bs=512 skip=8193213 count=$((8610839-8193213+1))
  2. 417627+0 records in
  3. 417627+0 records out
  4. 213825024 bytes (214 MB) copied, 4.67434 s, 45.7 MB/s
  5. root@lj-laptop:/opt/vm# mount -o loop linux2.img ./part/
  6. root@lj-laptop:/opt/vm# ls ./part/
  7. InLinux2.txt  lost+found
  8. root@lj-laptop:/opt/vm# umount ./part/

  到这一步,我们已经实现了从磁盘映像中挂载或提取指定分区。其中 fdisk 帮我们完成了磁盘映像的分析,直接将分区的逻辑地址显示给了我们。现在我们再借机复习一下磁盘分区表的格式,试试手工计算相关地址。这里推荐大家阅读网上这篇《解读 Windows 操作系统分区表的秘密》,其中详解过的概念这里不再赘述,下面的内容权当对这篇文章在 Linux 平台下的补充。
  首先查看磁盘映像的主引导扇区,其中分区表位于 0x1be 开始的 64 字节。

  1. root@lj-laptop:/opt/vm# cat vmtest.img | xxd | head -32
  2. ...
  3. 00001b0: 0000 0000 0000 0000 86bd 86bd 0000 0001  ................
  4. 00001c0: 0100 83fe 7ffd 3f00 0000 3f04 7d00 0000  ......?...?.}...
  5. 00001d0: 41fe 05fe bf7d 7e04 7d00 8060 1f00 0000  A....}~.}..`....
  6. 00001e0: 817e 06fe bf8b fe64 9c00 8e6e 0300 0000  .~.....d...n....
  7. 00001f0: 0000 0000 0000 0000 0000 0000 0000 55aa  ..............U.

  对于 vmtest.img1 和 vmtest.img3 这两个主分区,我们读出它们的起始逻辑地址分别为 0x3f 和 0x9c64fe(注意在分区表中以 Little-endian 存储),换算成十进制与 fdisk 输出的一致。bash 的算术表达式支持十六进制字面值,挂载方式同上。

  1. root@lj-laptop:/opt/vm# mount -o loop,offset=$((0x3f*512)) vmtest.img ./part/
  2. root@lj-laptop:/opt/vm# ls ./part/
  3. InLinux.txt  lost+found
  4. root@lj-laptop:/opt/vm# umount ./part/
  5. root@lj-laptop:/opt/vm# mount -o loop,offset=$((0x9c64fe*512)) vmtest.img ./part/
  6. root@lj-laptop:/opt/vm# ls ./part/
  7. InFAT16.txt
  8. root@lj-laptop:/opt/vm# umount ./part/

  对于扩展分区 vmtest.img2,我们通过 dd 定位到它所指向的第一个逻辑分区 vmtest.img5 前面的卷引导记录,查看逻辑分区的链式分区表。

  1. root@lj-laptop:/opt/vm# dd if=vmtest.img bs=512 skip=$((0x7d047e)) | xxd | head -32
  2. ...
  3. 00001b0: 0000 0000 0000 0000 0000 0000 0000 0001  ................
  4. 00001c0: 41fe 83fe bf17 3f00 0000 5b5f 0600 0000  A.....?...[_....
  5. 00001d0: 8118 05fe bf31 9a5f 0600 9a5f 0600 0000  .....1._..._....
  6. 00001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
  7. 00001f0: 0000 0000 0000 0000 0000 0000 0000 55aa  ..............U.

  vmtest.img5 相对于 vmtest.img2 的偏移量为 0x3f,按此地址挂载。

  1. root@lj-laptop:/opt/vm# mount -o loop,offset=$(((0x7d047e+0x3f)*512)) vmtest.img ./part/
  2. root@lj-laptop:/opt/vm# ls ./part/
  3. InLinux2.txt  lost+found
  4. root@lj-laptop:/opt/vm# umount ./part/

  沿着链式分区表的第二条记录(即链表指针)指示的偏移量,我们可以找到第二、第三个逻辑分区(vmtest.img6、vmtest.img7)前面的卷引导记录以及这两个分区的逻辑地址。

  1. root@lj-laptop:/opt/vm# dd if=vmtest.img bs=512 skip=$((0x7d047e+0x65f9a)) | xxd | head -32
  2. ...
  3. 00001b0: 0000 0000 0000 0000 0000 0000 0000 0001  ................
  4. 00001c0: 8118 82fe bf31 3f00 0000 5b5f 0600 0000  .....1?...[_....
  5. 00001d0: 8132 05fe bf7d 34bf 0c00 4ca1 1200 0000  .2...}4...L.....
  6. 00001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
  7. 00001f0: 0000 0000 0000 0000 0000 0000 0000 55aa  ..............U.
  8. root@lj-laptop:/opt/vm# dd if=vmtest.img bs=512 skip=$((0x7d047e+0xcbf34)) | xxd | head -32
  9. ...
  10. 00001b0: 0000 0000 0000 0000 0000 0000 0000 0001  ................
  11. 00001c0: 8132 0bfe bf7d 3f00 0000 0da1 1200 0000  .2...}?.........
  12. 00001d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
  13. 00001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
  14. 00001f0: 0000 0000 0000 0000 0000 0000 0000 55aa  ..............U.

  取得了相应的地址,挂载或提取分区当然是轻而易举的。下面挂载了 vmtest.img7、提取了 vmtest.img5。

  1. root@lj-laptop:/opt/vm# mount -o loop,offset=$(((0x7d047e+0xcbf34+0x3f)*512)) vmtest.img ./part/
  2. root@lj-laptop:/opt/vm# ls ./part/
  3. InFAT32.txt
  4. root@lj-laptop:/opt/vm# umount ./part/
  5. root@lj-laptop:/opt/vm# dd if=vmtest.img of=linux2.img bs=512 skip=$((0x7d047e+0x3f)) count=$((0x65f5b))
  6. 417627+0 records in
  7. 417627+0 records out
  8. 213825024 bytes (214 MB) copied, 4.65149 s, 46.0 MB/s
  9. root@lj-laptop:/opt/vm# mount -o loop ./linux2.img ./part/
  10. root@lj-laptop:/opt/vm# ls ./part/
  11. InLinux2.txt  lost+found
  12. root@lj-laptop:/opt/vm# umount ./part/

借助虚拟机,在移动硬盘中安装Puppy Linux

2008/11/18 | 23:25 | 分类:Linux与开源 | 标签: | 1,154次阅读

  Puppy Linux 4.1.1发布了,把它安装在移动硬盘上作为随身系统是个不错的选择。Puppy的文档建议使用Live CD启动,然后通过其中的Puppy Universal Installer将其安装到USB硬盘,但刻录Live CD有点浪费。也有网友制作了Puppy硬盘安装程序,但只能安装在FAT或NTFS分区,以sfs镜像方式加载。不能安装在ext3分区,并且把文件系统在分区上展开。事实上,我们也可以不刻录Live CD,而借助虚拟机来加载Live CD ISO和移动硬盘执行安装程序,把Puppy像一般Linux发行版那样安装在ext3分区。我这里使用VMware Player,运行在Windows Vista上。

  1、将移动硬盘插好。
  2、在VMware Player中设置任一已存在的虚拟系统的光驱,加载Puppy的Live CD ISO。
  3、启动这一虚拟系统,通过Esc键的启动选项菜单选择光盘引导。
  4、待Puppy加载完成后,通过VMware Player的Genesys Logic Removable Disk功能挂载物理机上的移动硬盘。
  5、在虚拟机中运行Puppy Universal Installer,将Puppy安装到挂载好的移动硬盘的ext3分区中。

  理论上这样可以正确安装。但我安装后发现Puppy文件复制正确,而Grub或MBR不知何故有问题,用移动硬盘开机时显示乱码,没有响应。于是决定采用另外的思路,借助本地的Ubuntu 8.10系统在移动硬盘中重新安装Grub。

  1、启动Ubuntu,在移动硬盘的Puppy所在的分区中建立/boot/grub目录,将Ubuntu的/boot/grub下的所有文件复制到Puppy的/boot/grub下。
  2、在Ubuntu的终端下运行sudo grub,将Grub的引导信息写入移动硬盘的MBR,命令如下:
=============================
root (hd1,5)
setup (hd1)
quit
=============================
  3、修改移动硬盘上的/boot/grub/menu.lst。由于我的移动硬盘中已有一套WinPE系统,所以需要配置两个引导项。内容如下:
=============================
default 0

timeout 10

title Puppy Linux
root (hd0,5)
kernel /vmlinuz
initrd /initrd.gz

title Windows PE
root (hd0,0)
savedefault
makeactive
chainloader +1
==============================

  需要注意的是,在安装Grub时,本机硬盘为hd0,移动硬盘为hd1,所以要将Grub安装到hd1。而使用移动硬盘引导时,移动硬盘则成了hd0,故需要在menu.lst中加载hd0上的分区来启动系统。

  然后再次测试,Grub正常加载。分别选择“Puppy Linux”和“Windows PE”,可以进入对应的系统。