diff --git a/ChangeLog b/ChangeLog index 7a6ae00..91719d4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ btrbk-current + * Added "lockfile" configuration option and --lockfile command line + option (close: #81). * Bugfix: raw targets: correctly handle multiple backups in same target directory (close: #87). * Use relative instead of absolute binary calls in btrbk-mail. diff --git a/btrbk b/btrbk index daaf1d3..4c6ac4b 100755 --- a/btrbk +++ b/btrbk @@ -96,6 +96,7 @@ my %config_options = ( rate_limit => { default => undef, accept => [ "no" ], accept_regexp => qr/^[0-9]+[kmgt]?$/, require_bin => 'pv' }, transaction_log => { default => undef, accept_file => { absolute => 1 } }, transaction_syslog => { default => undef, accept => \@syslog_facilities }, + lockfile => { default => undef, accept_file => { absolute => 1 }, context => [ "root" ] }, raw_target_compress => { default => undef, accept => [ "no", "gzip", "bzip2", "xz" ] }, raw_target_compress_level => { default => "default", accept => [ "default" ], accept_numeric => 1 }, @@ -204,6 +205,7 @@ my $show_progress = 0; my $err = ""; my $abrt = ""; # last ABORTED() message my $output_format; +my $lockfile; my $tlog_fh; my $syslog_enabled = 0; my $current_transaction; @@ -3379,7 +3381,7 @@ MAIN: @tm_now = localtime($start_time); my %config_override_cmdline; - my ($config_cmdline, $quiet, $verbose, $preserve_backups, $resume_only, $print_schedule); + my ($config_cmdline, $quiet, $verbose, $preserve_backups, $resume_only, $print_schedule, $lockfile_cmdline); unless(GetOptions( 'help|h' => sub { VERSION_MESSAGE(); HELP_MESSAGE(0); exit 0; }, 'version' => sub { VERSION_MESSAGE(); exit 0; }, @@ -3394,6 +3396,7 @@ MAIN: '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 )) { @@ -3535,6 +3538,15 @@ MAIN: exit 2; } } + if(defined($lockfile_cmdline)) { + if($lockfile_cmdline =~ /^($file_match)$/) { + $lockfile = $1; # untaint argument + } else { + ERROR "Option \"--lockfile\" is not a valid file name: \"$lockfile_cmdline\""; + HELP_MESSAGE(0); + exit 2; + } + } INFO "$VERSION_INFO (" . localtime($start_time) . ")"; @@ -3637,6 +3649,22 @@ MAIN: exit 2; } + # + # try exclusive lock if set in config or command-line option + # + $lockfile //= config_key($config, "lockfile"); + if(defined($lockfile) && (not $dryrun)) { + unless(open(LOCKFILE, ">>$lockfile")) { + # NOTE: the lockfile is never deleted by design + ERROR "Failed to open lock file '$lockfile': $!"; + exit 3; + } + unless(flock(LOCKFILE, 6)) { # exclusive, non-blocking (LOCK_EX | LOCK_NB) + ERROR "Failed to take lock (another btrbk instance is running): $lockfile"; + exit 3; + } + } + if($action_archive) { diff --git a/btrbk.conf.example b/btrbk.conf.example index 82e50bd..1977f92 100644 --- a/btrbk.conf.example +++ b/btrbk.conf.example @@ -56,6 +56,10 @@ snapshot_dir _btrbk_snap #ssh_compression no #ssh_cipher_spec default +# Enable lock file support: Ensures that only one instance of btrbk +# can be run at a time. +#lockfile /var/lock/btrbk.lock + # Don't wait for transaction commit on deletion. Set this to "after" # or "each" to make sure the deletion of subvolumes is committed to # disk when btrbk terminates. diff --git a/contrib/cron/btrbk-mail b/contrib/cron/btrbk-mail index dc1c629..60c940d 100755 --- a/contrib/cron/btrbk-mail +++ b/contrib/cron/btrbk-mail @@ -111,6 +111,8 @@ exitcode=$? case $exitcode in 0) status="All backups successful" ;; + 3) status="Another instance of btrbk is running, no backup tasks performed!" + ;; 10) status="ERROR: At least one backup task aborted!" ;; *) status="ERROR: btrbk failed with error code $exitcode" diff --git a/doc/btrbk.1 b/doc/btrbk.1 index dbfd064..6b2274b 100644 --- a/doc/btrbk.1 +++ b/doc/btrbk.1 @@ -1,4 +1,4 @@ -.TH "btrbk" "1" "2016-05-03" "btrbk v0.23.1" "" +.TH "btrbk" "1" "2016-06-07" "btrbk v0.23.2-dev" "" .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) @@ -118,6 +118,14 @@ between different output formats. Override a configuration option with . Globally, for ALL contexts. Use with care! .RE +.PP +\-\-lockfile +.RS 4 +Create lockfile on startup; checks lockfile before running any +btrfs commands (using perl "flock"), and exits if the lock is held by +another btrbk instance. Overrides configuration option +"lockfile". Ignored on dryrun (\fI\-n\fR, \fI\-\-dry\-run\fR). +.RE .SH COMMANDS .PP .B run @@ -324,6 +332,8 @@ No problems occurred. Generic error code. .IP "2" 4 Parse error: when parsing command-line options or configuration file. +.IP "3" 4 +Lockfile error: if lockfile is present on startup. .IP "10" 4 Backup abort: At least one backup task aborted. .IP "255" 4 diff --git a/doc/btrbk.conf.5 b/doc/btrbk.conf.5 index 02be036..f7b8b1d 100644 --- a/doc/btrbk.conf.5 +++ b/doc/btrbk.conf.5 @@ -1,4 +1,4 @@ -.TH "btrbk.conf" "5" "2016-05-03" "btrbk v0.23.1" "" +.TH "btrbk.conf" "5" "2016-06-07" "btrbk v0.23.2-dev" "" .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) @@ -231,6 +231,14 @@ suffix of "k", "m", "g", or "t" can be added to denote kilobytes (*1024), megabytes, and so on. Defaults to \[lq]no\[rq]. .RE .PP +\fBlockfile\fR +.RS 4 +Create lockfile on startup; checks lockfile before running any +btrfs commands (using perl "flock"), and exits if the lock is held by +another btrbk instance. Ignored on dryrun (\fI\-n\fR, +\fI\-\-dry\-run\fR). See also \fI\-\-lockfile\fR command-line option. +.RE +.PP \fBbtrfs_commit_delete\fR after|each|no .RS 4 If set, make sure the deletion of snapshot and backup subvolumes are