mirror of https://github.com/tLDP/LDP
1036 lines
39 KiB
Plaintext
1036 lines
39 KiB
Plaintext
<![ CDATA [#! /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.
|
|
|
|
# The directory tree where everything is put must already exist and be
|
|
# specified in the environment variable $zip.
|
|
|
|
# Time-stamp: <2007-07-08 10:26:04 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
# 02110-1301, 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:
|
|
|
|
# 2007-06-10: In addition to scanning /etc/fstab for LVM partitions
|
|
# (logical volumes), we also check the device files in /dev. This is
|
|
# because some logical volumes may be mounted by label, and scanning
|
|
# fstab won't pick those up.
|
|
|
|
# 2007-05-22: Changes for FHS compliance. Removed commented out
|
|
# references to ZIP drives. N.B.: we now take the location of where to
|
|
# put things as an environment variable, $zip.
|
|
|
|
# 2006-04-15: Added support for partition type 0x12, "Compaq
|
|
# diagnostic". This type is used for so-called "hidden diagnostics"
|
|
# partitions, e.g. on Lenovo/IBM computers.
|
|
|
|
# 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
# 02110-1301, 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];
|
|
|
|
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, "> ${outputfilepath}bin/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
|
|
|
|
FINIS
|
|
|
|
$mtlvs = open (MTLVS, "> ${outputfilepath}bin/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, "2007");
|
|
|
|
|
|
# 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 ${outputfilepath}metadata/LVM.backs.$pvname $pvname");
|
|
|
|
print (MKLVS "echo \"y\\n\" | pvcreate -ff --uuid \"$uid\"\\\n");
|
|
print (MKLVS " --restorefile ../metadata/lvm/backup/${pvname} $phv\n");
|
|
print (MKLVS "vgcfgrestore --file ../metadata/LVM.backs.$pvname $pvname\n\n");
|
|
}
|
|
|
|
print (MKLVS "# Hideously disty dependent! turn on LVM.\n");
|
|
print (MKLVS "if [ -e /etc/init.d/lvm ] ; then\n");
|
|
print (MKLVS " /etc/init.d/lvm start\nfi\n\n");
|
|
|
|
# Now walk fstab in search of logical volumes. This is
|
|
# necessary to pick up swap partitions, and it may pick up
|
|
# others. We need fstab below to match the partitions up with
|
|
# their mount points, so we keep the array around.
|
|
|
|
%volsfound = ();
|
|
open (FSTAB, "< /etc/fstab")
|
|
or die "Couldn't fork: $!\n";
|
|
@fstab = <FSTAB>;
|
|
foreach $line (@fstab) {
|
|
@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");
|
|
$volsfound{@fstabs[0]} = 3;
|
|
} 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");
|
|
$volsfound{@fstabs[0]} = 2;
|
|
} else {
|
|
print ("Opps, unknown type of logical volume, @fstabs[0]\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
# print ("Volumes already found are: ");
|
|
# while ( ($k, $v) = each %volsfound ) {
|
|
# print ("$k ==> $v ");
|
|
# }
|
|
# print ("\n");
|
|
|
|
# Now walk the logical volume devices and pick up any
|
|
# partitions formated ext3/ext2. This may result in duplicates
|
|
# if the partitions have labels but are mounted by device name
|
|
# rather than by label.
|
|
|
|
opendir (DEVHANDLE, "/dev") or die ("Can't open /dev!!\n");
|
|
while ( defined ($fname = readdir (DEVHANDLE))) {
|
|
@fnames = (@fnames, $fname);
|
|
}
|
|
@sorted = sort (@fnames);
|
|
foreach $fname (@sorted) {
|
|
if ($fname =~ /^VolGroup/ && -d "/dev/$fname") {
|
|
# print ("Inside /dev is $fname.\n");
|
|
opendir (VOLHANDLE, "/dev/$fname")
|
|
or die ("Can't open /dev/$fname!!\n");
|
|
while ( defined ($vname = readdir (VOLHANDLE))) {
|
|
@vnames = (@vnames, $vname);
|
|
}
|
|
@vsorted = sort (@vnames);
|
|
foreach $vname (@vsorted) {
|
|
# print "/dev/$fname/$vname: " . $volsfound{"/dev/$fname/$vname"} . "\n";
|
|
if($vname ne "." && $vname ne ".."
|
|
&& $volsfound{"/dev/$fname/$vname"} < 1) {
|
|
# print ("Inside /dev/$fname is $vname.\n");
|
|
my $journal = 0;
|
|
|
|
# FIX ME: add tests to be sure it's a symlink
|
|
# to a block device.
|
|
|
|
# Is it extX?
|
|
open (DUMP, "dumpe2fs /dev/$fname/$vname 2> /dev/null|");
|
|
|
|
@lines = <DUMP>;
|
|
|
|
if (scalar (@lines) > 1) {
|
|
|
|
# If we've gotten here we have a valid
|
|
# ext[2|3] file system. Now prepare to
|
|
# spit out the commands to recreate
|
|
# it. Get the label, if any, and whether
|
|
# there is a journal or not.
|
|
|
|
foreach $_ (@lines) {
|
|
if (/Filesystem volume name:/) {
|
|
$label = substr ($_, 26);
|
|
chop ($label);
|
|
# print ("\$label is \"$label\".\n");
|
|
}
|
|
if (/has_journal/) {
|
|
$journal = 1;
|
|
}
|
|
|
|
}
|
|
|
|
# get the mount point from fstab so we can mount it.
|
|
foreach $fstab (@fstab) {
|
|
@fstabs = split (" ", $line);
|
|
if (@fstabs[0] eq "LABEL=$label" ) {
|
|
$mountpoint = @fstabs[1];
|
|
# print ("mount point is \"$mountpoint\".\n");
|
|
last;
|
|
}
|
|
}
|
|
if (length ($label) ) {
|
|
$label = "-L \"" . $label . "\"";
|
|
}
|
|
|
|
if ($journal > 0) {
|
|
print (MKLVS "echo\necho making LV /dev/$fname/$vname");
|
|
print (MKLVS " an ext3 partition.\n");
|
|
print (MKLVS "mke2fs -j $label \$blockcheck /dev/$fname/$vname\n\n");
|
|
|
|
print (MTLVS "mkdir -p /target$mountpoint\n");
|
|
print (MTLVS "mount /dev/$fname/$vname /target$mountpoint\n\n");
|
|
} else {
|
|
print (MKLVS "echo\necho making LV /dev/$fname/$vname");
|
|
print (MKLVS " an ext2 partition.\n");
|
|
print (MKLVS "mke2fs $label \$blockcheck /dev/$fname/$vname\n\n");
|
|
|
|
print (MTLVS "mkdir -p /target$mountpoint\n");
|
|
print (MTLVS "mount /dev/$fname/$vname /target$mountpoint\n\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
closedir (VOLHANDLE);
|
|
}
|
|
}
|
|
print (MTLVS "mount | grep -i \"/target\"\n");
|
|
|
|
closedir (DEVHANDLE);
|
|
|
|
close (FSTAB);
|
|
close (MKLVS);
|
|
close (MTLVS);
|
|
|
|
chmod 0700, "${outputfilepath}bin/make.lvs";
|
|
chmod 0700, "${outputfilepath}bin/mount.lvs";
|
|
|
|
# Copy the LVM configuration to where we can get at it...
|
|
system ("cp -rp /etc/lvm ${outputfilepath}metadata/");
|
|
|
|
}
|
|
|
|
# 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/";
|
|
$outputfilepath = $ENV{"zip"} . "/";
|
|
# print "\$outputfilepath is ${outputfilepath}\n";
|
|
|
|
# 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}metadata/${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}metadata/${outputfilename}")
|
|
or die "Couldn't open output file ${outputfilepath}metadata/${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" || @_[$parttype] eq "12" ) {
|
|
# print ("Making DOS primary partition.\n");
|
|
|
|
getBootSector (@_[$dev], "${outputfilepath}metadata/$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
|
|
|| @_[$parttype] eq "12" ) {
|
|
# 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" || @_[$parttype] eq "12" ) {
|
|
# print ("Making DOS logical partition.\n");
|
|
|
|
getBootSector (@_[$dev], "${outputfilepath}metadata/$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
|
|
|| @_[$parttype] eq "12" ) {
|
|
# 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}bin/make.$outputfilename")
|
|
or die "Couldn't open output file ${outputfilepath}bin/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! Turn off LVM.
|
|
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";
|
|
print OUTPUT "dd if=/dev/zero of=$device bs=1024 count=2000\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 $geometry $device < ../metadata/${outputfilename}.sfd\n";
|
|
$fdiskcmd .= "else\n";
|
|
$fdiskcmd .= " echo \"using fdisk.\"\n";
|
|
$fdiskcmd .= " fdisk $geometry $device \< ../metadata/$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}bin/mount.$outputfilename")
|
|
or die "Couldn't open output file ${outputfilepath}bin/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}bin/make.$outputfilename";
|
|
chmod 0700, "${outputfilepath}bin/mount.$outputfilename";
|
|
chmod 0600, "${outputfilepath}metadata/${outputfilename}*";
|
|
]]>
|