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 2021-03-10 08:46:20 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/transactional-update (Old) and /work/SRC/openSUSE:Factory/.transactional-update.new.2378 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "transactional-update" Wed Mar 10 08:46:20 2021 rev:69 rq:876314 version:3.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/transactional-update/transactional-update.changes 2021-02-18 20:50:15.175317660 +0100 +++ /work/SRC/openSUSE:Factory/.transactional-update.new.2378/transactional-update.changes 2021-03-10 08:46:22.686215349 +0100 @@ -1,0 +2,15 @@ +Tue Mar 2 23:58:27 UTC 2021 - Ignaz Forster <ifors...@suse.com> + +- Version 3.2.0 + - tukit: Add new command 'callext' to execute an application while the + snapshot is mounted. '{}' as a parameter will be replaced with the path + of the bind mount. + - Fix --drop-if-no-change [boo#1182525] + - Check whether self-updated version is executable (e.g. on noexec /tmp) + [bsc#1173842] + - Fix overlay synchronisation with SELinux (again) + - Always overwrite supplemental files (e.g. for network configuration) + even if they exist in the snapshot already [boo#1182544] + - Improve logging and error messages + +------------------------------------------------------------------- Old: ---- transactional-update-3.1.4.tar.gz New: ---- transactional-update-3.2.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ transactional-update.spec ++++++ --- /var/tmp/diff_new_pack.bd2OdR/_old 2021-03-10 08:46:23.198215877 +0100 +++ /var/tmp/diff_new_pack.bd2OdR/_new 2021-03-10 08:46:23.202215881 +0100 @@ -26,7 +26,7 @@ %{!?_distconfdir: %global _distconfdir %{_prefix}%{_sysconfdir}} Name: transactional-update -Version: 3.1.4 +Version: 3.2.0 Release: 0 Summary: Transactional Updates with btrfs and snapshots License: GPL-2.0-or-later AND LGPL-2.1-or-later ++++++ transactional-update-3.1.4.tar.gz -> transactional-update-3.2.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-3.1.4/NEWS new/transactional-update-3.2.0/NEWS --- old/transactional-update-3.1.4/NEWS 2021-02-17 09:41:55.000000000 +0100 +++ new/transactional-update-3.2.0/NEWS 2021-03-03 00:56:13.000000000 +0100 @@ -2,6 +2,18 @@ Copyright (C) 2016-2020 Thorsten Kukuk, Ignaz Forster et al. +Version 3.2.0 +* tukit: Add new command 'callext' to execute an application while the + snapshot is mounted. '{}' as a parameter will be replaced with the path + of the bind mount. +* Fix --drop-if-no-change [boo#1182525] +* Check whether self-updated version is executable (e.g. on noexec /tmp) + [bsc#1173842] +* Fix overlay synchronisation with SELinux (again) +* Always overwrite supplemental files (e.g. for network configuration) + even if they exist in the snapshot already [boo#1182544] +* Improve logging and error messages + Version 3.1.4 * SELinux: Fix syncing of SELinux attributes when using overlays * SELinux: Tag the overlay directory itself (again) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-3.1.4/configure.ac new/transactional-update-3.2.0/configure.ac --- old/transactional-update-3.1.4/configure.ac 2021-02-17 09:41:55.000000000 +0100 +++ new/transactional-update-3.2.0/configure.ac 2021-03-03 00:56:13.000000000 +0100 @@ -1,8 +1,11 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT(transactional-update, 3.1.4) -LIBTOOL_CURRENT=1 # Increase on any interface change and reset revision -LIBTOOL_REVISION=4 # Increase or reset on any VERSION update -LIBTOOL_AGE=1 # Increase if interface change is backwards compatible, reset otherwise +AC_INIT(transactional-update, 3.2.0) +# Increase on any interface change and reset revision +LIBTOOL_CURRENT=2 +# Increase or reset on any VERSION update +LIBTOOL_REVISION=0 +# Increase if interface change is backwards compatible, reset otherwise +LIBTOOL_AGE=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-3.1.4/lib/Overlay.cpp new/transactional-update-3.2.0/lib/Overlay.cpp --- old/transactional-update-3.1.4/lib/Overlay.cpp 2021-02-17 09:41:55.000000000 +0100 +++ new/transactional-update-3.2.0/lib/Overlay.cpp 2021-03-03 00:56:13.000000000 +0100 @@ -15,6 +15,7 @@ #include <filesystem> #include <regex> #include <selinux/selinux.h> +#include <selinux/context.h> #include <sstream> #include <unistd.h> @@ -117,11 +118,15 @@ previousEtc->mount(previousOvl.upperdir.parent_path() / "sync"); tulog.info("Syncing /etc of previous snapshot ", previousSnapId, " as base into new snapshot ", snapshot); if (is_selinux_enabled()) { + tulog.info("SELinux is enabled."); // Ignore the SELinux attributes when synchronizing pre-SELinux files, // rsync will fail otherwise char* context; - if (getfilecon(syncSource.c_str(), &context) > 0 && strcmp(context, "unlabeled_t") == 0) { - rsyncExtraArgs = "--filter='-x security.selinux'"; + if (getfilecon(syncSource.c_str(), &context) > 0) { // && + auto contextt = context_new(context); + if (strcmp(context_type_get(contextt), "unlabeled_t") == 0) { + rsyncExtraArgs = "--filter='-x security.selinux'"; + } } } Util::exec("rsync --quiet --archive --inplace --xattrs --exclude='/fstab' " + rsyncExtraArgs + " --acls --delete " + syncSource + " " + snapshot + "/etc"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-3.1.4/lib/Supplement.cpp new/transactional-update-3.2.0/lib/Supplement.cpp --- old/transactional-update-3.1.4/lib/Supplement.cpp 2021-02-17 09:41:55.000000000 +0100 +++ new/transactional-update-3.2.0/lib/Supplement.cpp 2021-03-03 00:56:13.000000000 +0100 @@ -41,11 +41,9 @@ void Supplements::addFile(fs::path file) { if (fs::exists(file)) { - auto copyOptions = fs::copy_options::none; + auto copyOptions = fs::copy_options::overwrite_existing | fs::copy_options::recursive; createDirs(file.parent_path()); fs::path target = snapshot / file.relative_path(); - if (fs::is_regular_file(file)) - copyOptions = fs::copy_options::overwrite_existing; fs::copy(file, target, copyOptions); supplementalFiles.push_back(std::move(target)); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-3.1.4/lib/Transaction.cpp new/transactional-update-3.2.0/lib/Transaction.cpp --- old/transactional-update-3.1.4/lib/Transaction.cpp 2021-02-17 09:41:55.000000000 +0100 +++ new/transactional-update-3.2.0/lib/Transaction.cpp 2021-03-03 00:56:13.000000000 +0100 @@ -28,6 +28,7 @@ public: void addSupplements(); void mount(); + int runCommand(char* argv[], bool inChroot); std::unique_ptr<Snapshot> snapshot; std::string bindDir; std::vector<std::unique_ptr<Mount>> dirsToMount; @@ -55,8 +56,10 @@ } } try { - if (isInitialized() && !getSnapshot().empty()) + if (isInitialized() && !getSnapshot().empty() && fs::exists(getRoot())) { + tulog.info("Discarding snapshot ", pImpl->snapshot->getUid(), "."); pImpl->snapshot->abort(); + } } catch (const std::exception &e) { tulog.error("ERROR: ", e.what()); } @@ -183,7 +186,7 @@ pImpl->addSupplements(); } -int Transaction::execute(char* argv[]) { +int Transaction::impl::runCommand(char* argv[], bool inChroot) { std::string opts = "Executing `"; int i = 0; while (argv[i]) { @@ -201,11 +204,13 @@ if (pid < 0) { throw std::runtime_error{"fork() failed: " + std::string(strerror(errno))}; } else if (pid == 0) { - if (chdir(pImpl->bindDir.c_str()) < 0) { - tulog.info("Warning: Couldn't set working directory: ", std::string(strerror(errno))); - } - if (chroot(pImpl->bindDir.c_str()) < 0) { - throw std::runtime_error{"Chrooting to " + pImpl->bindDir + " failed: " + std::string(strerror(errno))}; + if (inChroot) { + if (chdir(bindDir.c_str()) < 0) { + tulog.info("Warning: Couldn't set working directory: ", std::string(strerror(errno))); + } + if (chroot(bindDir.c_str()) < 0) { + throw std::runtime_error{"Chrooting to " + bindDir + " failed: " + std::string(strerror(errno))}; + } } // Set indicator for RPM pre/post sections to detect whether we run in a // transactional update @@ -216,9 +221,9 @@ throw std::runtime_error{"Calling " + std::string(argv[0]) + " failed: " + std::string(strerror(errno))}; } } else { - this->pImpl->pid = pid; + this->pid = pid; ret = waitpid(pid, &status, 0); - this->pImpl->pid = 0; + this->pid = 0; if (tulog.level > TULogLevel::ERROR) std::cout << "???" << std::endl; if (ret < 0) { @@ -237,6 +242,20 @@ return ret; } +int Transaction::execute(char* argv[]) { + return this->pImpl->runCommand(argv, true); +} + +int Transaction::callExt(char* argv[]) { + for (int i=0; argv[i] != nullptr; i++) { + if (strcmp(argv[i], "{}") == 0) { + char* bindDir = strdup(pImpl->bindDir.c_str()); + argv[i] = bindDir; + } + } + return this->pImpl->runCommand(argv, false); +} + void Transaction::sendSignal(int signal) { if (pImpl->pid != 0) { if (kill(pImpl->pid, signal) < 0) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-3.1.4/lib/Transaction.hpp new/transactional-update-3.2.0/lib/Transaction.hpp --- old/transactional-update-3.1.4/lib/Transaction.hpp 2021-02-17 09:41:55.000000000 +0100 +++ new/transactional-update-3.2.0/lib/Transaction.hpp 2021-03-03 00:56:13.000000000 +0100 @@ -64,8 +64,8 @@ * @param argv * @return application's return code * - * Execute any given command in the new snapshot. The application's output will not be - * modified and printed to the corresponding streams. + * Execute any given command within the new snapshot. The application's output will be + * printed to the corresponding streams. * * Note that @param is following the default C style syntax: * @example: char *args[] = {(char*)"ls", (char*)"-l", NULL}; @@ -74,6 +74,23 @@ int execute(char* argv[]); /** + * @brief Replace '{}' in argv with mount directory and execute command + * @param argv + * @return application's return code + * + * Replace any standalone occurrence of '{}' in argv with the snapshot's mount directory + * and execute the given command *outside* of the snapshot in the running system. This may + * be useful if the command needs access to the current environment, e.g. to copy a file + * from a directory not accessible from within the chroot environment. + * The application's output will be printed to the corresponding streams. + * + * Note that @param is following the default C style syntax: + * @example: char *args[] = {(char*)"zypper", (char*)"-R", (char*)"{}", (char*)"up", NULL}; + int status = transaction.execute(args); + */ + int callExt(char* argv[]); + + /** * @brief Close a transaction and set it as the new default snapshot * * Note that it is necessary to call this method if the snapshot is supposed to be kept. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-3.1.4/sbin/transactional-update.in new/transactional-update-3.2.0/sbin/transactional-update.in --- old/transactional-update-3.1.4/sbin/transactional-update.in 2021-02-17 09:41:55.000000000 +0100 +++ new/transactional-update-3.2.0/sbin/transactional-update.in 2021-03-03 00:56:13.000000000 +0100 @@ -101,7 +101,6 @@ log_error "ERROR: Couldn't create temporary directory for self-update." quit 1 fi - export TA_UPDATE_TMPFILE pushd "${TA_UPDATE_TMPFILE}" >/dev/null zypper --non-interactive --pkg-cache-dir "${TA_UPDATE_TMPFILE}" download transactional-update find . -name transactional-update*.rpm -exec rpm2cpio {} \; | cpio -idmv 2>/dev/null @@ -111,6 +110,12 @@ fi # Reset CWD before restart popd >/dev/null + if ! "${TA_UPDATE_TMPFILE}/usr/sbin/transactional-update" --version >/dev/null; then + log_error "Cannot execute updated transactional-update - skipping" + rm -rf "${TA_UPDATE_TMPFILE}" + return + fi + export TA_UPDATE_TMPFILE exec "${TA_UPDATE_TMPFILE}/usr/sbin/transactional-update" "$@" fi } @@ -252,12 +257,6 @@ quit() { teardown - # Exit open transaction (used by zypper commands) - pkill -f "tu_keep-transaction-alive 1d" - while pgrep -f tukit >/dev/null; do - sleep 0.5 - done - if [ -n "${SNAPSHOT_ID}" ] ; then log_error "Removing snapshot #${SNAPSHOT_ID}..." tukit abort ${SNAPSHOT_ID} |& tee -a ${LOGFILE} @@ -360,7 +359,7 @@ # If VARDIR is part of the root file system (usually on rw systems), then # create the file in the new snapshot if [ "$(findmnt --noheadings --output TARGET --target "${VARDIR}")" = "/" ]; then - VARDIR="${SNAPSHOT_DIR}/${VARDIR}" + VARDIR="${SNAPSHOT_DIR}${VARDIR}" fi test -d "${VARDIR}" || mkdir -p "${VARDIR}" touch "${VARDIR}/check-registration" @@ -878,8 +877,13 @@ fi fi - SNAPSHOT_ID=`tukit -c"${BASE_SNAPSHOT_ID}" open | grep -e "^ID:" | cut -d " " -f 2-` - SNAPSHOT_DIR="/.snapshots/${SNAPSHOT_ID}/snapshot/" + output="`tukit -c"${BASE_SNAPSHOT_ID}" open |& tee -a ${LOGFILE}`" + echo "$output" + SNAPSHOT_ID=`echo "${output}" | grep -e "^ID:" | cut -d " " -f 2-` + if [ -z ${SNAPSHOT_ID} ]; then + quit 1 + fi + SNAPSHOT_DIR="/.snapshots/${SNAPSHOT_ID}/snapshot" # Remember all snapshots we create for update. If transactional-update is # run several times before a reboot, we need to clean up the unused @@ -910,34 +914,20 @@ else # Check if there are updates at all. TMPFILE=`mktemp ${TMPDIR}/transactional-update.XXXXXXXXXX` - tukit call "${SNAPSHOT_ID}" bash -c 'exec -a tu_keep-transaction-alive sleep 1d' & - while ! pgrep -f "tu_keep-transaction-alive 1d" >/dev/null; do - sleep 0.5 - done - BINDMNT=$(realpath /proc/$(pgrep -fn tu_keep-transaction-alive)/root) - echo zypper -R ${BINDMNT} --xmlout ${ZYPPER_ARG} -y --auto-agree-with-product-licenses --dry-run "${ZYPPER_ARG_PKGS[@]}" > ${TMPFILE} - zypper -R ${BINDMNT} --xmlout ${ZYPPER_ARG} -y --auto-agree-with-product-licenses --dry-run "${ZYPPER_ARG_PKGS[@]}" > ${TMPFILE} + tukit callext "${SNAPSHOT_ID}" zypper -R {} --xmlout ${ZYPPER_ARG} -y --auto-agree-with-product-licenses --dry-run "${ZYPPER_ARG_PKGS[@]}" > ${TMPFILE} PACKAGE_UPDATES=`grep "install-summary download-size" ${TMPFILE} | sed -e 's|.*install-summary download-size=\"\(.*\)\" space-usage-diff.*|\1|g'` SIZE_OF_UPDATES=`grep "install-summary.*space-usage-diff" ${TMPFILE} | sed -e 's|.*install-summary.*space-usage-diff=\"\([^"]*\)\".*|\1|g'` NUM_OF_UPDATES=`grep "install-summary.*packages-to-change" ${TMPFILE} | sed -e 's|.*install-summary.*packages-to-change=\"\([^"]*\)\".*|\1|g'` rm -f ${TMPFILE} TELEM_PAYLOAD="${TELEM_PAYLOAD}\npackages=${NUM_OF_UPDATES}\ndownload_size=${PACKAGE_UPDATES}\nspace-usage=${SIZE_OF_UPDATES}" if [ "${NUM_OF_UPDATES}" = "0" ] || [ -z "${NUM_OF_UPDATES}" -a "${PACKAGE_UPDATES}" = "0" -a "${SIZE_OF_UPDATES}" = "0" ]; then - pkill -f "tu_keep-transaction-alive 1d" - while pgrep -f tukit >/dev/null; do - sleep 0.5 - done log_info "zypper: nothing to update" quit 0 fi export DISABLE_RESTART_ON_UPDATE=yes - zypper -R ${BINDMNT} ${ZYPPER_ARG} ${ZYPPER_NONINTERACTIVE} "${ZYPPER_ARG_PKGS[@]}" |& tee -a ${LOGFILE} + tukit callext "${SNAPSHOT_ID}" zypper -R {} ${ZYPPER_ARG} ${ZYPPER_NONINTERACTIVE} "${ZYPPER_ARG_PKGS[@]}" |& tee -a ${LOGFILE} RETVAL=${PIPESTATUS[0]} - pkill -f "tu_keep-transaction-alive 1d" - while pgrep -f tukit >/dev/null; do - sleep 0.5 - done fi # in case of migration, we need to do a little bit more: if [ ${DO_MIGRATION} -eq 1 ]; then diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transactional-update-3.1.4/tukit/tukit.cpp new/transactional-update-3.2.0/tukit/tukit.cpp --- old/transactional-update-3.1.4/tukit/tukit.cpp 2021-02-17 09:41:55.000000000 +0100 +++ new/transactional-update-3.2.0/tukit/tukit.cpp 2021-03-03 00:56:13.000000000 +0100 @@ -35,9 +35,14 @@ cout << "open\n"; cout << "\tCreates a new transaction and prints its unique ID\n"; cout << "call <ID> <command>\n"; - cout << "\tExecutes the given command, resuming the transaction with the given ID; returns\n"; - cout << "\tthe exit status of the given command, but will not delete the snapshot in case\n"; - cout << "\tof errors\n"; + cout << "\tExecutes the given command from within the transaction's chroot environment,\n"; + cout << "\tresuming the transaction with the given ID; returns the exit status of the\n"; + cout << "\tgiven command, but will not delete the snapshot in case of errors\n"; + cout << "callext <ID> <command>\n"; + cout << "\tExecutes the given command. The command is not executed in a chroot\n"; + cout << "\tenvironment, but instead runs in the current system, replacing '{}' with the\n"; + cout << "\tmount directory of the given snapshot; returns the exit status of the given\n"; + cout << "\tcommand, but will not delete the snapshot in case of errors\n"; cout << "close <ID>\n"; cout << "\tCloses the given transaction and sets the snapshot as the new default snapshot\n"; cout << "abort <ID>\n"; @@ -96,6 +101,9 @@ int TUKit::processCommand(char *argv[]) { TransactionalUpdate::Transaction transaction{}; + if (argv[0] == nullptr) { + throw invalid_argument{"Missing command. See --help for usage information."}; + } string arg = argv[0]; if (arg == "execute") { transaction.init(baseSnapshot); @@ -123,6 +131,16 @@ transaction.keep(); return status; } + else if (arg == "callext") { + if (argv[1] == nullptr) { + displayHelp(); + throw invalid_argument{"Missing argument for 'callext'"}; + } + transaction.resume(argv[1]); + int status = transaction.callExt(&argv[2]); // All remaining arguments + transaction.keep(); + return status; + } else if (arg == "close") { transaction.resume(argv[1]); transaction.finalize();