diff --git a/ChangeLog b/ChangeLog index 7c9fd0b..f445572 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,7 @@ btrbk-current * Allow filtering subcommands by group as well as targets. * Added "--raw-output" command line option, producing raw (machine-readable) output for "(dry)run" and "tree" commands. + * Added "config dump" command (experimental). * Added configuration option "ssh_cipher_spec" (close: #47). * Hardened ssh_filter_btrbk.sh script: fine-grained access control, restrict-path option, sudo option (close: #45) diff --git a/btrbk b/btrbk index 3616730..7de840b 100755 --- a/btrbk +++ b/btrbk @@ -1523,7 +1523,7 @@ MAIN: WARN 'found option "--progress", but "pv" is not present: (please install "pv")'; $show_progress = 0; } - my ($action_run, $action_info, $action_tree, $action_diff, $action_origin); + my ($action_run, $action_info, $action_tree, $action_diff, $action_origin, $action_config); my @filter_args; my $args_allow_group = 0; my ($args_expected_min, $args_expected_max) = (0, 0); @@ -1559,6 +1559,22 @@ MAIN: $args_expected_min = $args_expected_max = 1; @filter_args = @ARGV; } + elsif ($command eq "config") { + $action_config = shift @ARGV // ""; + $action_config .= ' ' . (shift @ARGV // ""); + unless(($action_config eq "dump source") || + ($action_config eq "dump target") || + ($action_config eq "dump volume")) + { + ERROR "unknown subcommand for \"config\" command: $action_config"; + HELP_MESSAGE(0); + exit 1; + } + $args_expected_min = 0; + $args_expected_max = 9999; + $args_allow_group = 1; + @filter_args = @ARGV; + } else { ERROR "Unrecognized command: $command"; HELP_MESSAGE(0); @@ -1711,7 +1727,7 @@ MAIN: # # filter subvolumes matching command line arguments # - if(($action_run || $action_tree || $action_info) && scalar(@filter_args)) + if(($action_run || $action_tree || $action_info || $action_config) && scalar(@filter_args)) { my %match; foreach my $config_vol (@{$config->{VOLUME}}) { @@ -1837,6 +1853,60 @@ MAIN: } + if($action_config) + { + # + # print configuration lines, machine readable + # + foreach my $config_vol (@{$config->{VOLUME}}) { + next if($config_vol->{ABORTED}); + my $sroot = vinfo($config_vol->{url}, $config_vol); + + my @vol_info; + push @vol_info, "volume_url=\"$sroot->{URL}\""; + push @vol_info, "volume_path=\"$sroot->{PATH}\""; + push @vol_info, "volume_rsh=\"" . ($sroot->{RSH} ? join(" ", @{$sroot->{RSH}}) : "") . "\""; + + if($action_config eq "dump volume") { + print join(' ', @vol_info) . "\n"; + next; + } + + foreach my $config_subvol (@{$config_vol->{SUBVOLUME}}) { + next if($config_subvol->{ABORTED}); + my $svol = vinfo_child($sroot, $config_subvol->{rel_path}); + + my @sline; + push @sline, "source_url=\"$svol->{URL}\""; + push @sline, "source_path=\"$svol->{PATH}\""; + push @sline, "snapshot_path=\"$sroot->{PATH}" . (config_key($config_subvol, "snapshot_dir", prefix => '/') // "") . "\""; + push @sline, "snapshot_basename=\"" . config_key($config_subvol, "snapshot_name") . "\""; + push @sline, "source_host=\"" . ($svol->{HOST} // "") . "\""; + push @sline, "source_rsh=\"" . ($svol->{RSH} ? join(" ", @{$svol->{RSH}}) : "") . "\""; + + if($action_config eq "dump source") { + print join(' ', @sline) . "\n"; + } + elsif($action_config eq "dump target") + { + foreach my $config_target (@{$config_subvol->{TARGET}}) + { + next if($config_target->{ABORTED}); + my $droot = vinfo($config_target->{url}, $config_target); + my @dline = @sline; + push @dline, "target_url=\"$droot->{URL}\""; + push @dline, "target_path=\"$droot->{PATH}\""; + push @dline, "target_host=\"" . ($droot->{HOST} // "") . "\""; + push @dline, "target_rsh=\"" . ($droot->{RSH} ? join(" ", @{$droot->{RSH}}) : "") . "\""; + print join(' ', @dline) . "\n"; + } + } + } + } + exit 0; + } + + # # fill vinfo hash, basic checks on configuration # diff --git a/doc/FAQ.md b/doc/FAQ.md index d1c00f1..1809915 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -29,6 +29,27 @@ This will produce daily snapshots `/mnt/btr_backup/myhost.20150101`, with retention as defined with the snapshot_preserve_* options. +How can I auto-mount btrfs filesystems used by btrbk? +----------------------------------------------------- + +Given that the "volume" lines in the btrbk configuration file are +valid mount-points, you can loop through the configuration and mount +the volumes like this: + + #!/bin/sh + btrbk config dump volume | while read line; do + eval $line + $volume_rsh mount $volume_path + done + +Note that the `btrbk config dump volume` command accepts filters (see +[btrbk(1)], FILTER STATEMENTS), which means you can e.g. add "group +automount" tags in your configuration and dump only the volumes of +this group: `btrbk config dump volume automount`. + + [btrbk(1)]: http://www.digint.ch/btrbk/doc/btrbk.html + + Why is it not possible to backup '/' (btrfs root) ? --------------------------------------------------- diff --git a/doc/btrbk.1 b/doc/btrbk.1 index 835123c..77d15d4 100644 --- a/doc/btrbk.1 +++ b/doc/btrbk.1 @@ -182,6 +182,12 @@ parent-child relationship as well as the received-from information. .RS 4 Print new files since subvolume for subvolume . .RE +.PP +.B config dump +volume|source|target [filter...] \fI*experimental*\fR +.RS 4 +Dump parsed content from the configuration file, in format: key="value"... +.RE .SH FILTER STATEMENTS Filter arguments are accepted in form: .PP