# HG changeset patch # User Heiko Schlittermann # Date 1264025479 -3600 # Node ID 6432e90cc34d4fba7c9bb97df7c870b7b76672d8 # Parent 39421a9700c5e9d0f51652ec4c344a75f8ae725d# Parent 8f9e45f83a656cb40b80231b6e42c2d0087c9c7b merged from default diff -r 39421a9700c5 -r 6432e90cc34d SI/.perltidyrc --- a/SI/.perltidyrc Wed Jan 20 21:35:35 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -../.perltidyrc \ No newline at end of file diff -r 39421a9700c5 -r 6432e90cc34d SI/blkid.pm --- a/SI/blkid.pm Wed Jan 20 21:35:35 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -package SI::blkid; - -use if $ENV{DEBUG} ~~ /blkid|all/ => "Smart::Comments"; - -use strict; -use warnings; -use IO::File; -use File::Basename; - -use SI::tools; - -sub ids($\%) { - my ($file, $devs) = @_; - - my @volumes = sort keys %{ $devs->{volume} }; - verbose("reading blkids: @volumes"); - foreach (`blkid -c /dev/null @volumes`) { - my $dev = (split /:/)[0]; - - my ($uuid) = /\sUUID=.(.*?).\s/; - my ($type) = /\sTYPE=.(.*?).\s/; - my ($label) = /\sLABEL=.(.*?).\s/; - - if (exists $devs->{volume}{$dev}) { - $devs->{volume}{$dev}{uuid} = $uuid; - $devs->{volume}{$dev}{type} = $type; - $devs->{volume}{$dev}{label} = $label; - - my ($of, $oh); - if (defined $uuid) { - $of = sprintf $file, "uuid." . basename $dev; - $oh = new IO::File ">$of" or die "ERR: Can't open $of: $!\n"; - $oh->print("$uuid\n"); - } - - if (defined $label) { - $of = sprintf $file, "label." . basename $dev; - $oh = new IO::File ">$of" or die "ERR: Can't open $of: $!\n"; - $oh->print("$label\n"); - } - - if (defined $type) { - $of = sprintf $file, "type." . basename $dev; - $oh = new IO::File ">$of" or die "ERR: Can't open $of: $!\n"; - $oh->print("$type\n"); - } - - } - - } - verbose("\n"); -} - -1; - -# vim:sts=4 sw=4 aw ai si: diff -r 39421a9700c5 -r 6432e90cc34d SI/dumper.pm --- a/SI/dumper.pm Wed Jan 20 21:35:35 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -package SI::dumper; - -use if $ENV{DEBUG} ~~ /dumper|all/ => "Smart::Comments"; -use strict; -use warnings; -use SI::tools; -use File::Basename; - -sub dump($\%) { - my ($file, $devs) = @_; - - foreach my $volume ( - map { { name => $_, %{ $devs->{volume}{$_} } } } - keys %{ $devs->{volume} } - ) - { - next if !defined $volume->{type} or $volume->{type} !~ /^ext/i; - - verbose("dumping volume $volume->{name}"); - my $dumpdev = $volume->{name}; - my $of = sprintf $file, basename($volume->{name}); - run("dump -0 -z -f $of $dumpdev"); - verbose("\n"); - } -} - -1; - -# vim:sts=4 sw=4 aw ai sm: diff -r 39421a9700c5 -r 6432e90cc34d SI/lvm.pm --- a/SI/lvm.pm Wed Jan 20 21:35:35 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -package SI::lvm; - -use if $ENV{DEBUG} ~~ /lvm|all/ => qw(Smart::Comments); - -use strict; -use warnings; -use IO::File; -use Cwd qw(abs_path); -use File::Basename; - -use SI::tools; - -my @volumegroups = (); - -sub _vgs(\%) { - return @volumegroups if @volumegroups; - - my $devs = shift; - - # find the physical volumes we've already recognised as „non-removable“ - my @known = keys %{ $devs->{volume} }, keys %{ $devs->{disk} }; - - my @pvs = - grep { $_ ~~ @known } map { s/\s*//; (split /:/)[0] } `pvdisplay -c`; - @volumegroups = map { (split /:/)[1] } `pvdisplay -c @pvs 2>/dev/null`; - run("vgchange -ay @volumegroups 2>&1 >/dev/null"); - - # we wait for the /dev/mapper devices to appear - run("udevadm settle"); - return @volumegroups; -} - -sub volumes(\%) { - my ($devs) = @_; - - # we can't just use `pvs', since this would return *all* - # physical devices known to lvm, not just the non-removable - - my @vgs = _vgs(%$devs); - my @lvs = - map { abs_path((dirname $_) . "/" . readlink) } - map { s/^\s*//; (split /:/)[0] } - grep { (split /:/)[1] ~~ @vgs } `lvdisplay -c`; - foreach (@lvs) { - $devs->{volume}{$_} = { origin => "lvm" }; - } - - push @{ $devs->{volumes} }, @lvs; -} - -sub vgcfgbackup($\%) { - my ($file, $devs) = @_; - - # we save it vg by vg to have the restore more easy - my @vgs = _vgs(%$devs); - foreach (map { s/^\s*(.*)/$1/; $_ = (split /:/)[0] } - `vgs --noheadings --separator : @vgs`) - { - verbose("saving vg $_\n"); - my $file = sprintf $file, $_; - run("vgcfgbackup -f '$file' '$_' >/dev/null"); - } - - # for testing let's save it all - verbose("saving vg *\n"); - $file = sprintf $file, "*"; - run("vgcfgbackup -f '$file' >/dev/null"); -} - -1; - -# vim:sts=4 sw=4 aw ai si: diff -r 39421a9700c5 -r 6432e90cc34d SI/mbr.pm --- a/SI/mbr.pm Wed Jan 20 21:35:35 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -package SI::mbr; - -use strict; -use warnings; -use File::Basename; -use IO::File; -use if $ENV{DEBUG} ~~ q(mbr) => "Smart::Comments"; - -use SI::tools; - -sub save($\%) { - my ($file, $devs) = @_; - - foreach my $disk (keys %{ $devs->{disk} }) { - verbose("saving mbr of $disk\n"); - open((my $o), $_ = sprintf(">$file", basename($disk))) - or die "Can't open $_: $!\n"; - - local $/ = \512; - my $in = new IO::File $disk or die "Can't open $disk: $!\n"; - print $o $_ = <$in>; - } -} - -1; diff -r 39421a9700c5 -r 6432e90cc34d SI/ptable.pm --- a/SI/ptable.pm Wed Jan 20 21:35:35 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -package SI::ptable; - -use if $ENV{DEBUG} ~~ /ptable|all/ => qw(Smart::Comments); - -use strict; -use warnings; -use File::Find; -use File::Basename; -use IO::File; - -use SI::tools; -$ENV{LC_ALL} = "C"; - -sub volumes($\%) { - my ($file, $devs) = @_; - - # find the partition tables of all - # non-removable block devices (this may include - # LVs (used as disk itself) too) - foreach (glob("/sys/block/*")) { - my $name = basename($_); - my $dev = "/dev/$name"; - - next if !-e "$_/device"; - next - if (grep { /ATTR{removable}/ } - `udevadm info --attribute-walk --name $name`)[0] !~ /==.0./; - next if (stat $dev)[0] == (stat $0)[0]; - - # exclude the device (stick) we're part of - this HACK is - # only useful on KVM - the usb stick doesn't appear as a removeable - # device - next - if (stat $0)[0] ~~ [ - map { (stat)[6] } - map { "/dev/" . basename(dirname $_) } glob("$_/*/partition") - ]; - - verbose("\n"); - verbose("device $dev\n"); - - die "ERR: $dev does not exist. (should not happen): $!" - if !-b $dev; - - # now the physical disk -- let's ask for the partition table - - my @sfdisk = `sfdisk -d /dev/$name 2>/dev/null`; - - my $of = sprintf $file, $name; - my $oh = new IO::File ">$of" or die "Can't open >$of: $!\n"; - print $oh @sfdisk; - - $devs->{disk}{"/dev/$name"} = { pt => \@sfdisk }; - - # and let's prepare the volume entries - foreach (@sfdisk) { - /^(\S+)\s*:.*Id=\s*([[:xdigit:]]+)/ or next; - $devs->{volume}{$1} = { - origin => "ptable", - ptable_type => $2, - }; - push @{ $devs->{volumes} }, $1; - } - } - - return; -} -1; - -# vim:sts=4 sw=4 aw ai si: diff -r 39421a9700c5 -r 6432e90cc34d SI/system.pm --- a/SI/system.pm Wed Jan 20 21:35:35 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -package SI::system; - -use strict; -use warnings; -use File::Temp qw(tempdir); -use if $ENV{DEBUG} ~~ qw(system) => "Smart::Comments"; -use SI::tools; - -$ENV{LC_ALL} = "C"; - -sub id() { - - # hope it's eth* or wlan* - local $_ = (sort grep { /^(eth|wlan)/ } `ifconfig -a`)[0]; - /^(?\S+)\s.*HWaddr\s+(?[\da-f:]+)\s*$/i - and return $+{mac}; - die "ERR: Can't get system identification (MAC address)\n"; -} - -sub hostname(\%) { - my $devs = shift; - my $mnt = tempdir(CLEANUP => 1); - my $h; - - foreach my $fs ( - grep { - exists $devs->{volume}{$_}{type} - and $devs->{volume}{$_}{type} =~ /^ext/i - } @{ $devs->{volumes} } - ) - { - run("mount -r $fs $mnt"); - if (-f "$mnt/etc/hostname") { - chomp($h = cat("$mnt/etc/hostname")); - } - run("umount $mnt"); - return $h if defined $h; - } - - return $h; -} - -sub fsck(\%) { - my $devs = shift; - - foreach - my $v (grep { exists $devs->{volume}{type} } keys %{ $devs->{volume} }) - { - my $volume = $devs->{volume}{$v}; - next if $volume->{type} !~ /^ext/i; - - system("fsck -C0 $v"); - die "ERR: fsck failed\n" if $? > 2; - } -} - -1; - -# vim:sts=4 sw=4 aw ai si: diff -r 39421a9700c5 -r 6432e90cc34d SI/tools.pm --- a/SI/tools.pm Wed Jan 20 21:35:35 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -package SI::tools; - -use if $ENV{DEBUG} ~~ /tools|all/ => "Smart::Comments"; - -use strict; -use warnings; -use File::Find; -use Data::Dumper; -use base "Exporter"; - -our @EXPORT = qw(&run &verbose &find_by_devid &cat &barf); - -sub run(@) { - system(@_); - die "$_[0] failed with exit code " . ($? >> 8) . "\n" - if $?; -} - -sub barf(@) { die Dumper @_ } - -sub cat($) { - my $fh = new IO::File $_[0] - or die "Can't open $_[0]: $!\n"; - return (<$fh>) if wantarray; - return join "", <$fh>; -} - -my $last = "\n"; - -sub verbose(@) { - print $last eq "\n" ? "" : " " - if not(@_ == 1 and length($_[0]) == 1); - print @_; - $last = substr($_[-1], -1, 1); -} - -sub find_by_devid($$) { - my ($dir, $id) = @_; - my @found; - find( - sub { - push @found, $File::Find::name if (stat)[6] == $id; - return; - }, - $dir - ); - die "ERR: found more than one alias (@found) for $id\n" if @found > 1; - die "ERR: found no alias for $id\n" if not @found; - return $found[0]; -} - -1; - -# vim:sts=4 sw=4 aw ai si: diff -r 39421a9700c5 -r 6432e90cc34d lib/SI/.perltidyrc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/SI/.perltidyrc Wed Jan 20 23:11:19 2010 +0100 @@ -0,0 +1,2 @@ +--paren-tightness=2 +--square-bracket-tightness=2 diff -r 39421a9700c5 -r 6432e90cc34d lib/SI/blkid.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/SI/blkid.pm Wed Jan 20 23:11:19 2010 +0100 @@ -0,0 +1,56 @@ +package SI::blkid; + +use if $ENV{DEBUG} ~~ /blkid|all/ => "Smart::Comments"; + +use strict; +use warnings; +use IO::File; +use File::Basename; + +use SI::tools; + +sub ids($\%) { + my ($file, $devs) = @_; + + my @volumes = sort keys %{ $devs->{volume} }; + verbose("reading blkids: @volumes"); + foreach (`blkid -c /dev/null @volumes`) { + my $dev = (split /:/)[0]; + + my ($uuid) = /\sUUID=.(.*?).\s/; + my ($type) = /\sTYPE=.(.*?).\s/; + my ($label) = /\sLABEL=.(.*?).\s/; + + if (exists $devs->{volume}{$dev}) { + $devs->{volume}{$dev}{uuid} = $uuid; + $devs->{volume}{$dev}{type} = $type; + $devs->{volume}{$dev}{label} = $label; + + my ($of, $oh); + if (defined $uuid) { + $of = sprintf $file, "uuid." . basename $dev; + $oh = new IO::File ">$of" or die "ERR: Can't open $of: $!\n"; + $oh->print("$uuid\n"); + } + + if (defined $label) { + $of = sprintf $file, "label." . basename $dev; + $oh = new IO::File ">$of" or die "ERR: Can't open $of: $!\n"; + $oh->print("$label\n"); + } + + if (defined $type) { + $of = sprintf $file, "type." . basename $dev; + $oh = new IO::File ">$of" or die "ERR: Can't open $of: $!\n"; + $oh->print("$type\n"); + } + + } + + } + verbose("\n"); +} + +1; + +# vim:sts=4 sw=4 aw ai si: diff -r 39421a9700c5 -r 6432e90cc34d lib/SI/dumper.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/SI/dumper.pm Wed Jan 20 23:11:19 2010 +0100 @@ -0,0 +1,30 @@ +package SI::dumper; + +use if $ENV{DEBUG} ~~ /dumper|all/ => "Smart::Comments"; +use strict; +use warnings; +use SI::tools; +use File::Basename; + +sub dump($\%) { + my ($file, $devs) = @_; + my $dumpdates = dirname($file) . "/dumpdates"; + + foreach my $volume ( + map { { name => $_, %{ $devs->{volume}{$_} } } } + keys %{ $devs->{volume} } + ) + { + next if !defined $volume->{type} or $volume->{type} !~ /^ext/i; + + verbose("dumping volume $volume->{name}"); + my $dumpdev = $volume->{name}; + my $of = sprintf $file, basename($volume->{name}); + run("dump -D $dumpdates -u -0 -z -f $of $dumpdev"); + verbose("\n"); + } +} + +1; + +# vim:sts=4 sw=4 aw ai sm: diff -r 39421a9700c5 -r 6432e90cc34d lib/SI/lvm.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/SI/lvm.pm Wed Jan 20 23:11:19 2010 +0100 @@ -0,0 +1,72 @@ +package SI::lvm; + +use if $ENV{DEBUG} ~~ /lvm|all/ => qw(Smart::Comments); + +use strict; +use warnings; +use IO::File; +use Cwd qw(abs_path); +use File::Basename; + +use SI::tools; + +my @volumegroups = (); + +sub _vgs(\%) { + return @volumegroups if @volumegroups; + + my $devs = shift; + + # find the physical volumes we've already recognised as „non-removable“ + my @known = keys %{ $devs->{volume} }, keys %{ $devs->{disk} }; + + my @pvs = + grep { $_ ~~ @known } map { s/\s*//; (split /:/)[0] } `pvdisplay -c`; + @volumegroups = map { (split /:/)[1] } `pvdisplay -c @pvs 2>/dev/null`; + run("vgchange -ay @volumegroups 2>&1 >/dev/null"); + + # we wait for the /dev/mapper devices to appear + run("udevadm settle"); + return @volumegroups; +} + +sub volumes(\%) { + my ($devs) = @_; + + # we can't just use `pvs', since this would return *all* + # physical devices known to lvm, not just the non-removable + + my @vgs = _vgs(%$devs); + my @lvs = + map { abs_path((dirname $_) . "/" . readlink) } + map { s/^\s*//; (split /:/)[0] } + grep { (split /:/)[1] ~~ @vgs } `lvdisplay -c`; + foreach (@lvs) { + $devs->{volume}{$_} = { origin => "lvm" }; + } + + push @{ $devs->{volumes} }, @lvs; +} + +sub vgcfgbackup($\%) { + my ($file, $devs) = @_; + + # we save it vg by vg to have the restore more easy + my @vgs = _vgs(%$devs); + foreach (map { s/^\s*(.*)/$1/; $_ = (split /:/)[0] } + `vgs --noheadings --separator : @vgs`) + { + verbose("saving vg $_\n"); + my $file = sprintf $file, $_; + run("vgcfgbackup -f '$file' '$_' >/dev/null"); + } + + # for testing let's save it all + verbose("saving vg *\n"); + $file = sprintf $file, "*"; + run("vgcfgbackup -f '$file' >/dev/null"); +} + +1; + +# vim:sts=4 sw=4 aw ai si: diff -r 39421a9700c5 -r 6432e90cc34d lib/SI/mbr.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/SI/mbr.pm Wed Jan 20 23:11:19 2010 +0100 @@ -0,0 +1,25 @@ +package SI::mbr; + +use strict; +use warnings; +use File::Basename; +use IO::File; +use if $ENV{DEBUG} ~~ q(mbr) => "Smart::Comments"; + +use SI::tools; + +sub save($\%) { + my ($file, $devs) = @_; + + foreach my $disk (keys %{ $devs->{disk} }) { + verbose("saving mbr of $disk\n"); + open((my $o), $_ = sprintf(">$file", basename($disk))) + or die "Can't open $_: $!\n"; + + local $/ = \512; + my $in = new IO::File $disk or die "Can't open $disk: $!\n"; + print $o $_ = <$in>; + } +} + +1; diff -r 39421a9700c5 -r 6432e90cc34d lib/SI/ptable.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/SI/ptable.pm Wed Jan 20 23:11:19 2010 +0100 @@ -0,0 +1,70 @@ +package SI::ptable; + +use if $ENV{DEBUG} ~~ /ptable|all/ => qw(Smart::Comments); + +use strict; +use warnings; +use File::Find; +use File::Basename; +use IO::File; + +use SI::tools; +$ENV{LC_ALL} = "C"; + +sub volumes($\%) { + my ($file, $devs) = @_; + + # find the partition tables of all + # non-removable block devices (this may include + # LVs (used as disk itself) too) + foreach (glob("/sys/block/*")) { + my $name = basename($_); + my $dev = "/dev/$name"; + + next if !-e "$_/device"; + next + if (grep { /ATTR{removable}/ } + `udevadm info --attribute-walk --name $name`)[0] !~ /==.0./; + next if (stat $dev)[0] == (stat $0)[0]; + + # exclude the device (stick) we're part of - this HACK is + # only useful on KVM - the usb stick doesn't appear as a removeable + # device + next + if (stat $0)[0] ~~ [ + map { (stat)[6] } + map { "/dev/" . basename(dirname $_) } glob("$_/*/partition") + ]; + + verbose("\n"); + verbose("device $dev\n"); + + die "ERR: $dev does not exist. (should not happen): $!" + if !-b $dev; + + # now the physical disk -- let's ask for the partition table + + my @sfdisk = `sfdisk -d /dev/$name 2>/dev/null`; + + my $of = sprintf $file, $name; + my $oh = new IO::File ">$of" or die "Can't open >$of: $!\n"; + print $oh @sfdisk; + + $devs->{disk}{"/dev/$name"} = { pt => \@sfdisk }; + + # and let's prepare the volume entries + foreach (@sfdisk) { + /^(\S+)\s*:.*Id=\s*([[:xdigit:]]+)/ or next; + $devs->{volume}{$1} = { + origin => "ptable", + ptable_type => $2, + }; + push @{ $devs->{volumes} }, $1; + } + } + + return; +} +1; + +# vim:sts=4 sw=4 aw ai si: diff -r 39421a9700c5 -r 6432e90cc34d lib/SI/system.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/SI/system.pm Wed Jan 20 23:11:19 2010 +0100 @@ -0,0 +1,63 @@ +package SI::system; + +use strict; +use warnings; +use File::Temp qw(tempdir); +use if $ENV{DEBUG} ~~ qw(system) => "Smart::Comments"; +use SI::tools; + +$ENV{LC_ALL} = "C"; + +sub id() { + + $_ = `ip link`; + s/\n\s+/ /g; + s/^\d+:\s*//mg; + + (sort grep /^(eth|wlan)/, split /\n/, $_)[0] + =~ /link\/ether\s+(?\S+)/ + and return $+{mac}; + + die "ERR: Can't get system identification (MAC address)\n"; +} + +sub hostname(\%) { + my $devs = shift; + my $mnt = tempdir(CLEANUP => 1); + my $h; + + foreach my $fs ( + grep { + exists $devs->{volume}{$_}{type} + and $devs->{volume}{$_}{type} =~ /^ext/i + } @{ $devs->{volumes} } + ) + { + run("mount -r $fs $mnt"); + if (-f "$mnt/etc/hostname") { + chomp($h = cat("$mnt/etc/hostname")); + } + run("umount $mnt"); + return $h if defined $h; + } + + return $h; +} + +sub fsck(\%) { + my $devs = shift; + + foreach + my $v (grep { exists $devs->{volume}{type} } keys %{ $devs->{volume} }) + { + my $volume = $devs->{volume}{$v}; + next if $volume->{type} !~ /^ext/i; + + system("fsck -C0 $v"); + die "ERR: fsck failed\n" if $? > 2; + } +} + +1; + +# vim:sts=4 sw=4 aw ai si: diff -r 39421a9700c5 -r 6432e90cc34d lib/SI/tools.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/SI/tools.pm Wed Jan 20 23:11:19 2010 +0100 @@ -0,0 +1,54 @@ +package SI::tools; + +use if $ENV{DEBUG} ~~ /tools|all/ => "Smart::Comments"; + +use strict; +use warnings; +use File::Find; +use Data::Dumper; +use base "Exporter"; + +our @EXPORT = qw(&run &verbose &find_by_devid &cat &barf); + +sub run(@) { + system(@_); + die "$_[0] failed with exit code " . ($? >> 8) . "\n" + if $?; +} + +sub barf(@) { die Dumper @_ } + +sub cat($) { + my $fh = new IO::File $_[0] + or die "Can't open $_[0]: $!\n"; + return (<$fh>) if wantarray; + return join "", <$fh>; +} + +my $last = "\n"; + +sub verbose(@) { + print $last eq "\n" ? "" : " " + if not(@_ == 1 and length($_[0]) == 1); + print @_; + $last = substr($_[-1], -1, 1); +} + +sub find_by_devid($$) { + my ($dir, $id) = @_; + my @found; + find( + sub { + push @found, $File::Find::name if (stat)[6] == $id; + return; + }, + $dir + ); + die "ERR: found more than one alias (@found) for $id\n" if @found > 1; + die "ERR: found no alias for $id\n" if not @found; + return $found[0]; +} + +1; + +# vim:sts=4 sw=4 aw ai si: diff -r 39421a9700c5 -r 6432e90cc34d si --- a/si Wed Jan 20 21:35:35 2010 +0100 +++ b/si Wed Jan 20 23:11:19 2010 +0100 @@ -11,9 +11,11 @@ use IO::File; use Sys::Hostname; use Getopt::Long; -use File::Path qw(make_path remove_tree); +use File::Path; use File::Basename; +use Pod::Usage; +use lib "lib"; use SI::ptable; use SI::blkid; use SI::lvm; @@ -22,32 +24,30 @@ use SI::tools; use SI::system; +my $opt_base = ".."; my $opt_exit = ""; -my $opt_dir = ""; MAIN: { - my %id = ( - mac => SI::system::id, - name => undef, - ); - GetOptions( - "exit=s" => \$opt_exit, - "dir=s" => \$opt_dir - ) or die "Bad usage\n"; + "exit=s" => \$opt_exit, + "b|base=s" => \$opt_base, + "h|help" => sub { pod2usage(-verbose => 1, -exit => 0) }, + "m|man" => sub { pod2usage(-verbose => 2, -exit => 0) }, + ) or pod2usage; my %devices; # the overall data collector - my $dir; + my $dir; + + my $sys_id = SI::system::id; # mostly the MAC + my $sys_name; - if ($opt_dir ne "") { - $dir = $opt_dir; - } - else { - $dir = dirname($0) . "/../image-$id{mac}"; - remove_tree($dir); - -d $dir or mkdir($dir, 0700) or die "Can't mkdir $dir: $!\n"; - } - make_path(map { "$dir/$_" } qw(info ptable lvm blkid mbr dump)); + $dir = "$opt_base/image-$sys_id"; + $dir =~ s/\/+/\//g; + + rmtree($dir); + mkpath([map { "$dir/$_" } qw(info ptable lvm blkid mbr dump)]); + + #print grep { -l && readlink =~ /\/.*-$sys_id$/ } glob("$opt_base"); SI::ptable::volumes("$dir/ptable/%s", %devices); die Dumper \%devices if $opt_exit =~ /ptable/; @@ -67,19 +67,17 @@ SI::system::fsck(%devices); die Dumper \%devices if $opt_exit =~ /fsck/; - $id{name} = SI::system::hostname(%devices); - unlink("../image-$id{name}") if -l "../image-$id{name}"; - symlink(basename($dir), "../image-$id{name}"); + # now we can retrieve the system name, first we had to + # check the devices + $sys_name = SI::system::hostname(%devices); - print { new IO::File ">$dir/info/mac" } "$id{mac}\n"; - print { new IO::File ">$dir/info/name" } "$id{name}\n"; + print { new IO::File ">$dir/info/mac" } "$sys_id\n"; + print { new IO::File ">$dir/info/name" } "$sys_name\n"; print { new IO::File ">$dir/info/devices" } Dumper \%devices or die "ERR: Can't open $dir/info/devices: $!\n"; SI::dumper::dump("$dir/dump/%s", %devices); - - # HACK ... fixme - system("rmdir ../* 2>/dev/null"); + symlink(basename($dir), "../image-$sys_name"); print { new IO::File ">$dir/done" } localtime() . "\n"; run("sync"); @@ -87,4 +85,43 @@ } +=head1 NAME + +si - system imager + +=head1 SYNOPSIS + + si [-b|--base-dir DIR] + +=head1 DESCRIPTION + +The B tool tries its best to create a restorable system backup - but +it is B to Linux filesystems and a simple LVM structure. + +(The restore tool currently does not exist.) + +=head1 OPTIONS + +=over + +=item B<-b>|B<--base-dir> I + +Where to create the directories for saving the system. (default: ..) + +=back + +=head1 Operational Details + +B saves the master boot record and the partition table (via C) of any non-removeable hard disk. It analyzes an LVM setup and +saves the volume manger configuration. And last but not least it dumps +all ext* file systems. + + +=head1 AUTHOR + +Heiko Schlittermann + +=cut + # vim:sts=4 sw=4 aw ai si: