请参阅每个脚本开头的注释,以了解其功能的摘要。
此脚本在备份时运行,创建类似于 make.dev.hda 和 mount.dev.x 的脚本(如下所示),供您在恢复时运行。它还会生成类似于 dev.hda 的数据文件(如下所示)。生成的脚本和数据文件的名称取决于作为参数提供给此脚本的设备。该脚本在恢复时运行,用于在硬盘驱动器上构建分区。make.fdisk从下面的 save.metadata 调用。
#! /usr/bin/perl # A perl script to create a script and input file for fdisk to # re-create the partitions on the hard disk, and format the Linux and # Linux swap partitions. The first parameter is the fully qualified # path of the device of the hard disk, e.g. /dev/hda. The two # resulting files are the script make.dev.x and the data file dev.x # (where x is the hard drive described, e.g. hda, sdc). make.dev.x is # run at restore time to rebuild hard drive x, prior to running # restore.metadata. dev.x is the input file for fdisk. # Time-stamp: <2006-04-08 15:23:55 ccurley make.fdisk> # Copyright 2001 through the last date of modification Charles Curley # except for the subroutine cut2fmt. # cut2fmt Copyright (c) 1998 Tom Christiansen, Nathan Torkington and # O'Reilly & Associates, Inc. Permission is granted to use this code # freely EXCEPT for book publication. You may use this code for book # publication only with the explicit permission of O'Reilly & # Associates, Inc. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # In addition, as a special exception, Tom Christiansen, Nathan # Torkington and O'Reilly & Associates, Inc. give permission to use # the code of this program with the subroutine cut2fmt (or with # modified versions of the subroutine cut2fmt that use the same # license as the subroutine cut2fmt), and distribute linked # combinations including the two. You must obey the GNU General # Public License in all respects for all of the code used other than # the subroutine cut2fmt. If you modify this file, you may extend # this exception to your version of the file, but you are not # obligated to do so. If you do not wish to do so, delete this # exception statement and the subroutine cut2fmt from your version. # You can also contact the Free Software Foundation at # http://www.fsf.org/ # Changes: # 2006-04-08: Primitive LVM support. It is kludgy in that it uses # first stage restoration distribution (finnix) specific code to turn # LVM on and off, but otherwise seems to work. # 2006-03-28: We have a problem if swap partitions have # labels. There's no way to retrieve the label from a swap # partition. If we have one & only one swap partition, then we can # pull it out of /etc/fstab. Otherwise the user is on her own. We scan # fstab for swap mount points that have labels for their devices. If # there is one and only one, we assume that's it, otherwise pass. # 2005-10-29: We now provide the geometry as an argument to fdisk # (which does not work on tomsrtbt). We also save data for sfdisk, and # write out make.dev.xxx so that it will use sfdisk if it finds it. # 2005-08-14: Due to experience on Knoppix, we now add the code to # change the partition types to the end of the fdisk input file # instead of right after creating the partition. # 2004 04 10: fdisk v > 2.11 has wider columns. Added code to select # the appropriate cut string based on fdisk's version. # 2004 04 09: Added support for Mandrake's idea of devfs. On Mandrake, # everything is mounted with devfs. So the mount devices are buried # deep in places like /dev/ide/host0/bus0/target0/lun0/part1 instead # of places like /dev/hda1, where $DEITY intended they should be. We # have to reverse from the long devfs device to the shorter old style # that tomsrtbt uses. The alternative is to keep track in an array of # which devfs device belongs to which short device. # 2003 12 29: Changed the regex for detecting whether a file system is # read-write in the code that builds the mount file(s). The old test # does not work if mount returns multiple parameters in the 5th field, # e.g. (rw,errors=remount-ro) on some debian systems. This regex # assumes that the rw parameter is always listed first, which may not # always be the case. If it fails, take out the '\('. Thanks to Pasi # Oja-Nisula <pon at iki dot fi> for pointing this out. # 2003 01 09: Added support for FAT32. We now create two scripts for # each hard drive, make.dev.[as]dx and mount.dev.[as]dx. These create # and make file systems on each partition, and make mount points and # mount them. # 2002 12 25: added support to handle W95 extended (LBA) (f) and W95 # FAT 32 partitions. I have tested this for primary but not logical # partitions. # 2002 09 08: Added minimal support for ext3fs. We now detect mounted # ext3fs partitions & rebuild but with no options. The detection # depends on the command line "dumpe2fs <device> 2>/dev/null | grep -i # journal" producing no output for an ext2fs, and output (we don't # care what) for an ext3fs. # This could stand extension to support non-default ext3 options such # as the type of journaling. Volunteers? # 2002 07 25: Bad block checking is now a command line option (-c) at # the time the product script is run. # 2002 07 03: Corrected the mechanism for specifying the default # drive. # 2001 11 25: Changed the way mke2fs gets its bad block # list. badblocks does not guess at the block size, so you have to get # it (from dumpe2fs) and feed it to badblocks. It is simpler to just # have mke2fs call badblocks, but you do loose the ability to have a # writing test easily. -- C^2 # 2001 11 25: Changed the regex that extracts partition labels from # the mount command. This change does not affect the results at all, # it just makes it possible to use Emacs' perl mode to indent # correctly. I just escaped the left bracket in the regex. -- C^2 # Discussion: # fdisk will spit out a file of the form below if you run it as "fdisk # -l". # root@tester ~/bin $ fdisk -l /dev/hda # Disk /dev/hda: 64 heads, 63 sectors, 1023 cylinders # Units = cylinders of 4032 * 512 bytes # Device Boot Start End Blocks Id System # /dev/hda1 1 9 18112+ 83 Linux # /dev/hda2 10 1023 2044224 5 Extended # /dev/hda5 10 368 723712+ 83 Linux # /dev/hda6 369 727 723712+ 83 Linux # /dev/hda7 728 858 264064+ 83 Linux # /dev/hda8 859 989 264064+ 83 Linux # /dev/hda9 990 1022 66496+ 82 Linux swap # What fdisk does not do is provide output suitable for later # importing into fdisk, a la sfdisk. This script parses the output # from fdisk and creates an input file for fdisk. Use the input file # like so: # fdisk /dev/hdx < dev.hdx # For the bare metal restore package, this script also builds a script # that will execute the above command so you can run it from your zip # disk. Because the bare metal restore scripts all are in /root/bin, # the data file and script created by this script are also placed # there. The same script also creates appropriate Linux file systems, # either ext2fs, or Linux swap. There is limited support for FAT12, # FAT16 and FAT32. For anything else, you're on your own. # Note for FAT32: According to the MS KB, there are more than one # reserved sectors for FAT32, usually 32, but it can vary. Do a search # in M$'s KB for "boot sector" or BPB for the gory details. For more # info than you really need on how boot sectors are used, see # http://support.microsoft.com/support/kb/articles/Q140/4/18.asp # You can also edit dev.x to change the sizes of partitions. Don't # forget, if you change the size of a FAT partition across the 32MB # boundary, you need to change the type as well! Run "fdisk /dev/hda" # or some such, then the l command to see the available partition # types. Then go ahead and edit dev.x appropriately. Also, when moving # partition boundarys with hand edits, make sure you move both logical # and extended partition boundaries appropriately. # Bad block checking right now is a quick read of the partition. A # writing check is also possible but more difficult. You have to run # badblocks as a separate command, and pass the bad block list to # mke2fs in a file (in /tmp, which is a ram disk). You also have to # know how large the blocks are, which you learn by running # dumpe2fs. It gets messy and I haven't done it yet. You probably # don't need it for a new hard drive, but if you have had a hard drive # crash on you and you are reusing it (while you are waiting for its # replacement to come in, I presume), then I highly recommend it. Let # me know how you do it. # For more information contact the author, Charles Curley, at # http://www.charlescurley.com/. # cut2fmt figures out the format string for the unpack function we use # to slice and dice the output from fdisk. From Christiansen and # Torkington, Perl Cookbook 5. sub cut2fmt { my (@positions) = @_; my $template = ''; my $lastpos = 1; foreach $place (@positions) { $template .= "A" . ($place - $lastpos) . " "; $lastpos = $place; } $template .= "A*"; return $template; } # Sub gpl, a subroutine to ship the GPL and other header information # to the current output file. sub gpl { my $FILE = shift; my $year = shift; print $FILE <<FINIS; # Copyright $year through the last date of modification Charles Curley. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # You can also contact the Free Software Foundation at http://www.fsf.org/ # For more information contact the author, Charles Curley, at # http://www.charlescurley.com/. FINIS } sub getBootSector { my $infile = $_[0]; my $outfile = $_[1]; $systemcmd = "dd if=$infile of=$outfile bs=512 count=1 &> /dev/null "; system ($systemcmd); } # If we have one & only one swap partition, then this must be # it. Otherwise the user is on her own. We scan fstab for swap mount # points that have labels for their devices. If there is one and only # one, we assume that's it, otherwise pass. sub getswaplabel { my $dev = $_[0]; $fstabpid = open (FSTAB, "< /etc/fstab") or die "Couldn't fork: $!\n"; while (defined (my $line = <FSTAB>)) { chop ($line); @fstabs = split (" ", $line); if (@fstabs[1] eq "swap") { $swaplabel = @fstabs[0]; if ($swaplabel =~ /LABEL/) { $swaps++; $sl = substr ($swaplabel, 6); } # print ("\"@fstabs[0]\", \"@fstabs[1]\", \"$sl\", $swaps.\n"); break; } } close (FSTAB); # print "label is $sl.\n"; if ($swaps == 1) { $ret = "mkswap \$blockcheck -L $sl"; $ret .= " $dev\n\n"; } else { $ret = "mkswap \$blockcheck $dev\n\n"; } # print ("Returning :$ret\n"); return $ret; } # dolvm is a subroutine to handle LVM partitions. This is # experimental.... $lvms = 0; # true if we've been here before sub dolvm { print ("In dolvm ()...\n"); if ($lvms == 0) { $lvms = 1; # Scan /etc/fstab for the logical volumes and write a script to # make file systems on them and another to mount 'em later on. $mklvs = open (MKLVS, "> make.lvs") or die "Couldn't fork: $!\n"; print MKLVS <<FINIS; #! /bin/sh # A script to create file systems on logical volumes. Created at bare # metal backup time by the Perl script make.fdisk. FINIS &gpl (*MKLVS, "2006"); print MKLVS <<FINIS; export blockcheck=\$1; if [ "\$blockcheck" != "-c" ] && [ -n "\$blockcheck" ] then echo "\${0}: Build file systems on logical volumes." echo "\${0}: -c: block check during file system making." exit 1; fi export LVM_SYSTEM_DIR=\$(pwd)/lvm FINIS $mtlvs = open (MTLVS, "> mount.lvs") or die "Couldn't fork: $!\n"; print MTLVS <<FINIS; #! /bin/sh # A script to mount file systems on logical volumes. Created at bare # metal backup time by the Perl script make.fdisk. FINIS &gpl (*MTLVS, "2006"); # Now cycle through all the known logical volumes & set them # up. N.B.: This has been tested on a machine with only one # LV. But it *should* work. $pvdisp = open (PVDISP, "pvdisplay -c |") or die ("Can't open LVM display.\n"); while (defined (my $pv = <PVDISP>)) { chop ($pv); print ("$pv\n"); @pv = split (":", $pv); $uid = @pv[11]; $pvname = @pv[1]; $phv = @pv[0]; print ("pv $pvname has uid $uid.\n"); # back up the LVM's lvm details. Get the config files. system ("vgcfgbackup -f LVM.backs.$pvname $pvname"); print (MKLVS "echo \"y\\n\" | pvcreate -ff --uuid \"$uid\"\\\n"); print (MKLVS " --restorefile lvm/archive/${pvname}_*.vg $phv\n"); print (MKLVS "vgcfgrestore --file LVM.backs.$pvname $pvname\n\n"); } print (MKLVS "# Hideously disty dependent!\nif [ -e /etc/init.d/lvm ] ; then\n"); print (MKLVS " /etc/init.d/lvm start\nfi\n\n"); $fstabpid = open (FSTAB, "< /etc/fstab") or die "Couldn't fork: $!\n"; while (defined (my $line = <FSTAB>)) { chop ($line); @fstabs = split (" ", $line); if (@fstabs[0] =~ /VolGroup/ ) { # print ("$line\n"); if (@fstabs[2] eq "swap") { print (MKLVS "echo\necho making LV @fstabs[0] a swap partition.\n"); print (MKLVS "mkswap \$blockcheck @fstabs[0]\n\n"); } elsif (@fstabs[2] == "ext3") { print (MKLVS "echo\necho making LV @fstabs[0], @fstabs[1],"); print (MKLVS " an ext3 partition.\n"); print (MKLVS "mke2fs -j \$blockcheck @fstabs[0]\n\n"); print (MTLVS "mkdir -p /target$fstabs[1]\n"); print (MTLVS "mount @fstabs[0] /target$fstabs[1]\n\n"); } elsif (@fstabs[2] == "ext2") { print (MKLVS "echo\necho making LV @fstabs[0], @fstabs[1],"); print (MKLVS " an ext2 partition.\n"); print (MKLVS "mke2fs \$blockcheck @fstabs[0]\n\n"); print (MTLVS "mkdir -p /target$fstabs[1]\n"); print (MTLVS "mount @fstabs[0] /target$fstabs[1]\n\n"); } else { print ("Opps, unknown type of logical volume, @fstabs[0]\n"); } } } print (MTLVS "mount | grep -i \"/target\"\n"); close (FSTAB); close (MKLVS); close (MTLVS); chmod 0700, "${outputfilepath}make.lvs"; chmod 0700, "${outputfilepath}mount.lvs"; # Copy the LVM configuration to where we can get at it... system ("cp -rp /etc/lvm ."); } print ("Leaving dolvm ()...\n"); return ($ret); } # Begin main line code. # Provide a default device. # print "\$ARGV[0] is $ARGV[0].\n"; $device = defined ($ARGV[0]) ? $ARGV[0] : "/dev/hda"; # Need to check to see if $device is a sym link. If it is, the mount # point is the target of the link. (Mandrake) Otherwise we search for # mount points on $device. Fedora, Red Hat. if ( -l $device) { # It is a sym link. Get the target of the link, then make it into # an absolute path, preserving the numbering. $mountdev = '/dev/' . readlink ($device); $mountdev =~ s|ide/host(\d+)/bus(\d+)/target(\d+)/lun(\d+)/disc |ide/host\1/bus\2/target\3/lun\4|x; } else { # not a sym link; just assign it. $mountdev = $device; } # print "Device is $device; mount device is $mountdev.\n"; # Prepare format string. Here are two format strings I have found # useful. Here, column numbers are 1 based, i.e. the leftmost column # is column 1, not column 0 as in Emacs. # We select a format string according to fdisk's version. $fdpid = open (FDVER, "fdisk -v |") or die "Couldn't fork: $!\n"; while (<FDVER>) { @_ = unpack ("A7 A*", $_); $fdver=$_[1]; $fdver =~ s/[^\d.]//g; # strip non-numbers, non-periods, as in "2.12pre". } # print "fdisk version is $fdver\n"; if ($fdver < 2.12) { # fdisk to 2.11?? Red Hat, Fedora Core 1 $fmt = cut2fmt (11, 19, 24, 34, 45, 49); } else { # fdisk 2.12 & up?? Mandrake 10.0, Fedora Core 2 $fmt = cut2fmt (12, 14, 26, 38, 50, 55); } # print "Format string is $fmt.\n"; # define fields in the array @_. $dev = 0; $bootable = 1; $firstcyl = 2; $lastcyl = 3; $parttype = 5; $partstring = 6; $target = "\/target"; $outputfilename = $device; $outputfilename =~ s/\//./g; $outputfilename = substr ($outputfilename, 1, 100); $outputfilepath = "/root/bin/"; # Make a hash of the labels. $mpid = open (MOUNT, "mount -l |") or die "Couldn't fork: $!\n"; while (<MOUNT>) { if ($_ =~ /^$mountdev/i) { # is this a line with a partition in it? # print $_; # print it just for grins split; if ($_[6] ne "") { # only process if there actually is a label $_[6] =~ s/[\[\]]//g; # strike [ and ]. $labels{$_[0]} = $_[6]; # print "The label of file device $_[0] is $labels{$_[0]}.\n"; } # We only mount if it's ext2fs or ext3fs and read and write. if ($_[4] =~ /ext[23]/ and $_[5] =~ /\(rw/ ) { if ($_[0] =~ /ide/i) { # We have a devfs system, e.g. Mandrake. This code # converts back from the devfs designation to the old # /dev/hd* designation for tomsrtb. I have NOT checked # this out for drives other than /dev/hda. Also, this # code does not handle SCSI drives. if ( $_[0] =~ /target0/ && $_[0] =~ /bus0/ ) { $letter = 'a'; } elsif ( $_[0] =~ /target1/ && $_[0] =~ /bus0/) { $letter = 'b'; } elsif ( $_[0] =~ /target0/ && $_[0] =~ /bus1/) { $letter = 'c'; } else { $letter = 'd'; } $_[0] =~ s|/ide/host\d+/bus\d+/target\d+/lun\d+/part|/hd|g; $_[0] =~ s/hd/hd$letter/; } $mountpoints{$_[2]} = $_[0]; # print "$_[2] is the mountpoint for tomsrtbt"; # print " device $mountpoints{$_[2]}.\n"; } } } close (MOUNT); # Get sfdisk output. If we have sfdisk at restore time (e.g. Knoppix), # we'll use it. system "sfdisk -d $device > $outputfilepath${outputfilename}.sfd"; # Otherwise we'll use the output from fdisk, which may or may not be # any more accurate. $fpid = open (FDISK, "fdisk -l $device |") or die "Couldn't fork: $!\n"; open (OUTPUT, "> $outputfilepath${outputfilename}") or die "Couldn't open output file $outputfilepath${outputfilename}.\n"; while (<FDISK>) { if ($_ =~ /^$device/i) { # is this a line with a partition in it? # print $_; # print it just for grins chop; # kill trailing \r @_ = unpack ($fmt, $_); # Now strip white spaces from cylinder numbers, white space & # leading plus signs from partition type. @_[$firstcyl] =~ s/[ \t]+//; @_[$lastcyl] =~ s/[ \t]+//; @_[$parttype] =~ s/[+ \t]+//; $partnumber = substr(@_[$dev], 8, 10); # get partition number for this line # just for grins # print " $partnumber, @_[$firstcyl], @_[$lastcyl],"; # print " @_[$parttype], @_[$partstring]\n"; # Here we start creating the input to recreate the partition # this line represents. print OUTPUT "n\n"; if ($partnumber < 5) { # primary Linux partition if (@_[$parttype] == 83) { print OUTPUT "p\n$partnumber\n@_[$firstcyl]\n"; # in case it's all on one cylinder if (@_[$firstcyl] ne @_[$lastcyl]) { print OUTPUT "@_[$lastcyl]\n"; } # Now detect if this is an ext3 (journaling) # partition. We do this using dumpe2fs to dump the # partition and grepping on "journal". If the # partition is ext2, there will be no output. If it is # ext3, there will be output, and we use that fact to # set a command line switch. The command line switch # goes into an associative array (hash) so we don't # have to remember to reset it to the null string when # we're done. $dpid = open (DUMPE2FS, "dumpe2fs @_[$dev] 2>/dev/null | grep -i journal |") or die "Couldn't fork: $!\n"; while (<DUMPE2FS>) { # print "Dumpe2fs: $_"; $ext3{$_[$dev]} = "-j "; last; } close (DUMPE2FS); if ($labels{@_[$dev]}) { # do we have a label? $format .= "echo\necho formatting $checking@_[$dev]\n"; $format .= "mke2fs $ext3{$_[$dev]}\$blockcheck"; $format .= " -L $labels{@_[$dev]} @_[$dev]\n\n"; } else { $format .= "echo\necho formatting $checking@_[$dev]\n"; $format .= "mke2fs $ext3{$_[$dev]}\$blockcheck @_[$dev]\n\n"; } # extended partition } elsif (@_[$parttype] == 5) { # print ("Creating Extended Partition.\n"); print OUTPUT "e\n$partnumber\n@_[$firstcyl]\n"; if (@_[$firstcyl] ne @_[$lastcyl]) { print OUTPUT "@_[$lastcyl]\n"; } # extended partition, Win95 Ext'd (LBA) } elsif (@_[$parttype] eq "f") { # print ("Creating Extended LBA Partition.\n"); print OUTPUT "e\n$partnumber\n@_[$firstcyl]\n"; if (@_[$firstcyl] ne @_[$lastcyl]) { print OUTPUT "@_[$lastcyl]\n"; } $typechanges .= "t\n$partnumber\nf\n"; # primary Linux swap partition } elsif (@_[$parttype] == 82) { print OUTPUT "p\n$partnumber\n@_[$firstcyl]\n"; if (@_[$firstcyl] ne @_[$lastcyl]) { print OUTPUT "@_[$lastcyl]\n"; } $typechanges .= "t\n$partnumber\n82\n"; $format .= "echo\necho Making @_[$dev] a swap partition.\n"; if ($labels{@_[$dev]}) { # do we have a label? $format .= "mkswap \$blockcheck -L $labels{@_[$dev]}"; $format .= " @_[$dev]\n\n"; } else { $format .= getswaplabel (@_[$dev]); } # Primary mess-dos partition. We don't handle hidden # partitions. } elsif ( @_[$parttype] == 1 || @_[$parttype] == 4 || @_[$parttype] == 6 || @_[$parttype] eq "b" || @_[$parttype] eq "c" || @_[$parttype] eq "e" ) { # print ("Making DOS primary partition.\n"); getBootSector (@_[$dev], "$outputfilepath$outputfilename$partnumber"); print OUTPUT "p\n$partnumber\n@_[$firstcyl]\n"; # in case it's all on one cylinder if (@_[$firstcyl] ne @_[$lastcyl]) { print OUTPUT "@_[$lastcyl]\n"; } $typechanges .= "t\n$partnumber\n@_[$parttype]\n"; $format .= "echo\necho formatting $checking@_[$dev]\n"; $format .= "mkdosfs \$blockcheck"; if ( @_[$parttype] == b || @_[$parttype] == c) { # We have a W9x FAT32 partition. Add a command line switch. $format .= " -F 32"; } $format .= " @_[$dev]\n"; $format .= "# restore FAT boot sector.\n"; $format .= "dd if=$outputfilename$partnumber"; $format .= " of=@_[$dev] bs=512 count=1\n\n"; } elsif ( @_[$parttype] == "8e") { $format .= dolvm (); } else { # anything else partition print OUTPUT "p\n@_[$firstcyl]\n"; if (@_[$firstcyl] ne @_[$lastcyl]) { print OUTPUT "@_[$lastcyl]\n"; } $typechanges .= "t\n$partnumber\n@_[$parttype]\n"; } } else { # logical Linux partition if (@_[$parttype] == 83) { print OUTPUT "l\n@_[$firstcyl]\n"; if (@_[$firstcyl] ne @_[$lastcyl]) { print OUTPUT "@_[$lastcyl]\n"; } # Now detect if this is an ext3 (journaling) # partition. We do this using dumpe2fs to dump the # partition and grepping on "journal". If the # partition is ext2, there will be no output. If it is # ext3, there will be output, and we use that fact to # set a command line switch. The command line switch # goes into an associative array (hash) so we don't # have to remember to reset it to the null string when # we're done. $dpid = open (DUMPE2FS, "dumpe2fs @_[$dev] 2>/dev/null | grep -i journal |") or die "Couldn't fork: $!\n"; while (<DUMPE2FS>) { # print "Dumpe2fs: $_"; $ext3{$_[$dev]} = "-j "; last; } close (DUMPE2FS); if ($labels{@_[$dev]}) { # do we have a label? $format .= "echo\necho formatting $checking@_[$dev]\n"; $format .= "mke2fs $ext3{@_[$dev]}\$blockcheck"; $format .= " -L $labels{@_[$dev]} @_[$dev]\n\n"; } else { $format .= "echo\necho formatting $checking@_[$dev]\n"; $format .= "mke2fs $ext3{@_[$dev]}\$blockcheck @_[$dev]\n\n"; } # logical Linux swap partition } elsif (@_[$parttype] == 82 ) { print OUTPUT "l\n@_[$firstcyl]\n"; if (@_[$firstcyl] ne @_[$lastcyl]) { print OUTPUT "@_[$lastcyl]\n"; } $typechanges .= "t\n$partnumber\n82\n"; $format .= "echo\necho Making @_[$dev] a swap partition.\n"; if ($labels{@_[$dev]}) { # do we have a label? $format .= "mkswap \$blockcheck -L $labels{@_[$dev]}"; $format .= " @_[$dev]\n\n"; } else { $format .= getswaplabel (@_[$dev]); } # Logical mess-dos partition. We don't handle hidden # partitions. } elsif ( @_[$parttype] == 1 || @_[$parttype] == 4 || @_[$parttype] == 6 || @_[$parttype] eq "b" || @_[$parttype] eq "c" || @_[$parttype] eq "e" ) { # print ("Making DOS logical partition.\n"); getBootSector (@_[$dev], "$outputfilepath$outputfilename$partnumber"); print OUTPUT "l\n$partnumber\n@_[$firstcyl]\n"; # in case it's all on one cylinder if (@_[$firstcyl] ne @_[$lastcyl]) { print OUTPUT "@_[$lastcyl]\n"; } $typechanges .= "t\n$partnumber\n@_[$parttype]\n"; $format .= "echo\necho formatting $checking@_[$dev]\n"; $format .= "mkdosfs \$blockcheck"; if ( @_[$parttype] == b || @_[$parttype] == c) { # We have a W9x FAT32 partition. Add a command line switch. $format .= " -F 32"; } $format .= " @_[$dev]\n"; $format .= "# restore FAT boot sector.\n"; $format .= "dd if=$outputfilename$partnumber"; $format .= " of=@_[$dev] bs=512 count=1\n\n"; } elsif ( @_[$parttype] == "8e") { $format .= dolvm (); } else { # anything else partition print OUTPUT "l\n@_[$firstcyl]\n"; if (@_[$firstcyl] ne @_[$lastcyl]) { print OUTPUT "@_[$lastcyl]\n"; } $typechanges .= "t\n$partnumber\n@_[$parttype]\n"; } } # handle bootable partitions if (@_[$bootable] =~ /\*/) { print OUTPUT "a\n$partnumber\n"; } } else { # If we got here, the current line does not have a partition in it. # Get the geometry for fdisk. Force fdisk to use the current # geometry at restoration time. Comment this out for # tomstrbt's fdisk; it doesn't like it. if ($_ =~ /heads.*sectors.*cylinders/i) { # print $_; # again, for grins. chop; @geometry = split (/ /, $_); $geometry = "-H $geometry[0] -S $geometry[2] -C $geometry[4]"; # print $geometry; } } } # Append all the partition type changes, validate, and print out the # results. print OUTPUT "${typechanges}v\nw\n"; close (OUTPUT); close (FDISK); open (OUTPUT, "> ${outputfilepath}make.$outputfilename") or die "Couldn't open output file ${outputfilepath}make.$outputfilename.\n"; print OUTPUT <<FINIS; #! /bin/sh # A script to restore the partition data of a hard drive and format # the partitions. Created at bare metal backup time by the Perl script # make.fdisk. FINIS &gpl (*OUTPUT, "2001"); print OUTPUT <<FINIS; swapoff -a # Hideously disty dependent! if [ -e /etc/init.d/lvm ] ; then /etc/init.d/lvm stop fi export blockcheck=\$1; if [ "\$blockcheck" != "-c" ] && [ -n "\$blockcheck" ] then echo "\${0}: automated restore with no human interaction." echo "\${0}: -c: block check during file system making." exit 1; fi FINIS # Clean the old partition table out. Turn off swap in case we're using # it. print OUTPUT "dd if=/dev/zero of=$device bs=512 count=2\n\nsync\n\n"; # command for fdisk $fdiskcmd .= "# see if we have sfdisk & if so use it.\n"; $fdiskcmd .= "if which sfdisk ; then\n"; $fdiskcmd .= " echo \"Using sfdisk.\"\n"; $fdiskcmd .= " sfdisk --force $geometry $device < ${outputfilename}.sfd\n"; $fdiskcmd .= "else\n"; $fdiskcmd .= " echo \"using fdisk.\"\n"; $fdiskcmd .= " fdisk $geometry $device \< $outputfilename\n"; $fdiskcmd .= "fi\n\nsync\n\n"; print OUTPUT $fdiskcmd; print OUTPUT $format; print OUTPUT "fdisk -l \"$device\"\n"; close (OUTPUT); # Now build the script that will build the mount points on the root # and other partitions. open (OUTPUT, "> ${outputfilepath}mount.$outputfilename") or die "Couldn't open output file ${outputfilepath}make.$outputfilename.\n"; print OUTPUT <<FINIS; #! /bin/sh # A script to create a minimal directory tree on the target hard drive # and mount the partitions on it. Created at bare metal backup time by # the Perl script make.fdisk. FINIS &gpl (*OUTPUT, "2001"); print OUTPUT <<FINIS; # WARNING: If your Linux system mount partitions across hard drive # boundaries, you will have multiple "mount.dev.* scripts. You must # ensure that they run in the proper order. The root partition should # be mounted first, then the rest in the order they cascade. If they # cross mount, you'll have to handle that manually. FINIS # We have a hash of mount points and devices in %mountpoints. However, # we have to process them such that directories are built on the # appropriate target partition. E.g. where /usr/local is on its own # partition, we have to mount /usr before we build /usr/local. We can # ensure this by sorting them. Shorter mount point paths will be built # first. We can't sort a hash directly, so we use an array. # We build commands to create the appropriate mount points and then # mount the partitions to the mount points. This is in preparation for # untarring the contents of the ZIP disk, done in restore.metadata. foreach $point ( sort keys %mountpoints) { print OUTPUT "\n# $point is the mountpoint for"; print OUTPUT " tomsrtbt device $mountpoints{$point}.\n"; print OUTPUT "mkdir -p $target$point\n"; print OUTPUT "mount $mountpoints{$point} $target$point\n"; } print OUTPUT "\nmount | grep -i \"/target\"\n"; close (OUTPUT); # These scripts are dangerous & should only be visible to root. chmod 0700, "${outputfilepath}make.$outputfilename"; chmod 0700, "${outputfilepath}mount.$outputfilename"; chmod 0600, "${outputfilepath}${outputfilename}*"; |
此脚本是 make.fdisk(如上所述)生成的脚本示例。它使用类似于 dev.hda 的数据文件(如下所示)。它构建分区并在其中一些分区上放置文件系统。这是恢复时运行的第一个脚本。
如果您足够勇敢去编辑 dev.hda(请参阅),例如,添加新分区,您可能还需要编辑此脚本。
如果您希望 make.dev.hda 在分区上放置文件系统时检查坏块,请使用 "-c" 命令行选项。
#! /bin/sh # A script to restore the partition data of a hard drive and format # the partitions. Created at bare metal backup time by the Perl script # make.fdisk. # Copyright 2001 through the last date of modification Charles Curley. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # You can also contact the Free Software Foundation at http://www.fsf.org/ # For more information contact the author, Charles Curley, at # http://www.charlescurley.com/. export blockcheck=$1; if [ "$blockcheck" != "-c" ] && [ -n "$blockcheck" ] then echo "${0}: automated restore with no human interaction." echo "${0}: -c: block check during file system making." exit 1; fi dd if=/dev/zero of=/dev/hda bs=512 count=2 swapoff -a sync # see if we have sfdisk & if so use it. if which sfdisk ; then echo "Using sfdisk." sfdisk -H 128 -S 63 -C 523 /dev/hda < dev.hda.sfd else echo "using fdisk." fdisk -H 128 -S 63 -C 523 /dev/hda < dev.hda fi sync echo echo formatting /dev/hda1 mkdosfs $blockcheck /dev/hda1 # restore FAT boot sector. dd if=dev.hda1 of=/dev/hda1 bs=512 count=1 echo echo formatting /dev/hda2 mke2fs -j $blockcheck -L /boot /dev/hda2 echo echo formatting /dev/hda3 mke2fs -j $blockcheck -L / /dev/hda3 echo Making /dev/hda5 a swap partition. mkswap $blockcheck /dev/hda5 fdisk -l "/dev/hda" |
make.lvs由 make.fdisk 生成,但仅当存在逻辑卷时才生成。顾名思义,它构建逻辑卷并在其上创建文件系统。
#! /bin/sh # A script to create file systems on logical volumes. Created at bare # metal backup time by the Perl script make.fdisk. # Copyright 2006 through the last date of modification Charles Curley. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # You can also contact the Free Software Foundation at http://www.fsf.org/ # For more information contact the author, Charles Curley, at # http://www.charlescurley.com/. export blockcheck=$1; if [ "$blockcheck" != "-c" ] && [ -n "$blockcheck" ] then echo "${0}: Build file systems on logical volumes." echo "${0}: -c: block check during file system making." exit 1; fi export LVM_SYSTEM_DIR=$(pwd)/lvm.cfg echo "y\n" | pvcreate -ff --uuid "CCmw0N-0We2-HzRS-jRZa-FkC7-NxTc-oAfvpX"\ --restorefile lvm.cfg/archive/VolGroup00_*.vg /dev/hda3 vgcfgrestore --file LVM.backs VolGroup00 # Hideously disty dependent! if [ -e /etc/init.d/lvm ] ; then /etc/init.d/lvm start fi echo echo making LV /dev/VolGroup00/LogVol00 an ext3 partition. mke2fs -j $blockcheck /dev/VolGroup00/LogVol00 echo echo making LV /dev/VolGroup00/LogVol02 an ext3 partition. mke2fs -j $blockcheck /dev/VolGroup00/LogVol02 echo echo making LV /dev/VolGroup00/LogVol01 a swap partition. mkswap $blockcheck /dev/VolGroup00/LogVol01 |
此脚本是 make.fdisk(如上所述)生成的脚本示例。它构建挂载点并将分区挂载到这些挂载点上,使目标文件系统准备好用于恢复文件。这是恢复时运行的第二个脚本。
如果您足够勇敢去编辑 dev.hda(请参阅),例如,添加新分区,您可能还需要编辑此脚本。
#! /bin/sh # A script to create a minimal directory tree on the target hard drive # and mount the partitions on it. Created at bare metal backup time by # the Perl script make.fdisk. # Copyright 2001 through the last date of modification Charles Curley. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # You can also contact the Free Software Foundation at http://www.fsf.org/ # For more information contact the author, Charles Curley, at # http://www.charlescurley.com/. # WARNING: If your Linux system mount partitions across hard drive # boundaries, you will have multiple "mount.dev.* scripts. You must # ensure that they run in the proper order. The root partition should # be mounted first, then the rest in the order they cascade. If they # cross mount, you'll have to handle that manually. # / is the mountpoint for tomsrtbt device /dev/hda3. mkdir /target/ mount /dev/hda3 /target/ # /boot is the mountpoint for tomsrtbt device /dev/hda2. mkdir /target/boot mount /dev/hda2 /target/boot mount | grep -i "/dev/hda" |
mount.lvs由 make.fdisk 生成,但仅当存在逻辑卷时才生成。顾名思义,它挂载逻辑卷,为恢复做好准备。
#! /bin/sh # A script to mount file systems on logical volumes. Created at bare # metal backup time by the Perl script make.fdisk. # Copyright 2006 through the last date of modification Charles Curley. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # You can also contact the Free Software Foundation at http://www.fsf.org/ # For more information contact the author, Charles Curley, at # http://www.charlescurley.com/. mkdir -p /target/ mount /dev/VolGroup00/LogVol00 /target/ mkdir -p /target/home mount /dev/VolGroup00/LogVol02 /target/home mount | grep -i "/target" |
此数据文件在恢复时使用。它由脚本 make.dev.hda 提供给 fdisk。它在备份时由 make.fdisk 生成。熟悉 fdisk 的人会认识到,每一行都是一个 fdisk 命令或值,例如柱面号。因此,可以通过编辑此文件来更改分区大小和添加新分区。这就是倒数第二个命令是 v 的原因,用于在写入之前验证分区表。
n p 1 1 29 a 1 n p 2 30 44 n e 3 45 1023 n l 45 944 n l 945 1023 t 1 6 t 6 82 v w |
这是作为备份过程一部分运行的第一个脚本。它调用上面的 make.fdisk。如果您有 SCSI 硬盘驱动器或多个硬盘驱动器要备份,请适当地编辑对 make.fdisk 的调用。
#! /bin/sh # A script to save certain meta-data off to the boot partition. Useful for # restoration. # Time-stamp: <2006-04-05 20:37:09 ccurley save.metadata> # Copyright 2000 through the last date of modification, Charles Curley. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # You can also contact the Free Software Foundation at # http://www.fsf.org/ # 2006-03-26: had a deprecated option in the sort options; fixed that. # 2005-09-09: Added a line to create a boot disk ISO in the ZIP drive. # 2005-08-30: Modernized sub-shell calls, a few other tweaks. # 2005-07-29: Fedora Core 4 mods. Name of the directory to be saved # has to be last. Also, we now specify --numeric-owner so as to avoid # UID problems when using some live CD systems. And we now save to # /var instead of a mounted ZIP disk. # 2005-02-19: Fedora Core 3 mods. # 2003 01 08: We now age the output from rpm -VA to make back # comparisons easier. # The loop that creates directories now has the -p option for mkdir, # which means you can create parents on the fly if they don't already # exist. # initrd is now in the list of directories to create automatically. # We now exclude more stuff when building the tarballs. # 2002 07 01: Went to bzip2 to compress the archives, for smaller # results. This is important in a 100MB ZIP disk. Also some general # code cleanup. # 2002 07 01: The function crunch will tar and BZIP2 the # archives. This is cleaner than the old code, and has better safety # checking. # For more information contact the author, Charles Curley, at # http://www.charlescurley.com/. # Crunch: A function to compress the contents of a directory and put # the archive onto the ZIP disk. # The first parameter is the name of the archive file to be # created. The backup location, $zip, will be prepended and the # extension, "tar.bz2" will be appended. # All following parameters will be taken as additional directories or # files to be put into the archive. function crunch { if [ -z "$1" ] || [ -z "$2" ] # Checks if parameter #1 or #2 is zero length. then echo "-Parameter #1 or #2 is missing.-" # Also if no parameter is passed. return 1 else local file=$1 # The archive file to create shift # Discard the file name local dirs=$@ # The director[y|ies] to archive local tarcmd="tar --numeric-owner -cjf" # The tar command. local tarit="$tarcmd $zip/$file.tar.bz2 $dirs" echo $tarit $tarit # do it!! error=$? # Preserve the exit code if [ $error != 0 ] # Did we fail? then # Yes echo "Tar failed with error $error" echo $tarcmd $zip/$file.tar.bz2 $dirs exit $error # return tar's exit code as ours fi return 0 # For error testing if needed. fi } # Begin the main line code export zip="/var/bare.metal"; # Where we will put archives. Not the ZIP drive here. # export save="/mnt/save"; RPMVABACKS=/etc # where we keep our backups RPMVAROOT=rpmVa # The root name of the pg backups ANC=${RPMVABACKS}/${RPMVAROOT}.anc # name for the oldest (ancient) backup OLD=${RPMVABACKS}/${RPMVAROOT}.old # name for the middling oldest backup NEW=${RPMVABACKS}/${RPMVAROOT}.txt # name for the newest backup if [ -f ${ANC} ]; then echo "Deleting ${ANC}" rm ${ANC} fi if [ -f ${OLD} ]; then echo "Aging ${OLD}" mv ${OLD} ${ANC} fi if [ -f ${NEW} ]; then echo "Aging ${NEW}" mv ${NEW} ${OLD} fi # Now we save hard drive information. Run make.fdisk on each hard # drive in the order in which it mounted from the root partition. That # is, run it first on the hard drive with your root partition, then # any hard drives that mount to the first hard drive, then any hard # drives that mount to those. For example, if your root partition is # on /dev/sdc, run "make.fdisk /dev/sdc" first. # The reason for this is that make.fdisk produces a script to make # mount points and then mount the appropriate partition to them during # first stage restore. Mount points must be created on the partition # where they will reside. The partitions must be mounted in this # order. For example, if your /var and /var/ftp are both separate # partitions, then you must mount /, create /var, then mount /var, # then create /var/ftp. The order in which the script "first.stage" # runs the mounting scripts is based on their time of creation. # If necessary, put a line, "sleep 1" between calls to make.fdisk. echo "Saving hard drive info" make.fdisk /dev/hda # back up RPM metadata echo "Verifying RPMs." rpm -Va | sort -t ' ' -k 3 | uniq > ${NEW} echo "Finished verifying RPMs; now mounting the ZIP drive." # Make sure we have the ZIP drive mounted. # umount $zip # modprobe ppa # Driver for 100MB parallel port ZIP disk # mount $zip # It should have ext2fs on partition 1. # clean it all out # rm -r $zip/* # mkdir -p $zip/lost+found # Since we aren't saving to ZIP disk, we age the local copy. rm -r $zip.old mv $zip $zip.old mkdir $zip echo -e "$(hostname) bare metal ZIP disk, created $(date)" > $zip/README.txt uname -a >> $zip/README.txt # Preserve the release information. Tested with Red Hat/Fedora, should # work with SuSE, Mandrake and other RPM based systems. Debian # equivalent, anyone? for releasefile in $(ls /etc/*release*) ; do # echo $releasefile if [ -e $releasefile ] && [ ! -L $releasefile ] ; then cat $releasefile >> $zip/README.txt fi done echo "Building the ZIP drive backups." # These are in case we need to refer to them while rebuilding. The # rebuilding process should be mostly automated, but you never # know.... fdisk -l /dev/hda > $zip/fdisk.hda ls -al /mnt > $zip/ls.mnt.txt ls -al / > $zip/ls.root.txt cd / # Build our minimal archives on the ZIP disk. These appear to be # required so we can restore later on. crunch root --exclude root/.cpan --exclude root/.mozilla --exclude root/down root crunch boot boot crunch etc --exclude etc/samba --exclude etc/X11 --exclude etc/gconf etc crunch lib lib crunch usr.sbin usr/sbin crunch usr.bin --exclude usr/bin/emacs-x --exclude usr/bin/emacs-21.4-x\ --exclude usr/bin/emacsclient --exclude usr/bin/emacs-nox --exclude\ usr/bin/gs --exclude usr/bin/pine --exclude usr/bin/gimp-1.2\ --exclude usr/bin/doxygen --exclude usr/bin/postgres --exclude\ usr/bin/gdb --exclude usr/bin/kmail --exclude usr/bin/splint\ --exclude usr/bin/odbctest --exclude usr/bin/php --exclude \ usr/bin/xchat --exclude usr/bin/gnucash --exclude usr/bin/pdfetex\ --exclude usr/bin/pdftex --exclude usr/bin/smbcacls\ --exclude usr/bin/evolution-calendar --exclude usr/bin/xpdf\ --exclude usr/bin/xmms usr/bin crunch sbin sbin crunch bin bin crunch dev dev # RH8. Fedora 1 puts them in /lib # crunch kerberos usr/kerberos/lib/ # Now optional saves. # arkeia specific: # crunch arkeia usr/knox # save these so we can use ssh for restore. *crack* for RH 7.0 login # authentication. # RH 8.0 # crunch usr.lib usr/lib/*crack* usr/lib/libz* usr/lib/libssl* usr/lib/libcrypto* # Fedora 1 # crunch usr.lib usr/lib/*crack* usr/lib/libz* usr/lib/libwrap*\ # usr/lib/libk* usr/lib/*krb5* /usr/lib/libgss* # Fedora 3 crunch usr.lib usr/lib/*crack* usr/lib/libz* usr/lib/libwrap*\ usr/lib/libk* usr/lib/*krb5* usr/lib/libgss* # Grub requires these at installation time. crunch usr.share.grub usr/share/grub # save the scripts we used to create the ZIP disk and the ones we will # use to restore it. mkdir $zip/root.bin cp -p /root/bin/* $zip/root.bin rm $zip/root.bin/*~ $zip/root.bin/#*# echo "Testing our results." find $zip -iname "*.bz2" | xargs bunzip2 -t # Not a normal part of the process: we duplicate the ZIP disk onto an # NFS mount elsewhere. # echo "Backing the ZIP drive to the NFS mount." # umount $save # mount $save # rm -r $save/zip # mkdir -p $save/zip # cp -pr $zip $save # Since we're doing system stuff anyway, make a boot disk ISO image # suitable for burning. It uses the current kernel. mkbootdisk --iso --device $zip/bootdisk.$(uname -r).iso $(uname -r) du -hs ${zip}* df -m |
此脚本从 ZIP 磁盘恢复元数据,作为第一阶段恢复。
#! /bin/sh # A script to restore the meta-data from the ZIP disk. This runs under # tomsrtbt only after partitions have been rebuilt, file systems made, # and mounted. It also assumes the ZIP disk has already been # mounted. Mounting the ZIP disk read only is probably a good idea. # Time-stamp: <2006-04-05 20:36:49 ccurley restore.metadata> # Copyright 2000 through the last date of modification Charles Curley. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # You can also contact the Free Software Foundation at http://www.fsf.org/ # 2005-08-03: We now use a relative path, so you can load from # different places depending on the first stage system you are # using. Also added some FC4 tricks, and some changes to better # reproduce the permissions and ownerships. # 2003 08 23: Oops: tar on tomsrtbt does not respect -p. Try setting # umask to 0000 instead. # 2003 02 13: Tar was not preserving permissions on restore. Fixed # that. # 2002 07 01: Went to bzip2 to compress the archives, for smaller # results. This is important in a 100MB ZIP disk. Also some general # code cleanup. # For more information contact the author, Charles Curley, at # http://www.charlescurley.com/. umask 0000 cd .. # Assume we are in root.bin zip=$(pwd); # Where we mount the zip drive. target="/target"; # Where the hard drive to restore is mounted. ls -lt $zip/*.bz2 # Warm fuzzies for the user. cd $target # Restore the archived metadata files. for archive in $( ls $zip/*.bz2 ); do echo $archive ls -al $archive bzip2 -dc $archive | tar -xf - done # Build the mount points for our second stage restoration and other # things. # If you boot via an initrd, make sure you build a directory here so # the kernel can mount the initrd at boot. tmp/.font-unix is for the # xfs font server. for dir in mnt/dosc mnt/zip mnt/imports mnt/nfs proc initrd tmp/.font-unix\ var/empty/sshd var/log back selinux sys /var/cache/yum /var/lock; do mkdir -p $target/$dir done for dir in mnt usr usr/share $(ls -d var/*) selinux usr/lib var var/cache/yum; do chmod go-w $target/$dir done chown root:lock /var/lock chmod 775 /var/lock # [root@jhereg /]# ll -d mnt usr usr/share $(ls -d var/*) selinux usr/lib var var/cache/yum # drwxr-xr-x 4 root root 4096 Oct 10 08:55 mnt # drwxr-xr-x 2 root root 4096 Oct 10 08:41 selinux # drwxr-xr-x 14 root root 4096 Oct 10 08:46 usr # drwxr-xr-x 40 root root 12288 Oct 10 10:40 usr/lib # drwxr-xr-x 63 root root 4096 Oct 10 11:11 usr/share # drwxr-xr-x 20 root root 4096 Oct 10 08:52 var # drwxr-xr-x 2 root root 4096 Oct 10 08:51 var/account # drwxr-xr-x 4 root root 4096 Oct 10 08:53 var/cache # drwxr-xr-x 4 root root 4096 Oct 10 10:44 var/cache/yum # drwxr-xr-x 3 netdump netdump 4096 Aug 22 13:13 var/crash # drwxr-xr-x 3 root root 4096 Oct 10 08:51 var/db # drwxr-xr-x 3 root root 4096 Oct 10 08:52 var/empty # drwxr-xr-x 13 root root 4096 Oct 10 11:11 var/lib # drwxr-xr-x 2 root root 4096 May 22 22:28 var/local # drwxrwxr-x 4 root lock 4096 Sep 1 08:37 var/lock # drwxr-xr-x 7 root root 4096 Oct 10 11:14 var/log # lrwxrwxrwx 1 root root 10 Oct 10 08:42 var/mail -> spool/mail # drwxr-x--- 4 root named 4096 Aug 22 14:33 var/named # drwxr-xr-x 2 root root 4096 May 22 22:28 var/nis # drwxr-xr-x 2 root root 4096 May 22 22:28 var/opt # drwxr-xr-x 2 root root 4096 May 22 22:28 var/preserve # drwxr-xr-x 2 root root 4096 Mar 28 2005 var/racoon # drwxr-xr-x 13 root root 4096 Oct 10 11:14 var/run # drwxr-xr-x 13 root root 4096 Oct 10 08:53 var/spool # drwxrwxrwt 2 root root 4096 Oct 10 11:14 var/tmp # drwxr-xr-x 3 root root 4096 Oct 10 08:53 var/yp # chmod a-w $target/proc # Restore /proc's read-only permissions # Set modes chmod 0111 $target/var/empty/sshd # For Fedora. First two for xfs. # chroot $target chown xfs:xfs /tmp/.font-unix # chmod 1777 $target/tmp/.font-unix # set the sticky bit. chmod 1777 $target/tmp # Restore the scripts we used to create the ZIP disk and the ones we will # use to restore it. These should be the latest & greatest in case we had # to do any editing during 1st stage restore. cp -p $zip/root.bin/* $target/root/bin # Now install the boot sector. # chroot $target /sbin/lilo -C /etc/lilo.conf chroot $target /sbin/grub-install /dev/hda df -m |
此脚本在没有操作员干预的情况下运行整个第一阶段恢复。
如果您希望在分区上放置文件系统时检查坏块,请使用 "-c" 命令行选项。
#! /bin/sh # A master script to run the other, detailed scripts. Use this script # only if you want no human intervention in the restore process. The # only option is -c, which forces bad block checking during formatting # of the partitions. # Time-stamp: <2006-04-05 20:35:39 ccurley first.stage> # Copyright 2002 through the last date of modification Charles Curley. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # You can also contact the Free Software Foundation at http://www.fsf.org/ # For more information contact the author, Charles Curley, at # http://www.charlescurley.com/. # 2005-08-07 We no longer assume the working directory. This is # because the working directory will vary greatly according to which # Linux disty you use and how you are doing your restoration. export blockcheck=$1; if [ "$blockcheck" != "-c" ] && [ -n "$blockcheck" ] then echo "${0}: automated restore with no human interaction." echo "${0}: -c: block check during file system making." exit 1; fi for drive in $( ls make.dev.* ); do echo $drive$'\a' sleep 2 ./$drive $blockcheck; done # If there are any LVM volumes, now is the time to restore them. if [ -e LVM.backs ] && [ -e make.lvs ] && [ -e mount.lvs ] then echo make.lvs$'\a' sleep 2 ./make.lvs echo mount.lvs$'\a' ./mount.lvs fi # WARNING: If your Linux system mount partitions across hard drive # boundaries, you will have multiple "mount.dev.* scripts. You must # ensure that they run in the proper order, which the loop below may # not do. The root partition should be mounted first, then the rest in # the order they cascade. If they cross mount, you'll have to handle # that manually. If you have LVMs to deal with, that's a whole 'nother # kettle of fish. # The "ls -tr" will list the scripts in the order they are created, so # it might be a good idea to create them (in the script save.metadata) # in the order in which you should run them. for drive in $( ls -tr mount.dev.* ); do echo $drive$'\a' sleep 2 ./$drive; done ./restore.metadata # People who are really confident may comment this line in. # reboot |
这些脚本在正在备份或恢复的计算机上运行。
此脚本通过 NFS 挂载保存到另一台计算机。您可以调整它以保存到磁带驱动器或其他介质。
#! /bin/sh # Back up the entire system to another computer's drive. To make this # work, we need a convenient chunk of disk space on the remote computer we # can nfs mount as /mnt/save. # Time-stamp: <2003-04-24 09:56:05 ccurley back.up.all> # Copyright 2000 through the last date of modification Charles Curley. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # You can also contact the Free Software Foundation at http://www.fsf.org/ # For more information contact the author, Charles Curley, at # http://www.charlescurley.com/. save="/mnt/save" # Make sure it's there umount $save mount $save cd / rm $save/tester.tar.old.gz mv $save/tester.tar.gz $save/tester.tar.old.gz # save everything except /mnt, /proc, and nfs mounted directories. time tar cf - / --exclude /mnt --exclude /proc --exclude $save\ | gzip -c > $save/tester.tar.gz |
此脚本的功能与 back.up.all 完全相同,但它使用 ssh 而不是 nfs。
#! /bin/sh # Back up the entire system to another computer's drive. To make this # work, we need a convenient chunk of disk space on the remote # computer. This version uses ssh to do its transfer, and compresses # using bz2. This means this script has to know more about the other # computer, which does not make for good modularization. # Time-stamp: <2003-04-24 09:56:52 ccurley back.up.all.ssh> # Copyright 2000 through the last date of modification Charles Curley. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # You can also contact the Free Software Foundation at http://www.fsf.org/ # For more information contact the author, Charles Curley, at # http://www.charlescurley.com/. save="/backs/tester" backup_server="charlesc" # rotate the old backups. Do it all in one line to minimze authentication overhead. ssh $backup_server "rm $save/tester.tar.old.bz2; mv $save/tester.tar.bz2 \ $save/tester.tar.old.bz2" # save everything except /mnt, /proc, and squid directories. time tar cf - / --exclude /mnt --exclude /proc --exclude /var/spool/squid\ | ssh $backup_server "bzip2 -9 > $save/tester.tar.bz2" |
如果您使用 back.up.all 进行备份,则使用此恢复脚本。
#! /bin/sh # A script to restore all of the data from an nfs mount. This is our final # stage restore. # Time-stamp: <2003-04-24 09:58:51 ccurley restore.all> # Copyright 2000 through the last date of modification Charles Curley. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # You can also contact the Free Software Foundation at http://www.fsf.org/ # For more information contact the author, Charles Curley, at # http://www.charlescurley.com/. export save="/mnt/save" mount $save cd / gunzip -dc $save/tester.tar.gz | tar -xpkf - rm /var/run/*.pid lilo |
如果您使用 back.up.all.ssh 进行备份,则使用此恢复脚本。
#! /bin/sh # A script to restore all of the data using ssh and bunzip2. This is # our final stage restore. # Copyright 2000 through the last date of modification Charles Curley. # Time-stamp: <2003-04-24 09:59:10 ccurley restore.all.ssh> # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # You can also contact the Free Software Foundation at http://www.fsf.org/ # For more information contact the author, Charles Curley, at # http://www.charlescurley.com/. save="/backs/tester/" backup_server="charlesc" cd / ssh $backup_server "cat $save/tester.tar.bz2" | bunzip2 | tar -xpkf - rm /var/run/*.pid lilo |
上面的 ssh 脚本可能存在安全问题。如果您在防火墙上运行它们,则防火墙必须通过 ssh 访问备份服务器。在这种情况下,聪明的黑客也可能能够破解备份服务器。在备份服务器上运行备份和恢复脚本,并让备份服务器访问防火墙会更安全。这些脚本就是为此而设的。将它们重命名为get.x和restore.x其中x是目标计算机的名称。编辑它们(变量 $target 的初始化)以使用目标计算机的主机名,或重写它们以使用命令行参数。
这些脚本完整地备份和恢复目标,而不仅仅是第一阶段备份和恢复。另请注意get.tester也备份 ZIP 磁盘,以防您需要更换故障的 ZIP 磁盘。
我经常使用这些脚本。
#! /bin/sh # Back up another computer's drive to this system. To make this work, # we need a convenient chunk of disk space on this computer. This # version uses ssh to do its transfer, and compresses using bz2. This # version was developed so that the system to be backed up won't be # authenticated to log onto the backup computer. This script is # intended to be used on a firewall. You don't want the firewall to be # authenticated to the backup system in case the firewall is cracked. # Time-stamp: <2006-04-05 20:36:00 ccurley get.tester> # Copyright 2000 through the last date of modification Charles Curley. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # You can also contact the Free Software Foundation at http://www.fsf.org/ # For more information contact the author, Charles Curley, at # http://www.charlescurley.com/. # 2004 04 03: added /sys to the list of excludes. It is a read-only # pseudo-file system like /proc. # 2002 07 01: We now set the path on the target to the zip drive with # a variable. This fixes a bug in the command to eject the zip disk. # 2002 07 01: The zip disk archives are now in bzip2 format, so this # script has been changed to reflect that. # The host name of the computer to be backed up. target=tester #zip=/mnt/zip export zip="/var/bare.metal"; # Where we will put archives. Not the ZIP drive here. echo Backing up $target echo Aging the ZIP disk backups. rm -r $target.old.zip mv $target.zip $target.old.zip # ssh $target "modprobe ppa ; mount -r $zip" echo Copying the ZIP disk. # -r for recursive copy, -p to preserve times and permissions, -q for # quiet: no progress meter. scp -qpr $target:$zip $target.zip du -hs $target.*zip echo Aging the archives rm $target.tar.old.bz2 mv $target.tar.bz2 $target.tar.old.bz2 echo Cleaning out old yum packages ssh $target "yum clean packages" echo Backing up $target to the backup server. # The "--anchored" option is there to prevent --exclude from excluding # all files with that name. E.g. we only want to exclude /sys, not # some other sys elsewhere in the file system. ssh $target "cd / ; tar -cf - --anchored --exclude sys --exclude $zip\ --exclude $zip.old --exclude mnt --exclude proc --exclude var/spool/squid\ *" | bzip2 -9 | cat > $target.tar.bz2 # ssh $target "eject $zip" echo Testing the results. find . -iname "*.bz2" | xargs bunzip2 -t |
#! /bin/sh # A script to restore all of the data to tester via ssh. This is our final # stage restore. # Time-stamp: <2003-04-24 09:59:45 ccurley restore.tester> # Copyright 2000 through the last date of modification Charles Curley. # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # You can also contact the Free Software Foundation at http://www.fsf.org/ # For more information contact the author, Charles Curley, at # http://www.charlescurley.com/. # The host name of the computer to be restored. target=tester bunzip2 -dc $target.tar.bz2 | ssh $target "cd / ; tar -xpkf - " ssh $target lilo |