This is yet another btrfs snapshotting program. Ever since I’ve been using btrfs as the filesystem of my daily driver, I took advantage of the main feature of btrfs: (almost) instantaneous snapshots. I created them through timeshift, then I eventually switched to snapper, never realizing that btrfs-progs already ships with a pretty usable snapshotting utility itself. The advantage of btrfs-progs over timeshift or snapper, is that it leaves decisions to the user and doesn’t impose specific filesystem configurations or naming conventions. Over the time, I accumulated several bash scripts wrapping these utility functions, most of which I used to run as cron jobs.
This is a unified re-write of these separate functions into a proper
framework unimaginatively called btrsnap
. It imposes my
configuration as defaults, but integrates environment variables and a
configuration file, giving the user the option to fully customize to
any setup. Moreover, it provides systemd service and timer templates
which can be used to run timed and automated snapshots.
Install btrsnap
using
sudo make install
This will install the script to /usr/local/bin/
which should already
be in your PATH.
Alternatively you can run
PREFIX=/path/of/your/choice make install
which might need sudo priviliges depending on your choice. Don’t forget to add the chosen prefix to your PATH.
In case you’re running on systemd
(I have no opinions on the matter,
and I’m not interested in discussions about it) and you want to
automate btrsnap, use
sudo btrsnap gentemp / root --delay 0
or for snapshotting your home directories
sudo btrsnap gentemp /home home --delay 10
These commands create a directory services
and
btrsnap-root@.service
and btrsnap-home@.service
with corresponding
btrsnap-*@.timer
templates within.
They can be installed with
sudo make install-services
which copies the service files and their corresponding timers to
/etc/systemd/system/
.
Services can then be timed with e.g.
sudo systemctl enable --now btrsnap-root@weekly.timer
which will run weekly snapshots of your root subvolume. You can also enable the following timers:
btrsnap-root@hourly.timer
btrsnap-root@daily.timer
btrsnap-root@monthly.timer
btrsnap-root@yearly.timer
- analogously for other service templates
These service templates enable you to periodically snapshot your root
subvolume mounted at /
(or in case of btrsnap-home@.service
to
snapshot /home
). If you have a different setup simply add analogous
files with your specifications using btrsnap-gentemp
.
Note that to avoid any issues with deadlocks due to simultaneously
writing to the log files, it is advisable to choose different delays
for different btrsnap tasks using the --delay
flag.
To uninstall btrsnap
(from any location) and installed btrsnap
services and timers, simply run
sudo make uninstall
btrsnap
has several subcommands which can be inspected using
sudo btrsnap help
Usage: sudo btrsnap <subcommand> [options]
Subcommands:
e(nv)
- Print all environment variables
l(i)[s](t) [options] [source]
- List all snapshots (and updates logs)
i(nfo) [options] [snapshot]
- Print info about a specific snapshot (wrapper for btrfs subvol show)
c(reate) [options] [source] [target]
- Create a snapshot in the target directory
r(e)m(ove) [options] [snapshot]
- Delete specific snapshots
d(iff) [options] [snapshot-a] [snapshot-b]
- Show diffs between two snapshots
u(ndo) <file> [snapshot]
- Undo changes to a specific file from a snapshot
r(estore) [options] [snapshot] [subvolume]
- Restore the filesystem to a former snapshot
s(crub) [options] [source]
- Scrub the oldest snapshots above the limits
g(en)t(emp) [options] [source] [target]
- Generate systemd service and timer templates
For help with each subcommand run:
btrsnap <subcommand> -h|--help
The current basedir for btrsnap is BTRSNAP_BASEDIR=/snapshots
If arguments are given as relative paths, the BTRSNAP_BASEDIR variable
is used as base path, otherwise it is ignored.
btrsnap configuration and logs are in
- .btrsnap/btrsnap.conf
- .btrsnap/btrsnap.log
The most frequently used command would probably be
sudo btrsnap create / /snapshots/root
which saves a snapshot of the root subvolume mounted at /
to
/snapshots/root/%y%m%dT%H:%M:%S.%2N
(this happens to be the default
which is why sudo btrsnap c
yields the same result).
You can also add a different name format and some description to the snapshot with
sudo btrsnap c -f special / /mydata/special_dir -m "A really special snapshot"
This saves the snapshot of /
to /mydata/special_dir/special
.
All snapshots, their most important attributes, and their description can be inspected using
sudo btrsnap ls
# Snapshot Source Time Flags Mode Description
1 /snapshots/root/220418T22:31:23.37 / 22-04-18 22:31:23.37 +0200 r manual
2 /mydata/special_dir/special / 22-04-19 22:32:01.68 +0200 r manual A really special snapshot
If at any point you decide to delete a snapshot, use
sudo btrsnap rm /mydata/special_dir/special
You can also select snapshots by index
sudo btrsnap rm 2
or since in this case it is the latest snapshot
sudo btrsnap rm -1
btrsnap
works with modes and limit parameters (which of course can
be reconfigured). Each mode has different limit defaults:
- manual: 12
- hourly: 4
- daily: 3
- weekly: 6
- monthly: 4
- yearly: 1
The scrub
subcommand enforces these limits and deletes the oldest
snapshots when the number of snapshots with that mode is exceeded.
For instance,
sudo btrsnap scrub /
clears all snapshots of root with all modes.
sudo btrsnap scrub --mode hourly
clears all snapshots taken in ‘hourly’ mode regardless of its source.
btrsnap
integrates with environment variables and configuration
files. In case you don’t want to change the program’s source code
itself, add
export BTRSNAP_CONF=/snapshots/.btrsnap/btrsnap.conf~
to your .bashrc
or .zshrc
. In the configuration file you can
define your own default values for
BTRSNAP_BASEDIR="/snapshots"
BTRSNAP_LOG=".$PROGNAME/$PROGNAME.log"
BTRSNAP_SRC='/'
BTRSNAP_TARGET="root"
BTRSNAP_MODE="manual"
BTRSNAP_WRITABLE=0
BTRSNAP_TIMEFORMAT="+%y%m%dT%H:%M:%S.%2N"
BTRSNAP_WARNINGS=1
BTRSNAP_MANUAL_LIMIT=12
BTRSNAP_MONTHLY_LIMIT=4
BTRSNAP_WEEKLY_LIMIT=3
BTRSNAP_DAILY_LIMIT=6
BTRSNAP_HOURLY_LIMIT=4
BTRSNAP_YEARLY_LIMIT=1
DRY_RUN=0
VERBOSE=0
Note, for now, snapshots have to reside on the same btrfs device.
- [ ] btrsnap-remove: * w/ mode selection
- [ ] compatibility with external devices/drives (for external devices you need to manually use btrfs send/receive and `btrfs property set` ro to false)
- [ ] pacman hooks to automatically run btrsnap on installs or upgrades