· 6 years ago · Sep 29, 2019, 04:02 PM
1#!/bin/bash
2
3# Live Ubuntu Backup V2.2, Nov 4th,2009
4# Copyright (C) 2009 billbear <billbear@gmail.com>
5
6# This program is free software; you can redistribute it and/or modify it
7# under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License,
9# or (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13# or FITNESS FOR A PARTICULAR PURPOSE.
14# See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along with this program;
17# if not, see <http://www.gnu.org/licenses>.
18
19mypath=$0
20
21VOL_ID(){
22 [ "$2" = "" ] && return
23 local voluuid=""
24 local voltype=""
25 for i in `blkid $2`; do
26 [ "${i#UUID=\"}" != "$i" ] && voluuid="${i#UUID=\"}" && voluuid="${voluuid%\"}"
27 [ "${i#TYPE=\"}" != "$i" ] && voltype="${i#TYPE=\"}" && voltype="${voltype%\"}"
28 done
29 [ "$1" = "--uuid" ] && echo $voluuid
30 [ "$1" = "--type" ] && echo $voltype
31}
32
33new_dir(){
34 local newdir="$*"
35 i=0
36 while [ -e $newdir ]; do
37 i=`expr $i + 1`
38 newdir="$*-$i"
39 done
40 echo $newdir
41}
42
43echoredcn(){
44 [ $lang = "cn" ] && echo -e "\033[31m$*\033[0m"
45 return 0
46}
47
48echoreden(){
49 [ $lang = "en" ] && echo -e "\033[31m$*\033[0m"
50 return 0
51}
52
53echocn(){
54 [ $lang = "cn" ] && echo $*
55 return 0
56}
57
58echoen(){
59 [ $lang = "en" ] && echo $*
60 return 0
61}
62
63packagecheck_b(){
64 dpkg -l | grep ^ii | sed 's/[ ][ ]*/ /g' | cut -d " " -f 2 | grep ^lupin-casper$ > /dev/null || { echoreden "Warning: lupin-casper is currently not installed. You can install it by typing:\nsudo apt-get install lupin-casper\nYou may need a working internet connection to do that.\nYou can also continue without installing it, but your backup may not be self-bootable. However, you can still restore your backup from something like a livecd environment.\nHit enter to continue and ctrl-c to quit"; echoredcn "警告: lupin-casper 尚未安装. 你可以用如下命令安装:\nsudo apt-get install lupin-casper\n这需要连上互联网。\n你也可以不安装而继续, 但生成的备份将不能够自行启动。\n不过你仍然可以从一个像 livecd 这样的环境中恢复你的备份。\n按回车不安装而继续, 按 ctrl-c 退出"; read yn; }
65
66 dpkg -l | grep ^ii | sed 's/[ ][ ]*/ /g' | cut -d " " -f 2 | grep ^squashfs-tools$ > /dev/null || { echoreden "squashfs-tools is required to run this program. You can install it by typing:\nsudo apt-get install squashfs-tools\nYou may need a working internet connection to do that."; echoredcn "要运行此程序必须先安装 squashfs-tools。你可以用如下命令安装:\nsudo apt-get install squashfs-tools\n这需要连上互联网。"; exit 1; }
67}
68
69packagecheck_r(){
70 dpkg -l | grep ^ii | sed 's/[ ][ ]*/ /g' | cut -d " " -f 2 | grep ^parted$ > /dev/null || { echoreden "parted is required to run this program. You can install it by typing:\nsudo apt-get install parted\nYou may need a working internet connection to do that."; echoredcn "要运行此程序必须先安装 parted。你可以用如下命令安装:\nsudo apt-get install parted\n这需要连上互联网。"; exit 1; }
71}
72
73rebuildtree(){ # Remounting the linux directories effectively excludes removable media, manually mounted devices, windows partitions, virtual files under /proc, /sys, /dev, the /host contents of a wubi install, etc. If your partition scheme is more complicated than listed below, you must add lines to rebuildtree() and destroytree(), otherwise the backup will be partial.
74 mkdir /$1
75 mount --bind / /$1
76 mount --bind /boot /$1/boot
77 mount --bind /home /$1/home
78 mount --bind /tmp /$1/tmp
79 mount --bind /usr /$1/usr
80 mount --bind /var /$1/var
81 mount --bind /srv /$1/srv
82 mount --bind /opt /$1/opt
83 mount --bind /usr/local /$1/usr/local
84}
85
86destroytree(){
87 umount /$1/usr/local
88 umount /$1/opt
89 umount /$1/srv
90 umount /$1/var
91 umount /$1/usr
92 umount /$1/tmp
93 umount /$1/home
94 umount /$1/boot
95 umount /$1
96 rmdir /$1
97}
98
99target_cmd(){
100 mount --bind /proc $1/proc
101 mount --bind /dev $1/dev
102 mount --bind /sys $1/sys
103 chroot $*
104 umount $1/sys
105 umount $1/dev
106 umount $1/proc
107}
108
109dequotepath(){ # If drag n drop from nautilus into terminal, the additional single quotes should be removed first.
110 local tmpath="$*"
111 [ "${tmpath#\'}" != "$tmpath" ] && [ "${tmpath%\'}" != "$tmpath" ] && { tmpath="${tmpath#\'}"; tmpath="${tmpath%\'}"; }
112 echo "$tmpath"
113}
114
115checkbackupdir(){
116 [ "${1#/}" = "$1" ] && { echoreden "You must specify the absolute path"; echoredcn "请使用绝对路径"; exit 1; }
117 [ -d "$*" ] || { echoreden "$* does not exist, or is not a directory"; echoredcn "$* 不存在, 或并非目录"; exit 1; }
118 [ `ls -A "$*" | wc -l` = 0 ] || { echoreden "$* is not empty"; echoredcn "$* 不是空目录"; exit 1; }
119}
120
121probe_partitions(){
122 for i in /dev/[hs]d[a-z][0-9]*; do
123 blkid $i > /dev/null 2>&1 || continue
124 parted -s $i print > /dev/null 2>&1 || continue
125 part[${#part[*]}]=$i
126 oldfstype[${#oldfstype[*]}]=`$VOL_ID --type $i`
127 size=`parted -s $i print | grep $i`
128 size=${size#*:}
129 size=${size#*:} #全角冒号,台湾 parted 输出用这个 :(
130 partinfo[${#partinfo[*]}]="$i `$VOL_ID --type $i` $size"
131 done
132}
133
134choose_partition(){
135 select opt in "${partinfo[@]}"; do
136 [ "$opt" = "" ] && continue
137 arrno=`expr $REPLY - 1`
138 [ $REPLY -gt ${#part[*]} ] && break
139 echoreden "You selected ${part[$arrno]}, it currently contains these files/directories:"
140 echoredcn "你选择的是 ${part[$arrno]}, 里面现有这些文件/目录:"
141 tmpdir=`new_dir /tmp/mnt`
142 [ "${oldfstype[$arrno]}" = "swap" ] || { mkdir $tmpdir; mount ${part[$arrno]} $tmpdir; ls -A $tmpdir; umount $tmpdir; rmdir $tmpdir; }
143 echoreden "confirm?(y/n)"
144 echoredcn "确定?(y/n)"
145 read yn
146 [ "$yn" != "y" ] && echoreden "Select again" && echoredcn "重新选择" && continue
147 partinfo[$arrno]=""
148 break
149 done
150
151 eval $1=$arrno
152 [ $REPLY -gt ${#part[*]} ] && return
153 [ $1 = swappart ] && echoreden "${part[$arrno]} will be formatted as swap." && echoredcn "${part[$arrno]} 将被格式化为 swap." && return
154
155 if [ "${oldfstype[$arrno]}" = "ext2" -o "${oldfstype[$arrno]}" = "ext3" -o "${oldfstype[$arrno]}" = "ext4" -o "${oldfstype[$arrno]}" = "reiserfs" -o "${oldfstype[$arrno]}" = "jfs" -o "${oldfstype[$arrno]}" = "xfs" ]; then
156 echoreden "Do you want to format this partition?(y/n)"
157 echoredcn "是否格式化此分区?(y/n)"
158 read yn
159 [ "$yn" != "y" ] && newfstype[$arrno]="keep" && return
160 fi
161 echoreden "Format ${part[$arrno]} as:"
162 echoredcn "格式化 ${part[$arrno]} 为:"
163
164 select opt in ext2 ext3 ext4 reiserfs jfs xfs; do
165 [ "$opt" = "" ] && continue
166 ls /sbin/mkfs.$opt > /dev/null 2>&1 && break
167 echoreden "mkfs.$opt is not installed."
168 echoredcn "mkfs.$opt 尚未安装。"
169 [ "$opt" = "reiserfs" ] && echoreden "You can install it by typing\nsudo apt-get install reiserfsprogs" && echoredcn "你可以通过如下命令安装\nsudo apt-get install reiserfsprogs"
170 [ "$opt" = "jfs" ] && echoreden "You can install it by typing\nsudo apt-get install jfsutils" && echoredcn "你可以通过如下命令安装\nsudo apt-get install jfsutils"
171 [ "$opt" = "xfs" ] && echoreden "You can install it by typing\nsudo apt-get install xfsprogs" && echoredcn "你可以通过如下命令安装\nsudo apt-get install xfsprogs"
172 echoreden "Please re-select file system type."
173 echoredcn "请重新选择文件系统。"
174 done
175
176 newfstype[$arrno]=$opt
177}
178
179setup_target_partitions(){
180 rootpart=1000
181 swappart=1000
182 homepart=1000
183 bootpart=1000
184 tmppart=1000
185 usrpart=1000
186 varpart=1000
187 srvpart=1000
188 optpart=1000
189 usrlocalpart=1000
190
191 echoreden "Which partition do you want to use as / ?"
192 echoredcn "将哪个分区作为 / ?"
193 choose_partition rootpart
194
195 [ $lang = "cn" ] && partinfo[${#partinfo[*]}]="无" || partinfo[${#partinfo[*]}]="None"
196 [ $lang = "cn" ] && partinfo[${#partinfo[*]}]="无,并结束分区设定。" || partinfo[${#partinfo[*]}]="None and finish setting up partitions"
197
198 echoreden "Which partition do you want to use as swap ?"
199 echoredcn "将哪个分区作为 swap ?"
200 choose_partition swappart
201 [ $arrno -gt ${#part[*]} ] && return
202
203 for i in home boot tmp usr var srv opt; do
204 echoreden "Which partition do you want to use as /$i ?"
205 echoredcn "将哪个分区作为 /$i ?"
206 eval choose_partition ${i}part
207 [ $arrno -gt ${#part[*]} ] && return
208 done
209
210 echoreden "Which partition do you want to use as /usr/local ?"
211 echoredcn "将哪个分区作为 /usr/local ?"
212 choose_partition usrlocalpart
213}
214
215umount_target_partitions(){
216 for i in usrlocalpart swappart homepart bootpart tmppart usrpart varpart srvpart optpart rootpart; do
217 eval thispart=\$$i
218 [ "${part[$thispart]}" = "" ] && continue
219 [ "${newfstype[$thispart]}" = "keep" ] && continue
220 while mount | grep "^${part[$thispart]} " > /dev/null; do
221 umount ${part[$thispart]} || { echoreden "Failed to umount ${part[$thispart]}"; echoredcn "无法卸载 ${part[$thispart]}"; exit 1; }
222 done
223 [ $i = swappart ] && continue
224 swapon -s | grep "^${part[$thispart]} " > /dev/null && echoreden "swapoff ${part[$thispart]} and try again." && echoredcn "请先 swapoff ${part[$thispart]}" && exit 1
225 done
226}
227
228format_target_partitions(){
229 for i in rootpart homepart bootpart tmppart usrpart varpart srvpart optpart usrlocalpart; do
230 eval thispart=\$$i
231 [ "${part[$thispart]}" = "" ] && continue
232 [ "${newfstype[$thispart]}" = "keep" ] && continue
233 echoreden "Formatting ${part[$thispart]}"
234 echoredcn "正在格式化 ${part[$thispart]}"
235 [ "${newfstype[$thispart]}" = "xfs" ] && formatoptions=fq || formatoptions=q
236 mkfs.${newfstype[$thispart]} -$formatoptions ${part[$thispart]} > /dev/null || { echoreden "Failed to format ${part[$thispart]}"; echoredcn "无法格式化 ${part[$thispart]}"; exit 1; }
237 disk=`expr substr ${part[$thispart]} 1 8`
238 num=${part[$thispart]#$disk}
239 sfdisk -c -f $disk $num 83
240 done
241
242 [ "${part[$swappart]}" = "" ] && return
243 [ "${oldfstype[$swappart]}" = "swap" ] && return
244 echoreden "Formatting ${part[$swappart]}"
245 echoredcn "正在格式化 ${part[$swappart]}"
246 mkfs.ext2 -q ${part[$swappart]} || { echoreden "Failed to format ${part[$swappart]}"; echoredcn "无法格式化 ${part[$swappart]}"; exit 1; }
247 mkswap ${part[$swappart]} || { echoreden "Failed to format ${part[$swappart]}"; echoredcn "无法格式化 ${part[$swappart]}"; exit 1; }
248 disk=`expr substr ${part[$swappart]} 1 8`
249 num=${part[$swappart]#$disk}
250 sfdisk -c -f $disk $num 82
251}
252
253chkuuids(){
254 uuids=""
255 for i in /dev/[hs]d[a-z][0-9]*; do
256 uuids="$uuids\n`$VOL_ID --uuid $i 2> /dev/null`"
257 done
258 [ "`echo -e $uuids | sort | uniq -d`" = "" ] && return
259 echoreden "duplicate UUIDs detected! The program will now terminate."
260 echoredcn "检测到某些分区有重复的 UUID! 程序将终止。"
261 exit 1
262}
263
264mount_target_partitions(){
265 tgt=`new_dir /tmp/target`
266 mkdir $tgt
267 mount ${part[$rootpart]} $tgt
268 [ "${part[$homepart]}" != "" ] && mkdir -p $tgt/home && mount ${part[$homepart]} $tgt/home
269 [ "${part[$bootpart]}" != "" ] && mkdir -p $tgt/boot && mount ${part[$bootpart]} $tgt/boot
270 [ "${part[$tmppart]}" != "" ] && mkdir -p $tgt/tmp && mount ${part[$tmppart]} $tgt/tmp
271 [ "${part[$usrpart]}" != "" ] && mkdir -p $tgt/usr && mount ${part[$usrpart]} $tgt/usr
272 [ "${part[$varpart]}" != "" ] && mkdir -p $tgt/var && mount ${part[$varpart]} $tgt/var
273 [ "${part[$srvpart]}" != "" ] && mkdir -p $tgt/srv && mount ${part[$srvpart]} $tgt/srv
274 [ "${part[$optpart]}" != "" ] && mkdir -p $tgt/opt && mount ${part[$optpart]} $tgt/opt
275 [ "${part[$usrlocalpart]}" != "" ] && mkdir -p $tgt/usr/local && mount ${part[$usrlocalpart]} $tgt/usr/local
276}
277
278gettargetmount(){ # Generate a list of mounted partitions and mount points of the restore target.
279 for i in `mount | grep " $* "`; do
280 [ "${i#/dev/}" != "$i" ] && echo $i
281 [ "$i" = "$*" ] && echo "$i/"
282 done
283
284 for i in `mount | grep " $*/"`; do
285 [ "${i#/}" != "$i" ] && echo $i
286 done
287}
288
289getdefaultgrubdev(){ # Find the root or boot partition.
290 local bootdev=""
291 local rootdev=""
292 for i in $*; do
293 [ "$i" = "$tgt/" ] && rootdev="$j" || j=$i
294 [ "$i" = "$tgt/boot" ] && bootdev="$k" || k=$i
295 done
296 [ "$bootdev" = "" ] && echo $rootdev && return
297 echo $bootdev && return 67
298}
299
300listgrubdev(){
301 for i in /dev/[hs]d[a-z]; do
302 echo $i,MBR
303 done
304
305 for i in /dev/[hs]d[a-z][0-9]*; do
306 blkid $i > /dev/null 2>&1 || continue
307 [ "`$VOL_ID --type $i`" = "ntfs" ] && continue
308 parted -s $i print > /dev/null 2>&1 || continue
309 echo $i,`$VOL_ID --type $i`
310 done
311
312 echoen none,not_recommended
313 echocn 不安装(不推荐)
314}
315
316getmountoptions(){ # According to the default behavior of ubuntu installer. You can alter these or add options for other fs types.
317 case "$*" in
318 "/ ext4" ) echo relatime,errors=remount-ro;;
319 "/ ext3" ) echo relatime,errors=remount-ro;;
320 "/ ext2" ) echo relatime,errors=remount-ro;;
321 "/ reiserfs" ) [ "$hasboot" = "yes" ] && echo relatime || echo notail,relatime;;
322 "/ jfs" ) echo relatime,errors=remount-ro;;
323
324 "/boot reiserfs" ) echo notail,relatime;;
325
326 *"ntfs" ) echo defaults,umask=007,gid=46;;
327 *"vfat" ) echo utf8,umask=007,gid=46;;
328 *) echo relatime;;
329 esac
330}
331
332generate_fstab(){
333 local targetfstab="$*/etc/fstab"
334
335 echo "# /etc/fstab: static file system information." > "$targetfstab"
336 echo "#" >> "$targetfstab"
337 echo "# <file system> <mount point> <type> <options> <dump> <pass>" >> "$targetfstab"
338 echo "proc /proc proc defaults 0 0" >> "$targetfstab"
339
340 for i in $tgtmnt; do
341 [ "${i#/dev/}" != "$i" ] && { echo "# $i" >> "$targetfstab"; j=$i; continue; }
342 uuid="`$VOL_ID --uuid $j`"
343 [ "$uuid" = "" ] && partition=$j || partition="UUID=$uuid"
344 mntpnt=${i#$tgt}
345 fs=`$VOL_ID --type $j`
346 fsckorder=`echo "${i#$tgt/} s" | wc -w`
347 echo "$partition $mntpnt $fs `getmountoptions "$mntpnt $fs"` 0 $fsckorder" >> "$targetfstab"
348 done
349
350 for i in /dev/[hs]d[a-z][0-9]*; do
351 [ "`$VOL_ID --type $i 2> /dev/null`" = swap ] || continue
352 echo "# $i" >> "$targetfstab"
353 swapuuid="`$VOL_ID --uuid $i`"
354 [ "$swapuuid" = "" ] && partition=$i || partition="UUID=$swapuuid"
355 echo "$partition none swap sw 0 0" >> "$targetfstab"
356 haswap="yes"
357 [ -f $tgt/etc/initramfs-tools/conf.d/resume ] || { echo "RESUME=$partition" > $tgt/etc/initramfs-tools/conf.d/resume; continue; }
358 lastresume="`cat $tgt/etc/initramfs-tools/conf.d/resume`"
359 lastresume="${lastresume#RESUME=}"
360 [ "${lastresume#UUID=}" != "$lastresume" ] && lastresume="`parted /dev/disk/by-uuid/${lastresume#UUID=} unit B print | grep /dev/`"
361 [ "${lastresume#/dev/}" != "$lastresume" ] && lastresume="`parted $lastresume unit B print | grep /dev/`"
362 lastresume=${lastresume#*:}
363 lastresume=${lastresume#*:} #有可能是全角冒号
364 lastresume=${lastresume%B}
365 thisresume="`parted $i unit B print | grep $i`"
366 thisresume=${thisresume#*:}
367 thisresume=${thisresume#*:} #有可能是全角冒号
368 thisresume=${thisresume%B}
369 [ "$thisresume" -gt "$lastresume" ] && echo "RESUME=$partition" > $tgt/etc/initramfs-tools/conf.d/resume
370 done
371
372 echo "/dev/scd0 /media/cdrom0 udf,iso9660 user,noauto,exec,utf8 0 0" >> "$targetfstab"
373}
374
375makelostandfound(){ # If lost+found is removed from an ext? FS, create it with the command mklost+found. Don't just mkdir lost+found
376 for i in $tgtmnt; do
377 [ "${i#/dev/}" != "$i" ] && j=$i
378 [ "${i#$tgt}" != "$i" ] && $VOL_ID --type $j | grep ext > /dev/null && cd $i && mklost+found 2> /dev/null
379 done
380}
381
382makeswapfile(){
383 echoreden "You do not have a swap partition. Would you like a swap file? Default is yes.(y/n)"
384 echoredcn "你没有 swap 分区。是否做一个 swap 文件? 默认的回答为是。(y/n)"
385 read yn
386 [ "$yn" = "n" ] && return
387 echoreden "The size of the swap file in megabytes, defaults to 512"
388 echoredcn "做一个多少兆的 swap 文件? 默认值为 512"
389 read swapsize
390 swapsize=`expr $swapsize + 0 2> /dev/null`
391 [ "$swapsize" = "" ] && swapsize=512
392 [ "$swapsize" = "0" ] && swapsize=512
393 local sf=`new_dir $*/swapfile`
394 echoreden "Generating swap file..."
395 echoredcn "正在创建 swap 文件..."
396 dd if=/dev/zero of=$sf bs=1M count=$swapsize
397 mkswap $sf
398 echo "${sf#$*} none swap sw 0 0" >> "$*/etc/fstab"
399}
400
401sqshboot_menulst(){ # Generate a windows-notepad-compatible menu.lst in the backup directory with instructions to boot backup.squashfs directly.
402 [ $lang = "cn" ] && echo -e "# 这个 menu.lst 是给 grub4dos 用的。稍作修改才能用于 gnu grub\r
403\r
404\r
405# 如何在 windows 机器上直接启动你的 backup$today.squashfs:\r
406# 从 http://download.gna.org/grub4dos 下载最新的 grub4dos\r
407# 解压下载的 grub4dos, 并拷贝其中的 grldr 和 grldr.mbr 到 c: 盘根目录\r
408# 把这个 menu.lst 也拷贝到 c: 盘根目录\r
409# 然后在任意 fat ntfs ext 分区根目录建立一个 \"casper\" 目录并拷贝 backup$today.squashfs, initrd.img-`uname -r`, vmlinuz-`uname -r` 到它里面\r
410# 接着添加下面这行文字到 boot.ini 末尾 (不包含#号)\r
411# c:\grldr.mbr=\"grub4dos\"\r
412##### 对于 Windows Vista, 可以自行建立一个 boot.ini 文件,写上:\r
413##### [boot loader]\r
414##### [operating systems]\r
415##### c:\grldr.mbr=\"grub4dos\"\r
416# 重启选择 grub4dos 即可\r
417\r
418\r
419# 如何在 linux 机器上直接启动你的 backup$today.squashfs:\r
420# 在任意 fat ntfs ext 分区根目录建立一个 \"casper\" 文件夹并拷贝 backup$today.squashfs, initrd.img-`uname -r`, vmlinuz-`uname -r` 到它里面(注意 gnu grub 不能读取 NTFS, 因此不能把 initrd.img-`uname -r`, vmlinuz-`uname -r` 放在那里,不过依然可以把 squashfs 放在那里)\r
421# 然后拷贝下面的两个 Live Ubuntu Backup 启动项到 /boot/grub/menu.lst 末尾并把 \"find --set-root\" 行改为 \"root (hd?,?)\" (你创建 \"casper\" 文件夹的那个分区)\r" || echo -e "# This menu.lst is for grub4dos only. You must edit it to use with gnu grub\r
422\r
423\r
424# Instructions to boot your backup$today.squashfs directly on a windows PC:\r
425# Download the latest grub4dos from http://download.gna.org/grub4dos\r
426# Unzip grub4dos, then copy grldr and grldr.mbr to the root of your c: drive\r
427# Also copy this menu.lst to the root of your c: drive\r
428# Then make a directory \"casper\" under the root of any fat, ntfs, or ext partition and copy backup$today.squashfs, initrd.img-`uname -r`, vmlinuz-`uname -r` to the directory\r
429# Then add this line to boot.ini (without #)\r
430# c:\grldr.mbr=\"grub4dos\"\r
431##### On Windows Vista, you can still create a boot.ini yourself with these lines:\r
432##### [boot loader]\r
433##### [operating systems]\r
434##### c:\grldr.mbr=\"grub4dos\"\r
435# Reboot and select grub4dos\r
436\r
437\r
438# Instructions to boot your backup$today.squashfs directly on a linux PC:\r
439# Make a directory \"casper\" under the root of any fat, ntfs, or ext partition and copy backup$today.squashfs, initrd.img-`uname -r`, vmlinuz-`uname -r` to the directory. (Note that NTFS is not readable by gnu grub so don't put initrd.img-`uname -r` & vmlinuz-`uname -r` there)\r
440# Then copy the Live Ubuntu Backup entries below to the end of your /boot/grub/menu.lst file and change the \"find --set-root\" line to \"root (hd?,?)\" (where you created the directory \"casper\")\r"
441
442echo -e "\r
443\r
444default 0\r
445timeout 10\r
446\r
447title Live Ubuntu Backup $today\r
448find --set-root /casper/vmlinuz-`uname -r`\r
449kernel /casper/vmlinuz-`uname -r` boot=casper ro ignore_uuid\r
450initrd /casper/initrd.img-`uname -r`\r
451\r
452title Live Ubuntu Backup $today, Recovery Mode\r
453find --set-root /casper/vmlinuz-`uname -r`\r
454kernel /casper/vmlinuz-`uname -r` boot=casper ro single ignore_uuid\r
455initrd /casper/initrd.img-`uname -r`\r"
456}
457
458windowsentry(){
459 for i in /dev/[hs]d[a-z][0-9]*; do
460 volid="`$VOL_ID --type $i 2> /dev/null`"
461 [ "$volid" != ntfs -a "$volid" != vfat ] && continue
462 tmpdir=`new_dir /tmp/mnt`
463 mkdir $tmpdir
464 mount $i $tmpdir || { rmdir $tmpdir; continue; }
465 disk=`expr substr $i 1 8`
466 num=${i#$disk}
467 num=`expr $num - 1`
468 [ -f $tmpdir/bootmgr -o -f $tmpdir/ntldr ] && { echo >> $tgt/boot/grub/menu.lst; echo "# This entry may not be correct when you have multiple hard disks" >> $tgt/boot/grub/menu.lst; echo "title windows" >> $tgt/boot/grub/menu.lst; echo "rootnoverify (hd0,$num)" >> $tgt/boot/grub/menu.lst; echo "chainloader +1" >> $tgt/boot/grub/menu.lst; }
469 umount $i
470 rmdir $tmpdir
471 done
472}
473
474grub1(){
475 grub-install --root-directory="$tgt" $grubdev
476 grub-install --root-directory="$tgt" $grubdev
477 # grub-install (onto reiserfs) sometimes fails for unknown reason. Installing it twice succeeds most of the time.
478 target_cmd "$tgt" update-grub -y
479 sed -i "s/^hiddenmenu/#hiddenmenu/" $tgt/boot/grub/menu.lst
480 windowsentry
481}
482
483grub2(){
484 target_cmd "$tgt" grub-install $grubdev
485 target_cmd "$tgt" grub-install $grubdev
486 # grub-install onto reiserfs still buggy in grub2. Installing it twice fixs problems.
487 target_cmd "$tgt" update-grub
488}
489
490cleartgtmnt(){
491 [ "${part[$usrlocalpart]}" != "" ] && umount ${part[$usrlocalpart]}
492 [ "${part[$homepart]}" != "" ] && umount ${part[$homepart]}
493 [ "${part[$bootpart]}" != "" ] && umount ${part[$bootpart]}
494 [ "${part[$tmppart]}" != "" ] && umount ${part[$tmppart]}
495 [ "${part[$usrpart]}" != "" ] && umount ${part[$usrpart]}
496 [ "${part[$varpart]}" != "" ] && umount ${part[$varpart]}
497 [ "${part[$srvpart]}" != "" ] && umount ${part[$srvpart]}
498 [ "${part[$optpart]}" != "" ] && umount ${part[$optpart]}
499 umount ${part[$rootpart]} || { echoreden "Please umount $tgt yourself"; echoredcn "请自行卸载 $tgt"; }
500}
501
502dobackup(){
503 bindingdir=`new_dir /tmp/bind`
504 backupdir=`new_dir ~/backup-$today`
505 bindingdir="${bindingdir#/}"
506 backupdir="${backupdir#/}"
507 packagecheck_b
508 packagecheck_r
509 echoreden "You are about to backup your system. It is recommended that you quit all open applications now. Continue?(y/n)"
510 echoredcn "将要备份系统。建议退出其他程序。继续?(y/n)"
511 read yn
512 [ "$yn" != "y" ] && exit 1
513 echoreden "Specify an empty directory(absolute path) to save the backup. You can drag directory from Nautilus File Manager and drop it here. Feel free to use external media.
514If you don't specify, the backup will be saved to /$backupdir"
515 echoredcn "指定一个空目录 (绝对路径) 来存放备份。\n可以从 Nautilus 文件管理器拖放目录至此。\n可以使用移动硬盘。\n如果不指定, 将会存放到 /$backupdir"
516 read userdefined_backupdir
517 [ "$userdefined_backupdir" != "" ] && { userdefined_backupdir="`dequotepath "$userdefined_backupdir"`"; checkbackupdir "$userdefined_backupdir"; backupdir="${userdefined_backupdir#/}"; }
518
519 exclude=`new_dir /tmp/exclude`
520 echo $backupdir > $exclude
521 echo $bindingdir >> $exclude
522 echo boot/grub >> $exclude
523 echo etc/fstab >> $exclude
524 echo etc/mtab >> $exclude
525 echo etc/blkid.tab >> $exclude
526 echo etc/udev/rules.d/70-persistent-net.rules >> $exclude
527 echo lost+found >> $exclude
528 echo boot/lost+found >> $exclude
529 echo home/lost+found >> $exclude
530 echo tmp/lost+found >> $exclude
531 echo usr/lost+found >> $exclude
532 echo var/lost+found >> $exclude
533 echo srv/lost+found >> $exclude
534 echo opt/lost+found >> $exclude
535 echo usr/local/lost+found >> $exclude
536
537 for i in `swapon -s | grep file | cut -d " " -f 1`; do
538 echo "${i#/}" >> $exclude
539 done
540
541 for i in `ls /tmp -A`; do
542 echo "tmp/$i" >> $exclude
543 done
544
545 echoreden "Do you want to exclude all user files in /home? (y/n)"
546 echoredcn "是否排除 /home 里所有的用户文件? (y/n)"
547 read yn
548 if [ "$yn" = y ]; then
549 for i in /home/*; do
550 [ -f "$i" ] && echo "${i#/}" >> $exclude
551 [ -d "$i" ] || continue
552 for j in "$i"/*; do
553 [ -e "$j" ] && echo "${j#/}" >> $exclude
554 done
555 done
556 fi
557
558 echoreden "Do you want to exclude all user configurations (hidden files) in /home as well? (y/n)"
559 echoredcn "是否也排除 /home 里所有的用户配置文件(隐藏文件)? (y/n)"
560 read yn
561 if [ "$yn" = y ]; then
562 for i in /home/*; do
563 [ -d "$i" ] || continue
564 for j in "$i"/.*; do
565 [ "$j" = "$i/." ] && continue
566 [ "$j" = "$i/.." ] && continue
567 echo "${j#/}" >> $exclude
568 done
569 done
570 fi
571
572 echoreden "Do you want to exclude the local repository of retrieved package files in /var/cache/apt/archives/ ? (y/n)"
573 echoredcn "是否排除已下载软件包在 /var/cache/apt/archives/ 里的本地缓存 ? (y/n)"
574 read yn
575 if [ "$yn" = y ]; then
576 for i in /var/cache/apt/archives/*.deb; do
577 [ -e "$i" ] && echo "${i#/}" >> $exclude
578 done
579 for i in /var/cache/apt/archives/partial/*; do
580 [ -e "$i" ] && echo "${i#/}" >> $exclude
581 done
582 fi
583
584 echoreden "(For advanced users only) Specify other files/folders you want to exclude from the backup, one file/folder per line. You can drag and drop from Nautilus. End with an empty line.\nNote that the program has automatically excluded all removable media, windows partitions, manually mounted devices, files under /proc, /sys, /tmp, the /host contents of a wubi install, etc. So in most cases you can just hit enter now.\nIf you exclude important system files/folders, the backup will fail to restore."
585 echoredcn "(高级用户功能)指定其他需要排除的文件/目录, 一行写一个。以空行结束。\n可以从 Nautilus 文件管理器拖放至此。\n注意程序已经自动排除所有移动设备, windows 分区, 手动挂载的所有设备, /proc, /sys, /tmp 下的文件, wubi 的 /host 内容, 等等。\n所以在绝大多数情况下你只需要直接回车就可以了。\n如果你排除了重要的系统文件/目录, 不要指望你的备份能够工作。"
586 read ex
587 while [ "$ex" != "" ]; do
588 ex=`dequotepath "$ex"`
589 [ "${ex#/}" = "$ex" ] && { echoen "You must specify the absolute path"; echocn "请使用绝对路径"; read ex; continue; }
590 [ -e "$ex" ] || { echoen "$ex does not exist"; echocn "$ex 并不存在"; read ex; continue; }
591 ex="${ex#/}"
592 echo $ex >> $exclude
593 read ex
594 done
595
596 rebuildtree $bindingdir
597
598 for i in /$bindingdir/media/*; do
599 ls -ld "$i" | grep "^drwx------ " > /dev/null || continue
600 [ `ls -A "$i" | wc -l` = 0 ] || continue
601 echo "${i#/$bindingdir/}" >> $exclude
602 done
603
604 echoreden "Start to backup?(y/n)"
605 echoredcn "开始备份?(y/n)"
606 read yn
607 [ "$yn" != "y" ] && { destroytree $bindingdir; rm $exclude; exit 1; }
608 stime=`date`
609 mkdir -p "/$backupdir"
610 mksquashfs /$bindingdir "/$backupdir/backup$today.squashfs" -ef $exclude
611 destroytree $bindingdir
612 rm $exclude
613 cp /boot/initrd.img-`uname -r` "/$backupdir"
614 cp /boot/vmlinuz-`uname -r` "/$backupdir"
615 sqshboot_menulst > "/$backupdir/menu.lst"
616 thisuser=`basename ~`
617 chown -R $thisuser:$thisuser "/$backupdir" 2> /dev/null
618 echoreden "Your backup is ready in /$backupdir. Please read the menu.lst inside :)"
619 echoreden " started at: $stime\nfinished at: `date`"
620 echoredcn "已备份至 /$backupdir。请阅读里面的 menu.lst :)"
621 echoredcn "开始于: $stime\n结束于: `date`"
622 tput bel
623}
624
625dorestore(){
626 sqshmnt="/rofs"
627 tgtmnt=""
628 haswap="no"
629 hasboot="no"
630
631 declare -a part oldfstype newfstype partinfo
632 packagecheck_r
633 echoreden "This will restore your backup. Continue? (y/n)"
634 echoredcn "将恢复你的备份。继续? (y/n)"
635 read yn
636 [ "$yn" != "y" ] && exit 1
637
638 echoreden "Specify the squashfs backup file (absolute path). You can drag the file from Nautilus File Manager and drop it here. If you are booting from the backup squashfs, you can just hit enter, and the squashfs you are booting from will be used."
639 echoredcn "指定 squashfs 备份文件 (绝对路径)。可以从 Nautilus 文件管理器拖放。\n从备份的 squashfs 启动的,直接回车即可,将使用本次启动的 squashfs 文件。"
640 read backupfile
641 [ "$backupfile" = "" ] && { ls /rofs > /dev/null 2>&1 || { echoreden "/rofs not found"; echoredcn "/rofs 没看到。"; exit 1; } }
642 [ "$backupfile" != "" ] && { backupfile="`dequotepath "$backupfile"`"; sqshmnt=`new_dir /tmp/sqsh`; mkdir $sqshmnt; mount -o loop "$backupfile" $sqshmnt 2> /dev/null || { echoreden "$backupfile mount error"; echoredcn "$backupfile 挂载不上"; rmdir $sqshmnt; exit 1; } }
643
644 probe_partitions
645 setup_target_partitions
646 echoreden "Start to format partitions (if any). Continue? (y/n)"
647 echoredcn "开始格式化分区 (如果有需要格式化的分区的话)。继续? (y/n)"
648 read yn
649 [ "$yn" != "y" ] && [ "$sqshmnt" != "/rofs" ] && { umount $sqshmnt; rmdir $sqshmnt; }
650 [ "$yn" != "y" ] && exit 1
651 umount_target_partitions
652 format_target_partitions
653 chkuuids
654 mount_target_partitions
655
656 echoreden "If you have other partitions for the target system, open another terminal and mount them to appropriate places under $tgt. Then press return."
657 echoredcn "如果你为目标系统安排了其他分区, 现在打开另一个终端并挂载它们在 $tgt 下合适的地方。完成后回车。"
658 read yn
659
660 tgtmnt=`gettargetmount $tgt`
661 defaultgrubdev=`getdefaultgrubdev "$tgtmnt"`
662 [ $? = 67 ] && hasboot=yes
663 echoreden "Specify the place into which you want to install GRUB."
664 echoreden "`expr substr $defaultgrubdev 1 8` and $defaultgrubdev are recommended."
665 echoredcn "把 GRUB 安装到哪里?"
666 echoredcn "建议安装到 `expr substr $defaultgrubdev 1 8` 或 $defaultgrubdev"
667 select grubdev in `listgrubdev`; do
668 [ "$grubdev" = "" ] && continue
669 break
670 done
671 grubdev=${grubdev%,*}
672
673 echoreden "The restore process will launch. Continue?(y/n)"
674 echoredcn "将马上开始恢复。继续?(y/n)"
675 read yn
676 [ "$yn" != "y" ] && [ "$sqshmnt" != "/rofs" ] && { umount $sqshmnt; rmdir $sqshmnt; }
677 [ "$yn" != "y" ] && { cleartgtmnt; exit 1; }
678 stime=`date`
679 cp -av $sqshmnt/* $tgt
680 rm -f $tgt/etc/initramfs-tools/conf.d/resume
681 touch $tgt/etc/mtab
682 generate_fstab "$tgt"
683 target_cmd "$tgt" update-initramfs -u
684
685 if [ "${grubdev#/dev/}" != "$grubdev" ]; then
686 mv $tgt/boot/grub `new_dir $tgt/boot/grub.old` 2> /dev/null
687 grub-install -v | grep 0. > /dev/null && grub1
688 grub-install -v | grep 1. > /dev/null && grub2
689 fi
690
691 makelostandfound
692 tput bel
693 echoreden "Restore started at: $stime,\n finished at: `date`"
694 echoredcn "恢复过程开始于: $stime,\n 结束于: `date`"
695 [ "$haswap" = "no" ] && makeswapfile $tgt
696 [ "$sqshmnt" != "/rofs" ] && { umount $sqshmnt; rmdir $sqshmnt; }
697
698 echoreden "Enter new hostname or leave blank to use the old one."
699 echoredcn "输入新的主机名。留空将使用旧的主机名。"
700 oldhostname=`cat $tgt/etc/hostname`
701 echoreden "old hostname: $oldhostname"
702 echoreden "new hostname:"
703 echoredcn "旧的主机名: $oldhostname"
704 echoredcn "新的主机名:"
705 read newhostname
706 [ "$newhostname" != "" ] && { echo $newhostname > $tgt/etc/hostname; sed -i "s/\t$oldhostname/\t$newhostname/g" $tgt/etc/hosts; }
707
708 for i in `ls $tgt/home`; do
709 [ -d $tgt/home/$i ] || continue
710 target_cmd "$tgt" id $i 2> /dev/null | grep "$i" > /dev/null || continue
711 echoreden "Do you want to change the name of user $i? (y/n)"
712 echoredcn "是否改变用户名 $i? (y/n)"
713 read yn
714 [ "$yn" != "y" ] && continue
715 echoreden "new username:"
716 echoredcn "新的用户名:"
717 read newname
718 while target_cmd "$tgt" id $newname 2> /dev/null | grep "$newname" > /dev/null; do
719 echoreden "$newname already exists"
720 echoreden "new username:"
721 echoredcn "$newname 已存在"
722 echoredcn "新的用户名:"
723 read newname
724 done
725 [ -e $tgt/home/$newname ] && mv $tgt/home/$newname `new_dir $tgt/home/$newname`
726 target_cmd "$tgt" chfn -f $newname $i
727 target_cmd "$tgt" usermod -l $newname -d /home/$newname -m $i
728 target_cmd "$tgt" groupmod -n $newname $i
729 done
730
731 for i in `ls $tgt/home`; do
732 [ -d $tgt/home/$i ] || continue
733 target_cmd "$tgt" id $i 2> /dev/null | grep "$i" > /dev/null || continue
734 echoreden "Do you want to change the password of user $i? (y/n)"
735 echoredcn "是否改变用户 $i 的密码? (y/n)"
736 read yn
737 while [ "$yn" = "y" ]; do
738 target_cmd "$tgt" passwd $i
739 echoreden "If the password was not successfully changed, now you have another chance to change it. Do you want to change the password of user $i again? (y/n)"
740 echoredcn "如果刚才的密码改变不成功, 你还有机会。是否再次改变用户 $i 的密码? (y/n)"
741 read yn
742 done
743 done
744
745 rm -f $tgt/etc/blkid.tab
746 [ "${part[$usrlocalpart]}" != "" ] && umount ${part[$usrlocalpart]}
747 [ "${part[$homepart]}" != "" ] && umount ${part[$homepart]}
748 [ "${part[$bootpart]}" != "" ] && umount ${part[$bootpart]}
749 [ "${part[$tmppart]}" != "" ] && umount ${part[$tmppart]}
750 [ "${part[$usrpart]}" != "" ] && umount ${part[$usrpart]}
751 [ "${part[$varpart]}" != "" ] && umount ${part[$varpart]}
752 [ "${part[$srvpart]}" != "" ] && umount ${part[$srvpart]}
753 [ "${part[$optpart]}" != "" ] && umount ${part[$optpart]}
754 umount ${part[$rootpart]} || { echoreden "Please umount $tgt yourself"; echoredcn "请自行卸载 $tgt"; }
755
756 echoreden "Done! Enjoy:)"
757 echoredcn "搞定了 :)"
758}
759
760echohelpen(){
761 [ $lang = "en" ] && echo "live ubuntu backup $version, copyleft billbear <billbear@gmail.com>
762
763This program can backup your running ubuntu system to a compressed, bootable squashfs file. When you want to restore, boot the squashfs backup and run this program again. You can also restore the backup to another machine. And with this script you can migrate ubuntu system on a virtual machine or a wubi installation to physical partitions.
764
765Install:
766Just copy this script anywhere and allow execution of the script. I put this script under /usr/local/bin, so that I don't have to type the path to this script everytime.
767
768Use:
769sudo /path/to/this/script -b
770to backup or
771sudo /path/to/this/script -r
772to restore
773You can also type
774sudo bash /path/to/this/script -b
775or
776sudo bash /path/to/this/script -r
777
778Note that
779sudo sh /path/to/this/script -b
780and
781sudo sh /path/to/this/script -r
782will not work.
783
784Backup:
785squashfs-tools is required for this program to backup your system. lupin-casper is required to make a bootable backup.
786You can install them by typing
787sudo apt-get install squashfs-tools lupin-casper
788in a terminal.
789Then you can backup your running ubuntu system by typing
790sudo /path/to/this/script -b
791If you put this script under /usr/local/bin, just type
792sudo `basename $mypath` -b
793and follow the instructions.
794You can specify where to save the backup, files/folders you want to exclude from the backup.
795You don't need to umount external media, windows partitions, or any manually mounted partitions. They will be automatically ignored. Therefore you can save the backup to external media, windows partitions, etc.
796Waring: You must make sure you have enough space to save the backup.
797The program will generate other files needed for booting the backup. Read the menu.lst file the program generated under the backup folder for details on how to boot the backup.
798
799Restore:
800Read the menu.lst file the program generated under the backup folder for details on how to boot the backup.
801After booting into the live ubuntu backup, open a terminal and type
802sudo /path/to/this/script -r
803If you have put this script under /usr/local/bin when backup, now just type
804sudo `basename $mypath` -r
805and follow the instructions.
806Note: This program does not provide a partitioner (it can only format partitions but cannot create, delete, or resize partitions). The backup can be restored to existing partitions. So it is recommended that you include gparted in the backup. And if the partition table has any error, you will not be able to restore the backup until the errors are fixed.
807You can specify partitions and mount points, if you have no swap partition, the program will make a swap file for you if you tell it to do so. It will generate new fstab and install grub. It can also change the hostname, username and password if you tell it to do so." | more
808}
809
810echohelpcn(){
811 [ $lang = "cn" ] && echo "live ubuntu backup $version, copyleft billbear <billbear@gmail.com>
812
813本程序将帮助你备份运行中的 ubuntu 系统为一个可启动的 squashfs 压缩备份文件。
814要恢复的时候, 从备份文件启动并再次运行本程序。
815可以把备份文件恢复到另一台机器。
816可以把虚拟机里的 ubuntu 迁移到真机。
817可以把 wubi 安装的系统迁移到真分区。
818
819安装:
820只要拷贝此脚本到任何地方并赋予执行权限即可。
821我喜欢把它放在 /usr/local/bin 里面, 这样每次运行的时候就不用写绝对路径了。
822
823使用:
824sudo 到此脚本的路径 -b
825是备份,而
826sudo 到此脚本的路径 -r
827是恢复。
828也可以用
829sudo bash 到此脚本的路径 -b
830和
831sudo bash 到此脚本的路径 -r
832
833注意不能用
834sudo sh 到此脚本的路径 -b
835和
836sudo sh 到此脚本的路径 -r
837
838备份:
839程序依赖 squashfs-tools 来工作。
840另外必须安装 lupin-casper 才能做出可启动的备份来。
841在终端用如下命令来安装它们:
842sudo apt-get install squashfs-tools lupin-casper
843而后就可以用这样的命令来备份运行中的 ubuntu 系统了:
844sudo 到此脚本的路径 -b
845如果这个脚本在 /usr/local/bin, 只要这样
846sudo `basename $mypath` -b
847然后根据提示进行就可以了。
848你可以指定存放备份的路径, 以及需要排除的文件和目录。
849不必卸载移动硬盘, windows 分区, 或任何你手动挂载了的分区。它们将会自动被忽略。
850因此你可以直接存放备份到移动硬盘, windows 分区等等。
851小心: 你必须确定有足够的空间来存放备份。
852脚本将会生成启动所需的另外几个文件。
853阅读在备份存放目录生成的 menu.lst,里面会详细告诉你如何从备份文件直接启动。
854
855恢复:
856阅读在备份存放目录生成的 menu.lst,里面会详细告诉你如何从备份文件直接启动。
857启动了 live ubuntu backup 之后, 打开一个终端输入
858sudo 到此脚本的路径 -r
859如果在备份时已经把此脚本放到了 /usr/local/bin, 现在只需敲入
860sudo `basename $mypath` -r
861并根据提示进行恢复就可以了。
862注意:此脚本并不提供分区功能(只能格式化分区但不能创建,删除分区或调整分区大小)。
863只能恢复备份到已有的分区。
864因此建议在备份前安装 gparted,这样恢复时你就有分区工具可用了。
865另外如果分区表有错误, 将不允许恢复备份,直到错误被修复。
866你可以指定若干分区和它们的挂载点。
867如果没有 swap 分区, 可以为你创建一个 swap 文件 (如果你这样要求的话)。
868会自动生成新的 fstab 并安装 grub。
869如果有必要, 还可以改变主机名, 用户名和密码。" | more
870}
871
872
873echousage(){
874 [ $lang = "cn" ] && echo "用法:
875备份:
876sudo bash $mypath -b
877恢复:
878sudo bash $mypath -r
879帮助:
880bash $mypath -h" || echo "Usage:
881sudo bash $mypath -b
882to backup;
883or
884sudo bash $mypath -r
885to restore;
886or
887bash $mypath -h
888to view help."
889}
890
891ls /sbin/vol_id > /dev/null 2>&1 && VOL_ID=vol_id || VOL_ID=VOL_ID
892echo -e "\033[31me\033[0mnglish/\033[31mc\033[0mhinese?"
893read lang
894[ "$lang" = "c" ] && lang=cn || lang=en
895[ "$lang" = "cn" ] && today=`date +%Y.%m.%d` || today=`date +%d.%m.%Y`
896[ "$lang" = "cn" ] && version="V2.2, 2009年11月4日" || version="V2.2, Nov 4th,2009"
897[ "$*" = -h ] && { echohelpen; echohelpcn; exit 0; }
898[ "`id -u`" != 0 ] && { echoen "Root privileges are required for running this program."; echocn "备份和恢复需要 root 权限。"; echousage; exit 1; }
899[ "$*" = -b ] && { dobackup; exit 0; }
900[ "$*" = -r ] && { dorestore; exit 0; }
901echousage
902exit 1