diff --git a/btrbk b/btrbk index 67693c7..868f365 100755 --- a/btrbk +++ b/btrbk @@ -216,6 +216,12 @@ my %table_formats = ( long => [ qw( tree uuid parent_uuid received_uuid recursion ) ], raw => [ qw( tree uuid parent_uuid received_uuid recursion ) ], }, + + fs_list => { table => [ qw( mount_point id flags path ) ], + rel => [ qw( mount_point mount_source path subvolume_path subvolume_rel_path ) ], + long => [ qw( mount_point mount_source id top_level cgen gen uuid parent_uuid received_uuid flags path ) ], + raw => [ qw( mount_point mount_source mount_subvolid id top_level cgen gen uuid parent_uuid received_uuid readonly path subvolume_path ) ], + }, ); my %backend_cmd_map = ( @@ -353,6 +359,7 @@ commands: usage print filesystem usage origin print origin information for subvolume diff shows new files between related subvolumes + ls list all btrfs subvolumes below path For additional information, see $PROJECT_HOME END_HELP @@ -4873,7 +4880,7 @@ MAIN: WARN 'Found option "--progress", but required executable "mbuffer" does not exist on your system. Please install "mbuffer".'; $show_progress = 0; } - my ($action_run, $action_usage, $action_resolve, $action_diff, $action_origin, $action_config_print, $action_list, $action_clean, $action_archive); + my ($action_run, $action_usage, $action_resolve, $action_diff, $action_origin, $action_config_print, $action_list, $action_clean, $action_archive, $action_ls); my @filter_args; my @subvol_args; my @dir_args; @@ -4915,6 +4922,12 @@ MAIN: $action_usage = 1; @filter_args = @ARGV; } + elsif ($command eq "ls") { + $action_ls = 1; + $fallback_default_config = 1; + $args_expected_min = $args_expected_max = 1; + @dir_args = @ARGV; + } elsif ($command eq "diff") { $action_diff = 1; $fallback_default_config = 1; @@ -5156,6 +5169,79 @@ MAIN: } + if($action_ls) + { + # + # print accessible subvolumes for local path + # + my $path = $dir_args[0] || die; + my $root_vol = vinfo($path, $config); + + # map url to real path (we need to match against mount points below) + my $root_path = system_realpath($root_vol); + unless($root_path) { + ERROR "Cannot find real path for: $root_vol->{PATH}"; + exit 1; + } + $root_vol = vinfo($root_path, $config); + $root_path .= '/' unless($root_path =~ /\/$/); # append trailing slash + + my $mountinfo = system_list_mountinfo($root_vol) || die; + $mountinfo_cache{$root_vol->{MACHINE_ID}} = $mountinfo; + + my @data; + my @path_hidden; + foreach my $mnt (reverse @$mountinfo) { + my $mnt_path = $mnt->{mount_point}; + $mnt_path .= '/' unless($mnt_path =~ /\/$/); # append trailing slash + + if(($mnt->{fs_type} eq "btrfs") && + (($root_path =~ /^\Q$mnt_path\E/) || ($mnt_path =~ /^\Q$root_path\E/))) + { + $realpath_cache{$mnt->{mount_point}} = $mnt->{mount_point}; # we know those are real paths, prevents calling readlink in btrfs_mountpoint + my $vol = vinfo($mnt->{mount_point}, $config); + unless(vinfo_init_root($vol)) { + ERROR "Failed to fetch subvolume detail for: $vol->{PRINT}" . ($err ? ": $err" : ""); + exit 1; + } + + my $subvol_list = vinfo_subvol_list($vol); + foreach my $svol ($vol, @$subvol_list) { + my $svol_path = $svol->{PATH}; + $svol_path .= '/' unless($svol_path =~ /\/$/); # append trailing slash + + next unless($svol_path =~ /^\Q$root_path\E/); + + if(grep { $svol_path =~ /^\Q$_\E/ } @path_hidden) { + DEBUG "subvolume is hidden by another mount point: $svol->{PRINT}"; + next; + } + + push @data, { + %{$svol->{node}}, # copy node + mount_point => $svol->{VINFO_MOUNTPOINT}{PATH}, + mount_source => $svol->{node}{TREE_ROOT}{host_mount_source}, + mount_subvolid => $mnt->{MNTOPS}{subvolid}, + subvolume_path => $svol->{node}{path}, + subvolume_rel_path => $svol->{node}{REL_PATH}, + path => $svol->{PATH}, + flags => ($svol->{node}{readonly} ? "readonly" : undef), + }; + } + } + last if($root_path =~ /^\Q$mnt_path\E/); + push @path_hidden, ($mnt->{mount_point} . '/'); + } + + my @sorted = sort { $a->{path} cmp $b->{path} } @data; + if($output_format) { + print_formatted("fs_list", \@sorted); + } else { + print join("\n", map { $_->{path} } @sorted) . "\n"; + } + exit 0; + } + # # try exclusive lock if set in config or command-line option