Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package transactional-update for openSUSE:Factory checked in at 2023-01-24 19:42:21 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/transactional-update (Old) and /work/SRC/openSUSE:Factory/.transactional-update.new.32243 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "transactional-update" Tue Jan 24 19:42:21 2023 rev:95 rq:1060452 version:4.1.2 Changes: -------- --- /work/SRC/openSUSE:Factory/transactional-update/transactional-update.changes 2023-01-23 04:38:08.576888702 +0100 +++ /work/SRC/openSUSE:Factory/.transactional-update.new.32243/transactional-update.changes 2023-01-24 20:36:05.561550354 +0100 @@ -0,0 +1,23 @@ +------------------------------------------------------------------- +Mon Jan 23 13:54:11 UTC 2023 - Ignaz Forster <ifors...@suse.com> + +- Version 4.1.2 + - Don't try to mount user mounts if they don't exist [boo#1207366] + +------------------------------------------------------------------- +Wed Jan 18 16:56:16 UTC 2023 - Ignaz Forster <ifors...@suse.com> + +- Version 4.1.1 + - Mount user specific binddirs last: Prevously the internal mounts would + potentially overwrite user bind mounts [boo#1205011] + - selinux: Relabel shadowed /var files during update to make sure they + don't interfere with the update [boo#1205937] + - Clean up /var/lib/overlay more aggressively [boo#1206947] + - tukit: Merge /etc overlay into parent if --discard is used together + with --continue - previously the files were incorrectly always merged + with the currently running system + - status: do not execute the status command if experimental + - Don't delete created mount point dirs any more + - Small code optimizations + +------------------------------------------------------------------- Old: ---- transactional-update-4.1.0.tar.gz New: ---- transactional-update-4.1.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ transactional-update.spec ++++++ --- /var/tmp/diff_new_pack.bCmhYg/_old 2023-01-24 20:36:06.061552944 +0100 +++ /var/tmp/diff_new_pack.bCmhYg/_new 2023-01-24 20:36:06.077553027 +0100 @@ -1,7 +1,7 @@ # # spec file for package transactional-update # -# Copyright (c) 2022 SUSE LLC +# Copyright (c) 2023 SUSE LLC # Copyright (c) 2021 Neal Gompa # # All modifications and additions to the file contributed by third parties @@ -26,7 +26,7 @@ %{!?_distconfdir: %global _distconfdir %{_prefix}%{_sysconfdir}} Name: transactional-update -Version: 4.1.0 +Version: 4.1.2 Release: 0 Summary: Transactional Updates with btrfs and snapshots License: GPL-2.0-or-later AND LGPL-2.1-or-later ++++++ transactional-update-4.1.0.tar.gz -> transactional-update-4.1.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-4.1.0/NEWS new/transactional-update-4.1.2/NEWS --- old/transactional-update-4.1.0/NEWS 2022-10-26 16:50:43.000000000 +0200 +++ new/transactional-update-4.1.2/NEWS 2023-01-23 14:31:20.000000000 +0100 @@ -2,6 +2,22 @@ Copyright (C) 2016-2022 Thorsten Kukuk, Ignaz Forster et al. +Version 4.1.2 +* Don't try to mount user mounts if they don't exist [boo#1207366] + +Version 4.1.1 +* Mount user specific binddirs last: Prevously the internal mounts would + potentially overwrite user bind mounts [boo#1205011] +* selinux: Relabel shadowed /var files during update to make sure they + don't interfere with the update [boo#1205937] +* Clean up /var/lib/overlay more aggressively [boo#1206947] +* tukit: Merge /etc overlay into parent if --discard is used together + with --continue - previously the files were incorrectly always merged + with the currently running system +* status: do not execute the status command if experimental +* Don't delete created mount point dirs any more +* Small code optimizations + Version 4.1.0 * t-u: Add a "setup-kdump" command; implements [jsc#PED-1441] * Add support for ULP (Userspace Live Patching) [jsc#PED-1078]: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-4.1.0/README.md new/transactional-update-4.1.2/README.md --- old/transactional-update-4.1.0/README.md 2022-10-26 16:50:43.000000000 +0200 +++ new/transactional-update-4.1.2/README.md 2023-01-23 14:31:20.000000000 +0100 @@ -29,7 +29,7 @@ ## Known users * **dnf**, Fedora's package management system, supports transactional systems directly via the [libdnf-plugin-txnupd](https://code.opensuse.org/microos/libdnf-plugin-txnupd) plugin (libtukit). -* **Cockpit** can update transactionals systems via the [cockpit-tukit](https://github.com/openSUSE/cockpit-tukit) plugin (tukitd). +* **Cockpit** can update transactional systems via the [cockpit-tukit](https://github.com/openSUSE/cockpit-tukit) plugin (tukitd). * **Salt** contains the [salt.modules.transactional\_update module](https://docs.saltproject.io/en/3004/ref/modules/all/salt.modules.transactional_update.html) module (transactional-update). * **Ansible** also supports transactional-update via the the [community.general.zypper](https://docs.ansible.com/ansible/latest/collections/community/general/zypper_module.html) module (transactional-update). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-4.1.0/configure.ac new/transactional-update-4.1.2/configure.ac --- old/transactional-update-4.1.0/configure.ac 2022-10-26 16:50:43.000000000 +0200 +++ new/transactional-update-4.1.2/configure.ac 2023-01-23 14:31:20.000000000 +0100 @@ -1,11 +1,11 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT(transactional-update, 4.1.0) +AC_INIT(transactional-update, 4.1.2) # Increase on any interface change and reset revision LIBTOOL_CURRENT=4 # On interface change increase if backwards compatible, reset otherwise LIBTOOL_AGE=0 # Increase on *any* C/C++ library code change, reset at interface change -LIBTOOL_REVISION=1 +LIBTOOL_REVISION=2 AC_CANONICAL_SYSTEM AM_INIT_AUTOMAKE([foreign]) AC_CONFIG_FILES([tukit.pc]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-4.1.0/lib/Mount.cpp new/transactional-update-4.1.2/lib/Mount.cpp --- old/transactional-update-4.1.0/lib/Mount.cpp 2022-10-26 16:50:43.000000000 +0200 +++ new/transactional-update-4.1.2/lib/Mount.cpp 2023-01-23 14:31:20.000000000 +0100 @@ -13,9 +13,9 @@ namespace TransactionalUpdate { -Mount::Mount(std::string mountpoint, unsigned long flags) +Mount::Mount(std::string mountpoint, unsigned long flags, bool umount) : mnt_table{mnt_new_table()}, mountpoint{std::move(mountpoint)}, - flags{std::move(flags)} + flags{std::move(flags)}, umount{std::move(umount)} { } @@ -29,7 +29,7 @@ } Mount::~Mount() { - if (mnt_fs) { + if (mnt_fs && umount) { struct libmnt_table* umount_table = mnt_new_table(); if ((mnt_table_parse_mtab(umount_table, nullptr)) != 0) tulog.error("Error reading mtab for umount"); @@ -39,14 +39,6 @@ mnt_free_table(umount_table); } - if (!directoryCreated.empty()) { - try { - std::filesystem::remove_all(std::filesystem::path{directoryCreated}); - } catch (const std::exception &e) { - tulog.error("ERROR: ", e.what()); - } - } - mnt_free_context(mnt_cxt); mnt_unref_fs(mnt_fs); mnt_free_table(mnt_table); @@ -192,10 +184,6 @@ throw std::runtime_error{"Setting mount flags for '" + mountpoint + "' failed: " + std::to_string(rc)}; } - if (! std::filesystem::is_directory(mounttarget)) { - tulog.debug("Mount target ", mounttarget, " does not exist - creating..."); - directoryCreated = mounttarget; - } std::filesystem::create_directories(mounttarget); rc = mnt_context_mount(mnt_cxt); @@ -269,8 +257,8 @@ mnt_free_context(umount_cxt); } -BindMount::BindMount(std::string mountpoint, unsigned long flags) - : Mount(mountpoint, flags | MS_BIND) +BindMount::BindMount(std::string mountpoint, unsigned long flags, bool umount) + : Mount(mountpoint, flags | MS_BIND, umount) { } @@ -281,8 +269,8 @@ Mount::mount(prefix); } -PropagatedBindMount::PropagatedBindMount(std::string mountpoint, unsigned long flags) - : BindMount(mountpoint, flags | MS_REC | MS_SLAVE) +PropagatedBindMount::PropagatedBindMount(std::string mountpoint, unsigned long flags, bool umount) + : BindMount(mountpoint, flags | MS_REC | MS_SLAVE, umount) { } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-4.1.0/lib/Mount.hpp new/transactional-update-4.1.2/lib/Mount.hpp --- old/transactional-update-4.1.0/lib/Mount.hpp 2022-10-26 16:50:43.000000000 +0200 +++ new/transactional-update-4.1.2/lib/Mount.hpp 2023-01-23 14:31:20.000000000 +0100 @@ -18,7 +18,7 @@ class Mount { public: - Mount(std::string mountpoint, unsigned long flags = 0); + Mount(std::string mountpoint, unsigned long flags = 0, bool umount = false); Mount(Mount&& other) noexcept; virtual ~Mount(); std::string getFilesystem(); @@ -38,7 +38,7 @@ std::string tabsource; std::string mountpoint; unsigned long flags; - std::string directoryCreated; + bool umount; struct libmnt_fs* findFS(); struct libmnt_fs* getTabEntry(); struct libmnt_fs* newFS(); @@ -48,14 +48,14 @@ class BindMount : public Mount { public: - BindMount(std::string mountpoint, unsigned long flags = 0); + BindMount(std::string mountpoint, unsigned long flags = 0, bool umount = false); void mount(std::string prefix = "/") override; }; class PropagatedBindMount : public BindMount { public: - PropagatedBindMount(std::string mountpoint, unsigned long flags = 0); + PropagatedBindMount(std::string mountpoint, unsigned long flags = 0, bool umount = false); }; class MountList diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-4.1.0/lib/Overlay.cpp new/transactional-update-4.1.2/lib/Overlay.cpp --- old/transactional-update-4.1.0/lib/Overlay.cpp 2022-10-26 16:50:43.000000000 +0200 +++ new/transactional-update-4.1.2/lib/Overlay.cpp 2023-01-23 14:31:20.000000000 +0100 @@ -115,7 +115,6 @@ previousEtc->removeOption("workdir"); string syncSource = string(previousOvl.upperdir.parent_path() / "sync" / "etc") + "/"; - string rsyncExtraArgs; previousEtc->mount(previousOvl.upperdir.parent_path() / "sync"); tulog.info("Syncing /etc of previous snapshot ", previousSnapId, " as base into new snapshot ", snapRoot); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-4.1.0/lib/Snapshot/Snapper.cpp new/transactional-update-4.1.2/lib/Snapshot/Snapper.cpp --- old/transactional-update-4.1.0/lib/Snapshot/Snapper.cpp 2022-10-26 16:50:43.000000000 +0200 +++ new/transactional-update-4.1.2/lib/Snapshot/Snapper.cpp 2023-01-23 14:31:20.000000000 +0100 @@ -7,7 +7,6 @@ #include "Snapper.hpp" #include "Exceptions.hpp" -#include "Log.hpp" #include "Util.hpp" #include <regex> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-4.1.0/lib/Transaction.cpp new/transactional-update-4.1.2/lib/Transaction.cpp --- old/transactional-update-4.1.0/lib/Transaction.cpp 2022-10-26 16:50:43.000000000 +0200 +++ new/transactional-update-4.1.2/lib/Transaction.cpp 2023-01-23 14:31:20.000000000 +0100 @@ -25,6 +25,8 @@ #include <limits.h> #include <poll.h> #include <sched.h> +#include <selinux/restorecon.h> +#include <selinux/selinux.h> #include <signal.h> #include <sys/inotify.h> #include <sys/mount.h> @@ -106,18 +108,13 @@ // mount the snapshot directory on a temporary mount point char bindTemplate[] = "/tmp/transactional-update-XXXXXX"; bindDir = mkdtemp(bindTemplate); - std::unique_ptr<BindMount> mntBind{new BindMount{bindDir, MS_PRIVATE}}; + std::unique_ptr<BindMount> mntBind{new BindMount{bindDir, MS_PRIVATE, true}}; mntBind->setSource(snapshot->getRoot()); mntBind->mount(); dirsToMount.push_back(std::make_unique<PropagatedBindMount>("/dev")); dirsToMount.push_back(std::make_unique<BindMount>("/var/log")); - std::vector<std::string> customDirs = config.getArray("BINDDIRS"); - for (auto it = customDirs.begin(); it != customDirs.end(); ++it) { - dirsToMount.push_back(std::make_unique<BindMount>(*it)); - } - Mount mntVar{"/var"}; if (mntVar.isMount()) { if (fs::is_directory("/var/lib/zypp")) @@ -127,7 +124,41 @@ dirsToMount.push_back(std::make_unique<BindMount>("/var/lib/alternatives")); if (fs::is_directory("/var/lib/selinux")) dirsToMount.push_back(std::make_unique<BindMount>("/var/lib/selinux")); + if (is_selinux_enabled()) { + // If packages installed files into /var (which is not allowed, but still happens), they will end + // up in the root file system, but will always be shadowed by the real /var mount. Due to that they + // also won't be relabelled at any time. During updates this may cause problems if packages try to + // access those leftover directories with wrong permissions, so they have to be relabelled manually... + BindMount selinuxVar("/var/lib/selinux", 0, true); + selinuxVar.mount(bindDir); + BindMount selinuxEtc("/etc/selinux", 0, true); + selinuxEtc.mount(bindDir); + + // restorecon keeps open file handles, so execute it in a child process - umount will fail otherwise + pid_t childPid = fork(); + if (childPid < 0) { + throw std::runtime_error{"Forking for SELinux relabelling failed: " + std::string(strerror(errno))}; + } else if (childPid == 0) { + if (chroot(bindDir.c_str()) < 0) { + tulog.error("Chrooting to " + bindDir + " for SELinux relabelling failed: " + std::string(strerror(errno))); + _exit(errno); + } + if (selinux_restorecon("/var", SELINUX_RESTORECON_RECURSE | SELINUX_RESTORECON_VERBOSE | SELINUX_RESTORECON_IGNORE_DIGEST) < 0) { + tulog.error("Relabelling of snapshot /var failed: " + std::string(strerror(errno))); + _exit(errno); + } + _exit(0); + } + else { + int status; + waitpid(childPid, &status, 0); + if ((WIFEXITED(status) && WEXITSTATUS(status) != 0) || WIFSIGNALED(status)) { + throw std::runtime_error{"SELinux relabelling failed."}; + } + } + } } + std::unique_ptr<Mount> mntEtc{new Mount{"/etc"}}; if (mntEtc->isMount() && mntEtc->getFilesystem() == "overlay") { Overlay overlay = Overlay{snapshot->getUid()}; @@ -171,6 +202,14 @@ if (BindMount{"/boot/writable"}.isMount()) dirsToMount.push_back(std::make_unique<BindMount>("/boot/writable")); + std::vector<std::string> customDirs = config.getArray("BINDDIRS"); + for (auto it = customDirs.begin(); it != customDirs.end(); ++it) { + if (fs::is_directory(*it)) + dirsToMount.push_back(std::make_unique<BindMount>(*it)); + else + tulog.info("Not bind mounting directory '" + *it + "' as it doesn't exist."); + } + dirsToMount.push_back(std::make_unique<BindMount>("/.snapshots")); for (auto it = dirsToMount.begin(); it != dirsToMount.end(); ++it) { @@ -276,7 +315,7 @@ struct pollfd pfd = {inotifyFd, POLLIN, 0}; ret = (poll(&pfd, 1, 500)); if (ret == -1) { - throw std::runtime_error{"Polling inotify file descriptior failed: " + std::string(strerror(errno))}; + throw std::runtime_error{"Polling inotify file descriptor failed: " + std::string(strerror(errno))}; } else if (ret > 0) { numRead = read(inotifyFd, buf, bufLen); if (numRead == 0) @@ -432,12 +471,33 @@ (inotifyFd == 0 && fs::exists(getRoot() / "discardIfNoChange")))) { tulog.info("No changes to the root file system - discarding snapshot."); - // Even if the snapshot itself did not contain any changes, /etc may do so. Changes - // in /etc may be applied immediately, so merge them back into the running system. + // Even if the snapshot itself does not contain any changes, /etc may do so. If the new snapshot is a + // direct descendant of the currently running system, then merge the changes back into the currently + // running system directly and delete the snapshot. Otherwise merge it back into the previous overlay + // (using rsync instead of a plain copy to preserve xattrs). std::unique_ptr<Mount> mntEtc{new Mount{"/etc"}}; if (mntEtc->isMount() && mntEtc->getFilesystem() == "overlay") { - Util::exec("rsync --archive --inplace --xattrs --acls --exclude 'fstab' --delete --quiet '" + this->pImpl->bindDir + "/etc/' /etc"); + std::filesystem::path targetRoot; + std::unique_ptr<Mount> previousEtc{new Mount("/etc", 0, true)}; + if (pImpl->snapshotMgr->getCurrent() == Overlay{pImpl->snapshot->getUid()}.getPreviousSnapshotOvlId()) { + tulog.info("Merging changes in /etc into the running system."); + targetRoot = "/"; + } else { + tulog.info("Merging changes in /etc into the previous snapshot."); + + auto previousSnapId = Overlay{pImpl->snapshot->getUid()}.getPreviousSnapshotOvlId(); + std::unique_ptr<Snapshot> previousSnapshot = pImpl->snapshotMgr->open(previousSnapId); + previousEtc->setTabSource(previousSnapshot->getRoot() / "etc" / "fstab"); + + Overlay previousOvl{previousSnapId}; + previousOvl.lowerdirs.back() = previousSnapshot->getRoot(); + previousOvl.setMountOptionsForMount(previousEtc); + targetRoot = previousOvl.upperdir.parent_path() / "sync"; + previousEtc->mount(targetRoot); + } + Util::exec("rsync --archive --inplace --xattrs --acls --exclude 'fstab' --delete --quiet '" + this->pImpl->bindDir + "/etc/' " + targetRoot.native() + "/etc"); } + return; } if (fs::exists(getRoot() / "discardIfNoChange")) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-4.1.0/sbin/transactional-update.in new/transactional-update-4.1.2/sbin/transactional-update.in --- old/transactional-update-4.1.0/sbin/transactional-update.in 2022-10-26 16:50:43.000000000 +0200 +++ new/transactional-update-4.1.2/sbin/transactional-update.in 2023-01-23 14:31:20.000000000 +0100 @@ -1209,10 +1209,14 @@ fi if [ "${DO_STATUS}" -eq 1 ]; then - for snapshot in $(ls -d /.snapshots/*/ | cut -d '/' -f 3 | sort --reverse --numeric-sort); do - show_snapshot_status "/.snapshots/$snapshot/" - [ "${DO_STATUS_LAST}" -eq 1 ] && break - done + if [ "${EXPERIMENTAL_STATUS}" -eq 1 ]; then + for snapshot in $(ls -d /.snapshots/*/ | cut -d '/' -f 3 | sort --reverse --numeric-sort); do + show_snapshot_status "/.snapshots/$snapshot/" + [ "${DO_STATUS_LAST}" -eq 1 ] && break + done + else + echo "The status command is disabled by default as it is marked as experimental" + fi exit 0 fi @@ -1290,11 +1294,10 @@ # Clean up old unused overlays if [ ${RO_ROOT} == "true" ]; then shopt -s nullglob - for overlay in /var/lib/overlay/[0-9]*/etc /var/lib/overlay/etc; do + for overlay in /var/lib/overlay/*; do if [ -e ${overlay} ] && ! grep -qs "${overlay}" /.snapshots/*/snapshot/etc/fstab{,.sys}; then log_info "Deleting unused overlay ${overlay}" - rm -rf "${overlay}" - rmdir --ignore-fail-on-non-empty "$(dirname "${overlay}")" + rm -r "${overlay}" fi done shopt -u nullglob