~ubuntu-core-dev/unattended-upgrades/ubuntu

« back to all changes in this revision

Viewing changes to unattended-upgrade

  • Committer: Barry Warsaw
  • Date: 2012-06-19 20:19:36 UTC
  • mfrom: (277.1.5 unattended-upgrades)
  • mto: This revision was merged to the branch mainline in revision 288.
  • Revision ID: barry@python.org-20120619201936-vrpi8yxbbxzdr6qg
Merge Thomas's branch: Port to Python 3
- Additional fixes by Barry

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/python
 
1
#!/usr/bin/python3
2
2
# Copyright (c) 2005-2012 Canonical Ltd
3
3
#
4
4
# AUTHOR:
20
20
# along with unattended-upgrades; if not, write to the Free Software
21
21
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
22
#
23
 
 
24
23
import apt_inst
25
24
import apt_pkg
26
25
 
27
 
import ConfigParser
 
26
try:
 
27
    import configparser         # Python 3            
 
28
except ImportError:
 
29
    import ConfigParser as configparser  # Python 2
28
30
import copy
29
31
import datetime
30
32
import fcntl
33
35
import string
34
36
import sys
35
37
 
36
 
from StringIO import StringIO
 
38
try:
 
39
    from StringIO import StringIO    # Python 2
 
40
except ImportError:
 
41
    from io import StringIO          # Python 3
37
42
from optparse import OptionParser
38
43
from subprocess import Popen, PIPE
39
44
 
112
117
    LOG = PROGRESS_LOG 
113
118
 
114
119
    def status_change(self, pkg, percent, status):
115
 
        f=open(self.LOG, "w")
116
 
        f.write(_("Progress: %s %% (%s)") % (percent, pkg))
117
 
        f.close()
 
120
        with open(self.LOG, "w") as f:
 
121
            f.write(_("Progress: %s %% (%s)") % (percent, pkg))
118
122
 
119
123
    def _fixup_fds(self):
120
124
        required_fds = [ 0, 1, 2, # stdin, stdout, stderr
135
139
                try:
136
140
                    fd = int(fdname)
137
141
                except Exception as e:
138
 
                    print "ERROR: can not get fd for '%s'" % fdname
 
142
                    print("ERROR: can not get fd for '%s'" % fdname)
139
143
                if fd in required_fds:
140
144
                    continue
141
145
                try:
142
146
                    os.close(fd)
143
 
                    #print "closed: ", fd
 
147
                    #print("closed: ", fd)
144
148
                except OSError as e:
145
149
                    # there will be one fd that can not be closed
146
150
                    # as its the fd from pythons internal diropen()
147
151
                    # so its ok to ignore one close error
148
152
                    error_count += 1
149
153
                    if error_count > 1:
150
 
                        print "ERROR: os.close(%s): %s" % (fd, e)
 
154
                        print("ERROR: os.close(%s): %s" % (fd, e))
151
155
 
152
156
    def fork(self):
153
157
        pid = os.fork()
270
274
    try:
271
275
        with Unlocked():
272
276
            res = cache.commit(install_progress=iprogress)
273
 
    except SystemError,e:
 
277
    except SystemError as e:
274
278
        error = e
275
279
    if res:
276
280
        logging.info(_("All upgrades installed"))
334
338
                if not res:
335
339
                    raise Exception("cache.commit() returned false")
336
340
            cache.open()
337
 
        except Exception, e:
 
341
        except Exception as e:
338
342
            logging.error(_("Installing the upgrades failed!"))
339
343
            logging.error(_("error message: '%s'") % e)
340
344
            logging.error(_("dpkg returned a error! See '%s' for details") % \
390
394
        control = apt_inst.DebFile(debfile).control.extractdata("control")
391
395
        sections = apt_pkg.TagSection(control)
392
396
        return sections["Package"]
393
 
    except (IOError, SystemError), e:
 
397
    except (IOError, SystemError) as e:
394
398
        logging.error("failed to read deb file '%s' (%s)" % (debfile, e))
395
399
        # dumb fallback
396
400
        return debfile.split("_")[0]
408
412
                conffiles = section.get("Conffiles")
409
413
                # Conffiles:
410
414
                # /etc/bash_completion.d/m-a c7780fab6b14d75ca54e11e992a6c11c
411
 
                for line in string.split(conffiles,"\n"):
 
415
                for line in conffiles.splitlines():
412
416
                    logging.debug("conffile line: %s", line)
413
 
                    l = string.split(string.strip(line))
 
417
                    l = line.strip().split()
414
418
                    conf_file = l[0]
415
419
                    md5 = l[1]
416
420
                    if len(l) > 2:
428
432
                    # does not have conffiles anymore
429
433
                    deb = apt_inst.DebFile(destFile)
430
434
                    try:
431
 
                        pkg_conffiles = deb.control.extractdata("conffiles")
 
435
                        pkg_conffiles = deb.control.extractdata("conffiles").decode('utf-8')
432
436
                    except LookupError as e:
433
437
                        logging.debug("No conffiles in %s anymore? (%s)" % (destFile, e))
434
438
                        pkg_conffiles = ""
437
441
                        logging.debug("'%s' not in package conffiles '%s'" % (conf_file, pkg_conffiles))
438
442
                        continue
439
443
                    # test against the installed file
440
 
                    current_md5 = apt_pkg.md5sum(open(prefix+conf_file).read())
 
444
                    with open(prefix+conf_file, 'rb') as fp:
 
445
                        current_md5 = apt_pkg.md5sum(fp.read())
441
446
                    logging.debug("current md5: %s" % current_md5)
442
447
                    # hashes are the same, no conffile prompt
443
448
                    if current_md5 == md5:
446
451
                    dpkg_cmd = ["dpkg-deb","--fsys-tarfile",destFile]
447
452
                    tar_cmd = ["tar","-x","-O", "-f","-", "."+conf_file]
448
453
                    md5_cmd = ["md5sum"]
449
 
                    dpkg_p = Popen(dpkg_cmd, stdout=PIPE)
450
 
                    tar_p = Popen(tar_cmd, stdin=dpkg_p.stdout, stdout=PIPE)
451
 
                    md5_p = Popen(md5_cmd, stdin=tar_p.stdout, stdout=PIPE)
452
 
                    pkg_md5sum = md5_p.communicate()[0].split()[0]
 
454
                    dpkg_p = Popen(dpkg_cmd, stdout=PIPE,
 
455
                                   universal_newlines=True)
 
456
                    tar_p = Popen(tar_cmd, stdin=dpkg_p.stdout, stdout=PIPE,
 
457
                                  universal_newlines=True)
 
458
                    md5_p = Popen(md5_cmd, stdin=tar_p.stdout, stdout=PIPE,
 
459
                                  universal_newlines=True)
 
460
                    pkg_md5sum = md5_p.communicate()[0].split()[0].decode('ascii')
453
461
                    logging.debug("pkg_md5sum: %s" % pkg_md5sum)
454
462
                    # the md5sum in the deb is unchanged, this will not 
455
463
                    # trigger a conffile prompt
496
504
    """ deal with apt-listchanges """
497
505
    if os.path.exists(conf):
498
506
        # check if mail is used by apt-listchanges
499
 
        cf = ConfigParser.ConfigParser()
 
507
        cf = configparser.ConfigParser()
500
508
        cf.read(conf)
501
509
        if cf.has_section("apt") and cf.has_option("apt", "frontend"):
502
510
            frontend = cf.get("apt","frontend")
520
528
    # mails on on errors, just exit here
521
529
    if (res and
522
530
        apt_pkg.config.find_b("Unattended-Upgrade::MailOnlyOnError", False)):
523
 
        return
 
531
        return
524
532
    # Check if reboot-required flag is present
525
533
    logging.debug("Sending mail with '%s' to '%s'" % (logfile_dpkg, email))
526
534
    if os.path.isfile(REBOOT_REQUIRED_FILE):
527
535
        subject = _("[reboot required] unattended-upgrades result for '%s'") % host()
528
536
    else:
529
537
        subject = _("unattended-upgrades result for '%s'") % host()
530
 
    mail = subprocess.Popen([MAIL_BINARY, "-s", subject,
531
 
                             email], stdin=subprocess.PIPE)
 
538
    mail = subprocess.Popen([MAIL_BINARY, "-s", subject, email], 
 
539
                            stdin=subprocess.PIPE,
 
540
                            universal_newlines=True)
532
541
    s = _("Unattended upgrade returned: %s\n\n") % res
533
542
    if os.path.isfile(REBOOT_REQUIRED_FILE):
534
543
        s += _("Warning: A reboot is required to complete this upgrade.\n\n")
542
551
    s += "\n"
543
552
    if os.path.exists(logfile_dpkg):
544
553
        s += _("Package installation log:")+"\n"
545
 
        s += open(logfile_dpkg).read()
 
554
        with open(logfile_dpkg) as fp:
 
555
            s += fp.read()
546
556
        s += "\n\n"
547
557
    s += _("Unattended-upgrades log:\n")
548
558
    s += mem_log.getvalue()
569
579
        old_stdout = 1
570
580
        old_stderr = 2
571
581
    else:
572
 
        fd = os.open(logfile_dpkg, os.O_RDWR|os.O_CREAT, 0644)
 
582
        fd = os.open(logfile_dpkg, os.O_RDWR|os.O_CREAT, 0o644)
573
583
        old_stdout = os.dup(1)
574
584
        old_stderr = os.dup(2)
575
585
        os.dup2(fd,1)
580
590
            # COMPAT with the mispelling
581
591
            apt_pkg.config.find_b("Unattended-Upgrades::MinimalSteps", False) or
582
592
            apt_pkg.config.find_b("Unattended-Upgrade::MinimalSteps", False)):
583
 
            open("/var/run/unattended-upgrades.pid", "w").write("%s" % os.getpid())
 
593
            with open("/var/run/unattended-upgrades.pid", "w") as fp:
 
594
                fp.write("%s" % os.getpid())
584
595
            # try upgrade all "pkgs" in minimal steps
585
596
            pkg_install_success = upgrade_in_minimal_steps(
586
597
                cache, [pkg.name for pkg in pkgs_to_upgrade], logfile_dpkg)
677
688
        lockfd = apt_pkg.get_lock(os.path.join(admindir, "lock"), False)
678
689
        if lockfd > 0:
679
690
            logging.warning(_("Unclean dpkg state detected, trying to correct"))
680
 
            print _("Unclean dpkg state detected, trying to correct")
 
691
            print(_("Unclean dpkg state detected, trying to correct"))
681
692
            env = copy.copy(os.environ)
682
693
            env["DEBIAN_FRONTEND"] = "noninteractive"
683
694
            try:
693
704
    # check and get lock
694
705
    try:
695
706
        apt_pkg.pkgsystem_lock()
696
 
    except SystemError, e:
 
707
    except SystemError as e:
697
708
        logging.error(_("Lock could not be acquired (another package "
698
709
                        "manager running?)"))
699
 
        print _("Cache lock can not be acquired, exiting")
 
710
        print(_("Cache lock can not be acquired, exiting"))
700
711
        sys.exit(1)
701
712
 
702
713
    # get a cache
703
714
    cache = UnattendedUpgradesCache(rootdir=rootdir, 
704
715
                                    allowed_origins=allowed_origins)
705
716
    if cache._depcache.broken_count > 0:
706
 
        print _("Cache has broken packages, exiting")
 
717
        print(_("Cache has broken packages, exiting"))
707
718
        logging.error(_("Cache has broken packages, exiting"))
708
719
        sys.exit(1)
709
720
    # speed things up with latest apt
739
750
                    logging.debug("sanity check failed")
740
751
                    rewind_cache(cache, pkgs_to_upgrade)
741
752
                    pkgs_kept_back.append(pkg.name)
742
 
            except SystemError, e:
 
753
            except SystemError as e:
743
754
                # can't upgrade
744
755
                logging.warning(_("package '%s' upgradable but fails to be marked for upgrade (%s)") % (pkg.name, e))
745
756
                rewind_cache(cache, pkgs_to_upgrade)
761
772
    pm = apt_pkg.PackageManager(cache._depcache)
762
773
    try:
763
774
        pm.get_archives(fetcher,list,recs)
764
 
    except SystemError, e:
 
775
    except SystemError as e:
765
776
        logging.error(_("GetArchives() failed: '%s'") % e)
766
777
    res = fetcher.run()
767
778
 
771
782
        for item in fetcher.items:
772
783
            logging.debug("%s" % item)
773
784
            if item.status == item.STAT_ERROR:
774
 
                print _("An error ocured: '%s'") % item.error_text
 
785
                print(_("An error ocured: '%s'") % item.error_text)
775
786
                logging.error(_("An error ocured: '%s'") % item.error_text)
776
787
            if not item.complete:
777
 
                print _("The URI '%s' failed to download, aborting") % item.desc_uri
 
788
                print(_("The URI '%s' failed to download, aborting") % item.desc_uri)
778
789
                logging.error(_("The URI '%s' failed to download, aborting") % item.desc_uri)
779
790
                sys.exit(1)
780
791
            if not os.path.exists(item.destfile):
781
 
                print _("Download finished, but file '%s' not there?!?" % item.destfile)
 
792
                print(_("Download finished, but file '%s' not there?!?" % item.destfile))
782
793
                logging.error("Download finished, but file '%s' not there?!?" % item.destfile)
783
794
                sys.exit(1)
784
795
            if not item.is_trusted:
792
803
                # the cron mail (only if no summary mail is requested)
793
804
                email = apt_pkg.config.find("Unattended-Upgrade::Mail", "")
794
805
                if not email:
795
 
                    print _("Package '%s' has conffile prompt and needs to be upgraded manually") % pkgname_from_deb(item.destfile)
 
806
                    print(_("Package '%s' has conffile prompt and needs to be upgraded manually") % pkgname_from_deb(item.destfile))
796
807
                # log to the logfile
797
808
                logging.warning(_("Package '%s' has conffile prompt and needs to be upgraded manually") % pkgname_from_deb(item.destfile))
798
809
                blacklisted_pkgs.append(pkgname_from_deb(item.destfile))
907
918
    (options, args) = parser.parse_args()
908
919
 
909
920
    if os.getuid() != 0:
910
 
        print _("You need to be root to run this application")
 
921
        print(_("You need to be root to run this application"))
911
922
        sys.exit(1)
912
923
 
913
924
    # nice & ionce