diff --git a/btrbk b/btrbk index b696639..cb03aa8 100755 --- a/btrbk +++ b/btrbk @@ -87,6 +87,8 @@ my $loglevel = 1; my $ip_addr_match = qr/(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/; my $host_name_match = qr/(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])/; my $file_match = qr/[0-9a-zA-Z_\-\.\/]+/; +my $ssh_prefix_match = qr/ssh:\/\/($ip_addr_match|$host_name_match)/; + $SIG{__DIE__} = sub { print STDERR "\nERROR: process died unexpectedly (btrbk v$VERSION)"; @@ -213,7 +215,7 @@ sub check_file($$$$) my $config_file = shift; # only for error text if($accept->{ssh} && ($file =~ /^ssh:\/\//)) { - unless($file =~ /^ssh:\/\/($ip_addr_match|$host_name_match)\/$file_match$/) { + unless($file =~ /^$ssh_prefix_match\/$file_match$/) { ERROR "Ambiguous ssh url for option \"$key\" in \"$config_file\" line $.: $file"; return undef; } @@ -971,6 +973,8 @@ MAIN: } my ($action_run, $action_info, $action_tree, $action_diff, $action_origin); + my @subvol_args; + my $args_expected = 0; if(($command eq "run") || ($command eq "dryrun")) { $action_run = 1; $dryrun = 1 if($command eq "dryrun"); @@ -983,15 +987,36 @@ MAIN: } elsif ($command eq "diff") { $action_diff = 1; + $args_expected = 2; + @subvol_args = @ARGV; } elsif ($command eq "origin") { $action_origin = 1; + $args_expected = 1; + @subvol_args = @ARGV; } else { ERROR "Unrecognized command: $command"; HELP_MESSAGE(0); exit 1; } + if($args_expected != scalar(@ARGV)) { + ERROR "Incorrect number of arguments"; + HELP_MESSAGE(0); + exit 1; + } + + # input validation + foreach (@subvol_args) { + s/\/+$//; # remove trailing slash + unless(/^(($ssh_prefix_match)?\/$file_match)$/) { # matches ssh statement or absolute file + ERROR "Bad argument: not a subvolume declaration: $_"; + HELP_MESSAGE(0); + exit 1; + } + $_ = $1; # untaint argument + } + INFO "$version_info (" . localtime($start_time) . ")"; @@ -1000,24 +1025,9 @@ MAIN: # # print snapshot diff # - my $src_vol = shift @ARGV; - my $target_vol = shift @ARGV; - unless($src_vol && $target_vol) { - ERROR "Missing subvolume argument for \"diff\" command"; - HELP_MESSAGE(0); - exit 1; - } - # untaint arguments - unless($src_vol =~ /^($file_match)$/) { - ERROR "bad argument: not a file: $src_vol"; - exit 1; - } - $src_vol = $1; - unless($target_vol =~ /^($file_match)$/) { - ERROR "bad argument: not a file: $target_vol"; - exit 1; - } - $target_vol = $1; + my $src_vol = $subvol_args[0] || die; + my $target_vol = $subvol_args[1] || die; + # FIXME: allow ssh:// src/dest (does not work since the configuration is not yet read). my $src_detail = btr_subvolume_detail($src_vol); unless($src_detail) { exit 1; } @@ -1207,14 +1217,9 @@ MAIN: # # print origin information # - my $subvol = shift @ARGV; + my $subvol = $subvol_args[0] || die; my $dump_uuid = 0; - unless($subvol) { - ERROR "Missing subvolume argument for \"origin\" command"; - HELP_MESSAGE(0); - exit 1; - } - $subvol =~ s/\/+$//; # remove trailing slash + my $uuid; foreach(values %uuid_info) { if($_->{FS_PATH} eq $subvol) {