/[42-fs]/42.pl
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /42.pl

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1 by dpavlin, Sat Jul 18 17:31:53 2009 UTC revision 3 by dpavlin, Sun Jul 19 11:55:06 2009 UTC
# Line 6  use strict; Line 6  use strict;
6  use File::Slurp;  use File::Slurp;
7  use File::Path;  use File::Path;
8  use Getopt::Long;  use Getopt::Long;
9    use Data::Dump qw/dump/;
10    
11  my $dev = '/dev/sdb2';  my $dev = '/dev/sdb';
12  my $mnt = '/mnt/42';  my $mnt = '/mnt/42';
13    
14  my ( $rollback, $commit );  my ( $init, $debug );
15    
16  GetOptions(  GetOptions(
17          'rollback!' => \$rollback,          'init!' => \$init,
18          'commit!'   => \$commit,          'debug!' => \$debug,
19  ) or die "unknown options: $!";  ) or die "unknown options: $!";
20    
 map { mkdir $_ unless -e $_ } map { "$mnt/$_" } ( 'log', 'ps' );  
21    
22  my $path = shift @ARGV;  my @part;
23    
24  my ($dir,$file) = ($1,$2) if $path =~ m{^(?:(.+)/)?([^/]+)};  sub partitions {
25            open(my $parted, '-|', "parted -s $dev unit mb print free") || die "parted: $!";
26  my $seq;          while(<$parted>) {
27  my $opos = 0;                  warn "## $_" if $debug;
28                    if ( m{^\s+([\d\.]+)MB\s+([\d\.]+)MB\s+([\d\.]+)MB\s+Free Space} ) {
29  if ( -e "$mnt/last" ) {                          $part[0] = [ $1, $2, $3, 'free' ];
30          my $log = read_file("$mnt/last");                  }
31          $seq = readlink("$mnt/last");                  next unless m{^\s+\d+\s+};
32          $seq =~ s{^.+/(\d+)$}{$1} || die "can't parse sequence: $seq";                  s{^\s+}{};
33          $seq++;                  s{([\d\.]+)MB}{$1}g;
34          $opos = $1 if $log =~ m{opos:\s+(\d+\.\d[k])};                  my ( $nr, $start, $end, $size, undef ) = split(/\s+/, $_, 5);
35          die "can't decode opos" unless $opos;                  $part[$nr] = [ $start, $end, $size ];
36          warn "# seq: $seq start: $opos\n";          }
37            warn "## part = ",dump( @part ) if $debug;
38  } else {          return @part;
         $seq = scalar(glob("$mnt/log/*"));  
         warn "# $mnt/last not found, recover seq: $seq\n";  
39  }  }
40    
41    sub parted {
42            my $command = shift;
43            warn "+ $command\n";
44            system("parted -s $dev unit mb $command") == 0 or die "parted: $!";
45    }
46    
 my $log = "$mnt/log/$seq";  
47    
48  if ( -e $log ) {  if ( $init ) {
49          print "ERROR $log exists!\n",read_file($log);          system("umount $mnt");
50          if ( $rollback ) {          partitions();
51                  unlink $log || die "can't rollback $log: $!";          parted("rm $_") foreach grep { defined $part[$_] } ( 1 .. 4 );
52                  die "RECOVERY removed $log\n";          parted("mkpartfs primary ext2 0 42MB");
53          } elsif ( $commit ) {          partitions();
54                  unlink "$mnt/last" || die "can't remove $mnt/last: $!";          parted("mkpart extended 42MB " . $part[0]->[1] . 'MB');
55                  symlink $log,"$mnt/last" || die "can't commit $log: $!";          system "sync;sync";
56                  die "ERROR: can't update $mnt/last -> $log" unless $log eq readlink "$mnt/last";          partitions();
57                  die "RECOVERY updated $mnt/last -> $log\n";          system("mount ${dev}1 $mnt") == 0 or die "can't mount: $!";
58          } else {          my $cmd = read_file($0);
59                  die "$log exists, re-run with --commit or --rollback";          write_file( "$mnt/42.pl", $cmd );
60          }          chmod 0755, "$mnt/42.pl";
61            exit;
62  }  }
63    
64  my $cmd = "dd_rescue -l $log -S $opos $path $dev && ln -s $log $mnt/last";  map { mkdir $_ unless -e $_ } map { "$mnt/$_" } ( 'log', 'fs', 'stat' );
65  print "+ $cmd\n";  
66  system($cmd) == 0 or die $?;  my $path = shift @ARGV || die "usage: $0 /path/to/file\n";
67    
68    my ($dir,$file) = ($1,$2) if $path =~ m{^(?:(.+)/)?([^/]+)};
69    
70  my $fs = "$mnt/fs/$dir";  my $fs = "$mnt/fs/$dir";
71  mkdir $fs unless -e $fs;  mkpath $fs unless -e $fs;
72    
73  $fs .= '/' . $file;  $fs .= '/' . $file;
74  symlink $fs,$log || die "can't create $fs: $!";  die "$fs exists!" if -e $fs;
75    
76    my @stat = stat($path);
77    die "can't stat $path: $!" unless @stat;
78    warn "# $path ",$stat[7],$/;
79    
80    partitions();
81    
82    my $size_mb = int( $stat[7] / 1000 / 1000 ) + 1;
83    my ( $free_start, undef, $free_size ) = @{$part[0]};
84    
85    my $part_end = $free_start + $size_mb;
86    
87    my $last_part = $#part;
88    
89    system("umount $mnt");
90    parted("mkpart logical ${free_start}MB ${part_end}MB");
91    partitions();
92    system("mount ${dev}1 $mnt") == 0 or die "can't mount $mnt: $!";
93    
94    my $part_size = $part[$#part]->[2] || die "can't get size of new partition";
95    
96    die "not enough space on $dev $size_mb > $part_size" if $size_mb > $part_size;
97    
98    my $part_nr = $#part;
99    
100    die "can't create partition $last_part == $part_nr" if $last_part == $part_nr;
101    
102    write_file( "$mnt/stat/$part_nr", join("\n",@stat) );
103    
104    my $log = "$mnt/log/$part_nr";
105    
106    my $to_dev = $dev . $part_nr;
107    
108    symlink( $to_dev ,$fs) || die "can't create $fs: $!";
109    
110    my $cmd = "dd_rescue -w -l $log $path $to_dev";
111    print "+ $cmd\n";
112    exec $cmd;

Legend:
Removed from v.1  
changed lines
  Added in v.3

  ViewVC Help
Powered by ViewVC 1.1.26