# HG changeset patch # User Heiko Schlittermann # Date 1263908983 -3600 # Node ID 4e3753b998a93d363f32de2267b01e2a1c321c15 # Parent aecda276307938aa4113249e4ca767490dd90d70 first real live test diff -r aecda2763079 -r 4e3753b998a9 SI/dumper.pm --- a/SI/dumper.pm Mon Jan 18 22:55:10 2010 +0100 +++ b/SI/dumper.pm Tue Jan 19 14:49:43 2010 +0100 @@ -6,44 +6,11 @@ use SI::tools; use File::Basename; -#$VAR1 = { -# 'volume' => { -# '/dev/mapper/debian-swap' => { -# 'origin' => 'lvm', -# 'label' => undef, -# 'type' => 'swap', -# 'uuid' => undef -# }, -# '/dev/hda4' => { -# 'ptable_type' => '0', -# 'origin' => 'ptable' -# }, -# '/dev/hda1' => { -# 'ptable_type' => '83', -# 'origin' => 'ptable', -# 'label' => undef, -# 'type' => 'ext2', -# 'uuid' => 'a1fc3fc0-7bde-49c4-9afe-c71db8c4d08b' -# }, -# '/dev/hda3' => { -# 'ptable_type' => '0', -# 'origin' => 'ptable' -# }, -# '/dev/mapper/debian-root' => { -# 'origin' => 'lvm', -# 'label' => undef, -# 'type' => 'ext3', -# 'uuid' => 'b30578ac-841f-48b4-8ceb-1cdcbabc7fab' -# }, -# '/dev/hda2' => { -# 'ptable_type' => '8', -# 'origin' => 'ptable', -# 'label' => undef, -# 'type' => 'lvm2pv', -# 'uuid' => 'S4zDgc-hEWW-h9BY-XHz3-32TE-66W1-W0iMVE' -# } -# }, -# }; +my @cleanup; +END { + #map { eval { run("lvchange -an $_ 2>/dev/null") } } @cleanup; + #map { eval { run("lvremove -ff $_ 2>/dev/null") } } @cleanup; +} sub dump($\%) { my ($file, $devs) = @_; @@ -54,20 +21,18 @@ verbose("dumping volume $volume->{name}"); my $dumpdev = $volume->{name}; - if ($volume->{origin} =~ /lvm/i) { - verbose("(lvm)"); - my ($vg, $lv) = `lvdisplay -c $volume->{name}` =~ /\s*\/dev\/(.*?)\/(.*?):/; - my $snap = "snap$$"; - - END { eval { run("lvchange -an $vg/$snap 2>/dev/null") }; - eval { run("lvremove -ff $vg/$snap 2>/dev/null") }; } - - eval { - run("lvcreate -s -L 1G -n snap$$ $vg/$lv 2>/dev/null"); - }; - if ($@) { warn "Can't create snapshot\n" } - else { $dumpdev = "/dev/$vg/$snap$$" }; - } +# if ($volume->{origin} =~ /lvm/i) { +# verbose("(lvm)"); +# my ($vg, $lv) = `lvdisplay -c $volume->{name}` =~ /\s*\/dev\/(.*?)\/(.*?):/; +# my $snap = "snap$$"; +# push @cleanup, "$vg/$lv"; +# +# #eval { +# # run("lvcreate -s -L 1G -n snap$$ $vg/$lv 2>/dev/null"); +# #}; +# if ($@) { warn "Can't create snapshot\n" } +# else { $dumpdev = "/dev/$vg/$snap$$" }; +# } my $of = sprintf $file, basename($volume->{name}); run("dump -0 -z -f $of $dumpdev"); diff -r aecda2763079 -r 4e3753b998a9 SI/lvm.pm --- a/SI/lvm.pm Mon Jan 18 22:55:10 2010 +0100 +++ b/SI/lvm.pm Tue Jan 19 14:49:43 2010 +0100 @@ -5,7 +5,8 @@ use strict; use warnings; use IO::File; - +use Cwd qw(abs_path); +use File::Basename; use SI::tools; @@ -16,6 +17,7 @@ my $devs = shift; + # find the physical volumes we've already recognised as „non-removable“ my @pvs = grep { $_ ~~ $devs->{known} } map { s/\s*//; (split /:/)[0] } `pvdisplay -c`; return @volumegroups = map { (split /:/)[1] } `pvdisplay -c @pvs 2>/dev/null`; @@ -28,10 +30,12 @@ # physical devices known to lvm, not just the non-removable my @vgs = _vgs(%$devs); - my @lvs = map { readlink } + run("vgchange -ay @vgs 2>/dev/null"); + + my @lvs = + map { abs_path ((dirname $_) . "/" . readlink) } map { s/^\s*//; (split /:/)[0] } grep { (split /:/)[1] ~~ @vgs } `lvdisplay -c`; - foreach (@lvs) { $devs->{volume}{$_} = { origin => "lvm" }; } diff -r aecda2763079 -r 4e3753b998a9 SI/ptable.pm --- a/SI/ptable.pm Mon Jan 18 22:55:10 2010 +0100 +++ b/SI/ptable.pm Tue Jan 19 14:49:43 2010 +0100 @@ -19,17 +19,18 @@ # LVs (used as disk itself) too) foreach (glob("/sys/block/*")) { my $name = basename($_); - verbose("device $name"); + # verbose("device $name"); if (!-e "$_/device") { - verbose("skipping (non-dev)\n"); + # verbose("skipping (non-dev)\n"); next; } if ((grep { /ATTR{removable}/ } `udevadm info --attribute-walk --name $name`)[0] !~ /==.0./) { - verbose("skipping (removable)\n"); + # verbose("skipping (removable)\n"); next; } verbose("\n"); + verbose("device $name\n"); die "ERR: /dev/$name does not exist. (should not happen)" if !-e "/dev/$name"; @@ -50,7 +51,7 @@ # and let's prepare the volume entries foreach (@sfdisk) { - /^(\S+)\s*:.*Id=\s*(\d+)/ or next; + /^(\S+)\s*:.*Id=\s*([[:xdigit:]]+)/ or next; $devs->{volume}{$1} = { origin => "ptable", ptable_type => $2, diff -r aecda2763079 -r 4e3753b998a9 SI/system.pm --- a/SI/system.pm Mon Jan 18 22:55:10 2010 +0100 +++ b/SI/system.pm Tue Jan 19 14:49:43 2010 +0100 @@ -6,14 +6,12 @@ $ENV{LC_ALL} = "C"; -sub id($) { - my ($file) = @_; - open(my $f, ">$file") or die "Can't open $file: $!\n"; - # hope it's eth* +sub id() { + # hope it's eth* or wlan* local $_ = (sort grep { /^(eth|wlan)/ } `ifconfig -a`)[0]; - return if not $_; - return if not /^(?\S+)\s.*HWaddr\s+(?[\da-f:]+)\s*$/i; - print $f "ethernet $+{dev} $+{mac}\n"; + /^(?\S+)\s.*HWaddr\s+(?[\da-f:]+)\s*$/i + and return $+{mac}; + die "ERR: Can't get system identification (MAC address)\n"; } 1; diff -r aecda2763079 -r 4e3753b998a9 SI/tools.pm --- a/SI/tools.pm Mon Jan 18 22:55:10 2010 +0100 +++ b/SI/tools.pm Tue Jan 19 14:49:43 2010 +0100 @@ -5,9 +5,10 @@ use strict; use warnings; use File::Find; +use Data::Dumper; use base "Exporter"; -our @EXPORT = qw(&run &verbose &find_by_devid &cat); +our @EXPORT = qw(&run &verbose &find_by_devid &cat &barf); sub run(@) { system(@_); @@ -15,6 +16,8 @@ if $?; } +sub barf(@) { die Dumper @_ } + sub cat($) { my $fh = new IO::File $_[0] or die "Can't open $_[0]: $!\n"; diff -r aecda2763079 -r 4e3753b998a9 si --- a/si Mon Jan 18 22:55:10 2010 +0100 +++ b/si Tue Jan 19 14:49:43 2010 +0100 @@ -1,5 +1,7 @@ #! /usr/bin/perl -# system imager +# system imager - proof of concept +# (c) 2010 Heiko Schlittermann +# see http://keller.schlittermann.de/hg/ius/si use if $ENV{DEBUG} ~~ /main|all/ => "Smart::Comments"; @@ -7,8 +9,10 @@ use warnings; use Data::Dumper; use IO::File; - use Sys::Hostname; +use Getopt::Long; +use File::Path; +use File::Basename; use SI::ptable; use SI::blkid; @@ -17,25 +21,46 @@ use SI::dumper; use SI::system; -MAIN: { - my $OUT = "../out-" . hostname; +my $opt_exit = ""; +my $opt_dir = ""; - unlink(glob("$OUT/*")); - -d $OUT or mkdir($OUT, 0700) or die "Can't mkdir $OUT: $!\n"; +MAIN: { - my %devices; - - SI::system::id("$OUT/system"); + GetOptions("exit=s" => \$opt_exit, + "dir=s" => \$opt_dir) + or die "Bad usage\n"; - SI::ptable::volumes("$OUT/partitions.%s", %devices); + my %devices; # the overall data collector + my $dir; + + if ($opt_dir ne "") { + $dir = $opt_dir; + } + else { + $dir = dirname($0) . "/../image-" . SI::system::id(); + rmtree($dir); + -d $dir or mkdir($dir, 0700) or die "Can't mkdir $dir: $!\n"; + } + + SI::ptable::volumes("$dir/partitions.%s", %devices); + die Dumper \%devices if $opt_exit =~ /ptable/; + SI::lvm::volumes(%devices); - SI::blkid::ids("$OUT/blkid", %devices); - SI::lvm::vgcfgbackup("$OUT/vg.%s", %devices); - SI::mbr::save("$OUT/mbr.%s", %devices); - SI::dumper::dump("$OUT/dump.%s", %devices); + die Dumper \%devices if $opt_exit =~ /lvm::volumes/; + + SI::blkid::ids("$dir/blkid", %devices); + die Dumper \%devices if $opt_exit =~ /blkid/; + + SI::lvm::vgcfgbackup("$dir/vg.%s", %devices); + die Dumper \%devices if $opt_exit =~ /lvm::vgcfg/; - my $o = new IO::File ">$OUT/devices" - or die "ERR: Can't open $OUT/devices: $!\n"; + SI::mbr::save("$dir/mbr.%s", %devices); + die Dumper \%devices if $opt_exit =~ /mbr/; + + SI::dumper::dump("$dir/dump.%s", %devices); + + my $o = new IO::File ">$dir/devices" + or die "ERR: Can't open $dir/devices: $!\n"; $o->print(Dumper \%devices);