3
# Copyright (c) 2004-2010 Canonical
5
# Author: Michael Vogt <michael.vogt@ubuntu.com>
7
# This program is free software; you can redistribute it and/or
8
# modify it under the terms of the GNU General Public License as
9
# published by the Free Software Foundation; either version 2 of the
10
# License, or (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with this program; if not, write to the Free Software
19
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22
from __future__ import absolute_import
34
from subprocess import PIPE, Popen
35
from hashlib import md5
37
from .utils import lsmod, get_arch
39
from .DistUpgradeGettext import gettext as _
40
from janitor.plugincore.manager import PluginManager
42
class DistUpgradeQuirks(object):
44
This class collects the various quirks handlers that can
45
be hooked into to fix/work around issues that the individual
49
def __init__(self, controller, config):
50
self.controller = controller
51
self._view = controller._view
53
self.uname = Popen(["uname","-r"], stdout=PIPE,
54
universal_newlines=True).communicate()[0].strip()
55
self.arch = get_arch()
56
self.plugin_manager = PluginManager(self.controller, ["./plugins"])
58
# the quirk function have the name:
59
# $Name (e.g. PostUpgrade)
60
# $todist$Name (e.g. intrepidPostUpgrade)
61
# $from_$fromdist$Name (e.g. from_dapperPostUpgrade)
62
def run(self, quirksName):
64
Run the specific quirks handler, the follow handlers are supported:
65
- PreCacheOpen: run *before* the apt cache is opened the first time
66
to set options that affect the cache
67
- PostInitialUpdate: run *before* the sources.list is rewritten but
68
after a initial apt-get update
69
- PostDistUpgradeCache: run *after* the dist-upgrade was calculated
71
- StartUpgrade: before the first package gets installed (but the
73
- PostUpgrade: run *after* the upgrade is finished successfully and
74
packages got installed
75
- PostCleanup: run *after* the cleanup (orphaned etc) is finished
77
# we do not run any quirks in partialUpgrade mode
78
if self.controller._partialUpgrade:
79
logging.info("not running quirks in partialUpgrade mode")
81
# first check for matching plugins
84
"%s%s" % (self.config.get("Sources","To"), quirksName),
85
"from_%s%s" % (self.config.get("Sources","From"), quirksName)
87
for plugin in self.plugin_manager.get_plugins(condition):
88
logging.debug("running quirks plugin %s" % plugin)
89
plugin.do_cleanup_cruft()
91
# run the handler that is common to all dists
92
funcname = "%s" % quirksName
93
func = getattr(self, funcname, None)
95
logging.debug("quirks: running %s" % funcname)
98
# run the quirksHandler to-dist
99
funcname = "%s%s" % (self.config.get("Sources","To"), quirksName)
100
func = getattr(self, funcname, None)
102
logging.debug("quirks: running %s" % funcname)
105
# now run the quirksHandler from_${FROM-DIST}Quirks
106
funcname = "from_%s%s" % (self.config.get("Sources","From"), quirksName)
107
func = getattr(self, funcname, None)
109
logging.debug("quirks: running %s" % funcname)
112
# individual quirks handler that run *before* the cache is opened
113
def PreCacheOpen(self):
114
""" run before the apt cache is opened the first time """
115
logging.debug("running Quirks.PreCacheOpen")
117
def oneiricPreCacheOpen(self):
118
logging.debug("running Quirks.oneiricPreCacheOpen")
119
# enable i386 multiach temporarely during the upgrade if on amd64
120
# this needs to be done very early as libapt caches the result
121
# of the "getArchitectures()" call in aptconfig and its not possible
122
# currently to invalidate this cache
123
if apt.apt_pkg.config.find("Apt::Architecture") == "amd64":
124
logging.debug("multiarch: enabling i386 as a additional architecture")
125
apt.apt_pkg.config.set("Apt::Architectures::", "i386")
126
# increase case size to workaround bug in natty apt that
127
# may cause segfault on cache grow
128
apt.apt_pkg.config.set("APT::Cache-Start", str(48*1024*1024))
131
# individual quirks handler when the dpkg run is finished ---------
132
def PostCleanup(self):
133
" run after cleanup "
134
logging.debug("running Quirks.PostCleanup")
136
def from_dapperPostUpgrade(self):
137
" this works around quirks for dapper->hardy upgrades "
138
logging.debug("running Controller.from_dapperQuirks handler")
140
self._checkAdminGroup()
142
def intrepidPostUpgrade(self):
143
" this applies rules for the hardy->intrepid upgrade "
144
logging.debug("running Controller.intrepidQuirks handler")
145
self._addRelatimeToFstab()
147
def gutsyPostUpgrade(self):
148
""" this function works around quirks in the feisty->gutsy upgrade """
149
logging.debug("running Controller.gutsyQuirks handler")
151
def feistyPostUpgrade(self):
152
""" this function works around quirks in the edgy->feisty upgrade """
153
logging.debug("running Controller.feistyQuirks handler")
155
self._checkAdminGroup()
157
def karmicPostUpgrade(self):
158
""" this function works around quirks in the jaunty->karmic upgrade """
159
logging.debug("running Controller.karmicPostUpgrade handler")
160
self._ntfsFstabFixup()
161
self._checkLanguageSupport()
163
# quirks when run when the initial apt-get update was run ----------------
164
def from_lucidPostInitialUpdate(self):
165
""" Quirks that are run before the sources.list is updated to the
166
new distribution when upgrading from a lucid system (either
167
to maverick or the new LTS)
169
logging.debug("running %s" % sys._getframe().f_code.co_name)
170
# systems < i686 will not upgrade
171
self._test_and_fail_on_non_i686()
172
self._test_and_warn_on_i8xx()
174
def oneiricPostInitialUpdate(self):
175
self._test_and_warn_on_i8xx()
177
def lucidPostInitialUpdate(self):
178
""" quirks that are run before the sources.list is updated to lucid """
179
logging.debug("running %s" % sys._getframe().f_code.co_name)
180
# upgrades on systems with < arvm6 CPUs will break
181
self._test_and_fail_on_non_arm_v6()
182
# vserver+upstart are problematic
183
self._test_and_warn_if_vserver()
184
# fglrx dropped support for some cards
185
self._test_and_warn_on_dropped_fglrx_support()
187
# quirks when the cache upgrade calculation is finished -------------------
188
def from_dapperPostDistUpgradeCache(self):
189
self.hardyPostDistUpgradeCache()
190
self.gutsyPostDistUpgradeCache()
191
self.feistyPostDistUpgradeCache()
192
self.edgyPostDistUpgradeCache()
194
def from_hardyPostDistUpgradeCache(self):
195
""" this function works around quirks in upgrades from hardy """
196
logging.debug("running %s" % sys._getframe().f_code.co_name)
197
# ensure 386 -> generic transition happens
198
self._kernel386TransitionCheck()
199
# ensure kubuntu-kde4-desktop transition
200
self._kubuntuDesktopTransition()
201
# evms got removed after hardy, warn and abort
202
if self._usesEvmsInMounts():
203
logging.error("evms in use in /etc/fstab")
204
self._view.error(_("evms in use"),
205
_("Your system uses the 'evms' volume manager "
207
"The 'evms' software is no longer supported, "
208
"please switch it off and run the upgrade "
209
"again when this is done."))
210
self.controller.abort()
211
# check if "wl" module is loaded and if so, install bcmwl-kernel-source
212
self._checkAndInstallBroadcom()
213
# langpacks got re-organized in 9.10
214
self._dealWithLanguageSupportTransition()
215
# nvidia-71, nvidia-96 got dropped
216
self._test_and_warn_on_old_nvidia()
217
# new nvidia needs a CPU with sse support
218
self._test_and_warn_on_nvidia_and_no_sse()
220
def nattyPostDistUpgradeCache(self):
222
this function works around quirks in the
223
maverick -> natty cache upgrade calculation
225
self._add_kdegames_card_extra_if_installed()
227
def maverickPostDistUpgradeCache(self):
229
this function works around quirks in the
230
lucid->maverick upgrade calculation
232
self._add_extras_repository()
233
self._gutenprint_fixup()
235
def karmicPostDistUpgradeCache(self):
237
this function works around quirks in the
238
jaunty->karmic upgrade calculation
240
# check if "wl" module is loaded and if so, install
241
# bcmwl-kernel-source (this is needed for lts->lts as well)
242
self._checkAndInstallBroadcom()
243
self._dealWithLanguageSupportTransition()
244
self._kernel386TransitionCheck()
245
self._mysqlClusterCheck()
247
def jauntyPostDistUpgradeCache(self):
249
this function works around quirks in the
250
intrepid->jaunty upgrade calculation
252
logging.debug("running %s" % sys._getframe().f_code.co_name)
253
# bug 332328 - make sure pidgin-libnotify is upgraded
254
for pkg in ["pidgin-libnotify"]:
255
if (pkg in self.controller.cache and
256
self.controller.cache[pkg].is_installed and
257
not self.controller.cache[pkg].marked_upgrade):
258
logging.debug("forcing '%s' upgrade" % pkg)
259
self.controller.cache[pkg].mark_upgrade()
260
# deal with kipi/gwenview/kphotoalbum
261
for pkg in ["gwenview","digikam"]:
262
if (pkg in self.controller.cache and
263
self.controller.cache[pkg].is_installed and
264
not self.controller.cache[pkg].marked_upgrade):
265
logging.debug("forcing libkipi '%s' upgrade" % pkg)
266
if "libkipi0" in self.controller.cache:
267
logging.debug("removing libkipi0)")
268
self.controller.cache["libkipi0"].mark_delete()
269
self.controller.cache[pkg].mark_upgrade()
271
def intrepidPostDistUpgradeCache(self):
273
this function works around quirks in the
274
hardy->intrepid upgrade
276
logging.debug("running %s" % sys._getframe().f_code.co_name)
277
# kdelibs4-dev is unhappy (#279621)
278
fromp = "kdelibs4-dev"
280
if (fromp in self.controller.cache and
281
self.controller.cache[fromp].is_installed and
282
to in self.controller.cache):
283
self.controller.cache.mark_install(to, "kdelibs4-dev -> kdelibs5-dev transition")
285
def hardyPostDistUpgradeCache(self):
287
this function works around quirks in the
288
{dapper,gutsy}->hardy upgrade
290
logging.debug("running %s" % sys._getframe().f_code.co_name)
291
# deal with gnome-translator and help apt with the breaks
292
if ("nautilus" in self.controller.cache and
293
self.controller.cache["nautilus"].is_installed and
294
not self.controller.cache["nautilus"].marked_upgrade):
295
# uninstallable and gutsy apt is unhappy about this
296
# breaks because it wants to upgrade it and gives up
298
for broken in ("link-monitor-applet"):
299
if broken in self.controller.cache and self.controller.cache[broken].is_installed:
300
self.controller.cache[broken].mark_delete()
301
self.controller.cache["nautilus"].mark_install()
302
# evms gives problems, remove it if it is not in use
303
self._checkAndRemoveEvms()
304
# give the language-support-* packages a extra kick
305
# (if we have network, otherwise this will not work)
306
if self.config.get("Options","withNetwork") == "True":
307
for pkg in self.controller.cache:
308
if (pkg.name.startswith("language-support-") and
310
not pkg.marked_upgrade):
311
self.controller.cache.mark_install(pkg.name,"extra language-support- kick")
313
def gutsyPostDistUpgradeCache(self):
314
""" this function works around quirks in the feisty->gutsy upgrade """
315
logging.debug("running %s" % sys._getframe().f_code.co_name)
316
# lowlatency kernel flavour vanished from feisty->gutsy
318
(version, build, flavour) = self.uname.split("-")
319
if (flavour == 'lowlatency' or
322
kernel = "linux-image-generic"
323
if not (self.controller.cache[kernel].is_installed or self.controller.cache[kernel].marked_install):
324
logging.debug("Selecting new kernel '%s'" % kernel)
325
self.controller.cache[kernel].mark_install()
326
except Exception as e:
327
logging.warning("problem while transitioning lowlatency kernel (%s)" % e)
328
# fix feisty->gutsy utils-linux -> nfs-common transition (LP: #141559)
330
for line in open("/proc/mounts"):
332
if line == '' or line.startswith("#"):
335
(device, mount_point, fstype, options, a, b) = line.split()
336
except Exception as e:
337
logging.error("can't parse line '%s'" % line)
340
logging.debug("found nfs mount in line '%s', marking nfs-common for install " % line)
341
self.controller.cache["nfs-common"].mark_install()
343
except Exception as e:
344
logging.warning("problem while transitioning util-linux -> nfs-common (%s)" % e)
346
def feistyPostDistUpgradeCache(self):
347
""" this function works around quirks in the edgy->feisty upgrade """
348
logging.debug("running %s" % sys._getframe().f_code.co_name)
349
# ndiswrapper changed again *sigh*
350
for (fr, to) in [("ndiswrapper-utils-1.8","ndiswrapper-utils-1.9")]:
351
if fr in self.controller.cache and to in self.controller.cache:
352
if self.controller.cache[fr].is_installed and not self.controller.cache[to].marked_install:
354
self.controller.cache.mark_install(to,"%s->%s quirk upgrade rule" % (fr, to))
355
except SystemError as e:
356
logging.warning("Failed to apply %s->%s install (%s)" % (fr, to, e))
359
def edgyPostDistUpgradeCache(self):
360
""" this function works around quirks in the dapper->edgy upgrade """
361
logging.debug("running %s" % sys._getframe().f_code.co_name)
362
for pkg in self.controller.cache:
363
# deal with the python2.4-$foo -> python-$foo transition
364
if (pkg.name.startswith("python2.4-") and
366
not pkg.marked_upgrade):
367
basepkg = "python-"+pkg.name[len("python2.4-"):]
368
if (basepkg in self.controller.cache and
369
self.controller.cache[basepkg].candidate and
370
self.controller.cache[basepkg].candidate.downloadable and
371
not self.controller.cache[basepkg].marked_install):
373
self.controller.cache.mark_install(basepkg,
374
"python2.4->python upgrade rule")
375
except SystemError as e:
376
logging.debug("Failed to apply python2.4->python install: %s (%s)" % (basepkg, e))
377
# xserver-xorg-input-$foo gives us trouble during the upgrade too
378
if (pkg.name.startswith("xserver-xorg-input-") and
380
not pkg.marked_upgrade):
382
self.controller.cache.mark_install(pkg.name, "xserver-xorg-input fixup rule")
383
except SystemError as e:
384
logging.debug("Failed to apply fixup: %s (%s)" % (pkg.name, e))
386
# deal with held-backs that are unneeded
387
for pkgname in ["hpijs", "bzr", "tomboy"]:
388
if (pkgname in self.controller.cache and self.controller.cache[pkgname].is_installed and
389
self.controller.cache[pkgname].is_upgradable and not self.controller.cache[pkgname].marked_upgrade):
391
self.controller.cache.mark_install(pkgname,"%s quirk upgrade rule" % pkgname)
392
except SystemError as e:
393
logging.debug("Failed to apply %s install (%s)" % (pkgname,e))
394
# libgl1-mesa-dri from xgl.compiz.info (and friends) breaks the
395
# upgrade, work around this here by downgrading the package
396
if "libgl1-mesa-dri" in self.controller.cache:
397
pkg = self.controller.cache["libgl1-mesa-dri"]
398
# the version from the compiz repo has a "6.5.1+cvs20060824" ver
399
if (pkg.candidate is not None and pkg.installed is not None and
400
pkg.candidate.version == pkg.installed.version and
401
"+cvs2006" in pkg.candidate.version):
402
for ver in pkg._pkg.version_list:
403
# the "official" edgy version has "6.5.1~20060817-0ubuntu3"
404
if "~2006" in ver.ver_str:
405
# ensure that it is from a trusted repo
406
for (VerFileIter, index) in ver.file_list:
407
indexfile = self.controller.cache._list.find_index(VerFileIter)
408
if indexfile and indexfile.is_trusted:
409
logging.info("Forcing downgrade of libgl1-mesa-dri for xgl.compz.info installs")
410
self.controller.cache._depcache.set_candidate_ver(pkg._pkg, ver)
413
# deal with general if $foo is installed, install $bar
414
for (fr, to) in [("xserver-xorg-driver-all","xserver-xorg-video-all")]:
415
if fr in self.controller.cache and to in self.controller.cache:
416
if self.controller.cache[fr].is_installed and not self.controller.cache[to].marked_install:
418
self.controller.cache.mark_install(to,"%s->%s quirk upgrade rule" % (fr, to))
419
except SystemError as e:
420
logging.debug("Failed to apply %s->%s install (%s)" % (fr, to, e))
422
def dapperPostDistUpgradeCache(self):
423
""" this function works around quirks in the breezy->dapper upgrade """
424
logging.debug("running %s" % sys._getframe().f_code.co_name)
425
if ("nvidia-glx" in self.controller.cache and self.controller.cache["nvidia-glx"].is_installed and
426
"nvidia-settings" in self.controller.cache and self.controller.cache["nvidia-settings"].is_installed):
427
logging.debug("nvidia-settings and nvidia-glx is installed")
428
self.controller.cache.mark_remove("nvidia-settings")
429
self.controller.cache.mark_install("nvidia-glx")
431
# run right before the first packages get installed
432
def StartUpgrade(self):
434
self._removeOldApportCrashes()
435
self._removeBadMaintainerScripts()
436
self._killUpdateNotifier()
437
self._killKBluetooth()
438
self._killScreensaver()
439
self._pokeScreensaver()
440
self._stopDocvertConverter()
441
def oneiricStartUpgrade(self):
442
logging.debug("oneiric StartUpgrade quirks")
444
if (os.path.exists("/usr/sbin/update-grub") and
445
not os.path.exists("/etc/kernel/postinst.d/zz-update-grub")):
446
# create a version of zz-update-grub to avoid depending on
447
# the upgrade order. if that file is missing, we may end
448
# up generating a broken grub.cfg
449
targetdir = "/etc/kernel/postinst.d"
450
if not os.path.exists(targetdir):
451
os.makedirs(targetdir)
452
logging.debug("copying zz-update-grub into %s" % targetdir)
453
shutil.copy("zz-update-grub", targetdir)
454
os.chmod(os.path.join(targetdir, "zz-update-grub"), 0o755)
455
# enable multiarch permanently
456
if apt.apt_pkg.config.find("Apt::Architecture") == "amd64":
457
self._enable_multiarch(foreign_arch="i386")
459
def from_hardyStartUpgrade(self):
460
logging.debug("from_hardyStartUpgrade quirks")
462
def jauntyStartUpgrade(self):
463
self._createPycentralPkgRemove()
464
# hal/NM triggers problem, if the old (intrepid) hal gets
465
# triggered for a restart this causes NM to drop all connections
466
# because (old) hal thinks it has no devices anymore (LP: #327053)
467
ap = "/var/lib/dpkg/info/hal.postinst"
468
if os.path.exists(ap):
469
# intrepid md5 of hal.postinst (jaunty one is different)
470
# md5 jaunty 22c146857d751181cfe299a171fc11c9
471
md5sum = "146145275900af343d990a4dea968d7c"
472
if md5(open(ap).read()).hexdigest() == md5sum:
473
logging.debug("removing bad script '%s'" % ap)
477
def _get_pci_ids(self):
478
""" return a set of pci ids of the system (using lspci -n) """
481
p = subprocess.Popen(["lspci","-n"], stdout=subprocess.PIPE,
482
universal_newlines=True)
485
for line in p.communicate()[0].split("\n"):
487
lspci.add(line.split()[2])
490
def _test_and_warn_on_i8xx(self):
491
I8XX_PCI_IDS = ["8086:7121", # i810
499
lspci = self._get_pci_ids()
500
if set(I8XX_PCI_IDS).intersection(lspci):
501
res = self._view.askYesNoQuestion(
502
_("Your graphics hardware may not be fully supported in "
503
"Ubuntu 12.04 LTS."),
504
_("The support in Ubuntu 12.04 LTS for your Intel "
505
"graphics hardware is limited "
506
"and you may encounter problems after the upgrade. "
507
"For more information see "
508
"https://wiki.ubuntu.com/X/Bugs/UpdateManagerWarningForI8xx "
509
"Do you want to continue with the upgrade?")
512
self.controller.abort()
514
def _test_and_warn_on_nvidia_and_no_sse(self):
517
# check if we have sse
518
cache = self.controller.cache
519
for pkgname in ["nvidia-glx-180", "nvidia-glx-185", "nvidia-glx-195"]:
520
if (pkgname in cache and
521
cache[pkgname].marked_install and
522
self._checkVideoDriver("nvidia")):
523
logging.debug("found %s video driver" % pkgname)
524
if not self._cpuHasSSESupport():
525
logging.warning("nvidia driver that needs SSE but cpu has no SSE support")
526
res = self._view.askYesNoQuestion(_("Upgrading may reduce desktop "
527
"effects, and performance in games "
528
"and other graphically intensive "
530
_("This computer is currently using "
531
"the NVIDIA 'nvidia' "
533
"No version of this driver is "
534
"available that works with your "
535
"video card in Ubuntu "
536
"10.04 LTS.\n\nDo you want to continue?"))
538
self.controller.abort()
539
# if the user continue, do not install the broken driver
540
# so that we can transiton him to the free "nv" one after
542
self.controller.cache[pkgname].mark_keep()
545
def _test_and_warn_on_old_nvidia(self):
546
""" nvidia-glx-71 and -96 are no longer in the archive since 8.10 """
547
# now check for nvidia and show a warning if needed
548
cache = self.controller.cache
549
for pkgname in ["nvidia-glx-71","nvidia-glx-96"]:
550
if (pkgname in cache and
551
cache[pkgname].marked_install and
552
self._checkVideoDriver("nvidia")):
553
logging.debug("found %s video driver" % pkgname)
554
res = self._view.askYesNoQuestion(_("Upgrading may reduce desktop "
555
"effects, and performance in games "
556
"and other graphically intensive "
558
_("This computer is currently using "
559
"the NVIDIA 'nvidia' "
561
"No version of this driver is "
562
"available that works with your "
563
"video card in Ubuntu "
564
"10.04 LTS.\n\nDo you want to continue?"))
566
self.controller.abort()
567
# if the user continue, do not install the broken driver
568
# so that we can transiton him to the free "nv" one after
570
self.controller.cache[pkgname].mark_keep()
572
def _test_and_warn_on_dropped_fglrx_support(self):
574
Some cards are no longer supported by fglrx. Check if that
577
# this is to deal with the fact that support for some of the cards
578
# that fglrx used to support got dropped
579
if (self._checkVideoDriver("fglrx") and
580
not self._supportInModaliases("fglrx")):
581
res = self._view.askYesNoQuestion(_("Upgrading may reduce desktop "
582
"effects, and performance in games "
583
"and other graphically intensive "
585
_("This computer is currently using "
586
"the AMD 'fglrx' graphics driver. "
587
"No version of this driver is "
588
"available that works with your "
589
"hardware in Ubuntu "
590
"10.04 LTS.\n\nDo you want to continue?"))
592
self.controller.abort()
593
# if the user wants to continue we remove the fglrx driver
594
# here because its no use (no support for this card)
595
logging.debug("remove xorg-driver-fglrx,xorg-driver-fglrx-envy,fglrx-kernel-source")
596
l=self.controller.config.getlist("Distro","PostUpgradePurge")
597
l.append("xorg-driver-fglrx")
598
l.append("xorg-driver-fglrx-envy")
599
l.append("fglrx-kernel-source")
600
l.append("fglrx-amdcccle")
601
l.append("xorg-driver-fglrx-dev")
602
l.append("libamdxvba1")
603
self.controller.config.set("Distro","PostUpgradePurge",",".join(l))
605
def _test_and_fail_on_non_i686(self):
607
Test and fail if the cpu is not i686 or more or if its a newer
608
CPU but does not have the cmov feature (LP: #587186)
611
if self.arch == "i386":
612
logging.debug("checking for i586 CPU")
613
if not self._cpu_is_i686_and_has_cmov():
614
logging.error("not a i686 or no cmov")
615
summary = _("No i686 CPU")
616
msg = _("Your system uses an i586 CPU or a CPU that does "
617
"not have the 'cmov' extension. "
618
"All packages were built with "
619
"optimizations requiring i686 as the "
620
"minimal architecture. It is not possible to "
621
"upgrade your system to a new Ubuntu release "
622
"with this hardware.")
623
self._view.error(summary, msg)
624
self.controller.abort()
626
def _cpu_is_i686_and_has_cmov(self, cpuinfo_path="/proc/cpuinfo"):
627
if not os.path.exists(cpuinfo_path):
628
logging.error("cannot open %s ?!?" % cpuinfo_path)
630
cpuinfo = open(cpuinfo_path).read()
632
if re.search("^cpu family\s*:\s*[345]\s*", cpuinfo, re.MULTILINE):
633
logging.debug("found cpu family [345], no i686+")
635
# check flags for cmov
636
match = re.search("^flags\s*:\s*(.*)", cpuinfo, re.MULTILINE)
638
if not "cmov" in match.group(1).split():
639
logging.debug("found flags '%s'" % match.group(1))
640
logging.debug("can not find cmov in flags")
645
def _test_and_fail_on_non_arm_v6(self):
647
Test and fail if the cpu is not a arm v6 or greater,
648
from 9.10 on we do no longer support those CPUs
650
if self.arch == "armel":
651
if not self._checkArmCPU():
652
self._view.error(_("No ARMv6 CPU"),
653
_("Your system uses an ARM CPU that is older "
654
"than the ARMv6 architecture. "
655
"All packages in karmic were built with "
656
"optimizations requiring ARMv6 as the "
657
"minimal architecture. It is not possible to "
658
"upgrade your system to a new Ubuntu release "
659
"with this hardware."))
660
self.controller.abort()
662
def _test_and_warn_if_vserver(self):
664
upstart and vserver environments are not a good match, warn
667
# verver test (LP: #454783), see if there is a init around
671
logging.warn("no init found")
672
res = self._view.askYesNoQuestion(
673
_("No init available"),
674
_("Your system appears to be a virtualised environment "
675
"without an init daemon, e.g. Linux-VServer. "
676
"Ubuntu 10.04 LTS cannot function within this type of "
677
"environment, requiring an update to your virtual "
678
"machine configuration first.\n\n"
679
"Are you sure you want to continue?"))
681
self.controller.abort()
682
self._view.processEvents()
684
def _kubuntuDesktopTransition(self):
686
check if a key depends of kubuntu-kde4-desktop is installed
687
and transition in this case as well
690
frompkg = "kubuntu-kde4-desktop"
691
topkg = "kubuntu-desktop"
692
if self.config.getlist(frompkg,"KeyDependencies"):
694
for pkg in self.config.getlist(frompkg,"KeyDependencies"):
695
deps_found &= (pkg in self.controller.cache and
696
self.controller.cache[pkg].is_installed)
698
logging.debug("transitioning %s to %s (via key depends)" % (frompkg, topkg))
699
self.controller.cache[topkg].mark_install()
701
def _mysqlClusterCheck(self):
703
check if ndb clustering is used and do not upgrade mysql
704
if it is (LP: #450837)
706
logging.debug("_mysqlClusterCheck")
707
if ("mysql-server" in self.controller.cache and
708
self.controller.cache["mysql-server"].is_installed):
709
# taken from the mysql-server-5.1.preinst
710
ret = subprocess.call([
711
"egrep", "-q", "-i", "-r",
712
"^[^#]*ndb.connectstring|^[:space:]*\[[:space:]*ndb_mgmd",
714
logging.debug("egrep returned %s" % ret)
715
# if clustering is used, do not upgrade to 5.1 and
716
# remove mysql-{server,client}
717
# metapackage and upgrade the 5.0 packages
719
logging.debug("mysql clustering in use, do not upgrade to 5.1")
720
for pkg in ("mysql-server", "mysql-client"):
721
self.controller.cache.mark_remove(pkg, "clustering in use")
722
# mark mysql-{server,client}-5.0 as manual install (#453513)
723
depcache = self.controller.cache._depcache
724
for pkg in ["mysql-server-5.0", "mysql-client-5.0"]:
725
if pkg.is_installed and depcache.is_auto_installed(pkg._pkg):
726
logging.debug("marking '%s' manual installed" % pkg.name)
729
depcache.Mark_install(pkg._pkg, autoInstDeps, fromUser)
731
self.controller.cache.mark_upgrade("mysql-server", "no clustering in use")
733
def _checkArmCPU(self):
735
parse /proc/cpuinfo and search for ARMv6 or greater
737
logging.debug("checking for ARM CPU version")
738
if not os.path.exists("/proc/cpuinfo"):
739
logging.error("cannot open /proc/cpuinfo ?!?")
741
cpuinfo = open("/proc/cpuinfo")
742
if re.search("^Processor\s*:\s*ARMv[45]", cpuinfo.read(), re.MULTILINE):
746
def _dealWithLanguageSupportTransition(self):
748
In karmic the language-support-translations-* metapackages
749
are gone and the direct dependencies will get marked for
750
auto removal - mark them as manual instead
752
logging.debug("language-support-translations-* transition")
753
for pkg in self.controller.cache:
754
depcache = self.controller.cache._depcache
755
if (pkg.name.startswith("language-support-translations") and
757
for dp_or in pkg.installed.dependencies:
758
for dpname in dp_or.or_dependencies:
759
dp = self.controller.cache[dpname.name]
760
if dp.is_installed and depcache.is_auto_installed(dp._pkg):
761
logging.debug("marking '%s' manual installed" % dp.name)
764
depcache.mark_install(dp._pkg, autoInstDeps, fromUser)
766
def _checkLanguageSupport(self):
768
check if the language support is fully installed and if
769
not generate a update-notifier note on next login
771
if not os.path.exists("/usr/bin/check-language-support"):
772
logging.debug("no check-language-support available")
774
p = subprocess.Popen(["check-language-support"],
775
stdout=subprocess.PIPE, universal_newlines=True)
776
for pkgname in p.communicate()[0].split():
777
if (pkgname in self.controller.cache and
778
not self.controller.cache[pkgname].is_installed):
779
logging.debug("language support package '%s' missing" % pkgname)
780
# check if kde/gnome and copy language-selector note
781
base = "/usr/share/language-support/"
782
target = "/var/lib/update-notifier/user.d"
783
for p in ("incomplete-language-support-gnome.note",
784
"incomplete-language-support-qt.note"):
785
if os.path.exists(os.path.join(base,p)):
786
shutil.copy(os.path.join(base,p), target)
789
def _checkAndInstallBroadcom(self):
791
check for the 'wl' kernel module and install bcmwl-kernel-source
792
if the module is loaded
794
logging.debug("checking for 'wl' module")
796
self.controller.cache.mark_install("bcmwl-kernel-source",
797
"'wl' module found in lsmod")
799
def _stopApparmor(self):
800
""" /etc/init.d/apparmor stop (see bug #559433)"""
801
if os.path.exists("/etc/init.d/apparmor"):
802
logging.debug("/etc/init.d/apparmor stop")
803
subprocess.call(["/etc/init.d/apparmor","stop"])
804
def _stopDocvertConverter(self):
805
" /etc/init.d/docvert-converter stop (see bug #450569)"
806
if os.path.exists("/etc/init.d/docvert-converter"):
807
logging.debug("/etc/init.d/docvert-converter stop")
808
subprocess.call(["/etc/init.d/docvert-converter","stop"])
809
def _killUpdateNotifier(self):
810
"kill update-notifier"
811
# kill update-notifier now to suppress reboot required
812
if os.path.exists("/usr/bin/killall"):
813
logging.debug("killing update-notifier")
814
subprocess.call(["killall","-q","update-notifier"])
815
def _killKBluetooth(self):
816
"""killall kblueplugd kbluetooth (riddel requested it)"""
817
if os.path.exists("/usr/bin/killall"):
818
logging.debug("killing kblueplugd kbluetooth4")
819
subprocess.call(["killall", "-q", "kblueplugd", "kbluetooth4"])
820
def _killScreensaver(self):
821
"""killall gnome-screensaver """
822
if os.path.exists("/usr/bin/killall"):
823
logging.debug("killing gnome-screensaver")
824
subprocess.call(["killall", "-q", "gnome-screensaver"])
825
def _pokeScreensaver(self):
826
if os.path.exists("/usr/bin/xdg-screensaver") and os.environ.get('DISPLAY') :
827
logging.debug("setup poke timer for the scrensaver")
829
self._poke = subprocess.Popen(
830
"while true; do /usr/bin/xdg-screensaver reset >/dev/null 2>&1; sleep 30; done",
832
atexit.register(self._stopPokeScreensaver)
834
logging.exception("failed to setup screensaver poke")
835
def _stopPokeScreensaver(self):
839
self._poke.terminate()
840
res = self._poke.wait()
842
logging.exception("failed to stop screensaver poke")
845
def _removeBadMaintainerScripts(self):
846
" remove bad/broken maintainer scripts (last resort) "
847
# apache: workaround #95325 (edgy->feisty)
848
# pango-libthai #103384 (edgy->feisty)
849
bad_scripts = ["/var/lib/dpkg/info/apache2-common.prerm",
850
"/var/lib/dpkg/info/pango-libthai.postrm",
852
for ap in bad_scripts:
853
if os.path.exists(ap):
854
logging.debug("removing bad script '%s'" % ap)
857
def _createPycentralPkgRemove(self):
859
intrepid->jaunty, create /var/lib/pycentral/pkgremove flag file
860
to help python-central so that it removes all preinst links
863
logging.debug("adding pkgremove file")
864
if not os.path.exists("/var/lib/pycentral/"):
865
os.makedirs("/var/lib/pycentral")
866
open("/var/lib/pycentral/pkgremove","w")
868
def _removeOldApportCrashes(self):
869
" remove old apport crash files "
871
for f in glob.glob("/var/crash/*.crash"):
872
logging.debug("removing old crash file '%s'" % f)
874
except Exception as e:
875
logging.warning("error during unlink of old crash files (%s)" % e)
877
def _cpuHasSSESupport(self, cpuinfo="/proc/cpuinfo"):
878
" helper that checks if the given cpu has sse support "
879
if not os.path.exists(cpuinfo):
881
for line in open(cpuinfo):
882
if line.startswith("flags") and not " sse" in line:
886
def _usesEvmsInMounts(self):
887
" check if evms is used in /proc/mounts "
888
logging.debug("running _usesEvmsInMounts")
889
for line in open("/proc/mounts"):
891
if line == '' or line.startswith("#"):
894
(device, mount_point, fstype, options, a, b) = line.split()
896
logging.error("can't parse line '%s'" % line)
899
logging.debug("found evms device in line '%s', skipping " % line)
903
def _checkAndRemoveEvms(self):
904
" check if evms is in use and if not, remove it "
905
logging.debug("running _checkAndRemoveEvms")
906
if self._usesEvmsInMounts():
908
# if not in use, nuke it
909
for pkg in ["evms","libevms-2.5","libevms-dev",
910
"evms-ncurses", "evms-ha",
912
"evms-gui", "evms-cli",
914
if pkg in self.controller.cache and self.controller.cache[pkg].is_installed:
915
self.controller.cache[pkg].mark_delete()
918
def _addRelatimeToFstab(self):
919
" add the relatime option to ext2/ext3 filesystems on upgrade "
920
logging.debug("_addRelatime")
923
for line in open("/etc/fstab"):
925
if line == '' or line.startswith("#"):
929
(device, mount_point, fstype, options, a, b) = line.split()
931
logging.error("can't parse line '%s'" % line)
934
if (("ext2" in fstype or
935
"ext3" in fstype) and
936
(not "noatime" in options) and
937
(not "relatime" in options) ):
938
logging.debug("adding 'relatime' to line '%s' " % line)
939
line = line.replace(options,"%s,relatime" % options)
940
logging.debug("replaced line is '%s' " % line)
943
# we have converted a line
945
logging.debug("writing new /etc/fstab")
946
f=open("/etc/fstab.intrepid","w")
947
f.write("\n".join(lines))
948
# add final newline (see LP: #279093)
951
os.rename("/etc/fstab.intrepid","/etc/fstab")
954
def _ntfsFstabFixup(self, fstab="/etc/fstab"):
955
"""change PASS 1 to 0 for ntfs entries (#441242)"""
956
logging.debug("_ntfsFstabFixup")
959
for line in open(fstab):
961
if line == '' or line.startswith("#"):
965
(device, mount_point, fstype, options, fdump, fpass) = line.split()
967
logging.error("can't parse line '%s'" % line)
970
if ("ntfs" in fstype and fpass == "1"):
971
logging.debug("changing PASS for ntfs to 0 for '%s' " % line)
973
line = line[:-1] + "0"
975
logging.error("unexpected value in line")
976
logging.debug("replaced line is '%s' " % line)
979
# we have converted a line
982
logging.debug("writing new /etc/fstab")
983
f=open(fstab + suffix, "w")
984
f.write("\n".join(lines))
985
# add final newline (see LP: #279093)
988
os.rename(fstab+suffix, fstab)
992
def _rewriteFstab(self):
993
" convert /dev/{hd?,scd0} to /dev/cdrom for the feisty upgrade "
994
logging.debug("_rewriteFstab()")
997
# we have one cdrom to convert
998
for line in open("/etc/fstab"):
1000
if line == '' or line.startswith("#"):
1004
(device, mount_point, fstype, options, a, b) = line.split()
1006
logging.error("can't parse line '%s'" % line)
1009
# edgy kernel has /dev/cdrom -> /dev/hd?
1010
# feisty kernel (for a lot of chipsets) /dev/cdrom -> /dev/scd0
1011
# this breaks static mounting (LP#86424)
1013
# we convert here to /dev/cdrom only if current /dev/cdrom
1014
# points to the device in /etc/fstab already. this ensures
1015
# that we don't break anything or that we get it wrong
1016
# for systems with two (or more) cdroms. this is ok, because
1017
# we convert under the old kernel
1018
if ("iso9660" in fstype and
1019
device != "/dev/cdrom" and
1020
os.path.exists("/dev/cdrom") and
1021
os.path.realpath("/dev/cdrom") == device
1023
logging.debug("replacing '%s' " % line)
1024
line = line.replace(device,"/dev/cdrom")
1025
logging.debug("replaced line is '%s' " % line)
1028
# we have converted a line (otherwise we would have exited already)
1030
logging.debug("writing new /etc/fstab")
1031
shutil.copy("/etc/fstab","/etc/fstab.edgy")
1032
f=open("/etc/fstab","w")
1033
f.write("\n".join(lines))
1034
# add final newline (see LP: #279093)
1039
def _checkAdminGroup(self):
1040
" check if the current sudo user is in the admin group "
1041
logging.debug("_checkAdminGroup")
1044
admin_group = grp.getgrnam("admin").gr_mem
1045
except KeyError as e:
1046
logging.warning("System has no admin group (%s)" % e)
1047
subprocess.call(["addgroup","--system","admin"])
1050
admin_group = grp.getgrnam("admin").gr_mem
1051
except KeyError as e:
1052
logging.warning("adding the admin group failed (%s)" % e)
1054
# if the current SUDO_USER is not in the admin group
1055
# we add him - this is no security issue because
1056
# the user is already root so adding him to the admin group
1057
# does not change anything
1058
if ("SUDO_USER" in os.environ and
1059
not os.environ["SUDO_USER"] in admin_group):
1060
admin_user = os.environ["SUDO_USER"]
1061
logging.info("SUDO_USER=%s is not in admin group" % admin_user)
1062
cmd = ["usermod","-a","-G","admin",admin_user]
1063
res = subprocess.call(cmd)
1064
logging.debug("cmd: %s returned %i" % (cmd, res))
1066
def _checkVideoDriver(self, name):
1067
" check if the given driver is in use in xorg.conf "
1068
XORG="/etc/X11/xorg.conf"
1069
if not os.path.exists(XORG):
1071
for line in open(XORG):
1072
s=line.split("#")[0].strip()
1073
# check for fglrx driver entry
1074
if (s.lower().startswith("driver") and
1075
s.endswith('"%s"' % name)):
1079
def _applyPatches(self, patchdir="./patches"):
1081
helper that applies the patches in patchdir. the format is
1082
_path_to_file.md5sum
1084
and it will apply the diff to that file if the md5sum
1087
if not os.path.exists(patchdir):
1088
logging.debug("no patchdir")
1090
for f in os.listdir(patchdir):
1091
# skip, not a patch file, they all end with .$md5sum
1093
logging.debug("skipping '%s' (no '.')" % f)
1095
logging.debug("check if patch '%s' needs to be applied" % f)
1096
(encoded_path, md5sum, result_md5sum) = f.rsplit(".", 2)
1097
# FIXME: this is not clever and needs quoting support for
1098
# filenames with "_" in the name
1099
path = encoded_path.replace("_","/")
1100
logging.debug("target for '%s' is '%s' -> '%s'" % (
1101
f, encoded_path, path))
1102
# target does not exist
1103
if not os.path.exists(path):
1104
logging.debug("target '%s' does not exist" % path)
1106
# check the input md5sum, this is not strictly needed as patch()
1107
# will verify the result md5sum and discard the result if that
1108
# does not match but this will remove a misleading error in the
1111
with open(path, "rb") as fd:
1112
md5.update(fd.read())
1113
if md5.hexdigest() == result_md5sum:
1114
logging.debug("already at target hash, skipping '%s'" % path)
1116
elif md5.hexdigest() != md5sum:
1117
logging.warn("unexpected target md5sum, skipping: '%s'" % path)
1120
from .DistUpgradePatcher import patch
1122
patch(path, os.path.join(patchdir, f), result_md5sum)
1123
logging.info("applied '%s' successfully" % f)
1125
logging.exception("ed failed for '%s'" % f)
1127
def _supportInModaliases(self, pkgname, lspci=None):
1129
Check if pkgname will work on this hardware
1131
This helper will check with the modaliasesdir if the given
1132
pkg will work on this hardware (or the hardware given
1133
via the lspci argument)
1135
# get lspci info (if needed)
1137
lspci = self._get_pci_ids()
1139
if (not pkgname in self.controller.cache or
1140
not self.controller.cache[pkgname].candidate):
1141
logging.warn("can not find '%s' in cache")
1143
pkg = self.controller.cache[pkgname]
1144
for (module, pciid_list) in self._parse_modaliases_from_pkg_header(pkg.candidate.record):
1145
for pciid in pciid_list:
1146
m = re.match("pci:v0000(.+)d0000(.+)sv.*", pciid)
1148
matchid = "%s:%s" % (m.group(1), m.group(2))
1149
if matchid.lower() in lspci:
1150
logging.debug("found system pciid '%s' in modaliases" % matchid)
1152
logging.debug("checking for %s support in modaliases but none found" % pkgname)
1155
def _parse_modaliases_from_pkg_header(self, pkgrecord):
1156
""" return a list of (module1, (pciid, ...), (module2, (pciid, ...)))"""
1157
if not "Modaliases" in pkgrecord:
1161
for m in pkgrecord["Modaliases"].split(")"):
1165
(module, pciids) = m.split("(")
1166
modules.append ((module, [x.strip() for x in pciids.split(",")]))
1169
def _kernel386TransitionCheck(self):
1170
""" test if the current kernel is 386 and if the system is
1171
capable of using a generic one instead (#353534)
1173
logging.debug("_kernel386TransitionCheck")
1174
# we test first if one of 386 is installed
1175
# if so, check if the system could also work with -generic
1176
# (we get that from base-installer) and try to installed
1178
for pkgname in ["linux-386", "linux-image-386"]:
1179
if (pkgname in self.controller.cache and
1180
self.controller.cache[pkgname].is_installed):
1181
working_kernels = self.controller.cache.getKernelsFromBaseInstaller()
1182
upgrade_to = ["linux-generic", "linux-image-generic"]
1183
for pkgname in upgrade_to:
1184
if pkgname in working_kernels:
1185
logging.debug("386 kernel installed, but generic kernel will work on this machine")
1186
if self.controller.cache.mark_install(pkgname, "386 -> generic transition"):
1190
def _add_extras_repository(self):
1191
logging.debug("_add_extras_repository")
1192
cache = self.controller.cache
1193
if not "ubuntu-extras-keyring" in cache:
1194
logging.debug("no ubuntu-extras-keyring, no need to add repo")
1196
if not (cache["ubuntu-extras-keyring"].marked_install or
1197
cache["ubuntu-extras-keyring"].installed):
1198
logging.debug("ubuntu-extras-keyring not installed/marked_install")
1201
import aptsources.sourceslist
1202
sources = aptsources.sourceslist.SourcesList()
1203
for entry in sources:
1204
if "extras.ubuntu.com" in entry.uri:
1205
logging.debug("found extras.ubuntu.com, no need to add it")
1208
logging.info("no extras.ubuntu.com, adding it to sources.list")
1209
sources.add("deb","http://extras.ubuntu.com/ubuntu",
1210
self.controller.toDist, ["main"],
1211
"Third party developers repository")
1214
logging.exception("error adding extras.ubuntu.com")
1216
def _gutenprint_fixup(self):
1217
""" foomatic-db-gutenprint get removed during the upgrade,
1218
replace it with the compressed ijsgutenprint-ppds
1219
(context is foomatic-db vs foomatic-db-compressed-ppds)
1222
cache = self.controller.cache
1223
if ("foomatic-db-gutenprint" in cache and
1224
cache["foomatic-db-gutenprint"].marked_delete and
1225
"ijsgutenprint-ppds" in cache):
1226
logging.info("installing ijsgutenprint-ppds")
1228
"ijsgutenprint-ppds",
1229
"foomatic-db-gutenprint -> ijsgutenprint-ppds rule")
1231
logging.exception("_gutenprint_fixup failed")
1233
def _enable_multiarch(self, foreign_arch="i386"):
1234
""" enable multiarch via /etc/dpkg/dpkg.cfg.d/multiarch """
1235
cfg = "/etc/dpkg/dpkg.cfg.d/multiarch"
1236
if not os.path.exists(cfg):
1238
os.makedirs("/etc/dpkg/dpkg.cfg.d/")
1241
open(cfg, "w").write("foreign-architecture %s\n" % foreign_arch)
1243
def _add_kdegames_card_extra_if_installed(self):
1244
""" test if kdegames-card-data is installed and if so,
1245
add kdegames-card-data-extra so that users do not
1246
loose functionality (LP: #745396)
1249
cache = self.controller.cache
1250
if not ("kdegames-card-data" in cache or
1251
"kdegames-card-data-extra" in cache):
1253
if (cache["kdegames-card-data"].is_installed or
1254
cache["kdegames-card-data"].marked_install):
1256
"kdegames-card-data-extra",
1257
"kdegames-card-data -> k-c-d-extra transition")
1259
logging.exception("_add_kdegames_card_extra_if_installed failed")
1261
def ensure_recommends_are_installed_on_desktops(self):
1262
""" ensure that on a desktop install recommends are installed
1266
if not self.controller.serverMode:
1267
if not apt.apt_pkg.config.find_b("Apt::Install-Recommends"):
1268
logging.warn("Apt::Install-Recommends was disabled, enabling it just for the upgrade")
1269
apt.apt_pkg.config.set("Apt::Install-Recommends", "1")