diff --git a/btrbk b/btrbk index 51edb45..04aa451 100755 --- a/btrbk +++ b/btrbk @@ -132,6 +132,10 @@ my %config_options = ( backend_local => { default => undef, accept => [ "no", "btrfs-progs", "btrfs-progs-btrbk", "btrfs-progs-sudo" ] }, backend_remote => { default => undef, accept => [ "no", "btrfs-progs", "btrfs-progs-btrbk", "btrfs-progs-sudo" ] }, + compat => { default => undef, accept => [ "no", "busybox" ] }, + compat_local => { default => undef, accept => [ "no", "busybox" ] }, + compat_remote => { default => undef, accept => [ "no", "busybox" ] }, + snapshot_qgroup_destroy => { default => undef, accept => [ "yes", "no" ], context => [ "global", "volume", "subvolume" ] }, target_qgroup_destroy => { default => undef, accept => [ "yes", "no" ] }, archive_qgroup_destroy => { default => undef, accept => [ "yes", "no" ], context => [ "global" ] }, @@ -1883,23 +1887,43 @@ sub system_list_mountinfo($) } +sub system_testdir($) +{ + my $vol = shift // die; + my $path = $vol->{PATH} // die; + my $ret = run_cmd(cmd => vinfo_cmd($vol, "test", '-d', { unsafe => $path } ), + rsh => vinfo_rsh($vol), + non_destructive => 1, + ); + return undef unless(defined($ret)); + DEBUG "Directory exists: $vol->{PRINT}"; + return 1; +} + + sub system_realpath($) { my $vol = shift // die; - - my $path = $vol->{PATH} // die;; - my $ret = run_cmd(cmd => vinfo_cmd($vol, "readlink", '-v', '-e', { unsafe => $path } ), + my $path = $vol->{PATH} // die; + my $compat = (($vol->{HOST} && config_key($vol, "compat_remote")) // + config_key($vol, "compat_local") // + config_key($vol, "compat")) // "" eq "busybox"; + my @options = ("-v"); # report error messages + push @options, "-e" unless($compat); # all components must exist (not available in busybox!) + push @options, "-f" if($compat); # all but the last component must exist. + my $ret = run_cmd(cmd => vinfo_cmd($vol, "readlink", @options, { unsafe => $path } ), rsh => vinfo_rsh($vol), non_destructive => 1, ); return undef unless(defined($ret)); - unless(scalar(@$ret) && ($ret->[0] =~ /^($file_match)$/)) { + my $realpath = scalar(@$ret) ? (check_file($ret->[0], { absolute => 1 }) // "") : ""; + unless($realpath) { ERROR "Failed to parse output of `realpath` for \"$vol->{PRINT}\": \"$ret->[0]\""; return undef; } - my $realpath = $1; # untaint argument DEBUG "Real path for \"$vol->{PRINT}\" is: $realpath"; + return undef if($compat && !system_testdir($vol)); return $realpath; } diff --git a/doc/btrbk.conf.5.asciidoc b/doc/btrbk.conf.5.asciidoc index de02799..0ac4e67 100644 --- a/doc/btrbk.conf.5.asciidoc +++ b/doc/btrbk.conf.5.asciidoc @@ -364,6 +364,9 @@ constraints. *backend* btrfs-progs|btrfs-progs-btrbk|btrfs-progs-sudo:: Backend filesystem utilities to be used for btrfs specific operations. Defaults to ``btrfs-progs''. + If you want to set this option for local or remote hosts only, you + can set *backend_local* or *backend_remote* + (e.g. "backend_remote btrfs-progs-btrbk"). + -- btrfs-progs:: @@ -381,13 +384,17 @@ btrfs-progs-sudo:: btrfs commands are prefixed with "sudo -n" (e.g. "sudo -n btrfs subvolume show" instead of "btrfs subvolume show"). Make sure to have appropriate (root) permissions for the "btrfs" command groups - and the "readlink" command in /etc/sudoers. + as well as the "readlink" and "test" commands in /etc/sudoers. -- + -For convenience, it is also possible to set *backend_local* or -*backend_remote* options, which will override the backend only for -local or remote sources/targets (e.g. "backend_remote -btrfs-progs-btrbk"). + + +*compat* busybox|no:: + If set to ``busybox'', use busybox compatible commands. Defaults + to ``no''. + If you want to set this option for local or remote hosts only, you + can set *compat_local* or *compat_remote* + (e.g. "compat_remote busybox"). === Btrfs Specific Options diff --git a/doc/ssh_filter_btrbk.1.asciidoc b/doc/ssh_filter_btrbk.1.asciidoc index 3d28dc7..9948269 100644 --- a/doc/ssh_filter_btrbk.1.asciidoc +++ b/doc/ssh_filter_btrbk.1.asciidoc @@ -37,6 +37,7 @@ The following commands are always allowed: - "btrfs subvolume show" (not affected by "--restrict-path") - "btrfs subvolume list" (not affected by "--restrict-path") - "readlink" + - "test -d" (only if "compat busybox" configuration option is set) - "cat /proc/self/mountinfo" - pipes through "gzip", "pigz", "bzip2", "pbzip2", "xz", "lzop", "lz4" (stream_compress) diff --git a/ssh_filter_btrbk.sh b/ssh_filter_btrbk.sh index bfdb2cb..2ba8144 100755 --- a/ssh_filter_btrbk.sh +++ b/ssh_filter_btrbk.sh @@ -164,9 +164,10 @@ done # NOTE: subvolume queries are NOT affected by "--restrict-path": # btrbk also calls show/list on the mount point of the subvolume allow_exact_cmd "${sudo_prefix}btrfs subvolume (show|list)( ${option_match})* ${file_match}"; -allow_cmd "${sudo_prefix}readlink" # used to resolve mountpoints -allow_exact_cmd "cat /proc/self/mountinfo" # used to resolve mountpoints -allow_exact_cmd "cat /proc/self/mounts" # legacy, for btrbk < 0.27.0 +allow_cmd "${sudo_prefix}readlink" # resolve symlink +allow_exact_cmd "${sudo_prefix}test -d ${file_match}" # check directory (only for compat=busybox) +allow_exact_cmd "cat /proc/self/mountinfo" # resolve mountpoints +allow_exact_cmd "cat /proc/self/mounts" # legacy, for btrbk < 0.27.0 # remove leading "|" on alternation lists allow_list=${allow_list#\|}