2
2
2014
17

grub2 引导 Arch Linux 安装镜像的方法

志以备链。

一、准备设备

U 盘、SD 卡、硬盘、移动硬盘均可。不需要重新分区,但是引导部分将被覆盖。不要用太奇葩的分区格式,Windows 和 Linux 下常见的都行。要有地方装 grub。grub 一般情况是安装在第一个分区前的空闲空间(MBR 分区表)或者专门准备的一个分区(GPT 分区表,参见 ArchWiki)。把下回来的镜像文件(如archlinux-2014.01.05-dual.iso)扔进去。注意据说 BIOS 只能读取 USB 设备前 8G 的内容,因此如果是移动硬盘,最好把文件放第一个分区中。

二、安装 grub2 到设备上(如果目标设备已经安装则跳过)

先挂载镜像所在分区,再执行安装命令。注意:老旧系统可能需要使用grub2-install命令。

sudo mount /dev/sdb1 /mnt
sudo grub-install /dev/sdb --boot-directory=/mnt

三、配置

默认没有配置文件,我这里给出一个:

set UUID=xxxxxxx
set ver=2014.01.05
set label=ARCH_201401
set isofile="/archlinux-$ver-dual.iso"

insmod part_gpt
insmod part_msdos
if [ -s $prefix/grubenv ]; then
  load_env
fi
if [ "${next_entry}" ] ; then
  set default="${next_entry}"
  set next_entry=
  save_env next_entry
  set boot_once=true
else
  set default="0"
fi

if [ x"${feature_menuentry_id}" = xy ]; then
  menuentry_id_option="--id"
else
  menuentry_id_option=""
fi

export menuentry_id_option

if [ "${prev_saved_entry}" ]; then
  set saved_entry="${prev_saved_entry}"
  save_env saved_entry
  set prev_saved_entry=
  save_env prev_saved_entry
  set boot_once=true
fi

function savedefault {
if [ -z "${boot_once}" ]; then
  saved_entry="${chosen}"
  save_env saved_entry
fi
}

function load_video {
if [ x$feature_all_video_module = xy ]; then
  insmod all_video
else
  insmod efi_gop
  insmod efi_uga
  insmod ieee1275_fb
  insmod vbe
  insmod vga
  insmod video_bochs
  insmod video_cirrus
fi
}

set menu_color_normal=light-blue/black
set menu_color_highlight=light-cyan/blue

if [ x$feature_default_font_path = xy ] ; then
  font=unicode
else
  insmod part_msdos
  insmod ext2
  # 填入自己那个分区的 UUID
  search --no-floppy --fs-uuid --set=root $UUID
  font="/grub/fonts/unicode.pf2"
fi

if loadfont $font ; then
  set gfxmode=auto
  load_video
  insmod gfxterm
  set locale_dir=$prefix/locale
  set lang=zh_CN
  insmod gettext
fi
terminal_input console
terminal_output gfxterm
set timeout=500

menuentry "Archlinux Live ISO $ver (x86_64)" {
  loopback loop $isofile
  linux (loop)/arch/boot/x86_64/vmlinuz archisolabel=$label img_dev=/dev/disk/by-uuid/$UUID img_loop=$isofile earlymodules=loop
  initrd (loop)/arch/boot/x86_64/archiso.img
}

注意前几行。把UUID设置成自己 grub 安装的那个分区的 UUID。UUID 可以使用命令lsblk -o +UUID取得。ver设置成自己所使用的安装镜像中间的日期部分,label那里有相应的年份和月份,相应地修改一下。然后保存为/mnt/grub/grub.cfg就可以了。isofile指向自己放 ISO 文件的地方,路径也是相对于挂载点的。

四、外部链接

  1. 雪月秋水的使用GRUB2引导ISO镜像
Category: Linux | Tags: grub grub2 Arch Linux
12
29
2013
30

rsync+btrfs+dm-crypt 备份整个系统

生成目录!

目标:增量式备份整个系统

怎么做到增量呢?rsync + btrfs 快照。其实只用 rsync 也是可以做到增量式的1,但是支持子卷的 btrfs 可以做得更好:

  1. 快速删除旧的备份
  2. 更简单的备份逻辑
  3. 子卷可以设置成只读(这是个很重要的优点哦~)
  4. btrfs 支持压缩。系统里有好多文本文件的,遇到压缩效果不好的文件 btrfs 会自动放弃压缩

为什么要备份整个系统呢?——因为配置一个高度定制化的系统麻烦啊,只备份部分数据的话还可能漏掉需要的文件。另一个优点是可以直接启动到某个备份

备份了整个系统,包括各种公开或者隐私的数据,一堆 cookies 和帐号配置,邮件和聊天记录等。难道就不需要加密一下下吗?于是,在 btrfs 之下再加一层 dm-crypt 加密。

介绍完毕,下边进入正题。

准备工作

首先,需要一个足够新的 Linux 内核,因为 btrfs 还是「实验特性」,每个版本都会有大量改进。如果用比较旧的内核就有可能出事。我用的是 3.12.6 版本。其次,安装 rsync 和 cryptsetup。

当然还要准备硬件:一块希捷 BackupPlus 1T USB 3.0 移动硬盘,以及一枚Express Card 34mm 转 USB 3.0 扩展卡,因为我的笔记本没有 3.0 的接口。注意使用 USB 3.0 扩展卡,内核需要载入 pciehp 模块,否则会出现不能识别 3.0 的设备或者后续接上去的设备的情况。Arch 官方内核将这个模块直接编译进内核了,而我自己编译的很不幸没有,只好重新编译了下内核。

PS: 这俩家伙一起配合工作,写入峰值能达到 110MiB/s,比我笔记本自身的硬盘还要快。

然后是分区、格式化。我使用了 GPT 分区表。为了安装 grub 以便启动,最好在开头分配 2M 空间给 grub 使用,不然会很麻烦2。记得给这个分区 bios_grub 标志(GParted「管理标志」里勾上即可)。下一个分区是 ext4 格式的启动分区。我会在这里放一个 Arch Linux Live 系统用于维护任务,以及用于启动到备份的内核和 initramfs。因为备份的分区会被加密,所以必须把内核和 initramfs 放在另外的地方。接下来的一个分区放加密过的备份数据用的。

像这样初始化加密分区:

cryptsetup luksFormat /dev/sdc3

密码要长,但也一定要记住密码,因为除了穷举外是没有办法恢复的。

初始化完毕之后就可以使用密码打开该设备了:

cryptsetup open /dev/sdc3 lilybackup

最后的参数是一个名字,它会是解密后的设备在 /dev/mapper 下的文件名。

如果一切完毕,要记得(在卸载文件系统之后)关闭该设备:

cryptsetup luksClose lilybackup

dm-crypt 是块设备级的加密。我们还要在其上建立文件系统:

mkfs.btrfs /dev/mapper/lilybackup

然后挂载之,并建立相应的目录和子卷结构。比如我的:

* backup (dir)
  * home (dir)
    * current (subvol, rw)
    * 20131016_1423 (subvol, ro)
    * 20131116_2012 (subvol, ro)
    * ...
  * root (dir)
    * current (subvol, rw)
    * 20131016_1821 (subvol, ro)
    * 20131116_2128 (subvol, ro)
    * ...
* run, for boot up directly, with edited /etc/fstab (dir)
  * home (dir)
    * 20131116 (subvol, rw)
    * ...
  * root (dir)
    * 20131116 (subvol, rw)
    * ...
* etc, store information and scripts (subvol, rw)

我把备份数据放到 backup 目录下,/ 和主目录 /home/lilydjwg 分开备份的。每个备份是使用日期和时间命名的快照子卷。除了用于每次同步的 current 目录外其它的子卷都是只读的,以免被意外修改。在 run 目录下是用于直接运行的,可写。这些可以按需建立。

开始备份

这是我备份 / 使用的脚本。是一个 zsh 脚本,这样可以避免 bash 中特殊字符可能带来的问题,虽然 bash 有 shellcheck 可以静态分析出可能有问题的地方。

这个脚本带两到三个参数。第一个是 / 的位置,因为我一般会直接从运行的系统执行备份,但也有可能使用另外的维护系统(比如系统滚挂掉的时候)。第三个参数是用于确认操作的。不加它的话会以 --dry-run 参数来运行 rsync。rsync 很复杂,所以最好先演习一遍以避免不小心手抖了做错事 =w=

为了避免日后对照着 rsync 手册来揣摸每个单字母选项的意义,我在这里全部使用了选项的完整形式。反正我是 zsh 用户,那么长的命令中大部分字符都是 zsh 给我补全出来的 =w=

#!/bin/zsh -e

cd $(dirname $0)

if [[ $# -lt 2 || $# -gt 3 ]]; then
  echo "usage: $0 SRC_DIR DEST_DIR [-w]"
  exit 1
fi

src=$1
dest=$2
doit=$3

if [[ $doit == -w ]]; then
  dry=
else
  dry='-n'
fi

rsync --archive --one-file-system --inplace --hard-links \
  --human-readable --numeric-ids --delete --delete-excluded \
  --acls --xattrs --sparse \
  --itemize-changes --verbose --progress \
  --exclude='*~' --exclude=__pycache__ \
  --exclude-from=root.exclude \
  $src $dest $dry

比较重要的几个 rsync 选项:

--archive
我们要备份,所以请保留所有信息
--one-file-system
只备份这个文件系统的内容,不要跑到 /sys 啊 /proc 啊 /dev 啊 /tmp 这类目录里去了。这也省得自己手动排除
--numeric-ids
文件的所有者信息使用数字而不要解析成用户名/组名。避免在跨系统使用时出差错
--exclude-from=root.exclude
root.exclude文件中读取额外的排除列表
--acls --xattrs
保留文件 ACL 和扩展属性

我发现的 / 里需要排除的目录如下:

/var/cache/*/*
/var/tmp/
/var/abs/local/
/var/lib/mongodb/journal/

其中第一项写成那样是因为,我要保留 /var/cache 下的一级目录。

主目录的备份是类似的过程,只是更加复杂罢了。当我写我的主目录的备份脚本的时候,深切地体会到有圣人说过的一句话——过早的优化是万恶之源。因为我使用 eCryptfs 加密主目录时为了避免可以公开的文件被加密造成性能损失,做了一系列的软链接。它们一直在给我带来各种小麻烦和不爽……

注意这些脚本要以 root 的身份运行。待所有备份脚本跑完之后,对那个 current 子卷做一个只读快照就好了:

sudo btrfs subvolume snapshot -r current $(date +'%Y%m%d_%H%M')

下次要更新备份时是一样的步骤:跑同步脚本,创建新快照。第一次同步会比较慢,跑了一个多小时吧。后边的增量备份就比较快了,十几分钟就好。

从备份启动

要启动,首先把 grub 装过去。把 Arch Linux live 系统的配置写好,当然还有启动备份系统的配置,如下:

search --no-floppy --fs-uuid --set=root 090dcc64-2b6d-421c-8ef6-2ab3321aec62

menuentry "Archlinux-2013.12.01-dual.iso (x86_64)" {
    load_video
    set gfxpayload=keep
    insmod gzio
    insmod ext2

    set isofile="/images/archlinux-2013.12.01-dual.iso"
    echo "Setup loop device..."
    loopback loop $isofile
    echo "Loading kernel..."
    linux (loop)/arch/boot/x86_64/vmlinuz archisolabel=ARCH_201312 img_dev=/dev/disk/by-label/lilyboot img_loop=$isofile earlymodules=loop
    echo "Loading initrd..."
    initrd (loop)/arch/boot/x86_64/archiso.img
}

menuentry "Archlinux-2013.12.01-dual.iso (i686)" {
    load_video
    set gfxpayload=keep
    insmod gzio
    insmod ext2

    set isofile="/images/archlinux-2013.12.01-dual.iso"
    echo "Setup loop device..."
    loopback loop $isofile
    echo "Loading kernel..."
    linux (loop)/arch/boot/i686/vmlinuz archisolabel=ARCH_201312 img_dev=/dev/disk/by-label/lilyboot img_loop=$isofile earlymodules=loop
    echo "Loading initrd..."
    initrd (loop)/arch/boot/i686/archiso.img
}

set ver=3.12.6
menuentry "Arch Linux $ver backup" {
    load_video
    set gfxpayload=keep
    insmod gzio
    insmod ext2

    echo    'Loading Linux kernel ...'
    linux   /boot/vmlinuz-linux-lily-$ver root=/dev/mapper/lilybackup rw cryptdevice=/dev/disk/by-uuid/815d01ea-6390-460f-8c82-84c9e9497423:lilybackup rootflags=compress=lzo,subvolid=0 break=postmount
    echo    'Loading initramfs...'
    initrd  /boot/initramfs-$ver-backup.img
}

各个设备的卷标、UUID 和文件路径自己调整。最后一项需要的文件在后边准备,先介绍一下几个参数:

root
根分区所在的设备。是解密后的设备路径或者用 UUID 也可以。不过没关系的,这里不会有冲突的
cryptdevice
如果使用密码(而不是密钥文件)加密的话,这里是冒号分隔的两个参数:你的加密设备是哪个文件,以及它解密之后叫什么名字。
rootflags
这个是给我们的 btrfs 用的。指定要启用 lzo 算法压缩,使用根子卷。实际上根子卷里不是 Linux 系统的根。这里我只是让脚本把它挂载到/new_root上而已,脚本会因为找不到/sbin/init而进入一个 shell 的
break=postmount
即使根没有问题,也请在挂载好它之后给我一个 shell,我可能需要做一些调整

内核很简单,直接 cp 过去就好了。initramfs 要另外生成。这是我用来生成的 mkinitcpio.conf.crypt 文件:

MODULES="btrfs"
BINARIES="/usr/bin/btrfs"
FILES=""
HOOKS="base udev autodetect modconf block encrypt filesystems keyboard fsck shutdown"
COMPRESSION="xz"

重要的地方:内核模块 btrfs 一定是要的,另外我还需要 btrfs 程序来操作子卷。在 HOOKS 数组的 filesystems 前添加了 encrypt,用于在启动时询问密码并解码根分区。

我还准备添加 vi 程序来着,但是它说终端类型不认识,还说 /var/tmp 目录不存在。于是索性把自己静态链接的 vim 扔到内核一块去了。Vim 内建常见终端类型的数据,不那么挑剔的。zsh 所需要的文件太多,也放弃了。

然后使用 mkinitcpio 命令生成 initramfs 镜像:

sudo mkinitcpio -c mkinitcpio.conf.crypt -g initramfs-backup.img

然后把生成的文件复制到启动分区的相应路径下。

注意:如果你在 Arch Linux live 系统中为另外的内核生成该 initramfs,要指定内核和内核模块路径的根。一定不要将内核模块所在的目录软链接到/lib/modules,那样 mkinitcpio 不会添加任何块设备的内核模块的。我使用的命令如下:

mkinitcpio --kernel /run/archiso/img_dev/boot/vmlinuz-linux-lily-3.12.6 -r /mnt/backup/root/20131227_2044 --config mkinitcpio.conf -g /run/archiso/img_dev/boot/initramfs-3.12.6-backup.img

文件准备完毕,就可以启动过去了。注意我没有在备份分区的 run 目录下建立子卷,因为我准备进入 initramfs 之后再建立它们。

PS: 因为 BIOS 不支持,所以必须从 USB 2.0 来启动。在 Linux 内核启动的时候,可以将移动硬盘接到 USB 3.0 扩展卡上。具体时机是,initramfs 载入完毕,内核开始打印日志的时候。

进入备份系统

启动之后,会进入 initramfs 的 shell。在这个没有任务管理的 ash 中,使用 btrfs 命令在 /new_root/run 目录下建立新的子卷,注意不要加 -r 这个表示只读的选项了:

btrfs subvolume snapshot ../backup/root/20131016_1423 root/20131016
btrfs subvolume snapshot ../backup/home/20131016_1423 home/20131016

因为文件系统树的挂载结构变了,所以得拿准备好的 vim(或者 vi,如果你没准备 vim 的话)去编辑 root/20131016/etc/fstab 文件,将那些不会成功的挂载项都去掉,添加新的正确的项。PS: 如果使用 vim 的话,记得进去先set nocp一下,不然会是兼容模式,和 vi 一样只能撒消一步的。

/dev/mapper/lilybackup  /       btrfs   rw,relatime,compress=lzo,subvol=run/root/xxx     0 0
/dev/mapper/lilybackup  /home/lilydjwg  btrfs   rw,relatime,compress=lzo,subvol=run/home/xxx     0 0

然后 cd /,卸载 /new_root 并重新以子卷挂载之:

cd /
umount /new_root
mount -o compress=lzo,subvol=run/root/20131016 /dev/mapper/lilybackup /new_root

如果是因为找不到 /sbin/init 而进来这个 shell 的,那么就tail /init,最后那行是需要执行的命令(当然有些修改):

exec env -i "TERM=$TERM" /usr/bin/switch_root /new_root /sbin/init

如果是因为break=postmount参数而进来的,直接按Ctrl-D退出 shell 即可。

启动会继续进行,systemd 启动了,各种服务陆续启动中~~

如果很不幸地,忘记修改/etc/fstab了,或者有错,那么 systemd 会毫不留情地「Welcome to emergency shell」。不过现在更正也为时未晚。在编辑完 fstab 之后,要先执行下systemctl daemon-reload再退出那个 emergency shell。

接下来应该能一路顺利地到达指定时间的系统啦 =w=

时间机器打造完成哦耶~~

参考资料

Category: Linux | Tags: linux grub grub2 btrfs Arch Linux
7
10
2013
4

grub2 引导 openSUSE 安装镜像

想安装 openSUSE 12.2,但是目标机器没有光驱,亦没有可用的能够容纳下 DVD 镜像的 U 盘。尝试 dd 镜像到 U 盘,报告找不到光驱还是什么的,启动失败,自动重启。 官方 Wiki 上 http://en.opensuse.org/Installation_without_CD 这个页面已经被删除。其它页面只有如何将 ISO 镜像弄到 U 盘上的说明,没有说明如何正确启动之。grub2 带内核参数install=hd:$isofile失败。这个据说只对 DVD 镜像有效。

最终,像很早之前那样阅读init脚本后,终于得出正确的启动方法:

menuentry "openSUSE 12.2 KDE LiveCD x86_64" {
    set isofile="/images/openSUSE-12.2-KDE-LiveCD-x86_64.iso"
    echo "Setup loop device..."
    loopback loop $isofile
    echo "Loading kernel..."
    linux (loop)/boot/x86_64/loader/linux isofrom=/dev/disk/by-label/4lin:$isofile
    echo "Loading initrd..."
    initrd (loop)/boot/x86_64/loader/initrd
}

其中,isofrom指定 ISO 文件所在的设备和路径,以冒号分隔。如果没有写对的话,将得到Failed to find MBR identifier !错误。

2013年12月22日更新:对于 openSUSE 13.1,其引导命令应该这么写:

menuentry "openSUSE 13.1 KDE Live x86_64 (zh_CN)" {
	set isofile="/images/openSUSE-13.1-KDE-Live-x86_64.iso"
	echo "Setup loop device..."
	loopback loop $isofile
	echo "Loading kernel..."
	linux (loop)/boot/x86_64/loader/linux isofrom_device=/dev/disk/by-label/4lin isofrom_system=$isofile LANG=zh_CN.UTF-8
	echo "Loading initrd..."
	initrd (loop)/boot/x86_64/loader/initrd
}
Category: Linux | Tags: linux grub grub2
10
24
2010
4

把Parted Magic装到移动硬盘

首先,不知道Parted Magic为何物的童鞋请先移步这里

之前折腾了Gparted live,然后看到了muzuiget童鞋的留言,决定有时间还是折腾下。首先去官网,结果官网说

As of Parted Magic version 5.3 the USB zip has been discontinued. We are only supporting Unetbootin as the method for booting Parted Magic from a USB drive.

Note: If you still want to do it manually, extract the files from the ISO image and execute the syslinux commands. If you know what you are doing this shouldn't be an issue.

好吧,我在看到第一段,在失望之余,“note”到了后面那段。

fuseiso ~/dl/pmagic-5.5.iso pm

我不喜欢需要根用户权限的mount,所以有一天在新立得里翻到了这个fuseiso,现在用上了。

里边就两个目录,boot和pmagic。pmagic比较简单,先说说它。

它下面也就三项,内核bzImage,initrd文件initramfs,和一个可以用来自定义其模块的目录pmodules,目前只包含pmagic-5.5.sqfs,file之可以知道它是一个Squashfs filesystem。

boot下东西有点多,还好我需要的很少,就是boot/isolinux/isolinux.cfg这个isolinux的配置文件了,里面有需要传给内核的参数,有好几个选项,基本上是这样子的:

LINUX /pmagic/bzImage
INITRD /pmagic/initramfs
APPEND edd=off noapic load_ramdisk=1 prompt_ramdisk=0 rw vga=788 loglevel=0 max_loop=256

APPEND那行就是内核的参数了。于是,grub2的参数应该这么写:

menuentry "Parted Magic (中文)" {
	set root="(hd1,1)"
	echo "Loading kernel..."
	linux /boot/pmagic/bzImage edd=off noapic load_ramdisk=1 prompt_ramdisk=0 rw vga=791 loglevel=0 max_loop=256 keymap=us zh_CN
	echo "Loading initrd..."
	initrd /boot/pmagic/initramfs
}

vga参数我自然要改下的,呵呵。

但是——

内核加载完毕之后它就告诉我找不到pmagic-5.5.sqfs文件……看来需要把它放到分区的/pmagic/pmodules下才行啊。可是我又不是做LiveUSB,是移动硬盘耶,不可能随随便便就把整个分区弄乱的。

于是——

file一下那个initramfs可知它是gzip压缩过的。

zcat initramfs > ../../initrd

然后继续file之,cpio文件。那就继续解包吧:

cat initrd|cpio -i

其实两步是可以一起做的。但没有file以及man cpio之前谁知道呢。

然后我很惊奇地看到一个名为init的可执行文件躺在当前目录下!我都没file,直接把它扔给Vim了。接下来就是看shell脚本了。

find_pmagic () {

   if [ ! -e /test_mnt/${directory}/pmagic/pmodules/pmagic-$VERSION.sqfs ]; then
      umount /test_mnt &> /dev/null
      return
   fi

关键是${directory}变量。继续寻找。。。

for i in $(cat /proc/cmdline); do
   case $i in
      directory=*)     directory=$(get_opt $i) ;;
      iso_location=*)  iso_location=$(get_opt $i)  ;;
      iso_filename=*)  ISO_VERSION=$(get_opt $i) ;;
      root=*)          root=$(get_opt $i)  ;;
      label=*)         label=$(get_opt $i)  ;;
      uuid=*)          uuid=$(get_opt $i) ;;
   esac
done

OK,原来是内核参数,于是在linux那行后面再加上directory=other,重启OK!

10
7
2010
3

grub2不显示自定义菜单项的解决

今天弄gparted的live版,在虚拟机里按照这里的说明配置grub2,却始终不见自己新加的菜单项,只好每次尝试启动gparted时手动输入那一串长长的指令,郁闷啊。。。

Google了半天,用中文只能找到些grub2的配置说明的文章,而且代码十分地不整洁,光看到页面鼠标就不由自主地中键点击标签页标题了。于是换用英文,搜索“grub2 menuentry not display”,也没什么有针对性的结果,于是我点了第一项,是Ubuntu的文档。看了一小会儿后,终于有了重大发现——

  • Do not leave empty spaces at the end of lines

再看看自己复制过来的配置,果然在最后一个}后多了一个空格!

但我还是有点纳闷:为什么行末多了一个空格就不行了呢?也没有错误或警告。。。

Category: Linux | Tags: linux grub

Mastodon | Theme: Aeros 2.0 by TheBuckmaker.com