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

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

  ViewVC Help
Powered by ViewVC 1.1.26