commit 94710167395197879bb0004e0c05b5ca915c9eb7 Author: Willi Mutschler Date: Wed Apr 29 09:59:11 2020 +0200 Initial fork of timeshift-autosnap Forked timeshift-autosnap to work in Ubuntu-based distros, updated README and LICENSE diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..275c9d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ + +\.directory + +aur/ diff --git a/80-timeshift-autosnap-apt b/80-timeshift-autosnap-apt new file mode 100644 index 0000000..dfab674 --- /dev/null +++ b/80-timeshift-autosnap-apt @@ -0,0 +1 @@ +DPkg::Pre-Invoke {"/usr/bin/timeshift-autosnap-apt"; }; diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..6659f14 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2019 gobonja +Copyright (c) 2020 Willi Mutschler (wmutschl, willi@mutschler.eu) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..81b84af --- /dev/null +++ b/README.md @@ -0,0 +1,148 @@ +# timeshift-autosnap-apt +Timeshift auto-snapshot script which runs before `apt upgrade|install|remove` using a `DPkg::Pre-Invoke` hook in apt. + +## Features +* This scrips is a fork of [timeshift-autosnap](https://gitlab.com/gobonja/timeshift-autosnap) from the [AUR](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=timeshift-autosnap) for Arch and Arch based distros but adapted for usage in Debian based systems which use apt as their package manager. +* Creates [Timeshift](https://github.com/teejee2008/timeshift) snapshots with unique comment. +* Deletes old snapshots which are created using this script. +* Can be manually executed by running `sudo timeshift-autosnap-apt` command. +* Autosnaphot can be temporarily skipped by setting SKIP_AUTOSNAP environment variable (e.g. `sudo SKIP_AUTOSNAP= apt upgrade`) +* Supports both `BTRFS` and `RSYNC` mode. +* For a tutorial how to use this script in production to easily rollback your system, see [Pop!_OS 20.04 btrfs-luks disaster recovery and easy system rollback using Timeshift and timeshift-autosnap-apt](https://mutschler.eu/linux/install-guides/pop-os-btrfs-recovery/). + +## Installation +If you haven't, first install Timeshift: +```bash +sudo apt install timeshift +``` +Open Timeshift and configure it either using btrfs or rsync. I recommend using btrfs as a filesystem for this, see my [btrfs installation guides](https://mutschler.eu/linux/install-guides/) for Pop!_OS, Ubuntu, and Manjaro. + +Clone the repository and run the following commands to copy the hook, bash script and configuration file. +```bash +git clone https://github.com/wmutschl/timeshift-autosnap-apt.git +cd timeshift-autosnap-apt +sudo cp 80-timeshift-autosnap-apt /etc/apt/apt.conf.d/80-timeshift-autosnap-apt +sudo chmod 644 /etc/apt/apt.conf.d/80-timeshift-autosnap-apt +sudo cp timeshift-autosnap-apt /usr/bin/timeshift-autosnap-apt +sudo chmod 755 /usr/bin/timeshift-autosnap-apt +sudo cp timeshift-autosnap-apt.conf /etc/timeshift-autosnap-apt.conf +sudo chmod 644 /etc/timeshift-autosnap-apt.conf +``` +After this, optionally, make changes to the configuration file: +```bash +sudo nano /etc/timeshift-autosnap-apt.conf +``` + +## Configuration +The configuration file is located in `/etc/timeshift-autosnap-apt.conf`. You can set the following options: +* `skipAutosnap`: If set to **true** script won't be executed. Default: **false**. +* `deleteSnapshots`: If set to **false** old snapshots won't be deleted. Default: **true** +* `maxSnapshots`: Defines **maximum** number of old snapshots to keep. Default: **3** +* `snapshotDescription` Defines **value** used to distinguish snapshots created using timeshift-autosnap-apt. Default: **{timeshift-autosnap-apt} {created before upgrade}** + + +## Test functionality +To test the functionality, try (re)installing some package `maxSnapshots` number of times, e.g. +```bash +sudo apt install --reinstall rolldice +sudo apt install --reinstall rolldice +sudo apt install --reinstall rolldice +``` +You should see output for BTRFS similar to +```bash +# Using system disk as snapshot device for creating snapshots in BTRFS mode +# +# /dev/dm-1 is mounted at: /run/timeshift/backup, options: rw,relatime,compress=zstd:3,ssd,space_cache,commit=120,subvolid=5,subvol=/ +# +# Creating new backup...(BTRFS) +# Saving to device: /dev/dm-1, mounted at path: /run/timeshift/backup +# Created directory: /run/timeshift/backup/timeshift-btrfs/snapshots/2020-04-29_09-46-30 +# Created subvolume snapshot: /run/timeshift/backup/timeshift-btrfs/snapshots/2020-04-29_09-46-30/@ +# Created subvolume snapshot: /run/timeshift/backup/timeshift-btrfs/snapshots/2020-04-29_09-46-30/@home +# Created control file: /run/timeshift/backup/timeshift-btrfs/snapshots/2020-04-29_09-46-30/info.json +# BTRFS Snapshot saved successfully (0s) +# Tagged snapshot '2020-04-29_09-46-30': ondemand +# -------------------------------------------------------------------------- +``` +or for RSYNC similar to +```bash +# /dev/vdb1 is mounted at: /run/timeshift/backup, options: rw,relatime +# ------------------------------------------------------------------------------ +# Creating new snapshot...(RSYNC) +# Saving to device: /dev/vdb1, mounted at path: /run/timeshift/backup +# Synching files with rsync... +# Created control file: /run/timeshift/backup/timeshift/snapshots/2020-04-29_10-25-35/info.json +# RSYNC Snapshot saved successfully (6s) +# Tagged snapshot '2020-04-29_10-25-35': ondemand +------------------------------------------------------------------------------ +``` + +Open timeshift and see whether there are `maxSnapshots` packages: +![Timeshift](timeshift-autosnap-apt.png) + +Close timeshift and reinstall the package another time and you should see that the first package is now deleted: +```bash +sudo apt install --reinstall rolldice +# +# Using system disk as snapshot device for creating snapshots in BTRFS mode +# /dev/dm-1 is mounted at: /run/timeshift/backup, options: rw,relatime,compress=zstd:3,ssd,space_cache,commit=120,subvolid=5,subvol=/ +# Creating new backup...(BTRFS) +# Saving to device: /dev/dm-1, mounted at path: /run/timeshift/backup +# Created directory: /run/timeshift/backup/timeshift-btrfs/snapshots/2020-04-29_09-53-25 +# Created subvolume snapshot: /run/timeshift/backup/timeshift-btrfs/snapshots/2020-04-29_09-53-25/@ +# Created subvolume snapshot: /run/timeshift/backup/timeshift-btrfs/snapshots/2020-04-29_09-53-25/@home +# Created control file: /run/timeshift/backup/timeshift-btrfs/snapshots/2020-04-29_09-53-25/info.json +# BTRFS Snapshot saved successfully (0s) +# Tagged snapshot '2020-04-29_09-53-25': ondemand +# ------------------------------------------------------------------------------ +# +# /dev/dm-1 is mounted at: /run/timeshift/backup, options: rw,relatime,compress=zstd:3,ssd,space_cache,commit=120,subvolid=5,subvol=/ +# +# ------------------------------------------------------------------------------ +# Removing snapshot: 2020-04-29_09-46-30 +# Deleting subvolume: @home (Id:662) +# Deleted subvolume: @home (Id:662) +# +# Destroying qgroup: 0/662 +# Destroyed qgroup: 0/662 +# +# Deleting subvolume: @ (Id:661) +# Deleted subvolume: @ (Id:661) +# +# Destroying qgroup: 0/661 +# Destroyed qgroup: 0/661 +# +# Deleted directory: /run/timeshift/backup/timeshift-btrfs/snapshots/2020-04-29_09-46-30 +# Removed snapshot: 2020-04-29_09-46-30 +# ------------------------------------------------------------------------------ +``` +or for RSYNC: + +```bash +# /dev/vdb1 is mounted at: /run/timeshift/backup, options: rw,relatime +# +# ------------------------------------------------------------------------------ +# Creating new snapshot...(RSYNC) +# Saving to device: /dev/vdb1, mounted at path: /run/timeshift/backup +# Linking from snapshot: 2020-04-29_10-25-15 +# Synching files with rsync... +# Created control file: /run/timeshift/backup/timeshift/snapshots/2020-04-29_10-25-35/info.json +# RSYNC Snapshot saved successfully (6s) +# Tagged snapshot '2020-04-29_10-25-35': ondemand +# ------------------------------------------------------------------------------ +# +# /dev/vdb1 is mounted at: /run/timeshift/backup, options: rw,relatime +# +# ------------------------------------------------------------------------------ +# Removing '2020-04-29_10-24-35'... +# Removed '2020-04-29_10-24-35' +# ------------------------------------------------------------------------------ +``` + +## Ideas and contributions +- [x] Ask to be included into official Timeshift package, [status pending](https://github.com/teejee2008/timeshift/issues/595). +- [ ] Add systemd-boot entry to boot into automatically generated snapshots (test on Pop!_OS) +- [ ] Add grub boot entry to boot into automatically generated snapshots, similar to ARCH package [grub-btrfs](https://github.com/Antynea/grub-btrfs) (test on Ubuntu) + +**All new ideas and contributors are welcomed, just open an issue for that!** + diff --git a/timeshift-autosnap-apt b/timeshift-autosnap-apt new file mode 100755 index 0000000..e77eb68 --- /dev/null +++ b/timeshift-autosnap-apt @@ -0,0 +1,57 @@ +#!/bin/bash +#original author: gobonja +#adapted for apt by Willi Mutschler (wmutschl) + +[ $(findmnt / -no fstype) == "overlay" ] && { echo "==> skipping timeshift-autosnap because system is booted in Live CD mode..."; exit 0; } + +[[ -v SKIP_AUTOSNAP ]] && { echo "==> skipping timeshift-autosnap due SKIP_AUTOSNAP environment variable being set."; exit 0; } + +readonly CONF_FILE=/etc/timeshift-autosnap-apt.conf +readonly SNAPSHOTS_TO_DELETE=$(mktemp -u --tmpdir ${0##*/}.XXXXXXXX) + +readonly SNAPSHOT_NAME_DATE_PATTERN="[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}_[0-9]\{2\}-[0-9]\{2\}-[0-9]\{2\}" + +get_property() { + if [ ! -f $CONF_FILE ]; then + echo "$CONF_FILE not found! Using $1=$3" >&2; + param_value=$3 + else + param_value=`sed '/^\#/d' $CONF_FILE | grep $1 | tail -n 1 |\ + cut -d "=" -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'` + + if ([ "$2" == "boolean" ] && [ "$param_value" != true ] && [ "$param_value" != false ]) || \ + ([ "$2" == "integer" ] && [[ ! "$param_value" =~ ^[-+]?([1-9][[:digit:]]*|1)$ ]]) || \ + ([ "$2" == "string" ] && [ "$param_value" == "" ]) ; then + echo "Wrong paramater in $CONF_FILE. Using $1=$3" >&2 + param_value=$3 + fi + fi + + echo $param_value +} + +if $(get_property "skipAutosnap" "boolean" "false") ; then + echo "==> skipping timeshift-autosnap-apt due skipAutosnap in $CONF_FILE set to TRUE." >&2; exit 0; +fi + +readonly SNAPSHOT_DESCRIPTION=$(get_property "snapshotDescription" "string" "{timeshift-autosnap-apt} {created before upgrade}") + +timeshift --create --comments "$SNAPSHOT_DESCRIPTION" || { echo "Unable to run timeshift-autosnap-apt! Please close Timeshift and try again. Script will now exit..." >&2; exit 1; } + +if $(get_property "deleteSnapshots" "boolean" "true") ; then + timeshift --list > $SNAPSHOTS_TO_DELETE + sed -ni "/$SNAPSHOT_DESCRIPTION/p" $SNAPSHOTS_TO_DELETE + sed -ni "s/.*\($SNAPSHOT_NAME_DATE_PATTERN\).*/\1/p" $SNAPSHOTS_TO_DELETE + + count=$(($(sed -n '$=' $SNAPSHOTS_TO_DELETE)-$(get_property "maxSnapshots" "integer" "3"))) + + if [ "$count" -gt 0 ] ; then + sed -i $(($count))q $SNAPSHOTS_TO_DELETE + + for snapshot in $(cat $SNAPSHOTS_TO_DELETE); do + timeshift --delete --snapshot $snapshot + done + fi +fi; + +exit 0 diff --git a/timeshift-autosnap-apt.conf b/timeshift-autosnap-apt.conf new file mode 100644 index 0000000..e6ebe71 --- /dev/null +++ b/timeshift-autosnap-apt.conf @@ -0,0 +1,20 @@ +# +# /etc/timeshift-autosnap.conf +# + +# skipAutosnap defines if timeshift-autosnap execution should be skipped. +# Default value is false. +skipAutosnap=false + +# deleteSnapshots defines if old snapshots should be deleted. +# Default value is true. +deleteSnapshots=true + +# maxSnapshots defines how much old snapshots script should left. +# Only positive whole numbers can be used. +# Default value is 3. +maxSnapshots=3 + +# snapshotDescription defines value used to distinguish snapshots created using timeshift-autosnap +# Default value is "{timeshift-autosnap} {created before upgrade}". +snapshotDescription={timeshift-autosnap-apt} {created before upgrade} diff --git a/timeshift-autosnap-apt.png b/timeshift-autosnap-apt.png new file mode 100644 index 0000000..9c9256d Binary files /dev/null and b/timeshift-autosnap-apt.png differ