Linux下使用dd命令备份硬盘

我们最近做的项目是和多方合作,系统依赖的很多程序和设置都来自第三方,系统的运行环境全都做在了一块硬盘里。从我们拿到这块硬盘起系统的运行就没有正常过。经过多日的调试,可以判断出是依赖的一些库和配置文件有错误,导致软件运行异常。多次协调对方也不愿意提供更多关于修复安装和配置的信息(当然可能他们也不知道)。项目开始时没有人留意,出了事故才发现,整个项目的开发过程中,能运行系统的环境竟然在唯一的一块硬盘上。简直是这辈子最苦逼的开发体验,所有人都很重视,所有领导都每天询问,各种高级工程师秒回你的邮件。但是…但是所有的细节都是秘密,所有问实现,问原理,求指导的问题都不正面回答,要求一个纯净的可用的硬盘也没人答复,所有人都等着你探索黑盒子里的秘密……

当然我是幸运的,最后通过其他途径找到一台还能运行的旧版设备,使用硬盘对拷的办法,在一块新的硬盘上克隆了全部运行环境,基于这个环境才搭起了系统。

系统备份和恢复工具选择很多,Windows下的各种一键复原,Mac os下的高大上的Time Machine,Linux下也有Clonezilla这样的全能选手。当然不求助第三方软件,最基本的linux dd 命令也能完成这些功能。这一次紧急情况下,正是这个在只有五寸屏的PowerPC Linux上也有的命令,救了大家一命。

dd命令

dd是Unix/Linux下转换和复制文件的命令,名字和用法都稍显怪异,据说来源于IBM的Job Control Language,意为Data Description。
dd命令秉承Unix哲学,专注文件复制和以及复制过程中的格式转换。但是类Unix操作系统下,万物皆文件,dd命令可以像对待普通文件一样,操作硬件的设备驱动和特殊设备文件等资源,这就赋予了dd命令各种不同的用途:驱动器性能测试,数据恢复,磁盘擦除,修复引导记录……

磁盘备份

使用fdisk 先查看磁盘分区,找到硬盘的位置。

1
sudo  fdisk -u -l

我的情况是需要用一块硬盘完全克隆另一块,只需要指明输入输出的硬盘文件路径就可以了。

1
sudo dd if=/dev/sda of=/dev/sdb

也可以将磁盘备份到image文件。需要注意的是,dd命令是按照文件块操作,如果不指明块的大小和数量,dd命令会对全部硬盘进行复制,并不会跳过磁盘未使用的空间。一定要确保目标文件比原来的磁盘文件大。

1
sudo dd if=/dev/sda of=~/disk1.img

一般情况下,对image文件压缩是更有效的方法。大部分压缩算法会把空白部分完全压缩,只留下标记,对只使用了很少的磁盘文件,可以得到很好的压缩比。

1
2
sudo dd if=/dev/sda | gzip > disk.img.gz
sudo dd if=/dev/sda | bzip2 > disk.img.bz2

需要恢复时,一样的解压拷贝

1
gzip -dc /disk.img.gz | dd of=/dev/sda

显示dd进度

dd命令执行相当的耗时,我100G的硬盘大概用了2个小时,期间dd进程并不反馈任何信息,对用户来说是相当痛苦的等待。其实查看dd的help信息,可以发现如果dd进程收到SIGSUR1 signal,就会在console打印出dd的当前状态,help中也给出了示例的脚本。

1
2
3
4
5
6
7
8
9
10
11
$ dd --help
......
Note that sending a SIGUSR1 signal to a running `dd' process makes it
print to standard error the number of records read and written so far,
then to resume copying.

$ dd if=/dev/zero of=/dev/null& pid=$!
$ kill -USR1 $pid; sleep 1; kill $pid
10899206+0 records in
10899206+0 records out
......

如果要定时更新状态,可以配合watch命令

1
sudo watch -n 5 pkill -USR1 ^dd$

每隔5秒钟打印dd的信息。

1
2
3
4
5
6
7
8
9
208485885+0 records in
208485884+0 records out
106744772608 bytes transferred in 9456.434242 seconds (11288057 bytes/sec)
208639230+0 records in
208639229+0 records out
106823285248 bytes transferred in 9461.445863 seconds (11290376 bytes/sec)
208763265+0 records in
208763264+0 records out
106886791168 bytes transferred in 9466.455442 seconds (11291110 bytes/se