diff --git a/extra/root.conf.example b/extra/root.conf.example deleted file mode 100644 index a9814d9..0000000 --- a/extra/root.conf.example +++ /dev/null @@ -1,7 +0,0 @@ -# snap-pac example configuration file for a snapper config named "root" -# See snap-pac(8) for details - -SNAPSHOT="yes" -CLEANUP_ALGORITHM="number" -#PRE_DESCRIPTION="pacman pre snapshot" -#POST_DESCRIPTION="pacman post snapshot" diff --git a/extra/snap-pac.conf.example b/extra/snap-pac.conf.example deleted file mode 100644 index 14764c2..0000000 --- a/extra/snap-pac.conf.example +++ /dev/null @@ -1,5 +0,0 @@ -# snap-pac example configuration file -# See snap-pac(8) for details - -ABORT_ON_FAIL="no" -DESC_LIMIT="72" diff --git a/extra/snap-pac.ini b/extra/snap-pac.ini new file mode 100644 index 0000000..4d3260e --- /dev/null +++ b/extra/snap-pac.ini @@ -0,0 +1,10 @@ +# snap-pac example configuration file +# See snap-pac(8) for details + +[root] +abort_on_fail = False +desc_limit = 72 +snapshot = True +cleanup_algorithm = number +#pre_description = "pacman pre snapshot" +#post_description = "pacman post snapshot" diff --git a/scripts/snap-pac.py b/scripts/snap-pac.py new file mode 100755 index 0000000..7f35da7 --- /dev/null +++ b/scripts/snap-pac.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python + +""" +Copyright (C) 2021 Wes Barnett + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +from argparse import ArgumentParser +from configparser import ConfigParser +import os + + +def create_snapper_cmd(args, config): + chroot = os.stat("/") != os.stat("/proc/1/root/.") + snapper_cmd = ["snapper"] + if chroot: + snapper_cmd.append("--no-dbus") + snapper_cmd.append("--config") + snapper_cmd.append(c) + snapper_cmd.append("create") + snapper_cmd.append("--type") + snapper_cmd.append(args.preorpost) + snapper_cmd.append("--cleanup-algorithm") + snapper_cmd.append(config.get(x, "cleanup_algorithm")) + snapper_cmd.append("--print-number") + snapper_cmd.append("--description") + desc_limit = config.getint(x, "desc_limit") + if args.preorpost == "pre": + snapper_cmd.append(config.get(x, "pre_description")[:desc_limit]) + else: + snapper_cmd.append(config.get(x, "post_description")[:desc_limit]) + return snapper_cmd + + +def do_snapshot(preorpost, cmd, prefile): + if preorpost == "pre": + return do_pre_snapshot(cmd, prefile) + else: + return do_post_snapshot(cmd, prefile) + + +def do_pre_snapshot(cmd, prefile): + """Run snapper command, write snapshot number to file.""" + num = os.popen(" ".join(cmd)).read().rstrip("\n") + with open(prefile, "w") as f: + f.write(num) + return num + + +def do_post_snapshot(cmd, prefile): + """Read pre snapshot number from file, run snapper, delete prefile.""" + cmd.append("--pre-number") + with open(prefile, "r") as f: + cmd.append(f.read().rstrip("\n")) + num = os.popen(" ".join(cmd)).read().rstrip("\n") + os.remove(prefile) + return num + + +def get_snapper_configs(conf_file): + """Get the snapper configurations.""" + with open(conf_file, "r") as f: + for line in f: + if line.startswith("SNAPPER_CONFIGS"): + line = line.rstrip("\n").rstrip("\"") + line = line.split("=") + line = line[1].lstrip("\"") + return line.split() + + +def setup_config_parser(ini_file): + """Set up defaults for snap-pac configuration.""" + parent_cmd = os.popen(f"ps -p {os.getppid()} -o args=").read().strip() + + config = ConfigParser() + config["DEFAULT"] = { + "snapshot": False, + "cleanup_algorithm": "number", + "pre_description": "".join(["\"", parent_cmd, "\""]), + "post_description": "TODO", + "desc_limit": 72 + } + config["root"] = { + "snapshot": True + } + config.read(ini_file) + return config + + +if __name__ == "__main__": + + snap_pac_ini = "/etc/snap-pac.ini" + snapper_conf_file = "/etc/conf.d/snapper" + + parser = ArgumentParser() + parser.add_argument(dest="preorpost") + args = parser.parse_args() + + config = setup_config_parser(snap_pac_ini) + snapper_configs = get_snapper_configs(snapper_conf_file) + + for c in snapper_configs: + + if c in config: + x = c + else: + x = "DEFAULT" + + if config.getboolean(x, "snapshot"): + prefile = f"/tmp/snap-pac-pre_{c}" + snapper_cmd = create_snapper_cmd(args, config) + num = do_snapshot(args.preorpost, snapper_cmd, prefile) + print(f"==> {c}: {num}")