diff -Nru unattended-upgrades-0.90ubuntu0.6/debian/changelog unattended-upgrades-0.90ubuntu0.7/debian/changelog --- unattended-upgrades-0.90ubuntu0.6/debian/changelog 2017-05-03 01:41:25.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.7/debian/changelog 2017-07-02 23:46:26.000000000 +0000 @@ -1,3 +1,11 @@ +unattended-upgrades (0.90ubuntu0.7) xenial; urgency=medium + + * Fix lock handling between unattended-upgrade and u-u-shutdown + (LP: #1690980) + * Stop unattended-upgrade with inhibitor file instead of wih SIGUSR1 + + -- Balint Reczey Sun, 02 Jul 2017 23:46:26 +0000 + unattended-upgrades (0.90ubuntu0.6) xenial; urgency=medium * Add UbuntuESM to the list of sources automatically upgraded from by diff -Nru unattended-upgrades-0.90ubuntu0.6/test/test_remove_unused.py unattended-upgrades-0.90ubuntu0.7/test/test_remove_unused.py --- unattended-upgrades-0.90ubuntu0.6/test/test_remove_unused.py 2016-02-18 22:19:18.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.7/test/test_remove_unused.py 2017-07-02 23:46:03.000000000 +0000 @@ -92,6 +92,7 @@ Unattended-Upgrade::Remove-Unused-Dependencies "true"; """) options = MockOptions() + unattended_upgrade.LOCK_FILE = "./u-u.lock" unattended_upgrade.main( options, rootdir="./root.unused-deps") with open(self.log) as f: @@ -113,6 +114,7 @@ Unattended-Upgrade::Remove-New-Unused-Dependencies "true"; """) options = MockOptions() + unattended_upgrade.LOCK_FILE = "./u-u.lock" unattended_upgrade.main( options, rootdir="./root.unused-deps") with open(self.log) as f: diff -Nru unattended-upgrades-0.90ubuntu0.6/test/test_untrusted.py unattended-upgrades-0.90ubuntu0.7/test/test_untrusted.py --- unattended-upgrades-0.90ubuntu0.6/test/test_untrusted.py 2016-02-18 22:19:18.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.7/test/test_untrusted.py 2017-07-02 23:46:03.000000000 +0000 @@ -40,6 +40,7 @@ # run it options = MockOptions() + unattended_upgrade.LOCK_FILE = "./u-u.lock" unattended_upgrade.main(options, rootdir=self.rootdir) # read the log to see what happend with open(self.log) as f: diff -Nru unattended-upgrades-0.90ubuntu0.6/test/unattended_upgrade.py unattended-upgrades-0.90ubuntu0.7/test/unattended_upgrade.py --- unattended-upgrades-0.90ubuntu0.6/test/unattended_upgrade.py 2016-11-08 16:34:35.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.7/test/unattended_upgrade.py 2017-07-02 23:46:03.000000000 +0000 @@ -72,9 +72,8 @@ # progress information is written here PROGRESS_LOG = "/var/run/unattended-upgrades.progress" PID_FILE = "/var/run/unattended-upgrades.pid" - -# set from the sigint signal handler -SIGNAL_STOP_REQUEST = False +LOCK_FILE = "/var/run/unattended-upgrades.lock" +INHIBIT_FILE = "/var/run/unattended-upgrades.inhibit" class LoggingDateTime: @@ -291,12 +290,6 @@ return False -def signal_handler(signal, frame): - logging.warning("SIGUSR1 received, will stop") - global SIGNAL_STOP_REQUEST - SIGNAL_STOP_REQUEST = True - - def substitute(line): """ substitude known mappings and return a new string @@ -431,9 +424,6 @@ install_log = LogInstallProgress(logfile_dpkg, verbose) install_log.progress_log += ".minimal-steps" - # setup signal handler - signal.signal(signal.SIGUSR1, signal_handler) - # double check any changes we do allowed_origins = get_allowed_origins() @@ -443,8 +433,8 @@ # find smallest set smallest_partition = to_upgrade for pkgname in to_upgrade: - if SIGNAL_STOP_REQUEST: - logging.warning("SIGNAL received, stopping") + if os.path.exists(INHIBIT_FILE): + logging.warning("inhibitor file exists, stopping") return True pkg = cache[pkgname] if pkg.is_upgradable: @@ -977,7 +967,7 @@ return set(users.split()) -def reboot_if_requested_and_needed(shutdown_lock=0): +def reboot_if_requested_and_needed(): """auto-reboot (if required and the config for this is set)""" if not os.path.exists(REBOOT_REQUIRED_FILE): return @@ -1000,8 +990,6 @@ # reboot at the specified time when = apt_pkg.config.find( "Unattended-Upgrade::Automatic-Reboot-Time", "now") - if shutdown_lock > 0: - os.close(shutdown_lock) logging.warning("Found %s, rebooting" % REBOOT_REQUIRED_FILE) subprocess.call(["/sbin/shutdown", "-r", when]) @@ -1150,6 +1138,15 @@ logging.info(_("Starting unattended upgrades script")) + # lock for the shutdown check + shutdown_lock = apt_pkg.get_lock(LOCK_FILE) + if shutdown_lock < 0: + logging.error("Lock file is already taken, exiting") + sys.exit(1) + if os.path.exists(INHIBIT_FILE): + logging.debug("Shutdown is already in progress, exiting") + sys.exit(0) + # display available origin logging.info(_("Allowed origins are: %s"), allowed_origins) @@ -1333,6 +1330,7 @@ write_stamp_file() # check if we couldn't reboot on previous run because # a user was logged-in at this time + os.close(shutdown_lock) reboot_if_requested_and_needed() return @@ -1344,6 +1342,7 @@ "Unattended-Upgrade::InstallOnShutdown", False)): logger = logging.getLogger() logger.debug("Configured to install on shutdown, so exiting now") + os.close(shutdown_lock) return # check if we are in dry-run mode @@ -1363,11 +1362,7 @@ # only perform install step if we actually have packages to install pkg_install_success = True - shutdown_lock = -1 if len(pkgs_to_upgrade) > 0: - # lock for the shutdown check - its fine if the system - # is shutdown while downloading but not so much while installing - shutdown_lock = apt_pkg.get_lock("/var/run/unattended-upgrades.lock") # do install pkg_install_success = do_install(cache, pkgs_to_upgrade, @@ -1423,9 +1418,10 @@ # write timestamp file write_stamp_file() + os.close(shutdown_lock) # check if the user wants a reboot if not options.dry_run: - reboot_if_requested_and_needed(shutdown_lock) + reboot_if_requested_and_needed() if __name__ == "__main__": diff -Nru unattended-upgrades-0.90ubuntu0.6/unattended-upgrade unattended-upgrades-0.90ubuntu0.7/unattended-upgrade --- unattended-upgrades-0.90ubuntu0.6/unattended-upgrade 2016-11-08 16:34:35.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.7/unattended-upgrade 2017-07-02 23:46:03.000000000 +0000 @@ -72,9 +72,8 @@ # progress information is written here PROGRESS_LOG = "/var/run/unattended-upgrades.progress" PID_FILE = "/var/run/unattended-upgrades.pid" - -# set from the sigint signal handler -SIGNAL_STOP_REQUEST = False +LOCK_FILE = "/var/run/unattended-upgrades.lock" +INHIBIT_FILE = "/var/run/unattended-upgrades.inhibit" class LoggingDateTime: @@ -291,12 +290,6 @@ return False -def signal_handler(signal, frame): - logging.warning("SIGUSR1 received, will stop") - global SIGNAL_STOP_REQUEST - SIGNAL_STOP_REQUEST = True - - def substitute(line): """ substitude known mappings and return a new string @@ -431,9 +424,6 @@ install_log = LogInstallProgress(logfile_dpkg, verbose) install_log.progress_log += ".minimal-steps" - # setup signal handler - signal.signal(signal.SIGUSR1, signal_handler) - # double check any changes we do allowed_origins = get_allowed_origins() @@ -443,8 +433,8 @@ # find smallest set smallest_partition = to_upgrade for pkgname in to_upgrade: - if SIGNAL_STOP_REQUEST: - logging.warning("SIGNAL received, stopping") + if os.path.exists(INHIBIT_FILE): + logging.warning("inhibitor file exists, stopping") return True pkg = cache[pkgname] if pkg.is_upgradable: @@ -977,7 +967,7 @@ return set(users.split()) -def reboot_if_requested_and_needed(shutdown_lock=0): +def reboot_if_requested_and_needed(): """auto-reboot (if required and the config for this is set)""" if not os.path.exists(REBOOT_REQUIRED_FILE): return @@ -1000,8 +990,6 @@ # reboot at the specified time when = apt_pkg.config.find( "Unattended-Upgrade::Automatic-Reboot-Time", "now") - if shutdown_lock > 0: - os.close(shutdown_lock) logging.warning("Found %s, rebooting" % REBOOT_REQUIRED_FILE) subprocess.call(["/sbin/shutdown", "-r", when]) @@ -1150,6 +1138,15 @@ logging.info(_("Starting unattended upgrades script")) + # lock for the shutdown check + shutdown_lock = apt_pkg.get_lock(LOCK_FILE) + if shutdown_lock < 0: + logging.error("Lock file is already taken, exiting") + sys.exit(1) + if os.path.exists(INHIBIT_FILE): + logging.debug("Shutdown is already in progress, exiting") + sys.exit(0) + # display available origin logging.info(_("Allowed origins are: %s"), allowed_origins) @@ -1333,6 +1330,7 @@ write_stamp_file() # check if we couldn't reboot on previous run because # a user was logged-in at this time + os.close(shutdown_lock) reboot_if_requested_and_needed() return @@ -1344,6 +1342,7 @@ "Unattended-Upgrade::InstallOnShutdown", False)): logger = logging.getLogger() logger.debug("Configured to install on shutdown, so exiting now") + os.close(shutdown_lock) return # check if we are in dry-run mode @@ -1363,11 +1362,7 @@ # only perform install step if we actually have packages to install pkg_install_success = True - shutdown_lock = -1 if len(pkgs_to_upgrade) > 0: - # lock for the shutdown check - its fine if the system - # is shutdown while downloading but not so much while installing - shutdown_lock = apt_pkg.get_lock("/var/run/unattended-upgrades.lock") # do install pkg_install_success = do_install(cache, pkgs_to_upgrade, @@ -1423,9 +1418,10 @@ # write timestamp file write_stamp_file() + os.close(shutdown_lock) # check if the user wants a reboot if not options.dry_run: - reboot_if_requested_and_needed(shutdown_lock) + reboot_if_requested_and_needed() if __name__ == "__main__": diff -Nru unattended-upgrades-0.90ubuntu0.6/unattended-upgrade-shutdown unattended-upgrades-0.90ubuntu0.7/unattended-upgrade-shutdown --- unattended-upgrades-0.90ubuntu0.6/unattended-upgrade-shutdown 2016-02-18 22:19:18.000000000 +0000 +++ unattended-upgrades-0.90ubuntu0.7/unattended-upgrade-shutdown 2017-07-02 23:46:03.000000000 +0000 @@ -25,7 +25,6 @@ # import copy -import signal import sys import time import logging @@ -132,6 +131,9 @@ # run the monitoring loop and keep the "UI" updated start_time = time.time() lock_was_taken = False + # inhibit further upgrade rounds of unattended-upgrade + with open("/var/run/unattended-upgrades.inhibit", 'w') as f: + pass while True: res = apt_pkg.get_lock(options.lock_file) logging.debug("get_lock returned %i" % res) @@ -140,12 +142,6 @@ logging.debug("lock not taken") break lock_was_taken = True - # signal unattended-upgrades to stop - p = "/var/run/unattended-upgrades.pid" - if os.path.exists(p): - pid = int(open(p).read()) - logging.debug("found running unattended-upgrades pid %s" % pid) - os.kill(pid, signal.SIGUSR1) # show log log_progress() time.sleep(5)