SNAP-PAC(8) snap-pac SNAP-PAC(8)

snap-pac - Pacman hooks that use snapper to create pre/post btrfs snapshots like openSUSE's YaST

This is a set of pacman hooks and script that causes snapper to automatically take a pre and post snapshot before and after pacman transactions, similar to how YaST does with OpenSuse. This provides a simple way to undo changes to a system after a pacman transaction.

Because these are pacman hooks, it doesn't matter how you call pacman—whether directly, through an AUR helper, or using an alias—snapper will create the snapshots when pacman installs, upgrades, or removes a package. The pacman command used is logged in the snapper description for the snapshots. Additionally the snapshot numbers are output to the screen and to the pacman log for each snapper configuration during the pacman transaction, so that the user can easily find which changes he or she may want to revert.

When you run pacman, the snapper pre/post snapshots are created automatically. For a fuller example see Example.

$ sudo pacman -S vim
resolving dependencies...
looking for conflicting packages...
Packages (1) vim-8.2.2489-1
Total Installed Size:  3.79 MiB
Net Upgrade Size:      0.00 MiB
:: Proceed with installation? [Y/n]
(1/1) checking keys in keyring                     [############] 100%
(1/1) checking package integrity                   [############] 100%
(1/1) loading package files                        [############] 100%
(1/1) checking for file conflicts                  [############] 100%
(1/1) checking available disk space                [############] 100%
:: Running pre-transaction hooks...
(1/1) Performing snapper pre snapshots for the following configurations...
==> root: 7394
:: Processing package changes...
(1/1) installing vim                               [############] 100%
:: Running post-transaction hooks...
(1/4) Arming ConditionNeedsUpdate...
(2/4) Updating icon theme caches...
(3/4) Updating the desktop file MIME type cache...
(4/4) Performing snapper post snapshots for the following configurations...
==> root: 7395

To undo changes from a pacman transaction, use snapper undochange. See the snapper(8) for more details as well as examples.

If you have severe breakage—like snapper is gone for some reason and you can't get it back—you'll have to resort to more extreme methods, such as taking a snapshot of the pre snapshot and making it the default subvolume or mounting it as /. Most likely you'll need to use a live USB to get into a chroot environment to do any of these things. Snapper has a snapper rollback feature, but your setup has to be properly configured to use it. The exact procedure depends on your specific setup. Be careful.

Note that the pre transaction hooks occur before the pacman transaction but after the pacman database is synced, if applicable. In other words, if you run pacman -Syu and roll back the upgrade according to the above instructions, you will not have rolled back the pacman database to the previous state. Thus, if, after upgrading and rolling back the upgrade, you then install a package, it will possibly be a partial upgrade, which is unsupported.

Install the snap-pac package using pacman:

pacman -S snap-pac

Alternatively download the latest release and signature. Then, verify the download:

gpg --verify snap-pac-<version>.tar.gz.sig

where <version> is the version number you downloaded.

Finally, run:

make install

I have signed the release tarball and commits with my PGP key. Starting with release 2.2, the tarballs are signed with my key with fingerprint F7B28C61944FE30DABEEB0B01070BCC98C18BD66.

For previous releases, the key's fingerprint was 8535CEF3F3C38EE69555BF67E4B5E45AA3B8C5C3.

python, pacman, and snapper are all required.

For testing, pytest is required. To run the tests do:

make test

Typically, you will not need to build the documentation on your own and can simply access it by visiting the online documentation or by accessing the manpage:

man 8 snap-pac

To build the documentation, sphinx is required. To build the documentation you can do:

make docs

The resulting html documentation will then be located at docs/build/index.html. Additionally, this generates the manpage which will be located under man8.

Configuration is done via Python ini configuration files. The defaults should be suitable for most users, so you may not need to do any configuration at all. By default only the root snapper configuration is snapshotted.

A commented example configuration files is located at /etc/snap-pac.ini.

Edit with your favorite editor. The file is commented and should be self-explanatory.

Each section corresponds with a snapper configuration. Add additional sections to add other snapper configurations to be snapshotted. By default, only the root configuration is snapshotted. Additionally you can add a section named DEFAULT with options that apply to all snapper configurations unless overridden in a later section.

Each section can have the following entries:

  • desc_limit - integer; maximum length of description string before being truncated. Default: 72
  • important_packages - list of strings; names of packages that if involved in a pacman transaction will add important=yes to the snapper userdata for the pair of snapshots. Default: []
  • important_commands - list of strings; parent commands that will add important=yes to the snapper userdata for the pair of snapshots. Default: []
  • pre_description - string; description for the pre snapshot. Default: the parent command that called the pacman hook.
  • post_description - string; description for the post snapshot. Default: space separated list of packages that were installed, upgraded, or removed.
  • snapshot - boolean; whether or not to snapshot the configuration. Default: True for root configuration; False otherwise.
  • userdata - list of strings; key-value pairs that will be added to the userdata for the pair of snapshots. Default: []

Turn off snapshots for root configuration and turn on for home configuration:

[root]
snapshot = False
[home]
snapshot = True

Set the snapper to add the userdata important=yes for every snapshot in the root configuration when a system upgrade is performed:

[root]
important_commands = ["pacman -Syu"]

Set the snapper to add the userdata important=yes for every snapshot in the root configuration when a pacman transaction handles the packages linux and linux-lts:

[root]
important_packages = ["linux", "linux-lts"]

Here's a fuller example, with several options set for different configurations. In this case the root configuration snapshot will have important=yes when linux and linux-lts packages are part of the transaction. Additionally when full system upgrades are performed root snapshots will be marked important=yes. Note that you don't have to add snapshot = True for the root configuration since that is the default.

This file also turns one snapshots for the home snapper configuration and adds the userdata requestid=42,user=arthur to all snapshots for that configuration. Additionally he post snapshot description is overridden.

[root]
important_packages = ["linux", "linux-lts"]
important_commands = ["pacman -Syu"]
[home]
snapshot = True
userdata = ["requestid=42", "user=arthur"]
post_description = "pacman transaction post snapshot"

To temporarily prevent snapshots from being performed for a single pacman command, set the environment variable SNAP_PAC_SKIP. For example:

sudo SNAP_PAC_SKIP=y pacman -Syu

Here is an example of how the snapshots are created and how to rollback and pacman transaction. Here the nano package is installed:

pacman -S nano
resolving dependencies...
looking for conflicting packages...
Packages (1) nano-2.5.3-1
Total Installed Size:  2.14 MiB
:: Proceed with installation? [Y/n] Y
(1/1) checking keys in keyring                               [######################################] 100%
(1/1) checking package integrity                             [######################################] 100%
(1/1) loading package files                                  [######################################] 100%
(1/1) checking for file conflicts                            [######################################] 100%
(1/1) checking available disk space                          [######################################] 100%
:: Running pre-transaction hooks...
(1/1) Performing snapper pre snapshots for the following configurations...
=> root: 1033
:: Processing package changes...
(1/1) installing nano                                        [######################################] 100%
:: Running post-transaction hooks...
(1/1) Performing snapper post snapshots for the following configurations...
=> root: 1034

The snapper snapshot number is given for each snapper configuration that is used. This is also logged in pacman's log.

Here are the snapshots created before and after the pacman transaction:

snapper -c root list -t pre-post | tail -n 1
1033  | 1034   | Fri 22 Apr 2016 01:54:13 PM CDT | Fri 22 Apr 2016 01:54:14 PM CDT | pacman -S nano      |

Here is what changed during the transaction:

snapper -c root status 1033..1034
+..... /etc/nanorc
c..... /etc/snapper/.snap-pac-pre
+..... /usr/bin/nano
+..... /usr/bin/rnano
+..... /usr/share/doc/nano
+..... /usr/share/doc/nano/faq.html
+..... /usr/share/doc/nano/fr
+..... /usr/share/doc/nano/fr/nano.1.html
+..... /usr/share/doc/nano/fr/nanorc.5.html
+..... /usr/share/doc/nano/fr/rnano.1.html

The above output is truncated, but it continues. See snapper(8) to for what each symbol means. You can also do snapper diff in the same way.

Then, to undo the pacman transaction:

snapper -c root undochange 1033..1034
create:0 modify:3 delete:100

Now nano is no longer installed, along with all the files it changed:

pacman -Qi nano
error: package 'nano' was not found

snap-pac is only taking snapshots of the root configuration.

That's the default behavior. See Configuration.

No snapshots are being taken when I run pacman.

No snapper configurations are set up for snap-pac's pacman hooks. By default snap-pac will take snapshots for the root configuration and any other configuration which has SNAPSHOT set to yes in its configuration file. See Configuration.

After restoring snapshot from snap-pac, the pacman database is locked.

The pre/post snaphots are taken while pacman is running, so this is expected. Follow the instructions pacman gives you (e.g., removing the lock file). You can add the database lock file to a snapper filter so that snapper won't consider it when performing snapper diff, snapper status, snapper undochange, etc. See the Filters section in snapper(8) for more information.

Does snap-pac backup non-btrfs /boot partitions?

No, but you can add a hook that does it for you. It would be something like the following:

[Trigger]
Operation = Upgrade
Operation = Install
Operation = Remove
Type = Package
Target = linux
[Action]
Description = Backing up /boot...
When = PreTransaction
Exec = /usr/bin/rsync -avzq --delete /boot /.bootbackup

Note that you will probably want to name the file with a numbered prefix less than 05 so that it is run before the snap-pac pre snapshot takes place. That will ensure that the snapshot taken will have the boot partition back-up corresponding with the state of the system. For example, you could name it 04-backupboot.hook.

How do I link old kernel modules automatically when the kernel is upgraded?

This behavior is no longer a part of this package. Use a pacman hook like the following:

[Trigger]
Operation = Upgrade
Operation = Install
Operation = Remove
Type = Package
Target = linux
[Action]
Description = Symlinking old kernel modules...
When = PostTransaction
Exec = /usr/bin/bash -c "find /usr/lib/modules -xtype l -delete; ln -sv /.snapshots/$(snapper -c root list | awk 'END{print $1}')/snapshot/usr/lib/modules/$(uname -r) /usr/lib/modules/"

Wes Barnett

2022, Wes Barnett, PhD

December 7, 2022