diff --git a/ChangeLog b/ChangeLog index ffb6c22..0fe77a1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +btrbk-current + + * Add "resume" command, replacement for "-r, --resume-only" command + line option (which is now deprecated). + * Add "snapshot" command (close #150). + * Add "--preserve-snapshots" and "--preserve-backups" options. + btrbk-0.25.1 * Support for btrfs-progs v4.12: fix parsing of "btrfs sub show" diff --git a/btrbk b/btrbk index 09813f1..6452907 100755 --- a/btrbk +++ b/btrbk @@ -22,7 +22,7 @@ Axel Burri =head1 COPYRIGHT AND LICENSE -Copyright (c) 2014-2016 Axel Burri. All rights reserved. +Copyright (c) 2014-2017 Axel Burri. All rights reserved. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -46,7 +46,7 @@ use Carp qw(confess); use Getopt::Long qw(GetOptions); use Time::Local qw( timelocal timegm timegm_nocheck ); -our $VERSION = '0.25.1'; +our $VERSION = '0.26.0-dev'; our $AUTHOR = 'Axel Burri '; our $PROJECT_HOME = ''; @@ -280,24 +280,26 @@ sub HELP_MESSAGE print STDERR "\n"; print STDERR "options:\n"; # "--------------------------------------------------------------------------------"; # 80 - print STDERR " -h, --help display this help message\n"; - print STDERR " --version display version information\n"; - print STDERR " -c, --config=FILE specify configuration file\n"; - print STDERR " -n, --dry-run perform a trial run with no changes made\n"; - print STDERR " -p, --preserve preserve all backups (do not delete any old targets)\n"; - print STDERR " -r, --resume-only resume only (do not create new snapshots, only resume\n"; - print STDERR " missing backups)\n"; - print STDERR " -v, --verbose be verbose (set loglevel=info)\n"; - print STDERR " -q, --quiet be quiet (do not print summary for the \"run\" command)\n"; - print STDERR " -l, --loglevel=LEVEL set logging level (warn, info, debug, trace)\n"; - print STDERR " -t, --table change output to table format\n"; - print STDERR " --format=FORMAT change output format, FORMAT=table|long|raw\n"; - print STDERR " --print-schedule print scheduler details (for the \"run\" command)\n"; - print STDERR " --progress show progress bar on send-receive operation\n"; + print STDERR " -h, --help display this help message\n"; + print STDERR " --version display version information\n"; + print STDERR " -c, --config=FILE specify configuration file\n"; + print STDERR " -n, --dry-run perform a trial run with no changes made\n"; + print STDERR " -p, --preserve preserve all (do not delete anything)\n"; + print STDERR " --preserve-snapshots preserve snapshots (do not delete snapshots)\n"; + print STDERR " --preserve-backups preserve backups (do not delete backups)\n"; + print STDERR " -v, --verbose be verbose (set loglevel=info)\n"; + print STDERR " -q, --quiet be quiet (do not print backup summary)\n"; + print STDERR " -l, --loglevel=LEVEL set logging level (warn, info, debug, trace)\n"; + print STDERR " -t, --table change output to table format\n"; + print STDERR " --format=FORMAT change output format, FORMAT=table|long|raw\n"; + print STDERR " --print-schedule print scheduler details (for the \"run\" command)\n"; + print STDERR " --progress show progress bar on send-receive operation\n"; print STDERR "\n"; print STDERR "commands:\n"; - print STDERR " run perform backup operations as defined in the config\n"; + print STDERR " run run snapshot and backup operations\n"; print STDERR " dryrun don't run btrfs commands; show what would be executed\n"; + print STDERR " snapshot run snapshot operations only\n"; + print STDERR " resume run backup operations, and delete snapshots\n"; print STDERR " stats print snapshot/backup statistics\n"; print STDERR " list available subcommands are:\n"; print STDERR " backups all backups and corresponding snapshots\n"; @@ -3478,6 +3480,11 @@ sub print_header(@) if($args{info}) { print "\n" . join("\n", grep(defined, @{$args{info}})) . "\n"; } + if($args{options} && (scalar @{$args{options}})) { + print "\nOptions:\n "; + print join("\n ", @{$args{options}}); + print "\n"; + } if($args{legend}) { print "\nLegend:\n "; print join("\n ", @{$args{legend}}); @@ -3707,23 +3714,26 @@ MAIN: @tm_now = localtime($start_time); my %config_override_cmdline; - my ($config_cmdline, $quiet, $verbose, $preserve_backups, $resume_only, $print_schedule, $lockfile_cmdline); + my ($config_cmdline, $quiet, $verbose, $preserve_snapshots, $preserve_backups, $skip_snapshots, $skip_backups, $print_schedule, $lockfile_cmdline); + my $resume_only_DEPRECATED; # as of btrbk-v0.26.0 unless(GetOptions( - 'help|h' => sub { VERSION_MESSAGE(); HELP_MESSAGE(0); exit 0; }, - 'version' => sub { VERSION_MESSAGE(); exit 0; }, - 'config|c=s' => \$config_cmdline, - 'dry-run|n' => \$dryrun, - 'preserve|p' => \$preserve_backups, - 'resume-only|r' => \$resume_only, - 'quiet|q' => \$quiet, - 'verbose|v' => sub { $loglevel = 2; }, - 'loglevel|l=s' => \$loglevel, - 'progress' => \$show_progress, - 'table|t' => sub { $output_format = "table" }, - 'format=s' => \$output_format, - 'print-schedule' => \$print_schedule, - 'lockfile=s' => \$lockfile_cmdline, - 'override=s' => \%config_override_cmdline, # e.g. --override=incremental=no + 'help|h' => sub { VERSION_MESSAGE(); HELP_MESSAGE(0); exit 0; }, + 'version' => sub { VERSION_MESSAGE(); exit 0; }, + 'config|c=s' => \$config_cmdline, + 'dry-run|n' => \$dryrun, + 'preserve|p' => sub { $preserve_snapshots = 1, $preserve_backups = 1 }, + 'preserve-snapshots' => \$preserve_snapshots, + 'preserve-backups' => \$preserve_backups, + 'resume-only|r' => \$resume_only_DEPRECATED, + 'quiet|q' => \$quiet, + 'verbose|v' => sub { $loglevel = 2; }, + 'loglevel|l=s' => \$loglevel, + 'progress' => \$show_progress, + 'table|t' => sub { $output_format = "table" }, + 'format=s' => \$output_format, + 'print-schedule' => \$print_schedule, + 'lockfile=s' => \$lockfile_cmdline, + 'override=s' => \%config_override_cmdline, # e.g. --override=incremental=no )) { VERSION_MESSAGE(); @@ -3747,6 +3757,14 @@ MAIN: else { $loglevel = 1; } require_data_dumper() if(($loglevel >= 4) || ($VERSION =~ /-dev$/)); + # DEPRECATED options + if($resume_only_DEPRECATED) { + WARN "Found deprecated command line option \"-r, --resume-only\": Use \"btrbk resume --preserve\""; + $skip_snapshots = 1; + $preserve_backups = 1; + $preserve_snapshots = 1; + } + # check command line options if($show_progress && (not check_exe('pv'))) { WARN 'Found option "--progress", but required executable "pv" does not exist on your system. Please install "pv".'; @@ -3763,6 +3781,19 @@ MAIN: $args_allow_group = 1; @filter_args = @ARGV; } + elsif($command eq "snapshot") { + $action_run = 1; + $skip_backups = 1; + $preserve_backups = 1; + $args_allow_group = 1; + @filter_args = @ARGV; + } + elsif($command eq "resume") { + $action_run = 1; + $skip_snapshots = 1; + $args_allow_group = 1; + @filter_args = @ARGV; + } elsif ($command eq "clean") { $action_clean = 1; @filter_args = @ARGV; @@ -4110,12 +4141,13 @@ MAIN: } - my $del_schedule_results = []; - if($preserve_backups || $resume_only) { + my $del_schedule_results; + if($preserve_backups) { INFO "Preserving all archives (option \"-p\" or \"-r\" present)"; } else { + $del_schedule_results = []; foreach my $sroot (vinfo_subsection($config, 'archive_source')) { foreach my $droot (vinfo_subsection($sroot, 'target')) { my $snapshot_name = config_key($droot, "snapshot_name") // die; @@ -4152,7 +4184,7 @@ MAIN: print "\n"; } - if($print_schedule && not ($preserve_backups || $resume_only)) { + if($print_schedule && $del_schedule_results) { my @data = map { { %$_, vinfo_prefixed_keys("", $_->{value}) }; } @$del_schedule_results; print_formatted("schedule", \@data, title => "DELETE SCHEDULE"); print "\n"; @@ -4192,8 +4224,12 @@ MAIN: } } + my @cmdline_options; + push @cmdline_options, "preserve: Preserved all archives" if($preserve_backups); + print_header(title => "Archive Summary", time => $start_time, + options => \@cmdline_options, legend => [ "++. created directory", "--- deleted subvolume", @@ -5034,8 +5070,8 @@ MAIN: init_transaction_log(config_key($config, "transaction_log"), config_key($config, "transaction_syslog")); - if($resume_only) { - INFO "Skipping snapshot creation (option \"-r\" present)"; + if($skip_snapshots) { + INFO "Skipping snapshot creation (btrbk resume)"; } else { @@ -5133,96 +5169,101 @@ MAIN: # # create backups # - foreach my $sroot (vinfo_subsection($config, 'volume')) { - foreach my $svol (vinfo_subsection($sroot, 'subvolume')) { - my $snapdir = config_key($svol, "snapshot_dir") // ""; - my $snapshot_basename = config_key($svol, "snapshot_name") // die; - my @snapshot_children = sort({ cmp_date($a->{node}{BTRBK_DATE}, $b->{node}{BTRBK_DATE}) } - get_snapshot_children($sroot, $svol, $snapdir, $snapshot_basename)); + if($skip_backups) { + INFO "Skipping backup creation (btrbk snapshot)"; + } + else { + foreach my $sroot (vinfo_subsection($config, 'volume')) { + foreach my $svol (vinfo_subsection($sroot, 'subvolume')) { + my $snapdir = config_key($svol, "snapshot_dir") // ""; + my $snapshot_basename = config_key($svol, "snapshot_name") // die; + my @snapshot_children = sort({ cmp_date($a->{node}{BTRBK_DATE}, $b->{node}{BTRBK_DATE}) } + get_snapshot_children($sroot, $svol, $snapdir, $snapshot_basename)); - foreach my $droot (vinfo_subsection($svol, 'target')) { - INFO "Checking for missing backups of subvolume \"$svol->{PRINT}\" in \"$droot->{PRINT}/\""; - my @schedule; - my $resume_total = 0; - my $resume_success = 0; + foreach my $droot (vinfo_subsection($svol, 'target')) { + INFO "Checking for missing backups of subvolume \"$svol->{PRINT}\" in \"$droot->{PRINT}/\""; + my @schedule; + my $resume_total = 0; + my $resume_success = 0; - my $droot_subvol_list = vinfo_subvol_list($droot); # cache subvol list for get_receive_targets() - foreach my $child (@snapshot_children) - { - my $warning_seen = []; - my @receive_targets = get_receive_targets($droot, $child, exact_match => 1, warn => 1, seen => $warning_seen, droot_subvol_list => $droot_subvol_list ); - get_receive_targets_fsroot($droot, $child, exclude => $warning_seen, warn => 1); # warn on unexpected on fs - if(scalar(@receive_targets)){ - DEBUG "Found receive target of: $child->{PRINT}"; - next; - } - - DEBUG "Adding backup candidate: $child->{PRINT}"; - push(@schedule, { value => $child, - btrbk_date => $child->{node}{BTRBK_DATE}, - # not enforcing resuming of latest snapshot anymore (since v0.23.0) - # preserve => $child->{node}{FORCE_PRESERVE}, - }); - } - - if(scalar @schedule) - { - DEBUG "Checking schedule for backup candidates"; - # add all present backups as informative_only: these are needed for correct results of schedule() - foreach my $vol (@$droot_subvol_list) { - unless($vol->{btrbk_direct_leaf} && ($vol->{node}{BTRBK_BASENAME} eq $snapshot_basename)) { - TRACE "Receive target does not match btrbk filename scheme, skipping: $vol->{PRINT}"; + my $droot_subvol_list = vinfo_subvol_list($droot); # cache subvol list for get_receive_targets() + foreach my $child (@snapshot_children) + { + my $warning_seen = []; + my @receive_targets = get_receive_targets($droot, $child, exact_match => 1, warn => 1, seen => $warning_seen, droot_subvol_list => $droot_subvol_list ); + get_receive_targets_fsroot($droot, $child, exclude => $warning_seen, warn => 1); # warn on unexpected on fs + if(scalar(@receive_targets)){ + DEBUG "Found receive target of: $child->{PRINT}"; next; } - push(@schedule, { informative_only => 1, - value => $vol, - btrbk_date => $vol->{node}{BTRBK_DATE}, + + DEBUG "Adding backup candidate: $child->{PRINT}"; + push(@schedule, { value => $child, + btrbk_date => $child->{node}{BTRBK_DATE}, + # not enforcing resuming of latest snapshot anymore (since v0.23.0) + # preserve => $child->{node}{FORCE_PRESERVE}, }); } - my ($preserve, undef) = schedule( - schedule => \@schedule, - preserve => config_preserve_hash($droot, "target"), - ); - my @resume = grep defined, @$preserve; # remove entries with no value from list (target subvolumes) - $resume_total = scalar @resume; - foreach my $child (sort { $a->{node}{cgen} <=> $b->{node}{cgen} } @resume) + if(scalar @schedule) { - # Continue gracefully (skip instead of abort) on existing (possibly garbled) target - my $err_vol = vinfo_subvol($droot, $child->{NAME}); - if($err_vol) { - my $status_msg = "Please delete stray subvolume (\"btrbk clean\"): $err_vol->{PRINT}"; - WARN "Target subvolume \"$err_vol->{PRINT}\" exists, but is not a receive target of \"$child->{PRINT}\""; - WARN $status_msg; - WARN "Skipping backup of: $child->{PRINT}"; - $droot->{SUBVOL_RECEIVED} //= []; - push(@{$droot->{SUBVOL_RECEIVED}}, { ERROR => $status_msg, received_subvolume => $err_vol }); - $droot->{CONFIG}->{UNRECOVERABLE} = $status_msg; - next; + DEBUG "Checking schedule for backup candidates"; + # add all present backups as informative_only: these are needed for correct results of schedule() + foreach my $vol (@$droot_subvol_list) { + unless($vol->{btrbk_direct_leaf} && ($vol->{node}{BTRBK_BASENAME} eq $snapshot_basename)) { + TRACE "Receive target does not match btrbk filename scheme, skipping: $vol->{PRINT}"; + next; + } + push(@schedule, { informative_only => 1, + value => $vol, + btrbk_date => $vol->{node}{BTRBK_DATE}, + }); } + my ($preserve, undef) = schedule( + schedule => \@schedule, + preserve => config_preserve_hash($droot, "target"), + ); + my @resume = grep defined, @$preserve; # remove entries with no value from list (target subvolumes) + $resume_total = scalar @resume; - INFO "Creating subvolume backup (send-receive) for: $child->{PRINT}"; - my ($latest_common_src, $latest_common_target) = get_latest_common($sroot, $child, $droot, $snapdir); - if(macro_send_receive(source => $child, - target => $droot, - parent => $latest_common_src, # this is if no common found - latest_common_target => $latest_common_target, - )) + foreach my $child (sort { $a->{node}{cgen} <=> $b->{node}{cgen} } @resume) { - $resume_success++; - } - else { - # note: ABORTED flag is already set by macro_send_receive() - ERROR("Error while resuming backups, aborting"); - last; + # Continue gracefully (skip instead of abort) on existing (possibly garbled) target + my $err_vol = vinfo_subvol($droot, $child->{NAME}); + if($err_vol) { + my $status_msg = "Please delete stray subvolume (\"btrbk clean\"): $err_vol->{PRINT}"; + WARN "Target subvolume \"$err_vol->{PRINT}\" exists, but is not a receive target of \"$child->{PRINT}\""; + WARN $status_msg; + WARN "Skipping backup of: $child->{PRINT}"; + $droot->{SUBVOL_RECEIVED} //= []; + push(@{$droot->{SUBVOL_RECEIVED}}, { ERROR => $status_msg, received_subvolume => $err_vol }); + $droot->{CONFIG}->{UNRECOVERABLE} = $status_msg; + next; + } + + INFO "Creating subvolume backup (send-receive) for: $child->{PRINT}"; + my ($latest_common_src, $latest_common_target) = get_latest_common($sroot, $child, $droot, $snapdir); + if(macro_send_receive(source => $child, + target => $droot, + parent => $latest_common_src, # this is if no common found + latest_common_target => $latest_common_target, + )) + { + $resume_success++; + } + else { + # note: ABORTED flag is already set by macro_send_receive() + ERROR("Error while resuming backups, aborting"); + last; + } } } - } - if($resume_total) { - INFO "Created $resume_success/$resume_total missing backups"; - } else { - INFO "No missing backups found"; + if($resume_total) { + INFO "Created $resume_success/$resume_total missing backups"; + } else { + INFO "No missing backups found"; + } } } } @@ -5232,12 +5273,13 @@ MAIN: # # remove backups following a preserve daily/weekly/monthly scheme # - my $schedule_results = []; - if($preserve_backups || $resume_only) { - INFO "Preserving all snapshots and backups (option \"-p\" or \"-r\" present)"; + my $schedule_results; + if($preserve_snapshots && $preserve_backups) { + INFO "Preserving all snapshots and backups"; } else { + $schedule_results = []; foreach my $sroot (vinfo_subsection($config, 'volume')) { foreach my $svol (vinfo_subsection($sroot, 'subvolume')) { my $snapdir = config_key($svol, "snapshot_dir") // ""; @@ -5272,43 +5314,52 @@ MAIN: } } - # - # delete backups - # - INFO "Cleaning backups of subvolume \"$svol->{PRINT}\": $droot->{PRINT}/$snapshot_basename.*"; - unless(macro_delete($droot, "", $snapshot_basename, $droot, - { preserve => config_preserve_hash($droot, "target"), - results => $schedule_results, - result_hints => { topic => "backup", root_path => $droot->{PATH} }, - }, - commit => config_key($droot, "btrfs_commit_delete"), - type => "delete_target", - )) - { - $target_aborted = -1; + if($preserve_backups) { + INFO "Preserving all backups"; + } + else { + # + # delete backups + # + INFO "Cleaning backups of subvolume \"$svol->{PRINT}\": $droot->{PRINT}/$snapshot_basename.*"; + unless(macro_delete($droot, "", $snapshot_basename, $droot, + { preserve => config_preserve_hash($droot, "target"), + results => $schedule_results, + result_hints => { topic => "backup", root_path => $droot->{PATH} }, + }, + commit => config_key($droot, "btrfs_commit_delete"), + type => "delete_target", + )) + { + $target_aborted = 1; + } } } # # delete snapshots # - if($target_aborted) { + if($preserve_snapshots) { + INFO "Preserving all snapshots"; + } + elsif($target_aborted) { if($target_aborted == -1) { INFO "Skipping cleanup of snapshots for subvolume \"$svol->{PRINT}\", as at least one target is skipped by command line argument"; } else { WARN "Skipping cleanup of snapshots for subvolume \"$svol->{PRINT}\", as at least one target aborted earlier"; } - next; } - INFO "Cleaning snapshots: $sroot->{PRINT}/$snapdir_ts$snapshot_basename.*"; - macro_delete($sroot, $snapdir, $snapshot_basename, $svol, - { preserve => config_preserve_hash($svol, "snapshot"), - results => $schedule_results, - result_hints => { topic => "snapshot", root_path => $sroot->{PATH} }, - }, - commit => config_key($svol, "btrfs_commit_delete"), - type => "delete_snapshot", - ); + else { + INFO "Cleaning snapshots: $sroot->{PRINT}/$snapdir_ts$snapshot_basename.*"; + macro_delete($sroot, $snapdir, $snapshot_basename, $svol, + { preserve => config_preserve_hash($svol, "snapshot"), + results => $schedule_results, + result_hints => { topic => "snapshot", root_path => $sroot->{PATH} }, + }, + commit => config_key($svol, "btrfs_commit_delete"), + type => "delete_snapshot", + ); + } } } } @@ -5329,7 +5380,7 @@ MAIN: # # print scheduling results # - if($print_schedule) { + if($print_schedule && $schedule_results) { my @data = map { { %$_, vinfo_prefixed_keys("", $_->{value}) }; } @$schedule_results; my @data_snapshot = grep { $_->{topic} eq "snapshot" } @data; my @data_backup = grep { $_->{topic} eq "backup" } @data; @@ -5406,9 +5457,16 @@ MAIN: } } + my @cmdline_options; + push @cmdline_options, "btrbk resume: No snapshots created" if($skip_snapshots); + push @cmdline_options, "btrbk snapshot: No backups created" if($skip_backups); + push @cmdline_options, "preserve-snapshots: Preserved all snapshots" if($preserve_snapshots); + push @cmdline_options, "preserve-backups: Preserved all backups" if($preserve_backups); + print_header(title => "Backup Summary", config => $config, time => $start_time, + options => \@cmdline_options, legend => [ "=== up-to-date subvolume (source snapshot)", "+++ created subvolume (source snapshot)", @@ -5420,12 +5478,6 @@ MAIN: print join("\n", @out); - if($resume_only) { - print "\nNOTE: No snapshots created (option -r present)\n"; - } - if($preserve_backups || $resume_only) { - print "\nNOTE: Preserved all snapshots and backups (option -p or -r present)\n"; - } if($exit_status || scalar(@unrecoverable)) { print "\nNOTE: Some errors occurred, which may result in missing backups!\n"; print "Please check warning and error messages above.\n"; diff --git a/doc/btrbk.1 b/doc/btrbk.1 index 5ba640d..72f9635 100644 --- a/doc/btrbk.1 +++ b/doc/btrbk.1 @@ -1,4 +1,4 @@ -.TH "btrbk" "1" "2017-07-30" "btrbk v0.25.1" "" +.TH "btrbk" "1" "2017-08-21" "btrbk v0.26.0-dev" "" .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) @@ -8,7 +8,8 @@ btrbk \- backup tool for btrfs volumes .SH SYNOPSIS .nf \fBbtrbk\fR [\-h|\-\-help] [\-\-version] [\-c|\-\-config ] - [\-n|\-\-dry\-run] [\-p|\-\-preserve] [\-r|\-\-resume\-only] + [\-n|\-\-dry\-run] [\-p|\-\-preserve] + [\-\-preserve\-snapshots] [\-\-preserve\-backups] [\-v|\-\-verbose] [\-q|\-\-quiet] [\-l|\-\-loglevel ] [\-t|\-\-table] [\-\-format ] [\-\-progress] [\-\-print\-schedule] @@ -50,8 +51,9 @@ Prints the btrbk version. .RS 4 Don't run anything that would alter the filesystem, just show the snapshots and backup subvolumes that would be created/deleted by the -\fBrun\fR and \fBclean\fR commands. Use in conjunction with \fI\-l -debug\fR to see the btrfs commands that would be executed. +\fBrun\fR, \fBsnapshot\fR, \fBresume\fR, \fBarchive\fR and \fBclean\fR +commands. Use in conjunction with \fI\-l debug\fR to see the btrfs +commands that would be executed. .RE .PP \-c, \-\-config @@ -62,13 +64,20 @@ Read the configuration from . \-p, \-\-preserve .RS 4 Preserve all snapshots and backups. Skips deletion of any snapshots -and backups, even if specified in the configuration file. +and backups, even if specified in the configuration file (shortcut for +"\-\-preserve\-snapshots \-\-preserve\-backups"). .RE .PP -\-r, \-\-resume-only +\-\-preserve-snapshots .RS 4 -Resume only. Skips snapshot creation, only resumes missing backups to -satisfy the target retention policy. +Preserve all snapshots. Skips deletion of any snapshots, even if +specified in the configuration file. +.RE +.PP +\-\-preserve-backups +.RS 4 +Preserve all backups. Skips deletion of any backups, even if specified +in the configuration file. .RE .PP \-v, \-\-verbose @@ -79,7 +88,8 @@ Verbose output (shortcut for "\-\-loglevel=info"). \-q, \-\-quiet .RS 4 Quiet operation. If set, btrbk does not print the summary after -executing the "run" command. +executing the \fBrun\fR, \fBsnapshot\fR, \fBresume\fR, or +\fBarchive\fR commands. .RE .PP \-l, \-\-loglevel @@ -97,8 +107,8 @@ Print output in table format (shortcut for "\-\-format=table"). .RS 4 Print output in specified format. If set to "raw", prints space-separated key="value" pairs (machine readable). Affects output -format for \fBrun\fR, \fBdryrun\fR and \fBlist\fR commands. Useful for -further exporting/scripting. +format for \fBrun\fR, \fBsnapshot\fR, \fBresume\fR, \fBarchive\fR and +\fBlist\fR commands. Useful for further exporting/scripting. .RE .PP \-\-progress @@ -108,15 +118,15 @@ Show progress bar on send-receive operation. .PP \-\-print\-schedule .RS 4 -Print detailed scheduler information on \fBrun\fR and \fBdryrun\fR -commands. Use the \fI\-\-format\fR command line option to switch -between different output formats. +Print detailed scheduler information on \fBrun\fR, \fBsnapshot\fR, +\fBresume\fR and \fBarchive\fR commands. Use the \fI\-\-format\fR +command line option to switch between different output formats. .RE .PP \-\-override = .RS 4 -Override a configuration option with . -Globally, for ALL contexts. Use with care! +Override a configuration option with +. Globally, for ALL contexts. Use with care! .RE .PP \-\-lockfile @@ -136,27 +146,47 @@ configuration file. If the optional [filter...] arguments are present, snapshots and backups are only performed for the subvolumes/targets matching a \fIFILTER STATEMENT\fR (see below). .PP -First, btrbk reads information from the source and target btrfs -filesystems in order to perform sanity checks and identify -parent/child and received-from relationships. +.B Step 0: Read Data +.RS 4 +Read information from the source and target btrfs filesystems in order +to perform sanity checks and identify parent/child and received-from +relationships. +.RE .PP +.B Step 1: Create Snapshots +.RS 4 If the checks succeed, btrbk creates snapshots for the source subvolumes specified in the configuration file, according to the \fIsnapshot_create\fR option. +.RE .PP -Then, for each specified target, btrbk creates the backups as follows: -After comparing the backups to the source snapshots, btrbk transfers -all missing snapshots needed to satisfy the configured target -retention policy, incrementally from the latest common parent -subvolume found. If no common parent subvolume is found (or if the +.B Step 2: Create Backups +.RS 4 +For each specified target, btrbk creates the backups as follows: After +comparing the backups to the source snapshots, btrbk transfers all +missing snapshots needed to satisfy the configured target retention +policy, incrementally from the latest common parent subvolume +found. If no common parent subvolume is found (or if the \fIincremental\fR option is set to \[lq]no\[rq]), a full (non-incremental) backup is created. +.RE .PP -As a last step, unless the \-p (\-\-preserve) option is set, snapshots -and backup subvolumes that are not preserved by their configured -retention policy will be deleted. Note that the latest snapshot (the -one created in the first step) as well as the latest snapshot/backup -pair are always preserved, regardless of the retention policy. +.B Step 3: Delete Backups +.RS 4 +Unless the \-p, \-\-preserve or \-\-preserve\-backups option is set, +backup subvolumes that are not preserved by their configured retention +policy will be deleted. Note that the latest snapshot/backup pair are +always preserved, regardless of the retention policy. +.RE +.PP +.B Step 4: Delete Snapshots +.RS 4 +Unless the \-p, \-\-preserve or \-\-preserve-snapshots option is set, +snapshots that are not preserved by their configured retention policy +will be deleted. Note that the latest snapshot (the one created in +step 1) as well as the latest snapshot/backup pair are always +preserved, regardless of the retention policy. +.RE .PP See section RETENTION POLICY in .BR btrbk.conf (5) @@ -175,6 +205,24 @@ by the \fBrun\fR command. Use in conjunction with \fI\-l debug\fR to see the btrfs commands that would be executed. .RE .PP +.B snapshot +[filter...] +.RS 4 +Snapshot only: skips backup creation and deletion (steps 2 and 3). Use +in conjunction with \-p, \-\-preserve (or \-\-preserve\-snapshots) if +you also want to skip snapshot deletion (step 4). +.RE +.PP +.B resume +[filter...] +.RS 4 +Resume backups: skips snapshot creation (step 1), transfers and +deletes snapshots/backups in order to satisfy their configured +retention policy. Use in conjunction with \-p, \-\-preserve, +\-\-preserve\-backups, \-\-preserve\-snapshots if you want to skip +backup and/or snapshot deletion (steps 3, 4). +.RE +.PP .B archive .I *experimental*