diff -Nru unattended-upgrades-0.55ubuntu3/README unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/README --- unattended-upgrades-0.55ubuntu3/README 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/README 2011-11-09 08:25:22.000000000 +0000 @@ -1,108 +1,82 @@ Unattended upgrades ------------------- -This script can install security upgrades automatically and -unattended. However, it is not enabled by default. Most users -enable it via the Software Sources programm (available in -System/Administration), which has a simple radiobutton in the UI -for enabling unattended upgrades. +This script can upgrade packages automatically and unattended. +However, it is not enabled by default. Most users enable it via the +Software Sources program (available in System/Administration). If you would prefer to enable it from the command line, run "sudo dpkg-reconfigure -plow unattended-upgrades". -It will not install packages that require dependencies -that can't be fetched from security and it will check for conffile -prompts before the install and holds back the package that creates -them. +It will not install packages that require dependencies that can't be +fetched from allowed origins and it will check for conffile prompts +before the install and holds back any package that requires them. == Setup == -The unattended-upgrades package will *not* act unless it is enabled -explicitly. To activate this script you need to ensure that the apt -configuration contains the following lines (this can be done via the -graphical "Software Source" program or via dpkg-reconfigure): - -APT::Periodic::Update-Package-Lists "1"; -APT::Periodic::Unattended-Upgrade "1"; - -This means that it will check for upates every day and install them -(if that is possible). If you have update-notifier installed, it will -setup /etc/apt/apt.conf.d/10periodic. Just edit this file then to fit -your needs. If you do not have this file, just create it or -create/edit /etc/apt/apt.conf - you can check your configuration by -running "apt-config dump". - -== Options == - -By default it will only install from the the (Ubuntu, jaunty-security) -repository. This can be changed with the -"Unattended-Upgrade::Allowed-Origins" apt configuration list. It can -be configured to allow any (origin, archive) combination. Those values -are taken from the "Release" file on the archive server, e.g. -http://security.ubuntu.com/ubuntu/dists/hardy/Release - -The value of "origin" is taken from the "Origin:" header in the file, -the value of "archive" is taken from the "Suite:" header. -It is recommended to use the default (only security updates from Ubuntu). +The unattended-upgrades package is normally activated by +software-properties or via debconf. By default this runs an update +every day. + +The main way to specify which packages will be auto-upgraded is by +means of their "origin" and "archive". These are taken respectively +from the Origin and Suite fields of the respository's Release file, +or can be found in the output of "apt-cache policy" in the "o" and +"a" fields for the given repository. + +The default setup auto-updates packages in the main and security +archives, which means that only stable and security updates are +applied. + +This can be changed either with the +"Unattended-Upgrade::Allowed-Origins" or the +"Unattended-Upgrade::Origins-Pattern" apt configuration lists, which +can be configured in /etc/apt/apt.conf.d/50unattended-upgrades. +Also in this file are a range of other options that can be configured. + +Allowed-Origins is a simple list of patterns of the form +"origin:archive". + +Origins-Pattern allows you to give a list of +patterns to match against. For example: + + Unattended-Upgrade::Origins-Pattern { + "origin=Google\, Inc.,suite=contrib"; + "site=www.example.com,component=main"; + }; + +will upgrade a package if either the origin is "Google, Inc." and +suite is "contrib" or if it comes from www.example.com and is in +component "main". The apt-cache policy short identifiers +(e.g. "o" for "origin") are also supported. -All operations will be logged in /var/log/unattended-upgrades/. This +All operations are be logged in /var/log/unattended-upgrades/. This includes the dpkg output as well. -See https://wiki.ubuntu.com/AutomaticUpdates for more details about -this feature. - -The following configuration options are supported via the standard -apt configuration: -"APT::UnattendedUpgrades::LogDir" -"APT::UnattendedUpgrades::LogFile" -"Unattended-Upgrade::Allowed-Origins" -"Unattended-Upgrade::Package-Blacklist" -"Unattended-Upgrade::Mail" - -If you use the mail feature, make sure that /usr/bin/mail is available -and working (usually the mailx package is required). - == Debugging == If something goes wrong or if you want to report a bug about the way the script works its a good idea to run: + $ sudo unattended-upgrade --debug --dry-run and look at the resulting logfile in: /var/log/unattended-upgrades/unattended-upgrades.log then. It will contain additional debug information. -== Config example == -A example configuration that will install from the -jaunty-security and jaunty-updates repositories daily: +== Manual Setup == + +To activate this script manually you need to ensure that the apt +configuration contains the following lines (this can be done via the +graphical "Software Source" program or via dpkg-reconfigure as well): -------------------------------8<-------------------------------------- -// Automaticall upgrade packages from these (origin, archive) pairs -Unattended-Upgrade::Allowed-Origins { - "Ubuntu jaunty-security"; - "Ubuntu jaunty-updates"; -}; - -// List of packages to not update -Unattended-Upgrade::Package-Blacklist { -// "vim"; - "libc6"; - "libc6-dev"; - "libc6-i686"; -}; - -// Send email to this address for problems or packages upgrades -// If empty or unset then no email is sent -//Unattended-Upgrade::Mail "root@localhost"; - -// These APT::Periodic settings mean that each day the /etc/cron.daily/apt -// cron job will the update package list, download packages and then run -// unattended-grade to install them. -// Lock/Stamp files are in /var/lib/apt/periodic/ APT::Periodic::Update-Package-Lists "1"; -APT::Periodic::Download-Upgradeable-Packages "1"; APT::Periodic::Unattended-Upgrade "1"; -------------------------------8<-------------------------------------- - +This means that it will check for upates every day and install them +(if that is possible). If you have update-notifier installed, it will +setup /etc/apt/apt.conf.d/10periodic. Just edit this file then to fit +your needs. If you do not have this file, just create it or +create/edit /etc/apt/apt.conf - you can check your configuration by +running "apt-config dump". diff -Nru unattended-upgrades-0.55ubuntu3/data/20auto-upgrades-disabled unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/data/20auto-upgrades-disabled --- unattended-upgrades-0.55ubuntu3/data/20auto-upgrades-disabled 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/data/20auto-upgrades-disabled 2011-11-08 16:31:29.000000000 +0000 @@ -0,0 +1,2 @@ +APT::Periodic::Update-Package-Lists "0"; +APT::Periodic::Unattended-Upgrade "0"; diff -Nru unattended-upgrades-0.55ubuntu3/data/50unattended-upgrades unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/data/50unattended-upgrades --- unattended-upgrades-0.55ubuntu3/data/50unattended-upgrades 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/data/50unattended-upgrades 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -// Automatically upgrade packages from these (origin, archive) pairs -Unattended-Upgrade::Allowed-Origins { - "Ubuntu lucid-security"; -// "Ubuntu lucid-updates"; -}; - -// List of packages to not update -Unattended-Upgrade::Package-Blacklist { -// "vim"; -// "libc6"; -// "libc6-dev"; -// "libc6-i686"; -}; - -// Send email to this address for problems or packages upgrades -// If empty or unset then no email is sent, make sure that you -// have a working mail setup on your system. The package 'mailx' -// must be installed or anything that provides /usr/bin/mail. -//Unattended-Upgrade::Mail "root@localhost"; - -// Do automatic removal of new unused dependencies after the upgrade -// (equivalent to apt-get autoremove) -//Unattended-Upgrade::Remove-Unused-Dependencies "false"; - -// Automatically reboot *WITHOUT CONFIRMATION* if a -// the file /var/run/reboot-required is found after the upgrade -//Unattended-Upgrade::Automatic-Reboot "false"; - - -// Use apt bandwidth limit feature, this example limits the download -// speed to 70kb/sec -//Acquire::http::Dl-Limit "70"; \ No newline at end of file diff -Nru unattended-upgrades-0.55ubuntu3/data/50unattended-upgrades.Debian unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/data/50unattended-upgrades.Debian --- unattended-upgrades-0.55ubuntu3/data/50unattended-upgrades.Debian 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/data/50unattended-upgrades.Debian 2012-03-09 08:41:10.000000000 +0000 @@ -0,0 +1,67 @@ +// Automatically upgrade packages from these origin patterns +Unattended-Upgrade::Origins-Pattern { + // Codename based matching: + // This will follow the migration of a release through different + // archives (e.g. from testing to stable and later oldstable). +// "o=Debian,n=squeeze"; +// "o=Debian,n=squeeze-updates"; +// "o=Debian,n=squeeze-proposed-updates"; +// "o=Debian,n=squeeze,l=Debian-Security"; + + // Archive or Suite based matching: + // Note that this will silently match a different release after + // migration to the specified archive (e.g. testing becomes the + // new stable). +// "o=Debian,a=stable"; +// "o=Debian,a=stable-updates"; +// "o=Debian,a=proposed-updates"; + "origin=Debian,archive=stable,label=Debian-Security"; +}; + +// List of packages to not update +Unattended-Upgrade::Package-Blacklist { +// "vim"; +// "libc6"; +// "libc6-dev"; +// "libc6-i686"; +}; + +// This option allows you to control if on a unclean dpkg exit +// unattended-upgrades will automatically run +// dpkg --force-confold --configure -a +// The default is true, to ensure updates keep getting installed +//Unattended-Upgrade::AutoFixInterruptedDpkg "false"; + +// Split the upgrade into the smallest possible chunks so that +// they can be interrupted with SIGUSR1. This makes the upgrade +// a bit slower but it has the benefit that shutdown while a upgrade +// is running is possible (with a small delay) +//Unattended-Upgrade::MinimalSteps "true"; + +// Install all unattended-upgrades when the machine is shuting down +// instead of doing it in the background while the machine is running +// This will (obviously) make shutdown slower +//Unattended-Upgrade::InstallOnShutdown "true"; + +// Send email to this address for problems or packages upgrades +// If empty or unset then no email is sent, make sure that you +// have a working mail setup on your system. A package that provides +// 'mailx' must be installed. +//Unattended-Upgrade::Mail "root@localhost"; + +// Set this value to "true" to get emails only on errors. Default +// is to always send a mail if Unattended-Upgrade::Mail is set +//Unattended-Upgrade::MailOnlyOnError "true"; + +// Do automatic removal of new unused dependencies after the upgrade +// (equivalent to apt-get autoremove) +//Unattended-Upgrade::Remove-Unused-Dependencies "false"; + +// Automatically reboot *WITHOUT CONFIRMATION* if a +// the file /var/run/reboot-required is found after the upgrade +//Unattended-Upgrade::Automatic-Reboot "false"; + + +// Use apt bandwidth limit feature, this example limits the download +// speed to 70kb/sec +//Acquire::http::Dl-Limit "70"; diff -Nru unattended-upgrades-0.55ubuntu3/data/50unattended-upgrades.Ubuntu unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/data/50unattended-upgrades.Ubuntu --- unattended-upgrades-0.55ubuntu3/data/50unattended-upgrades.Ubuntu 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/data/50unattended-upgrades.Ubuntu 2012-03-09 08:41:19.000000000 +0000 @@ -0,0 +1,55 @@ +// Automatically upgrade packages from these (origin:archive) pairs +Unattended-Upgrade::Allowed-Origins { + "${distro_id}:${distro_codename}-security"; +// "${distro_id}:${distro_codename}-updates"; +// "${distro_id}:${distro_codename}-proposed"; +// "${distro_id}:${distro_codename}-backports"; +}; + +// List of packages to not update +Unattended-Upgrade::Package-Blacklist { +// "vim"; +// "libc6"; +// "libc6-dev"; +// "libc6-i686"; +}; + +// This option allows you to control if on a unclean dpkg exit +// unattended-upgrades will automatically run +// dpkg --force-confold --configure -a +// The default is true, to ensure updates keep getting installed +//Unattended-Upgrade::AutoFixInterruptedDpkg "false"; + +// Split the upgrade into the smallest possible chunks so that +// they can be interrupted with SIGUSR1. This makes the upgrade +// a bit slower but it has the benefit that shutdown while a upgrade +// is running is possible (with a small delay) +//Unattended-Upgrade::MinimalSteps "true"; + +// Install all unattended-upgrades when the machine is shuting down +// instead of doing it in the background while the machine is running +// This will (obviously) make shutdown slower +//Unattended-Upgrade::InstallOnShutdown "true"; + +// Send email to this address for problems or packages upgrades +// If empty or unset then no email is sent, make sure that you +// have a working mail setup on your system. A package that provides +// 'mailx' must be installed. +//Unattended-Upgrade::Mail "root@localhost"; + +// Set this value to "true" to get emails only on errors. Default +// is to always send a mail if Unattended-Upgrade::Mail is set +//Unattended-Upgrade::MailOnlyOnError "true"; + +// Do automatic removal of new unused dependencies after the upgrade +// (equivalent to apt-get autoremove) +//Unattended-Upgrade::Remove-Unused-Dependencies "false"; + +// Automatically reboot *WITHOUT CONFIRMATION* if a +// the file /var/run/reboot-required is found after the upgrade +//Unattended-Upgrade::Automatic-Reboot "false"; + + +// Use apt bandwidth limit feature, this example limits the download +// speed to 70kb/sec +//Acquire::http::Dl-Limit "70"; diff -Nru unattended-upgrades-0.55ubuntu3/debian/NEWS.Debian unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/NEWS.Debian --- unattended-upgrades-0.55ubuntu3/debian/NEWS.Debian 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/NEWS.Debian 2011-10-07 07:31:17.000000000 +0000 @@ -8,4 +8,4 @@ install/upgrade. There is a new option called "--dry-run" to get this behavior back. - -- Michael Vogt Fri, 03 Jul 2009 09:15:08 +0200 + -- Michael Vogt Fri, 03 Jul 2009 09:15:08 +0200 diff -Nru unattended-upgrades-0.55ubuntu3/debian/changelog unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/changelog --- unattended-upgrades-0.55ubuntu3/debian/changelog 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/changelog 2013-07-12 19:54:21.000000000 +0000 @@ -1,3 +1,392 @@ +unattended-upgrades (0.76ubuntu1~ubuntu10.04.1) lucid-backports; urgency=low + + * backport for lucid, minimal source changes: + - drop dh_python2 as this is not available in lucid + (LP: #1200367) + + -- Michael Vogt Fri, 12 Jul 2013 21:54:21 +0200 + +unattended-upgrades (0.76ubuntu1) precise-proposed; urgency=low + + * unattended-upgrade: ignore md5sum "newconffile" (LP: #936870) + + -- Brian Murray Thu, 08 Nov 2012 11:52:39 -0800 + +unattended-upgrades (0.76) unstable; urgency=low + + * add basic "Unattended-Upgrades::InstallOnShutdown" option to do + the install step on shutdown (closes: #652982) instead of doing + it in the backgroud while the machine is running + * test improvements + * fix mispelled "Unattended-Upgrade::MinimalSteps" (and add compat + mode) + * unattended-upgrade: + - cleanup FDs to hopefully fix zombies (closes: #646620) + + -- Michael Vogt Fri, 09 Mar 2012 09:42:33 +0100 + +unattended-upgrades (0.75.1) unstable; urgency=low + + * print conffile hold-backs to stdout to ensure its part of + the cron mail (LP: #773007), thanks to Jean-Baptiste Lallement + * unattended-upgrade: + - fix crash on automatic-reboot, thanks to Teodor (closes: #651822) + * typo fixes, thanks to Lei Zhang + + -- Michael Vogt Mon, 12 Dec 2011 14:01:41 +0100 + +unattended-upgrades (0.75) unstable; urgency=low + + * add tests for compat mode and spaces in a origin + * escape "," in the Allowed-Origins compat mode (LP: #824856) + * merged lp:~mvo/unattended-upgrades/unshadow-versions, this will + ensure that higher versions in a non-origin branch do not "shadow" + the versions from a desired origin (LP: #891747) + + -- Michael Vogt Tue, 22 Nov 2011 15:27:56 +0100 + +unattended-upgrades (0.74.4) UNRELEASED; urgency=low + + * add tests for compat mode and spaces in a origin + * escape "," in the Allowed-Origins compat mode (LP: #824856) + * merged lp:~mvo/unattended-upgrades/unshadow-versions, this will + ensure that higher versions in a non-origin branch do not "shadow" + the versions from a desired origin (LP: #891747) + + -- Michael Vogt Mon, 21 Nov 2011 18:00:57 +0100 + +unattended-upgrades (0.74.3) unstable; urgency=low + + * add missing "." to dh_installinit (closes: #648216) + + -- Michael Vogt Wed, 09 Nov 2011 20:16:12 +0100 + +unattended-upgrades (0.74.2) unstable; urgency=low + + * add missing "." to dh_installinit (closes: #648216) + + -- Michael Vogt Wed, 09 Nov 2011 19:27:43 +0100 + +unattended-upgrades (0.74.1) unstable; urgency=low + + * debian/unattended-upgrades.init: + - only run unattended-upgrades-shutdown if its actually installed + (closes: #643607) + * pm/sleep.d/10_unattended-upgrades-hibernate: + - only run shutdown helper when its available + * updated README and defaults based on the work from + Reuben Thomas, many thanks (closes: #632336) + * lintian fixes + * debian/rules, debian/unattended-upgrades.init: + - fix dh_initallinit arguments (closes: #630732) + + -- Michael Vogt Wed, 09 Nov 2011 09:26:56 +0100 + +unattended-upgrades (0.74) unstable; urgency=low + + * test improvements + * fix crash when no packages are upgraded + * only run dpkg if there are packages to upgrade (closes: #647476) + * include "stable-updates" in the configuration example + * debian/po/de.po: + - updated, thanks to Helge Kreutzmann (closes: #647172) + * debian/rules: + - install initscripts but do not run them on install/upgrade + (closes: #645919), thanks to Teodor MICU + * data/50unattended-upgrades.Debian: + - update default Debian config for squeeze, thanks to + John Feuerstein for the example (closes: #609854) + * debian/prerm: + - ignore failures from versions where the initscript is run + with "stop" even when not in shutdown mode (closes: #645919) + * unattended-upgrade: + - ensure to release shutdown-lock before shutting down + (closes: #645919) + * debian/postinst, data/20auto-upgrades-disabled: + - allow disabling via debconf (closes: #645971) + + -- Michael Vogt Tue, 08 Nov 2011 17:37:31 +0100 + +unattended-upgrades (0.73.1) unstable; urgency=low + + [ Michael Vogt ] + * unattended-upgrade: + - re-eval pkgs_kept_back after a successful upgrade to ensure + that its in sync with the cache (closes: #639840), thanks to + Iain Nicol + - do not write dpkg terminal log in --dry-run mode instead just + output to stdout (closes: #640329) + * test/test_origin_pattern.py: + - test fixes + + [ Peter Eisentraut ] + * debian/unattended-upgrade.init: + - add support for "status" action + + [ Iain Nicol ] + * unattended-upgrade: + - ensure pkgs_to_upgrade stays sorted and fix crash + + -- Michael Vogt Wed, 19 Oct 2011 15:16:20 +0200 + +unattended-upgrades (0.73ubuntu1) oneiric; urgency=low + + * debian/po/de.po: + - updated, closes: #631316 (thanks to Helge Kreutzmann) + * merged lp:~brian-murray/unattended-upgrades/init-eol, this + makes the shutdown message nicer, thanks to Brian Murray + * unattended-upgrade: + - write progress information /var/run/unattended-upgrades.progres + so that the progress can be displayed on shutdown + * unattended-upgrade-shutdown: + - show install progress during shutdown + * po/unattended-upgrades.pot: + - refresh + * unattended-upgrade: + - Do not upgrade apps if "XB-Upgrade-Requires: app-restart" + is set in the debian/control file. + This can be override with the option: + Unattended-Upgrade::IgnoreAppsRequireRestart=true + + -- Michael Vogt Tue, 19 Jul 2011 16:44:51 +0200 + +unattended-upgrades (0.72.3) unstable; urgency=low + + * debian/rules: + - run the original targets after override_dh_ + * test/create_debug_lock.py, unattended-upgrade: + - fix two missing python-apt 0.8 transition issues + (thanks to Reinhard Tartler, closes: #630192) + + -- Michael Vogt Thu, 16 Jun 2011 09:13:49 +0200 + +unattended-upgrades (0.72.2) unstable; urgency=low + + * po/fr.po: + - updated, thanks to to Steve Petruzzello (closes: #622718) + * debian/po/ca.po: + - added, thanks to Innocent De Marchi (closes: #628368) + * unattended-upgrade: + - fix conffile prompt detection (closes: #624148) + * debian/rules, debian/control: + - move to dh7 + * work with python-apt 0.8 (closes: #630192) + * switch to dh_python2 + + -- Michael Vogt Wed, 15 Jun 2011 09:50:25 +0200 + +unattended-upgrades (0.72.1ubuntu1) natty; urgency=low + + * unattended-upgrade: + - fix detection of unclean dpkg state if another package manager + is working (LP: #754330) + + -- Michael Vogt Tue, 12 Apr 2011 10:34:42 +0200 + +unattended-upgrades (0.72ubuntu1) natty; urgency=low + + * unattended-upgrade, data/50unattended-upgrades.{Debian,Ubuntu}: + - automatically fix a interrupted dpkg (e.g. from a powerfailure) + (LP: #584817) + - add Unattended-Upgrade::AutoFixInterruptedDpkg to allow the admin + to configure this option + + -- Michael Vogt Thu, 07 Apr 2011 11:43:26 +0200 + +unattended-upgrades (0.71ubuntu1) natty; urgency=low + + * debian/po/da.po: + - added, thanks toJoe Dalton (closes: #619320) + * unattended-upgrade, test/test_conffile.py: + - use apt_inst.DebFile.control.extractdata() instead of + apt_inst.debExtractControl() to not hit the limit of the + tag section parser (LP: #724994) + - add regression test + + -- Michael Vogt Wed, 06 Apr 2011 11:44:48 +0200 + +unattended-upgrades (0.70ubuntu1) natty; urgency=low + + * merged lp:~mvo/unattended-upgrades/minimal-steps-upgrade + - This allows performaing the upgrades in minimal chunks so + that they can be interrupted (relatively) quickly with + SIGUSR1 + - This feature is not enabled by default yet, in order + to use it, uncomment the line in 50unattended-upgrades: + Unattended-Upgrades::MinimalSteps "true"; + LP: #729214 + + -- Michael Vogt Mon, 14 Mar 2011 11:49:02 +0100 + +unattended-upgrades (0.70) unstable; urgency=low + + * pm/sleep.d/10_unattended-upgrades-hibernate: + - remove some unneeded lines from the script, thanks to + Seth Arnold (LP: #595792) + * test/test_mail.py: + - add tests for apt-listchanges.conf parser + * unattended-upgrade: + - add new Unattended-Upgrade::Origins-Pattern option that is much + more flexible than the previous Allowed-Origins. It supports + match patterns like: + "origin=Debian,label=Debian-Security,component=main" + "site=security.debian.org" + - add support for escaping, so "origin=Google\, Inc,suite=stable" + is possible (thanks to Alexander Reichle-Schmehl), closes: #609876 + - do not send a summary mail in --dry-run mode (closes: #609516) + * make Package-Blacklist a regexp (thanks to Raymond Lee) and add + test + * README: + - fixed outdated ubuntu centric info (closes: #611675) + * po/fr.po: + - updated, thanks to Steve Petruzzello (closes: #597606) + * data/50unattended-upgrades.Debian: + - add oldstable example (closes: #515980) + * test/test_against_real_archive.py, test/aptroot: + - add regression test that talks against the real archive + * unattended-upgrade: + - remove MyCache, apt.Cache has all the features we need + - add rootdir option to better support automatic testing + * unattended-upgrade: + - create logdir based on configuration, thanks to Arno Schuring + (closes: #615486) + - support Unattended-Upgrade::Log{Dir,File} as a config option, but + keep APT::UnattendedUpgrades::Log{Dir,File} for compatiblity + * test/test_logdir.py: + - add test for _setup_logging + + -- Michael Vogt Fri, 04 Mar 2011 13:17:39 +0100 + +unattended-upgrades (0.65ubuntu2) natty; urgency=low + + * add missing lsb-release build-depends + + -- Michael Vogt Fri, 07 Jan 2011 19:00:05 +0100 + +unattended-upgrades (0.65ubuntu1) natty; urgency=low + + [ Michael Vogt ] + * debian/po/pt_BR.po: + - updated, thanks to Adriano Rafael Gomes (closes: #607403) + * debian/rules: + - use different template depending on the build host + (ubuntu,debian) + - remove obsolete arch-build target + * data/50unattended-upgrades.Debian: + - add debian specific template + + [ Nobuto MURATA ] + * data/50unattended-upgrades.Ubuntu: + - adapt repository format for Ubuntu, LP: #691886 + + -- Michael Vogt Fri, 07 Jan 2011 15:57:20 +0100 + +unattended-upgrades (0.64ubuntu1) natty; urgency=low + + * debian/postinst: + - fixup incorrect LSB Default-Start and Stop values + + -- Michael Vogt Thu, 18 Nov 2010 09:35:39 +0100 + +unattended-upgrades (0.63ubuntu1) natty; urgency=low + + * debian/unattended-upgrades.init: + - fix default stop value, thanks to Petter Reinholdtsen, + closes: #593987 + * unattended-upgrade: + - add new Unattended-Upgrade::MailOnlyOnError option that will + make the script only send a mail when a error occured (thanks + to Steffen Kittel) + * test/test_mail.py: + - add test for Unattended-Upgrade::MailOnlyOnError feature + * README: + - improve description for the Allowed-Origins option + * test/Makefile: + - run test on bzr-buildpackage and fail if one of the tests + fail + + -- Michael Vogt Wed, 10 Nov 2010 15:18:37 +0100 + +unattended-upgrades (0.62.2) unstable; urgency=low + + * debian/postinst: + - add fixup code for installs with incorrect values from + the stop value (really closes: #593987), thanks to + Peter Reinholdtsen + + -- Michael Vogt Thu, 18 Nov 2010 09:00:44 +0100 + +unattended-upgrades (0.62.1) unstable; urgency=low + + * debian/unattended-upgrades.init: + - fix default stop value, thanks to Petter Reinholdtsen, + closes: #593987 + + -- Michael Vogt Wed, 17 Nov 2010 21:26:10 +0100 + +unattended-upgrades (0.62ubuntu1) maverick; urgency=low + + * merged fixes from debian/sid, notably allowing ":" + as seperator for (origin, archive) + + -- Michael Vogt Thu, 26 Aug 2010 18:45:07 +0200 + +unattended-upgrades (0.62) unstable; urgency=low + + [ Michael Vogt ] + * updated Russian program translation, thanks to + Yuri Kozlov, closes: #592646 + * updated pt_BR translations, thanks to Sergio Cipolla, + closes: #593755 + + [ Alex Owen ] + * allow ":" as seperator in Unattended-Upgrade::Allowed-Origins + (closes: #536754) + + -- Michael Vogt Thu, 26 Aug 2010 18:41:06 +0200 + +unattended-upgrades (0.61) unstable; urgency=low + + * merged changes from the ubuntu branch + + -- Michael Vogt Mon, 02 Aug 2010 12:10:00 +0200 + +unattended-upgrades (0.60ubuntu3) maverick; urgency=low + + * merged changes from debian-sid + * fix crash when the old package had a conffile but that + disappears in the new pacakge + + -- Michael Vogt Mon, 02 Aug 2010 12:08:21 +0200 + +unattended-upgrades (0.60ubuntu2) maverick; urgency=low + + * debian/control: + - add missing lsb-release dependency + * debian/control: + - depend on python-apt (>= 0.7.90) + * unattended-upgrade: + - port to python-apt 0.8 API + + -- Michael Vogt Mon, 02 Aug 2010 10:29:46 +0200 + +unattended-upgrades (0.60ubuntu1) maverick; urgency=low + + * Include reboot required notification in sent emails (LP: #415202) + and add test for it (thanks to Paul Elliott for the initial patch) + * allow ${distro_id} and ${distro_codename} in + Unattended-Upgrade::Allowed-Origins and update conffile to it + + -- Michael Vogt Mon, 17 May 2010 15:19:21 +0200 + +unattended-upgrades (0.55ubuntu4) lucid-proposed; urgency=low + + * unattended-upgrade: + - fix rewind_cache if a pkg fails to get marked for upgrade + (LP: #571734) + + -- Michael Vogt Thu, 29 Apr 2010 16:39:45 +0200 + unattended-upgrades (0.55ubuntu3) lucid; urgency=low [ Michael Vogt ] @@ -90,6 +479,27 @@ -- Michael Vogt Tue, 16 Jun 2009 11:52:32 +0200 +unattended-upgrades (0.42debian2) UNRELEASED; urgency=low + + * apply patch by Julian Andres Klode to move to the new + python-apt 0.8 API (closes: #572088) + + -- Michael Vogt Wed, 21 Apr 2010 10:19:05 +0200 + +unattended-upgrades (0.42debian1) unstable; urgency=low + + * debian/po/sk.po: + - new translation, thanks to helix84, closes: #532959 + * debian/po/ru.po: + - updated, thanks to Yuri Kozlov, closes: #527111 + * debian/po/eu.po: + - updated, thanks to Piarres Beobide, closes: #513436 + * debian/links + - add symlink to make binary name and package name match, + closes: #428965 + + -- Michael Vogt Thu, 25 Jun 2009 16:07:29 +0200 + unattended-upgrades (0.41ubuntu1) karmic; urgency=low * fix lintian warnings @@ -102,6 +512,18 @@ -- Michael Vogt Mon, 15 Jun 2009 10:27:51 +0200 +unattended-upgrades (0.41debian1) unstable; urgency=low + + * fix lintian warnings + * add man-page (closes: #394277) + * debian/po/cs.po: + - updated Czech translation (thanks to Vítězslav Kotrla) + closes: #532136 + * add kept back packages to the status email (thanks to + Maximilian Gaukler, closes: #526505) + + -- Michael Vogt Wed, 10 Jun 2009 20:36:39 +0200 + unattended-upgrades (0.40ubuntu1) karmic; urgency=low * data/50unattended-upgrades: @@ -114,6 +536,22 @@ -- Michael Vogt Wed, 06 May 2009 21:54:16 +0200 +unattended-upgrades (0.40debian1) unstable; urgency=low + + * unattended-upgrade: + - use the new python-apt apt.Package.Version class when + checking for the candidate origin (closes: #526791) + * data/50unattended-upgrades: + - updated for squeeze + + -- Michael Vogt Wed, 06 May 2009 08:18:50 +0200 + +unattended-upgrades (0.39debian1) unstable; urgency=low + + * Merging new Ubuntu release + + -- Michael Vogt Tue, 03 Mar 2009 08:38:08 +0100 + unattended-upgrades (0.39) jaunty; urgency=low * debian/po/fr.po: @@ -141,6 +579,20 @@ -- Michael Vogt Sat, 05 Jan 2009 10:38:34 +0100 +unattended-upgrades (0.37debian1) unstable; urgency=low + + * debian/po: + - add ru.po debian template (closes: #509032) + - add eu.po debian template (closes: #508983) + - add fr.po debian template (closes: #508389) + - add ja.po debian template (closes: #509343) + - add fi.po debian template (closes: #509370) + * po/eu.po: + - added eu.po translation (closes: #508984) + - added ja.po translation (closes: #509748) + + -- Michael Vogt Mon, 05 Jan 2009 10:34:14 +0100 + unattended-upgrades (0.37) jaunty; urgency=low * better debconf template and description (thanks to the @@ -167,6 +619,40 @@ -- Michael Vogt Mon, 15 Dec 2008 09:46:42 +0100 +unattended-upgrades (0.36debian1) unstable; urgency=low + + * merge from ubuntu: + * make cache calculations quicker (thanks to Ben Hutchings, + closes #475610) + * add hostname in mail header, thanks to Arthur de Jong + (closes: #502171, LP: #245417) + * better email summary of the performed actions + (closes: #502351) + * be more robust against failures to read the deb (LP: #227448) + * better debconf template and description (thanks to the + debian-l10 team (closes: #508136) + * debian/po/sv.po: + - add sv.po debian template (closes: #508225) + * debian/po/it.po: + - add it.po debian template (closes: #508193) + * debian/po/ja.po: + - add ja.po debian template (closes: #508564) + * debian/po/de.po: + - add de.po debian template (closes: #508481) + * po/fr.po: + - add fr.po translation (closes: #508390) + * po/cs.po: + - add cs.po translation (closes: #508702) + * po/pt.po: + - add pt.po translation (closes: #508705) + * unattended-upgrade: + - better default permissions of the install log + (closes: #507638) + - only disable apt-listchanges if it is not set to + 'mail' (closes: #507639) + + -- Michael Vogt Tue, 09 Dec 2008 01:45:31 +0100 + unattended-upgrades (0.36) jaunty; urgency=low * make cache calculations quicker (thanks to Ben Hutchings, @@ -179,6 +665,14 @@ -- Michael Vogt Wed, 26 Nov 2008 21:31:42 +0100 +unattended-upgrades (0.35debian1) unstable; urgency=low + + * merge from ubuntu (new upstream release) + * add debconf prompt (priority medium) that asks if auto + updates should be enabled + + -- Michael Vogt Wed, 26 Nov 2008 10:46:08 +0100 + unattended-upgrades (0.35) jaunty; urgency=low * updated for jaunty @@ -251,6 +745,20 @@ -- Michael Vogt Wed, 11 Jul 2007 11:19:49 +0100 +unattended-upgrades (0.25.1debian1-0.1) unstable; urgency=low + + * Non-Maintainter Update (BSP) + * Add dependency on apt (>=0.7) + (closes: #475611) + + -- Bas Zoetekouw Sat, 14 Jun 2008 14:55:51 +0200 + +unattended-upgrades (0.25.1debian1) unstable; urgency=low + + * documentation updated + + -- Michael Vogt Thu, 07 Jun 2007 13:36:47 +0200 + unattended-upgrades (0.25.1) gutsy; urgency=low * documentation updated @@ -263,6 +771,12 @@ -- Michael Vogt Wed, 16 May 2007 15:21:11 +0200 +unattended-upgrades (0.24debian1) unstable; urgency=low + + * new upstream version + + -- Michael Vogt Tue, 24 Apr 2007 23:34:15 +0200 + unattended-upgrades (0.23ubuntu3) feisty-proposed; urgency=low * added missing README (thanks to siretart, LP#109564) @@ -297,6 +811,12 @@ -- Michael Vogt Fri, 3 Nov 2006 22:31:02 +0100 +unattended-upgrades (0.2) unstable; urgency=low + + * initial debian upload + + -- Michael Vogt Mon, 2 Oct 2006 11:06:50 +0200 + unattended-upgrades (0.1ubuntu6) edgy; urgency=low * debian/control: diff -Nru unattended-upgrades-0.55ubuntu3/debian/compat unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/compat --- unattended-upgrades-0.55ubuntu3/debian/compat 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/compat 2011-10-07 07:31:17.000000000 +0000 @@ -1 +1 @@ -5 \ No newline at end of file +7 \ No newline at end of file diff -Nru unattended-upgrades-0.55ubuntu3/debian/control unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/control --- unattended-upgrades-0.55ubuntu3/debian/control 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/control 2013-07-12 19:52:12.000000000 +0000 @@ -2,7 +2,7 @@ Section: admin Priority: optional Maintainer: Michael Vogt -Build-Depends: debhelper (>= 5.0.37.2), po-debconf +Build-Depends: debhelper (>= 7.0.50~), po-debconf, lsb-release Build-Depends-Indep: python, python-distutils-extra Standards-Version: 3.8.3 Vcs-Bzr: http://code.launchpad.net/~ubuntu-core-dev/unattended-upgrades/ubuntu/ @@ -10,7 +10,7 @@ Package: unattended-upgrades Architecture: all Depends: ${shlibs:Depends}, ${misc:Depends}, debconf, python, - python-apt (>= 0.7.9), apt-utils (>= 0.7), apt (>= 0.7), ucf + python-apt (>= 0.7.90), apt-utils, apt, ucf, lsb-release Suggests: bsd-mailx Description: automatic installation of security upgrades This package can download and install security upgrades automatically diff -Nru unattended-upgrades-0.55ubuntu3/debian/po/ca.po unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/po/ca.po --- unattended-upgrades-0.55ubuntu3/debian/po/ca.po 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/po/ca.po 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,31 @@ +# unattended-upgrades po-debconf translation to Catalan +# Copyright (C) 2007 Software in the Public Interest, SPI Inc. +# This file is distributed under the same license as the PACKAGE package. +# Innocent De Marchi , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: unattended-upgrades 0.70\n" +"Report-Msgid-Bugs-To: unattended-upgrades@packages.debian.org\n" +"POT-Creation-Date: 2009-07-06 17:32+0100\n" +"PO-Revision-Date: 2011-06-01 18:28+0100\n" +"Last-Translator: Innocent De Marchi \n" +"Language-Team: Catalan <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Catalan\n" +"X-Poedit-Country: SPAIN\n" + +#. Type: boolean +#. Description +#: ../templates:2001 +msgid "Automatically download and install stable updates?" +msgstr "Desitjau descarregar i instal·lar automàticament les actualitzacions de la versió estable?" + +#. Type: boolean +#. Description +#: ../templates:2001 +msgid "Applying updates on a frequent basis is an important part of keeping systems secure. By default, updates need to be applied manually using package management tools. Alternatively, you can choose to have this system automatically download and install security updates." +msgstr "La instal·lació de les actualitzacions amb freqüència és un aspecte important per a mantenir la seguretat del sistema. Per defecte, les actualitzacions s'han de fer manualment utilitzant les eines de gestió de paquets. Si ho preferiu, podeu optar per fer que el sistema descarregui i instal li automàticament les actualitzacions de seguretat." + diff -Nru unattended-upgrades-0.55ubuntu3/debian/po/da.po unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/po/da.po --- unattended-upgrades-0.55ubuntu3/debian/po/da.po 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/po/da.po 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,38 @@ +# Danish translation unattended-upgrades. +# Copyright (C) 2011 unattended-upgrades og nedenstående oversættere. +# This file is distributed under the same license as the unattended-upgrades package. +# Joe Hansen (joedalton2@yahoo.dk), 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: unattended-upgrades\n" +"Report-Msgid-Bugs-To: unattended-upgrades@packages.debian.org\n" +"POT-Creation-Date: 2009-07-06 17:32+0100\n" +"PO-Revision-Date: 2011-03-22 19:25+0200\n" +"Last-Translator: Joe Hansen \n" +"Language-Team: Danish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: boolean +#. Description +#: ../templates:2001 +msgid "Automatically download and install stable updates?" +msgstr "Hent og installer automatisk stabile opdateringer?" + +#. Type: boolean +#. Description +#: ../templates:2001 +msgid "" +"Applying updates on a frequent basis is an important part of keeping systems " +"secure. By default, updates need to be applied manually using package " +"management tools. Alternatively, you can choose to have this system " +"automatically download and install security updates." +msgstr "" +"Løbende installation af opdateringer er en vigtig del af at holde et system " +"sikkert. Som standard skal opdateringer installeres manuelt med " +"pakkehåndteringsværktøjer. Alternativt kan du automatisk vælge at lade dette " +"system hente og installere sikkerhedsmæssige opdateringer." + + diff -Nru unattended-upgrades-0.55ubuntu3/debian/po/de.po unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/po/de.po --- unattended-upgrades-0.55ubuntu3/debian/po/de.po 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/po/de.po 2011-11-08 16:31:29.000000000 +0000 @@ -1,15 +1,16 @@ -# Translation of unattended-upgrades debconf templates to German -# Copyright (C) Helge Kreutzmann , 2008. +# Translation of unattended-upgrades templates to German +# Copyright (C) Helge Kreutzmann , 2009, 2011. # This file is distributed under the same license as the unattended-upgrades package. # msgid "" msgstr "" -"Project-Id-Version: unattended-upgrades 0.35debian2\n" +"Project-Id-Version: unattended-upgrades 0.73.1\n" "Report-Msgid-Bugs-To: unattended-upgrades@packages.debian.org\n" -"POT-Creation-Date: 2008-12-08 18:38+0100\n" -"PO-Revision-Date: 2008-12-09 18:19+0100\n" +"POT-Creation-Date: 2009-07-06 17:32+0100\n" +"PO-Revision-Date: 2011-10-30 19:26+0100\n" "Last-Translator: Helge Kreutzmann \n" "Language-Team: de \n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -29,8 +30,105 @@ "management tools. Alternatively, you can choose to have this system " "automatically download and install security updates." msgstr "" -"Das regelmäßige Anwenden von Aktualisierungen ist ein wichtiger Beitrag zu " -"einem sicherem System. Standardmäßig müssen Aktualisierungen mit den " -"Paketwerkzeugen manuell eingespielt werden. Alternativ können Sie auswählen, " -"dass dieses System automatisch die Sicherheitsaktualisierungen herunterlädt " -"und installiert." +"Das häufige Anwenden von Aktualisierungen ist ein wichtiger Aspekt beim " +"Erhalt der Sicherheit von Systemen. Standardmäßig müssen Aktualisierungen " +"manuell mit den Paketverwaltungswerkzeugen eingespielt werden. Alternativ " +"können Sie wählen, dass das System automatisch die " +"Sicherheitsaktualisierungen herunterlädt und installiert." + +#~ msgid "print debug messages" +#~ msgstr "Debug-Meldungen ausgeben" + +#~ msgid "Initial blacklisted packages: %s" +#~ msgstr "Anfänglich ausgeschlossene Pakete: %s" + +#~ msgid "Starting unattended upgrades script" +#~ msgstr "Unattended-Upgrades-Skript wird gestartet" + +#~ msgid "Allowed origins are: %s" +#~ msgstr "Erlaubte Quellen sind: %s" + +#~ msgid "Cache has broken packages, exiting" +#~ msgstr "" +#~ "Zwischenspeicher (Cache) enthält defekte Pakete, Programm wird beendet" + +#~ msgid "package '%s' upgradable but fails to be marked for upgrade (%s)" +#~ msgstr "" +#~ "Upgrade von »%s« möglich, aber Markierung für Upgrade konnte nicht " +#~ "gesetzt werden (%s)" + +#~ msgid "GetArchives() failed: '%s'" +#~ msgstr "GetArchives() fehlgeschlagen: »%s«" + +#~ msgid "An error ocured: '%s'" +#~ msgstr "Ein Fehler ist aufgetreten: »%s«" + +#~ msgid "The URI '%s' failed to download, aborting" +#~ msgstr "" +#~ "Von der URI »%s« konnte nicht heruntergeladen werden, Programm wird " +#~ "beendet" + +#~ msgid "Package '%s' has conffile prompt and needs to be upgraded manually" +#~ msgstr "" +#~ "Paket »%s« enthält eine Conffile-Eingabeaufforderung und das Upgrade muss " +#~ "manuell durchgeführt werden" + +#~ msgid "package '%s' not upgraded" +#~ msgstr "Upgrade von Paket »%s« nicht durchgeführt" + +#~ msgid "No packages found that can be upgraded unattended" +#~ msgstr "" +#~ "Keine Pakete gefunden, von denen ein unbeaufsichtigtes Upgrade " +#~ "durchgeführt werden kann." + +#~ msgid "Packages that are upgraded: %s" +#~ msgstr "Pakete, von denen ein Upgrade durchgeführt wird: %s" + +#~ msgid "Writing dpkg log to '%s'" +#~ msgstr "Dpkg-Protokoll wird nach »%s« geschrieben" + +#~ msgid "pm.GetArchives() failed" +#~ msgstr "pm.GetArchives() fehlgeschlagen" + +#~ msgid "Installing the upgrades failed!" +#~ msgstr "Installation der Upgrades fehlgeschlagen!" + +#~ msgid "error message: '%s'" +#~ msgstr "Fehlermeldung: »%s«" + +#~ msgid "dpkg returned a error! See '%s' for details" +#~ msgstr "Dpkg meldete einen Fehler! Lesen Sie »%s« für Details" + +#~ msgid "All upgrades installed" +#~ msgstr "Alle Upgrades installiert" + +#~ msgid "" +#~ "No '/usr/bin/mail', can not send mail. You probably want to install the " +#~ "'mailx' package." +#~ msgstr "" +#~ "»/usr/bin/mail« nicht vorhanden, es können keine E-Mails versendet " +#~ "werden. Wahrscheinlich müssen Sie das Paket »mailx« installieren." + +#~ msgid "unattended-upgrades result for '%s'" +#~ msgstr "Ergebnis von unattended-upgrades für »%s«" + +#~ msgid "" +#~ "Unattended upgrade returned: %s\n" +#~ "\n" +#~ msgstr "" +#~ "Unbeaufsichtiges Upgrade meldete zurück: %s\n" +#~ "\n" + +#~ msgid "Packages that are upgraded:\n" +#~ msgstr "Pakete, bei denen ein Upgrade durchgeführt wurde:\n" + +#~ msgid "Packages with upgradable origin but kept back:\n" +#~ msgstr "" +#~ "Pakete, bei denen die Quelle Upgrade-fähig war, die aber zurückgehalten " +#~ "wurden:\n" + +#~ msgid "Package installation log:" +#~ msgstr "Paketinstallationsprotokoll:" + +#~ msgid "You need to be root to run this application" +#~ msgstr "Sie müssen »root« sein, um dieses Programm auszuführen." diff -Nru unattended-upgrades-0.55ubuntu3/debian/po/nl.po unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/po/nl.po --- unattended-upgrades-0.55ubuntu3/debian/po/nl.po 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/po/nl.po 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,38 @@ +# Dutch translation of unattended-upgrades debconf templates. +# Copyright (C) 2011 THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the unattended-upgrades package. +# Jeroen Schot , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: unattended-upgrades_0.70\n" +"Report-Msgid-Bugs-To: unattended-upgrades@packages.debian.org\n" +"POT-Creation-Date: 2009-07-06 17:32+0100\n" +"PO-Revision-Date: 2011-05-09 11:21+0200\n" +"Last-Translator: Jeroen Schot \n" +"Language-Team: Debian l10n Dutch \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: nl\n" + +#. Type: boolean +#. Description +#: ../templates:2001 +msgid "Automatically download and install stable updates?" +msgstr "Updates van 'stable' automatisch binnenhalen en installeren?" + +#. Type: boolean +#. Description +#: ../templates:2001 +msgid "" +"Applying updates on a frequent basis is an important part of keeping systems " +"secure. By default, updates need to be applied manually using package " +"management tools. Alternatively, you can choose to have this system " +"automatically download and install security updates." +msgstr "" +"Regelmatig updates installeren is een belangrijk onderdeel van de " +"beveiliging van systemen. Standaard moeten updates handmatig worden " +"toegepast met een van de hulpprogramma's voor pakketbeheer. U kunt er ook " +"voor kiezen om op dit systeem beveilingingsupdates automatisch binnen te " +"halen en te installeren." diff -Nru unattended-upgrades-0.55ubuntu3/debian/po/pt_BR.po unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/po/pt_BR.po --- unattended-upgrades-0.55ubuntu3/debian/po/pt_BR.po 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/po/pt_BR.po 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,40 @@ +# Debconf translations for unattended-upgrades. +# Copyright (C) 2009 THE unattended-upgrades'S COPYRIGHT HOLDER +# This file is distributed under the same license as the unattended-upgrades package. +# Adriano Rafael Gomes , 2009-2010. +# +msgid "" +msgstr "" +"Project-Id-Version: unattended-upgrades\n" +"Report-Msgid-Bugs-To: unattended-upgrades@packages.debian.org\n" +"POT-Creation-Date: 2009-07-06 17:32+0100\n" +"PO-Revision-Date: 2010-12-17 21:58-0200\n" +"Last-Translator: Adriano Rafael Gomes \n" +"Language-Team: Brazilian Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"pt_BR utf-8\n" + +#. Type: boolean +#. Description +#: ../templates:2001 +msgid "Automatically download and install stable updates?" +msgstr "Baixar e instalar atualizações estáveis automaticamente?" + +#. Type: boolean +#. Description +#: ../templates:2001 +msgid "" +"Applying updates on a frequent basis is an important part of keeping systems " +"secure. By default, updates need to be applied manually using package " +"management tools. Alternatively, you can choose to have this system " +"automatically download and install security updates." +msgstr "" +"Aplicar atualizações com frequência é uma parte importante de manter os " +"sistemas seguros. Por padrão, as atualizações precisam ser aplicadas " +"manualmente usando ferramentas de gerenciamento de pacotes. " +"Alternativamente, você pode escolher que esse sistema baixe e instale " +"automaticamente as atualizações de segurança." diff -Nru unattended-upgrades-0.55ubuntu3/debian/postinst unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/postinst --- unattended-upgrades-0.55ubuntu3/debian/postinst 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/postinst 2011-11-08 16:31:29.000000000 +0000 @@ -26,13 +26,25 @@ rm -f /etc/pm/sleep.d/10_unatteded-upgrades-hibernate fi - db_get unattended-upgrades/enable_auto_updates || true - if [ "${RET}" = "true" ]; then - NEWFILE="/usr/share/unattended-upgrades/20auto-upgrades" + db_get unattended-upgrades/enable_auto_updates || true CONFIG="/etc/apt/apt.conf.d/20auto-upgrades" - ucf --three-way --debconf-ok "$NEWFILE" "$CONFIG" - ucfr unattended-upgrades "$CONFIG" - fi + if [ "${RET}" = "true" ]; then + NEWFILE="/usr/share/unattended-upgrades/20auto-upgrades" + ucf --three-way --debconf-ok "$NEWFILE" "$CONFIG" + ucfr unattended-upgrades "$CONFIG" + elif [ "${RET}" = "false" ] && [ -e "$CONFIG" ]; then + # disable again + NEWFILE="/usr/share/unattended-upgrades/20auto-upgrades-disabled" + ucf --three-way --debconf-ok "$NEWFILE" "$CONFIG" + ucfr unattended-upgrades "$CONFIG" + fi + + # Recover from incorrect init.d script header in versions < 0.64 + if dpkg --compare-versions "$2" lt "0.64" \ + && [ -f /etc/rc0.d/S[0-9][0-9]unattended-upgrades ] \ + && [ -f /etc/rc6.d/S[0-9][0-9]unattended-upgrades ] ; then + update-rc.d -f unattended-upgrades remove + fi ;; abort-upgrade|abort-remove|abort-deconfigure) diff -Nru unattended-upgrades-0.55ubuntu3/debian/prerm unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/prerm --- unattended-upgrades-0.55ubuntu3/debian/prerm 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/prerm 2011-11-08 16:31:29.000000000 +0000 @@ -0,0 +1,45 @@ +#!/bin/sh +# prerm script for unattended-upgrades +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `upgrade' +# * `failed-upgrade' +# * `remove' `in-favour' +# * `deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + remove|upgrade|deconfigure) + ;; + + failed-upgrade) + if dpkg --compare-versions "$2" lt 0.73.3; then + cat >&2 <&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff -Nru unattended-upgrades-0.55ubuntu3/debian/rules unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/rules --- unattended-upgrades-0.55ubuntu3/debian/rules 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/rules 2013-07-12 19:52:12.000000000 +0000 @@ -1,52 +1,16 @@ #!/usr/bin/make -f -# -*- makefile -*- -# Sample debian/rules that uses debhelper. -# GNU copyright 1997 to 1999 by Joey Hess. -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 +DIST=$(shell /usr/bin/lsb_release -i -s) +%: + dh $@ -PKG=unattended-upgrades -DIST=$(shell /usr/bin/lsb_release -c -s) -DEBVER=$(shell dpkg-parsechangelog |sed -n -e '/^Version:/s/^Version: //p') -DEB_BUILD_PROG:=debuild --preserve-envvar PATH --preserve-envvar CCACHE_DIR -us -uc $(DEB_BUILD_PROG_OPTS) -PYVER=$(shell pyversions -dv) - - - -ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) - INSTALL_PROGRAM += -s -endif - -configure: configure-stamp -configure-stamp: - dh_testdir - # Add here commands to configure the package. - - touch configure-stamp - - -build: build-stamp - -build-stamp: configure-stamp - dh_testdir - - # Add here commands to compile the package. - #$(MAKE) - ./setup.py build - - touch build-stamp - -clean: - dh_testdir - dh_testroot - rm -f build-stamp configure-stamp - - # Add here commands to clean up after the build process. - #-$(MAKE) clean - ./setup.py clean --all +override_dh_auto_build: + # copy the right template into place + cp data/50unattended-upgrades.$(DIST) data/50unattended-upgrades + dh_auto_build +override_dh_auto_clean: # Sanity-check before upload. set -e; if [ -e /usr/lib/python$(PYVER)/py_compile.py ]; then \ for f in unattended-upgrade unattended-upgrade-shutdown; do \ @@ -56,59 +20,9 @@ rm -f $$f.py; \ done; \ fi + dh_auto_clean - find . -name "*.so" -exec rm {} \; - find . -name "*.o" -exec rm {} \; - find . -name "*.pyc" -exec rm {} \; - - debconf-updatepo - dh_clean - -install: build - dh_testdir - dh_testroot - dh_clean -k - dh_installdirs - - # Add here commands to install the package into debian/$(PKG). - ./setup.py install --prefix=$(CURDIR)/debian/$(PKG)/usr --install-layout=deb - -# Build architecture-independent files here. -binary-indep: build install - dh_testdir - dh_testroot - dh_installchangelogs - dh_installdocs - dh_installexamples -# dh_install - dh_installdebconf - dh_installlogrotate - dh_installmime - dh_installinit --no-start -- start 10 0 6 . - dh_installman - dh_link - dh_strip - dh_compress - dh_fixperms - dh_python - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb - - -arch-build: - # update the default distro - sed -i "s/\"Ubuntu\ [a-z]*-security\"\;/\"Ubuntu $(DIST)-security\"\;/" data/50unattended-upgrades - sed -i "s/\"Ubuntu\ [a-z]*-updates\"\;/\"Ubuntu $(DIST)-updates\"\;/" data/50unattended-upgrades - - # now do the rest - rm -rf debian/arch-build - mkdir -p debian/arch-build/$(PKG)-$(DEBVER) - tar -c --no-recursion -f - `bzr inventory` | (cd debian/arch-build/$(PKG)-$(DEBVER);tar xf -) - (cd debian/arch-build/$(PKG)-$(DEBVER) && $(DEB_BUILD_PROG)) - - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install configure +override_dh_installinit: + # we do not want to run the init script in the postinst/prerm, its + # really only useful on shutdown, see Debian bug #645919 + dh_installinit $@ --no-start -- stop 10 0 6 . diff -Nru unattended-upgrades-0.55ubuntu3/debian/unattended-upgrades.init unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/unattended-upgrades.init --- unattended-upgrades-0.55ubuntu3/debian/unattended-upgrades.init 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/debian/unattended-upgrades.init 2011-11-09 08:25:22.000000000 +0000 @@ -1,11 +1,11 @@ #! /bin/sh # ### BEGIN INIT INFO -# Required-Start: -# Required-Stop: +# Required-Start: $remote_fs +# Required-Stop: $remote_fs # Provides: unattended-upgrade-shutdown-check -# Default-Start: 0 6 -# Default-Stop: +# Default-Start: +# Default-Stop: 0 6 # Short-Description: Check if unattended upgrades are being applied # Description: Check if unattended upgrades are being applied # and wait for them to finish @@ -15,20 +15,29 @@ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin NAME=unattended-upgrades DESC=unattended-upgrades +SHUTDOWN_HELPER=/usr/share/unattended-upgrades/unattended-upgrade-shutdown set -e case "$1" in - start|stop) - echo -n "Checking for running $DESC: " - python /usr/share/unattended-upgrades/unattended-upgrade-shutdown + start) + # nothing, just to keep update-rc.d happy (see debian #630732) + ;; + stop) + echo "Checking for running $DESC: " + if [ -e $SHUTDOWN_HELPER ]; then + python $SHUTDOWN_HELPER + fi ;; restart|force-reload) # nothing ;; + status) + exit 0 + ;; *) N=/etc/init.d/$NAME - echo "Usage: $N {start|stop|restart|force-reload}" >&2 + echo "Usage: $N {start|stop|restart|force-reload|status}" >&2 exit 1 ;; esac diff -Nru unattended-upgrades-0.55ubuntu3/man/unattended-upgrade.8 unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/man/unattended-upgrade.8 --- unattended-upgrades-0.55ubuntu3/man/unattended-upgrade.8 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/man/unattended-upgrade.8 2011-12-12 13:10:14.000000000 +0000 @@ -25,12 +25,12 @@ and unattended, taking care to only install packages from the configured APT source, and checking for dpkg prompts about configuration file changes. All output is logged to -/var/log/unattended-ugprades.log. +/var/log/unattended-upgrades.log. .sp This script is the backend for the APT::Periodic::Unattended-Upgrade option and designed to be run from cron (e.g. via /etc/cron.daily/apt). .SH OPTIONS -unattended-upgrade accepts the following options +unattended-upgrade accepts the following options: .TP \fB-h\fR, \fB\-\-help\fR help output @@ -41,17 +41,17 @@ \fB--dry-run\fR Just simulate installing updates, do not actually do it .SH CONFIGURATION -The configuration is done via the apt configuration mechanism, the -default configuration file can be found at +The configuration is done via the apt configuration mechanism. The +default configuration file can be found at /etc/apt/apt.conf.d/50unattended-upgrades .SH AUTHORS unattended-upgrade is written by Michael Vogt .PP -This manual page was originally written by Michael Vogt +This manual page was originally written by Michael Vogt .SH COPYRIGHT Copyright (C) 2005-2009 Canonical .PP -There is NO warranty. +There is NO warranty. You may redistribute this software under the terms of the GNU General Public License. For more information about these matters, see the files named COPYING. diff -Nru unattended-upgrades-0.55ubuntu3/pm/sleep.d/10_unattended-upgrades-hibernate unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/pm/sleep.d/10_unattended-upgrades-hibernate --- unattended-upgrades-0.55ubuntu3/pm/sleep.d/10_unattended-upgrades-hibernate 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/pm/sleep.d/10_unattended-upgrades-hibernate 2011-11-09 08:25:22.000000000 +0000 @@ -8,23 +8,17 @@ # PATH=/sbin:/usr/sbin:/bin:/usr/bin +SHUTDOWN_HELPER=/usr/share/unattended-upgrades/unattended-upgrade-shutdown if [ ! -x /usr/share/unattended-upgrades/unattended-upgrade-shutdown ]; then exit 0 fi -SELF=unattended-upgrades-hibernate -COMMAND= -IFPLUGD_IFACE= - -# pm-action(8) - -# -# On suspend|hibernate, disconnect any wpa-roam managed interfaces, -# reconnect it on resume. - case "${1}" in hibernate) - python /usr/share/unattended-upgrades/unattended-upgrade-shutdown + if [ -e $SHUTDOWN_HELPER ]; then + python $SHUTDOWN_HELPER + fi ;; resume|thaw) # nothing diff -Nru unattended-upgrades-0.55ubuntu3/po/fr.po unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/po/fr.po --- unattended-upgrades-0.55ubuntu3/po/fr.po 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/po/fr.po 2011-10-07 07:31:17.000000000 +0000 @@ -7,140 +7,169 @@ msgstr "" "Project-Id-Version: 0.35\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-05-06 10:52+0200\n" -"PO-Revision-Date: 2008-11-27 12:00+0200\n" +"POT-Creation-Date: 2009-07-03 12:21+0200\n" +"PO-Revision-Date: 2011-03-30 12:28+0200\n" "Last-Translator: Steve Petruzzello \n" "Language-Team: French \n" +"Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: ../unattended-upgrade:151 +#: ../unattended-upgrade:174 +msgid "" +"No '/usr/bin/mail', can not send mail. You probably want to install the " +"'mailx' package." +msgstr "" +"L'exécutable « /usr/bin/mail » est introuvable, impossible d'envoyer un " +"courrier électronique. Veuillez installer le paquet « mailx »." + +#: ../unattended-upgrade:179 +#, c-format +msgid "unattended-upgrades result for '%s'" +msgstr "unattended-upgrades a retourné : %s" + +#: ../unattended-upgrade:183 +#, c-format +msgid "" +"Unattended upgrade returned: %s\n" +"\n" +msgstr "" +"La mise à niveau automatique a retourné : %s\n" +"\n" + +#: ../unattended-upgrade:184 +msgid "Packages that are upgraded:\n" +msgstr "Paquets mis à niveau :\n" + +#: ../unattended-upgrade:188 +msgid "Packages with upgradable origin but kept back:\n" +msgstr "" +"Paquets susceptibles d'une mise à niveau mais maintenus dans leur état " +"actuel :\n" + +#: ../unattended-upgrade:192 +msgid "Package installation log:" +msgstr "Journal d'installation du paquet :" + +#: ../unattended-upgrade:195 +#| msgid "unattended-upgrades result for '%s'" +msgid "Unattended-upgrades log:\n" +msgstr "Journal de unattended-upgrades :\n" + +#: ../unattended-upgrade:208 msgid "print debug messages" msgstr "Afficher les messages de débogage" -#: ../unattended-upgrade:170 +#: ../unattended-upgrade:211 +msgid "Simulation, download but do not install" +msgstr "Simulation, télécharge mais n'installe pas" + +#: ../unattended-upgrade:230 #, c-format msgid "Initial blacklisted packages: %s" msgstr "Paquets initialement sur la liste noire : %s" -#: ../unattended-upgrade:171 +#: ../unattended-upgrade:231 msgid "Starting unattended upgrades script" -msgstr "Démarrage du script de mise à jour automatique" +msgstr "Démarrage du script de mise à niveau automatique" -#: ../unattended-upgrade:174 +#: ../unattended-upgrade:234 #, c-format msgid "Allowed origins are: %s" msgstr "Les origines permises sont : %s" -#: ../unattended-upgrade:179 ../unattended-upgrade:180 +#: ../unattended-upgrade:241 +msgid "Lock could not be acquired (another package manager running?)" +msgstr "" +"Verrouillage impossible (y a-t-il un autre gestionnaire de paquets en cours " +"d'exécution ?)" + +#: ../unattended-upgrade:243 +#| msgid "Cache has broken packages, exiting" +msgid "Cache lock can not be acquired, exiting" +msgstr "Le verrouillage du cache est impossible, abandon" + +#: ../unattended-upgrade:249 ../unattended-upgrade:250 msgid "Cache has broken packages, exiting" msgstr "Le cache contient des paquets cassés, abandon" -#: ../unattended-upgrade:204 +#: ../unattended-upgrade:274 #, c-format msgid "package '%s' upgradable but fails to be marked for upgrade (%s)" msgstr "" +"Le paquet « %s » peut être mis à niveau mais échoue à être marqué comme tel " +"(%s)" -#: ../unattended-upgrade:224 +#: ../unattended-upgrade:294 #, c-format msgid "GetArchives() failed: '%s'" -msgstr "Echec de GetArchives() : '%s'" +msgstr "Échec de GetArchives() : %s" -#: ../unattended-upgrade:233 ../unattended-upgrade:234 +#: ../unattended-upgrade:303 ../unattended-upgrade:304 #, c-format msgid "An error ocured: '%s'" -msgstr "Une erreur s'est produite : '%s'" +msgstr "Une erreur s'est produite : %s" -#: ../unattended-upgrade:236 ../unattended-upgrade:237 +#: ../unattended-upgrade:306 ../unattended-upgrade:307 #, c-format msgid "The URI '%s' failed to download, aborting" -msgstr "Echec du téléchargement à l'URI '%s', abandon" +msgstr "Échec du téléchargement à l'URI « %s », abandon" + +#: ../unattended-upgrade:310 +#, c-format +msgid "Download finished, but file '%s' not there?!?" +msgstr "Téléchargement terminé mais le fichier « %s » est absent !" -#: ../unattended-upgrade:245 +#: ../unattended-upgrade:319 #, c-format msgid "Package '%s' has conffile prompt and needs to be upgraded manually" msgstr "" -"Le paquet '%s' provoque un conflit de fichiers de configuration et nécessite " -"une mise à jour manuelle" +"Le paquet « %s » provoque un conflit de fichiers de configuration et " +"nécessite une mise à niveau manuelle" -#: ../unattended-upgrade:264 +#: ../unattended-upgrade:341 #, c-format msgid "package '%s' not upgraded" -msgstr "Le paquet '%s' n'a pas été mis à jour" +msgstr "Le paquet « %s » n'a pas été mis à niveau" -#: ../unattended-upgrade:275 +#: ../unattended-upgrade:352 msgid "No packages found that can be upgraded unattended" -msgstr "Aucun paquet à mettre à jour automatiquement" +msgstr "Aucun paquet à mettre à niveau automatiquement" -#: ../unattended-upgrade:280 +#: ../unattended-upgrade:362 #, c-format msgid "Packages that are upgraded: %s" -msgstr "Paquets mis à jour : %s" +msgstr "Paquets mis à niveau : %s" -#: ../unattended-upgrade:293 +#: ../unattended-upgrade:375 #, c-format msgid "Writing dpkg log to '%s'" -msgstr "Écriture du journal de dpkg dans '%s'" +msgstr "Écriture du journal de dpkg dans « %s »" -#: ../unattended-upgrade:305 +#: ../unattended-upgrade:386 msgid "pm.GetArchives() failed" -msgstr "Echec de pm.GetArchives()" +msgstr "Échec de pm.GetArchives()" -#: ../unattended-upgrade:313 +#: ../unattended-upgrade:407 msgid "Installing the upgrades failed!" -msgstr "Échec de l'installation des mises à jour" +msgstr "Échec de l'installation des mises à niveau" -#: ../unattended-upgrade:314 +#: ../unattended-upgrade:408 #, c-format msgid "error message: '%s'" -msgstr "Message d'erreur : '%s'" +msgstr "Message d'erreur : %s" -#: ../unattended-upgrade:318 +#: ../unattended-upgrade:409 #, c-format msgid "dpkg returned a error! See '%s' for details" msgstr "Dpkg a retourné une erreur. Voir « %s » pour les détails" -#: ../unattended-upgrade:320 +#: ../unattended-upgrade:411 msgid "All upgrades installed" -msgstr "Toutes les mises à jour ont été installées" - -#: ../unattended-upgrade:326 -msgid "" -"No '/usr/bin/mail', can not send mail. You probably want to install the " -"'mailx' package." -msgstr "" - -#: ../unattended-upgrade:331 -#, fuzzy, c-format -msgid "unattended-upgrades result for '%s'" -msgstr "" -"La mise à jour automatique a retourné : %s\n" -"\n" - -#: ../unattended-upgrade:335 -#, c-format -msgid "" -"Unattended upgrade returned: %s\n" -"\n" -msgstr "" -"La mise à jour automatique a retourné : %s\n" -"\n" - -#: ../unattended-upgrade:336 -#, fuzzy -msgid "Packages that are upgraded:\n" -msgstr "Paquets mis à jour : %s" - -#: ../unattended-upgrade:340 -msgid "Packages with upgradable origin but kept back:\n" -msgstr "" - -#: ../unattended-upgrade:344 -msgid "Package installation log:" -msgstr "" +msgstr "Toutes les mises à niveau ont été installées" -#: ../unattended-upgrade:359 +#: ../unattended-upgrade:424 msgid "You need to be root to run this application" msgstr "" "Vous devez posséder les privilèges du superutilisateur pour exécuter cette " diff -Nru unattended-upgrades-0.55ubuntu3/po/pt_BR.po unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/po/pt_BR.po --- unattended-upgrades-0.55ubuntu3/po/pt_BR.po 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/po/pt_BR.po 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,161 @@ +msgid "" +msgstr "" +"Project-Id-Version: unattended-upgrades-0.61\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-07-03 12:21+0200\n" +"PO-Revision-Date: \n" +"Last-Translator: Sérgio Cipolla \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Portuguese\n" +"X-Poedit-Country: BRAZIL\n" + +#: ../unattended-upgrade:174 +msgid "No '/usr/bin/mail', can not send mail. You probably want to install the 'mailx' package." +msgstr "Nenhum '/usr/bin/mail', incapaz de enviar email. Você provavelmente gostaria de instalar o pacote 'mailx'." + +#: ../unattended-upgrade:179 +#, c-format +msgid "unattended-upgrades result for '%s'" +msgstr "Resultado da atualização desacompanhada para '%s'" + +#: ../unattended-upgrade:183 +#, c-format +msgid "" +"Unattended upgrade returned: %s\n" +"\n" +msgstr "" +"A atualização desacompanhada retornou: %s\n" +"\n" + +#: ../unattended-upgrade:184 +msgid "Packages that are upgraded:\n" +msgstr "Pacotes atualizados:\n" + +#: ../unattended-upgrade:188 +msgid "Packages with upgradable origin but kept back:\n" +msgstr "Pacotes atualizáveis na origem mas mantidos na versão atual:\n" + +#: ../unattended-upgrade:192 +msgid "Package installation log:" +msgstr "Relatório de instalação de pacotes:" + +#: ../unattended-upgrade:195 +msgid "Unattended-upgrades log:\n" +msgstr "Relatório da atualização desacompanhada:\n" + +#: ../unattended-upgrade:208 +msgid "print debug messages" +msgstr "imprimir mensagens de depuração" + +#: ../unattended-upgrade:211 +msgid "Simulation, download but do not install" +msgstr "Simulação, baixar mas não instalar" + +#: ../unattended-upgrade:230 +#, c-format +msgid "Initial blacklisted packages: %s" +msgstr "Pacotes inicialmente na lista negra: %s" + +#: ../unattended-upgrade:231 +msgid "Starting unattended upgrades script" +msgstr "Iniciando o script da atualização desacompanhada" + +#: ../unattended-upgrade:234 +#, c-format +msgid "Allowed origins are: %s" +msgstr "São origens permitidas: %s" + +#: ../unattended-upgrade:241 +msgid "Lock could not be acquired (another package manager running?)" +msgstr "O lock não pôde ser obtido (outro gerenciador de pacotes em funcionamento?)" + +#: ../unattended-upgrade:243 +msgid "Cache lock can not be acquired, exiting" +msgstr "O lock do cache não pode ser obtido, saindo" + +#: ../unattended-upgrade:249 +#: ../unattended-upgrade:250 +msgid "Cache has broken packages, exiting" +msgstr "O cache tem pacotes quebrados, saindo" + +#: ../unattended-upgrade:274 +#, c-format +msgid "package '%s' upgradable but fails to be marked for upgrade (%s)" +msgstr "o pacote '%s' é atualizável mas falha ao ser marcado para atualização (%s)" + +#: ../unattended-upgrade:294 +#, c-format +msgid "GetArchives() failed: '%s'" +msgstr "GetArchives() falhou: '%s'" + +#: ../unattended-upgrade:303 +#: ../unattended-upgrade:304 +#, c-format +msgid "An error ocured: '%s'" +msgstr "Ocorreu um erro; '%s'" + +#: ../unattended-upgrade:306 +#: ../unattended-upgrade:307 +#, c-format +msgid "The URI '%s' failed to download, aborting" +msgstr "O URI '%s' falhou no download, abortando" + +#: ../unattended-upgrade:310 +#, c-format +msgid "Download finished, but file '%s' not there?!?" +msgstr "Download terminado, mas o arquivo '%s' não está lá?!?" + +#: ../unattended-upgrade:319 +#, c-format +msgid "Package '%s' has conffile prompt and needs to be upgraded manually" +msgstr "O pacote '%s' possui um diálogo conffile e necessita ser atualizado manualmente" + +#: ../unattended-upgrade:341 +#, c-format +msgid "package '%s' not upgraded" +msgstr "o pacote '%s' não foi atualizado" + +#: ../unattended-upgrade:352 +msgid "No packages found that can be upgraded unattended" +msgstr "Não foi encontrado nenhum pacote que possa ser atualizado desacompanhadamente" + +#: ../unattended-upgrade:362 +#, c-format +msgid "Packages that are upgraded: %s" +msgstr "Pacotes atualizados: %s" + +#: ../unattended-upgrade:375 +#, c-format +msgid "Writing dpkg log to '%s'" +msgstr "Escrevendo o relatório do dpkg em '%s'" + +#: ../unattended-upgrade:386 +msgid "pm.GetArchives() failed" +msgstr "pm.GetArchives() falhou" + +#: ../unattended-upgrade:407 +msgid "Installing the upgrades failed!" +msgstr "Falha ao instalar as atualizações!" + +#: ../unattended-upgrade:408 +#, c-format +msgid "error message: '%s'" +msgstr "mensagem de erro: '%s'" + +#: ../unattended-upgrade:409 +#, c-format +msgid "dpkg returned a error! See '%s' for details" +msgstr "O dpkg retornou um erro! Veja '%s' para mais detalhes" + +#: ../unattended-upgrade:411 +msgid "All upgrades installed" +msgstr "Todas as atualizações instaladas" + +#: ../unattended-upgrade:424 +msgid "You need to be root to run this application" +msgstr "Você precisa ser root para executar este aplicativo" + diff -Nru unattended-upgrades-0.55ubuntu3/po/ru.po unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/po/ru.po --- unattended-upgrades-0.55ubuntu3/po/ru.po 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/po/ru.po 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,173 @@ +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# +# Yuri Kozlov , 2010. +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-07-03 12:21+0200\n" +"PO-Revision-Date: 2010-08-11 21:59+0400\n" +"Last-Translator: Yuri Kozlov \n" +"Language-Team: Russian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.0\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#: ../unattended-upgrade:174 +msgid "" +"No '/usr/bin/mail', can not send mail. You probably want to install the " +"'mailx' package." +msgstr "" +"Нет программы /usr/bin/mail, невозможно послать почту. Вероятно, лучше " +"установить пакет mailx." + +#: ../unattended-upgrade:179 +#, c-format +msgid "unattended-upgrades result for '%s'" +msgstr "Результат unattended-upgrades для %s" + +#: ../unattended-upgrade:183 +#, c-format +msgid "" +"Unattended upgrade returned: %s\n" +"\n" +msgstr "" +"Результат необслуживаемой установки: %s\n" +"\n" + +#: ../unattended-upgrade:184 +msgid "Packages that are upgraded:\n" +msgstr "Обновлённые пакеты:\n" + +#: ../unattended-upgrade:188 +msgid "Packages with upgradable origin but kept back:\n" +msgstr "" +"Пакеты, обновлённые в источнике, но оставленные теми же в системе:\n" + +#: ../unattended-upgrade:192 +msgid "Package installation log:" +msgstr "Журнал установки пакетов:" + +#: ../unattended-upgrade:195 +msgid "Unattended-upgrades log:\n" +msgstr "Журнал unattended-upgrades:\n" + +#: ../unattended-upgrade:208 +msgid "print debug messages" +msgstr "выводить отладочные сообщения" + +#: ../unattended-upgrade:211 +msgid "Simulation, download but do not install" +msgstr "Имитация, скачивать но не устанавливать" + +#: ../unattended-upgrade:230 +#, c-format +msgid "Initial blacklisted packages: %s" +msgstr "Пакеты в чёрном списке изначально: %s" + +#: ../unattended-upgrade:231 +msgid "Starting unattended upgrades script" +msgstr "Запускаются сценарии необслуживаемой установки" + +#: ../unattended-upgrade:234 +#, c-format +msgid "Allowed origins are: %s" +msgstr "Разрешённые источники: %s" + +#: ../unattended-upgrade:241 +msgid "Lock could not be acquired (another package manager running?)" +msgstr "" +"Не удалось выполнить блокировку (запущен ещё один менеджер пакетов?)" + +#: ../unattended-upgrade:243 +msgid "Cache lock can not be acquired, exiting" +msgstr "Не удалось выполнить блокировку кэша, завершение работы" + +#: ../unattended-upgrade:249 ../unattended-upgrade:250 +msgid "Cache has broken packages, exiting" +msgstr "В кэше сломанные пакеты, завершение работы" + +#: ../unattended-upgrade:274 +#, c-format +msgid "package '%s' upgradable but fails to be marked for upgrade (%s)" +msgstr "" +"пакет %s можно обновить, но его не удалось пометить как обновляемый (%s)" + +#: ../unattended-upgrade:294 +#, c-format +msgid "GetArchives() failed: '%s'" +msgstr "GetArchives() завершилась с ошибкой: '%s'" + +#: ../unattended-upgrade:303 ../unattended-upgrade:304 +#, c-format +msgid "An error ocured: '%s'" +msgstr "Произошла ошибка: %s" + +#: ../unattended-upgrade:306 ../unattended-upgrade:307 +#, c-format +msgid "The URI '%s' failed to download, aborting" +msgstr "Невозможно скачать URI '%s', останов" + +#: ../unattended-upgrade:310 +#, c-format +msgid "Download finished, but file '%s' not there?!?" +msgstr "Скачивание завершено, но файла %s нет?!?" + +#: ../unattended-upgrade:319 +#, c-format +msgid "Package '%s' has conffile prompt and needs to be upgraded manually" +msgstr "" +"В пакете %s есть conffile с вводом от пользователя и его нужно " +"обновлять вручную" + +#: ../unattended-upgrade:341 +#, c-format +msgid "package '%s' not upgraded" +msgstr "пакет %s не обновлён" + +#: ../unattended-upgrade:352 +msgid "No packages found that can be upgraded unattended" +msgstr "" +"Пакеты, для которых можно выполнить необслуживаемое обновление, не " +"найдены" + +#: ../unattended-upgrade:362 +#, c-format +msgid "Packages that are upgraded: %s" +msgstr "Обновлённые пакеты: %s" + +#: ../unattended-upgrade:375 +#, c-format +msgid "Writing dpkg log to '%s'" +msgstr "Журнал dpkg записывается в %s" + +#: ../unattended-upgrade:386 +msgid "pm.GetArchives() failed" +msgstr "pm.GetArchives() завершилась с ошибкой" + +#: ../unattended-upgrade:407 +msgid "Installing the upgrades failed!" +msgstr "Установка обновлений завершилась с ошибкой!" + +#: ../unattended-upgrade:408 +#, c-format +msgid "error message: '%s'" +msgstr "сообщение об ошибке: %s" + +#: ../unattended-upgrade:409 +#, c-format +msgid "dpkg returned a error! See '%s' for details" +msgstr "dpkg завершилась с ошибкой! Подробности смотрите в %s" + +#: ../unattended-upgrade:411 +msgid "All upgrades installed" +msgstr "Все обновления установлены" + +#: ../unattended-upgrade:424 +msgid "You need to be root to run this application" +msgstr "Вы должны быть root для запуска этого приложения" + diff -Nru unattended-upgrades-0.55ubuntu3/po/unattended-upgrades.pot unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/po/unattended-upgrades.pot --- unattended-upgrades-0.55ubuntu3/po/unattended-upgrades.pot 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/po/unattended-upgrades.pot 2011-10-07 07:32:01.000000000 +0000 @@ -8,153 +8,200 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-07-03 12:21+0200\n" +"POT-Creation-Date: 2011-07-19 15:24+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: ../unattended-upgrade:174 +#: ../unattended-upgrade:72 +#, c-format +msgid "Progress: %s %% (%s)" +msgstr "" + +#: ../unattended-upgrade:190 ../unattended-upgrade:254 +msgid "All upgrades installed" +msgstr "" + +#: ../unattended-upgrade:192 ../unattended-upgrade:246 +msgid "Installing the upgrades failed!" +msgstr "" + +#: ../unattended-upgrade:193 ../unattended-upgrade:247 +#, c-format +msgid "error message: '%s'" +msgstr "" + +#: ../unattended-upgrade:194 ../unattended-upgrade:248 +#, c-format +msgid "dpkg returned a error! See '%s' for details" +msgstr "" + +#: ../unattended-upgrade:231 +#, c-format +msgid "Progress: %s %%: (%s)" +msgstr "" + +#: ../unattended-upgrade:412 msgid "" "No '/usr/bin/mail', can not send mail. You probably want to install the " "'mailx' package." msgstr "" -#: ../unattended-upgrade:179 +#: ../unattended-upgrade:423 +#, c-format +msgid "[reboot required] unattended-upgrades result for '%s'" +msgstr "" + +#: ../unattended-upgrade:425 #, c-format msgid "unattended-upgrades result for '%s'" msgstr "" -#: ../unattended-upgrade:183 +#: ../unattended-upgrade:428 #, c-format msgid "" "Unattended upgrade returned: %s\n" "\n" msgstr "" -#: ../unattended-upgrade:184 +#: ../unattended-upgrade:430 +msgid "" +"Warning: A reboot is required to complete this upgrade.\n" +"\n" +msgstr "" + +#: ../unattended-upgrade:431 msgid "Packages that are upgraded:\n" msgstr "" -#: ../unattended-upgrade:188 +#: ../unattended-upgrade:435 msgid "Packages with upgradable origin but kept back:\n" msgstr "" -#: ../unattended-upgrade:192 +#: ../unattended-upgrade:439 msgid "Package installation log:" msgstr "" -#: ../unattended-upgrade:195 +#: ../unattended-upgrade:442 msgid "Unattended-upgrades log:\n" msgstr "" -#: ../unattended-upgrade:208 -msgid "print debug messages" +#: ../unattended-upgrade:513 +#, c-format +msgid "Initial blacklisted packages: %s" msgstr "" -#: ../unattended-upgrade:211 -msgid "Simulation, download but do not install" +#: ../unattended-upgrade:514 +msgid "Starting unattended upgrades script" msgstr "" -#: ../unattended-upgrade:230 +#: ../unattended-upgrade:517 #, c-format -msgid "Initial blacklisted packages: %s" +msgid "Allowed origins are: %s" msgstr "" -#: ../unattended-upgrade:231 -msgid "Starting unattended upgrades script" +#: ../unattended-upgrade:528 ../unattended-upgrade:529 +msgid "Unclean dpkg state detected, trying to correct" msgstr "" -#: ../unattended-upgrade:234 +#: ../unattended-upgrade:538 #, c-format -msgid "Allowed origins are: %s" +msgid "" +"dpkg --configure -a output:\n" +"%s" msgstr "" -#: ../unattended-upgrade:241 +#: ../unattended-upgrade:546 msgid "Lock could not be acquired (another package manager running?)" msgstr "" -#: ../unattended-upgrade:243 +#: ../unattended-upgrade:548 msgid "Cache lock can not be acquired, exiting" msgstr "" -#: ../unattended-upgrade:249 ../unattended-upgrade:250 +#: ../unattended-upgrade:554 ../unattended-upgrade:555 msgid "Cache has broken packages, exiting" msgstr "" -#: ../unattended-upgrade:274 +#: ../unattended-upgrade:581 #, c-format msgid "package '%s' upgradable but fails to be marked for upgrade (%s)" msgstr "" -#: ../unattended-upgrade:294 +#: ../unattended-upgrade:601 #, c-format msgid "GetArchives() failed: '%s'" msgstr "" -#: ../unattended-upgrade:303 ../unattended-upgrade:304 +#: ../unattended-upgrade:610 ../unattended-upgrade:611 #, c-format msgid "An error ocured: '%s'" msgstr "" -#: ../unattended-upgrade:306 ../unattended-upgrade:307 +#: ../unattended-upgrade:613 ../unattended-upgrade:614 #, c-format msgid "The URI '%s' failed to download, aborting" msgstr "" -#: ../unattended-upgrade:310 +#: ../unattended-upgrade:617 #, c-format msgid "Download finished, but file '%s' not there?!?" msgstr "" -#: ../unattended-upgrade:319 +#: ../unattended-upgrade:626 #, c-format msgid "Package '%s' has conffile prompt and needs to be upgraded manually" msgstr "" -#: ../unattended-upgrade:341 +#: ../unattended-upgrade:648 #, c-format msgid "package '%s' not upgraded" msgstr "" -#: ../unattended-upgrade:352 +#: ../unattended-upgrade:662 +#, c-format +msgid "Packages that are auto removed: '%s'" +msgstr "" + +#: ../unattended-upgrade:669 msgid "No packages found that can be upgraded unattended" msgstr "" -#: ../unattended-upgrade:362 +#: ../unattended-upgrade:679 #, c-format msgid "Packages that are upgraded: %s" msgstr "" -#: ../unattended-upgrade:375 +#: ../unattended-upgrade:693 #, c-format msgid "Writing dpkg log to '%s'" msgstr "" -#: ../unattended-upgrade:386 -msgid "pm.GetArchives() failed" +#: ../unattended-upgrade:744 +msgid "print debug messages" msgstr "" -#: ../unattended-upgrade:407 -msgid "Installing the upgrades failed!" +#: ../unattended-upgrade:747 +msgid "Simulation, download but do not install" msgstr "" -#: ../unattended-upgrade:408 -#, c-format -msgid "error message: '%s'" +#: ../unattended-upgrade:750 +msgid "Upgrade in minimal steps (and allow interrupting with SIGINT" msgstr "" -#: ../unattended-upgrade:409 -#, c-format -msgid "dpkg returned a error! See '%s' for details" +#: ../unattended-upgrade:754 +msgid "You need to be root to run this application" msgstr "" -#: ../unattended-upgrade:411 -msgid "All upgrades installed" +#: ../unattended-upgrade-shutdown:95 +msgid "Unattended-upgrade in progress during shutdown, sleeping for 5s" msgstr "" -#: ../unattended-upgrade:424 -msgid "You need to be root to run this application" +#: ../unattended-upgrade-shutdown:106 +#, c-format +msgid "Giving up on lockfile after %s delay" msgstr "" diff -Nru unattended-upgrades-0.55ubuntu3/setup.py unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/setup.py --- unattended-upgrades-0.55ubuntu3/setup.py 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/setup.py 2011-11-08 16:31:29.000000000 +0000 @@ -15,6 +15,7 @@ ["data/logrotate.d/unattended-upgrades"]), ('../usr/share/unattended-upgrades/', ["data/20auto-upgrades", + "data/20auto-upgrades-disabled", "unattended-upgrade-shutdown"]), ('../usr/share/man/man8/', ["man/unattended-upgrade.8"]), diff -Nru unattended-upgrades-0.55ubuntu3/test/Makefile unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/Makefile --- unattended-upgrades-0.55ubuntu3/test/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/Makefile 2011-10-19 13:13:20.000000000 +0000 @@ -0,0 +1,19 @@ +#!/usr/bin/make + +all: check + +check: + set -e; \ + find . -name 'test_*.py' | \ + while read file; do \ + echo "Running $$file"; \ + if [ -x $$file ]; then \ + python $$file ; \ + fi \ + done + +clean: + rm -rf ./aptroot/var/cache/ + rm -rf ./aptroot/var/lib/apt + rm -rf ./aptroot/var/run + diff -Nru unattended-upgrades-0.55ubuntu3/test/aptroot/etc/apt/apt.conf.d/50unattended-upgrades unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/aptroot/etc/apt/apt.conf.d/50unattended-upgrades --- unattended-upgrades-0.55ubuntu3/test/aptroot/etc/apt/apt.conf.d/50unattended-upgrades 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/aptroot/etc/apt/apt.conf.d/50unattended-upgrades 2011-10-07 07:32:01.000000000 +0000 @@ -0,0 +1,36 @@ +// Automatically upgrade packages from these (origin, archive) pairs +Unattended-Upgrade::Allowed-Origins { + "Ubuntu lucid-security"; +}; + +// List of packages to not update +Unattended-Upgrade::Package-Blacklist { +// "vim"; +// "libc6"; +// "libc6-dev"; +// "libc6-i686"; + "ant-doc"; +}; + +// Send email to this address for problems or packages upgrades +// If empty or unset then no email is sent, make sure that you +// have a working mail setup on your system. The package 'mailx' +// must be installed or anything that provides /usr/bin/mail. +//Unattended-Upgrade::Mail "root@localhost"; + +// Set this value to "true" to get emails only on errors. Default +// is to always send a mail if Unattended-Upgrade::Mail is set +//Unattended-Upgrade::MailOnlyOnError "true"; + +// Do automatic removal of new unused dependencies after the upgrade +// (equivalent to apt-get autoremove) +//Unattended-Upgrade::Remove-Unused-Dependencies "false"; + +// Automatically reboot *WITHOUT CONFIRMATION* if a +// the file /var/run/reboot-required is found after the upgrade +//Unattended-Upgrade::Automatic-Reboot "false"; + + +// Use apt bandwidth limit feature, this example limits the download +// speed to 70kb/sec +//Acquire::http::Dl-Limit "70"; diff -Nru unattended-upgrades-0.55ubuntu3/test/aptroot/etc/apt/sources.list unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/aptroot/etc/apt/sources.list --- unattended-upgrades-0.55ubuntu3/test/aptroot/etc/apt/sources.list 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/aptroot/etc/apt/sources.list 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,4 @@ +# updates +deb http://archive.ubuntu.com/ubuntu/ lucid-updates main restricted +# security +deb http://security.ubuntu.com/ubuntu lucid-security main restricted Binary files /tmp/vBk4ErTvGJ/unattended-upgrades-0.55ubuntu3/test/aptroot/etc/apt/trusted.gpg and /tmp/jYeRZNsOgz/unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/aptroot/etc/apt/trusted.gpg differ diff -Nru unattended-upgrades-0.55ubuntu3/test/aptroot/var/lib/dpkg/status unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/aptroot/var/lib/dpkg/status --- unattended-upgrades-0.55ubuntu3/test/aptroot/var/lib/dpkg/status 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/aptroot/var/lib/dpkg/status 2011-12-12 13:10:14.000000000 +0000 @@ -0,0 +1,52 @@ +Package: awstats +Status: install ok installed +Priority: extra +Section: admin +Installed-Size: 1260 +Maintainer: Ubuntu Core Developers +Architecture: all +Version: 6.9~dfsg-1ubuntu3 +Description: dummy + +Package: perl +Status: install ok installed +Priority: standard +Section: perl +Installed-Size: 18556 +Maintainer: Ubuntu Developers +Architecture: amd64 +Version: 5.10.1-17ubuntu1 +Description: Larry Wall's Practical Extraction and Report Language + An interpreted scripting language, known among some as "Unix's Swiss + Army Chainsaw". + . + Perl is optimised for scanning arbitrary text files and system + administration. It has built-in extended regular expression matching + and replacement, a data-flow mechanism to improve security with + setuid scripts and is extensible via modules that can interface to C + libraries. + +Package: ant-doc +Status: install ok installed +Priority: optional +Section: doc +Installed-Size: 35776 +Maintainer: Ubuntu Core Developers +Architecture: all +Version: 1.0 +Description: Java based build tool like make - API documentation and manual + A system independent (i.e. not shell based) build tool that uses XML files + as "Makefiles". This package contains the manual of ant as well as the + Javadoc API documentation. + +Package: apt-doc +Status: install ok installed +Priority: optional +Section: doc +Installed-Size: 388 +Maintainer: Ubuntu Developers +Architecture: all +Version: 0.7.25.3ubuntu9 +Description-en_GB: Documentation for APT + This package contains the user guide and offline guide, for APT, an + Advanced Package Tool. diff -Nru unattended-upgrades-0.55ubuntu3/test/aptroot/var/log/apt/history.log unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/aptroot/var/log/apt/history.log --- unattended-upgrades-0.55ubuntu3/test/aptroot/var/log/apt/history.log 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/aptroot/var/log/apt/history.log 2012-03-09 08:45:32.000000000 +0000 @@ -0,0 +1,4 @@ + +Start-Date: 2012-03-09 09:45:32 +Upgrade: awstats:amd64 (6.9~dfsg-1ubuntu3, 6.9~dfsg-1ubuntu3.10.04.1), apt-doc:amd64 (0.7.25.3ubuntu9, 0.7.25.3ubuntu9.9) +End-Date: 2012-03-09 09:45:32 diff -Nru unattended-upgrades-0.55ubuntu3/test/aptroot/var/log/apt/term.log unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/aptroot/var/log/apt/term.log --- unattended-upgrades-0.55ubuntu3/test/aptroot/var/log/apt/term.log 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/aptroot/var/log/apt/term.log 2012-03-09 08:45:32.000000000 +0000 @@ -0,0 +1,3 @@ + +Log started: 2012-03-09 09:45:32 +Log ended: 2012-03-09 09:45:32 diff -Nru unattended-upgrades-0.55ubuntu3/test/aptroot/var/log/unattended-upgrades.log unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/aptroot/var/log/unattended-upgrades.log --- unattended-upgrades-0.55ubuntu3/test/aptroot/var/log/unattended-upgrades.log 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/aptroot/var/log/unattended-upgrades.log 2012-03-09 08:45:32.000000000 +0000 @@ -0,0 +1,27 @@ +2012-03-09 09:45:29,793 INFO Initial blacklisted packages: ant-doc +2012-03-09 09:45:29,793 INFO Starting unattended upgrades script +2012-03-09 09:45:29,794 INFO Allowed origins are: ['o=Ubuntu,a=lucid-security'] +2012-03-09 09:45:30,561 DEBUG adjusting candidate version: '' +2012-03-09 09:45:30,634 DEBUG Checking: ant-doc (["", ""]) +2012-03-09 09:45:30,636 DEBUG skipping blacklisted package 'ant-doc' +2012-03-09 09:45:30,636 DEBUG sanity check failed +2012-03-09 09:45:30,649 DEBUG adjusting candidate version: '' +2012-03-09 09:45:30,683 DEBUG Checking: apt-doc ([""]) +2012-03-09 09:45:30,726 DEBUG Checking: awstats (["", ""]) +2012-03-09 09:45:30,801 DEBUG pkgs that look like they should be upgraded: apt-doc +awstats +2012-03-09 09:45:32,493 DEBUG +2012-03-09 09:45:32,498 DEBUG check_conffile_prompt('/home/egon/devel/unattended-upgrades/build-area/unattended-upgrades-0.76/test/aptroot/var/cache/apt/archives/apt-doc_0.7.25.3ubuntu9.9_all.deb') +2012-03-09 09:45:32,502 DEBUG found pkg: apt-doc +2012-03-09 09:45:32,503 DEBUG +2012-03-09 09:45:32,505 DEBUG check_conffile_prompt('/home/egon/devel/unattended-upgrades/build-area/unattended-upgrades-0.76/test/aptroot/var/cache/apt/archives/awstats_6.9~dfsg-1ubuntu3.10.04.1_all.deb') +2012-03-09 09:45:32,507 DEBUG found pkg: awstats +2012-03-09 09:45:32,508 DEBUG blacklist: ['ant-doc'] +2012-03-09 09:45:32,526 DEBUG adjusting candidate version: '' +2012-03-09 09:45:32,559 DEBUG Checking (blacklist): apt-doc +2012-03-09 09:45:32,622 DEBUG Checking (blacklist): awstats +2012-03-09 09:45:32,662 DEBUG InstCount=2 DelCount=0 BrokenCout=0 +2012-03-09 09:45:32,663 INFO Option --dry-run given, *not* performing real actions +2012-03-09 09:45:32,664 INFO Packages that are upgraded: apt-doc awstats +2012-03-09 09:45:32,665 INFO Writing dpkg log to '/home/egon/devel/unattended-upgrades/build-area/unattended-upgrades-0.76/test/aptroot/var/log/unattended-upgrades-dpkg_2012-03-09_09:45:32.664630.log' +2012-03-09 09:45:32,969 INFO All upgrades installed diff -Nru unattended-upgrades-0.55ubuntu3/test/create_debug_lock.py unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/create_debug_lock.py --- unattended-upgrades-0.55ubuntu3/test/create_debug_lock.py 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/create_debug_lock.py 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,14 @@ +#!/usr/bin/python +# +# create a lock file so that unattended-upgrades-shutdown pauses +# on shutdown -- useful for testing + +import apt_pkg +import os +import time + +pid = os.fork() +if pid == 0: + os.setsid() + lock = apt_pkg.get_lock("/var/run/unattended-upgrades.lock") + time.sleep(500) diff -Nru unattended-upgrades-0.55ubuntu3/test/data/50unattended-upgrades.Test unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/data/50unattended-upgrades.Test --- unattended-upgrades-0.55ubuntu3/test/data/50unattended-upgrades.Test 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/data/50unattended-upgrades.Test 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,6 @@ +// Automatically upgrade packages from these (origin, archive) pairs +Unattended-Upgrade::Origins-Pattern { + "o=aOrigin,a=aArchive"; + "s=aSite,l=aLabel"; + "o=Google\, Inc.,suite=stable"; +}; diff -Nru unattended-upgrades-0.55ubuntu3/test/data/50unattended-upgrades.compat unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/data/50unattended-upgrades.compat --- unattended-upgrades-0.55ubuntu3/test/data/50unattended-upgrades.compat 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/data/50unattended-upgrades.compat 2011-12-12 13:10:14.000000000 +0000 @@ -0,0 +1,6 @@ +// Automatically upgrade packages from these (origin:archive) pairs +Unattended-Upgrade::Allowed-Origins { + "Google, Inc.:stable"; + "MoreCorp\, eink:stable"; + "${distro_id}:${distro_codename}-security"; +}; diff -Nru unattended-upgrades-0.55ubuntu3/test/data/listchanges.conf.mail unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/data/listchanges.conf.mail --- unattended-upgrades-0.55ubuntu3/test/data/listchanges.conf.mail 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/data/listchanges.conf.mail 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,6 @@ +[apt] +frontend=mail +email_address=root +confirm=0 +save_seen=/var/lib/apt/listchanges.db +which=both diff -Nru unattended-upgrades-0.55ubuntu3/test/data/listchanges.conf.pager unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/data/listchanges.conf.pager --- unattended-upgrades-0.55ubuntu3/test/data/listchanges.conf.pager 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/data/listchanges.conf.pager 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,6 @@ +[apt] +frontend=pager +email_address=root +confirm=0 +save_seen=/var/lib/apt/listchanges.db +which=both diff -Nru unattended-upgrades-0.55ubuntu3/test/mock-mail unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/mock-mail --- unattended-upgrades-0.55ubuntu3/test/mock-mail 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/mock-mail 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,4 @@ +#!/bin/sh + +echo $2 > mail.txt +cat - -- >> mail.txt Binary files /tmp/vBk4ErTvGJ/unattended-upgrades-0.55ubuntu3/test/packages/conf-test-package-257-conffiles_1.deb and /tmp/jYeRZNsOgz/unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/packages/conf-test-package-257-conffiles_1.deb differ Binary files /tmp/vBk4ErTvGJ/unattended-upgrades-0.55ubuntu3/test/packages/conf-test-package-no-conffiles-anymore_2.deb and /tmp/jYeRZNsOgz/unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/packages/conf-test-package-no-conffiles-anymore_2.deb differ Binary files /tmp/vBk4ErTvGJ/unattended-upgrades-0.55ubuntu3/test/packages/conf-test-package_1.0.deb and /tmp/jYeRZNsOgz/unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/packages/conf-test-package_1.0.deb differ Binary files /tmp/vBk4ErTvGJ/unattended-upgrades-0.55ubuntu3/test/packages/conf-test-package_1.1.deb and /tmp/jYeRZNsOgz/unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/packages/conf-test-package_1.1.deb differ Binary files /tmp/vBk4ErTvGJ/unattended-upgrades-0.55ubuntu3/test/packages/multiple-conffiles_1_all.deb and /tmp/jYeRZNsOgz/unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/packages/multiple-conffiles_1_all.deb differ Binary files /tmp/vBk4ErTvGJ/unattended-upgrades-0.55ubuntu3/test/packages/multiple-conffiles_2_all.deb and /tmp/jYeRZNsOgz/unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/packages/multiple-conffiles_2_all.deb differ diff -Nru unattended-upgrades-0.55ubuntu3/test/root.conffile/etc/configuration-file unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/root.conffile/etc/configuration-file --- unattended-upgrades-0.55ubuntu3/test/root.conffile/etc/configuration-file 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/root.conffile/etc/configuration-file 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,3 @@ +This is a configuration file, +dfasddfasdff +No really. diff -Nru unattended-upgrades-0.55ubuntu3/test/root.conffile/etc/configuration-file1 unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/root.conffile/etc/configuration-file1 --- unattended-upgrades-0.55ubuntu3/test/root.conffile/etc/configuration-file1 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/root.conffile/etc/configuration-file1 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,3 @@ +This is a first configuration file, + +No really. diff -Nru unattended-upgrades-0.55ubuntu3/test/root.conffile/etc/configuration-file2 unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/root.conffile/etc/configuration-file2 --- unattended-upgrades-0.55ubuntu3/test/root.conffile/etc/configuration-file2 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/root.conffile/etc/configuration-file2 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,3 @@ +This is a second configuration file, + +It is modified by the user. by the user. diff -Nru unattended-upgrades-0.55ubuntu3/test/root.conffile/var/lib/dpkg/status unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/root.conffile/var/lib/dpkg/status --- unattended-upgrades-0.55ubuntu3/test/root.conffile/var/lib/dpkg/status 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/root.conffile/var/lib/dpkg/status 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,16 @@ +Package: test-package +Status: install ok installed +Architecture: all +Version: 0.9 +Conffiles: + /etc/not-available-config-file 99b99d59ac8f5ecd3375107755ee8599 + /etc/configuration-file 26b99d59ac8f5ecd3375107755ee8527 + /etc/not-available-config-file2 88b99d59ac8f5ecd3375107755ee8588 + +Package: multiple-conffiles +Status: install ok installed +Architecture: all +Version: 1.0 +Conffiles: + /etc/configuration-file1 cb9a458f0fdc96e10b4d23923f16e3a0 + /etc/configuration-file2 8bf10a884dcfe6a8c3e57039e14d2b92 diff -Nru unattended-upgrades-0.55ubuntu3/test/test_against_real_archive.py unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_against_real_archive.py --- unattended-upgrades-0.55ubuntu3/test/test_against_real_archive.py 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_against_real_archive.py 2012-03-09 08:34:44.000000000 +0000 @@ -0,0 +1,62 @@ +#!/usr/bin/python + +import apt +import apt_pkg +import glob +import os +import re +import unittest + +import unattended_upgrade + +apt_pkg.config.set("APT::Architecture", "amd64") + +class MockOptions(): + def __init__(self, debug=True, dry_run=True): + self.debug = debug + self.dry_run = dry_run + self.minimal_upgrade_steps = False + +class TestAgainstRealArchive(unittest.TestCase): + + def setUp(self): + for f in glob.glob("./aptroot/var/log/*"): + if os.path.isfile(f): + os.remove(f) + + def test_against_real_archive(self): + # get a lucid based cache (test good for 5y) + cache = apt.Cache(rootdir="./aptroot") + cache.update() + del cache + # create mock options + options = MockOptions(debug=True) + # ensure apt does not do any post-invoke stuff that fails + # (because we are not root) + apt_pkg.config.clear("DPkg::Post-Invoke") + # run unattended-upgrades against fake system + logdir = os.path.abspath("./aptroot/var/log/") + logfile = os.path.join(logdir, "unattended-upgrades.log") + apt_pkg.config.set("APT::UnattendedUpgrades::LogDir", logdir) + unattended_upgrade.DISTRO_CODENAME = "lucid" + res = unattended_upgrade.main(options, os.path.abspath("./aptroot")) + # check if the log file exists + self.assertTrue(os.path.exists(logfile)) + log = open(logfile).read() + # check that stuff worked + self.assertFalse(" ERROR " in log) + # check if we actually have the expected ugprade in it + self.assertTrue( + re.search("INFO Packages that are upgraded:.*awstats", log)) + # apt-doc has a higher version in -updates than in -security + # and no other dependencies so its a perfect test + self.assertTrue( + re.search("INFO Packages that are upgraded:.*apt-doc", log)) + self.assertFalse( + re.search("INFO Packages that are upgraded:.*ant-doc", log)) + self.assertTrue( + re.search("DEBUG skipping blacklisted package 'ant-doc'", log)) + +if __name__ == "__main__": + unittest.main() + diff -Nru unattended-upgrades-0.55ubuntu3/test/test_conffile.py unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_conffile.py --- unattended-upgrades-0.55ubuntu3/test/test_conffile.py 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_conffile.py 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,49 @@ +#!/usr/bin/python + +import apt_pkg +import logging +import unittest +import sys + +from unattended_upgrade import conffile_prompt + +class TestConffilePrompt(unittest.TestCase): + def setUp(self): + apt_pkg.config.set("Dir::State::status", + "./root.conffile/var/lib/dpkg/status") + + def testWillPrompt(self): + # conf-test 0.9 is installed, 1.1 gets installed + # they both have different config files + test_pkg = "./packages/conf-test-package_1.1.deb" + self.assertTrue(conffile_prompt(test_pkg, prefix="./root.conffile"), + "conffile prompt detection incorrect") + + def testWillNotPrompt(self): + # conf-test 0.9 is installed, 1.0 gets installed + # they both have the same config files + test_pkg = "./packages/conf-test-package_1.0.deb" + self.assertFalse(conffile_prompt(test_pkg, prefix="./root.conffile"), + "conffile prompt detection incorrect") + + def testWillNotPrompt(self): + # ensure we don't crash when encountering a conffile with overly + # many entries + test_pkg = "./packages/conf-test-package-257-conffiles_1.deb" + self.assertFalse(conffile_prompt(test_pkg, prefix="./root.conffile"), + "conffile prompt detection incorrect") + # no conffiles anymore in the pkg + test_pkg = "./packages/conf-test-package-no-conffiles-anymore_2.deb" + self.assertFalse(conffile_prompt(test_pkg, prefix="./root.conffile"), + "conffile prompt detection incorrect") + + def testWillPromptMultiple(self): + test_pkg = "./packages/multiple-conffiles_2_all.deb" + self.assertTrue(conffile_prompt(test_pkg, prefix="./root.conffile"), + "conffile prompt detection incorrect") + + +if __name__ == "__main__": + logging.basicConfig(level=logging.DEBUG) + unittest.main() + diff -Nru unattended-upgrades-0.55ubuntu3/test/test_in_chroot.py unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_in_chroot.py --- unattended-upgrades-0.55ubuntu3/test/test_in_chroot.py 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_in_chroot.py 2012-03-09 08:34:44.000000000 +0000 @@ -0,0 +1,207 @@ +#!/usr/bin/python + +import apt +import logging +import glob +import os +import re +import shutil +import subprocess +import sys +import time +import unittest + +# debian +#SOURCES_LIST=""" +#deb http://ftp.de.debian.org/debian squeeze main contrib non-free +#deb http://ftp.de.debian.org/debian squeeze-updates main contrib non-free +#deb http://ftp.de.debian.org/debian squeeze-proposed-updates main contrib non-f#ree +#deb http://security.debian.org squeeze/updates main contrib non-free +#""" +#DISTRO="squeeze" +#ARCH="i386" +#TARBALL="%s-%s.tgz" % (DISTRO, ARCH) +#MIRROR="http://ftp.de.debian.org/debian" +#APT_CONF="""APT::Architecture "%s";""" % ARCH +#ORIGINS_PATTERN="origin=Debian,archive=stable,label=Debian-Security" + + +# ubuntu +SOURCES_LIST=""" +deb http://archive.ubuntu.com/ubuntu/ lucid main restricted +deb-src http://archive.ubuntu.com/ubuntu/ lucid main restricted + +deb http://archive.ubuntu.com/ubuntu/ lucid-updates main restricted +deb-src http://archive.ubuntu.com/ubuntu/ lucid-updates main restricted + +deb http://security.ubuntu.com/ubuntu/ lucid-security main restricted +deb-src http://security.ubuntu.com/ubuntu/ lucid-security main restricted +""" +DISTRO="lucid" +ARCH="i386" +TARBALL="%s-%s.tgz" % (DISTRO, ARCH) +MIRROR="http://archive.ubuntu.com/ubuntu" +APT_CONF="""APT::Architecture "%s";""" % ARCH +ORIGINS_PATTERN="origin=Ubuntu,archive=lucid-security" + +apt.apt_pkg.config.set("APT::Architecture", ARCH) +sys.path.insert(0, "..") +import unattended_upgrade + +class MockOptions(object): + debug = True + dry_run = False + minimal_upgrade_steps = False + +class TestUnattendedUpgrade(unittest.TestCase): + + def _create_new_debootstrap_tarball(self, tarball, target): + print "creating initial test tarball, this is needed only once" + # force i386 + subprocess.call(["debootstrap", + "--arch=%s" % ARCH, + # smaller version of the minimal system + "--variant=minbase", + "--include=python-apt,apt-utils,gpgv,ubuntu-keyring", + DISTRO, + target, + MIRROR]) + subprocess.call(["chroot", target, "apt-get", "clean"]) + subprocess.call(["tar", "czf", tarball, target]) + + def _unpack_debootstrap_tarball(self, tarball, target): + subprocess.call(["tar", "xzf", tarball]) + + def test_normal_upgrade(self): + print "Running normal unattended upgrade in chroot" + options = MockOptions() + options.minimal_upgrade_steps = False + # run it + target = self._run_upgrade_test_in_real_chroot(options) + # ensure we upgraded the expected packages + self.assertTrue(self._verify_install_log_in_real_chroot(target)) + + def test_minimal_steps_upgrade(self): + print "Running minimal steps unattended upgrade in chroot" + options = MockOptions() + options.minimal_upgrade_steps = True + # run it + target = self._run_upgrade_test_in_real_chroot(options) + # ensure we upgraded the expected packages + self.assertTrue(self._verify_install_log_in_real_chroot(target)) + + def test_upgrade_on_shutdown_upgrade(self): + print "Running unattended upgrade on shutdown (download and install) in chroot" + # ensure that it actually installs in shutdown env mode + options = MockOptions() + os.environ["UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN"] = "1" + apt.apt_pkg.config.set("Unattended-Upgrade::InstallOnShutdown", "1") + target = self._run_upgrade_test_in_real_chroot(options) + self.assertTrue(self._verify_install_log_in_real_chroot(target)) + + def _get_lockfile_location(self, target): + return os.path.join( + target, "var/log/unattended-upgrades/unattended-upgrades.log") + + def _setup_chroot(self, target): + """ helper that setups a clean chroot """ + if os.path.exists(target): + shutil.rmtree(target) + if not os.path.exists(TARBALL): + self._create_new_debootstrap_tarball(TARBALL, target) + # create new + self._unpack_debootstrap_tarball(TARBALL, target) + open(os.path.join(target, "etc/apt/apt.conf"), "w").write(APT_CONF) + open(os.path.join(target, "etc/apt/sources.list"), "w").write( + SOURCES_LIST) + + + def _run_upgrade_test_in_real_chroot(self, options, clean_chroot=True): + """ helper that runs the unattended-upgrade in a chroot + and does some basic verifications + """ + if os.getuid() != 0: + print "Skipping because uid != 0" + return + + # clear to avoid pollution in the chroot + apt.apt_pkg.config.clear("Acquire::http::ProxyAutoDetect") + + # create chroot + target = "./test-chroot.%s" % DISTRO + + # setup chroot if needed + if clean_chroot: + self._setup_chroot(target) + + # and run the upgrade test + pid = os.fork() + if pid == 0: + # chroot + os.chroot(target) + os.chdir("/") + if not os.path.exists("/var/log/unattended-upgrades/"): + os.makedirs("/var/log/unattended-upgrades/") + # make sure we are up-to-date + subprocess.call(["apt-get","update", "-q", "-q"]) + # run it + apt.apt_pkg.config.clear("Unattended-Upgrade::Allowed-Origins") + apt.apt_pkg.config.clear("Unattended-Upgrade::Origins-Pattern") + apt.apt_pkg.config.set( + "Unattended-Upgrade::Origins-Pattern::", ORIGINS_PATTERN) + unattended_upgrade.DISTRO_CODENAME = "lucid" + unattended_upgrade.main(options) + os._exit(0) + else: + has_progress=False + all_progress = "" + last_progress = "" + progress_log = os.path.join( + target, "var/run/unattended-upgrades.progress") + while True: + time.sleep(0.01) + if os.path.exists(progress_log): + progress = open(progress_log).read() + if progress and progress != last_progress: + has_progress = progress.startswith("Progress") + last_progress = progress + all_progress += progress + # check exit status + (apid, status) = os.waitpid(pid, os.WNOHANG) + if pid == apid: + ret = os.WEXITSTATUS(status) + break + #print "*******************", all_progress + self.assertEqual(ret, 0) + # this number is a bit random, we just want to be sure we have + # progress data + self.assertTrue(has_progress, True) + self.assertTrue(len(all_progress) > 5) + return target + + def _verify_install_log_in_real_chroot(self, target): + # examine log + log = self._get_lockfile_location(target) + logfile = open(log).read() + #print logfile + NEEDLE_PKG="ca-certificates" + if not re.search( + "Packages that are upgraded:.*%s" % NEEDLE_PKG, logfile): + logging.warn("Can not find expected %s upgrade in log" % NEEDLE_PKG) + return False + if "ERROR Installing the upgrades failed" in logfile: + logging.warn("Got a ERROR in the logfile") + return False + dpkg_log = os.path.join( + target, "var/log/unattended-upgrades/*-dpkg*.log") + dpkg_logfile = open(glob.glob(dpkg_log)[0]).read() + if not "Preparing to replace %s" % NEEDLE_PKG in dpkg_logfile: + logging.warn("Did not find %s upgrade in the dpkg.log" % NEEDLE_PKG) + return False + #print dpkg_logfile + return True + + +if __name__ == "__main__": + #logging.basicConfig(level=logging.DEBUG) + unittest.main() diff -Nru unattended-upgrades-0.55ubuntu3/test/test_logdir.py unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_logdir.py --- unattended-upgrades-0.55ubuntu3/test/test_logdir.py 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_logdir.py 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,45 @@ +#!/usr/bin/python + +import apt_pkg +import logging +import os +import mock +import sys +import tempfile +import unittest + +sys.path.insert(0, "..") +from unattended_upgrade import _setup_logging + +class MockOptions: + dry_run = False + +class TestLogdir(unittest.TestCase): + + def setUp(self): + self.tempdir = tempfile.mkdtemp() + apt_pkg.init() + self.mock_options = MockOptions() + + def test_logdir(self): + # test log + logdir = os.path.join(self.tempdir, "mylog") + apt_pkg.config.set("Unattended-Upgrade::LogDir", logdir) + _setup_logging(self.mock_options) + self.assertTrue(os.path.exists(logdir)) + + def test_logdir_depreated(self): + # test if the deprecated APT::UnattendedUpgrades dir is not used + # if the new UnaUnattendedUpgrades::LogDir is given + logdir = os.path.join(self.tempdir, "mylog-use") + logdir2 = os.path.join(self.tempdir, "mylog-dontuse") + apt_pkg.config.set("Unattended-Upgrade::LogDir", logdir) + apt_pkg.config.set("APT::UnattendedUpgrades::LogDir", logdir2) + _setup_logging(self.mock_options) + self.assertTrue(os.path.exists(logdir)) + self.assertFalse(os.path.exists(logdir2)) + + +if __name__ == "__main__": + logging.basicConfig(level=logging.DEBUG) + unittest.main() diff -Nru unattended-upgrades-0.55ubuntu3/test/test_mail.py unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_mail.py --- unattended-upgrades-0.55ubuntu3/test/test_mail.py 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_mail.py 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,97 @@ +#!/usr/bin/python + +import apt +import apt_pkg +import os +import logging +import unittest +import sys + +from StringIO import StringIO + +import unattended_upgrade +import unattended_upgrade +from unattended_upgrade import send_summary_mail, setup_apt_listchanges + +class TestSendSummaryMail(unittest.TestCase): + + def setUp(self): + # monkey patch to make it testable + unattended_upgrade.REBOOT_REQUIRED_FILE = "./reboot-required" + # mock-mail binary that creates a mail.txt file + unattended_upgrade.MAIL_BINARY = "./mock-mail" + # setup mail + apt_pkg.config.set("Unattended-Upgrade::Mail", "root") + apt_pkg.config.set("Unattended-Upgrade::MailOnlyOnError", "false") + + def tearDown(self): + for f in ["mail.txt", "reboot-required", "apt-term.log"]: + if os.path.exists(f): + os.unlink(f) + + def _return_mock_data(self, successful=True): + """ return input tuple for send_summary_mail """ + pkgs = "\n".join(["2vcard"]) + res = successful + pkgs_kept_back = [] + mem_log = StringIO("mem_log text") + logfile_dpkg = "./apt-term.log" + open("./apt-term.log", "w").write("logfile_dpkg text") + return (pkgs, res, pkgs_kept_back, mem_log, logfile_dpkg) + + def _verify_common_mail_content(self, mail_txt): + self.assertTrue("logfile_dpkg text" in mail_txt) + self.assertTrue("mem_log text" in mail_txt) + self.assertTrue("Packages that are upgraded:\n 2vcard" in mail_txt) + + def test_summary_mail_reboot(self): + open("./reboot-required","w").write("") + send_summary_mail(*self._return_mock_data()) + os.unlink("./reboot-required") + mail_txt = open("mail.txt").read() + self.assertTrue("[reboot required]" in mail_txt) + self._verify_common_mail_content(mail_txt) + + def test_summary_mail_no_reboot(self): + send_summary_mail(*self._return_mock_data()) + mail_txt = open("mail.txt").read() + self.assertFalse("[reboot required]" in mail_txt) + self._verify_common_mail_content(mail_txt) + + def test_summary_mail_only_on_error(self): + # default is to always send mail, ensure this is correct + # for both success and failure + apt_pkg.config.set("Unattended-Upgrade::MailOnlyOnError", "false") + send_summary_mail(*self._return_mock_data(successful=True)) + self._verify_common_mail_content(open("mail.txt").read()) + os.remove("mail.txt") + # now with a simulated failure + send_summary_mail(*self._return_mock_data(successful=False)) + self._verify_common_mail_content(open("mail.txt").read()) + os.remove("mail.txt") + # now test with "MailOnlyOnError" + apt_pkg.config.set("Unattended-Upgrade::MailOnlyOnError", "true") + send_summary_mail(*self._return_mock_data(successful=True)) + self.assertFalse(os.path.exists("mail.txt")) + send_summary_mail(*self._return_mock_data(successful=False)) + mail_txt = open("mail.txt").read() + self._verify_common_mail_content(mail_txt) + self.assertTrue("Unattended upgrade returned: False" in mail_txt) + self.assertTrue(os.path.exists("mail.txt")) + + def test_apt_listchanges(self): + # test with mail as frontend + os.environ["APT_LISTCHANGES_FRONTEND"] = "canary" + unattended_upgrade.SENDMAIL_BINARY="/bin/true" + setup_apt_listchanges("./data/listchanges.conf.mail") + self.assertEqual(os.environ["APT_LISTCHANGES_FRONTEND"], "canary") + # test with pager as frontend + os.environ["APT_LISTCHANGES_FRONTEND"] = "canary" + unattended_upgrade.SENDMAIL_BINARY="/bin/true" + setup_apt_listchanges("./data/listchanges.conf.pager") + self.assertEqual(os.environ["APT_LISTCHANGES_FRONTEND"], "none") + +if __name__ == "__main__": + logging.basicConfig(level=logging.DEBUG) + unittest.main() + diff -Nru unattended-upgrades-0.55ubuntu3/test/test_minimal_partitions.py unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_minimal_partitions.py --- unattended-upgrades-0.55ubuntu3/test/test_minimal_partitions.py 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_minimal_partitions.py 2011-10-19 13:13:20.000000000 +0000 @@ -0,0 +1,57 @@ +#!/usr/bin/python + +import apt +import apt_pkg +import os +import logging +import unittest +import sys +import time + +import unattended_upgrade + +class LogInstallProgressMock(unattended_upgrade.LogInstallProgress): + + # klass data so that we can veriy in the test as the actual + # object is destroyed + DATA = [] + + # overwrite to log the data + def status_change(self, pkg, percent, status): + print pkg, percent + self.DATA.append([pkg, percent]) + +class TestMinimalPartitions(unittest.TestCase): + + def setUp(self): + # setup dry-run mode for apt + apt_pkg.config.set("Dir::Cache", "/tmp") + apt_pkg.config.set("Debug::NoLocking","1") + apt_pkg.config.set("Debug::pkgDPkgPM","1") + apt_pkg.config.set("Dir::State::extended_states", "./extended_states") + apt_pkg.config.clear("Dpkg::Post-Invoke") + apt_pkg.config.clear("Dpkg::Pre-Install-Pkgs") + self.cache = apt.Cache() + + def tearDown(self): + if os.path.exists("./extended_states"): + os.remove("./extended_states") + + def test_upgrade_in_minimal_steps(self): + self.cache.upgrade(True) + pkgs_to_upgrade = [pkg.name for pkg in self.cache.get_changes()] + unattended_upgrade.PROGRESS_LOG="./aptroot/var/run/unatteded-upgrades.progress" + unattended_upgrade.LogInstallProgress = LogInstallProgressMock + unattended_upgrade.upgrade_in_minimal_steps( + self.cache, pkgs_to_upgrade) + # ensure we count upwarts + last_percent = -1 + for (pkg, percent) in LogInstallProgressMock.DATA: + self.assertTrue(last_percent < percent) + last_percent = percent + # cleanup class data + LogInstallProgressMock.DATA = [] + +if __name__ == "__main__": + #logging.basicConfig(level=logging.DEBUG) + unittest.main() diff -Nru unattended-upgrades-0.55ubuntu3/test/test_origin_pattern.py unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_origin_pattern.py --- unattended-upgrades-0.55ubuntu3/test/test_origin_pattern.py 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_origin_pattern.py 2011-12-12 13:10:14.000000000 +0000 @@ -0,0 +1,121 @@ +#!/usr/bin/python + +import apt +import apt_pkg +import os +import logging +import unittest +import sys + +import unattended_upgrade +from unattended_upgrade import ( + match_whitelist_string, check_changes_for_sanity, is_allowed_origin) + +class MockOrigin(): + pass +class MockCandidate(): + pass +class MockPackage(): + pass +class MockCache(list): + pass +class MockDepCache(): + pass + +class TestOriginPatern(unittest.TestCase): + + def setUp(self): + pass + def tearDown(self): + pass + def test_match_whitelist_string(self): + origin = self._get_mock_origin( + "OriginUbuntu", "LabelUbuntu", "ArchiveUbuntu", + "archive.ubuntu.com", "main") + # good + s="o=OriginUbuntu" + self.assertTrue(match_whitelist_string(s, origin)) + s="o=OriginUbuntu,l=LabelUbuntu,a=ArchiveUbuntu,site=archive.ubuntu.com" + self.assertTrue(match_whitelist_string(s, origin)) + # bad + s="" + self.assertFalse(match_whitelist_string(s, origin)) + s="o=something" + self.assertFalse(match_whitelist_string(s, origin)) + s="o=LabelUbuntu,a=no-match" + self.assertFalse(match_whitelist_string(s, origin)) + # with escaping + origin = self._get_mock_origin("Google, Inc.", archive="stable") + # good + s="o=Google\, Inc.,a=stable" + self.assertTrue(match_whitelist_string(s, origin)) + + def test_match_whitelist_from_conffile(self): + # read some + apt_pkg.config.clear("Unattended-Upgrade") + apt_pkg.read_config_file(apt_pkg.config, "./data/50unattended-upgrades.Test") + allowed_origins = unattended_upgrade.get_allowed_origins() + #print allowed_origins + self.assertTrue("o=aOrigin,a=aArchive" in allowed_origins) + self.assertTrue("s=aSite,l=aLabel" in allowed_origins) + self.assertTrue("o=Google\, Inc.,suite=stable" in allowed_origins) + + def test_compatiblity(self): + apt_pkg.config.clear("Unattended-Upgrade") + apt_pkg.read_config_file(apt_pkg.config, "./data/50unattended-upgrades.compat") + allowed_origins = unattended_upgrade.get_allowed_origins() + #print allowed_origins + self.assertTrue("o=Google\, Inc.,a=stable" in allowed_origins) + self.assertTrue("o=MoreCorp\, eink,a=stable" in allowed_origins) + # test whitelist + pkg = self._get_mock_package() + self.assertTrue(is_allowed_origin(pkg.candidate, allowed_origins)) + + def test_blacklist(self): + # mock pkg (yeah, complicated) + pkg = self._get_mock_package() + # mock cache + cache = MockCache() + cache._depcache = MockDepCache() + cache._depcache.broken_count = 0 + cache.append(pkg) + # origins and blacklist + allowed_origins = ["o=Ubuntu"] + blacklist = ["linux-.*"] + # with blacklist pkg + self.assertFalse(check_changes_for_sanity(cache, allowed_origins, blacklist)) + # with "normal" pkg + pkg.name = "apt" + self.assertTrue(check_changes_for_sanity(cache, allowed_origins, blacklist)) + + def _get_mock_origin(self, aorigin="", label="", archive="", + site="", component=""): + origin = MockOrigin() + origin.origin = aorigin + origin.label = label + origin.archive = archive + origin.site = site + origin.compoent = component + return origin + + def _get_mock_package(self): + pkg = MockPackage() + pkg._pkg = MockPackage() + pkg._pkg.selected_state = 0 + pkg.name = "linux-image" + pkg.marked_install = True + pkg.marked_upgrade = True + pkg.marked_delete = False + pkg.candidate = MockCandidate() + pkg.candidate.origins = [self._get_mock_origin("Ubuntu"), + self._get_mock_origin(aorigin="Google, Inc.", + archive="stable"), + ] + pkg.candidate.record = {} + return pkg + + +if __name__ == "__main__": + logging.basicConfig(level=logging.DEBUG) + unittest.main() + diff -Nru unattended-upgrades-0.55ubuntu3/test/test_substitute.py unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_substitute.py --- unattended-upgrades-0.55ubuntu3/test/test_substitute.py 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/test_substitute.py 2011-10-07 07:31:17.000000000 +0000 @@ -0,0 +1,39 @@ +#!/usr/bin/python + +import apt +import apt_pkg +import os +import logging +import unittest +import sys + +from StringIO import StringIO + +import unattended_upgrade +from unattended_upgrade import substitute, get_allowed_origins + +class TestSubstitude(unittest.TestCase): + + def setUp(self): + # monkey patch DISTRO_{CODENAME, ID} + unattended_upgrade.DISTRO_CODENAME = "nacked" + unattended_upgrade.DISTRO_ID = "MyDistroID" + + def testSubstitute(self): + """ test if the substitute function works """ + self.assertTrue(substitute("${distro_codename}-updates"), + "nacked-updates") + self.assertTrue(substitute("${distro_id}"), "MyDistroID") + + def test_get_allowed_origins_with_substitute(self): + """ test if substitute for get_allowed_origins works """ + apt_pkg.config.clear("Unattended-Upgrade::Allowed-Origins") + apt_pkg.config.set("Unattended-Upgrade::Allowed-Origins::", + "${distro_id} ${distro_codename}-security") + l = get_allowed_origins() + self.assertTrue(("o=MyDistroID,a=nacked-security") in l) + +if __name__ == "__main__": + logging.basicConfig(level=logging.DEBUG) + unittest.main() + diff -Nru unattended-upgrades-0.55ubuntu3/test/unattended_upgrade.py unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/unattended_upgrade.py --- unattended-upgrades-0.55ubuntu3/test/unattended_upgrade.py 1970-01-01 00:00:00.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/test/unattended_upgrade.py 2012-11-08 19:52:23.000000000 +0000 @@ -0,0 +1,906 @@ +#!/usr/bin/python +# Copyright (c) 2005-2010 Canonical Ltd +# +# AUTHOR: +# Michael Vogt +# +# This file is part of unattended-upgrades +# +# unattended-upgrades 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. +# +# unattended-upgrades 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 unattended-upgrades; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +import apt_inst +import apt_pkg + +import ConfigParser +import copy +import datetime +import fcntl +import re +import os +import string +import sys + +from StringIO import StringIO +from optparse import OptionParser +from subprocess import Popen, PIPE + +import warnings +warnings.filterwarnings("ignore", "apt API not stable yet", FutureWarning) +import apt +import logging +import lsb_release +import signal +import subprocess + +import gettext +from gettext import gettext as _ + +# the reboot required flag file used by packages +REBOOT_REQUIRED_FILE = "/var/run/reboot-required" +MAIL_BINARY = "/usr/bin/mail" +SENDMAIL_BINARY = "/usr/sbin/sendmail" +DISTRO_CODENAME = lsb_release.get_distro_information()['CODENAME'] +DISTRO_ID = lsb_release.get_distro_information()['ID'] + +# progress information is written here +PROGRESS_LOG="/var/run/unattended-upgrades.progress" + +# set from the sigint signal handler +SIGNAL_STOP_REQUEST=False + +class UnattendedUpgradesCache(apt.Cache): + + def __init__(self, rootdir, allowed_origins): + apt.Cache.__init__(self, rootdir=rootdir) + self.allowed_origins = allowed_origins + # ensure we update the candidate versions + self.adjust_candidate_versions() + def clear(self): + apt.Cache.clear(self) + # ensure we update the candidate versions + self.adjust_candidate_versions() + def adjust_candidate_versions(self): + """ Adjust candidate versions to match highest allowed origin + + This adjusts the origin even if the candidate has a higher + version + """ + for pkg in self: + # important! this avoids downgrades below + if not pkg.is_upgradable: + continue + # check if we have a version in a allowed origin that is + # not the candidate + new_cand = None + for ver in pkg.versions: + if is_allowed_origin(ver, self.allowed_origins): + # leave as soon as we have the highest new candidate + new_cand = ver + break + if new_cand and new_cand != pkg.candidate: + logging.debug("adjusting candidate version: '%s'" % new_cand) + pkg.candidate = new_cand + + +class LogInstallProgress(apt.progress.base.InstallProgress): + """ Install progress that writes to self.LOG + (/var/run/unattended-upgrades.progress by default) + """ + + LOG = PROGRESS_LOG + + def status_change(self, pkg, percent, status): + f=open(self.LOG, "w") + f.write(_("Progress: %s %% (%s)") % (percent, pkg)) + f.close() + + def _fixup_fds(self): + required_fds = [ 0, 1, 2, # stdin, stdout, stderr + self.writefd, + self.write_stream.fileno(), + self.statusfd, + self.status_stream.fileno() + ] + # ensure that our required fds close on exec + for fd in required_fds[3:]: + old_flags = fcntl.fcntl(fd, fcntl.F_GETFD) + fcntl.fcntl(fd, fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC) + # close all fds + proc_fd = "/proc/self/fd" + if os.path.exists(proc_fd): + error_count = 0 + for fdname in os.listdir(proc_fd): + try: + fd = int(fdname) + except Exception as e: + print "ERROR: can not get fd for '%s'" % fdname + if fd in required_fds: + continue + try: + os.close(fd) + #print "closed: ", fd + except OSError as e: + # there will be one fd that can not be closed + # as its the fd from pythons internal diropen() + # so its ok to ignore one close error + error_count += 1 + if error_count > 1: + print "ERROR: os.close(%s): %s" % (fd, e) + + def fork(self): + pid = os.fork() + if pid == 0: + self._fixup_fds() + return pid + + +class Unlocked: + """ context manager for unlocking the apt lock while cache.commit() + is run + """ + def __enter__(self): + try: + apt_pkg.pkgsystem_unlock() + except: + pass + def __exit__(self, exc_type, exc_value, exc_tb): + try: + apt_pkg.pkgsystem_unlock() + except: + pass + +def is_dpkg_journal_dirty(): + """ + test if the dpkg journal is dirty + (similar to debSystem::CheckUpdates) + """ + d = os.path.dirname( + apt_pkg.config.find_file("Dir::State::status"))+"/updates" + for f in os.listdir(d): + if re.match("[0-9]+", f): + return True + return False + +def signal_handler(signal, frame): + logging.warn("SIGUSR1 recieved, will stop") + global SIGNAL_STOP_REQUEST + SIGNAL_STOP_REQUEST=True + +def substitute(line): + """ substitude known mappings and return a new string + + Currently supported ${distro-release} + """ + mapping = {"distro_codename" : get_distro_codename(), + "distro_id" : get_distro_id(), + } + return string.Template(line).substitute(mapping) + +def get_distro_codename(): + return DISTRO_CODENAME + +def get_distro_id(): + return DISTRO_ID + +def get_allowed_origins_legacy(): + """ legacy support for old Allowed-Origins var """ + allowed_origins = [] + for s in apt_pkg.config.value_list("Unattended-Upgrade::Allowed-Origins"): + # if there is a ":" use that as seperator, else use spaces + if ":" in s: + (distro_id, distro_codename) = s.split(':') + else: + (distro_id, distro_codename) = s.split() + # escape "," (see LP: #824856) - i wonder if there is a simpler way? + distro_id = re.sub(r'([^\\]),', r'\1\\,', distro_id) + distro_codename = re.sub(r'([^\\]),', r'\1\\,', distro_codename) + # convert to new format + allowed_origins.append("o=%s,a=%s" % (substitute(distro_id), + substitute(distro_codename))) + return allowed_origins + +def get_allowed_origins(): + """ return a list of allowed origins from apt.conf + + This will take substitutions (like distro_id) into account. + """ + allowed_origins = get_allowed_origins_legacy() + for s in apt_pkg.config.value_list("Unattended-Upgrade::Origins-Pattern"): + allowed_origins.append(substitute(s)) + return allowed_origins + +def match_whitelist_string(whitelist, origin): + """ + take a whitelist string in the form "origin=Debian,label=Debian-Security" + and match against the given python-apt origin. A empty whitelist string + never matches anything. + """ + whitelist = whitelist.strip() + if whitelist == "": + logging.warn("empty match string matches nothing") + return False + res = True + # make "\," the html quote equivalent + whitelist = whitelist.replace("\,", "%2C") + for token in whitelist.split(","): + # strip and unquote the "," back + (what, value) = [s.strip().replace("%2C",",") + for s in token.split("=")] + #logging.debug("matching '%s'='%s' against '%s'" % (what, value, origin)) + # first char is apt-cache policy output, send is the name + # in the Release file + if what in ("o", "origin"): + res &= (value == origin.origin) + elif what in ("l", "label"): + res &= (value == origin.label) + elif what in ("a", "suite", "archive"): + res &= (value == origin.archive) + elif what in ("c", "component"): + res &= (value == origin.component) + elif what in ("site",): + res &= (value == origin.site) + return res + +def upgrade_normal(cache, pkgs_to_upgrade, logfile_dpkg): + error = None + res = False + iprogress = LogInstallProgress() + try: + with Unlocked(): + res = cache.commit(install_progress=iprogress) + except SystemError,e: + error = e + if res: + logging.info(_("All upgrades installed")) + else: + logging.error(_("Installing the upgrades failed!")) + logging.error(_("error message: '%s'") % error) + logging.error(_("dpkg returned a error! See '%s' for details") % \ + logfile_dpkg) + return res + +def upgrade_in_minimal_steps(cache, pkgs_to_upgrade, logfile_dpkg=""): + + install_log = LogInstallProgress() + install_log.LOG += ".minimal-steps" + + # setup signal handler + signal.signal(signal.SIGUSR1, signal_handler) + + # to upgrade contains the package names + to_upgrade = set(pkgs_to_upgrade) + while True: + # find smallest set + smallest_partition = to_upgrade + for pkgname in to_upgrade: + if SIGNAL_STOP_REQUEST: + logging.warn("SIGNAL recieved, stopping") + return True + pkg = cache[pkgname] + if pkg.is_upgradable: + pkg.mark_upgrade() + elif not pkg.is_installed: + pkg.mark_install() + else: + continue + changes = [pkg.name for pkg in cache.get_changes()] + if len(changes) == 1: + logging.debug("found leaf package %s" % pkg.name) + smallest_partition = changes + break + if len(changes) < len(smallest_partition): + logging.debug("found partition of size %s (%s)" % (len(changes), changes)) + smallest_partition = changes + cache.clear() + + # write progress log information + if len(pkgs_to_upgrade) > 0: + percent = (len(pkgs_to_upgrade)-len(to_upgrade)) / float(len(pkgs_to_upgrade))*100.0 + else: + percent = 100.0 + install_log.status_change(pkg=",".join(smallest_partition), + percent=percent, + status="") + # apply changes + logging.debug("applying set %s" % smallest_partition) + rewind_cache(cache, [cache[name] for name in smallest_partition]) + + try: + iprogress = LogInstallProgress() + with Unlocked(): + res = cache.commit(install_progress=iprogress) + if not res: + raise Exception("cache.commit() returned false") + cache.open() + except Exception, e: + logging.error(_("Installing the upgrades failed!")) + logging.error(_("error message: '%s'") % e) + logging.error(_("dpkg returned a error! See '%s' for details") % \ + logfile_dpkg) + return False + to_upgrade = to_upgrade-set(smallest_partition) + logging.debug("left to upgrade %s" % to_upgrade) + if len(to_upgrade) == 0: + logging.info(_("All upgrades installed")) + break + return True + +def is_allowed_origin(ver, allowed_origins): + if not ver: + return False + for origin in ver.origins: + for allowed in allowed_origins: + if match_whitelist_string(allowed, origin): + return True + return False + +def check_changes_for_sanity(cache, allowed_origins, blacklist): + if cache._depcache.broken_count != 0: + return False + for pkg in cache: + if pkg.marked_delete: + logging.debug("pkg '%s' now marked delete" % pkg.name) + return False + if pkg.marked_install or pkg.marked_upgrade: + if not is_allowed_origin(pkg.candidate, allowed_origins): + logging.debug("pkg '%s' not in allowed origin" % pkg.name) + return False + for blacklist_regexp in blacklist: + if re.match(blacklist_regexp, pkg.name): + logging.debug("skipping blacklisted package '%s'" % pkg.name) + return False + if pkg._pkg.selected_state == apt_pkg.SELSTATE_HOLD: + logging.debug("pkg '%s' is on hold" % pkg.name) + return False + # check if the package is unsafe to upgrade unattended + ignore_require_restart = apt_pkg.config.find_b( + "Unattended-Upgrade::IgnoreAppsRequireRestart", False) + if (pkg.marked_upgrade and + ignore_require_restart == False and + pkg.candidate.record.get("Upgrade-Requires") == "app-restart"): + logging.debug("pkg '%s' requires app-restart, not safe to upgrade unattended") + return False + return True + +def pkgname_from_deb(debfile): + # FIXME: add error checking here + try: + control = apt_inst.DebFile(debfile).control.extractdata("control") + sections = apt_pkg.TagSection(control) + return sections["Package"] + except (IOError, SystemError), e: + logging.error("failed to read deb file '%s' (%s)" % (debfile, e)) + # dumb fallback + return debfile.split("_")[0] + +# prefix is *only* needed for the build-in tests +def conffile_prompt(destFile, prefix=""): + logging.debug("check_conffile_prompt('%s')" % destFile) + pkgname = pkgname_from_deb(destFile) + status_file = apt_pkg.config.find("Dir::State::status") + tagfile = apt_pkg.TagFile(open(status_file,"r")) + for section in tagfile: + if section.get("Package") == pkgname: + logging.debug("found pkg: %s" % pkgname) + if "Conffiles" in section: + conffiles = section.get("Conffiles") + # Conffiles: + # /etc/bash_completion.d/m-a c7780fab6b14d75ca54e11e992a6c11c + for line in string.split(conffiles,"\n"): + logging.debug("conffile line: %s", line) + l = string.split(string.strip(line)) + conf_file = l[0] + md5 = l[1] + if len(l) > 2: + obs = l[2] + else: + obs = None + # ignore if conffile is obsolete or does not exist + if obs == "obsolete" or not os.path.exists(prefix+conf_file): + continue + # ignore state "newconffile" until its clearer if there + # might be a dpkg prompt (LP: #936870) + if md5 == "newconffile": + continue + # get conffile value from pkg, its ok if the new version + # does not have conffiles anymore + deb = apt_inst.DebFile(destFile) + try: + pkg_conffiles = deb.control.extractdata("conffiles") + except LookupError as e: + logging.debug("No conffiles in %s anymore? (%s)" % (destFile, e)) + pkg_conffiles = "" + if (not pkg_conffiles or + not conf_file in pkg_conffiles.split("\n")): + logging.debug("'%s' not in package conffiles '%s'" % (conf_file, pkg_conffiles)) + continue + # test against the installed file + current_md5 = apt_pkg.md5sum(open(prefix+conf_file).read()) + logging.debug("current md5: %s" % current_md5) + # hashes are the same, no conffile prompt + if current_md5 == md5: + continue + # calculate md5sum from the deb (may take a bit) + dpkg_cmd = ["dpkg-deb","--fsys-tarfile",destFile] + tar_cmd = ["tar","-x","-O", "-f","-", "."+conf_file] + md5_cmd = ["md5sum"] + dpkg_p = Popen(dpkg_cmd, stdout=PIPE) + tar_p = Popen(tar_cmd, stdin=dpkg_p.stdout, stdout=PIPE) + md5_p = Popen(md5_cmd, stdin=tar_p.stdout, stdout=PIPE) + pkg_md5sum = md5_p.communicate()[0].split()[0] + logging.debug("pkg_md5sum: %s" % pkg_md5sum) + # the md5sum in the deb is unchanged, this will not + # trigger a conffile prompt + if pkg_md5sum == md5: + continue + # if we made it to this point: + # current_md5 != pkg_md5sum != md5 + # and that will trigger a conffile prompt, we can + # stop processing at this point and just return True + return True + return False + + +def dpkg_conffile_prompt(): + if not "DPkg::Options" in apt_pkg.config: + return True + options = apt_pkg.config.value_list("DPkg::Options") + for option in map(string.strip, options): + if (option == "--force-confold" or + option == "--force-confnew"): + return False + return True + +def rewind_cache(cache, pkgs_to_upgrade): + " set the cache back to the state with packages_to_upgrade " + cache.clear() + for pkg2 in pkgs_to_upgrade: + pkg2.mark_upgrade() + +def host(): + return os.uname()[1] + +# *sigh* textwrap is nice, but it breaks "linux-image" into two +# seperate lines +def wrap(t, width=70, subsequent_indent=""): + out = "" + for s in t.split(): + if (len(out)-out.rfind("\n")) + len(s) > width: + out += "\n" + subsequent_indent + out += s + " " + return out + +def setup_apt_listchanges(conf="/etc/apt/listchanges.conf"): + """ deal with apt-listchanges """ + if os.path.exists(conf): + # check if mail is used by apt-listchanges + cf = ConfigParser.ConfigParser() + cf.read(conf) + if cf.has_section("apt") and cf.has_option("apt", "frontend"): + frontend = cf.get("apt","frontend") + if frontend == "mail" and os.path.exists(SENDMAIL_BINARY): + # mail frontend and sendmail, we are fine + logging.debug("apt-listchanges is set to mail frontend, ignoring") + return + # setup env (to play it safe) and return + os.environ["APT_LISTCHANGES_FRONTEND"] = "none" + +def send_summary_mail(pkgs, res, pkgs_kept_back, mem_log, logfile_dpkg): + " send mail (if configured in Unattended-Upgrade::Mail) " + email = apt_pkg.config.find("Unattended-Upgrade::Mail", "") + if not email: + return + if not os.path.exists(MAIL_BINARY): + logging.error(_("No '/usr/bin/mail', can not send mail. " + "You probably want to install the 'mailx' package.")) + return + # if the operation was successful and the user has requested to get + # mails on on errors, just exit here + if (res and + apt_pkg.config.find_b("Unattended-Upgrade::MailOnlyOnError", False)): + return + # Check if reboot-required flag is present + logging.debug("Sending mail with '%s' to '%s'" % (logfile_dpkg, email)) + if os.path.isfile(REBOOT_REQUIRED_FILE): + subject = _("[reboot required] unattended-upgrades result for '%s'") % host() + else: + subject = _("unattended-upgrades result for '%s'") % host() + mail = subprocess.Popen([MAIL_BINARY, "-s", subject, + email], stdin=subprocess.PIPE) + s = _("Unattended upgrade returned: %s\n\n") % res + if os.path.isfile(REBOOT_REQUIRED_FILE): + s += _("Warning: A reboot is required to complete this upgrade.\n\n") + s += _("Packages that are upgraded:\n") + s += " " + wrap(pkgs, 70, " ") + s += "\n" + if pkgs_kept_back: + s += _("Packages with upgradable origin but kept back:\n") + s += " " + wrap(" ".join(pkgs_kept_back), 70, " ") + s += "\n" + s += "\n" + if os.path.exists(logfile_dpkg): + s += _("Package installation log:")+"\n" + s += open(logfile_dpkg).read() + s += "\n\n" + s += _("Unattended-upgrades log:\n") + s += mem_log.getvalue() + mail.stdin.write(s) + mail.stdin.close() + ret = mail.wait() + logging.debug("mail returned: %s" % ret) + + +def do_install(cache, pkgs_to_upgrade, options, logfile_dpkg): + # set debconf to NON_INTERACTIVE, redirect output + os.putenv("DEBIAN_FRONTEND","noninteractive"); + setup_apt_listchanges() + + # redirect to log + REDIRECT_INPUT = os.devnull + fd = os.open(REDIRECT_INPUT, os.O_RDWR) + os.dup2(fd,0) + + logging.info(_("Writing dpkg log to '%s'") % logfile_dpkg) + + # do not create log in dry-run mode, just output to stdout/stderr + if options.dry_run: + old_stdout = 1 + old_stderr = 2 + else: + fd = os.open(logfile_dpkg, os.O_RDWR|os.O_CREAT, 0644) + old_stdout = os.dup(1) + old_stderr = os.dup(2) + os.dup2(fd,1) + os.dup2(fd,2) + + try: + if (options.minimal_upgrade_steps or + # COMPAT with the mispelling + apt_pkg.config.find_b("Unattended-Upgrades::MinimalSteps", False) or + apt_pkg.config.find_b("Unattended-Upgrade::MinimalSteps", False)): + open("/var/run/unattended-upgrades.pid", "w").write("%s" % os.getpid()) + # try upgrade all "pkgs" in minimal steps + pkg_install_success = upgrade_in_minimal_steps( + cache, [pkg.name for pkg in pkgs_to_upgrade], logfile_dpkg) + else: + pkg_install_success = upgrade_normal( + cache, [pkg.name for pkg in pkgs_to_upgrade], logfile_dpkg) + except Exception as e: + # print unhandled exceptions here this way, while stderr is redirected + os.write(old_stderr, "Exception: %s" % e) + + # restore + os.dup2(old_stdout, 1) + os.dup2(old_stderr, 2) + + return pkg_install_success + + +def _setup_alternative_rootdir(rootdir): + # clear system unattended-upgrade stuff + apt_pkg.config.clear("Unattended-Upgrade") + # read rootdir (taken from apt.Cache, but we need to run it + # here before the cache gets initialized + if os.path.exists(rootdir+"/etc/apt/apt.conf"): + apt_pkg.read_config_file(apt_pkg.config, + rootdir + "/etc/apt/apt.conf") + if os.path.isdir(rootdir+"/etc/apt/apt.conf.d"): + apt_pkg.read_config_dir(apt_pkg.config, + rootdir + "/etc/apt/apt.conf.d") + +def _get_logdir(): + logdir= apt_pkg.config.find_dir( + "Unattended-Upgrade::LogDir", + # COMPAT only + apt_pkg.config.find_dir("APT::UnattendedUpgrades::LogDir", + "/var/log/unattended-upgrades/")) + return logdir + +def _setup_logging(options): + # init the logging + logdir = _get_logdir() + logfile = os.path.join( + logdir, + apt_pkg.config.find( + "Unattended-Upgrade::LogFile", + # COMPAT only + apt_pkg.config.find("APT::UnattendedUpgrades::LogFile", + "unattended-upgrades.log"))) + + if not options.dry_run and not os.path.exists(os.path.dirname(logfile)): + os.makedirs(os.path.dirname(logfile)) + + logging.basicConfig(level=logging.INFO, + format='%(asctime)s %(levelname)s %(message)s', + filename=logfile) + + +def main(options, rootdir=""): + + # useful for testing + if rootdir: + _setup_alternative_rootdir(rootdir) + + _setup_logging(options) + + # setup logging + logger = logging.getLogger() + mem_log = StringIO() + if options.debug: + logger.setLevel(logging.DEBUG) + stderr_handler = logging.StreamHandler() + logger.addHandler(stderr_handler) + if apt_pkg.config.find("Unattended-Upgrade::Mail", ""): + mem_log_handler = logging.StreamHandler(mem_log) + logger.addHandler(mem_log_handler) + + # format (origin, archive), e.g. ("Ubuntu","dapper-security") + allowed_origins = get_allowed_origins() + + # pkgs that are (for some reason) not save to install + blacklisted_pkgs = apt_pkg.config.value_list("Unattended-Upgrade::Package-Blacklist") + logging.info(_("Initial blacklisted packages: %s"), " ".join(blacklisted_pkgs)) + logging.info(_("Starting unattended upgrades script")) + + # display available origin + logging.info(_("Allowed origins are: %s") % map(str,allowed_origins)) + + # check if the journal is dirty and if so, take emergceny action + # the alternative is to leave the system potentially unsecure until + # the user comes in and fixes + if (is_dpkg_journal_dirty() and + apt_pkg.config.find_b("Unattended-Upgrade::AutoFixInterruptedDpkg", True)): + # ensure the dpkg database is not already locked (LP: #754330) + admindir = os.path.dirname(apt_pkg.config.find("Dir::State::Status")) + lockfd = apt_pkg.get_lock(os.path.join(admindir, "lock"), False) + if lockfd > 0: + logging.warning(_("Unclean dpkg state detected, trying to correct")) + print _("Unclean dpkg state detected, trying to correct") + env = copy.copy(os.environ) + env["DEBIAN_FRONTEND"] = "noninteractive" + try: + os.close(lockfd) + output = subprocess.check_output( + ["dpkg", "--force-confold", "--configure", "-a"], env=env) + except subprocess.CalledProcessError as e: + output = e.output + logging.warning(_("dpkg --configure -a output:\n%s" % output)) + else: + logging.debug("Unclean dpkg state, but locked, another package manager working?") + + # check and get lock + try: + apt_pkg.pkgsystem_lock() + except SystemError, e: + logging.error(_("Lock could not be acquired (another package " + "manager running?)")) + print _("Cache lock can not be acquired, exiting") + sys.exit(1) + + # get a cache + cache = UnattendedUpgradesCache(rootdir=rootdir, + allowed_origins=allowed_origins) + if cache._depcache.broken_count > 0: + print _("Cache has broken packages, exiting") + logging.error(_("Cache has broken packages, exiting")) + sys.exit(1) + # speed things up with latest apt + actiongroup = apt_pkg.ActionGroup(cache._depcache) + + # find out about the packages that are upgradable (in a allowed_origin) + pkgs_to_upgrade = [] + pkgs_kept_back = [] + pkgs_auto_removable = set([pkg.name for pkg in cache + if pkg.is_auto_removable]) + + # now do the actual upgrade + for pkg in cache: + if options.debug and pkg.is_upgradable: + logging.debug("Checking: %s (%s)" % (pkg.name, map(str, pkg.candidate.origins))) + if (pkg.is_upgradable and + is_allowed_origin(pkg.candidate, allowed_origins)): + try: + pkg.mark_upgrade() + if check_changes_for_sanity(cache, allowed_origins, + blacklisted_pkgs): + # add to packages to upgrade + pkgs_to_upgrade.append(pkg) + # re-eval pkgs_kept_back as the resolver may fail to + # directly upgrade a pkg, but that may work during + # a subsequent operation, see debian bug #639840 + for pkgname in pkgs_kept_back: + if (cache[pkgname].marked_install or + cache[pkgname].marked_upgrade): + pkgs_kept_back.remove(pkgname) + pkgs_to_upgrade.append(cache[pkgname]) + else: + logging.debug("sanity check failed") + rewind_cache(cache, pkgs_to_upgrade) + pkgs_kept_back.append(pkg.name) + except SystemError, e: + # can't upgrade + logging.warning(_("package '%s' upgradable but fails to be marked for upgrade (%s)") % (pkg.name, e)) + rewind_cache(cache, pkgs_to_upgrade) + pkgs_kept_back.append(pkg.name) + + + pkgs_to_upgrade.sort(key=lambda p: p.name) + pkgs = "\n".join([pkg.name for pkg in pkgs_to_upgrade]) + logging.debug("pkgs that look like they should be upgraded: %s" % pkgs) + + # download what looks good + if options.debug: + fetcher = apt_pkg.Acquire(apt.progress.text.AcquireProgress()) + else: + fetcher = apt_pkg.Acquire() + list = apt_pkg.SourceList() + list.read_main_list() + recs = cache._records + pm = apt_pkg.PackageManager(cache._depcache) + try: + pm.get_archives(fetcher,list,recs) + except SystemError, e: + logging.error(_("GetArchives() failed: '%s'") % e) + res = fetcher.run() + + if dpkg_conffile_prompt(): + # now check the downloaded debs for conffile conflicts and build + # a blacklist + for item in fetcher.items: + logging.debug("%s" % item) + if item.status == item.STAT_ERROR: + print _("An error ocured: '%s'") % item.error_text + logging.error(_("An error ocured: '%s'") % item.error_text) + if not item.complete: + print _("The URI '%s' failed to download, aborting") % item.desc_uri + logging.error(_("The URI '%s' failed to download, aborting") % item.desc_uri) + sys.exit(1) + if not os.path.exists(item.destfile): + print _("Download finished, but file '%s' not there?!?" % item.destfile) + logging.error("Download finished, but file '%s' not there?!?" % item.destfile) + sys.exit(1) + if not item.is_trusted: + blacklisted_pkgs.append(pkgname_from_deb(item.destfile)) + if conffile_prompt(item.destfile): + # skip package (means to re-run the whole marking again + # and making sure that the package will not be pulled in by + # some other package again!) + # + # print to stdout to ensure that this message is part of + # the cron mail + print _("Package '%s' has conffile prompt and needs to be upgraded manually") % pkgname_from_deb(item.destfile) + # log to the logfile + logging.warning(_("Package '%s' has conffile prompt and needs to be upgraded manually") % pkgname_from_deb(item.destfile)) + blacklisted_pkgs.append(pkgname_from_deb(item.destfile)) + pkgs_kept_back.append(pkgname_from_deb(item.destfile)) + + + # redo the selection about the packages to upgrade based on the new + # blacklist + logging.debug("blacklist: %s" % blacklisted_pkgs) + # find out about the packages that are upgradable (in a allowed_origin) + if len(blacklisted_pkgs) > 0: + cache.clear() + old_pkgs_to_upgrade = pkgs_to_upgrade[:] + pkgs_to_upgrade = [] + for pkg in old_pkgs_to_upgrade: + logging.debug("Checking (blacklist): %s" % (pkg.name)) + pkg.mark_upgrade() + if check_changes_for_sanity(cache, allowed_origins, + blacklisted_pkgs): + pkgs_to_upgrade.append(pkg) + else: + if not (pkg.name in pkgs_kept_back): + pkgs_kept_back.append(pkg.name) + logging.info(_("package '%s' not upgraded") % pkg.name) + cache.clear() + for pkg2 in pkgs_to_upgrade: + pkg2.mark_upgrade() + else: + logging.debug("dpkg is configured not to cause conffile prompts") + + # do auto-remove + if apt_pkg.config.find_b("Unattended-Upgrade::Remove-Unused-Dependencies", False): + now_auto_removable = set([pkg.name for pkg in cache + if pkg.is_auto_removable]) + for pkgname in now_auto_removable-pkgs_auto_removable: + logging.debug("marking %s for remove" % pkgname) + cache[pkgname].mark_delete() + logging.info(_("Packages that are auto removed: '%s'") % + " ".join(now_auto_removable-pkgs_auto_removable)) + + logging.debug("InstCount=%i DelCount=%i BrokenCout=%i" % (cache._depcache.inst_count, cache._depcache.del_count, cache._depcache.broken_count)) + + # exit if there is nothing to do and nothing to report + if (len(pkgs_to_upgrade) == 0) and (len(pkgs_kept_back) == 0): + logging.info(_("No packages found that can be upgraded unattended")) + return + + # check if its configured for install on shutdown, if so, the + # environment UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN will + # be set by the unatteded-upgrades-shutdown script + if (not "UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN" in os.environ and + apt_pkg.config.find_b("Unattended-Upgrade::InstallOnShutdown", False)): + logger.debug("Configured to install on shutdown, so exiting now") + return + + # check if we are in dry-run mode + if options.dry_run: + logging.info("Option --dry-run given, *not* performing real actions") + apt_pkg.config.set("Debug::pkgDPkgPM","1") + + # do the install based on the new list of pkgs + pkgs = " ".join([pkg.name for pkg in pkgs_to_upgrade]) + logging.info(_("Packages that are upgraded: %s" % pkgs)) + + # get log + now = datetime.datetime.now() + logfile_dpkg = os.path.join( + _get_logdir(), 'unattended-upgrades-dpkg_%s.log' % now.isoformat('_')) + + # only perform install step if we actually have packages to install + pkg_install_success = None + 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, options, logfile_dpkg) + + # send a mail (if needed) + if not options.dry_run: + send_summary_mail( + pkgs, pkg_install_success, pkgs_kept_back, mem_log, logfile_dpkg) + + # auto-reboot (if required and the config for this is set + if (apt_pkg.config.find_b("Unattended-Upgrade::Automatic-Reboot", False) and + os.path.exists(REBOOT_REQUIRED_FILE)): + if shutdown_lock > 0: + os.close(shutdown_lock) + logging.warning("Found %s, rebooting" % REBOOT_REQUIRED_FILE) + subprocess.call(["/sbin/reboot"]) + + +if __name__ == "__main__": + localesApp="unattended-upgrades" + localesDir="/usr/share/locale" + gettext.bindtextdomain(localesApp, localesDir) + gettext.textdomain(localesApp) + + # init the options + parser = OptionParser() + parser.add_option("-d", "--debug", + action="store_true", dest="debug", default=False, + help=_("print debug messages")) + parser.add_option("", "--dry-run", + action="store_true", default=False, + help=_("Simulation, download but do not install")) + parser.add_option("", "--minimal_upgrade_steps", + action="store_true", default=False, + help=_("Upgrade in minimal steps (and allow interrupting with SIGINT")) + (options, args) = parser.parse_args() + + if os.getuid() != 0: + print _("You need to be root to run this application") + sys.exit(1) + + # nice & ionce + os.nice(19) + subprocess.call(["ionice","-c3", "-p",str(os.getpid())]) + + # run the main code + main(options) diff -Nru unattended-upgrades-0.55ubuntu3/tests/create_debug_lock.py unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/tests/create_debug_lock.py --- unattended-upgrades-0.55ubuntu3/tests/create_debug_lock.py 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/tests/create_debug_lock.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -#!/usr/bin/python -# -# create a lock file so that unattended-upgrades-shutdown pauses -# on shutdown -- useful for testing - -import apt_pkg -import os -import time - -pid = os.fork() -if pid == 0: - os.setsid() - lock = apt_pkg.GetLock("/var/run/unattended-upgrades.lock") - time.sleep(500) diff -Nru unattended-upgrades-0.55ubuntu3/tests/etc/configuration-file unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/tests/etc/configuration-file --- unattended-upgrades-0.55ubuntu3/tests/etc/configuration-file 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/tests/etc/configuration-file 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -This is a configuration file, -dfasddfasdff -No really. Binary files /tmp/vBk4ErTvGJ/unattended-upgrades-0.55ubuntu3/tests/packages/conf-test-package_1.0.deb and /tmp/jYeRZNsOgz/unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/tests/packages/conf-test-package_1.0.deb differ Binary files /tmp/vBk4ErTvGJ/unattended-upgrades-0.55ubuntu3/tests/packages/conf-test-package_1.1.deb and /tmp/jYeRZNsOgz/unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/tests/packages/conf-test-package_1.1.deb differ diff -Nru unattended-upgrades-0.55ubuntu3/tests/test_conffile.py unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/tests/test_conffile.py --- unattended-upgrades-0.55ubuntu3/tests/test_conffile.py 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/tests/test_conffile.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -#!/usr/bin/python - -import apt_pkg -import logging -import unittest -import sys - -from unattended_upgrade import conffile_prompt - -class TestConffilePrompt(unittest.TestCase): - def setUp(self): - apt_pkg.Config.Set("Dir::State::status", "./var/lib/dpkg/status") - - def testWillPrompt(self): - # conf-test 0.9 is installed, 1.1 gets installed - # they both have different config files - test_pkg = "./packages/conf-test-package_1.1.deb" - self.assertTrue(conffile_prompt(test_pkg, prefix="./"), - "conffile prompt detection incorrect") - - def testWillNotPrompt(self): - # conf-test 0.9 is installed, 1.0 gets installed - # they both have the same config files - test_pkg = "./packages/conf-test-package_1.0.deb" - self.assertFalse(conffile_prompt(test_pkg, prefix="./"), - "conffile prompt detection incorrect") - - -if __name__ == "__main__": - logging.basicConfig(level=logging.DEBUG) - unittest.main() - diff -Nru unattended-upgrades-0.55ubuntu3/tests/unattended_upgrade.py unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/tests/unattended_upgrade.py --- unattended-upgrades-0.55ubuntu3/tests/unattended_upgrade.py 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/tests/unattended_upgrade.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,490 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2005-2009 Canonical Ltd -# -# AUTHOR: -# Michael Vogt -# -# This file is part of unattended-upgrades -# -# unattended-upgrades 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. -# -# unattended-upgrades 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 unattended-upgrades; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# - -import apt_inst -import apt_pkg - -import sys -import os -import string -import datetime -import ConfigParser - -from StringIO import StringIO -from optparse import OptionParser -from subprocess import Popen, PIPE - -import warnings -warnings.filterwarnings("ignore", "apt API not stable yet", FutureWarning) -import apt -import logging -import subprocess - -import gettext -from gettext import gettext as _ - -class MyCache(apt.Cache): - def __init__(self): - apt.Cache.__init__(self) - def clear(self): - self._depcache.Init() - assert (self._depcache.InstCount == 0 and - self._depcache.BrokenCount == 0 and - self._depcache.DelCount == 0) - - -def is_allowed_origin(pkg, allowed_origins): - if not pkg.candidate: - return False - for origin in pkg.candidate.origins: - for allowed in allowed_origins: - if origin.origin == allowed[0] and origin.archive == allowed[1]: - return True - return False - -def check_changes_for_sanity(cache, allowed_origins, blacklist): - if cache._depcache.BrokenCount != 0: - return False - for pkg in cache: - if pkg.markedDelete: - logging.debug("pkg '%s' now marked delete" % pkg.name) - return False - if pkg.markedInstall or pkg.markedUpgrade: - if not is_allowed_origin(pkg, allowed_origins): - logging.debug("pkg '%s' not in allowed origin" % pkg.name) - return False - if pkg.name in blacklist: - logging.debug("pkg '%s' blacklisted" % pkg.name) - return False - if pkg._pkg.SelectedState == apt_pkg.SelStateHold: - logging.debug("pkg '%s' is on hold" % pkg.name) - return False - return True - -def pkgname_from_deb(debfile): - # FIXME: add error checking here - try: - control = apt_inst.debExtractControl(open(debfile)) - sections = apt_pkg.ParseSection(control) - return sections["Package"] - except (IOError, SystemError), e: - logging.error("failed to read deb file '%s' (%s)" % (debfile, e)) - # dumb fallback - return debfile.split("_")[0] - -# prefix is *only* needed for the build-in tests -def conffile_prompt(destFile, prefix=""): - logging.debug("check_conffile_prompt('%s')" % destFile) - pkgname = pkgname_from_deb(destFile) - status_file = apt_pkg.Config.Find("Dir::State::status") - parse = apt_pkg.ParseTagFile(open(status_file,"r")) - while parse.Step() == 1: - if parse.Section.get("Package") == pkgname: - logging.debug("found pkg: %s" % pkgname) - if parse.Section.has_key("Conffiles"): - conffiles = parse.Section.get("Conffiles") - # Conffiles: - # /etc/bash_completion.d/m-a c7780fab6b14d75ca54e11e992a6c11c - for line in string.split(conffiles,"\n"): - logging.debug("conffile line: %s", line) - l = string.split(string.strip(line)) - conf_file = l[0] - md5 = l[1] - if len(l) > 2: - obs = l[2] - else: - obs = None - # ignore if conffile is obsolete or does not exist - if obs == "obsolete" or not os.path.exists(prefix+conf_file): - continue - # get conffile value from pkg - pkg_conffiles = apt_inst.debExtractControl( - open(destFile), "conffiles").split("\n") - if not conf_file in pkg_conffiles: - logging.debug("'%s' not in package conffiles '%s'" % (conf_file, pkg_conffiles)) - continue - # test against the installed file - current_md5 = apt_pkg.md5sum(open(prefix+conf_file).read()) - logging.debug("current md5: %s" % current_md5) - # hashes are the same, no conffile prompt - if current_md5 == md5: - return False - # calculate md5sum from the deb (may take a bit) - dpkg_cmd = ["dpkg-deb","--fsys-tarfile",destFile] - tar_cmd = ["tar","-x","-O", "-f","-", "."+conf_file] - md5_cmd = ["md5sum"] - dpkg_p = Popen(dpkg_cmd, stdout=PIPE) - tar_p = Popen(tar_cmd, stdin=dpkg_p.stdout, stdout=PIPE) - md5_p = Popen(md5_cmd, stdin=tar_p.stdout, stdout=PIPE) - pkg_md5sum = md5_p.communicate()[0].split()[0] - logging.debug("pkg_md5sum: %s" % pkg_md5sum) - # the md5sum in the deb is unchanged, this will not - # trigger a conffile prompt - if pkg_md5sum == md5: - continue - # if we made it to this point: - # current_md5 != pkg_md5sum != md5 - # and that will trigger a conffile prompt, we can - # stop processing at this point and just return True - return True - return False - - -def dpkg_conffile_prompt(): - if not apt_pkg.Config.has_key("DPkg::Options"): - return True - options = apt_pkg.Config.ValueList("DPkg::Options") - for option in map(string.strip, options): - if (option == "--force-confold" or - option == "--force-confnew"): - return False - return True - -def rewind_cache(cache, pkgs_to_upgrade): - " set the cache back to the state with packages_to_upgrade " - cache.clear() - for pkg2 in pkgs_to_upgrade: - pkg2.markUpgrade() - -def host(): - return os.uname()[1] - -# *sigh* textwrap is nice, but it breaks "linux-image" into two -# seperate lines -def wrap(t, width=70, subsequent_indent=""): - out = "" - for s in t.split(): - if (len(out)-out.rfind("\n")) + len(s) > width: - out += "\n" + subsequent_indent - out += s + " " - return out - -def setup_apt_listchanges(): - " deal with apt-listchanges " - conf = "/etc/apt/listchanges.conf" - if os.path.exists(conf): - # check if mail is used by apt-listchanges - cf = ConfigParser.ConfigParser() - cf.read(conf) - if cf.has_section("apt") and cf.has_option("apt","frontend"): - frontend = cf.get("apt","frontend") - if frontend == "mail" and os.path.exists("/usr/sbin/sendmail"): - # mail frontend and sendmail, we are fine - logging.debug("apt-listchanges is set to mail frontend, ignoring") - return - # setup env (to play it safe) and return - os.putenv("APT_LISTCHANGES_FRONTEND","none"); - -def send_summary_mail(pkgs, res, pkgs_kept_back, mem_log, logfile_dpkg): - " send mail (if configured in Unattended-Upgrades::Mail) " - email = apt_pkg.Config.Find("Unattended-Upgrade::Mail", "") - if not email: - return - if not os.path.exists("/usr/bin/mail"): - logging.error(_("No '/usr/bin/mail', can not send mail. " - "You probably want to install the 'mailx' package.")) - return - logging.debug("Sending mail with '%s' to '%s'" % (logfile_dpkg, email)) - mail = subprocess.Popen(["/usr/bin/mail", - "-s", _("unattended-upgrades result " - "for '%s'") % host(), - email], - stdin=subprocess.PIPE) - s = _("Unattended upgrade returned: %s\n\n") % res - s += _("Packages that are upgraded:\n") - s += " " + wrap(pkgs, 70, " ") - s += "\n" - if pkgs_kept_back: - s += _("Packages with upgradable origin but kept back:\n") - s += " " + wrap(" ".join(pkgs_kept_back), 70, " ") - s += "\n" - s += "\n" - s += _("Package installation log:")+"\n" - s += open(logfile_dpkg).read() - s += "\n\n" - s += _("Unattended-upgrades log:\n") - s += mem_log.getvalue() - mail.stdin.write(s) - mail.stdin.close() - ret = mail.wait() - logging.debug("mail returned: %s" % ret) - - -def main(): - # init the options - parser = OptionParser() - parser.add_option("-d", "--debug", - action="store_true", dest="debug", default=False, - help=_("print debug messages")) - parser.add_option("", "--dry-run", - action="store_true", default=False, - help=_("Simulation, download but do not install")) - (options, args) = parser.parse_args() - - # setup logging - logger = logging.getLogger() - mem_log = StringIO() - if options.debug: - logger.setLevel(logging.DEBUG) - stderr_handler = logging.StreamHandler() - logger.addHandler(stderr_handler) - if apt_pkg.Config.Find("Unattended-Upgrade::Mail", ""): - mem_log_handler = logging.StreamHandler(mem_log) - logger.addHandler(mem_log_handler) - - # format (origin, archive), e.g. ("Ubuntu","dapper-security") - allowed_origins = map(string.split, apt_pkg.Config.ValueList("Unattended-Upgrade::Allowed-Origins")) - - # pkgs that are (for some reason) not save to install - blacklisted_pkgs = apt_pkg.Config.ValueList("Unattended-Upgrade::Package-Blacklist") - logging.info(_("Initial blacklisted packages: %s"), " ".join(blacklisted_pkgs)) - logging.info(_("Starting unattended upgrades script")) - - # display available origin - logging.info(_("Allowed origins are: %s") % map(str,allowed_origins)) - - # check and get lock - try: - apt_pkg.PkgSystemLock() - except SystemError, e: - logging.error(_("Lock could not be acquired (another package " - "manager running?)")) - print _("Cache lock can not be acquired, exiting") - sys.exit(1) - - # get a cache - cache = MyCache() - if cache._depcache.BrokenCount > 0: - print _("Cache has broken packages, exiting") - logging.error(_("Cache has broken packages, exiting")) - sys.exit(1) - # speed things up with latest apt - actiongroup = apt_pkg.GetPkgActionGroup(cache._depcache) - - # find out about the packages that are upgradable (in a allowed_origin) - pkgs_to_upgrade = [] - pkgs_kept_back = [] - pkgs_auto_removable = set([pkg.name for pkg in cache - if pkg.isAutoRemovable]) - for pkg in cache: - if options.debug and pkg.isUpgradable: - logging.debug("Checking: %s (%s)" % (pkg.name, map(str, pkg.candidate.origins))) - if (pkg.isUpgradable and - is_allowed_origin(pkg,allowed_origins)): - try: - pkg.markUpgrade() - if check_changes_for_sanity(cache, allowed_origins, - blacklisted_pkgs): - pkgs_to_upgrade.append(pkg) - else: - logging.debug("sanity check failed") - rewind_cache(cache, pkgs_to_upgrade) - pkgs_kept_back.append(pkg.name) - except SystemError, e: - # can't upgrade - logging.warning(_("package '%s' upgradable but fails to be marked for upgrade (%s)") % (pkg.name, e)) - rewind_cache(cache, pkgs_to_ugprade) - pkgs_kept_back.append(pkg.name) - - - pkgs = "\n".join([pkg.name for pkg in pkgs_to_upgrade]) - logging.debug("pkgs that look like they should be upgraded: %s" % pkgs) - - # download what looks good - if options.debug: - fetcher = apt_pkg.GetAcquire(apt.progress.TextFetchProgress()) - else: - fetcher = apt_pkg.GetAcquire() - list = apt_pkg.GetPkgSourceList() - list.ReadMainList() - recs = cache._records - pm = apt_pkg.GetPackageManager(cache._depcache) - try: - pm.GetArchives(fetcher,list,recs) - except SystemError, e: - logging.error(_("GetArchives() failed: '%s'") % e) - res = fetcher.Run() - - if dpkg_conffile_prompt(): - # now check the downloaded debs for conffile conflicts and build - # a blacklist - for item in fetcher.Items: - logging.debug("%s" % item) - if item.Status == item.StatError: - print _("An error ocured: '%s'") % item.ErrorText - logging.error(_("An error ocured: '%s'") % item.ErrorText) - if item.Complete == False: - print _("The URI '%s' failed to download, aborting") % item.DescURI - logging.error(_("The URI '%s' failed to download, aborting") % item.DescURI) - sys.exit(1) - if not os.path.exists(item.DestFile): - print _("Download finished, but file '%s' not there?!?" % item.DestFile) - logging.error("Download finished, but file '%s' not there?!?" % item.DestFile) - sys.exit(1) - if item.IsTrusted == False: - blacklisted_pkgs.append(pkgname_from_deb(item.DestFile)) - if conffile_prompt(item.DestFile): - # FIXME: skip package (means to re-run the whole marking again - # and making sure that the package will not be pulled in by - # some other package again! - logging.warning(_("Package '%s' has conffile prompt and needs to be upgraded manually") % pkgname_from_deb(item.DestFile)) - blacklisted_pkgs.append(pkgname_from_deb(item.DestFile)) - pkgs_kept_back.append(pkgname_from_deb(item.DestFile)) - - - # redo the selection about the packages to upgrade based on the new - # blacklist - logging.debug("blacklist: %s" % blacklisted_pkgs) - # find out about the packages that are upgradable (in a allowed_origin) - if len(blacklisted_pkgs) > 0: - cache.clear() - old_pkgs_to_upgrade = pkgs_to_upgrade[:] - pkgs_to_upgrade = [] - for pkg in old_pkgs_to_upgrade: - logging.debug("Checking (blacklist): %s" % (pkg.name)) - pkg.markUpgrade() - if check_changes_for_sanity(cache, allowed_origins, - blacklisted_pkgs): - pkgs_to_upgrade.append(pkg) - else: - if not (pkg.name in pkgs_kept_back): - pkgs_kept_back.append(pkg.name) - logging.info(_("package '%s' not upgraded") % pkg.name) - cache.clear() - for pkg2 in pkgs_to_upgrade: - pkg2.markUpgrade() - else: - logging.debug("dpkg is configured not to cause conffile prompts") - - # do auto-remove - if apt_pkg.Config.FindB("Unattended-Upgrade::Remove-Unused-Dependencies", False): - now_auto_removable = set([pkg.name for pkg in cache - if pkg.isAutoRemovable]) - for pkgname in now_auto_removable-pkgs_auto_removable: - logging.debug("marking %s for remove" % pkgname) - cache[pkgname].markDelete() - logging.info(_("Packages that are auto removed: '%s'") % - " ".join(now_auto_removable-pkgs_auto_removable)) - - logging.debug("InstCount=%i DelCount=%i BrokenCout=%i" % (cache._depcache.InstCount, cache._depcache.DelCount, cache._depcache.BrokenCount)) - - # exit if there is nothing to do and nothing to report - if (len(pkgs_to_upgrade) == 0) and (len(pkgs_kept_back) == 0): - logging.info(_("No packages found that can be upgraded unattended")) - sys.exit(0) - - # check if we are in dry-run mode - if options.dry_run: - logging.info("Option --dry-run given, *not* performing real actions") - apt_pkg.Config.Set("Debug::pkgDPkgPM","1") - - # do the install based on the new list of pkgs - pkgs = " ".join([pkg.name for pkg in pkgs_to_upgrade]) - logging.info(_("Packages that are upgraded: %s" % pkgs)) - - # set debconf to NON_INTERACTIVE, redirect output - os.putenv("DEBIAN_FRONTEND","noninteractive"); - setup_apt_listchanges() - - # redirect to log - REDIRECT_INPUT = os.devnull - fd = os.open(REDIRECT_INPUT, os.O_RDWR) - os.dup2(fd,0) - - now = datetime.datetime.now() - logfile_dpkg = logdir+'unattended-upgrades-dpkg_%s.log' % now.isoformat('_') - logging.info(_("Writing dpkg log to '%s'") % logfile_dpkg) - fd = os.open(logfile_dpkg, os.O_RDWR|os.O_CREAT, 0644) - old_stdout = os.dup(1) - old_stderr = os.dup(2) - os.dup2(fd,1) - os.dup2(fd,2) - - # create a new package-manager. the blacklist may have changed - # the markings in the depcache - pm = apt_pkg.GetPackageManager(cache._depcache) - if not pm.GetArchives(fetcher,list,recs): - logging.error(_("pm.GetArchives() failed")) - # run the fetcher again (otherwise local file:// - # URIs are unhappy (see LP: #56832) - res = fetcher.Run() - # unlock the cache - try: - apt_pkg.PkgSystemUnLock() - except SystemError, e: - pass - # lock for the shutdown check - its fine if the system - # is shutdown while downloading but not so much while installing - apt_pkg.GetLock("/var/run/unattended-upgrades.lock") - # now do the actual install - error = None - try: - res = pm.DoInstall() - except SystemError,e: - error = e - res = pm.ResultFailed - finally: - os.dup2(old_stdout, 1) - os.dup2(old_stderr, 2) - - if res == pm.ResultFailed: - logging.error(_("Installing the upgrades failed!")) - logging.error(_("error message: '%s'") % e) - logging.error(_("dpkg returned a error! See '%s' for details") % logfile_dpkg) - else: - logging.info(_("All upgrades installed")) - - # send a mail (if needed) - pkg_install_success = (res != pm.ResultFailed) - send_summary_mail(pkgs, pkg_install_success, pkgs_kept_back, mem_log, logfile_dpkg) - - # auto-reboot (if required and the config for this is set - if (apt_pkg.Config.FindB("Unattended-Upgrade::Automatic-Reboot", False) and - os.path.exists("/var/run/reboot-required")): - logging.warning("Found /var/run/reboot-required, rebooting") - subprocess.call(["/sbin/reboot"]) - - -if __name__ == "__main__": - localesApp="unattended-upgrades" - localesDir="/usr/share/locale" - gettext.bindtextdomain(localesApp, localesDir) - gettext.textdomain(localesApp) - - if os.getuid() != 0: - print _("You need to be root to run this application") - sys.exit(1) - - if not os.path.exists("/var/log/unattended-upgrades"): - os.makedirs("/var/log/unattended-upgrades") - - # init the logging - logdir = apt_pkg.Config.FindDir("APT::UnattendedUpgrades::LogDir", - "/var/log/unattended-upgrades/") - logfile = logdir+apt_pkg.Config.Find("APT::UnattendedUpgrades::LogFile", - "unattended-upgrades.log") - logging.basicConfig(level=logging.INFO, - format='%(asctime)s %(levelname)s %(message)s', - filename=logfile) - # run the main code - main() diff -Nru unattended-upgrades-0.55ubuntu3/tests/var/lib/dpkg/status unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/tests/var/lib/dpkg/status --- unattended-upgrades-0.55ubuntu3/tests/var/lib/dpkg/status 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/tests/var/lib/dpkg/status 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -Package: test-package -Status: install ok installed -Architecture: all -Version: 0.9 -Conffiles: - /etc/not-available-config-file 99b99d59ac8f5ecd3375107755ee8599 - /etc/configuration-file 26b99d59ac8f5ecd3375107755ee8527 - /etc/not-available-config-file2 88b99d59ac8f5ecd3375107755ee8588 diff -Nru unattended-upgrades-0.55ubuntu3/unattended-upgrade unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/unattended-upgrade --- unattended-upgrades-0.55ubuntu3/unattended-upgrade 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/unattended-upgrade 2012-11-08 19:52:23.000000000 +0000 @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright (c) 2005-2009 Canonical Ltd +# Copyright (c) 2005-2010 Canonical Ltd # # AUTHOR: # Michael Vogt @@ -24,11 +24,14 @@ import apt_inst import apt_pkg -import sys +import ConfigParser +import copy +import datetime +import fcntl +import re import os import string -import datetime -import ConfigParser +import sys from StringIO import StringIO from optparse import OptionParser @@ -38,54 +41,345 @@ warnings.filterwarnings("ignore", "apt API not stable yet", FutureWarning) import apt import logging +import lsb_release +import signal import subprocess import gettext from gettext import gettext as _ -class MyCache(apt.Cache): - def __init__(self): - apt.Cache.__init__(self) +# the reboot required flag file used by packages +REBOOT_REQUIRED_FILE = "/var/run/reboot-required" +MAIL_BINARY = "/usr/bin/mail" +SENDMAIL_BINARY = "/usr/sbin/sendmail" +DISTRO_CODENAME = lsb_release.get_distro_information()['CODENAME'] +DISTRO_ID = lsb_release.get_distro_information()['ID'] + +# progress information is written here +PROGRESS_LOG="/var/run/unattended-upgrades.progress" + +# set from the sigint signal handler +SIGNAL_STOP_REQUEST=False + +class UnattendedUpgradesCache(apt.Cache): + + def __init__(self, rootdir, allowed_origins): + apt.Cache.__init__(self, rootdir=rootdir) + self.allowed_origins = allowed_origins + # ensure we update the candidate versions + self.adjust_candidate_versions() def clear(self): - self._depcache.Init() - assert (self._depcache.InstCount == 0 and - self._depcache.BrokenCount == 0 and - self._depcache.DelCount == 0) + apt.Cache.clear(self) + # ensure we update the candidate versions + self.adjust_candidate_versions() + def adjust_candidate_versions(self): + """ Adjust candidate versions to match highest allowed origin + This adjusts the origin even if the candidate has a higher + version + """ + for pkg in self: + # important! this avoids downgrades below + if not pkg.is_upgradable: + continue + # check if we have a version in a allowed origin that is + # not the candidate + new_cand = None + for ver in pkg.versions: + if is_allowed_origin(ver, self.allowed_origins): + # leave as soon as we have the highest new candidate + new_cand = ver + break + if new_cand and new_cand != pkg.candidate: + logging.debug("adjusting candidate version: '%s'" % new_cand) + pkg.candidate = new_cand + + +class LogInstallProgress(apt.progress.base.InstallProgress): + """ Install progress that writes to self.LOG + (/var/run/unattended-upgrades.progress by default) + """ + + LOG = PROGRESS_LOG + + def status_change(self, pkg, percent, status): + f=open(self.LOG, "w") + f.write(_("Progress: %s %% (%s)") % (percent, pkg)) + f.close() + + def _fixup_fds(self): + required_fds = [ 0, 1, 2, # stdin, stdout, stderr + self.writefd, + self.write_stream.fileno(), + self.statusfd, + self.status_stream.fileno() + ] + # ensure that our required fds close on exec + for fd in required_fds[3:]: + old_flags = fcntl.fcntl(fd, fcntl.F_GETFD) + fcntl.fcntl(fd, fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC) + # close all fds + proc_fd = "/proc/self/fd" + if os.path.exists(proc_fd): + error_count = 0 + for fdname in os.listdir(proc_fd): + try: + fd = int(fdname) + except Exception as e: + print "ERROR: can not get fd for '%s'" % fdname + if fd in required_fds: + continue + try: + os.close(fd) + #print "closed: ", fd + except OSError as e: + # there will be one fd that can not be closed + # as its the fd from pythons internal diropen() + # so its ok to ignore one close error + error_count += 1 + if error_count > 1: + print "ERROR: os.close(%s): %s" % (fd, e) + + def fork(self): + pid = os.fork() + if pid == 0: + self._fixup_fds() + return pid + + +class Unlocked: + """ context manager for unlocking the apt lock while cache.commit() + is run + """ + def __enter__(self): + try: + apt_pkg.pkgsystem_unlock() + except: + pass + def __exit__(self, exc_type, exc_value, exc_tb): + try: + apt_pkg.pkgsystem_unlock() + except: + pass + +def is_dpkg_journal_dirty(): + """ + test if the dpkg journal is dirty + (similar to debSystem::CheckUpdates) + """ + d = os.path.dirname( + apt_pkg.config.find_file("Dir::State::status"))+"/updates" + for f in os.listdir(d): + if re.match("[0-9]+", f): + return True + return False + +def signal_handler(signal, frame): + logging.warn("SIGUSR1 recieved, will stop") + global SIGNAL_STOP_REQUEST + SIGNAL_STOP_REQUEST=True + +def substitute(line): + """ substitude known mappings and return a new string + + Currently supported ${distro-release} + """ + mapping = {"distro_codename" : get_distro_codename(), + "distro_id" : get_distro_id(), + } + return string.Template(line).substitute(mapping) + +def get_distro_codename(): + return DISTRO_CODENAME + +def get_distro_id(): + return DISTRO_ID + +def get_allowed_origins_legacy(): + """ legacy support for old Allowed-Origins var """ + allowed_origins = [] + for s in apt_pkg.config.value_list("Unattended-Upgrade::Allowed-Origins"): + # if there is a ":" use that as seperator, else use spaces + if ":" in s: + (distro_id, distro_codename) = s.split(':') + else: + (distro_id, distro_codename) = s.split() + # escape "," (see LP: #824856) - i wonder if there is a simpler way? + distro_id = re.sub(r'([^\\]),', r'\1\\,', distro_id) + distro_codename = re.sub(r'([^\\]),', r'\1\\,', distro_codename) + # convert to new format + allowed_origins.append("o=%s,a=%s" % (substitute(distro_id), + substitute(distro_codename))) + return allowed_origins + +def get_allowed_origins(): + """ return a list of allowed origins from apt.conf + + This will take substitutions (like distro_id) into account. + """ + allowed_origins = get_allowed_origins_legacy() + for s in apt_pkg.config.value_list("Unattended-Upgrade::Origins-Pattern"): + allowed_origins.append(substitute(s)) + return allowed_origins + +def match_whitelist_string(whitelist, origin): + """ + take a whitelist string in the form "origin=Debian,label=Debian-Security" + and match against the given python-apt origin. A empty whitelist string + never matches anything. + """ + whitelist = whitelist.strip() + if whitelist == "": + logging.warn("empty match string matches nothing") + return False + res = True + # make "\," the html quote equivalent + whitelist = whitelist.replace("\,", "%2C") + for token in whitelist.split(","): + # strip and unquote the "," back + (what, value) = [s.strip().replace("%2C",",") + for s in token.split("=")] + #logging.debug("matching '%s'='%s' against '%s'" % (what, value, origin)) + # first char is apt-cache policy output, send is the name + # in the Release file + if what in ("o", "origin"): + res &= (value == origin.origin) + elif what in ("l", "label"): + res &= (value == origin.label) + elif what in ("a", "suite", "archive"): + res &= (value == origin.archive) + elif what in ("c", "component"): + res &= (value == origin.component) + elif what in ("site",): + res &= (value == origin.site) + return res + +def upgrade_normal(cache, pkgs_to_upgrade, logfile_dpkg): + error = None + res = False + iprogress = LogInstallProgress() + try: + with Unlocked(): + res = cache.commit(install_progress=iprogress) + except SystemError,e: + error = e + if res: + logging.info(_("All upgrades installed")) + else: + logging.error(_("Installing the upgrades failed!")) + logging.error(_("error message: '%s'") % error) + logging.error(_("dpkg returned a error! See '%s' for details") % \ + logfile_dpkg) + return res + +def upgrade_in_minimal_steps(cache, pkgs_to_upgrade, logfile_dpkg=""): + + install_log = LogInstallProgress() + install_log.LOG += ".minimal-steps" + + # setup signal handler + signal.signal(signal.SIGUSR1, signal_handler) + + # to upgrade contains the package names + to_upgrade = set(pkgs_to_upgrade) + while True: + # find smallest set + smallest_partition = to_upgrade + for pkgname in to_upgrade: + if SIGNAL_STOP_REQUEST: + logging.warn("SIGNAL recieved, stopping") + return True + pkg = cache[pkgname] + if pkg.is_upgradable: + pkg.mark_upgrade() + elif not pkg.is_installed: + pkg.mark_install() + else: + continue + changes = [pkg.name for pkg in cache.get_changes()] + if len(changes) == 1: + logging.debug("found leaf package %s" % pkg.name) + smallest_partition = changes + break + if len(changes) < len(smallest_partition): + logging.debug("found partition of size %s (%s)" % (len(changes), changes)) + smallest_partition = changes + cache.clear() + + # write progress log information + if len(pkgs_to_upgrade) > 0: + percent = (len(pkgs_to_upgrade)-len(to_upgrade)) / float(len(pkgs_to_upgrade))*100.0 + else: + percent = 100.0 + install_log.status_change(pkg=",".join(smallest_partition), + percent=percent, + status="") + # apply changes + logging.debug("applying set %s" % smallest_partition) + rewind_cache(cache, [cache[name] for name in smallest_partition]) + + try: + iprogress = LogInstallProgress() + with Unlocked(): + res = cache.commit(install_progress=iprogress) + if not res: + raise Exception("cache.commit() returned false") + cache.open() + except Exception, e: + logging.error(_("Installing the upgrades failed!")) + logging.error(_("error message: '%s'") % e) + logging.error(_("dpkg returned a error! See '%s' for details") % \ + logfile_dpkg) + return False + to_upgrade = to_upgrade-set(smallest_partition) + logging.debug("left to upgrade %s" % to_upgrade) + if len(to_upgrade) == 0: + logging.info(_("All upgrades installed")) + break + return True -def is_allowed_origin(pkg, allowed_origins): - if not pkg.candidate: +def is_allowed_origin(ver, allowed_origins): + if not ver: return False - for origin in pkg.candidate.origins: + for origin in ver.origins: for allowed in allowed_origins: - if origin.origin == allowed[0] and origin.archive == allowed[1]: + if match_whitelist_string(allowed, origin): return True return False def check_changes_for_sanity(cache, allowed_origins, blacklist): - if cache._depcache.BrokenCount != 0: + if cache._depcache.broken_count != 0: return False for pkg in cache: - if pkg.markedDelete: + if pkg.marked_delete: logging.debug("pkg '%s' now marked delete" % pkg.name) return False - if pkg.markedInstall or pkg.markedUpgrade: - if not is_allowed_origin(pkg, allowed_origins): + if pkg.marked_install or pkg.marked_upgrade: + if not is_allowed_origin(pkg.candidate, allowed_origins): logging.debug("pkg '%s' not in allowed origin" % pkg.name) return False - if pkg.name in blacklist: - logging.debug("pkg '%s' blacklisted" % pkg.name) - return False - if pkg._pkg.SelectedState == apt_pkg.SelStateHold: + for blacklist_regexp in blacklist: + if re.match(blacklist_regexp, pkg.name): + logging.debug("skipping blacklisted package '%s'" % pkg.name) + return False + if pkg._pkg.selected_state == apt_pkg.SELSTATE_HOLD: logging.debug("pkg '%s' is on hold" % pkg.name) return False + # check if the package is unsafe to upgrade unattended + ignore_require_restart = apt_pkg.config.find_b( + "Unattended-Upgrade::IgnoreAppsRequireRestart", False) + if (pkg.marked_upgrade and + ignore_require_restart == False and + pkg.candidate.record.get("Upgrade-Requires") == "app-restart"): + logging.debug("pkg '%s' requires app-restart, not safe to upgrade unattended") + return False return True def pkgname_from_deb(debfile): # FIXME: add error checking here try: - control = apt_inst.debExtractControl(open(debfile)) - sections = apt_pkg.ParseSection(control) + control = apt_inst.DebFile(debfile).control.extractdata("control") + sections = apt_pkg.TagSection(control) return sections["Package"] except (IOError, SystemError), e: logging.error("failed to read deb file '%s' (%s)" % (debfile, e)) @@ -96,13 +390,13 @@ def conffile_prompt(destFile, prefix=""): logging.debug("check_conffile_prompt('%s')" % destFile) pkgname = pkgname_from_deb(destFile) - status_file = apt_pkg.Config.Find("Dir::State::status") - parse = apt_pkg.ParseTagFile(open(status_file,"r")) - while parse.Step() == 1: - if parse.Section.get("Package") == pkgname: + status_file = apt_pkg.config.find("Dir::State::status") + tagfile = apt_pkg.TagFile(open(status_file,"r")) + for section in tagfile: + if section.get("Package") == pkgname: logging.debug("found pkg: %s" % pkgname) - if parse.Section.has_key("Conffiles"): - conffiles = parse.Section.get("Conffiles") + if "Conffiles" in section: + conffiles = section.get("Conffiles") # Conffiles: # /etc/bash_completion.d/m-a c7780fab6b14d75ca54e11e992a6c11c for line in string.split(conffiles,"\n"): @@ -117,10 +411,20 @@ # ignore if conffile is obsolete or does not exist if obs == "obsolete" or not os.path.exists(prefix+conf_file): continue - # get conffile value from pkg - pkg_conffiles = apt_inst.debExtractControl( - open(destFile), "conffiles").split("\n") - if not conf_file in pkg_conffiles: + # ignore state "newconffile" until its clearer if there + # might be a dpkg prompt (LP: #936870) + if md5 == "newconffile": + continue + # get conffile value from pkg, its ok if the new version + # does not have conffiles anymore + deb = apt_inst.DebFile(destFile) + try: + pkg_conffiles = deb.control.extractdata("conffiles") + except LookupError as e: + logging.debug("No conffiles in %s anymore? (%s)" % (destFile, e)) + pkg_conffiles = "" + if (not pkg_conffiles or + not conf_file in pkg_conffiles.split("\n")): logging.debug("'%s' not in package conffiles '%s'" % (conf_file, pkg_conffiles)) continue # test against the installed file @@ -128,7 +432,7 @@ logging.debug("current md5: %s" % current_md5) # hashes are the same, no conffile prompt if current_md5 == md5: - return False + continue # calculate md5sum from the deb (may take a bit) dpkg_cmd = ["dpkg-deb","--fsys-tarfile",destFile] tar_cmd = ["tar","-x","-O", "-f","-", "."+conf_file] @@ -151,9 +455,9 @@ def dpkg_conffile_prompt(): - if not apt_pkg.Config.has_key("DPkg::Options"): + if not "DPkg::Options" in apt_pkg.config: return True - options = apt_pkg.Config.ValueList("DPkg::Options") + options = apt_pkg.config.value_list("DPkg::Options") for option in map(string.strip, options): if (option == "--force-confold" or option == "--force-confnew"): @@ -164,7 +468,7 @@ " set the cache back to the state with packages_to_upgrade " cache.clear() for pkg2 in pkgs_to_upgrade: - pkg2.markUpgrade() + pkg2.mark_upgrade() def host(): return os.uname()[1] @@ -179,38 +483,46 @@ out += s + " " return out -def setup_apt_listchanges(): - " deal with apt-listchanges " - conf = "/etc/apt/listchanges.conf" +def setup_apt_listchanges(conf="/etc/apt/listchanges.conf"): + """ deal with apt-listchanges """ if os.path.exists(conf): # check if mail is used by apt-listchanges cf = ConfigParser.ConfigParser() cf.read(conf) - if cf.has_section("apt") and cf.has_option("apt","frontend"): + if cf.has_section("apt") and cf.has_option("apt", "frontend"): frontend = cf.get("apt","frontend") - if frontend == "mail" and os.path.exists("/usr/sbin/sendmail"): + if frontend == "mail" and os.path.exists(SENDMAIL_BINARY): # mail frontend and sendmail, we are fine logging.debug("apt-listchanges is set to mail frontend, ignoring") return # setup env (to play it safe) and return - os.putenv("APT_LISTCHANGES_FRONTEND","none"); + os.environ["APT_LISTCHANGES_FRONTEND"] = "none" def send_summary_mail(pkgs, res, pkgs_kept_back, mem_log, logfile_dpkg): - " send mail (if configured in Unattended-Upgrades::Mail) " - email = apt_pkg.Config.Find("Unattended-Upgrade::Mail", "") + " send mail (if configured in Unattended-Upgrade::Mail) " + email = apt_pkg.config.find("Unattended-Upgrade::Mail", "") if not email: return - if not os.path.exists("/usr/bin/mail"): + if not os.path.exists(MAIL_BINARY): logging.error(_("No '/usr/bin/mail', can not send mail. " "You probably want to install the 'mailx' package.")) return + # if the operation was successful and the user has requested to get + # mails on on errors, just exit here + if (res and + apt_pkg.config.find_b("Unattended-Upgrade::MailOnlyOnError", False)): + return + # Check if reboot-required flag is present logging.debug("Sending mail with '%s' to '%s'" % (logfile_dpkg, email)) - mail = subprocess.Popen(["/usr/bin/mail", - "-s", _("unattended-upgrades result " - "for '%s'") % host(), - email], - stdin=subprocess.PIPE) + if os.path.isfile(REBOOT_REQUIRED_FILE): + subject = _("[reboot required] unattended-upgrades result for '%s'") % host() + else: + subject = _("unattended-upgrades result for '%s'") % host() + mail = subprocess.Popen([MAIL_BINARY, "-s", subject, + email], stdin=subprocess.PIPE) s = _("Unattended upgrade returned: %s\n\n") % res + if os.path.isfile(REBOOT_REQUIRED_FILE): + s += _("Warning: A reboot is required to complete this upgrade.\n\n") s += _("Packages that are upgraded:\n") s += " " + wrap(pkgs, 70, " ") s += "\n" @@ -219,27 +531,110 @@ s += " " + wrap(" ".join(pkgs_kept_back), 70, " ") s += "\n" s += "\n" - s += _("Package installation log:")+"\n" - s += open(logfile_dpkg).read() - s += "\n\n" + if os.path.exists(logfile_dpkg): + s += _("Package installation log:")+"\n" + s += open(logfile_dpkg).read() + s += "\n\n" s += _("Unattended-upgrades log:\n") s += mem_log.getvalue() mail.stdin.write(s) mail.stdin.close() ret = mail.wait() logging.debug("mail returned: %s" % ret) + + +def do_install(cache, pkgs_to_upgrade, options, logfile_dpkg): + # set debconf to NON_INTERACTIVE, redirect output + os.putenv("DEBIAN_FRONTEND","noninteractive"); + setup_apt_listchanges() + # redirect to log + REDIRECT_INPUT = os.devnull + fd = os.open(REDIRECT_INPUT, os.O_RDWR) + os.dup2(fd,0) -def main(): - # init the options - parser = OptionParser() - parser.add_option("-d", "--debug", - action="store_true", dest="debug", default=False, - help=_("print debug messages")) - parser.add_option("", "--dry-run", - action="store_true", default=False, - help=_("Simulation, download but do not install")) - (options, args) = parser.parse_args() + logging.info(_("Writing dpkg log to '%s'") % logfile_dpkg) + + # do not create log in dry-run mode, just output to stdout/stderr + if options.dry_run: + old_stdout = 1 + old_stderr = 2 + else: + fd = os.open(logfile_dpkg, os.O_RDWR|os.O_CREAT, 0644) + old_stdout = os.dup(1) + old_stderr = os.dup(2) + os.dup2(fd,1) + os.dup2(fd,2) + + try: + if (options.minimal_upgrade_steps or + # COMPAT with the mispelling + apt_pkg.config.find_b("Unattended-Upgrades::MinimalSteps", False) or + apt_pkg.config.find_b("Unattended-Upgrade::MinimalSteps", False)): + open("/var/run/unattended-upgrades.pid", "w").write("%s" % os.getpid()) + # try upgrade all "pkgs" in minimal steps + pkg_install_success = upgrade_in_minimal_steps( + cache, [pkg.name for pkg in pkgs_to_upgrade], logfile_dpkg) + else: + pkg_install_success = upgrade_normal( + cache, [pkg.name for pkg in pkgs_to_upgrade], logfile_dpkg) + except Exception as e: + # print unhandled exceptions here this way, while stderr is redirected + os.write(old_stderr, "Exception: %s" % e) + + # restore + os.dup2(old_stdout, 1) + os.dup2(old_stderr, 2) + + return pkg_install_success + + +def _setup_alternative_rootdir(rootdir): + # clear system unattended-upgrade stuff + apt_pkg.config.clear("Unattended-Upgrade") + # read rootdir (taken from apt.Cache, but we need to run it + # here before the cache gets initialized + if os.path.exists(rootdir+"/etc/apt/apt.conf"): + apt_pkg.read_config_file(apt_pkg.config, + rootdir + "/etc/apt/apt.conf") + if os.path.isdir(rootdir+"/etc/apt/apt.conf.d"): + apt_pkg.read_config_dir(apt_pkg.config, + rootdir + "/etc/apt/apt.conf.d") + +def _get_logdir(): + logdir= apt_pkg.config.find_dir( + "Unattended-Upgrade::LogDir", + # COMPAT only + apt_pkg.config.find_dir("APT::UnattendedUpgrades::LogDir", + "/var/log/unattended-upgrades/")) + return logdir + +def _setup_logging(options): + # init the logging + logdir = _get_logdir() + logfile = os.path.join( + logdir, + apt_pkg.config.find( + "Unattended-Upgrade::LogFile", + # COMPAT only + apt_pkg.config.find("APT::UnattendedUpgrades::LogFile", + "unattended-upgrades.log"))) + + if not options.dry_run and not os.path.exists(os.path.dirname(logfile)): + os.makedirs(os.path.dirname(logfile)) + + logging.basicConfig(level=logging.INFO, + format='%(asctime)s %(levelname)s %(message)s', + filename=logfile) + + +def main(options, rootdir=""): + + # useful for testing + if rootdir: + _setup_alternative_rootdir(rootdir) + + _setup_logging(options) # setup logging logger = logging.getLogger() @@ -248,24 +643,47 @@ logger.setLevel(logging.DEBUG) stderr_handler = logging.StreamHandler() logger.addHandler(stderr_handler) - if apt_pkg.Config.Find("Unattended-Upgrade::Mail", ""): + if apt_pkg.config.find("Unattended-Upgrade::Mail", ""): mem_log_handler = logging.StreamHandler(mem_log) logger.addHandler(mem_log_handler) # format (origin, archive), e.g. ("Ubuntu","dapper-security") - allowed_origins = map(string.split, apt_pkg.Config.ValueList("Unattended-Upgrade::Allowed-Origins")) + allowed_origins = get_allowed_origins() # pkgs that are (for some reason) not save to install - blacklisted_pkgs = apt_pkg.Config.ValueList("Unattended-Upgrade::Package-Blacklist") + blacklisted_pkgs = apt_pkg.config.value_list("Unattended-Upgrade::Package-Blacklist") logging.info(_("Initial blacklisted packages: %s"), " ".join(blacklisted_pkgs)) logging.info(_("Starting unattended upgrades script")) # display available origin logging.info(_("Allowed origins are: %s") % map(str,allowed_origins)) + + # check if the journal is dirty and if so, take emergceny action + # the alternative is to leave the system potentially unsecure until + # the user comes in and fixes + if (is_dpkg_journal_dirty() and + apt_pkg.config.find_b("Unattended-Upgrade::AutoFixInterruptedDpkg", True)): + # ensure the dpkg database is not already locked (LP: #754330) + admindir = os.path.dirname(apt_pkg.config.find("Dir::State::Status")) + lockfd = apt_pkg.get_lock(os.path.join(admindir, "lock"), False) + if lockfd > 0: + logging.warning(_("Unclean dpkg state detected, trying to correct")) + print _("Unclean dpkg state detected, trying to correct") + env = copy.copy(os.environ) + env["DEBIAN_FRONTEND"] = "noninteractive" + try: + os.close(lockfd) + output = subprocess.check_output( + ["dpkg", "--force-confold", "--configure", "-a"], env=env) + except subprocess.CalledProcessError as e: + output = e.output + logging.warning(_("dpkg --configure -a output:\n%s" % output)) + else: + logging.debug("Unclean dpkg state, but locked, another package manager working?") # check and get lock try: - apt_pkg.PkgSystemLock() + apt_pkg.pkgsystem_lock() except SystemError, e: logging.error(_("Lock could not be acquired (another package " "manager running?)")) @@ -273,29 +691,41 @@ sys.exit(1) # get a cache - cache = MyCache() - if cache._depcache.BrokenCount > 0: + cache = UnattendedUpgradesCache(rootdir=rootdir, + allowed_origins=allowed_origins) + if cache._depcache.broken_count > 0: print _("Cache has broken packages, exiting") logging.error(_("Cache has broken packages, exiting")) sys.exit(1) # speed things up with latest apt - actiongroup = apt_pkg.GetPkgActionGroup(cache._depcache) + actiongroup = apt_pkg.ActionGroup(cache._depcache) # find out about the packages that are upgradable (in a allowed_origin) pkgs_to_upgrade = [] pkgs_kept_back = [] pkgs_auto_removable = set([pkg.name for pkg in cache - if pkg.isAutoRemovable]) + if pkg.is_auto_removable]) + + # now do the actual upgrade for pkg in cache: - if options.debug and pkg.isUpgradable: + if options.debug and pkg.is_upgradable: logging.debug("Checking: %s (%s)" % (pkg.name, map(str, pkg.candidate.origins))) - if (pkg.isUpgradable and - is_allowed_origin(pkg,allowed_origins)): + if (pkg.is_upgradable and + is_allowed_origin(pkg.candidate, allowed_origins)): try: - pkg.markUpgrade() + pkg.mark_upgrade() if check_changes_for_sanity(cache, allowed_origins, blacklisted_pkgs): + # add to packages to upgrade pkgs_to_upgrade.append(pkg) + # re-eval pkgs_kept_back as the resolver may fail to + # directly upgrade a pkg, but that may work during + # a subsequent operation, see debian bug #639840 + for pkgname in pkgs_kept_back: + if (cache[pkgname].marked_install or + cache[pkgname].marked_upgrade): + pkgs_kept_back.remove(pkgname) + pkgs_to_upgrade.append(cache[pkgname]) else: logging.debug("sanity check failed") rewind_cache(cache, pkgs_to_upgrade) @@ -303,53 +733,59 @@ except SystemError, e: # can't upgrade logging.warning(_("package '%s' upgradable but fails to be marked for upgrade (%s)") % (pkg.name, e)) - rewind_cache(cache, pkgs_to_ugprade) + rewind_cache(cache, pkgs_to_upgrade) pkgs_kept_back.append(pkg.name) + pkgs_to_upgrade.sort(key=lambda p: p.name) pkgs = "\n".join([pkg.name for pkg in pkgs_to_upgrade]) logging.debug("pkgs that look like they should be upgraded: %s" % pkgs) # download what looks good if options.debug: - fetcher = apt_pkg.GetAcquire(apt.progress.TextFetchProgress()) + fetcher = apt_pkg.Acquire(apt.progress.text.AcquireProgress()) else: - fetcher = apt_pkg.GetAcquire() - list = apt_pkg.GetPkgSourceList() - list.ReadMainList() + fetcher = apt_pkg.Acquire() + list = apt_pkg.SourceList() + list.read_main_list() recs = cache._records - pm = apt_pkg.GetPackageManager(cache._depcache) + pm = apt_pkg.PackageManager(cache._depcache) try: - pm.GetArchives(fetcher,list,recs) + pm.get_archives(fetcher,list,recs) except SystemError, e: logging.error(_("GetArchives() failed: '%s'") % e) - res = fetcher.Run() + res = fetcher.run() if dpkg_conffile_prompt(): # now check the downloaded debs for conffile conflicts and build # a blacklist - for item in fetcher.Items: + for item in fetcher.items: logging.debug("%s" % item) - if item.Status == item.StatError: - print _("An error ocured: '%s'") % item.ErrorText - logging.error(_("An error ocured: '%s'") % item.ErrorText) - if item.Complete == False: - print _("The URI '%s' failed to download, aborting") % item.DescURI - logging.error(_("The URI '%s' failed to download, aborting") % item.DescURI) + if item.status == item.STAT_ERROR: + print _("An error ocured: '%s'") % item.error_text + logging.error(_("An error ocured: '%s'") % item.error_text) + if not item.complete: + print _("The URI '%s' failed to download, aborting") % item.desc_uri + logging.error(_("The URI '%s' failed to download, aborting") % item.desc_uri) sys.exit(1) - if not os.path.exists(item.DestFile): - print _("Download finished, but file '%s' not there?!?" % item.DestFile) - logging.error("Download finished, but file '%s' not there?!?" % item.DestFile) + if not os.path.exists(item.destfile): + print _("Download finished, but file '%s' not there?!?" % item.destfile) + logging.error("Download finished, but file '%s' not there?!?" % item.destfile) sys.exit(1) - if item.IsTrusted == False: - blacklisted_pkgs.append(pkgname_from_deb(item.DestFile)) - if conffile_prompt(item.DestFile): - # FIXME: skip package (means to re-run the whole marking again + if not item.is_trusted: + blacklisted_pkgs.append(pkgname_from_deb(item.destfile)) + if conffile_prompt(item.destfile): + # skip package (means to re-run the whole marking again # and making sure that the package will not be pulled in by - # some other package again! - logging.warning(_("Package '%s' has conffile prompt and needs to be upgraded manually") % pkgname_from_deb(item.DestFile)) - blacklisted_pkgs.append(pkgname_from_deb(item.DestFile)) - pkgs_kept_back.append(pkgname_from_deb(item.DestFile)) + # some other package again!) + # + # print to stdout to ensure that this message is part of + # the cron mail + print _("Package '%s' has conffile prompt and needs to be upgraded manually") % pkgname_from_deb(item.destfile) + # log to the logfile + logging.warning(_("Package '%s' has conffile prompt and needs to be upgraded manually") % pkgname_from_deb(item.destfile)) + blacklisted_pkgs.append(pkgname_from_deb(item.destfile)) + pkgs_kept_back.append(pkgname_from_deb(item.destfile)) # redo the selection about the packages to upgrade based on the new @@ -362,7 +798,7 @@ pkgs_to_upgrade = [] for pkg in old_pkgs_to_upgrade: logging.debug("Checking (blacklist): %s" % (pkg.name)) - pkg.markUpgrade() + pkg.mark_upgrade() if check_changes_for_sanity(cache, allowed_origins, blacklisted_pkgs): pkgs_to_upgrade.append(pkg) @@ -372,96 +808,70 @@ logging.info(_("package '%s' not upgraded") % pkg.name) cache.clear() for pkg2 in pkgs_to_upgrade: - pkg2.markUpgrade() + pkg2.mark_upgrade() else: logging.debug("dpkg is configured not to cause conffile prompts") # do auto-remove - if apt_pkg.Config.FindB("Unattended-Upgrade::Remove-Unused-Dependencies", False): + if apt_pkg.config.find_b("Unattended-Upgrade::Remove-Unused-Dependencies", False): now_auto_removable = set([pkg.name for pkg in cache - if pkg.isAutoRemovable]) + if pkg.is_auto_removable]) for pkgname in now_auto_removable-pkgs_auto_removable: logging.debug("marking %s for remove" % pkgname) - cache[pkgname].markDelete() + cache[pkgname].mark_delete() logging.info(_("Packages that are auto removed: '%s'") % " ".join(now_auto_removable-pkgs_auto_removable)) - logging.debug("InstCount=%i DelCount=%i BrokenCout=%i" % (cache._depcache.InstCount, cache._depcache.DelCount, cache._depcache.BrokenCount)) + logging.debug("InstCount=%i DelCount=%i BrokenCout=%i" % (cache._depcache.inst_count, cache._depcache.del_count, cache._depcache.broken_count)) # exit if there is nothing to do and nothing to report if (len(pkgs_to_upgrade) == 0) and (len(pkgs_kept_back) == 0): logging.info(_("No packages found that can be upgraded unattended")) - sys.exit(0) + return + + # check if its configured for install on shutdown, if so, the + # environment UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN will + # be set by the unatteded-upgrades-shutdown script + if (not "UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN" in os.environ and + apt_pkg.config.find_b("Unattended-Upgrade::InstallOnShutdown", False)): + logger.debug("Configured to install on shutdown, so exiting now") + return # check if we are in dry-run mode if options.dry_run: logging.info("Option --dry-run given, *not* performing real actions") - apt_pkg.Config.Set("Debug::pkgDPkgPM","1") + apt_pkg.config.set("Debug::pkgDPkgPM","1") # do the install based on the new list of pkgs pkgs = " ".join([pkg.name for pkg in pkgs_to_upgrade]) logging.info(_("Packages that are upgraded: %s" % pkgs)) - # set debconf to NON_INTERACTIVE, redirect output - os.putenv("DEBIAN_FRONTEND","noninteractive"); - setup_apt_listchanges() - - # redirect to log - REDIRECT_INPUT = os.devnull - fd = os.open(REDIRECT_INPUT, os.O_RDWR) - os.dup2(fd,0) - + # get log now = datetime.datetime.now() - logfile_dpkg = logdir+'unattended-upgrades-dpkg_%s.log' % now.isoformat('_') - logging.info(_("Writing dpkg log to '%s'") % logfile_dpkg) - fd = os.open(logfile_dpkg, os.O_RDWR|os.O_CREAT, 0644) - old_stdout = os.dup(1) - old_stderr = os.dup(2) - os.dup2(fd,1) - os.dup2(fd,2) - - # create a new package-manager. the blacklist may have changed - # the markings in the depcache - pm = apt_pkg.GetPackageManager(cache._depcache) - if not pm.GetArchives(fetcher,list,recs): - logging.error(_("pm.GetArchives() failed")) - # run the fetcher again (otherwise local file:// - # URIs are unhappy (see LP: #56832) - res = fetcher.Run() - # unlock the cache - try: - apt_pkg.PkgSystemUnLock() - except SystemError, e: - pass - # lock for the shutdown check - its fine if the system - # is shutdown while downloading but not so much while installing - apt_pkg.GetLock("/var/run/unattended-upgrades.lock") - # now do the actual install - error = None - try: - res = pm.DoInstall() - except SystemError,e: - error = e - res = pm.ResultFailed - finally: - os.dup2(old_stdout, 1) - os.dup2(old_stderr, 2) + logfile_dpkg = os.path.join( + _get_logdir(), 'unattended-upgrades-dpkg_%s.log' % now.isoformat('_')) - if res == pm.ResultFailed: - logging.error(_("Installing the upgrades failed!")) - logging.error(_("error message: '%s'") % e) - logging.error(_("dpkg returned a error! See '%s' for details") % logfile_dpkg) - else: - logging.info(_("All upgrades installed")) + # only perform install step if we actually have packages to install + pkg_install_success = None + 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, options, logfile_dpkg) # send a mail (if needed) - pkg_install_success = (res != pm.ResultFailed) - send_summary_mail(pkgs, pkg_install_success, pkgs_kept_back, mem_log, logfile_dpkg) + if not options.dry_run: + send_summary_mail( + pkgs, pkg_install_success, pkgs_kept_back, mem_log, logfile_dpkg) # auto-reboot (if required and the config for this is set - if (apt_pkg.Config.FindB("Unattended-Upgrade::Automatic-Reboot", False) and - os.path.exists("/var/run/reboot-required")): - logging.warning("Found /var/run/reboot-required, rebooting") + if (apt_pkg.config.find_b("Unattended-Upgrade::Automatic-Reboot", False) and + os.path.exists(REBOOT_REQUIRED_FILE)): + if shutdown_lock > 0: + os.close(shutdown_lock) + logging.warning("Found %s, rebooting" % REBOOT_REQUIRED_FILE) subprocess.call(["/sbin/reboot"]) @@ -471,20 +881,26 @@ gettext.bindtextdomain(localesApp, localesDir) gettext.textdomain(localesApp) + # init the options + parser = OptionParser() + parser.add_option("-d", "--debug", + action="store_true", dest="debug", default=False, + help=_("print debug messages")) + parser.add_option("", "--dry-run", + action="store_true", default=False, + help=_("Simulation, download but do not install")) + parser.add_option("", "--minimal_upgrade_steps", + action="store_true", default=False, + help=_("Upgrade in minimal steps (and allow interrupting with SIGINT")) + (options, args) = parser.parse_args() + if os.getuid() != 0: print _("You need to be root to run this application") sys.exit(1) - - if not os.path.exists("/var/log/unattended-upgrades"): - os.makedirs("/var/log/unattended-upgrades") - # init the logging - logdir = apt_pkg.Config.FindDir("APT::UnattendedUpgrades::LogDir", - "/var/log/unattended-upgrades/") - logfile = logdir+apt_pkg.Config.Find("APT::UnattendedUpgrades::LogFile", - "unattended-upgrades.log") - logging.basicConfig(level=logging.INFO, - format='%(asctime)s %(levelname)s %(message)s', - filename=logfile) + # nice & ionce + os.nice(19) + subprocess.call(["ionice","-c3", "-p",str(os.getpid())]) + # run the main code - main() + main(options) diff -Nru unattended-upgrades-0.55ubuntu3/unattended-upgrade-shutdown unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/unattended-upgrade-shutdown --- unattended-upgrades-0.55ubuntu3/unattended-upgrade-shutdown 2010-03-19 08:29:06.000000000 +0000 +++ unattended-upgrades-0.76ubuntu1~ubuntu10.04.1/unattended-upgrade-shutdown 2012-03-09 08:34:44.000000000 +0000 @@ -25,8 +25,12 @@ # import apt_pkg -import time +import copy +import signal +import struct import sys +import fcntl +import time import logging import logging.handlers import gettext @@ -47,6 +51,24 @@ logging.debug("Running plymouth --text") subprocess.call(["/bin/plymouth","message", "--text", msg]) +def log_msg(msg): + """ helper that will print msg to usplash, plymouth, console """ + logging.warning(msg) + do_plymouth(msg) + do_usplash(msg) + +def log_progress(): + """ helper to log the install progress (if any) """ + # wait a some seconds and try again + msg = _("Unattended-upgrade in progress during shutdown, " + "sleeping for 5s") + # progress info + progress = "/var/run/unattended-upgrades.progress" + if os.path.exists(progress): + msg += "\n" + open(progress).read() + # log it + log_msg(msg) + if __name__ == "__main__": # setup gettext localesApp="unattended-upgrades" @@ -77,20 +99,38 @@ except Exception, e: logging.debug("failed to setup syslog logger: %s" % e) - # run + # check if we need to run unattended-upgrades on shutdown and if so, + # run it + p = None + apt_pkg.init_config() + if apt_pkg.config.find_b("Unattended-Upgrade::InstallOnShutdown", False): + env = copy.copy(os.environ) + env["UNATTENDED_UPGRADES_FORCE_INSTALL_ON_SHUTDOWN"] = "1" + logging.debug("starting unattended-upgrades in shutdown mode") + p = subprocess.Popen(["unattended-upgrade"], env=env) + log_msg(_("Running unattended-upgrades in shutdown mode")) + while True: + log_progress() + if p.poll() is not None: + break + time.sleep(5) + + + # run the monitoring loop and keep the "UI" updated start_time = time.time() while True: - res = apt_pkg.GetLock(options.lock_file) - logging.debug("GetLock returned %i" % res) + res = apt_pkg.get_lock(options.lock_file) + logging.debug("get_lock returned %i" % res) if res > 0: - logging.debug("Lock not taken") + logging.debug("lock not taken") sys.exit(0) - # wait a some seconds and try again - msg = _("Unattended-upgrade in progress during shutdown, " - "sleeping for 5s") - logging.warning(msg) - do_plymouth(msg) - do_usplash(msg) + # signal unattended-upgrades to stop + p = "/var/run/unattended-upgrades.pid" + if os.path.exists(p): + pid = int(open(p).read()) + os.kill(pid, signal.SIGUSR1) + # show log + log_progress() time.sleep(5) if (time.time() - start_time) > options.delay*60: logging.warning(_("Giving up on lockfile after %s delay") % options.delay)