Compare commits

...

287 Commits

Author SHA1 Message Date
Axel Burri ba3c36c984 btrbk: fix duplicate cmdline option -l in lsbtr 2025-07-06 01:09:14 +02:00
Axel Burri c69f70e1d0 btrbk: fix loglevel along with verbose 2025-07-06 00:56:29 +02:00
Axel Burri 18ddc65979 documentation: fix stream_compress_adapt 2023-08-28 19:14:35 +02:00
Axel Burri 225f60f565 btrbk: remove handling of deprecated options before v0.23
After 7 years and a lot of warnings we can drop this code. Note that
most of those refer to `upgrade_to_v0.23.0.md`, which was removed in
16364e2.
2023-08-28 18:55:47 +02:00
Axel Burri f7e1265e7a documentation: remove upgrade_to_v0.23.0.md from Makefile
Forgotten after removal in:

   16364e2833 documentation: remove obsolete upgrade_to_v0.23.0.md
2023-08-28 18:42:42 +02:00
Axel Burri a4d4dff0d1 btrbk_restore_raw.py: fix spelling 2023-08-05 20:56:39 +02:00
Axel Burri d819f17e44 kdf_pbkdf2.py: fix spelling 2023-08-05 20:56:39 +02:00
Axel Burri 1807ad5cee btrbk-mail: fix spelling 2023-08-05 20:56:39 +02:00
Axel Burri b139875e2b btrbk: fix spelling 2023-08-05 20:56:39 +02:00
Axel Burri f6bdab143b documentation: fix spelling 2023-08-05 20:56:39 +02:00
Axel Burri 16364e2833 documentation: remove obsolete upgrade_to_v0.23.0.md 2023-08-05 20:56:34 +02:00
Axel Burri efa4d13111 ChangeLog: fix spelling 2023-08-05 20:56:34 +02:00
Yaroslav Halchenko dac6350b5d github: actions: add codespell master on push and PRs 2023-08-05 20:28:41 +02:00
oldherl a488096869 doc: README.md: fix typo 2023-07-14 19:40:18 +02:00
Sam James 9dfee7bc32 doc: allow asciidoc again
This effectively reverts 0e63843195 and
173319e7e1.

asciidoc has been revived (for a while now) and doesn't require Python 2. We
still prefer asciidoctor and fallback to asciidoc/a2x if it's not available.

Comparing the asciidoc and asciidoctor man pages, everything looks OK.

Python tends to be available more readily in distribution build environments
rather than the Ruby stack. Also, the pregenerated man pages are gone as of
f132c94c65.

Signed-off-by: Sam James <sam@gentoo.org>
2023-07-14 18:55:05 +02:00
Axel Burri db45f0b09c btrbk-mail: add example to enable all rsync 2023-07-07 01:53:15 +02:00
Axel Burri fa704c3185 btrbk-mail: add missing declare 2023-07-07 01:45:32 +02:00
Axel Burri b63609c298 btrbk-mail: declare associative arrays 2023-06-08 00:27:16 +02:00
Axel Burri 98580418e3 btrbk: fix displaying excluded in summary
- fix framework
 - print source excluded by archive_exclude in summary
 - fix exclude list in summary
2023-04-22 16:53:13 +02:00
Axel Burri 135edabc71 btrbk: rephrase warnings on unexpected (foreign) location 2023-04-22 16:51:32 +02:00
Axel Burri 4ba944e6a5 btrbk: fix exit status for action usage 2023-04-22 16:51:32 +02:00
Axel Burri dd7149b111 btrbk: improve error message 2023-04-22 16:51:32 +02:00
Axel Burri ed33db523c btrbk: add reason text to filter statements 2023-04-22 16:51:32 +02:00
Axel Burri 15a6b98a08 btrbk: print "create" action in schedule 2023-04-22 16:51:32 +02:00
Axel Burri eff9af34bc btrbk: fix print schedule if deletion is skipped
If deletion is skipped, we don't have a schedule call on the target,
which is used for --print-schedule text. Add some (rather hacky) code
to be able to also use the schedule result of the backup process.
2023-04-22 16:51:32 +02:00
Axel Burri 468ca1eae5 btrbk: tidy logging
Especially corrects $svol->{PRINT} where not applicable.
2023-04-22 16:51:32 +02:00
Axel Burri cca200707d btrbk: set subvolume url to /dev/null on archive
This should not be printed anywhere. If it is, it's a bug.
2023-04-22 16:51:32 +02:00
Axel Burri d4ab986245 btrbk: skip subvolume init on archive 2023-04-22 16:51:32 +02:00
Axel Burri 6f1145c279 btrbk: add archive related summary
Note that "no target action" for archive is replaced by "<no_action>",
for consistency with action run:

   [-] /path/to/target/snapshot_basename.*

is now displayed as:

   <no_action>
2023-04-22 16:51:32 +02:00
Axel Burri 6d047cbaec btrbk: disable target_create_dir for user; fix dryrun 2023-04-22 16:51:32 +02:00
Axel Burri e737927bd9 btrbk: tidy variable names 2023-04-22 16:51:32 +02:00
Axel Burri 053cd7a59c btrbk: use parser function for assembling archive config 2023-04-22 16:51:32 +02:00
Axel Burri 443cb1891b btrbk: action_archive: no strict_related parent search
strict_related parent search does not make much sense on archive: on
targets, parent_uuid chain is broken after first prune.

Ref: 318126b831
2023-04-22 16:51:32 +02:00
Axel Burri ac0f7e3b91 btrbk: action_archive: honor archive_exclude_older in backup step 2023-04-22 16:51:32 +02:00
Axel Burri d12241fcfc btrbk: action_archive: use correct config_preserve_hash 2023-04-22 16:51:32 +02:00
Axel Burri 1465a1ecc2 btrbk: use same code for backup and archive
Note that some functionality breaks with this commit. Specific
adaptions are done in following commits.
2023-04-22 16:51:32 +02:00
Axel Burri c385b0b731 btrbk: create dir if target_create_dir is set 2023-04-22 16:51:32 +02:00
Axel Burri 7aece45dbf btrbk: add vinfo_mkdir 2023-04-22 16:51:32 +02:00
Axel Burri 2bdd5eb8fc btrbk: use vinfo_realpath 2023-04-22 16:51:32 +02:00
Axel Burri 30b22d49d2 btrbk: add vinfo_realpath 2023-04-22 16:51:32 +02:00
Axel Burri 544d95e094 btrbk: add comment 2023-04-22 16:51:32 +02:00
Axel Burri fe137bd19c btrbk: honor --exclude on delete 2023-04-22 16:51:32 +02:00
Axel Burri 6d57aa4dbe documentation: honor --exclude on backup candidates 2023-04-22 16:51:32 +02:00
Axel Burri 4c174c8f72 btrbk: honor --exclude on backup candidates 2023-04-22 16:51:32 +02:00
Axel Burri c0da910276 btrbk: on resume, abort on unexpected if receive target is not present
A more sophisticated implementation would be to check this after
scheduling, only if the target really needs to be backuped.

We could as well automatically trigger a `btrfs snapshot -r` on target
in these cases, but this seems counter-intuitive.
2023-04-22 16:51:32 +02:00
Axel Burri d498dbb5c3 btrbk: list unexpected archive targets when aborting 2023-04-22 16:51:32 +02:00
Axel Burri 61691abbfc documentation: update deletion of raw targets 2023-04-22 16:51:32 +02:00
Axel Burri c4bf7b0c5a btrbk: use depends callback for raw depends 2023-04-22 16:51:32 +02:00
Axel Burri 6373e32875 btrbk: add depends callback to scheduler 2023-04-22 16:51:32 +02:00
Axel Burri 2a1a42e824 btrbk: related_nodes: add fatal option 2023-04-22 16:51:32 +02:00
Axel Burri e93952b08b btrbk: related_nodes: return reference instead of array
Preparatory for adding fatal option returning undef.
2023-04-22 16:51:32 +02:00
Axel Burri 131e75376f btrbk: fix raw parent_uuid 2023-04-22 16:51:32 +02:00
Axel Burri b77abb3eff btrbk: abort if cmdline specified config not found 2023-04-22 16:51:32 +02:00
Axel Burri 799d235218 btrbk: remove double-slash from file arguments
Sanitize file (or subvolume path) arguments in safe_cmd, effectively
removing leading double slash.

Files originating from "volume /" can be assembled as "//some/subvol",
which is useful internally but undesired as command arguments, as
ancient systems might interpret leading double slash "//" in a special
way.

Posix states:

> A pathname that begins with two successive slashes may be
> interpreted in an implementation-defined manner, although more than
> two leading slashes shall be treated as a single slash.
2023-04-22 16:51:32 +02:00
Axel Burri b9c5e3fc29 btrbk: bump version to 0.33.0-dev 2023-04-22 16:51:32 +02:00
Axel Burri 73c5d180f6 documentation: rephrase lockfile 2023-04-22 16:51:32 +02:00
Axel Burri ac42b29b0a bump copyright year 2023-04-10 16:04:27 +02:00
Axel Burri 5e44bc6a3e change version to 0.32.6; update Changelog 2023-03-25 17:19:14 +01:00
Christoph Anton Mitterer 7adb32c7e9 ssh_filter_btrbk.sh: further harden the shell execution environment
• In principle the special `IFS`-variable could be set to some unexpected non-
  standard value.
  Unsetting it causes its default to be used.
• Locales and in particular their characters sets are quite complex in POSIX and
  may have many subtle implications.
  For example, the pattern matching notation (used in `case`-compound-commands
  or some forms of parameter expansion) are in principle only defined for
  character strings. While some shells handle it gracefully, the behaviour is
  undefined if, for example, the character set is UTF-8 and a variable contains
  bytes that do not form valid caracters in that.
  Actually, there are quite some more implications.

  Also, pathnames, in POSIX, are strings of bytes excluding 0x0.

  For these reasons, the locale is set to the `C`/`POSIX`-locale.

Signed-off-by: Christoph Anton Mitterer <mail@christoph.anton.mitterer.name>
2023-03-25 16:02:04 +01:00
Christoph Anton Mitterer 5b8c1f8f7a ssh_filter_btrbk.sh: minor improvements
• Set shell options in one command.
• Homogeneously use local variables for function positional parameters in all
  places.
• In redirections, omit `1` for standard output.
• Homogeneously use `if`-compount-commands instead of `[ … ] && …` in all
  places.
• Homogeneously use curly brackets with parameter expansion.

Signed-off-by: Christoph Anton Mitterer <mail@christoph.anton.mitterer.name>
2023-03-25 16:02:04 +01:00
Christoph Anton Mitterer b274bd1d50 ssh_filter_btrbk.sh: replace OpenSSH’s deprecated SSH_CLIENT
OpenSSH’s environment variable `SSH_CLIENT` has been deprecated in upstream
commit f37e246f858cdd79be4f4e158b7b04778d1cb7e9 (2002-09-19) and replaced by
`SSH_CONNECTION`.

Both contain more than just the remote information, thus adapted the log message
to reflect that.

Since this might be used by 3rd-party programs (like fail2ban), added a specific
note to the changelog.

Signed-off-by: Christoph Anton Mitterer <mail@christoph.anton.mitterer.name>
2023-03-25 16:02:04 +01:00
Christoph Anton Mitterer ee5a543e0b ssh_filter_btrbk.sh: use printf instead of echo
In spirit, POSIX considers `echo` rather obsolete (it was just kept because of
its widespread use).

It’s also not possible to use `echo` portably unless it’s `-n`-option (as the
first argument) and escape sequences are omitted.
While neither was the case here, it’s better style to just always use `printf`
in order to avoid any future confusion when both are used.

Signed-off-by: Christoph Anton Mitterer <mail@christoph.anton.mitterer.name>
2023-03-25 16:02:04 +01:00
Christoph Anton Mitterer ddc9b810de ssh_filter_btrbk.sh: convert to POSIX sh
This commit finishes the work from the previous one and converts
ssh_filter_btrbk.sh to (mostly) pure POSIX Shell Command Language.

Instead of bash’s `=~`-operator for its `[[ … ]]`-compound-command it uses
`grep`.
At the time of writing, bash has at least the `nocasematch`-shell-option which
would have a negatve security impact for this program. While it’s not enabled
per default single users could potentially change that, not realising the
consequences.
Thus, moving away from this may also provide some hardening.

Unlike bash’s `=~`-operator, which matches against the whole string at once,
`grep` matches the pattern against each line of input.
This would allow for attacks by including a newline in the SSH command like in:
    SSH_ORIGINAL_COMMAND="readlink /dev/stdout
    cat /etc/shadow"
but is prevented by the general exclusion of newlines in commit TODO.

`grep` may return an exit status of `0` when used with its `-q`-option, even
when an error occurred.
Since this program is intended specifically for security purposes this shall be
avoided, even if such case is unlikely, and therefore its standard output and
standard error are redirected to `/dev/null` instead.

Further, using just:
    local formatted_restrict_path_list="$(printf '%s' "$restrict_path_list" | sed 's/|/", "/g')"
rather than:
    local formatted_restrict_path_list=""; formatted_restrict_path_list="$(printf '%s' "$restrict_path_list" | sed 's/|/", "/g')"
prevent `set -e` to take effect if the pipeline within the command substitution
fails, as the returned exit status of the whole command is the result of
`local`, not that of the assignment.
This is however no security problem here, as `formatted_restrict_path_list` is
only used for informative pruposes.

Signed-off-by: Christoph Anton Mitterer <mail@christoph.anton.mitterer.name>
2023-03-25 16:02:04 +01:00
Christoph Anton Mitterer ac1fd38beb ssh_filter_btrbk.sh: remove unnecessary bashishms
ssh_filter_btrbk.sh is mainly intended for security purposes and should
therefore itself be written with that in mind.
It is written for bash, which greatly extends the POSIX Shell Command Language
and is incompatible with it in some niche cases.

For several reasons, it seems a good idea to convert the program to (mostly)
pure POSIX Shell Command Language:
• People may try to use the program with other shells (for example when bash is
  not available) and make errors.
More pure `sh` implementations like dash …
• … have far less code and also less dependencies, which possibly also reduces
  the chance for bugs or exploits,
• … are less dynamic in development (and have thus possibly a lower chance of
 incompatible changes) …
• … and may run faster.

This commit replaces any unnecessary “bashishms” with purely POSIX compatible
code, with the exception of the `local`-built-in, which is however supported by
most POSIX compatible shells (including dash, klibc-utils’s `sh` and BusyBox’
`sh`) in some way.

Signed-off-by: Christoph Anton Mitterer <mail@christoph.anton.mitterer.name>
2023-03-25 16:02:04 +01:00
Christoph Anton Mitterer 5d79c012c4 ssh_filter_btrbk.sh: double quote variables expansions
Double quote any variable expansions that might ever contain field separators.

Signed-off-by: Christoph Anton Mitterer <mail@christoph.anton.mitterer.name>
2023-03-25 16:02:04 +01:00
Christoph Anton Mitterer 1980c1d939 ssh_filter_btrbk.sh: use single quotes where possible
In strings that don’t contain `'` nor do any expansions, use single quotes to
avoid any future unintended expansions or escapes.

Signed-off-by: Christoph Anton Mitterer <mail@christoph.anton.mitterer.name>
2023-03-25 16:02:04 +01:00
Axel Burri a75765cc9a btrbk: process all snapshots in snapdir (not only related ones) 2022-12-04 01:46:31 +01:00
Axel Burri 335e19e238 btrbk: allow quotes for all config values
Regression of:

   9d217857 btrbk: fix parsing of quoted "target" config line
2022-12-04 00:50:21 +01:00
Axel Burri f107507876 documentation: install add quick wget example in install 2022-12-03 12:10:05 +01:00
Axel Burri 1477fe5181 documentation: install: mention asciidoctor 2022-12-03 12:10:05 +01:00
Axel Burri 91b29ce32c documentation: install: fix broken link to fedora rpms 2022-12-03 12:10:05 +01:00
Axel Burri 6b95250b84 documentation: install: move gentoo down
Trying to more or less sort by popularity / relevance.
Sadly Gentoo is not on the top list any more these days.
2022-12-03 12:10:05 +01:00
Christoph Anton Mitterer 36d6ba7d07 ssh_filter_btrbk.sh: disallow newlines in the SSH command
This disallows newline (that is: LF characters) in the SSH command, which could
have been exploited for arbitrary code execution, since commit
77a39282de.

Example:
    # export SSH_ORIGINAL_COMMAND=$'readlink /dev/stdout\ncat /etc/shadow'
    # ssh_filter_btrbk.sh

Since `readlink` is a generally allowed command, this works with any of
ssh_filter_btrbk.sh’s options.
But most likely, other commands that are “added” via `allow_cmd()` can be used,
too.

Signed-off-by: Christoph Anton Mitterer <mail@christoph.anton.mitterer.name>

# Please enter the commit message for your changes. Lines starting
# with '#' will be kept; you may remove them yourself if you want to.
# An empty message aborts the commit.
#
# Date:      Wed Nov 30 04:29:53 2022 +0100
#
# On branch fix-remote-code-execution
# Your branch and 'origin/fix-remote-code-execution' have diverged,
# and have 1 and 1 different commits each, respectively.
#   (use "git pull" to merge the remote branch into yours)
#
# Changes to be committed:
#	modified:   ssh_filter_btrbk.sh
#
# Untracked files:
#	ORIG
#
2022-12-02 01:43:29 +01:00
Axel Burri fa7ef1bf63 documentation: ssh_filter_btrbk: add note on --restrict-path 2022-11-21 13:10:42 +01:00
Axel Burri f9c7a47b6a btrbk: use substitutions in printf
Avoid possible interpreted sequence from values (e.g. from FILE).
2022-11-20 15:57:25 +01:00
Axel Burri b800d1bb10 btrbk: strict input validation from kdf backend 2022-11-20 15:49:31 +01:00
Axel Burri a622fded5a btrbk: strict input validation from raw sidecar 2022-11-20 12:29:54 +01:00
Axel Burri f8280f591f btrbk: ignore redundand FILE from raw sidecar
If present, check against name calculated from raw info file name.
2022-11-20 11:19:49 +01:00
Axel Burri 7ad4ebe0af btrbk: make safe_commands more restrictive 2022-11-20 11:19:14 +01:00
Axel Burri 7a4a54db97 btrbk: disallow newline in files
While most functionality works fine, raw backups fail to write correct
"FILE=" information in info sidecar.

Disallowing newlines in files is a good idea in general.
2022-11-20 02:40:15 +01:00
Axel Burri 87ed9ffeb5 btrbk: improve raw sidecar files parsing 2022-11-20 02:40:15 +01:00
Axel Burri 9d0468070d btrbk-verify: do not use echo -e 2022-11-20 00:09:50 +01:00
Axel Burri 65886f10fd btrbk-mail: do not use echo -e 2022-11-20 00:09:32 +01:00
Axel Burri f52de197d6 btrbk: use printf instead of echo
Posix echo does not know about -e, -n flags, use printf instead.
2022-11-16 02:31:13 +01:00
Axel Burri 5c561d8c14 documentation: tidy --dry-run, --print-schedule examples 2022-11-16 01:37:12 +01:00
Axel Burri 125b37468a btrbk: tidy comments 2022-11-16 00:45:39 +01:00
Christoph Anton Mitterer 914f9286c7 btrbk: add bzip3 compression
This adds support for bzip3 [1].

 [1] https://github.com/kspalaiologos/bzip3

Signed-off-by: Christoph Anton Mitterer <mail@christoph.anton.mitterer.name>

Cosmetics: swap order pbzip2 / bzip3

Signed-off-by: Axel Burri <axel@tty0.ch>
2022-11-16 00:45:39 +01:00
Axel Burri af86dc8c52 btrbk: allow compressors not to have a compression level
Not all compressors support compression level (option `-#`): print a
warning if compress_level is set, and ignore its value for such
compressors.
2022-11-16 00:44:53 +01:00
Christoph Anton Mitterer af2d7b2c99 documentation: use "example.org" in examples
`mydomain.com` is actually a real domain and shouln’t be used in examples.

RFC 2606 (respectively RFC 6761) reserves `example.org` (and others) for that
purpose.

Signed-off-by: Christoph Anton Mitterer <mail@christoph.anton.mitterer.name>
2022-11-12 15:19:24 +01:00
Christoph Anton Mitterer 1287547df0 documentation: use "restrict" in authorized_keys for further hardening
Since `btrbk` executes only commands, it shouldn’t need any of what’s currently
disabled with the `restrict` flag in the `authorized_keys` file, that is:
Port-, agent- and X11-forwarding as well as PTY allocation and execution of
`~/.ssh/rc`.

Signed-off-by: Christoph Anton Mitterer <mail@christoph.anton.mitterer.name>
2022-11-12 15:17:28 +01:00
Axel Burri 9166d73be7 documentation: add send_protocol, send_compressed_data 2022-10-30 17:08:06 +01:00
Axel Burri cc08cef27c btrbk: add send_protocol and send_compressed_data config options
support btrfs send protocol v2
2022-10-30 17:08:06 +01:00
Axel Burri 1f7aa7e247 btrbk: unify btrfs send options 2022-10-30 17:08:06 +01:00
Axel Burri af4681319c btrbk: bump version to 0.32.6-dev 2022-10-30 17:08:05 +01:00
Axel Burri 58fffab405 change version to 0.32.5; update Changelog 2022-10-23 12:37:28 +02:00
Axel Burri dcee6222be btrbk: append to info file instead of rewriting
A redirection (e.g. `echo foo > bar.info`) can cause empty (zero-size)
files in some circumstances.

We still write INCOMPLETE=1 to the info file before send/receive, but
instead of re-creating it without the INCOMPLETE flag, we append
INCOMPLETE=0 (keeping up compatibility with old versions of btrbk).

Ref: 4e5ae975d8 btrbk: ignore zero-size info files
2022-10-19 11:38:11 +02:00
Axel Burri 51b2a5a9f5 btrbk: tidy comments 2022-10-19 11:38:11 +02:00
Axel Burri 25c8eb1705 btrbk: add timestamp to info file on write 2022-10-19 11:38:11 +02:00
Axel Burri 08cb900a9e btrbk: add append option to system_write_raw_info 2022-10-19 11:38:11 +02:00
Axel Burri 89c0aa31d7 btrbk: tidy raw info file parsing 2022-10-19 11:37:45 +02:00
Axel Burri d6910e43ea btrbk: add append_to_file option in run_cmd 2022-10-19 11:33:40 +02:00
Matthieu Patou 4e5ae975d8 btrbk: ignore zero-size info files
When backuping from devices that have configured to use raw backup and
that might disconnect from the network (ie. laptops) you end up once in
a while with 0 size info file (and backup file).
btrbk don't know how to handle 0 file and stop backing up until the zero
size file is removed.
With this change 0 size info file will be ignored, and hence the backup
for the given backup will be redone.

Signed-off-by: Matthieu Patou <mat@matws.net>
2022-10-18 11:46:32 +02:00
Axel Burri f77a33b340 btrbk: bump version to 0.32.5-dev 2022-10-18 11:08:31 +02:00
Axel Burri 6877825708 change version to 0.32.4; update Changelog 2022-08-20 14:26:36 +02:00
Axel Burri 116aface3c btrbk: fix regression: wrong deprecation warnings
Warning for btrfs_commit_delete is always printed, regardless of the
(possibly valid) values.

regression in btrbk-0.32.3

   687e0508b7 btrbk: tidy deprecation warnings
2022-08-20 14:24:17 +02:00
Axel Burri 411034e93f change version to 0.32.3; update Changelog 2022-08-07 11:04:39 +02:00
xskoak 3149aa9e10 btrbk.conf.example: fix spelling 2022-07-28 13:59:01 +02:00
Axel Burri 79b6a662f2 btrbk: fix missing error in action "ls" 2022-07-28 13:44:42 +02:00
Axel Burri cf2065df30 btrbk: hint missing ssh_identity on errors
It is perfectly ok to run btrbk without ssh_identity (using ssh
defaults), printing a warning if the option is not set is wrong.
Instead, hackily check for ssh_identity on ssh errors, and give a hint
in the error message.
2022-07-28 13:44:37 +02:00
Axel Burri 67020797ff btrbk.conf.example: tidy ssh_identity, add backend_local_user 2022-07-28 13:02:22 +02:00
Axel Burri a5dd4dd7b9 btrbk.conf.example: add local user on demand with ssh-agent 2022-07-28 13:01:56 +02:00
Axel Burri 19727e913b documentation: drop deprecation notice
gt 2 years, deprecated since v0.28.0
2022-07-28 12:18:04 +02:00
Axel Burri 588fc7faa8 documentation: tidy man reference 2022-07-28 12:18:04 +02:00
Axel Burri dc7b11653d documentation: adapt ssh_identity and ssh_user option
also mention ssh-agent for ssh_identity option.
2022-07-28 12:17:16 +02:00
Axel Burri 2621fb38ba btrbk: allow ssh_user=no 2022-07-28 12:10:06 +02:00
Axel Burri dd638ec9f4 btrbk: allow ssh_identity=no 2022-07-28 12:06:22 +02:00
Axel Burri f467de6c19 btrbk.conf.example: adapt btrfs_commit_delete 2022-07-28 12:06:22 +02:00
Axel Burri c5dff6afda documentation: adapt btrfs_commit_delete
Also move item down, closer to other delete-related options.
2022-07-27 20:41:59 +02:00
Axel Burri 6b465bf06b btrbk: never delete multiple subvolumes at once
Deleting multiple subvolumes at once always caused the problem that we
need to parse stderr of "rm" and "btrfs subvolume delete" in order to
know which subvolume actually failed, which is problematic (version
dependent, language dependent). Also, we would need to restrict the
number of subvolumes based on the maximum allowed length for shell
commands, which is system-dependent (check `getconf ARG_MAX`).

Deleting subvolumes sequentially has slightly negative impact on
execution time (multiple rsh commands), with the benefit of being more
robust and reducing the codesize.
2022-07-27 20:41:25 +02:00
Axel Burri b7df717611 btrbk: hide only fully deprecated keys when dumping 2022-07-27 18:36:20 +02:00
Axel Burri 687e0508b7 btrbk: tidy deprecation warnings 2022-07-27 18:20:33 +02:00
Axel Burri c5cb919f6c btrbk: tidy log functions 2022-07-27 18:19:46 +02:00
Axel Burri 805ab93fef btrbk: fix function argument
Does not trigger a bug in current program logic.

Ref: 3ea7746700 btrbk: cosmetics: separate get_btrbk_date function
2022-07-27 14:35:24 +02:00
Axel Burri 43a125d4e1 btrbk: bump version to 0.32.3-dev 2022-07-27 14:35:15 +02:00
Axel Burri bdc1f5caba change version to 0.32.2; update Changelog 2022-06-25 18:52:11 +02:00
Axel Burri 054146ac00 btrbk: keep quotes intact when removing comments in config 2022-06-06 22:00:46 +02:00
Axel Burri 9d21785778 btrbk: fix parsing of quoted "target" config line
Quotes were removed before passing value to parse_config_line,
resulting in failuer of parsing target url if quoted.
2022-06-06 21:59:11 +02:00
Axel Burri fb13848faf btrbk: tidy function prototype 2022-06-06 21:02:13 +02:00
Axel Burri f169456613 btrbk: tidy logging 2022-06-06 18:31:45 +02:00
Axel Burri a062f42344 documentation: allow multiple gpg_recipient 2022-05-29 21:44:11 +02:00
Axel Burri a70248376f btrbk: use no-default-recipient on gpg encrypt
In case the user has set a default recipient in his gpg config file,
ignore it.
2022-05-29 21:34:43 +02:00
Steven Brudenell b824d62449 btrbk: support multiple gpg recipients 2022-05-29 21:34:43 +02:00
Asbjørn Apeland b618c2dd90 contrib: bash: completion.bash: complete options without =
Currently, option arguments are only completed after =. For example:

	$ btrbk --loglevel=<TAB>
	debug  error  info   trace  warn
	$ btrbk --loglevel <TAB>
	archive   diff      extents   ls        prune     run
	stats     clean     dryrun    list      origin    resume
	snapshot  usage

This commit makes it so that both option styles are recognized:

	$ btrbk --loglevel=<TAB>
	debug  error  info   trace  warn
	$ btrbk --loglevel <TAB>
	debug  error  info   trace  warn

This was the intention all along, but it was implemented incorrectly.
2022-05-29 18:03:36 +02:00
Merlin Büge a8a5051f79 documentation: README.md: replace "resume" with "robust recovery"
There was some confusion about it, see the discussion in
https://github.com/digint/btrbk/issues/196
2022-05-29 17:45:10 +02:00
Merlin Büge 1d4a502ee3 documentation: fix small typos and rephrase some parts 2022-05-29 17:21:29 +02:00
Axel Burri 0b41942251 github: add FUNDING.yml 2022-05-29 16:21:38 +02:00
Axel Burri 9e32df5f90 documentaion: README.md: rephrase donate section 2022-05-29 16:02:00 +02:00
Axel Burri eadeb89232 btrbk: check results of btrfs filesystem usage 2022-05-29 14:32:27 +02:00
Axel Burri 691885e6b8 documentation: add compat=ignore_receive_errors option 2022-05-29 13:53:56 +02:00
Axel Burri b8464119f6 btrbk: add compat=ignore_receive_errors option 2022-05-29 12:29:19 +02:00
Axel Burri 023d75f7a5 documentation: cosmetics 2022-05-29 12:29:16 +02:00
Axel Burri 619403c9ad documentation: fix action "config print" 2022-05-29 12:29:13 +02:00
Axel Burri 527d1bf74f btrbk: improve action "config print"
- honor overrides
 - print unset lines as comments
 - skip lines on forbidden context
 - fix values "no" and "<unset>"
2022-05-29 12:26:37 +02:00
Axel Burri f187d6f6ee btrbk: tidy formatting 2022-05-29 12:26:37 +02:00
Axel Burri 321f3783d5 btrbk: use split in ssh_cipher_spec config definition 2022-05-29 12:21:39 +02:00
Axel Burri ce2afb427d btrbk: split all config values with same regex 2022-05-28 21:28:42 +02:00
Axel Burri ba3ee70d38 btrbk: tidy config options definition 2022-05-28 21:28:39 +02:00
Axel Burri 823419d510 btrbk: tidy config options parser
- handle regex within accept list
 - handle numeric as regex
 - split before checking accept
2022-05-28 21:27:39 +02:00
Axel Burri 90c5d119f6 documentation: clarify btrfs_commit_delete 2022-05-27 20:14:02 +02:00
Axel Burri 267cbcacdc documentation: clarify filter statement match multiple times 2022-05-27 19:31:48 +02:00
Axel Burri 04e0695429 btrbk: tidy logging 2022-05-27 19:31:48 +02:00
Axel Burri 12f608d828 btrbk: fix regression: clear realpath cache on mkdir
On btrbk archive, after creating a directory without dry-run, the
archive target is skipped with "Failed to fetch subvolume detail" due
to caching of realpath.

Regression in btrbk-0.32.0:

    eb69bc883e btrbk: refactor mountinfo
2022-05-27 19:31:48 +02:00
Axel Burri 4fcbbad802 btrbk: print version and help to stdout 2022-03-25 15:20:20 +01:00
Axel Burri be07f1908a btrbk: print shorter error help message 2022-03-25 15:20:14 +01:00
Axel Burri fc49abbbf8 btrbk: bump version to 0.32.2-dev 2022-03-25 15:19:59 +01:00
Axel Burri 593fa6b254 change version to 0.32.1; update Changelog 2022-02-26 18:35:09 +01:00
Axel Burri d9b9f20899 bump copyright year 2022-02-26 18:35:02 +01:00
Axel Burri 795418ebe1 btrbk.conf.example: remove timestamp_format
Now that timestamp_format defaults to "long", it seems no longer
needed to even mention it here. Setting to "short" or "long-iso" is
only required in rather special use cases.
2022-02-26 18:11:09 +01:00
Axel Burri 671df969a1 documentation: rephrase timestamp_format notes on preserve_hour_of_day 2022-02-26 18:11:09 +01:00
Axel Burri 047d3a1a65 btrbk: allow directory traversal for subvol_args 2022-02-26 18:11:09 +01:00
Axel Burri a25486336b btrbk: fix regression: filter paths for action "ls"
regression from: eb69bc883e btrbk: refactor mountinfo
2022-02-26 18:11:09 +01:00
Axel Burri ff0a887c32 btrbk: call filesystem usage from mount point 2022-02-22 20:28:23 +01:00
Axel Burri e9fe2cb5f5 btrbk: display all source subvolumes in btrbk usage 2022-02-22 20:28:17 +01:00
Axel Burri 31ce14e4c2 btrbk: handle errors from btrfs filesystem usage
Fix `btrbk usage` unhandled error case if usage data cannot be
retrieved, e.g.:

   ERROR: Failed to fetch btrfs filesystem usage for: example.com:/mnt/btr_pool
   ERROR: ... sh: ssh -i 'XXX' btrbk@example.com 'btrfs-filesystem-usage '\''/mnt/btr_pool'\'''
   ERROR: ... cannot access '/mnt/btr_pool': Permission denied
2022-02-22 20:28:01 +01:00
Axel Burri 0388cf4b2d documentation: add backend btrbk-progs-doas 2022-02-08 01:20:24 +01:00
Axel Burri 177f8547e3 btrbk: add backend btrfs-progs-doas 2022-02-08 01:06:04 +01:00
Axel Burri d3b7540b87 btrbk: tidy backend command map 2022-02-08 01:05:59 +01:00
Axel Burri db7082b4bc btrbk: add config_key_lru comfort function 2022-02-06 17:44:30 +01:00
Axel Burri 68d5fe3f55 btrbk: add match argument in config_key 2022-02-06 17:44:30 +01:00
Axel Burri e6ed21343c btrbk: remove dead code 2022-02-06 16:05:12 +01:00
Axel Burri 0172e4a240 btrbk: fix mountinfo tree root detection
Set node as tree root if mount_id == parent_id. For some reasons this
is never the case on my (mostly gentoo) systems.

Regression from: eb69bc88 btrbk: refactor mountinfo
2022-02-06 12:35:57 +01:00
Axel Burri ed8142ed9d btrbk: bump version to 0.32.1-dev 2022-02-06 12:35:53 +01:00
Axel Burri 8676191d45 change version to 0.32.0; update Changelog 2022-02-05 19:34:54 +01:00
Axel Burri 8cc74fecc1 btrbk: default timestamp_format=long
This is a relict of early days of btrbk, and I have already hesitated
for too long to change the default from legacy "short" to sane "long"
format.

Tests show that the scheduling behaves in a sane/expected way if this
change is applied unattended. I suppose everybody who has
preserve_hour_of_day set is already using timestamp_format=long.
2022-02-05 18:47:49 +01:00
znerol c5273a8745 documentation: fix openssh website URL 2021-11-06 17:24:52 +01:00
Axel Burri ca166d47b6 btrbk: add safe_commands config option
For the paranoid. For convenience, filename checking was removed in
[1], and quoting was (hopefully) implemented correctly in [2].

Allowing special characters as well as UTF8 leave behind a bad
feeling, as there are many special cases that needs to be taken care
of (e.g. newlines in file names, right-to-left encoding, etc.). In
order to mitigate attacks expoiting these error classes, leave an
option to power users which do only allow "sane" characters in their
filename hierarchy.

  [1] 6a29b08f00 btrbk: remove filename restrictions
  [2] acc7f9fc83 btrbk: quote unsafe characters in shell commands
2021-11-06 16:40:47 +01:00
Axel Burri 4f72ad123f btrbk: tidy error message 2021-11-06 16:09:51 +01:00
Axel Burri 2b21d1528c documentation: add "reference time" subsection 2021-11-06 13:50:38 +01:00
Axel Burri ed814aed5a documentation: rephrase retention policy 2021-11-06 13:27:22 +01:00
Axel Burri cb38b7efa4 btrbk: parse additional "btrfs subvolume show" lines from btrfs-progs-5.14.2 2021-10-24 10:39:16 +02:00
Axel Burri c538702d8c btrbk: abort on unexpected only if receive target is not present 2021-10-04 19:17:36 +02:00
Axel Burri 4234fb2965 btrbk-verify: cleanup 2021-09-04 17:15:56 +02:00
Axel Burri d554afab10 btrbk-verify: allow ssh-user without ssh-identity
Required e.g. if a ssh-agent is already running, and we want to set
user=root for rsync.
2021-09-04 16:57:05 +02:00
Axel Burri bef13275d3 btrbk: fix regression: print quoted rsh command in table output
regression from: 27388c7589 btrbk: treat all filenames as unsafe
2021-09-04 15:46:57 +02:00
Axel Burri 1bda5fd978 btrbk: tidy safe_cmd; die if quoting leading dash for command
This should never happen, as all our filenames are checked to be
absolute.
2021-09-04 15:46:09 +02:00
Axel Burri d1247359f8 btrbk: always return abort key 2021-08-28 14:49:12 +02:00
Axel Burri faec607d02 btrbk: drop deprecated -r,--resume-only argument
Deprecated as of btrbk v0.26.0 (more than 3 years ago).
2021-08-28 14:06:10 +02:00
Axel Burri 3f84345bed btrbk: tidy logging 2021-08-28 14:06:10 +02:00
Axel Burri 5dc2375a75 btrbk: fix raw file deletion 2021-08-28 14:06:10 +02:00
Axel Burri 424127441d btrbk: fix unsafe path for btrfs send to file 2021-08-28 14:06:10 +02:00
Axel Burri fe53198661 btrbk: drop support for deprecated raw format
Raw backups created by btrbk < 0.26.0 are now ignored:

   *.btrfs_<received_uuid>[@<parent_uuid>][.gz|bz2|xz][.gpg][.split][.part]
2021-08-28 14:06:02 +02:00
Axel Burri d7653a9e0a documentation: add incremental_prefs; adapt incremental_clones 2021-08-27 17:20:47 +02:00
Axel Burri 85c2d14287 btrbk: change incremental_prefs defaults
New defaults gives the btrbk_direct_leaf snapshots higher preference
than the global ones resolved by parent-uuid (which are best-guess).

This way the parent has a higher chance of being a backup created by
btrbk, which results in "btrfs receive" to start work on a snapshot of
this (and preferably not on the "best-guess" ones).
2021-08-27 17:20:47 +02:00
Axel Burri bde0c10a6c btrbk: add incremental_prefs config option 2021-08-27 17:20:47 +02:00
Axel Burri 6ca00feeb6 btrbk: tidy parent selection
Preparatory for incremental_prefs feature, no functional changes.
2021-08-27 17:20:47 +02:00
Axel Burri 10a6f51730 btrbk: remove deprecation on incremental_clones
btrbk does not set config defaults to global scope for deprecated
keys.
2021-08-27 17:20:47 +02:00
Axel Burri 9f877a4670 btrbk: remove extra clone source, deprecate numeric incremental_clones 2021-08-27 17:20:47 +02:00
Axel Burri 1cb958ee30 btrbk: add "match" target for deprecated options 2021-08-27 17:20:39 +02:00
Axel Burri ad6298bf37 btrbk: add global split_match (cosmetics) 2021-08-19 17:16:50 +02:00
Axel Burri eb69bc883e btrbk: refactor mountinfo
- Create tree from /proc/self/mountinfo, and use it to find mount
  points.

- Populate realpath cache from mount points, possibly reducing calls
  to `realpath`.

- Replace btrfs_mountpoint with vinfo_mountpoint(fs_type => 'btrfs)

- Tidy action "ls".

- Move code
2021-08-18 13:14:10 +02:00
Axel Burri 063c25ad24 btrbk: add sanity checks on mountinfo list 2021-08-18 13:14:10 +02:00
Axel Burri 2556492ec6 documentation: btrbk.conf.5: remove paragraph on filename restrictions 2021-08-18 13:14:10 +02:00
Axel Burri 6a29b08f00 btrbk: remove filename restrictions 2021-08-18 13:14:10 +02:00
Axel Burri b8370de9de documentation: terminate options using double dash "--" 2021-08-18 13:14:10 +02:00
Axel Burri 4b7b7cfc06 documentation: btrbk.1: rephrase --format=raw 2021-08-18 02:08:28 +02:00
Axel Burri af5d25c5a9 btrbk-verify: expect single quotes from btrbk raw table output 2021-08-18 02:08:28 +02:00
Axel Burri 81a04e4287 btrbk: use single quotes for raw table format 2021-08-18 02:08:28 +02:00
Axel Burri 48bf4f05b9 btrbk: fix table output for utf8 characters (require Text::CharWidth)
Use Text::CharWidth::mbswidth() if installed, fallback to
length(Encode::decode_utf8()), fallback to length().

 - Text::CharWidth handles wide chars (e.g. asian, taking up two
   columns on the terminal) correctly.

 - length(Encode::decode_utf8()) handles single-width chars only, and
   should be installed on most systems (perl >= v5.7.3).

 - langth() counts bytes, as we do not convert anything to UTF-8 in
   btrbk (NOT using `perl -CIOEioA` or binmode(STDOUT, ":utf8"))
2021-08-18 02:08:28 +02:00
Axel Burri 94a415e420 btrbk: check/sanitize leading/trailing whitespace on files 2021-08-18 02:08:28 +02:00
Axel Burri 77a39282de ssh_filter_btrbk.sh: allow quoted files 2021-08-18 02:08:28 +02:00
Axel Burri f7d3823d5d ssh_filter_btrbk.sh: fix files are always absolute 2021-08-18 02:08:28 +02:00
Axel Burri 3e9b581a54 btrbk: add --unsafe-filenames option 2021-08-18 02:08:28 +02:00
Axel Burri 1a7bbff767 btrbk: tidy run_cmd calls 2021-08-18 02:08:28 +02:00
Axel Burri 27388c7589 btrbk: treat all filenames as unsafe 2021-08-18 02:08:28 +02:00
Axel Burri 2933e65cbe btrbk: adapt usage of unsafe arguments for run_cmd 2021-08-18 02:08:28 +02:00
Axel Burri acc7f9fc83 btrbk: quote unsafe characters in shell commands
As filenames can contain meta characters like '$', we can't just put
ssh commands in double quotes. E.g. the following would trigger
variable expansion on local shell:

    ssh example.com "ls -l 'evil$x'"

Instead, we quote the ssh using single quotes (adding the need to
escape single quotes), while also quoting unsafe filenames using
single quotes. The above becomes:

    ssh example.com 'ls -l '\''evil$x'\'''

Or more complex, for a file named "file with'single quotes'":

    ssh example.com 'ls -l '\''file with'\''\'\'''\''single quotes'\''\'\'''\'''\'''

On the remote shell, this will expand to:

    ls -l 'file with'\''single quotes'\'''
2021-08-18 02:08:28 +02:00
Axel Burri d7f6d5fecf btrbk: accept quoted values in config 2021-08-18 02:08:28 +02:00
Axel Burri 5d94de9142 btrbk: use File::Spec for relative file arguments 2021-08-18 02:08:28 +02:00
Axel Burri eccb24ecd7 btrbk: fix action "usage"
Regression from:

   b658fba08c btrbk: print snapdir and targets for action "usage"
2021-08-18 02:08:28 +02:00
Axel Burri 3cf69f3537 btrbk: add missing table ralign 2021-08-18 02:08:28 +02:00
Axel Burri 2f88d5ab4c btrbk: check for deleted subvol before panicking 2021-08-18 02:08:28 +02:00
Axel Burri 6e7c8c409b btrbk: cosmetics: fix trace log 2021-08-18 02:08:28 +02:00
Axel Burri 808633a3ae btrbk-verify: remove workarounds for old versions; tidy eval 2021-08-09 19:06:20 +02:00
Axel Burri d9958cbbc1 btrbk-verify: use new raw table format keys 2021-08-09 19:06:20 +02:00
Axel Burri 9278211123 btrbk: fix resolved ambiguity in raw table formats
rename snapshot_path -> snapshot_subvolume
rename target_path   -> target_subvolume

These point to subvolumes, not paths containing subvolumes.
2021-08-09 19:06:20 +02:00
Axel Burri 2347163780 btrbk: table formats: replace source_path with source_subvolume 2021-08-09 19:06:20 +02:00
Axel Burri e6106c3cda documentation: btrbk.conf.5: optional volume section 2021-08-09 19:06:20 +02:00
Axel Burri 9a806d85ef btrbk.conf.example: add simple (non-volume) example; cleanup 2021-08-09 19:06:20 +02:00
Axel Burri 89ea680ce2 documentation: README.md: consequently depict commands with hash 2021-08-09 19:06:20 +02:00
Axel Burri 1eee2c0d2e documentation: README.md: add non-volume examples 2021-08-09 19:06:20 +02:00
Axel Burri b658fba08c btrbk: print snapdir and targets for action "usage" 2021-08-09 19:06:20 +02:00
Axel Burri 7603e03aad btrbk: never match dummy volume section 2021-08-09 19:06:20 +02:00
Axel Burri e1c5fd0029 btrbk: remove superfluous checks on volume 2021-08-09 19:06:20 +02:00
Axel Burri 47ea1f9481 btrbk: fix action "config print" for dummy volume section 2021-08-09 19:06:20 +02:00
Axel Burri e257077241 btrbk: allow subvolume context without volume (add dummy section)
Unfortunately the framework relies on "url" for the volume. This
should not be printed anywhere, using "/dev/null" should be fine.
2021-08-09 19:06:20 +02:00
Axel Burri e2de9de440 btrbk: expand subvolume globs independent of volume 2021-08-09 19:06:20 +02:00
Axel Burri 3b4f275126 btrbk: accept absolute path for subvolume 2021-08-09 19:06:20 +02:00
Axel Burri d40d75ef76 btrbk: accept absolute path for snapshot_dir 2021-08-09 19:06:20 +02:00
Axel Burri 5b2644f12a btrbk: fix check_file: accept both relative and absolute options 2021-08-09 19:06:20 +02:00
Axel Burri d3d04f2252 btrbk: remove subvolume_path from schedule table
This is the only format where SUBVOL_PATH is displayed. As SUBVOL_PATH
is only available for vinfo_child, this can not be used in global
scope.
2021-08-09 19:06:20 +02:00
Axel Burri c1610c754d btrbk: cleanup: add config_subsection 2021-08-09 19:06:20 +02:00
Axel Burri 247cb37acf btrbk: add comment on vinfo_child specific keys 2021-08-09 19:06:20 +02:00
Axel Burri 2d854c7327 btrbk: add comment on clone source from different mount point 2021-08-09 19:06:20 +02:00
Axel Burri 86e902cebc btrbk: remove dead code 2021-08-09 19:06:20 +02:00
Axel Burri ce9c21bd24 btrbk: tidy check for btrbk subvolume
The original idea was probably to have a trace log for skipped
subvols.
2021-08-09 19:06:20 +02:00
Axel Burri f86c563715 btrbk: tidy superfluous subvol_dir argument 2021-08-09 19:06:20 +02:00
Axel Burri 2da30f6b96 btrbk: bump version to 0.32.0-dev 2021-08-09 19:06:20 +02:00
Ingmar Lippert fa3204cd7e documentation: README.md: fix spelling
spelling correction
2021-08-08 20:36:23 +02:00
Axel Burri feba54a68d change version to 0.31.3; update ChangeLog 2021-08-07 00:13:21 +02:00
Axel Burri bddd7a1d69 Makefile: add btrbk_restore_raw.py to script install targets 2021-08-06 23:33:17 +02:00
fr3aker 82860f0f4c btrbk_restore_raw.py: add script for restoring raw backups 2021-08-06 23:33:17 +02:00
ullr23@gmail.com 322ae2c78f btrbk: add support for zstd adaptive compression
Requires zstd version >= 1.3.6
2021-08-06 17:51:20 +02:00
Axel Burri 907a5065ab documentation: add "resume" example; rephrase "ondemand" example 2021-08-06 16:55:53 +02:00
Axel Burri bf0b5997e8 btrbk: allow relative path arg for actions: archive, extents, diff, origin 2021-08-01 14:11:50 +02:00
Axel Burri 16cec0f6d4 btrbk: tidy map relative subvol argument 2021-07-25 13:32:27 +02:00
Axel Burri 2824668c0e btrbk: fix path sanitizer
Sanitize "/././" -> "/"
2021-07-24 14:40:30 +02:00
Axel Burri 2616028326 documentation: README.md: rephrase note on ubuntu @subvol notation 2021-07-17 15:36:59 +02:00
Axel Burri 712910b440 btrbk.conf.example: tidy spacing 2021-07-16 13:20:25 +02:00
Axel Burri 346f08220e btrbk.conf.example: revert to sane non-@subvol notation
We don't want to promote weird naming conventions here.

The idea behind the change in the previous commit [1] was to get rid
of confused people asking me: "hey, I don't have a subvolume for my
rootfs, all I see is @ and @home".

Left an example for "subvolume @" which should be clear to Ubuntu
people out there.

  [1] de6c7ab586 btrbk.conf.example: use @subvol notation
2021-07-16 13:12:03 +02:00
Axel Burri de6c7ab586 btrbk.conf.example: use @subvol notation 2021-07-15 14:51:30 +02:00
Axel Burri ff9e4b5b5f btrbk.conf.example: add timestamp_format 2021-07-15 14:51:30 +02:00
Axel Burri f1a92e4141 btrbk.conf.example: add comments 2021-07-15 14:51:30 +02:00
Axel Burri e110cc3e91 documentation: README.md: mention mandatory mounting of subvolid=5 2021-07-15 14:51:30 +02:00
Axel Burri 5524d16707 btrbk: add warn_unknown_targets config option 2021-07-15 14:11:03 +02:00
Axel Burri 54bb876b85 btrbk: tidy check_file 2021-07-15 14:11:03 +02:00
Axel Burri 47a3aa5849 btrbk: tidy assemble piped command; remove dead code 2021-07-15 14:11:03 +02:00
Axel Burri af6d719acc btrbk: fix: ignore mount points with unsupported filename in action "ls"
Mount points with illegal characters would die in vinfo. Print error
and ignore.
2021-07-15 14:11:03 +02:00
Axel Burri 12f6c5b69f btrbk: tidy mountinfo comments 2021-07-15 14:11:03 +02:00
Axel Burri 6c13a64459 btrbk: fix mountinfo parsing (octal encoded chars)
Making sure this is done after splitting, as encoded value could be a
comma.

After some testing it shows that the kernel [1] produces ambigous
output in "super options" if a subvolume containing a comma is mounted
using "-o subvolid=" (tried hard to mount with "-o subvol=", seems not
possible via shell):

    # btrfs sub create /tmp/btrbk_unittest/mnt_source/svol\,comma
    # mount /dev/loop0 -o subvolid=282 '/tmp/btrbk_unittest/mount,comma'
    # cat /proc/self/mountinfo
    [...]
    48 40 0:319 /svol,comma /tmp/btrbk_unittest/mount,comma rw,relatime - btrfs /dev/loop0 rw,ssd,noacl,space_cache,subvolid=282,subvol=/svol,comma
                                                                                                                                ^^^^^^^^^^^^^^^^^^

  [1] sys-kernel/gentoo-sources-5.10.45
2021-07-15 14:11:03 +02:00
Axel Burri eac9ef9828 btrbk: print non-parseable btrfs mountpoint info only once 2021-07-15 14:11:03 +02:00
Axel Burri db4f96ba65 btrbk: add function INFO_ONCE 2021-07-15 14:10:59 +02:00
Axel Burri f5657bffc0 documentation: add -1,--single-column option 2021-07-15 13:50:11 +02:00
Axel Burri 2c19c501a7 btrbk: add "-1,--single-column" command-line option 2021-07-15 13:50:11 +02:00
Axel Burri e82836be47 btrbk: add single_column output format 2021-07-15 13:50:11 +02:00
Axel Burri c06d94543c btrbk: add "backups" output format
Preparatory for single-column patchset.
2021-07-15 13:50:11 +02:00
Axel Burri d80a8abb8a btrbk: add "latest" output format
Same as "resolved", but hides target if none present.
2021-07-15 13:50:11 +02:00
Axel Burri d7902fb30c btrbk: rename action_list table formats 2021-07-15 13:50:11 +02:00
Axel Burri f197a08650 btrbk: tidy table_formats 2021-07-15 13:50:11 +02:00
Axel Burri bd68b15ebc btrbk: tidy print_formatted 2021-07-15 13:50:11 +02:00
Axel Burri 37ef87ddaf btrbk: add url to fs_list raw format 2021-07-15 13:50:11 +02:00
Axel Burri cd69d29705 btrbk: tidy variable name
Duplicate use (not a bug)
2021-07-15 13:50:04 +02:00
Axel Burri 043e270522 btrbk: change version to 0.31.3-dev 2021-05-27 23:26:38 +02:00
Axel Burri 88d4cc76f3 documentation: move to irc.libera.chat 2021-05-27 23:26:38 +02:00
Axel Burri c511fc9dd0 documentation: lsbtr.1: copy --format from btrbk.1 2021-04-20 21:02:51 +02:00
Axel Burri fb792f67a3 documentation: README.md: mention common subvol naming 2021-04-20 21:02:51 +02:00
Axel Burri e6cec73c8f documentation: README.md: mention btr_pool mount point 2021-04-20 21:02:51 +02:00
Axel Burri d2522c5836 documentation: mention preserve all snapshots on errors 2021-04-20 21:02:51 +02:00
22 changed files with 2323 additions and 2112 deletions

3
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,3 @@
# These are supported funding model platforms
custom: ['https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WFQSSCD9GNM4S', 'https://btc.com/19DYtoEepxBmn9ZPspJGZrhCtySKCxPcP1']

26
.github/workflows/codespell.yml vendored Normal file
View File

@ -0,0 +1,26 @@
---
name: Codespell
on:
push:
branches: [master]
pull_request:
branches: [master]
permissions:
contents: read
jobs:
codespell:
name: Check for spelling errors
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Codespell
uses: codespell-project/actions-codespell@v2
with:
check_filenames: true
skip: ".git,*.pdf,*.svg"
ignore_words_list: uptodate

View File

@ -1,9 +1,87 @@
btrbk-0.32.6
* Fix backup of unrelated (by parent_uuid) snapshots (close #339).
* Remove echo -e for portability (close #506).
* Support btrfs send protocol v2 (send_protocol and
send_compressed_data config options).
* Add bzip3 support.
* Convert ssh_filter_btrbk.sh to POSIX sh, and harden it.
* Slight change in ssh_filter_btrbk.sh logging output.
* Minor bugfixes, stability and documentation improvements.
btrbk-0.32.5
* Correct handling of zero-size raw info file (close #491).
btrbk-0.32.4
* Fix regression: wrong deprecation warnings in some cases.
btrbk-0.32.3
* Fix deletion of many subvolumes at once (close #476).
* Allow disabling ssh_identity and ssh_user options.
* Minor bugfixes and documentation improvements.
btrbk-0.32.2
* Fix regression: archive on missing target directories.
* Fix action "config print".
* Print version and help message to stdout (close #452).
* Check results of filesystem usage (close #469).
* Add "compat ignore_receive_errors" option (close #383).
* Support multiple gpg recipients (close #471).
* Fix changelog: remove "compat missing_otime" item in v0.32.1.
* Fix changelog: correct "warn_unknown_targets" item in v0.31.3.
* Minor bugfixes and framework improvements.
btrbk-0.32.1
* Fix regression: correctly read mountinfo (close #445).
* Fix regression: filter paths for "lsbtr" (action "ls").
* Add backend btrfs-progs-doas (close #444).
* Allow directory traversal for local command line arguments.
* Display all source subvolumes in "usage" action.
* Handle errors from btrfs filesystem usage.
btrbk-0.32.0
* MIGRATION
- If timestamp_format is not configured, explicitly set
"timestamp_format short" to revert old behavior.
- Update ssh_filter_btrbk.sh on remote hosts.
* Change default for timestamp_format to "long".
* Optional "volume" config section.
* Use "volume" section only for grouping and relative paths.
* Allow absolute path for "subvolume" and "snapshot_dir"
(close #407, #121).
* Support subvolume names with UTF-8 characters (close #392, #213,
#120). Add "safe_commands" option for paranoid people.
* Add "incremental_prefs" configuration option (close #387).
* Change incremental prefs policy, giving snapshots created by btrbk
higher preference than the global ones resolved by parent-uuid.
* Change "incremental_clones" option to boolean.
* Drop support of deprecated raw file format (btrbk < 0.26.0).
* Drop support of deprecated "-r, --resume-only" cmdline option.
* Fix ambiguous naming in --format=raw output of "list" actions.
* Accept quoted values in config.
* Use single quotes for raw table output.
btrbk-0.31.3
* Add "warn_unknown_targets" configuration option (close #393).
* Add -1,--single-column command-line option for listing actions.
* Allow relative path command line argument for all actions.
* Add support for zstd adaptive compression (close #397).
* Add contrib/tools/btrbk_restore_raw.py (close #401).
* Minor bugfixes and framework improvements.
btrbk-0.31.2
* MIGRATION
- Update ssh_filter_btrbk.sh on remote hosts.
* ssh_filter_btrbk.sh: Fix security vulnerability.
Specialy crafted commands may be executed without being propely
Specially crafted commands may be executed without being properly
checked. Applies to remote hosts filtering ssh commands using
ssh_filter_btrbk.sh in authorized_keys.
* Warn if no subvolume defined in config (close #378).
@ -170,7 +248,7 @@ btrbk-0.27.0
- Allow snapshot_dir to be a mountpoint.
- Search complete target tree for correlated subvolumes.
- Include snapshots from all mountpoints as candidates (disabled
due to uptream bug: github.com/kdave/btrfs-progs/issues/96).
due to upstream bug: github.com/kdave/btrfs-progs/issues/96).
- Read /proc/self/mountinfo instead of /proc/self/mounts.
- Always read /proc/self/mountinfo.
- Resolve realpath using readlink(1).
@ -241,7 +319,7 @@ btrbk-0.25.0
* Allow trailing comments in btrbk.conf (close #129).
* Bugfix: rate limiting must be done after compression (close #134).
* raw_target_encrypt: Always set "gpg --no-random-seed-file":
prevents creation of "~/.gnupg/random_seed" with slight perfomance
prevents creation of "~/.gnupg/random_seed" with slight performance
penalty.
btrbk-0.24.0

View File

@ -17,7 +17,8 @@ SCRIPTS = ssh_filter_btrbk.sh \
contrib/cron/btrbk-mail \
contrib/cron/btrbk-verify \
contrib/migration/raw_suffix2sidecar \
contrib/crypt/kdf_pbkdf2.py
contrib/crypt/kdf_pbkdf2.py \
contrib/tools/btrbk_restore_raw.py
PN = btrbk
PREFIX ?= /usr

114
README.md
View File

@ -9,7 +9,7 @@ The source and target locations are specified in a config file, which
allows to easily configure simple scenarios like "laptop with locally
attached backup disks", as well as more complex ones, e.g. "server
receiving backups from several hosts via ssh, with different retention
policy".
policies".
Key Features:
@ -18,7 +18,8 @@ Key Features:
* Flexible retention policy
* Backups to multiple destinations
* Transfer via ssh
* Resume backups (for removable and mobile devices)
* Robust recovery from interrupted backups (for removable and mobile
devices)
* Archive to offline storage
* Encrypted backups to non-btrfs storage
* Wildcard subvolumes (useful for docker and lxc containers)
@ -59,7 +60,7 @@ For more information, read the [installation documentation].
[btrfs-progs]: https://www.kernel.org/pub/linux/kernel/people/kdave/btrfs-progs/
[Perl interpreter]: https://www.perl.org
[OpenSSH]: https://www.openssh.org
[OpenSSH]: https://www.openssh.com
[mbuffer]: https://www.maier-komor.de/mbuffer.html
@ -72,8 +73,8 @@ a full description of the command line options.
[btrbk(1)]: https://digint.ch/btrbk/doc/btrbk.1.html
Configuration File
==================
Configuration
=============
Before running `btrbk`, you will need to create a configuration
file. You might want to take a look at `btrbk.conf.example` provided
@ -81,21 +82,37 @@ with this package. For a detailed description, please consult the
[btrbk.conf(5)] man-page.
After a configuration change, it is highly recommended to check it by
running btrbk with the `-n,--dryrun` option:
running btrbk with the `-n,--dry-run` option:
btrbk -c /path/to/myconfig -v -n run
# btrbk -c /path/to/myconfig -v -n run
This will read all btrfs information on the source/target filesystems
and show what actions would be performed (without writing anything to
the disks).
The examples below assume that the btrfs subvolume containing `home`
and `rootfs` is mounted at `/mnt/btr_pool`. This is usually the btrfs
root subvolume, which always has `subvolid=5`.
Mounting `subvolid=5` is *recommended* (mandatory for btrbk < v0.32.0)
if you want to backup your root filesystem `/`.
/etc/fstab:
/dev/sda1 /mnt/btr_pool btrfs subvolid=5,noatime 0 0
Note that some default btrfs installations (e.g. Ubuntu) use subvolume
names `@` for rootfs (mounted at `/`) and `@home` for `/home`, as a
naming convention. If this is the case on your file system, replace
the `subvolume` declarations in the examples accordingly.
[btrbk.conf(5)]: https://digint.ch/btrbk/doc/btrbk.conf.5.html
Example: Local Regular Snapshots (time-machine)
-----------------------------------------------
The simpliest use case is to only create snapshots of your data. This
The simplest use case is to only create snapshots of your data. This
will obviously not protect it against hardware failure, but can be
useful for:
@ -121,15 +138,32 @@ manage snapshots located on the same volume in `snapshot_dir`. Btrbk
does not create subdirs by default, the snapshot directory must first
be created manually:
sudo mkdir /mnt/btr_pool/btrbk_snapshots
# mkdir /mnt/btr_pool/btrbk_snapshots
Start a dry run:
The "volume" section is merely used as a specifier for a base
directory, and can be skipped if you prefer to configure everything
using absolute paths. The above configuration can also be written as:
sudo btrbk run -n
snapshot_dir /mnt/btr_pool/btrbk_snapshots
subvolume /mnt/btr_pool/home
If you don't want to mount the btrfs root filesystem to
`/mnt/btr_pool`, you might as well configure it like this:
snapshot_dir /btrbk_snapshots
subvolume /home
Start a dry run (-n, --dry-run):
# btrbk run -n
Create the first snapshot:
sudo btrbk run
# btrbk run
Print schedule (-S, --print-schedule):
# btrbk run -n -S
If it works as expected, configure a cron job to run btrbk hourly:
@ -138,13 +172,10 @@ If it works as expected, configure a cron job to run btrbk hourly:
#!/bin/sh
exec /usr/bin/btrbk -q run
Snapshots will now be created every hour, kept for 48h
(`snapshot_preserve`), then automatically removed.
With this setup, the snapshots will be kept at least for 18 hours
(`snapshot_preserve_min`). This can be useful to create manual
snapshots by calling `sudo btrbk run` on the command line and keep
them around for a while, in addition to the regular snapshots.
Snapshots will now be created every hour. All snapshots are preserved for at
least 18 hours (`snapshot_preserve_min`), whether they are created by the cron
job or manually by calling `sudo btrbk run` on the command line. Additionally,
48 hourly snapshots are preserved (`snapshot_preserve`).
Example: Backups to USB Disk
@ -177,6 +208,9 @@ Retention policy:
snapshot_preserve_min 2d
snapshot_preserve 14d
# Create snapshots only if the backup disk is attached
#snapshot_create ondemand
target_preserve_min no
target_preserve 20d 10w *m
@ -202,10 +236,11 @@ Retention policy:
* `/mnt/btr_backup/mylaptop/rootfs.YYYYMMDD`
* `/mnt/btr_backup/mylaptop/home.YYYYMMDD`
If you want the snapshots to be created only if the backup disk is
attached, simply add the following line to the config:
If you prefer triggering the backups manually, change the cron command
to run the `snapshot` action instead of `run`. Start the backups
manually by running:
snapshot_create ondemand
# btrbk resume
For a quick additional snapshot of your home, run:
@ -215,8 +250,8 @@ For a quick additional snapshot of your home, run:
Example: Host-initiated Backup on Fileserver
--------------------------------------------
Let's say you have a fileserver at "myserver.mydomain.com" where you
want to create backups of your laptop disk, the config would look like
Let's say you have a fileserver at "myserver.example.org" where you
want to create backups of your laptop disk. The config could look like
this:
ssh_identity /etc/btrbk/ssh/id_rsa
@ -224,11 +259,11 @@ this:
volume /mnt/btr_pool
subvolume rootfs
target /mnt/btr_backup/mylaptop
target ssh://myserver.mydomain.com/mnt/btr_backup/mylaptop
target ssh://myserver.example.org/mnt/btr_backup/mylaptop
In addition to the backups on your local usb-disk mounted at
`/mnt/btr_backup/mylaptop`, incremental backups would also be pushed
to `myserver.mydomain.com`.
to `myserver.example.org`.
Example: Fileserver-initiated Backups from Several Hosts
@ -239,17 +274,17 @@ fileserver, the config would be something like:
ssh_identity /etc/btrbk/ssh/id_rsa
volume ssh://alpha.mydomain.com/mnt/btr_pool
volume ssh://alpha.example.org/mnt/btr_pool
target /mnt/btr_backup/alpha
subvolume rootfs
subvolume home
volume ssh://beta.mydomain.com/mnt/btr_pool
volume ssh://beta.example.org/mnt/btr_pool
target /mnt/btr_backup/beta
subvolume rootfs
subvolume dbdata
This will pull backups from alpha/beta.mydomain.com and locally
This will pull backups from alpha/beta.example.org and locally
create:
* `/mnt/btr_backup/alpha/rootfs.YYYYMMDD`
@ -350,7 +385,7 @@ running btrbk. Something like:
rsync -az --delete \
--inplace --numeric-ids --acls --xattrs \
-e 'ssh -i /etc/btrbk/ssh/id_rsa' \
myhost.mydomain.com:/data/ \
myhost.example.org:/data/ \
/mnt/btr_backup/myhost_sync/
exec /usr/bin/btrbk -q run
@ -377,7 +412,7 @@ compressed and piped through GnuPG.
raw_target_compress xz
raw_target_encrypt gpg
gpg_keyring /etc/btrbk/gpg/pubring.gpg
gpg_recipient btrbk@mydomain.com
gpg_recipient btrbk@example.org
volume /mnt/btr_pool
subvolume home
@ -393,7 +428,7 @@ host. For each backup, two files are created:
* `/backup/home.YYYYMMDD.btrfs.xz.gpg.info`: sidecar file containing
metadata used by btrbk.
I you are using raw _incremental_ backups, please make sure you
If you are using raw _incremental_ backups, please make sure you
understand the implications (see [btrbk.conf(5)], TARGET TYPES).
@ -414,7 +449,7 @@ will need the `btrfs` executable from the [btrfs-progs] package.
On the client side, create a ssh key dedicated to btrbk, without
password protection:
ssh-keygen -t rsa -b 4096 -f /etc/btrbk/ssh/id_rsa -C btrbk@mydomain.com -N ""
# ssh-keygen -t rsa -b 4096 -f /etc/btrbk/ssh/id_rsa -C btrbk@example.org -N ""
The content of the public key (/etc/btrbk/ssh/id_rsa.pub) is used for
authentication in "authorized_keys" on the server side (see [sshd(8)]
@ -520,14 +555,14 @@ to run it whenever the key is used for authentication. Example
"/root/.ssh/authorized_keys":
# example backup source (also allowing deletion of old snapshots)
command="/backup/scripts/ssh_filter_btrbk.sh -l --source --delete" <pubkey>...
command="/backup/scripts/ssh_filter_btrbk.sh -l --source --delete",restrict <pubkey>...
# example backup target (also allowing deletion of old snapshots)
command="/backup/scripts/ssh_filter_btrbk.sh -l --target --delete" <pubkey>...
command="/backup/scripts/ssh_filter_btrbk.sh -l --target --delete",restrict <pubkey>...
# example fetch-only backup source (snapshot_preserve_min=all, snapshot_create=no),
# restricted to subvolumes within /home or /data
command="/backup/scripts/ssh_filter_btrbk.sh -l --send -p /home -p /data" <pubkey>...
command="/backup/scripts/ssh_filter_btrbk.sh -l --send -p /home -p /data",restrict <pubkey>...
[ssh_filter_btrbk(1)]: https://digint.ch/btrbk/doc/ssh_filter_btrbk.1.html
@ -645,8 +680,8 @@ Donate
So btrbk saved your day?
I will definitively continue developing btrbk for free, but if you
want to support me you can do so:
I will definitively continue to develop btrbk for free. If you want to
support my hard work with a donation, you are welcome to do so!
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WFQSSCD9GNM4S)
@ -677,7 +712,7 @@ If you would like to contribute or have found bugs:
* Visit the [btrbk project page on GitHub] and use the
[issues tracker] there.
* Talk to us on Freenode in `#btrbk`.
* Talk to us on [Libera.Chat] in `#btrbk`.
* Contact the author via email (the email address can be found in
the sources).
@ -685,6 +720,7 @@ Any feedback is appreciated!
[btrbk project page on GitHub]: https://github.com/digint/btrbk
[issues tracker]: https://github.com/digint/btrbk/issues
[Libera.Chat]: https://libera.chat
License

3089
btrbk

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,13 @@
# Enable transaction log
transaction_log /var/log/btrbk.log
# Specify SSH private key for remote connections
ssh_identity /etc/btrbk/ssh/id_ed25519
ssh_user root
# Use sudo if btrbk or lsbtr is run by regular user
backend_local_user btrfs-progs-sudo
# Enable stream buffer. Adding a buffer between the sending and
# receiving side is generally a good idea.
# NOTE: If enabled, make sure to install the "mbuffer" package!
@ -29,7 +36,7 @@ stream_buffer 256m
# If you want to set a custom name for the snapshot (and backups),
# use the "snapshot_name" option within the subvolume section.
#
# NOTE: btrbk does not autmatically create this directory, and the
# NOTE: btrbk does not automatically create this directory, and the
# snapshot creation will fail if it is not present.
#
snapshot_dir _btrbk_snap
@ -67,12 +74,6 @@ snapshot_dir _btrbk_snap
#archive_preserve_min no
#archive_preserve <NN>h <NN>d <NN>w <NN>m <NN>y
# Specify SSH private key for "ssh://" volumes / targets:
#ssh_identity /etc/btrbk/ssh/id_ed25519
#ssh_user root
#ssh_compression no
#ssh_cipher_spec default
# Enable compression for remote btrfs send/receive operations:
#stream_compress no
#stream_compress_level default
@ -82,19 +83,19 @@ snapshot_dir _btrbk_snap
# 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.
#btrfs_commit_delete no
# Don't wait for transaction commit on deletion. Enable this to make
# sure the deletion of subvolumes is committed to disk when btrbk
# terminates.
#btrfs_commit_delete no
#
# Volume section: "volume <volume-directory>"
# Volume section (optional): "volume <volume-directory>"
#
# <volume-directory> Directory of a btrfs volume (or subvolume)
# containing the subvolume to be backuped
# <volume-directory> Base path within a btrfs filesystem
# containing the subvolumes to be backuped
# (usually the mount-point of a btrfs filesystem
# mounted with subvolid=5 option)
# mounted with subvolid=5 option).
#
# Subvolume section: "subvolume <subvolume-name>"
#
@ -104,19 +105,19 @@ snapshot_dir _btrbk_snap
# Target section: "target <type> <volume-directory>"
#
# <type> (optional) type, defaults to "send-receive".
# <volume-directory> Directory of a btrfs volume (or subvolume)
# <volume-directory> Directory within a btrfs filesystem
# receiving the backups.
#
# NOTE: The parser does not care about indentation, this is only for
# human readability. The options always apply to the last section
# human readability. All options apply to the last section
# encountered, overriding the corresponding option of the upper
# section. This means that the global options must be set before any
# "volume" section.
# section. This means that the global options must be set on top,
# before any "volume", "subvolume" or "target section.
#
#
# Example configuration:
# Example retention policy:
#
snapshot_preserve_min 2d
snapshot_preserve 14d
@ -124,29 +125,49 @@ snapshot_preserve 14d
target_preserve_min no
target_preserve 20d 10w *m
archive_preserve_min latest
archive_preserve 12m 10y
#
# Simple setup: Backup root and home to external disk
#
snapshot_dir /btrbk_snapshots
target /mnt/btr_backup
subvolume /
subvolume /home
#
# Complex setup
#
# In order to keep things organized, it is recommended to use "volume"
# sections and mount the top-level subvolume (subvolid=5):
#
# $ mount -o subvolid=5 /dev/sda1 /mnt/btr_pool
#
# Backup to external disk mounted on /mnt/btr_backup
volume /mnt/btr_pool
# no action if external disk is not attached
snapshot_create ondemand
# Create snapshots in /mnt/btr_pool/btrbk_snapshots
snapshot_dir btrbk_snapshots
# propagates to all subvolume sections:
target /mnt/btr_backup/_btrbk
# Target for all subvolume sections:
target /mnt/btr_backup
subvolume root_gentoo
subvolume kvm
# use different retention policy for kvm backups
target_preserve 7d 4w
# Some default btrfs installations (e.g. Ubuntu) use "@" for rootfs
# (mounted at "/") and "@home" (mounted at "/home"). Note that this
# is only a naming convention.
#subvolume @
subvolume root
subvolume home
subvolume kvm
# Use different retention policy for kvm backups:
target_preserve 7d 4w
# Backup to external disk as well as some remote host
# Backup data to external disk as well as remote host
volume /mnt/btr_data
subvolume home
# always create snapshot, even if targets are unreachable
snapshot_create always
target /mnt/btr_backup/_btrbk
subvolume data
# Always create snapshot, even if targets are unreachable
snapshot_create always
target /mnt/btr_backup
target ssh://backup.my-remote-host.com/mnt/btr_backup
@ -155,7 +176,22 @@ volume ssh://my-remote-host.com/mnt/btr_pool
subvolume data_0
snapshot_dir snapshots/btrbk
snapshot_name data_main
target /mnt/btr_backup/_btrbk/my-remote-host.com
target /mnt/btr_backup/my-remote-host.com
# Backup on demand (noauto) to remote host running busybox, login as
# regular user using ssh-agent with current user name (ssh_user no)
# and default credentials (ssh_identity no).
volume /home
noauto yes
compat busybox
backend_remote btrfs-progs-sudo
ssh_user no
ssh_identity no
target ssh://my-user-host.com/mnt/btr_backup/home
subvolume alice
subvolume bob
# Resume backups from remote host which runs its own btrbk instance
@ -165,4 +201,4 @@ volume ssh://my-remote-host.com/mnt/btr_pool
snapshot_create no
snapshot_preserve_min all
subvolume home
target /mnt/btr_backup/_btrbk/my-remote-host.com
target /mnt/btr_backup/my-remote-host.com

View File

@ -4,7 +4,7 @@ _btrbk_init_cmds()
#
# for example, for this command:
#
# btrbk -v list config --long
# btrbk -v --override warn_unknown_targets=yes list config --long
#
# then $cmds is:
#
@ -14,6 +14,11 @@ _btrbk_init_cmds()
local i
for ((i = 1; i < cword; i++)); do
case "${words[i-1]}" in
'-c' | '--config' | '--exclude' | '-l' | '--loglevel' | '--format' | '--lockfile' | '--override')
continue
;;
esac
[[ ${words[i]} != -* ]] && cmds+=(${words[i]})
done
@ -29,21 +34,28 @@ _btrbk()
case "$prev" in
'-c' | '--config')
_filedir
return
;;
'--exclude')
return
;;
'-l' | '--loglevel')
COMPREPLY=($(compgen -W 'error warn info debug trace' -- "$cur"))
return
;;
'--format')
COMPREPLY=($(compgen -W 'table long raw' -- "$cur"))
return
;;
'--lockfile')
_filedir
return
;;
'--override')
return
;;
esac
$split && return
if [[ $cur == -* ]]; then

View File

@ -4,6 +4,9 @@
now=$(date +%Y%m%d)
declare -A rsync_src rsync_dst rsync_log rsync_rsh rsync_opt
declare -A sync_fs_onchange
##### start config section #####
# Email recipients, separated by whitespace:
@ -30,7 +33,9 @@ rsync_opt[example_data]="-az --delete --inplace --numeric-ids --acls --xattrs"
# If set, add "rsync_dst" to "sync_fs" (see below) if rsync reports files transferred
#sync_fs_onchange[example_data]=yes
# Enabled rsync declarations (whitespace-separated list)
# Enable all rsync declarations (all indices of rsync_src array)
#rsync_enable=${!rsync_src[@]}
# Explicitly enable rsync declarations (whitespace-separated list)
#rsync_enable="example_data"
rsync_enable=
@ -55,6 +60,8 @@ btrbk_opts="-c /etc/btrbk/btrbk.conf"
#mail_cmd_block_prefix='\\u200B' # zero-width whitespace
#mail_cmd_block_prefix=". "
# Newline character
BR=$'\n'
##### end config section #####
@ -83,47 +90,47 @@ send_mail()
body+="$info"
fi
if [[ -n "$detail" ]] && [[ -n "$has_errors" ]] || [[ "${mail_detail:-no}" = "yes" ]]; then
[[ -n "$body" ]] && body+="\n\nDETAIL:\n"
[[ -n "$body" ]] && body+="${BR}${BR}DETAIL:${BR}"
body+="$detail"
fi
# skip sending mail on empty body
if [[ -z "$body" ]] && [[ -n "$has_errors" ]]; then
body+="FATAL: something went wrong (errors present but empty mail body)\n"
body+="FATAL: something went wrong (errors present but empty mail body)${BR}"
fi
[[ -z "$body" ]] && exit 0
# send mail
echo -e "$body" | mail -s "$subject" $mailto
echo "$body" | mail -s "$subject" $mailto
if [[ $? -ne 0 ]]; then
echo -e "$0: Failed to send btrbk mail to \"$mailto\", dumping mail:\n" 1>&2
echo -e "<mail_subject>$subject</mail_subject>\n<mail_body>\n$body</mail_body>" 1>&2
echo "$0: Failed to send btrbk mail to \"$mailto\", dumping mail:${BR}" 1>&2
echo "<mail_subject>$subject</mail_subject>${BR}<mail_body>${BR}$body</mail_body>" 1>&2
fi
}
einfo()
{
info+="$1\n"
info+="$1${BR}"
}
ebegin()
{
ebtext=$1
detail+="\n### $1\n"
detail+="${BR}### $1${BR}"
}
eend()
{
if [[ $1 -eq 0 ]]; then
eetext=${3-success}
detail+="\n"
detail+="${BR}"
else
has_errors=1
eetext="ERROR (code=$1)"
[[ -n "$2" ]] && eetext+=": $2"
detail+="\n### $eetext\n"
detail+="${BR}### $eetext${BR}"
fi
info+="$ebtext: $eetext\n"
info+="$ebtext: $eetext${BR}"
return $1
}
@ -139,10 +146,10 @@ run_cmd()
{
cmd_out=$("$@" 2>&1)
local ret=$?
detail+="++ ${@@Q}\n"
detail+="++ ${@@Q}${BR}"
if [[ -n "${mail_cmd_block_prefix:-}" ]] && [[ -n "$cmd_out" ]]; then
detail+=$(echo -n "$cmd_out" | sed "s/^/${mail_cmd_block_prefix}/")
detail+="\n"
detail+="${BR}"
else
detail+=$cmd_out
fi
@ -159,7 +166,7 @@ mount_all()
if [[ $? -eq 0 ]]; then
eend -1 "already mounted"
else
detail+="\n"
detail+="${BR}"
run_cmd mount --target $mountpoint
eend $? && mounted+=" $mountpoint"
fi

View File

@ -31,7 +31,7 @@
# NOTE: Depending on your setup (hardware, btrfs mount options),
# btrbk-verify may eat all your CPU power and use high bandwidth!
# Consider nice(1), ionice(1).
#
# Incomplete resource eater list:
# - rsync: checksums, heavy disk I/O
# - btrfs: decompression, encryption
@ -77,7 +77,7 @@ set -u
set -e
set -o pipefail
btrbk_version_min='0.28.0'
btrbk_version_min='0.32.0'
# defaults: ignore subvol dirs and root folder timestamp change
ignore_nested_subvolume_dir=1
@ -107,8 +107,8 @@ options:
--ignore-xattrs ignore xattrs when verifying subvolumes
--ssh-identity FILE override ssh_identity from btrbk.conf(5) with FILE,
and clear all other ssh_* options (use with --ssh-user)
--ssh-user USER override ssh_user from btrbk.conf(5) with USER
(only in conjunction with --ssh-identity)
--ssh-user USER override ssh_user from btrbk.conf(5) with USER, and
clear all other ssh_* options(use with --ssh-identity)
--ssh-agent start ssh-agent(1) and add identity
commands:
@ -157,7 +157,6 @@ while [[ "$#" -ge 1 ]]; do
;;
--ssh-identity)
# use different ssh identity (-i option) for rsync rsh.
# if set, ssh_user defaults to root.
# NOTE: this overrides all btrbk ssh_* options
ssh_identity="$2"
shift
@ -186,6 +185,8 @@ while [[ "$#" -ge 1 ]]; do
shift
done
BR=$'\n'
log_line()
{
echo "$@" 1>&2
@ -208,13 +209,13 @@ tlog()
[[ -n "$dryrun" ]] && [[ "$status" == "starting" ]] && status="dryrun_starting"
local line="$(date --iso-8601=seconds) verify-rsync ${status} ${target} ${source} - -"
[[ -n "$comment" ]] && line="$line # $comment";
tlog_text+="$line\n"
tlog_text+="$line${BR}"
log_debug "$line"
}
tlog_print()
{
# tlog goes to stdout
echo -e "\nTRANSACTION LOG\n---------------\n${tlog_text:-}"
echo "${BR}TRANSACTION LOG${BR}---------------${BR}${tlog_text:-}"
}
# parse "rsync -i,--itemize-changes" output.
@ -267,11 +268,14 @@ rsync_rsh()
local rsh_match="(.*) ([a-z0-9_-]+)@([a-zA-Z0-9.-]+)$"
if [[ -z "$rsh" ]]; then
echo
elif [[ -n "$ssh_identity" ]]; then
return
elif [[ -n "$ssh_user" ]] || [[ -n "$ssh_identity" ]]; then
# override btrbk.conf from command line arguments
log_debug "Overriding all ssh_* options from btrbk.conf"
echo "ssh -q -i $ssh_identity -l $ssh_user"
local cmd="ssh -q"
[[ -n "$ssh_identity" ]] && cmd="$cmd -i '$ssh_identity'"
[[ -n "$ssh_user" ]] && cmd="$cmd -l '$ssh_user'"
echo "$cmd"
elif [[ $rsh =~ $rsh_match ]]; then
echo "${BASH_REMATCH[1]} -l ${BASH_REMATCH[2]}"
else
@ -302,7 +306,7 @@ start_ssh_agent()
eval_btrbk_resolved_line()
{
local line=$1
local line=" $1"
local prefix=$2
local required_keys=$3
# reset all variables first
@ -311,25 +315,13 @@ eval_btrbk_resolved_line()
done
for vv in $required_keys; do
# basic input validation, set prefixed variable (eval)
local var_assignment=$(echo "$line" | grep -Eo "${vv}"'="[^"]*"')
if [[ $? -ne 0 ]] || [[ -z "$var_assignment" ]]; then
if [[ $vv == "target_type" ]]; then
# hack for btrbk <= 0.27.2 bug: missing "target_type" in $table_formats{resolved}
# hardcode send-receive type, this results in rsync failing on raw targets with:
# rsync: ERROR: cannot stat destination "xxx.btrfs.xz.gpg/": Not a directory (20)
eval "${prefix}target_type=\"send-receive\"" || return 1
continue
fi
if [[ $vv == "target_rsh" ]] && [[ -z "$R_target_host" ]]; then
# hack for btrbk <= 0.27.2 bug: missing "target_rsh" in $table_formats{resolved}
# note that target_rsh is not needed if target_host is not set.
# variable has already been reset above, continue
continue
fi
log_line "btrbk-verify: missing required variable \"${vv}\" in btrbk --format=raw line"
local match=" ${vv}='([^']*('\\\\''[^']*)*)'"
if [[ $line =~ $match ]] ; then
eval "${prefix}${vv}='${BASH_REMATCH[1]}'" || return 1
else
log_line "btrbk-verify: ERROR: Missing variable \"${vv}\""
return 1
fi
eval "${prefix}${var_assignment}" || return 1
done
}
@ -339,10 +331,6 @@ exit_trap_action()
[[ $verbose -gt 0 ]] && tlog_print
}
# restrictions from rsync_rsh():
[[ -z "$ssh_identity" ]] && [[ -n "$ssh_user" ]] && print_usage 2
[[ -n "$ssh_identity" ]] && [[ -z "$ssh_user" ]] && print_usage 2
# start ssh-agent(1)
[[ -n "$ssh_start_agent" ]] && start_ssh_agent
@ -371,20 +359,22 @@ while read -r btrbk_list_line; do
log_debug "Evaluating [btrbk list] line: $btrbk_list_line"
[[ -z "$btrbk_list_line" ]] && continue
if ! eval_btrbk_resolved_line "$btrbk_list_line" \
"R_" "snapshot_path target_path source_host target_host target_type source_rsh target_rsh"
"R_" "snapshot_subvolume target_subvolume source_host target_host target_type source_rsh target_rsh"
then
log_line "btrbk-verify: WARNING: Skipping task (parse error). Make sure to have >=btrbk-${btrbk_version_min} installed!"
continue
log_line "btrbk-verify: ERROR: Parse error of command output: ${btrbk_cmd[@]}"
log_line "Make sure to have >=btrbk-${btrbk_version_min} installed!"
exitstatus=1
break
fi
source="${R_snapshot_path}"
target="${R_target_path}"
source="${R_snapshot_subvolume}/"
target="${R_target_subvolume}/"
[[ -n "$R_source_host" ]] && source="${R_source_host}:${source}"
[[ -n "$R_target_host" ]] && target="${R_target_host}:${target}"
if [[ -z "$R_snapshot_path" ]]; then
if [[ -z "$R_snapshot_subvolume" ]]; then
log_line "WARNING: Skipping task (missing snapshot): target=$target"
elif [[ -z "$R_target_path" ]]; then
elif [[ -z "$R_target_subvolume" ]]; then
log_line "Skipping task (no target): source=$source"
elif [[ "$R_target_type" != "send-receive" ]]; then
log_line "Skipping task (target_type=$R_target_type): source=$source, target=$target"
@ -396,10 +386,11 @@ while read -r btrbk_list_line; do
# rsync rsh is either source_rsh or target_rsh or empty
eff_rsh="$R_source_rsh"
[[ -z "$eff_rsh" ]] && eff_rsh="$R_target_rsh"
eff_rsh=$(rsync_rsh "$eff_rsh")
rsync_cmd=("rsync" "${rsync_args[@]}")
[[ -n "$eff_rsh" ]] && rsync_cmd+=(-e "$(rsync_rsh "$eff_rsh")")
rsync_cmd+=("${source}/" "${target}/")
[[ -n "$eff_rsh" ]] && rsync_cmd+=("-e" "$eff_rsh")
rsync_cmd+=("${source}" "${target}")
log_cmd "${rsync_cmd[@]}"
[[ -n "$dryrun" ]] && rsync_cmd=("cat" "/dev/null")

View File

@ -54,7 +54,7 @@ salt_hex = "".join(["{:02x}".format(x) for x in salt])
dk_hex = "".join(["{:02x}".format(x) for x in dk])
print("KEY=" + dk_hex);
print("algoritm=pbkdf2_hmac");
print("algorithm=pbkdf2_hmac");
print("hash_name=" + hash_name);
print("salt=" + salt_hex);
print("iterations=" + str(iterations));

View File

@ -42,7 +42,7 @@ my $compress_format_alt = 'gz|bz2|xz|lzo|lz4';
my $file_match = qr/[0-9a-zA-Z_@\+\-\.\/]+/; # note: ubuntu uses '@' in the subvolume layout: <https://help.ubuntu.com/community/btrfs>
my $uuid_match = qr/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/;
my $timestamp_postfix_match = qr/\.(?<YYYY>[0-9]{4})(?<MM>[0-9]{2})(?<DD>[0-9]{2})(T(?<hh>[0-9]{2})(?<mm>[0-9]{2})((?<ss>[0-9]{2})(?<zz>(Z|[+-][0-9]{4})))?)?(_(?<NN>[0-9]+))?/; # matches "YYYYMMDD[Thhmm[ss+0000]][_NN]"
my $raw_postfix_match = qr/--(?<received_uuid>$uuid_match)(\@(?<parent_uuid>$uuid_match))?\.btrfs?(\.(?<compress>($compress_format_alt)))?(\.(?<encrypt>gpg))?(\.(?<split>split_aa))?(\.(?<incomplete>part))?/; # matches ".btrfs_<received_uuid>[@<parent_uuid>][.gz|bz2|xz][.gpg][.split_aa][.part]"
my $raw_postfix_match = qr/--(?<received_uuid>$uuid_match)(\@(?<parent_uuid>$uuid_match))?\.btrfs?(\.(?<compress>($compress_format_alt)))?(\.(?<encrypt>gpg))?(\.(?<split>split_aa))?(\.(?<incomplete>part))?/; # matches ".btrfs_<received_uuid>[@<parent_uuid>][.gz|.bz2|.xz|...][.gpg][.split_aa][.part]"
my $dryrun;

View File

@ -0,0 +1,217 @@
#!/usr/bin/env python3
import os
import logging
import subprocess
import argparse
logger = logging.getLogger(__name__)
class TransformProcess:
def run(self, bfile, options, **kw):
return subprocess.Popen(self.get_cmd(bfile, options), **kw)
def get_cmd(self, bfile, options):
raise NotImplementedError()
@classmethod
def add_parser_options(cls, parser):
pass
class TransformOpensslDecrypt(TransformProcess):
@staticmethod
def get_cmd(bfile, options):
return [
'openssl', 'enc', '-d', '-' + bfile.info['cipher'], '-K',
open(options.openssl_keyfile, 'r').read(), '-iv', bfile.info['iv']
]
@staticmethod
def add_parser_options(parser):
parser.add_argument('--openssl-keyfile', help="path to private encryption key file")
class TransformDecompress(TransformProcess):
def __init__(self, program):
self.p = program
def get_cmd(self, bfile, options):
return [self.p, '-d']
class TransformBtrfsReceive(TransformProcess):
@classmethod
def run(cls, bfile, options, **kw):
return subprocess.Popen(cls.get_cmd(bfile, options), **kw)
@staticmethod
def get_cmd(bfile, options):
return ['btrfs', 'receive', options.restore_dir]
TRANSFORMERS = (
TransformOpensslDecrypt, TransformDecompress, TransformBtrfsReceive
)
class BtrfsPipeline:
def __init__(self, bfile):
self.bfile = bfile
self.processors = []
def append(self, transformer):
self.processors.append(transformer)
def run(self, options):
processes = []
with open(self.bfile.data_file, 'rb') as next_input:
for transformer in self.processors:
process = transformer.run(
self.bfile, options,
stdin=next_input, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
next_input = process.stdout
processes.append(process)
btrfs_process = TransformBtrfsReceive.run(
self.bfile, options, stdin=next_input,
stderr=subprocess.PIPE, stdout=subprocess.DEVNULL)
processes.append(btrfs_process)
# warning: the code below is pretty ugly and hacky
terminated = 0
while terminated < len(processes):
for p in processes:
if p.returncode is not None:
continue
msg = None
try:
p.wait(timeout=1)
except subprocess.TimeoutExpired as e:
pass
except Exception as e:
msg = e
else:
msg = p.stderr.read().decode('utf-8').strip()
finally:
if p.returncode is not None:
terminated += 1
if p.returncode != 0:
for p_other in processes:
p_other.terminate()
terminated += 1
if msg:
logger.error(f"error running {p.args}: {msg}")
def get_cmd(self, options):
command_pipe = [['cat', self.bfile.data_file]]
for transformer in self.processors:
command_pipe.append(transformer.get_cmd(self.bfile, options))
command_pipe.append(TransformBtrfsReceive.get_cmd(self.bfile, options))
return ' | '.join(' '.join(x) for x in command_pipe)
class BackupFile:
def __init__(self, path):
assert path.endswith('.info')
self.info_file = path
self.info = self._parse_info()
self.uuid = self.info['RECEIVED_UUID']
self.data_file = os.path.join(os.path.dirname(path), self.info['FILE'])
self.parent = self.info.get('RECEIVED_PARENT_UUID')
self.is_restored = False
def _parse_info(self):
config = {}
with open(self.info_file, 'r') as fh:
# skip command option line
for line in fh.readlines():
if '=' not in line:
continue
key, val = line.strip().split('=', maxsplit=1)
config[key] = val
return config
def get_transformers(self):
if 'encrypt' in self.info:
if self.info['encrypt'] == 'gpg':
raise NotImplementedError('gpg encryption')
elif self.info['encrypt'] == 'openssl_enc':
yield TransformOpensslDecrypt()
else:
raise Exception(f'unknown encryption type: "{self.info["encrypt"]}"')
if 'compress' in self.info:
yield TransformDecompress(self.info['compress'])
def restore_file(self, options):
assert self.info.get('TYPE') == 'raw'
assert not self.info.get('INCOMPLETE')
pipeline = BtrfsPipeline(self)
for transformer in self.get_transformers():
pipeline.append(transformer)
if options.dry_run:
print(pipeline.get_cmd(options))
else:
logger.info(f"restoring backup {os.path.basename(self.data_file)}")
pipeline.run(options)
self.is_restored = True
def restore_from_path(backup, options):
path = os.path.dirname(backup)
info_files = {}
backup_file = BackupFile(backup + '.info')
restored_files = set()
for entry in os.scandir(path):
if entry.is_file() and entry.name.endswith('.info'):
info = BackupFile(entry.path)
info_files[info.uuid] = info
restored_files.update(restore_backup(backup_file, info_files, options))
logger.info(f"finished; restored {len(restored_files)} backup files")
def restore_backup(bfile, parents, options):
if bfile.is_restored:
return
if bfile.parent:
parent = parents.get(bfile.parent)
if not parent:
msg = (f"missing parent {bfile.parent} for"
f"'{os.path.basename(bfile.info_file)}'")
if options.ignore_missing:
logger.warning(msg)
else:
raise Exception(msg)
else:
yield from restore_backup(parent, parents, options)
bfile.restore_file(options)
yield bfile.uuid
def main():
parser = argparse.ArgumentParser(description="restore btrbk raw backup")
parser.add_argument('backup', help="backup file to restore; for incremental"
" backups the parent files must be in the same directory")
parser.add_argument('restore_dir', help="target directory for restored subvolumes"
" (path argument for \"btrfs receive\")")
parser.add_argument('-n', '--dry-run', action='store_true',
help="print commands that would be executed")
parser.add_argument('--ignore-missing', action='store_true',
help="do not fail on missing parent snapshots")
for transformer in TRANSFORMERS:
transformer.add_parser_options(parser)
args = parser.parse_args()
if args.dry_run:
logger.setLevel('ERROR')
restore_from_path(args.backup, args)
if __name__ == '__main__':
logger.setLevel('INFO')
logging.basicConfig(format='%(asctime)s %(levelname)s - %(message)s')
main()

View File

@ -110,8 +110,8 @@ have to create a run-time (rw) snapshot before booting into it:
How do I convert '/' (subvolid=5) into a subvolume?
---------------------------------------------------
There's several ways to achieve this, the solution described below is
that it guarantees not to create new files (extents) on disk.
There's several ways to achieve this, the solution described below
guarantees not to create new files (extents) on disk.
### Step 1: make a snapshot of your root filesystem
@ -191,7 +191,7 @@ What is the most efficient way to clone btrfs storage?
------------------------------------------------------
It is very common (and avisable!) to keep backups on a separate
location. In some situations, is is also required to transport the
location. In some situations, it is also required to transport the
data physically, either to the datacenter or to your safe in the
basement.

View File

@ -1,5 +1,4 @@
DOCS = FAQ.md \
upgrade_to_v0.23.0.md
DOCS = FAQ.md
MAN_MAN1 = btrbk.1 \
lsbtr.1 \
ssh_filter_btrbk.1
@ -18,8 +17,19 @@ ifeq ($(COMPRESS), yes)
endif
# convert using "asciidoctor": <https://asciidoctor.org>
ASCIIDOCTOR_MANPAGE = asciidoctor -d manpage -b manpage
ASCIIDOCTOR_HTML = asciidoctor -b html5 -d article
# fallback to "a2x" from asciidoc package: <http://asciidoc.org>
ifneq (, $(shell command -v asciidoctor 2> /dev/null))
ASCIIDOC_MANPAGE = asciidoctor -d manpage -b manpage
ASCIIDOC_HTML = asciidoctor -b html5 -d article
else ifneq (, $(shell command -v a2x 2> /dev/null))
# NOTE: using -L (--no-xmllint), as xmllint is a separate package on many distros.
ASCIIDOC_MANPAGE = a2x -L -d manpage -f manpage
ASCIIDOC_HTML = asciidoc -b html -d article
else
ASCIIDOC_ERR = $(error "please install either asciidoc or asciidoctor")
ASCIIDOC_MANPAGE = $(ASCIIDOC_ERR)
ASCIIDOC_HTML = $(ASCIIDOC_ERR)
endif
# reproducible builds: reference date is ":date:" attribute from asciidoc source
date_attr = $(shell sed -rn 's/:date:\s*//p' $(1))
@ -50,10 +60,10 @@ clean:
gzip -9 -n -c $< > $@
%.1 : %.1.asciidoc
SOURCE_DATE_EPOCH=$(call source_date_epoch,$<) $(ASCIIDOCTOR_MANPAGE) -o $@ $<
SOURCE_DATE_EPOCH=$(call source_date_epoch,$<) $(ASCIIDOC_MANPAGE) $<
%.5 : %.5.asciidoc
SOURCE_DATE_EPOCH=$(call source_date_epoch,$<) $(ASCIIDOCTOR_MANPAGE) -o $@ $<
SOURCE_DATE_EPOCH=$(call source_date_epoch,$<) $(ASCIIDOC_MANPAGE) $<
%.html : %.asciidoc
SOURCE_DATE_EPOCH=$(call source_date_epoch,$<) $(ASCIIDOCTOR_HTML) -o $@ $<
SOURCE_DATE_EPOCH=$(call source_date_epoch,$<) $(ASCIIDOC_HTML) -o $@ $<

View File

@ -1,7 +1,7 @@
btrbk(1)
========
:date: 2021-03-21
:release-version: 0.31.2
:date: 2023-03-25
:release-version: 0.32.6
:man manual: Btrbk Manual
:man source: Btrbk {release-version}
@ -20,11 +20,12 @@ btrbk [-h|--help] [--version]
[-c|--config <file>] [-n|--dry-run] [--exclude <filter>]
[-p|--preserve] [--preserve-snapshots] [--preserve-backups]
[-v|--verbose] [-q|--quiet] [-l|--loglevel <level>]
[-t|--table] [-L|--long] [--format <output-format>] [--pretty]
[-t|--table] [-L|--long] [-1|--single-column]
[--format <output-format>] [--pretty]
[-S|--print-schedule] [--progress]
[--lockfile <file>]
[--override <config_option>=<value>]
<command> [<args>]
<command> [[--] <filter>...]
DESCRIPTION
@ -44,26 +45,27 @@ btrbk.conf(5) for more details.
=== Snapshots and Backups
Snapshots as well as backup subvolumes are created in form:
Snapshots as well as backup subvolumes are created in the form:
<snapshot-name>.<timestamp>[_N]
Where '<snapshot-name>' is identical to the source subvolume name,
unless the configuration option 'snapshot_name' is set. The
<timestamp> is either "YYYYMMDD" or "YYYYMMDDThhmm" (dependent of the
'timestamp_format' configuration option), where "YYYY" is the year,
"MM" is the month, "DD" is the day, "hh" is the hour and "mm" is the
minute of the creation time (local time of the host running btrbk). If
multiple snapshots/backups are created on the same date/time, N will
be incremented on each snapshot, starting at 1.
unless the configuration option 'snapshot_name' is set. '<timestamp>'
is a timestamp describing the creation time (local time of the host
running btrbk) of the snapshot/backup. The format can be configured
using the 'timestamp_format' option, refer to btrbk.conf(5) for
details. If multiple snapshots/backups are created on the same
date/time, 'N' will be incremented on each snapshot, starting at 1.
If a snapshot or backup does not match the naming scheme above
(i.e. if it has been renamed manually), btrbk will leave it untouched.
(e.g. if it has been renamed manually), btrbk will leave it untouched.
Note that 'snapshot' is a btrfs terminology for a ``read-only
subvolume'' (showing a parent-uuid, see btrfs-subvolume(8)); 'backup'
is a btrbk terminology for a ``read-only subvolume created with
send/receive'' (showing a received-uuid).
Note that in btrfs terminology, a 'snapshot' is a ``subvolume with
a given initial content of the original subvolume'' (showing a
parent-uuid, see btrfs-subvolume(8)), and they can be read-write
(default) or read-only. In btrbk terminology, 'snapshot' means
``read-only btrfs snapshot'', and 'backup' means ``read-only subvolume
created with send/receive'' (showing a received-uuid).
OPTIONS
@ -86,8 +88,15 @@ OPTIONS
commands that would be executed.
--exclude <filter>::
Exclude configured sections matching '<filter>'. See
<<_filter_statements,FILTER STATEMENTS>> below.
Exclude configured sections matching '<filter>' (see
<<_filter_statements,FILTER STATEMENTS>> below), or any specific
snapshot from being backuped or deleted, or any specific backup
from being deleted.
+
Note that excluding specific snapshots from being backuped has impact
on scheduling: e.g. if the "first snapshot of the day" is excluded,
the "second snapshot of the day" shifts to "first", creating a backup
as "first backup of the day".
-p, --preserve::
Preserve all snapshots and backups. Skips deletion of any
@ -103,7 +112,7 @@ OPTIONS
specified in the configuration file.
--wipe::
Ignore configured snapshot retention policy, delete all but latest
Ignore configured snapshot retention policy, delete all but the latest
snapshots instead. All snapshots needed for incremental backup
(latest common) are also preserved. Useful if you are getting low
on disk space (ENOSPC).
@ -126,12 +135,15 @@ OPTIONS
-L, --long::
Print output in long table format (shortcut for "--format=long").
-1, --single-column::
Print output as single column (not available for all commands).
--format table|long|raw|col:[h:]<columns>::
Print output in specified format. If set to "raw", prints
space-separated key="value" pairs (machine readable).
space-separated, quoted key=value pairs (machine readable).
+
If set to "col:", prints only the <columns> specified (comma-separated
list). Header lines are ommitted if the "h:" modifier is present.
list). Header lines are omitted if the "h:" modifier is present.
Columns prefixed with "-" are collapsed if empty. Columns postfixed
with ":RALIGN" are right-aligned.
@ -149,9 +161,9 @@ with ":RALIGN" are right-aligned.
command (version >= 20180505) installed on the host running btrbk.
--lockfile <file>::
Create lockfile <file> 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
Place an exclusive lock on <file> during program execution, using
flock(2). If the lock is held by another process, exit before
running any actions. Overrides configuration option
"lockfile". Ignored on dryrun ('-n', '--dry-run').
--override <config_option>=<value>::
@ -210,8 +222,9 @@ configuring the retention policy.
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.
always preserved, regardless of the retention policy. If any
target is unreachable or has errors, all snapshots are preserved
in order not to break the incremental chain.
*dryrun* [filter...]::
Don't run any btrfs commands that would alter the filesystem, just
@ -416,8 +429,7 @@ execution times and high ram usage. Consider setting 'cache_dir'.
lsbtr(1).
*config* print|print-all::
Prints the parsed configuration file. Use the '--format' command
line option to switch between different output formats.
Prints the parsed configuration file.
FILTER STATEMENTS
@ -468,6 +480,9 @@ Note that for *run* and *snapshot* commands, a filter matching a
surrounding 'subvolume' section. If this is not desired, consider
running *snapshot* and *resume* commands separately.
Filter statements can match multiple times (e.g. on group as well as
host name). In such a case, all matches are processed.
FILES
-----

View File

@ -1,7 +1,7 @@
btrbk.conf(5)
=============
:date: 2021-03-21
:release-version: 0.31.2
:date: 2023-03-25
:release-version: 0.32.6
:man manual: Btrbk Manual
:man source: Btrbk {release-version}
@ -36,34 +36,21 @@ global options must be set before any sections are defined.
Blank lines are ignored. A hash character (#) starts a comment
extending until end of line.
Whitespace or unicode characters are not allowed for file
names. Allowed characters are:
[0-9] [a-z] [A-Z] and "._+-@"
This is for sanity/safety/security reasons, we apologize for the
inconvenience.
SECTIONS
--------
*volume* <volume-directory>|<url>::
Directory of a btrfs volume containing the source subvolume(s) to
be backed up. '<volume-directory>' must be an absolute path and
point to a btrfs volume (or subvolume). Usually the mount point of
a btrfs filesystem mounted with the 'subvolid=5' option.
*volume* <volume-directory>|<url> (optional)::
Absolute path pointing to a btrfs file system containing the
source subvolume(s) to be backed up. Usually the mount point of a
btrfs filesystem mounted with the 'subvolid=5' option.
*subvolume* <subvolume-name>::
Subvolume to be backed up, relative to the '<volume-directory>'
specified in the 'volume' section. Multiple 'subvolume' sections
are allowed within 'volume' sections. Accepts wildcard character
"*".
Subvolume to be backed up, relative to the '<volume-directory>' of
the 'volume' section, or absolute if the 'volume' section is
omitted. Accepts wildcard character "*".
+
--
If set to ".", the subvolume at '<volume-directory>' is used as backup
source, and the snapshots will be created within the source subvolume
itself (see 'snapshot_dir' option below), which is not recommended.
Note that if this subvolume is btrfs root (id=5), it needs to have a
valid UUID, which is not the case for file systems created with
btrfs-progs < 4.16.
@ -109,7 +96,7 @@ otherwise.
*timestamp_format* short|long|long-iso::
Timestamp format used as postfix for new snapshot subvolume
names. Defaults to ``short''.
names. Defaults to ``long''.
+
--
ifndef::backend-docbook,backend-manpage[]
@ -129,12 +116,13 @@ snapshots are created during a daylight saving time clock
change).
+
Note that using ``long-iso'' has implications on the scheduling, see
<<_retention_policy,RETENTION POLICY>> (caveats) below.
<<_reference_time,Reference Time>> below.
*snapshot_dir* <directory>::
Directory in which the btrfs snapshots are created, relative to
'<volume-directory>' of the 'volume' section. Note that btrbk does
not automatically create this directory, and the snapshot creation
'<volume-directory>' of the 'volume' section, or absolute if the
'volume' section is omitted. Note that btrbk does not
automatically create this directory, and the snapshot creation
will fail if it is not present.
*snapshot_name* <basename>::
@ -197,10 +185,9 @@ not be certain about this, such operations are disallowed in
Defines after what time (in full hours since midnight) a
snapshot/backup is considered to be a "daily" backup. Daily,
weekly, monthly and yearly backups are preserved on this hour (see
<<_retention_policy,RETENTION POLICY>> below). If you set this
option, make sure to also set 'timestamp_format' to ``long'' or
``long-iso'' (backups and snapshots having no time information
will ignore this option). Defaults to ``0''.
<<_retention_policy,RETENTION POLICY>> below). Ignored on
snapshots or backups without time information ('timestamp_format
short'). Defaults to ``0''.
*snapshot_preserve* no|<retention_policy>::
Set retention policy for snapshots (see
@ -255,32 +242,29 @@ set to ``all'' (the default).
=== SSH Options
*ssh_identity* <file>::
Absolute path to a ssh identity file (private key). Note that if
the private key is password protected, btrbk will prompt for user
input, which is usually not desired.
*ssh_identity* <file>|no::
Absolute path to a ssh identity file (private key). If not set,
the ssh default is used (see ssh(1), "-i identity_file"). Note
that if the identity key is password protected and no
authentication agent is used, btrbk will prompt for user input on
every connection attempt.
*ssh_user* <username>::
*ssh_user* <username>|no::
Remote username for ssh. Defaults to ``root''. Make sure the
remote user is able to run "btrfs" with root privileges (see
option 'backend' for details).
option 'backend' for details). If set to ``no'', the ssh default
is used.
*ssh_compression* yes|no::
Enables or disables the compression of ssh connections. Defaults
to ``no''. Note that if *stream_compress* is enabled, ssh
compression will always be disabled for send/receive operations.
*ssh_cipher_spec* <cipher_spec>::
*ssh_cipher_spec* default|<cipher_spec>::
Selects the cipher specification for encrypting the session
(comma-separated list of ciphers in order of preference). See the
"-c cipher_spec" option in ssh(1) for more information. Defaults
to ``default'' (the ciphers specified in 'ssh_config').
Previous versions btrbk allowed you to set a *ssh_port* option, this
has been dropped in favor of the `ssh://hostname:port` notation in the
'volume' and 'target' <<_sections,sections>>. If you want to set a
global port for all SSH connections to remote hosts, set the ``Port''
option in ssh_config(5).
to ``default'' (the ciphers specified in ssh_config(5)).
=== Data Stream Options
@ -290,7 +274,7 @@ option in ssh_config(5).
remote locations. Defaults to ``no''. If enabled, make sure that
'<compress_command>' is available on the source and target
hosts. Supported '<compress_command>': gzip, pigz, bzip2, pbzip2,
xz, lzo, lz4, zstd.
bzip3, xz, lzo, lz4, zstd.
*stream_compress_level* default|<number>::
Compression level for the specified '<compress_command>'. Refer to
@ -305,7 +289,11 @@ option in ssh_config(5).
*stream_compress_threads* default|<number>::
Number of threads to use for <compress_command>. Only supported
for "pigz", "pbzip2", "zstd" and recent versions of "xz".
for "pigz", "pbzip2", "bzip3", "zstd" and recent versions of "xz".
*stream_compress_adapt* yes|no::
Enable adaptive compression for <compress_command>. Only supported
for "zstd" (version >= 1.3.6). Defaults to ``no''.
*stream_buffer* <size>|no::
Add a buffer to the btrfs send stream (locally, on uncompressed
@ -364,21 +352,21 @@ constraints.
in a space-separated table format: "localtime type status
target_url source_url parent_url message".
*transaction_syslog* <facility>|no::
*transaction_syslog* <facility>|no::
If set, all transactions (as described in 'transaction_log' above)
are logged to syslog. The program name used in the messages is
"btrbk". Accepted parameters for '<facility>': user, mail,
daemon, auth, lpr, news, cron, authpriv, local0..local7.
*lockfile* <file>|no::
Create lockfile <file> 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 ('-n',
'--dry-run'). See also '--lockfile' command-line option.
Place an exclusive lock on <file> during program execution, using
flock(2). If the lock is held by another process, exit before
running any actions. Ignored on dryrun ('-n', '--dry-run'). See
also '--lockfile' command-line option.
*backend* btrfs-progs|btrfs-progs-btrbk|btrfs-progs-sudo::
*backend* <backend>::
Backend filesystem utilities to be used for btrfs specific
operations. Defaults to ``btrfs-progs''.
operations. Available backends:
+
--
*btrfs-progs*::
@ -398,6 +386,9 @@ constraints.
have appropriate (root) permissions for the "btrfs" command groups
as well as the "readlink" and "test" commands in /etc/sudoers.
*btrfs-progs-doas*::
Similar to btrfs-progs-sudo, using prefix "doas -n".
If you want to set this option for local or remote hosts only, set
*backend_local* or *backend_remote* (e.g. "backend_remote
btrfs-progs-btrbk").
@ -406,12 +397,29 @@ If you want to set this option for regular (non-root) user only, set
*backend_local_user*.
--
*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").
*compat* <compat-option>...::
Enable compatibility options. Available 'compat-option':
+
--
*busybox*::
Use busybox compatible commands, at the expense of slight overhead
while reading filesystem information.
*ignore_receive_errors* _*experimental*_::
Tell btrfs-receive(8) to not terminate on errors by setting
"--max-errors=0" option. Print warnings instead.
+
A known use case for this are target hosts lacking xattr support
(e.g. some Synology NAS), while the send-stream contains "lsetxattr"
commands. Another case is targets failing to set otime, complaining
with "ERROR: attribute 12 requested but not present".
+
Note that there is *no guarantee that backups created with this
option enabled can be restored at all*.
If you want to set this option for local or remote hosts only, set
*compat_local* or *compat_remote* (e.g. "compat_remote busybox").
--
*cache_dir* <directory>::
If set, cache extent maps for the "btrbk extents" command.
@ -419,28 +427,74 @@ If you want to set this option for regular (non-root) user only, set
=== Btrfs Specific Options
*btrfs_commit_delete* after|each|no::
If set, make sure the deletion of snapshot and backup subvolumes
are committed to disk when btrbk terminates. Defaults to ``no''.
*incremental_prefs* <list-spec>[:<amount>]...::
Specify the preferences to determine the best common (correlated)
parent and clone sources for incremental backups, by choosing from
predefined candidate lists.
+
--
The 'list-spec' defines from what candidate list the next
parent/clone-src should be appended to a result list; 'amount' defines
how many (e.g. "sro:1 sro:1" is identical to "sro:2"), or all if
omitted. Any candidate which is already in the results is dropped.
*incremental_clones* <number>::
Maximum number of clone sources allowed for incremental send. If
set, btrbk adds "-c <clone-src>" to the btrfs-send(8) command for
all present snapshot/backup pairs (correlated subvolumes matching
matching 'received_uuid', printed by "btrbk stats"). Set this to a
high number if you want to make sure that no common data is missed
on incremental backups, in expense of btrfs-send
performance. Defaults to 0.
The resulting list of subvolumes is then used as parameters for the
btrfs-send(8) command: the first for "-p <parent>", all others for
"-c <clone-src>".
Available 'list-spec' (candidate lists = filtered subsets of
correlated subvolumes):
*sro*,*srn*:: All from 'snapshot_dir' matching 'snapshot_name', with
parent_uuid relationship, sorted by btrbk timestamp (o=older
n=newer).
*sao*,*san*:: All from 'snapshot_dir' matching 'snapshot_name', sorted
by btrbk timestamp (o=older n=newer).
*aro*,*arn*:: All from 'incremental_resolve', with parent_uuid
relationship, sorted by cgen (o=older n=newer).
Defaults to "sro:1 srn:1 sao:1 san:1 aro:1 arn:1". Note that for
most operations the default resolves a single parent, as there usually
are no newer snapshots, and all "sro:1 sao:1 aro:1" resolve to the
same snapshot.
Example: "defaults,sao,san,aro,arn" takes the defaults, and adds clone
sources for all (!) known candidates on the filesystem.
--
*incremental_clones* yes|no::
If enabled, btrbk adds "-c <clone-src>" to the btrfs-send(8)
command for all correlated subvolumes resolved by
'incremental_prefs'. If disabled, only "-p <parent>" is
used. Defaults to ``yes''.
*incremental_resolve* mountpoint|directory::
Specifies where to search for the best common parent for
incremental backups. If set to ``mountpoint'', use parents in the
filesystem tree below mount points of source
"<volume-directory>/<snapshot-dir>" and target
"<target-directory>". If set to ``directory'', use parents
strictly below source/target directories. Set this to
``directory'' if you get access problems (when not running btrbk
as root). Defaults to ``mountpoint''.
filesystem tree below the mount point of the snapshot and target
directory. If set to ``directory'', use parents strictly below
snapshot/target directories. Set this to ``directory'' if you get
access problems (when not running btrbk as root). Defaults to
``mountpoint''.
*btrfs_commit_delete* yes|no::
If set, wait for the transaction commit at the end of each
snapshot or backup deletion (sets '--commit-each' option for
"btrfs subvolume delete"). Defaults to ``no''.
*send_protocol* <number>|no _*experimental*_::
Use btrfs send protocol version N. If enabled on 'target', btrbk
adds "--proto <number>" to the btrfs-send(8) command. Defaults to
``no'' (btrfs default).
*send_compressed_data* yes|no _*experimental*_::
Send data that is compressed on the filesystem directly without
decompressing it. This requires protocol version 2 or higher
(btrfs-progs >= 5.19), and implies "send_protocol 2". If enabled
on 'target', btrbk adds "--compressed-data" to the btrfs-send(8)
command. Defaults to ``no'' (btrfs default).
*snapshot_qgroup_destroy* yes|no _*experimental*_:: {blank}
*target_qgroup_destroy* yes|no _*experimental*_:: {blank}
@ -451,30 +505,39 @@ If you want to set this option for regular (non-root) user only, set
<https://bugzilla.kernel.org/show_bug.cgi?id=91751>
=== Informative Options
*warn_unknown_targets* yes|no::
If set, prints a warning if btrbk encounters a target subvolume at
a unknown location (i.e. not following btrbk naming scheme, or
outside the target directory). Defaults to ``no''.
RETENTION POLICY
----------------
btrbk uses separate retention policies for snapshots and backups,
which are defined by the 'snapshot_preserve_min', 'snapshot_preserve',
'target_preserve_min', 'target_preserve', 'preserve_day_of_week' and
'preserve_hour_of_day' configuration options.
Retention policies are defined individually for snapshots, backups and
archives (summarized as "backups" in the following text), using a
combination of:
Within this section, any statement about "backups" is always valid for
backups as well as snapshots, referring to 'target_preserve' or
'snapshot_preserve' respectively.
**_preserve_min* all|latest|no|<number>{h,d,w,m,y}::
Amount of time (duration) in which all backups are preserved.
**_preserve* no|<retention_policy>::
Schedule (single points in time) for which individual backups are
preserved.
Note that if "preserve_min" is set to ``all'' (the default), any
setting of "preserve" obviously has no effect.
The format for '<retention_policy>' is:
[<hourly>h] [<daily>d] [<weekly>w] [<monthly>m] [<yearly>y]
With the following semantics:
*hourly*::
Defines how many hours back hourly backups should be
preserved. The first backup of an hour is considered an hourly
backup. Note that if you use <hourly> scheduling, make sure to
also set 'timestamp_format' to ``long'' or ``long-iso'', or the
scheduler will interpret the time as "00:00" (midnight).
backup.
*daily*::
Defines how many days back daily backups should be preserved. The
@ -501,29 +564,31 @@ Use an asterisk for ``all'' (e.g. "target_preserve 60d *m"
states: "preserve daily backups for 60 days back, and all monthly
backups").
The reference time (which defines the beginning of a day, week, month
or year) for all date/time calculations is the local time of the host
running btrbk.
Hint: Run btrbk with the '-S', '--print-schedule' option to get a
comprehensive output of the scheduler results.
Caveats:
* If you run a setup with several btrbk instances (e.g. one
snapshot-only instance per remote client, and a separate fetch-only
instance on the backup server), it makes perfectly sense to run
btrbk with different local time on the clients, in order to make
sure the backups from all the remote hosts are preserved for
"midnight", and not at "00:00 UTC" (which would be "14:00" in
Honolulu). If you want this behavior, do NOT use "timestamp_format
long-iso".
=== Reference Time
* If "timestamp_format long-iso" is set, running btrbk from different
time zones leads to different interpretation of "first in day, week,
month, or year". Make sure to run btrbk with the same time zone on
every host, e.g. by setting the TZ environment variable (see
tzset(3)).
The local time on the host running btrbk defines the reference time
for all date/time calculations, especially for "beginning of a day",
and as a consequence for the first daily, weekly, monthly or yearly
backups. The local time on remote hosts (ssh source/target) is never
used.
Unless "timestamp_format long-iso" is set, daily backups are preserved
at "preserve_hour_of_day" (defaults to midnight) of the respective
time zone (and not for "00:00 UTC", which would be "14:00" in
Honolulu). This becomes relevant for setups with multiple btrbk
instances, e.g. many snapshot-only instances (spread around the
world), and a fetch-only instance on the backup server.
Caveat:
* If "timestamp_format long-iso" is set, each btrbk instance on has a
different interpretation of "first in day". Make sure to run btrbk
with the same time zone on every host, e.g. by setting the TZ
environment variable (see tzset(3)).
TARGET TYPES
@ -532,24 +597,19 @@ TARGET TYPES
*send-receive*::
Backup to a btrfs filesystem, using "btrfs send/receive". This is
the recommended (standard) target type. The '<target-directory>'
must be an absolute path and point to a btrfs volume (or
subvolume), or to a directory within a subvolume. See
btrfs-send(8), btrfs-receive(8).
must be an absolute path and point to a subvolume or directory
within a btrfs file system. See btrfs-send(8), btrfs-receive(8).
*raw* _*experimental*_::
Backup to a raw (filesystem independent) file from the output of
btrfs-send(8), with optional compression and encryption.
+
--
Note that the target preserve mechanism is currently disabled for
incremental raw backups (btrbk does not delete any incremental raw
files)!
Raw backups consist of two files: the main data file containing the
btrfs send stream, and a sidecar file ".info" containing metadata:
<snapshot-name>.<timestamp>[_N].btrfs[.gz|.bz2|.xz][.gpg]
<snapshot-name>.<timestamp>[_N].btrfs[.gz|.bz2|.xz][.gpg].info
<snapshot-name>.<timestamp>[_N].btrfs[.gz|.bz2|...][.gpg]
<snapshot-name>.<timestamp>[_N].btrfs[.gz|.bz2|...][.gpg].info
For 'incremental' backups ("incremental yes"), please note that:
@ -560,6 +620,11 @@ For 'incremental' backups ("incremental yes"), please note that:
make sure that a non-incremental backup is triggered from time to
time.
* The scheduler will never delete dependent parents of backups
preserved by the retention policy (run btrbk with the '-S',
'--print-schedule' option to get a comprehensive output of the
scheduler results).
* There is currently no support for rotation of incremental backups:
if 'incremental' is set, a full backup must be triggered manually
from time to time in order to be able to delete old backups.
@ -569,8 +634,8 @@ Additional options for raw targets:
*raw_target_compress* <compress_command>|no::
Compression algorithm to use for raw backup target. Supported
'<compress_command>': gzip, pigz, bzip2, pbzip2, xz, lzo, lz4,
zstd.
'<compress_command>': gzip, pigz, bzip2, pbzip2, bzip3, xz, lzo,
lz4, zstd.
*raw_target_compress_level* default|<number>::
Compression level for the specified <compress_command>.
*raw_target_compress_long* default|<number>::
@ -591,7 +656,7 @@ Additional options for "raw_target_encrypt gpg":
*gpg_keyring* <file>::
Keyring to use for gpg, e.g. "`/etc/btrbk/gpg/pubring.kbx`".
*gpg_recipient* <name>::
*gpg_recipient* <name>...::
Encrypt for user id '<name>' (email address).

View File

@ -9,16 +9,18 @@ file, choose one of the following methods:
### Generic Linux System
Install [asciidoctor] or [asciidoc] if you want to build the
documentation.
Download and unpack the latest [btrbk source tarball] and type:
sudo make install
#### Try latest master from Github:
### Gentoo Linux
btrbk is in portage:
emerge app-backup/btrbk
wget https://raw.githubusercontent.com/digint/btrbk/master/btrbk
chmod +x btrbk
sudo ./btrbk ls /
### Debian Based Distros
@ -30,7 +32,7 @@ Packages are also available via NeuroDebian: http://neuro.debian.net/pkgs/btrbk.
### Fedora Linux
btrbk is in the official Fedora repos: https://apps.fedoraproject.org/packages/btrbk
btrbk is in the official Fedora repos: https://src.fedoraproject.org/rpms/btrbk
sudo dnf install btrbk
@ -47,6 +49,13 @@ btrbk is in the community repository
apk add btrbk
### Gentoo Linux
btrbk is in portage:
emerge app-backup/btrbk
### Void Linux
btrbk is in Void's `current` repository
@ -55,3 +64,5 @@ btrbk is in Void's `current` repository
[btrbk source tarball]: https://digint.ch/download/btrbk/releases/
[asciidoctor]: https://asciidoctor.org
[asciidoc]: https://asciidoc.org

View File

@ -1,7 +1,7 @@
lsbtr(1)
========
:date: 2021-03-21
:release-version: 0.31.2
:date: 2023-03-25
:release-version: 0.32.6
:man manual: Btrbk Manual
:man source: Btrbk {release-version}
@ -17,11 +17,12 @@ SYNOPSIS
[verse]
lsbtr [-h|--help] [--version]
[-l|--long] [-u|--uuid] [--raw]
[-l|--long] [-u|--uuid] [-1|--single-column] [--raw]
[--format <output-format>]
[-v|--verbose]
[-c|--config <file>]
[--override <config_option>=<value>]
[<path>|<url>...]
[[--] <path>|<url>...]
DESCRIPTION
@ -55,9 +56,21 @@ OPTIONS
-u, --uuid::
Print UUID table (parent/received relations).
-1, --single-column::
Print path column only (delimited by newline).
--raw::
Print space-separated key="value" pairs (machine readable).
--format table|long|raw|col:[h:]<columns>::
Print output in specified format. If set to "raw", prints
space-separated key="value" pairs (machine readable).
+
If set to "col:", prints only the <columns> specified (comma-separated
list). Header lines are omitted if the "h:" modifier is present.
Columns prefixed with "-" are collapsed if empty. Columns postfixed
with ":RALIGN" are right-aligned.
-v, --verbose::
Increase the level of verbosity.

View File

@ -1,7 +1,7 @@
ssh_filter_btrbk(1)
===================
:date: 2021-03-21
:release-version: 0.31.2
:date: 2023-03-25
:release-version: 0.32.6
:man manual: Btrbk Manual
:man source: Btrbk {release-version}
@ -39,13 +39,13 @@ The following commands are always allowed:
- "readlink"
- "test -d" (only if "compat busybox" configuration option is set)
- "cat /proc/self/mountinfo"
- pipes through "gzip", "pigz", "bzip2", "pbzip2", "xz", "lzop",
"lz4", "zstd" (stream_compress)
- pipes through "gzip", "pigz", "bzip2", "pbzip2", "bzip3", "xz",
"lzop", "lz4", "zstd" (stream_compress)
- pipes through "mbuffer" (stream_buffer, rate_limit)
Example line in /root/.ssh/authorized_keys on a backup target host:
command="ssh_filter_btrbk.sh --target --delete --restrict-path /mnt/btr_backup" ssh-rsa AAAAB3NzaC1...hwumXFRQBL btrbk@mydomain.com
command="ssh_filter_btrbk.sh --target --delete --restrict-path /mnt/btr_backup",restrict ssh-rsa AAAAB3NzaC1...hwumXFRQBL btrbk@example.org
OPTIONS
@ -82,6 +82,11 @@ OPTIONS
-p, --restrict-path <path>::
Restrict commands to <path>. Note that "btrfs subvolume show",
"btrfs subvolume list" are NOT affected by this option.
+
It is not possible to restrict commands to exact subvolume names, as
btrfs-receive(8) takes a <path> as argument (directory, not including
the subvolume file name to be created, this is encoded in the
send-stream).
-l, --log::
Log ACCEPT and REJECT messages to the system log.

View File

@ -1,92 +0,0 @@
Upgrading to btrbk-v0.23.0
==========================
In order to keep btrbk simple and intuitive while adding new features,
it became inevitable to change the semantics of the "retention policy"
related configuration options.
What has changed?
-----------------
### Preserve *first* instead of *last* snapshot/backup
btrbk used to *always* transfer the latest snapshot to the target
location, while considering the *last* snapshot/backup of a day as a
daily backup (and also the last weekly as a monthly). This made it
very cumbersome when running btrbk in a cron job as well as manually,
because the last manually created snapshot was immediately transferred
on every run, and used as the daily backup (instead of the one created
periodically by the cron job).
The new semantics are to consider the *first* (instead of *last*)
snapshot of a hour/day/week/month as the one to be preserved, while
only transferring the snapshots needed to satisfy the target retention
policy.
### Preserve snapshots for a minimum amount of time
In order to specify a minimum amount of time in which *all* snapshots
should be preserved, the new "snapshot_preserve_min" and
"target_preserve_min" configuration options were introduced. This was
previously covered by "snapshot_preserve_daily", which caused a lot of
confusion among users.
Upgrading the configuration file: /etc/btrbk/btrbk.conf
-------------------------------------------------------
Please read the description of the "run" command in [btrbk(1)], as
well as the "RETENTION POLICY" section in [btrbk.conf(5)] for a
detailed description. Make sure to understand the new concept, and run
`btrbk --print-schedule dryrun` after updating the configuration.
### Upgrade retention policy
If you want the same behaviour as before:
# replace this:
snapshot_preserve_daily <daily>
snapshot_preserve_weekly <weekly>
snapshot_preserve_monthly <monthly>
# with:
snapshot_preserve_min <daily>d
snapshot_preserve <weekly>w <monthly>m
# ... do the same with "target_preserve_*" options
But what you probably want is something like:
snapshot_preserve_min 5d
snapshot_preserve <daily>d <weekly>w <monthly>m
target_preserve_min no
target_preserve <daily>d <weekly>w <monthly>m *y
This states:
* Keep all snapshots for five days (no matter how many there are)
* Transfer only the first snapshot of a day to the target
* Keep all "first snapshots of a day" for `<daily>` days, etc.
### Upgrade "resume_missing"
If you have a line: "resume_missing yes" somwhere in your config,
simply remove it. btrbk always resumes missing backups.
If you have "resume_missing no", you can imitate this behaviour by
setting:
target_preserve_min latest
target_preserve no
This states: "always transfer the latest snapshot to the target".
[btrbk(1)]: https://digint.ch/btrbk/doc/btrbk.1.html
[btrbk.conf(5)]: https://digint.ch/btrbk/doc/btrbk.conf.5.html

View File

@ -1,9 +1,11 @@
#!/bin/bash
#!/bin/sh
set -e
set -u
# initialise and sanitise the shell execution environment
unset -v IFS
export LC_ALL=C
export PATH='/sbin:/bin:/usr/sbin:/usr/bin'
export PATH=/sbin:/bin:/usr/sbin:/usr/bin
set -e -u
enable_log=
restrict_path_list=
@ -12,55 +14,70 @@ allow_exact_list=
allow_rate_limit=1
allow_stream_buffer=1
allow_compress=1
compress_list="gzip|pigz|bzip2|pbzip2|xz|lzop|lz4|zstd"
compress_list='gzip|pigz|bzip2|pbzip2|bzip3|xz|lzop|lz4|zstd'
# note that the backslash is NOT a metacharacter in a POSIX bracket expression!
option_match='-[a-zA-Z0-9=-]+' # matches short as well as long options
file_match='[0-9a-zA-Z_@+./-]*' # matches file path (equal to $file_match in btrbk)
file_match_sane='/[0-9a-zA-Z_@+./-]*' # matches file path (equal to ${file_match} in btrbk < 0.32.0)
file_match="/[^']*" # btrbk >= 0.32.0 quotes file arguments: match all but single quote
file_arg_match="('${file_match}'|${file_match_sane})" # support btrbk < 0.32.0
log_cmd()
{
if [[ -n "$enable_log" ]]; then
logger -p $1 -t ssh_filter_btrbk.sh "$2 (Name: ${LOGNAME:-<unknown>}; Remote: ${SSH_CLIENT:-<unknown>})${3:+: $3}: $SSH_ORIGINAL_COMMAND"
local priority="$1"
local authorisation_decision="$2"
local reason="${3-}"
if [ -n "${enable_log}" ]; then
logger -p "${priority}" -t ssh_filter_btrbk.sh "${authorisation_decision} (Name: ${LOGNAME:-<unknown>}; Connection: ${SSH_CONNECTION:-<unknown>})${reason:+: ${reason}}: ${SSH_ORIGINAL_COMMAND}"
fi
}
allow_cmd()
{
allow_list="${allow_list}|$1"
local cmd="$1"
allow_list="${allow_list}|${cmd}"
}
allow_exact_cmd()
{
allow_exact_list="${allow_exact_list}|$1"
local cmd="$1"
allow_exact_list="${allow_exact_list}|${cmd}"
}
reject_and_die()
{
local reason=$1
log_cmd "auth.err" "btrbk REJECT" "$reason"
echo "ERROR: ssh_filter_btrbk.sh: ssh command rejected: $reason: $SSH_ORIGINAL_COMMAND" 1>&2
local reason="$1"
log_cmd 'auth.err' 'btrbk REJECT' "${reason}"
printf 'ERROR: ssh_filter_btrbk.sh: ssh command rejected: %s: %s\n' "${reason}" "${SSH_ORIGINAL_COMMAND}" >&2
exit 255
}
run_cmd()
{
log_cmd "auth.info" "btrbk ACCEPT"
eval " $SSH_ORIGINAL_COMMAND"
log_cmd 'auth.info' 'btrbk ACCEPT'
eval " ${SSH_ORIGINAL_COMMAND}"
}
reject_filtered_cmd()
{
if [[ -n "$restrict_path_list" ]]; then
# match any of restrict_path_list with or without trailing slash,
if [ -n "${restrict_path_list}" ]; then
# match any of restrict_path_list,
# or any file/directory (matching file_match) below restrict_path
path_match="(${restrict_path_list})(/${file_match})?"
path_match="'(${restrict_path_list})(${file_match})?'"
path_match_legacy="(${restrict_path_list})(${file_match_sane})?"
else
# match any absolute file/directory (matching file_match)
path_match="/${file_match}"
path_match="'${file_match}'"
path_match_legacy="${file_match_sane}"
fi
# btrbk >= 0.32.0 quotes files, allow both (legacy)
path_match="(${path_match}|${path_match_legacy})"
if [[ -n "$allow_compress" ]]; then
if [ -n "${allow_compress}" ]; then
decompress_match="(${compress_list}) -d -c( -[pT][0-9]+)?"
compress_match="(${compress_list}) -c( -[0-9])?( -[pT][0-9]+)?"
else
@ -70,8 +87,8 @@ reject_filtered_cmd()
# rate_limit_remote and stream_buffer_remote use combined
# "mbuffer" as of btrbk-0.29.0
if [[ -n "$allow_stream_buffer" ]] || [[ -n "$allow_rate_limit" ]]; then
mbuffer_match="mbuffer -v 1 -q( -s [0-9]+[kmgKMG]?)?( -m [0-9]+[kmgKMG]?)?( -[rR] [0-9]+[kmgtKMGT]?)?"
if [ -n "${allow_stream_buffer}" ] || [ -n "${allow_rate_limit}" ]; then
mbuffer_match='mbuffer -v 1 -q( -s [0-9]+[kmgKMG]?)?( -m [0-9]+[kmgKMG]?)?( -[rR] [0-9]+[kmgtKMGT]?)?'
else
mbuffer_match=
fi
@ -81,35 +98,44 @@ reject_filtered_cmd()
stream_in_match="(${decompress_match} \| )?(${mbuffer_match} \| )?"
stream_out_match="( \| ${mbuffer_match})?( \| ${compress_match}$)?"
# `grep`s `-q`-option is not used as it may cause an exit status of `0` even
# when an error occurred.
allow_stream_match="^${stream_in_match}${allow_cmd_match}${stream_out_match}"
if [[ $SSH_ORIGINAL_COMMAND =~ $allow_stream_match ]] ; then
if printf '%s' "${SSH_ORIGINAL_COMMAND}" | grep -E "${allow_stream_match}" >/dev/null 2>/dev/null; then
return 0
fi
exact_cmd_match="^(${allow_exact_list})$";
if [[ $SSH_ORIGINAL_COMMAND =~ $exact_cmd_match ]] ; then
if printf '%s' "${SSH_ORIGINAL_COMMAND}" | grep -E "${exact_cmd_match}" >/dev/null 2>/dev/null; then
return 0
fi
reject_and_die "disallowed command${restrict_path_list:+ (restrict-path: \"${restrict_path_list//|/\", \"}\")}"
local formatted_restrict_path_list="$(printf '%s' "${restrict_path_list}" | sed 's/|/", "/g')"
reject_and_die "disallowed command${restrict_path_list:+ (restrict-path: \"${formatted_restrict_path_list}\")}"
}
# check for "--sudo" option before processing other options
sudo_prefix=
for key; do
[[ "$key" == "--sudo" ]] && sudo_prefix="sudo -n "
for key in "$@"; do
if [ "${key}" = '--sudo' ]; then
sudo_prefix='sudo -n '
fi
if [ "${key}" = '--doas' ]; then
sudo_prefix='doas -n '
fi
done
while [[ "$#" -ge 1 ]]; do
while [ "$#" -ge 1 ]; do
key="$1"
case $key in
case "${key}" in
-l|--log)
enable_log=1
;;
--sudo)
--sudo|--doas)
# already processed above
;;
@ -154,7 +180,7 @@ while [[ "$#" -ge 1 ]]; do
;;
*)
echo "ERROR: ssh_filter_btrbk.sh: failed to parse command line option: $key" 1>&2
printf 'ERROR: ssh_filter_btrbk.sh: failed to parse command line option: %s\n' "${key}" >&2
exit 255
;;
esac
@ -163,19 +189,21 @@ 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_exact_cmd "${sudo_prefix}btrfs subvolume (show|list)( ${option_match})* ${file_arg_match}";
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
allow_exact_cmd "${sudo_prefix}test -d ${file_arg_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#\|}
allow_exact_list=${allow_exact_list#\|}
restrict_path_list=${restrict_path_list#\|}
allow_list="${allow_list#\|}"
allow_exact_list="${allow_exact_list#\|}"
restrict_path_list="${restrict_path_list#\|}"
case "$SSH_ORIGINAL_COMMAND" in
case "${SSH_ORIGINAL_COMMAND}" in
*\.\./*) reject_and_die 'directory traversal' ;;
*'
'*) reject_and_die 'unsafe character LF' ;;
*\$*) reject_and_die 'unsafe character "$"' ;;
*\&*) reject_and_die 'unsafe character "&"' ;;
*\(*) reject_and_die 'unsafe character "("' ;;
@ -184,7 +212,7 @@ case "$SSH_ORIGINAL_COMMAND" in
*\<*) reject_and_die 'unsafe character "<"' ;;
*\>*) reject_and_die 'unsafe character ">"' ;;
*\`*) reject_and_die 'unsafe character "`"' ;;
*\|*) [[ -n "$allow_compress" ]] || [[ -n "$allow_rate_limit" ]] || [[ -n "$allow_stream_buffer" ]] || reject_and_die 'unsafe character "|"' ;;
*\|*) [ -n "${allow_compress}" ] || [ -n "${allow_rate_limit}" ] || [ -n "${allow_stream_buffer}" ] || reject_and_die 'unsafe character "|"' ;;
esac
reject_filtered_cmd