LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 2161|回复: 26

将Arch启动后的修改保存到loop文件

[复制链接]
发表于 2011-4-14 17:08:12 | 显示全部楼层 |阅读模式
[color="Blue"]修订记录:
[color="Blue"]
3. 2011-04-15 添加badblocks, 以确保mkfs.ext4完美执行;
2. 2011-04-14 做成PKGBUILD,提交到aur上为 "save2loop", 大家可以 yaourt -S save2loop 来安装
1. 2011-04-14 初放  已经在archlive中测试


[color="Black"]继前一篇 《将Arch GNU/Linux 安装到磁盘文件(loop)》 之后,结合archlive的启动脚本重写, 再次改成普适启动脚本。

[color="Blue"]用途:
[color="Black"]1、安装到loop的所有功能:不让分区表太复杂等。。。支持将loop放于ntfs分区;
2、如果想尝试gnome3,又不会当工作系统, 可以将gnome3安装到changes loop文件中, 不想用gnome3的时候,删除对应loop文件,彻底。。。
3、也可以将修改保存到内存,这样就实现了硬盘上的live系统功能,“只读”, 重启,修改消失,不产生任何危害。。。



[color="Blue"]实现步骤:
[color="Black"]1、如果需要将主系统放在loop中,参考 《将Arch GNU/Linux 安装到磁盘文件(loop)》来制作主loop文件, 此步骤非必须,主系统不一定要在loop设备上;

2、将如下脚本保存到 /lib/initcpio/hooks/save2loop:
  1. # Update by Carbon Jiao in 2011-04-20
  2. export DEBUG_IS_ENABLED
  3. MEMORY="/memory"
  4. CHANGES="$MEMORY/changes"
  5. IMAGES="$MEMORY/images"
  6. XINO="$MEMORY/xino"
  7. UNION="/union"
  8. if [ -z $arch ]; then
  9.         export ARCH="$(uname -m)"
  10. else
  11.         export ARCH="$arch"
  12. fi
  13. ###################### 格式化 日志 提示 输出 #################
  14. BOOT_LOG=/var/log/livedbg
  15. [ -e $(dirname ${BOOT_LOG}) ] || mkdir -p $(dirname ${BOOT_LOG})
  16. # global variable
  17. if [ "$break" = "y" ] || [ "$debug" = "y" ]; then
  18.         DEBUG_IS_ENABLED="y"
  19. fi
  20. RST="\033[1;0m"
  21. W="\033[0;37m"
  22. EMR="\033[1;31m"
  23. EMY="\033[1;33m"
  24. EMB="\033[1;34m"
  25. hl() { echo -ne "${W}$@${RST}"; }
  26. #输出到日志文件
  27. log()
  28. {
  29.    echo "$@" 2>/dev/null >>${BOOT_LOG}
  30. }
  31. # echogreen will echo $@ in green color
  32. # $1 = text
  33. echogreen()
  34. {
  35.    echo -ne " $EMB""$@""$RST"
  36. }
  37. # 显示信息,并记录到日志文件
  38. echolog()
  39. {
  40.    if [ "$1" != "" ]; then
  41.       echogreen "* "
  42.       log "LOOP:" "$@"
  43.       echo "$@"
  44.    fi
  45. }
  46. # debug 模式下才显示日志,并记录到日志文件
  47. debug_log()
  48. {
  49.    if [ "$DEBUG_IS_ENABLED" ]; then
  50.       echo "  - debug: $*" >&2
  51.       log "- debug: $*"
  52.    fi
  53. }
  54. # 交互命令行
  55. interactive_shell() {
  56.    echo "====="
  57.    if [ "$cn" = "y" ]; then
  58.         echo ":: Ctrl+D 继续启动进程..."
  59.    else
  60.         echo ":: Press Ctrl+D to continue booting..."
  61.    fi
  62.    PS1='[ramfs \W]\$ ' /bin/sh -i 2>/dev/null
  63. }
  64. error () {
  65.     local message append
  66.     if [ $# -eq 2 ] && [ "$1" = "-n" ]; then
  67.         message="$2"
  68.         append=""
  69.     else
  70.         message="$@"
  71.         append="echo"
  72.     fi
  73.     echo -ne " $EMR*$RST "; hl "$message"; $append
  74.     interactive_shell
  75. }
  76. warn() {
  77.     if [ $# -eq 2 ] && [ "$1" = "-n" ]; then
  78.         echo -ne " $EMY*$RST "; hl "$2"
  79.     else
  80.         echo -ne " $EMY*$RST "; hl "$@"; echo
  81.     fi
  82. }
  83. ####################################
  84. # 获取 $1 对应硬件设备
  85. # 设备不存在则返回空
  86. # 获取 $1 对应硬件设备
  87. # 设备不存在则返回空
  88. real_device()
  89. {
  90.     #debug_log "real_device" "$*"
  91.     device=$1
  92.     while true; do
  93.         if [ -e $device ]; then break; fi
  94.         device=$(dirname $device)
  95.     done
  96.     if [ "${#device}" -eq 1 ] || [ "$device" = "/dev" ]; then
  97.         device=""
  98.     fi
  99.     debug_log "real_device" "$*" "is $device"
  100.     echo $device   
  101. }
  102. # 获取 $1 对应分区 /dev名
  103. real_device_name()
  104. {
  105.     device=$(real_device $1)
  106.     if [ "x$device" != "x" ]; then
  107.         if [ "x$(readlink $device)" != "x" ]; then
  108.                 device="/dev/$(basename $(readlink $device))"
  109.         fi
  110.     fi
  111.     debug_log "real_device_name" "$*" "is $device"
  112.     echo $device
  113. }
  114. # 将文件/设备 $1 挂载到 $2
  115. # $3 挂载选项  (可以为空)
  116. mount_file()
  117. {
  118.     debug_log "ARCH=$ARCH mount_file" "$*"
  119.     device=$1
  120.     target=$2
  121.     mountopts=$3
  122.     if [ ! -d $target ]; then mkdir -p $target; fi
  123.     if [ "$cn" = "y" ]; then
  124.         echolog "挂载 $device 到 $target ..."
  125.     else
  126.         echolog "Mount $device to $target ..."
  127.     fi
  128.     fstype=$(blkid -u filesystem -o value -s TYPE -p $device)
  129.     if [ "x$fstype" != "x" ]; then
  130.         fsopt="-t $fstype"
  131.         if [ "${readwrite}" = "no" ]; then rwopt="ro"; else rwopt="rw"; fi
  132.         MOUNT="mount"
  133.         case $fstype in
  134.                 ntfs)   MOUNT="mount.ntfs-3g"
  135.                         rwopt="rw"
  136.                         fsopt=""
  137.                         ;;
  138.                 vfat)   rwopt="rw"
  139.                         ;;
  140.                 squashfs|iso9660|udf) rwopt="ro"
  141.                         ;;
  142.                 esac
  143.         if [ "x$mountopts" != "x" ]; then
  144.                 mountopts="-o $mountopts,$rwopt"
  145.         else
  146.                 mountopts="-o $rwopt"
  147.         fi
  148.         debug_log "$MOUNT $fsopt $mountopts $device $target"
  149.         $MOUNT $fsopt $mountopts $device $target 2>&1 >/dev/null
  150.         if [ $? -ne 0 ]; then
  151.                 if [ "$cn" = "y" ]; then
  152.                         error "挂载$device 到 $target失败"
  153.                 else
  154.                         error "Failed mounting $device to $target"
  155.                 fi
  156.         fi
  157.     fi
  158. }
  159. # 将$1中的设备(本地或者远程)挂载到$2
  160. # 将loop(如果存在)挂载体到$3
  161. # 如果 $1 已经挂载, 则将指定的loop挂载到$2
  162. device_mount_handler()
  163. {
  164.     debug_log "ARCH=$ARCH device_mount_handler" "$*"
  165.     local bootdevice
  166.     bootdevice=$1
  167.     case $bootdevice in
  168.         /dev/*)
  169.                 device=$(real_device $bootdevice)
  170.                 if [ "x$device" = "x" ]; then
  171.                         bootdevice=$(echo $bootdevice | sed "s|/dev/sd|/dev/hd|")
  172.                         device=$(real_device $bootdevice)
  173.                 fi
  174.                 if [ "x$device" = "x" ]; then
  175.                         bootdevice=$(echo $bootdevice | sed "s|/dev/hd|/dev/sd|")
  176.                         device=$(real_device $bootdevice)
  177.                 fi
  178.                 if [ ! -e $device ]; then
  179.                         if [ "$cn" = "y" ]; then
  180.                                 error "设备 $device 不存在"
  181.                         else
  182.                                 error "$device not exists"
  183.                         fi
  184.                 fi
  185.                 loopfile=$(echo $bootdevice | cut -b $((${#device}+1))-)
  186.                 ;;
  187.         label=*|LABEL=*)
  188.                 label=$(echo $bootdevice | cut -d "=" -f2 | cut -d "/" -f1)
  189.                 if [ -e /dev/disk/by-label/$label ]; then
  190.                         device="/dev/disk/by-label/$label"
  191.                 else
  192.                         if [ "$cn" = "y" ]; then
  193.                                 error "没有盘符为 $label 的设备..."
  194.                         else
  195.                                 error "No device as LABEL: $label ..."
  196.                         fi
  197.                 fi
  198.                 loopfile=$(echo $bootdevice | cut -b $((${#label}+7))-)
  199.                 ;;
  200.         uuid=*|UUID=*)
  201.                 uuid=$(echo $bootdevice | cut -d "=" -f2 | cut -d "/" -f1)
  202.                 uuid_lowercase="$(echo $uuid | tr [:upper:] [:lower:])"
  203.                 uuid_uppercase="$(echo $uuid | tr [:lower:] [:upper:])"
  204.                 if [ -e /dev/disk/by-uuid/${uuid_lowercase} ]; then
  205.                         uuid="${uuid_lowercase}"
  206.                 elif [ -e /dev/disk/by-uuid/${uuid_uppercase} ]; then
  207.                         uuid="${uuid_uppercase}"
  208.                 else
  209.                         if [ "$cn" = "y" ]; then
  210.                                 error "没有UUID为 $uuid 的设备..."
  211.                         else
  212.                                 error "No device as UUID: $uuid ..."
  213.                         fi
  214.                 fi
  215.                 device="/dev/disk/by-uuid/$uuid"
  216.                 loopfile=$(echo $bootdevice | cut -b $((${#uuid}+6))-)
  217.                 ;;
  218.         cifs=*|CIFS=*)
  219.                 #  real_root=cifs="//192.168.0.252/share" user="archlive" passwd="archlive"
  220.                 #  real_root=cifs="192.168.0.252/share" user="archlive" passwd="archlive"
  221.                 #  或者debian系列用法:real_root=cifs=[<server-ip>:]<root-dir>[,<nfs-options>]
  222.                 #      real_root=cifs=192.168.0.252:share,user=archlive,passwd=archlive
  223.                 if [ "x$(echo $bootdevice | grep ",")" = "x" ]; then
  224.                         cifs=$(echo $bootdevice | cut -d "=" -f2)
  225.                 else
  226.                         cifs=$(echo $bootdevice | cut -d "," -f1 | cut -d "=" -f2 | tr ":" "\/")
  227.                         user="$(echo $bootdevice | tr "\," "\n" | grep user | cut -d "=" -f2)"
  228.                         passwd="$(echo $bootdevice | tr "\," "\n" | grep pass | cut -d "=" -f2)"
  229.                 fi       
  230.                 modprobe_network_modules
  231.                 init_net $netdevice $essid $key
  232.                 mount_cifs $cifs /host $user $passwd
  233.                 ;;
  234.         nfs=*|NFS=*)
  235.                     #  real_root=nfs="//192.168.0.252/share" user="archlive" passwd="archlive"
  236.                     #  或者debian系列用法:real_root=nfs=[<server-ip>:]<root-dir>[,<nfs-options>]
  237.                 #      real_root=nfs=192.168.0.252:share,user=archlive,passwd=archlive
  238.                 if [ "x$(echo $bootdevice | grep ",")" = "x" ]; then
  239.                         nfs=$(echo $bootdevice | cut -d "=" -f2)
  240.                 else
  241.                         nfs=$(echo $bootdevice | cut -d "," -f1 | cut -d "=" -f2 | tr ":" "\/")
  242.                         nfs_opt="$(echo $bootdevice | cut -b $((${#nfs}+7))-)"
  243.                         nfs_opt="-o ${nfs_opt}"
  244.                 fi
  245.                 modprobe_network_modules
  246.                 modprobe nfs
  247.                 init_net $netdevice $essid $key
  248.                 export NFS="$(ipconfig $nfs | grep rootpath | awk -Frootpath: '{print $2}')"
  249.                 nfsmount ${NFS} /host
  250.                 ;;
  251.         pxe=*|PXE=*) ;;
  252.     esac
  253.     debug_log "device=$device loopfile=$loopfile"
  254.     if [ ! -e $device ] || [ "x$device" = "x" ]; then
  255.         if [ "$cn" = "y" ]; then
  256.                 error "设备 $bootdevice 不存在..."
  257.         else
  258.                 error "No device: $$bootdevice ..."
  259.         fi
  260.     fi
  261.     # 将uuid label对应设备转换到/dev/sda...
  262.     device=$(real_device_name $device)
  263.     #if [ "x$(readlink $device)" != "x" ]; then
  264.         #device="/dev/$(basename $(readlink $device))"
  265.     #fi
  266.     debug_log "device=$device loopfile=$loopfile"
  267.     mnt=$(grep "$device " /proc/mounts | cut -d " " -f2)
  268.     if [ "x$mnt" != "x" ]; then
  269.         debug_log "$device already mounted to $mnt..."mount_file
  270.         # 设备已经挂载
  271.         if [ "$mnt" != $2 ]; then
  272.                 mount -o bind $mnt $2 2>&1 >/dev/null
  273.         fi
  274.     else
  275.         #device_mount $device $2
  276.         mount_file $device $2
  277.     fi
  278.     if [ "x$loopfile" != "x" ]; then
  279.         if [ -e $2/$loopfile ]; then
  280.                 modprobe loop
  281.                 mount_file $2/$loopfile $3
  282.         else
  283.                 if [ "$cn" = "y" ]; then
  284.                         error "$device$loopfile 不存在..."
  285.                 else
  286.                         error "$device$loopfile not exist..."
  287.                 fi
  288.         fi
  289.     fi
  290. }
  291. # 创建loop设备文件
  292. # $1 设备文件名(含路径)
  293. # $2 大小 (可选)
  294. creat_loop()
  295. {
  296.     debug_log "creat_loop" "$*" "size=$newloopsize"
  297.     loopfile=$1
  298.     [ "x$newloopsize" = "x" ] && eval newloopsize=2000
  299.     if [ "x$2" != "x" ]; then
  300.         newloopsize=$2
  301.     fi
  302.     case $newloopsize in
  303.         *M|*m) bs=1M; count=$(echo $newloopsize | tr [a-zA-Z] " ") ;;
  304.         *G|*g) bs=1M;
  305.                 count=$(echo $newloopsize | tr [a-zA-Z] " ");
  306.                 eval count=$(($count*1000)) ;;
  307.         *) bs=1M; count=$newloopsize ;;
  308.     esac
  309.     if [ "$cn" = "y" ]; then
  310.         echolog "创建loop设备文件$loopfile, 大小 $newloopsize"
  311.     else
  312.         echolog "Creat loop file $loopfile, size $newloopsize"
  313.     fi
  314.     [ -d $(dirname $loopfile) ] || mkdir -p $(dirname $loopfile)
  315.     [ -e /etc/mtab ] || ln -sf /proc/mounts /etc/mtab
  316.     dd if=/dev/zero of=$loopfile bs=$bs count=$count 2>&1 >/dev/null
  317.     echo y | mkfs.ext4 -c $loopfile 2>&1 >/dev/null
  318.     debug_log "Create loop file finished."
  319.     debug_shell
  320. }
  321. # 判断 $1 是否可用
  322. # return 0 可用
  323. # return 1 不可写
  324. # return 2 可写,不兼容posix
  325. is_usable()
  326. {
  327.     debug_log "is_usable" "$*"
  328.     touch $1/empty 2>/dev/null && rm -f $1/empty 2>/dev/null
  329.     if [ $? -ne 0 ]; then
  330.         echo 1
  331.     else
  332.         touch $1/.empty1 && \
  333.         ln -sf $1/.empty1 $1/.empty2 2>/dev/null && \
  334.         chmod +x $1/.empty1 2>/dev/null  && \
  335.         test -x $1/.empty1 && \
  336.         chmod -x $1/.empty1 2>/dev/null  && \
  337.         test ! -x $1/.empty1 && \
  338.         rm $1/.empty1 $1/.empty2 2>/dev/null
  339.         if [ $? -ne 0 ]; then
  340.                 echo 2
  341.         else
  342.                 echo 0
  343.         fi
  344.     fi       
  345. }
  346. # 将保存修改的介质挂载到$1
  347. mount_changes()
  348. {
  349.     debug_log "mount_changes" "$*"
  350.     local use_memory
  351.     export loopchangefile
  352.     export CHANGE_HOST
  353.     export new_create_loop
  354.      # 将xino文件存储在内存, 更快速、安全
  355.     [ -d $XINO ] || mkdir -p $XINO
  356.     mount -n -t tmpfs tmpfs $XINO
  357.     [ -d $CHANGES ] || mkdir -p $CHANGES
  358.     use_memory="n"
  359.     if [ "x$changes" != "x" ]; then
  360.         # 挂载命令行参数 changes 指定的设备/文件保存修改
  361.         # changes 指定办法类似real_root
  362.         # changes=/dev/sda1/Archlive/changes.img
  363.         # changes=label=C/Archlive/changes.img
  364.         # changes=uuid=047C-F52A/Archlive/changes.img
  365.         # changes=changes.img  #跟real_root 或者 root 同目录
  366.         if [ "x${newloopsize}" != "x" ] || [ "x${new_loop}" != "x" ] || [ "x${newloop}" != "x" ]; then
  367.                 new_create_loop=y
  368.         else
  369.                 new_create_loop=n
  370.         fi
  371.         debug_log "Create loop ?  $new_create_loop "
  372.         change_host=$(real_device_name $changes)
  373.         if [ "x${change_host}" != "x" ]; then
  374.                 # changes 指定了详细设备、目录
  375.                 CHANGE_HOST="$(cat /proc/mounts | grep $change_host | head -n1 | cut -d " " -f2)"
  376.                 if [ "x${CHANGE_HOST}" = "x" ]; then
  377.                         # changes 对应设备还未挂载
  378.                         if mount_file ${change_host} /change_host ; then
  379.                                 CHANGE_HOST="/change_host"
  380.                         else
  381.                                 eval "use_memory=y"
  382.                         fi
  383.                 fi
  384.                 loopchangefile="${CHANGE_HOST}$(echo $changes | cut -b $((${#change_host}+1))-)"
  385.         elif [ -d $host ]; then
  386.                 # changes 指定了相对路径(相对于root/real_root指定设备)
  387.                 CHANGE_HOST="$host"
  388.                 loopchangefile="${CHANGE_HOST}/$changes"
  389.         else
  390.                 if [ "$cn" = "y" ]; then
  391.                         warn "指定的 $changes 无效,使用内存"
  392.                 else
  393.                         warn "Wrong $changes pointed, use memory"
  394.                 fi
  395.                 eval "use_memory=y"
  396.         fi
  397.         debug_log "loopchangefile=$loopchangefile"
  398.         [ -e /tmp/new_loop ] && rm -f /tmp/new_loop
  399.         if [ ! -e $loopchangefile ] && [ "$new_create_loop" = "n" ]; then
  400.                 if [ "$cn" = "y" ]; then
  401.                         warn "$loopchangefile 不存在, \n   如果要创建(ext4格式,默认2000M, 请确保有足够空间),\
  402.                                 \n    则输入如下命令:\n    touch /tmp/new_loop \
  403.                                 \n    如果要设置大小为4G, 则输入如下命令:\
  404.                                 \n    echo size=4000M >/tmp/new_loop"
  405.                 else
  406.                         warn "No exits $loopchangefile, you can input below command to create a new one\
  407.                                 \n    (default as ext4, 2000M, sure have enough free space):\
  408.                                 \n    touch /tmp/new_loop \
  409.                                 \n    enter below command to create a 4G loop file:
  410.                                 \n    echo size=4000M >/tmp/new_loop"
  411.                 fi
  412.                 interactive_shell
  413.         fi
  414.         if [ -e /tmp/new_loop ]; then
  415.                 eval "new_create_loop=y"
  416.                 size=$(grep "size" /tmp/new_loop | cut -d "=" -f2)
  417.         fi
  418.         if [ "${new_create_loop}" = "y" ]; then
  419.                 if ! creat_loop $loopchangefile $size; then
  420.                         if [ "$cn" = "y" ]; then
  421.                                 warn "创建loop $changes 失败,使用内存"
  422.                         else
  423.                                 warn "Failed to create loop: $changes"
  424.                         fi
  425.                         eval "use_memory=y"
  426.                 fi
  427.         else
  428.                 if [ "$cn" = "y" ]; then
  429.                         warn "$loopchangefile 不存在,也无指令要求新建,使用内存"
  430.                 else
  431.                         warn "No exits $loopchangefile, also no command to create one, use memory."
  432.                 fi
  433.                 eval "use_memory=y"
  434.         fi
  435.         if [ "$use_memory" != "y" ]; then
  436.                 if mount_file $loopchangefile $CHANGES ; then
  437.                         if [ "$cn" = "y" ]; then
  438.                                 echolog "使用 $loopchangefile 保存修改..."
  439.                         else
  440.                                 echolog "Use $loopchangefile to save changes..."
  441.                         fi
  442.                 else
  443.                         if [ "$cn" = "y" ]; then
  444.                                 warn "挂载 $loopchangefile 出现了错误,使用内存"
  445.                         else
  446.                                 warn "Mounting $loopchangefile error, use memory"
  447.                         fi
  448.                         eval "use_memory=y"
  449.                 fi
  450.         fi
  451.         if [ "$(is_usable $CHANGES)" -ne 0 ]; then
  452.                 if [ "$cn" = "y" ]; then
  453.                         echolog "启动参数$changes设置的目标不可用或者不可写或者不兼容linux, 使用内存"
  454.                 else
  455.                         echolog "Changes not used or not writable or not compatible with linux, using memory."
  456.                 fi
  457.                 umount -l $CHANGES 2>/dev/null
  458.                 eval "use_memory=y"
  459.         fi
  460.     else
  461.         eval "use_memory=y"
  462.     fi
  463.     if [ "$use_memory" = "y" ]; then
  464.         [ -z $ramsize ] && ramsize="60%"
  465.         if [ "$cn" = "y" ]; then
  466.                 warn "使用内存(大小: $ramsize)存储修改,重启后修改丢失."
  467.         else
  468.                 warn "Use memory (size: $ramsize) to save changes, will be lost after reboot."
  469.         fi
  470.         debug_log "mount -t tmpfs -o "size=$ramsize" tmpfs $CHANGES"
  471.         mount -t tmpfs -o "size=$ramsize" tmpfs $CHANGES
  472.     fi
  473.     # mount aufs using the writable branch as the first one (leftmost/topmost)
  474.     #mount -t aufs -o nowarn_perm,xino=$XINO/.aufs.xino,br:$CHANGES=rw+nolwh aufs $1
  475.     debug_log "mount -t aufs -o nowarn_perm,xino=$XINO/.aufs.xino,br:$CHANGES=rw aufs $1"
  476.     mount -t aufs -o nowarn_perm,xino=$XINO/.aufs.xino,br:$CHANGES=rw aufs $1
  477.     if [ $? -ne 0 ]; then dmesg | tail -n 1; fatal "can't setup union (aufs)"; fi
  478.     #rm -rf $CHANGES/.wh..*
  479.     debug_log "mount_changes finished"
  480. }
  481. # 将文件夹$1 以只读方式合并到aufs文件系统的$1目录中
  482. union_insert_dir()
  483. {
  484.    debug_log "union_insert_dir" "$*"
  485.    debug_log "mount -n -o remount,add:1:$2=rr aufs $1"
  486.    mount -n -o remount,add:1:$2=rr aufs $1
  487. }
  488. mount_union_handler()
  489. {
  490.     debug_log "ARCH=$ARCH mount_union_handler" "$*"
  491.     [ -d $1 ] || mkdir -p $1
  492.     for dir in dev sys proc; do
  493.         [ -d /union/$dir ] || mkdir -p /union/$dir 2>&1 >/dev/null
  494.     done
  495.     mount -o bind /union $1
  496. }
  497. run_hook ()
  498. {
  499.     debug_log "ARCH=$ARCH run_hook $0" "$*"
  500.     # 启动参数 real_root=/dev/sda1   直接启动/dev/sda1下的Arch系统
  501.     # 启动参数 real_root=/dev/sda1/Archlive/Archlive.disk
  502.     #          则将/dev/sda1挂载到/host,将/host/Archlive/Archlive.disk 挂载到 /live
  503.     #          如果 /live 包含启动文件, 则将/live同时挂载到/union 再从/union 启动Arch系统
  504.     # 启动参数 changes=/dev/sda1/Archlive/changes.disk
  505.     #          如果/dev/sda1/Archlive/changes.disk不存在则创建(需要输入命令,或者启动参数加newloop)
  506.     #          加载/dev/sda1/Archlive/changes.disk用于保存修改,原主系统只读
  507.     # 还可以如下方式指定(同Arch默认,则不启用save2loop功能)
  508.     # root=/dev/sda1  root=uuid=047C-F52A root=label=Arch
  509.     [ -z $init ] && init="/sbin/init"
  510.     mkdir -p $UNION
  511.     if [ "x$real_root" = "x" -a "x$root" != "x" ]; then
  512.         real_root=$root
  513.     fi
  514.     if [ "x$real_root" != "x" ]; then
  515.         device_mount_handler $real_root /host /live
  516.         if [ -e /live/$init ]; then
  517.                 HOST="/live"
  518.         elif [ -e /host/$init ]; then
  519.                 HOST="/host"
  520.         fi
  521.     fi
  522.     if [ "x$changes" != "x" ]; then
  523.         modprobe aufs
  524.         mount_changes $UNION
  525.         [ -d $HOST/tmp ] && rm -rf $HOST/tmp/*
  526.         union_insert_dir $UNION $HOST
  527.     else
  528.         mount -o bind $HOST $UNION
  529.     fi
  530.     mount_handler="mount_union_handler"
  531.     debug_log "mount_handler=${mount_handler} HOST=$HOST CHANGE_HOST=$CHANGE_HOST"
  532.     debug_shell
  533. }
复制代码

3、将如下脚本保存到 /lib/initcpio/install/save2loop
  1. install ()
  2. {
  3.     BASEDIR=""
  4.     add_dir /tmp
  5.     MODULES="${MODULES} loop aufs nls_cp936 nls_utf8 ext4"
  6.     #trim whitespace
  7.     MODULES=$(echo ${MODULES})
  8.     add_binary "${BASEDIR}/sbin/mount.ntfs-3g" "/sbin/mount.ntfs-3g"
  9.     add_binary "${BASEDIR}/sbin/mount.aufs" "/bin/mount.aufs"
  10.     add_binary "${BASEDIR}/sbin/mkfs.ext4" "/sbin/mkfs.ext4"
  11.     add_binary "${BASEDIR}/sbin/badblocks" "/sbin/badblocks"
  12.     add_binary "${BASEDIR}/bin/dd" "/bin/dd"
  13.     SCRIPT="save2loop"
  14. }
  15. help ()
  16. {
  17. cat<<HELPEOF
  18.   This hook support boot Arch GNU/Linux from loop file, and save changes
  19.   to this main loop file, or another loop file appointed by "changes=".
  20.   If the loopfile for save changes (not the main loop file) not exists,
  21.   First time to use this hook, or the change_loop file not exists,
  22.   you can add "newloop" to grub.cfg or enter command after boot as the
  23.   directions.
  24.   Then this hook will create a loop file as ext4 format and load it to
  25.   save changes.
  26.   If the loop file already exists, then just loading it.
  27.   If change_loop file used, the main loop file will be mounted as read-only.
  28. HELPEOF
  29. }
复制代码

4、将 save2loop 加到 /etc/mkinitcpio.conf 的 HOOKS 行最后 (当然应该在"前)

5、在启动参数中加入   changes="你需要保存修改的loop文件"
     启动参数加入方法: 加入到grub.cfg 或者 menu.list 对应启动项
     "你需要保存修改的loop文件"  设定可以参考:

        # changes 指定办法类似real_root (上篇有描述)
        # changes=/dev/sda1/Archlive/changes.img
        # changes=label=C/Archlive/changes.img
        # changes=uuid=047C-F52A/Archlive/changes.img
        # changes=changes.img  #跟real_root 或者 root 同目录

[color="Blue"][注意] [color="Red"]如果changes 指定的loop还不存在,可以在启动参数中加入newloop,启动脚本会自动创建, 也可以通过指定 newloopsize=2000M 来指定新创建的loop的大小, 也可以不添加任何参数,启动脚本检测到不存在会做相关提示,按照提示操作也可创建loop文件


[color="Blue"]比如我的启动选项:
menu.lst
  1. title  Arch i686 on loop
  2. root   (hd0,9)
  3. kernel /Arch/sys/vmlinuz26 real_root=/dev/sda10/Arch/sys/Arch-i686.img earlymodules=nouveau changes=/dev/sda10/Arch/sys/i686-changes.img oss cn rw quiet
  4. initrd /Arch/sys/kernel26.img
复制代码
[color="Blue"]
grub2 的 grub.cfg
  1. menuentry "Arch i686 (on loop sda10)" {
  2.         set root=(hd0,msdos10)
  3.         linux /Arch/sys/vmlinuz26 real_root=/dev/sda10/Arch/sys/Arch-i686.img earlymodules=nouveau changes=/dev/sda10/Arch/sys/i686-changes.img oss cn rw quiet
  4.         initrd /boot/kernel26.img
  5. }
复制代码
[color="Black"]
6、 sudo mkinitcpio -p kernel26  来重新制作启动镜像


    [color="Red"]  [技巧][color="Blue"] 如果bootloader (GRUB或者其他)不支持主系统(loop文件或者真实分区上), 可以将 内核 和内核 镜像放到被bootloader 支持的分区,/etc/mkinitcpio.d/kernel26.preset 做相应修改, 比如我的 kernel26.preset
  1. # mkinitcpio preset file for kernel26
  2. ########################################
  3. # DO NOT EDIT THIS LINE:
  4. source /etc/mkinitcpio.d/kernel26.kver
  5. ########################################
  6. ALL_config="/etc/mkinitcpio.conf"
  7. PRESETS=('default' 'fallback')
  8. #default_config="/etc/mkinitcpio.conf"
  9. #default_image="/boot/kernel26.img"
  10. default_image="/mnt/sda10/Arch/sys/kernel26.img"
  11. #default_options=""
  12. #fallback_config="/etc/mkinitcpio.conf"
  13. #fallback_image="/boot/kernel26-fallback.img"
  14. fallback_image="/mnt/sda10/Arch/sys/kernel26-fallback.img"
  15. fallback_options="-S autodetect"
复制代码

[color="Red"][技巧] [color="Blue"]即使从loop启动作为主设备, 内核和内核镜像最好放出来,这样会快点, grub2虽然支持直接从loop中加载内核和内核镜像,但速度慢。

[color="Red"]
同样抛砖引玉,欢迎探讨。。。
 楼主| 发表于 2011-4-14 17:21:27 | 显示全部楼层
[color="Navy"]目前我的/proc/mounts 如下:

  1. $ cat /proc/mounts
  2. rootfs / rootfs rw 0 0
  3. proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
  4. sys /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
  5. udev /dev devtmpfs rw,nosuid,relatime,size=10240k,nr_inodes=126667,mode=755 0 0
  6. fusectl /sys/fs/fuse/connections fusectl rw,relatime 0 0
  7. /dev/sda10 /host fuseblk rw,nosuid,nodev,relatime,user_id=0,group_id=0,allow_other,blksize=4096 0 0
  8. /dev/loop0 /live ext4 rw,relatime,barrier=1,data=ordered 0 0
  9. tmpfs /memory/xino tmpfs rw,relatime 0 0
  10. /dev/loop1 /memory/changes ext4 rw,relatime,barrier=1,data=ordered 0 0
  11. aufs /union aufs rw,relatime,si=4a4db743,nowarn_perm 0 0
  12. aufs / aufs rw,relatime,si=4a4db743,nowarn_perm 0 0
  13. devpts /dev/pts devpts rw,relatime,mode=600,ptmxmode=000 0 0
  14. shm /dev/shm tmpfs rw,nosuid,nodev,relatime 0 0
  15. /dev/sda7 /mnt/sda7 ext4 rw,relatime,barrier=1,data=ordered 0 0
  16. /dev/sda6 /mnt/sda6 ext4 rw,relatime,barrier=1,data=ordered 0 0
  17. /dev/sda9 /mnt/sda9 reiserfs rw,relatime 0 0
  18. /dev/sda1 /mnt/sda1 fuseblk rw,nosuid,nodev,relatime,user_id=0,group_id=0,default_permissions,allow_other,blksize=4096 0 0
  19. /dev/sda10 /mnt/sda10 fuseblk rw,nosuid,nodev,relatime,user_id=0,group_id=0,allow_other,blksize=4096 0 0
  20. /dev/loop2 /mnt/cxoffice reiserfs rw,relatime 0 0
  21. /dev/loop3 /var/abs ext4 rw,relatime,barrier=1,data=ordered 0 0
  22. gvfs-fuse-daemon /home/arch/.gvfs fuse.gvfs-fuse-daemon rw,nosuid,nodev,relatime,user_id=1000,group_id=100 0 0
复制代码
回复 支持 反对

使用道具 举报

发表于 2011-4-14 22:26:41 | 显示全部楼层
留个脚印,后面修改一下。
回复 支持 反对

使用道具 举报

发表于 2011-4-15 10:14:47 | 显示全部楼层
太棒了,功能越来越高级了
到时尝试一下看因为这个save change 会不会占很大的内存 以及对速度的影响
发现笔误[常识] -> 尝试
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-4-15 10:21:11 | 显示全部楼层
Post by axlrose;2135118

发现笔误[常识] -> 尝试


这都被你揪到!

惭愧。。。
回复 支持 反对

使用道具 举报

发表于 2011-4-15 11:46:24 | 显示全部楼层
为什么不把之前和automount和这个save2loop做成一个AUR的PKGBUILD呢?毕竟是要一起工作的啊?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-4-15 12:36:02 | 显示全部楼层
Post by alpha.gu;2135128
为什么不把之前和automount和这个save2loop做成一个AUR的PKGBUILD呢?毕竟是要一起工作的啊?

已经做了  yaourt -S save2loop  来安装

save2loop 脚本已经将automount集成进来了,既可以工作于目前实体硬盘上加载loop保存修改,
也可以加载主loop,再加载保存修改的loop。。。

只是上篇里面有主loop文件制作方法,这里就不再介绍了
回复 支持 反对

使用道具 举报

发表于 2011-4-15 22:11:21 | 显示全部楼层
从上面Copy下代码后,/lib/initcpio/hooks/save2loop在加入mkinitcpio.conf后,重做了initrd,启动的时候提示这个save2loop的第519行有一个问题,大概是括号匹配还是别的什么,结果就Kernel Panic了,我再用AUR上的来试一下。

AUR上的无法安装,无法从GoogleCode上下载到正确的文件,PKGBUILD所提供的文件名和你存在GoogleCode上的文件名不同,我还是等你看一看那个519行问题吧,或者你检查过没问题的话,再告诉我一下:)
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-4-15 23:23:36 | 显示全部楼层
上传错附件了, 已经修复。。。
回复 支持 反对

使用道具 举报

发表于 2011-4-16 19:20:28 | 显示全部楼层
我按你的前一篇文章,将Arch安装到了loop文件,但是在Arch关机的时候,会有一些错误,所以,看到你的这篇文章,以为是修复这些错误提示的。
看了HELP当中的描述,似乎有这功能,可是试下来,总不是我想的那样。
我的loop文件存放在D:(NTFS格式,/dev/sda5)下,名为Arch.img,grub24dos的grub.cfg内容如下:


set default=0
set timeout=0

menuentry "Arch Linux" {
        insmod part_msdos
        insmod loopback
        set img_file=Arch.img
        search --file --no-floppy --set=img_root /$img_file
        loopback loop0 (hd0,msdos5)/$img_file
        set root=(loop0)
        linux /boot/vmlinuz26 real_root=loop=/dev/sda5 loopfile=$img_file quiet i915.powersave=0
        initrd /boot/kernel26.img
}

menuentry "Arch Linux Fallback" {
        insmod part_msdos
        insmod loopback
        set img_file=Arch.img
        search --file --no-floppy --set=img_root /$img_file
        loopback loop0 (hd0,msdos5)/$img_file
        set root=(loop0)
        linux /boot/vmlinuz26 real_root=loop=/dev/sda5 loopfile=$img_file quiet i915.powersave=0
        initrd /boot/kernel26-fallback.img
}

如果不指定changes,看起来它会自己去找Arch.img,但是提示找不到,并提示/etc/fstab有问题,如果用changes=/dev/sda5/Arch.img指定,也要先经历两次Ctrl+D,然后才能进入系统,进入系统后,关机时仍有错误。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表