Subversion Repositories zfs_utils

Rev

Rev 30 | Rev 33 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 30 Rev 31
Line 25... Line 25...
25
   $merge_stderr = 1 unless defined $merge_stderr;
25
   $merge_stderr = 1 unless defined $merge_stderr;
26
   my $output = '';
26
   my $output = '';
27
 
27
 
28
   if (ref $cmd eq 'ARRAY') {
28
   if (ref $cmd eq 'ARRAY') {
29
      # Execute without a shell (safer). Note: stderr is not merged in this path.
29
      # Execute without a shell (safer). Note: stderr is not merged in this path.
30
      logMsg( 'Running command [' . join ' ', @$cmd . ']');
30
      logMsg( 'Running command [' . join( ' ', @$cmd ) . ']');
31
      open my $fh, '-|', @{$cmd} or do {
31
      open my $fh, '-|', @{$cmd} or do {
32
         logMsg("runCmd: failed to exec '@{$cmd}': $!");
32
         logMsg("runCmd: failed to exec '@{$cmd}': $!");
33
         return wantarray ? () : '';
33
         return wantarray ? () : '';
34
      };
34
      };
35
      local $/ = undef;
35
      local $/ = undef;
Line 90... Line 90...
90
 
90
 
91
   logMsg("mountDriveByLabel: Looking for drive with label '$label'");
91
   logMsg("mountDriveByLabel: Looking for drive with label '$label'");
92
   # default to /mnt/label if not provided
92
   # default to /mnt/label if not provided
93
   $mountPath //= "/mnt/$label"; # this is where we'll mount it if we find it
93
   $mountPath //= "/mnt/$label"; # this is where we'll mount it if we find it
94
   $label = "/dev/gpt/$label"; #  this is where FreeBSD puts gpt labeled drives
94
   $label = "/dev/gpt/$label"; #  this is where FreeBSD puts gpt labeled drives
-
 
95
   # drive already mounted, just return the path
-
 
96
   return $mountPath if ( runCmd( "mount | grep '$mountPath'" ) );
95
   # default to 10 minutes (600 seconds) if not provided
97
   # default to 10 minutes (600 seconds) if not provided
96
   $timeout //= 600;
98
   $timeout //= 600;
97
   # default to checking every minute if not provided
99
   # default to checking every minute if not provided
98
   $checkEvery //= 60;
100
   $checkEvery //= 15;
99
   # wait up to $timeout seconds for device to appear, checking every 10 seconds
101
   # wait up to $timeout seconds for device to appear, checking every 10 seconds
100
   while ( $timeout > 0 ) {
102
   while ( $timeout > 0 ) {
101
      if ( -e "$label" ) {
103
      if ( -e "$label" ) {
102
         last;
104
         last;
103
      } else {
105
      } else {
104
         sleep $checkEvery;
106
         sleep $checkEvery;
105
         $timeout -= $checkEvery;
107
         $timeout -= $checkEvery;
-
 
108
         print "Waiting for drive labeled $label\n";
106
      }
109
      }
107
    }
110
    }
108
    # if we found it, mount and return mount path
111
    # if we found it, mount and return mount path
109
    if ( -e "$label" ) {
112
    if ( -e "$label" ) {
110
       # ensure mount point
113
       # ensure mount point
Line 431... Line 434...
431
   # decide if we can do a single recursive send:
434
   # decide if we can do a single recursive send:
432
   # condition: all 'to' snapshot names are identical
435
   # condition: all 'to' snapshot names are identical
433
   my %to_names = map { $_ => 1 } values %to_for;
436
   my %to_names = map { $_ => 1 } values %to_for;
434
   my $single_to_name = (keys %to_names == 1) ? (keys %to_names)[0] : undef;
437
   my $single_to_name = (keys %to_names == 1) ? (keys %to_names)[0] : undef;
435
 
438
 
436
   my @commands;
439
   my %commands;
437
 
440
 
438
   if ($single_to_name) {
441
   if ($single_to_name) {
439
      # check whether any from is missing
442
      # check whether any from is missing
440
      my @from_values = map { $from_for{$_} } sort keys %from_for;
443
      my @from_values = map { $from_for{$_} } sort keys %from_for;
441
      my $any_from_missing = grep { !defined $_ } @from_values;
444
      my $any_from_missing = grep { !defined $_ } @from_values;
442
      my %from_names = map { $_ => 1 } grep { defined $_ } @from_values;
445
      my %from_names = map { $_ => 1 } grep { defined $_ } @from_values;
443
      my $single_from_name = (keys %from_names == 1) ? (keys %from_names)[0] : undef;
446
      my $single_from_name = (keys %from_names == 1) ? (keys %from_names)[0] : undef;
444
 
447
 
445
      if ($any_from_missing) {
448
      if ($any_from_missing) {
446
         # full recursive send from root
449
         # full recursive send from root
447
         push @commands, sprintf('zfs send -R %s@%s', $root_fs, $single_to_name);
450
         $commands{'root_fs'} = sprintf('zfs send -R %s@%s', $root_fs, $single_to_name);
448
      }
451
      }
449
      elsif ($single_from_name) {
452
      elsif ($single_from_name) {
450
         # incremental recursive send
453
         # incremental recursive send, but don't do it if they are the same
451
         push @commands, sprintf('zfs send -R -I %s@%s %s@%s',
454
         $commands{$root_fs} = sprintf('zfs send -R -I %s@%s %s@%s',
452
                           $root_fs, $single_from_name, $root_fs, $single_to_name);
455
                           $root_fs, $single_from_name, $root_fs, $single_to_name)
-
 
456
                           unless $single_from_name eq $single_to_name;
453
      }
457
      }
454
      else {
458
      else {
455
         # from snapshots differ across children -> fall back to per-filesystem sends
459
         # from snapshots differ across children -> fall back to per-filesystem sends
456
         foreach my $fs (sort keys %to_for) {
460
         foreach my $fs (sort keys %to_for) {
457
            my $to  = $to_for{$fs};
461
            my $to  = $to_for{$fs};
458
            my $from = $from_for{$fs};
462
            my $from = $from_for{$fs};
459
            if ($from) {
463
            if ($from) {
-
 
464
               # if from and to are different, add it
460
               push @commands, sprintf('zfs send -I %s@%s %s@%s', $fs, $from, $fs, $to);
465
               $commands{$fs} = sprintf('zfs send -I %s@%s %s@%s', $fs, $from, $fs, $to)
-
 
466
                  unless $from eq $to;
461
            } else {
467
            } else {
462
               push @commands, sprintf('zfs send %s@%s', $fs, $to);
468
               $commands{$fs} = sprintf('zfs send %s@%s', $fs, $to);
463
            }
469
            }
464
         }
470
         }
465
      }
471
      }
466
 
472
 
467
      # update new status: record newest snap for every filesystem
473
      # update new status: record newest snap for every filesystem
Line 472... Line 478...
472
      # not all children share same newest snap -> per-filesystem sends
478
      # not all children share same newest snap -> per-filesystem sends
473
      foreach my $fs (sort keys %to_for) {
479
      foreach my $fs (sort keys %to_for) {
474
         my $to  = $to_for{$fs};
480
         my $to  = $to_for{$fs};
475
         my $from = $from_for{$fs};
481
         my $from = $from_for{$fs};
476
         if ($from) {
482
         if ($from) {
477
            push @commands, sprintf('zfs send -I %s@%s %s@%s', $fs, $from, $fs, $to);
483
            $commands{$fs} = sprintf('zfs send -I %s@%s %s@%s', $fs, $from, $fs, $to);
478
         } else {
484
         } else {
479
            push @commands, sprintf('zfs send %s@%s', $fs, $to);
485
            $commands{$fs} = sprintf('zfs send %s@%s', $fs, $to);
480
         }
486
         }
481
         push @$newStatusRef, sprintf('%s@%s', $fs, $to);
487
         push @$newStatusRef, sprintf('%s@%s', $fs, $to);
482
      }
488
      }
483
   }
489
   }
484
 
490
 
485
   # return arrayref of commands (caller can iterate or join with pipes)
491
   # return arrayref of commands (caller can iterate or join with pipes)
486
   return \@commands;
492
   return \%commands;
487
}
493
}
488
 
494
 
489
 
495
 
490
1;
496
1;