/[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 2 by dpavlin, Sat Jul 18 18:05:37 2009 UTC revision 4 by dpavlin, Sun Jul 19 13:08:33 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 ( $verbose, $init, $debug ) = ( 1 );
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', 'fs' );  
21    
22  my $path = shift @ARGV || die "usage: $0 /path/to/file\n";  sub size {
23            my $size = shift;
24  my ($dir,$file) = ($1,$2) if $path =~ m{^(?:(.+)/)?([^/]+)};          $size =~ s{MB}{};
25            $size;
26    }
27    
28  my $seq;  my @part;
 my $opos = 0;  
29    
30  if ( -e "$mnt/last" ) {  sub partitions {
31          my $log = read_file("$mnt/last");          @part = ();
32          $seq = readlink("$mnt/last");          open(my $parted, '-|', "parted -s $dev unit mb print free") || die "parted: $!";
33          $seq =~ s{^.+/(\d+)$}{$1} || die "can't parse sequence: $seq";          while(<$parted>) {
34          $seq++;                  chomp;
35          $opos = $1 if $log =~ m{opos:\s+(\d+\.\d[k])};                  s{^\s+}{};
36          die "can't decode opos" unless $opos;                  next unless $_;
37          warn "# seq: $seq start: $opos\n";                  my @p = map { size($_) } split(/\s+/, $_ );
38                    warn "## $_ ",dump( @p ) if $debug;
39  } else {                  if ( $p[3] && $p[3] eq 'Free' ) {
40          $seq = $#{ glob("$mnt/log/*") } + 1;                          $part[0] = [ @p ];
41          warn "# $mnt/last not found, recover seq: $seq\n";                  } elsif ( $p[0] =~ m{^\d+$} ) {
42                            my $nr = shift @p;
43                            $part[$nr] = [ @p ];
44                    } else {
45                            warn "SKIP ",dump( @p ) if $debug;
46                    }
47            }
48            warn "# part = ",dump( @part ) if $verbose;
49            return @part;
50  }  }
51    
52    sub mount_42 {
53            my $node = $dev . '1';
54            if ( ! -e $node ) {
55                    print STDERR "wait for $node";
56                    sleep 1;
57                    while ( ! -e $node ) {
58                            print STDERR ".";
59                            sleep 1;
60                    }
61            }
62            warn "+ mount $node $mnt";
63            system("mount $node $mnt") == 0 or die "can't mount: $!";
64    }
65    
66  my $log = "$mnt/log/$seq";  my $remount_on = qr/(mkpart|rm)/;
67    
68  if ( -e $log ) {  sub parted {
69          print "ERROR $log exists!\n",read_file($log);          my $command = shift;
70          if ( $rollback ) {          my @before = partitions();
71                  unlink $log || die "can't rollback $log: $!";  
72                  die "RECOVERY removed $log\n";          system "umount $mnt" if $command =~ $remount_on;
73          } elsif ( $commit ) {  
74                  unlink "$mnt/last" || die "can't remove $mnt/last: $!";          warn "+ $command\n";
75                  symlink $log,"$mnt/last" || die "can't commit $log: $!";          system("parted -s $dev unit mb $command") == 0 or die "parted: $?";
76                  die "ERROR: can't update $mnt/last -> $log" unless $log eq readlink "$mnt/last";          if ( $command =~ $remount_on ) {
77                  die "RECOVERY updated $mnt/last -> $log\n";                  my @part = partitions();
78          } else {                  while ( $#before == $#part ) {
79                  die "$log exists, re-run with --commit or --rollback";                          warn "re-read partition table\n";
80                            sleep 1;
81                            @part = partitions();
82                    }
83            mount_42 if $part[1];
84          }          }
85  }  }
86    
87    partitions();
88    
89    if ( $init ) {
90            parted("rm $_") foreach grep { defined $part[$_] } map { $#part - $_ + 1 } ( 1 .. $#part );
91            parted("mkpartfs primary ext2 0 42MB");
92            parted("mkpart extended 42MB " . $part[0]->[1] . 'MB');
93            my $cmd = read_file($0);
94            write_file( "$mnt/42.pl", $cmd );
95            chmod 0755, "$mnt/42.pl";
96            exit;
97    }
98    
99    map { mkdir $_ unless -e $_ } map { "$mnt/$_" } ( 'log', 'fs', 'stat' );
100    
101    my $path = shift @ARGV || die "usage: $0 /path/to/file\n";
102    
103    my ($dir,$file) = ($1,$2) if $path =~ m{^(?:(.+)/)?([^/]+)};
104    
105  my $fs = "$mnt/fs/$dir";  my $fs = "$mnt/fs/$dir";
106  mkpath $fs unless -e $fs;  mkpath $fs unless -e $fs;
107    
108  $fs .= '/' . $file;  $fs .= '/' . $file;
   
109  die "$fs exists!" if -e $fs;  die "$fs exists!" if -e $fs;
110    
111  my $cmd = "dd_rescue -l $log -S $opos $path $dev";  my @stat = stat($path);
112  print "+ $cmd\n";  die "can't stat $path: $!" unless @stat;
113  system($cmd) == 0 or warn "# exit code: $?";  warn "# $path ",$stat[7],$/;
114    
115    my $size_mb = int( $stat[7] / 1000 / 1000 ) + 1; # FIXME correctly round to something?
116    my ( $free_start, undef, $free_size ) = @{$part[0]};
117    
118    my $part_end = $free_start + $size_mb;
119    
120    my $last_part = $#part;
121    
122    parted("mkpart logical ${free_start}MB ${part_end}MB ");
123    
124  unlink("$mnt/last") && symlink($log,"$mnt/last") || die "can't commit log $log -> $mnt/last";  my $part_size = $part[$#part]->[2] || die "can't get size of new partition";
125    
126  symlink($log,$fs) || die "can't create $fs: $!";  die "not enough space on $dev $size_mb > $part_size" if $size_mb > $part_size;
127    
128  print "OK $fs -> $log\n";  my $part_nr = $#part;
129    
130    write_file( "$mnt/stat/$part_nr", join("\n",@stat) );
131    
132    my $log = "$mnt/log/$part_nr";
133    
134    my $to_dev = $dev . $part_nr;
135    
136    symlink( $to_dev ,$fs) || die "can't create $fs: $!";
137    
138    my $cmd = "dd_rescue -w -l $log $path $to_dev";
139    print "+ $cmd\n";
140    exec $cmd;

Legend:
Removed from v.2  
changed lines
  Added in v.4

  ViewVC Help
Powered by ViewVC 1.1.26