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 computerjanitor.plugin 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).communicate()[0].strip()
54
self.arch = get_arch()
55
self.plugin_manager = PluginManager(self.controller, ["./plugins"])
57
# the quirk function have the name:
58
# $Name (e.g. PostUpgrade)
59
# $todist$Name (e.g. intrepidPostUpgrade)
60
# $from_$fromdist$Name (e.g. from_dapperPostUpgrade)
61
def run(self, quirksName):
63
Run the specific quirks handler, the follow handlers are supported:
64
- PreCacheOpen: run *before* the apt cache is opened the first time
65
to set options that affect the cache
66
- PostInitialUpdate: run *before* the sources.list is rewritten but
67
after a initial apt-get update
68
- PostDistUpgradeCache: run *after* the dist-upgrade was calculated
70
- StartUpgrade: before the first package gets installed (but the
72
- PostUpgrade: run *after* the upgrade is finished successfully and
73
packages got installed
74
- PostCleanup: run *after* the cleanup (orphaned etc) is finished
76
# we do not run any quirks in partialUpgrade mode
77
if self.controller._partialUpgrade:
78
logging.info("not running quirks in partialUpgrade mode")
80
# first check for matching plugins
83
"%s%s" % (self.config.get("Sources","To"), quirksName),
84
"from_%s%s" % (self.config.get("Sources","From"), quirksName)
86
for plugin in self.plugin_manager.get_plugins(condition):
87
logging.debug("running quirks plugin %s" % plugin)
88
plugin.do_cleanup_cruft()
90
# run the handler that is common to all dists
91
funcname = "%s" % quirksName
92
func = getattr(self, funcname, None)
94
logging.debug("quirks: running %s" % funcname)
97
# run the quirksHandler to-dist
98
funcname = "%s%s" % (self.config.get("Sources","To"), quirksName)
99
func = getattr(self, funcname, None)
101
logging.debug("quirks: running %s" % funcname)
104
# now run the quirksHandler from_${FROM-DIST}Quirks
105
funcname = "from_%s%s" % (self.config.get("Sources","From"), quirksName)
106
func = getattr(self, funcname, None)
108
logging.debug("quirks: running %s" % funcname)
111
# individual quirks handler that run *before* the cache is opened
112
def PreCacheOpen(self):
113
""" run before the apt cache is opened the first time """
114
logging.debug("running Quirks.PreCacheOpen")
116
def oneiricPreCacheOpen(self):
117
logging.debug("running Quirks.oneiricPreCacheOpen")
118
# enable i386 multiach temporarely during the upgrade if on amd64
119
# this needs to be done very early as libapt caches the result
120
# of the "getArchitectures()" call in aptconfig and its not possible
121
# currently to invalidate this cache
122
if apt.apt_pkg.config.find("Apt::Architecture") == "amd64":
123
logging.debug("multiarch: enabling i386 as a additional architecture")
124
apt.apt_pkg.config.set("Apt::Architectures::", "i386")
125
# increase case size to workaround bug in natty apt that
126
# may cause segfault on cache grow
127
apt.apt_pkg.config.set("APT::Cache-Start", str(48*1024*1024))
130
# individual quirks handler when the dpkg run is finished ---------
131
def PostCleanup(self):
132
" run after cleanup "
133
logging.debug("running Quirks.PostCleanup")
135
def from_dapperPostUpgrade(self):
136
" this works around quirks for dapper->hardy upgrades "
137
logging.debug("running Controller.from_dapperQuirks handler")
139
self._checkAdminGroup()
141
def intrepidPostUpgrade(self):
142
" this applies rules for the hardy->intrepid upgrade "
143
logging.debug("running Controller.intrepidQuirks handler")
144
self._addRelatimeToFstab()
146
def gutsyPostUpgrade(self):
147
""" this function works around quirks in the feisty->gutsy upgrade """
148
logging.debug("running Controller.gutsyQuirks handler")
150
def feistyPostUpgrade(self):
151
""" this function works around quirks in the edgy->feisty upgrade """
152
logging.debug("running Controller.feistyQuirks handler")
154
self._checkAdminGroup()
156
def karmicPostUpgrade(self):
157
""" this function works around quirks in the jaunty->karmic upgrade """
158
logging.debug("running Controller.karmicPostUpgrade handler")
159
self._ntfsFstabFixup()
160
self._checkLanguageSupport()
162
# quirks when run when the initial apt-get update was run ----------------
163
def from_lucidPostInitialUpdate(self):
164
""" Quirks that are run before the sources.list is updated to the
165
new distribution when upgrading from a lucid system (either
166
to maverick or the new LTS)
168
logging.debug("running %s" % sys._getframe().f_code.co_name)
169
# systems < i686 will not upgrade
170
self._test_and_fail_on_non_i686()
171
self._test_and_warn_on_i8xx()
173
def oneiricPostInitialUpdate(self):
174
self._test_and_warn_on_i8xx()
176
def lucidPostInitialUpdate(self):
177
""" quirks that are run before the sources.list is updated to lucid """
178
logging.debug("running %s" % sys._getframe().f_code.co_name)
179
# upgrades on systems with < arvm6 CPUs will break
180
self._test_and_fail_on_non_arm_v6()
181
# vserver+upstart are problematic
182
self._test_and_warn_if_vserver()
183
# fglrx dropped support for some cards
184
self._test_and_warn_on_dropped_fglrx_support()
186
# quirks when the cache upgrade calculation is finished -------------------
187
def from_dapperPostDistUpgradeCache(self):
188
self.hardyPostDistUpgradeCache()
189
self.gutsyPostDistUpgradeCache()
190
self.feistyPostDistUpgradeCache()
191
self.edgyPostDistUpgradeCache()
193
def from_hardyPostDistUpgradeCache(self):
194
""" this function works around quirks in upgrades from hardy """
195
logging.debug("running %s" % sys._getframe().f_code.co_name)
196
# ensure 386 -> generic transition happens
197
self._kernel386TransitionCheck()
198
# ensure kubuntu-kde4-desktop transition
199
self._kubuntuDesktopTransition()
200
# evms got removed after hardy, warn and abort
201
if self._usesEvmsInMounts():
202
logging.error("evms in use in /etc/fstab")
203
self._view.error(_("evms in use"),
204
_("Your system uses the 'evms' volume manager "
206
"The 'evms' software is no longer supported, "
207
"please switch it off and run the upgrade "
208
"again when this is done."))
209
self.controller.abort()
210
# check if "wl" module is loaded and if so, install bcmwl-kernel-source
211
self._checkAndInstallBroadcom()
212
# langpacks got re-organized in 9.10
213
self._dealWithLanguageSupportTransition()
214
# nvidia-71, nvidia-96 got dropped
215
self._test_and_warn_on_old_nvidia()
216
# new nvidia needs a CPU with sse support
217
self._test_and_warn_on_nvidia_and_no_sse()
219
def nattyPostDistUpgradeCache(self):
221
this function works around quirks in the
222
maverick -> natty cache upgrade calculation
224
self._add_kdegames_card_extra_if_installed()
226
def maverickPostDistUpgradeCache(self):
228
this function works around quirks in the
229
lucid->maverick upgrade calculation
231
self._add_extras_repository()
232
self._gutenprint_fixup()
234
def karmicPostDistUpgradeCache(self):
236
this function works around quirks in the
237
jaunty->karmic upgrade calculation
239
# check if "wl" module is loaded and if so, install
240
# bcmwl-kernel-source (this is needed for lts->lts as well)
241
self._checkAndInstallBroadcom()
242
self._dealWithLanguageSupportTransition()
243
self._kernel386TransitionCheck()
244
self._mysqlClusterCheck()
246
def jauntyPostDistUpgradeCache(self):
248
this function works around quirks in the
249
intrepid->jaunty upgrade calculation
251
logging.debug("running %s" % sys._getframe().f_code.co_name)
252
# bug 332328 - make sure pidgin-libnotify is upgraded
253
for pkg in ["pidgin-libnotify"]:
254
if (self.controller.cache.has_key(pkg) and
255
self.controller.cache[pkg].is_installed and
256
not self.controller.cache[pkg].marked_upgrade):
257
logging.debug("forcing '%s' upgrade" % pkg)
258
self.controller.cache[pkg].mark_upgrade()
259
# deal with kipi/gwenview/kphotoalbum
260
for pkg in ["gwenview","digikam"]:
261
if (self.controller.cache.has_key(pkg) and
262
self.controller.cache[pkg].is_installed and
263
not self.controller.cache[pkg].marked_upgrade):
264
logging.debug("forcing libkipi '%s' upgrade" % pkg)
265
if self.controller.cache.has_key("libkipi0"):
266
logging.debug("removing libkipi0)")
267
self.controller.cache["libkipi0"].mark_delete()
268
self.controller.cache[pkg].mark_upgrade()
270
def intrepidPostDistUpgradeCache(self):
272
this function works around quirks in the
273
hardy->intrepid upgrade
275
logging.debug("running %s" % sys._getframe().f_code.co_name)
276
# kdelibs4-dev is unhappy (#279621)
277
fromp = "kdelibs4-dev"
279
if (self.controller.cache.has_key(fromp) and
280
self.controller.cache[fromp].is_installed and
281
self.controller.cache.has_key(to)):
282
self.controller.cache.mark_install(to, "kdelibs4-dev -> kdelibs5-dev transition")
284
def hardyPostDistUpgradeCache(self):
286
this function works around quirks in the
287
{dapper,gutsy}->hardy upgrade
289
logging.debug("running %s" % sys._getframe().f_code.co_name)
290
# deal with gnome-translator and help apt with the breaks
291
if (self.controller.cache.has_key("nautilus") and
292
self.controller.cache["nautilus"].is_installed and
293
not self.controller.cache["nautilus"].marked_upgrade):
294
# uninstallable and gutsy apt is unhappy about this
295
# breaks because it wants to upgrade it and gives up
297
for broken in ("link-monitor-applet"):
298
if self.controller.cache.has_key(broken) and self.controller.cache[broken].is_installed:
299
self.controller.cache[broken].mark_delete()
300
self.controller.cache["nautilus"].mark_install()
301
# evms gives problems, remove it if it is not in use
302
self._checkAndRemoveEvms()
303
# give the language-support-* packages a extra kick
304
# (if we have network, otherwise this will not work)
305
if self.config.get("Options","withNetwork") == "True":
306
for pkg in self.controller.cache:
307
if (pkg.name.startswith("language-support-") and
309
not pkg.marked_upgrade):
310
self.controller.cache.mark_install(pkg.name,"extra language-support- kick")
312
def gutsyPostDistUpgradeCache(self):
313
""" this function works around quirks in the feisty->gutsy upgrade """
314
logging.debug("running %s" % sys._getframe().f_code.co_name)
315
# lowlatency kernel flavour vanished from feisty->gutsy
317
(version, build, flavour) = self.uname.split("-")
318
if (flavour == 'lowlatency' or
321
kernel = "linux-image-generic"
322
if not (self.controller.cache[kernel].is_installed or self.controller.cache[kernel].marked_install):
323
logging.debug("Selecting new kernel '%s'" % kernel)
324
self.controller.cache[kernel].mark_install()
325
except Exception as e:
326
logging.warning("problem while transitioning lowlatency kernel (%s)" % e)
327
# fix feisty->gutsy utils-linux -> nfs-common transition (LP: #141559)
329
for line in open("/proc/mounts"):
331
if line == '' or line.startswith("#"):
334
(device, mount_point, fstype, options, a, b) = line.split()
335
except Exception as e:
336
logging.error("can't parse line '%s'" % line)
339
logging.debug("found nfs mount in line '%s', marking nfs-common for install " % line)
340
self.controller.cache["nfs-common"].mark_install()
342
except Exception as e:
343
logging.warning("problem while transitioning util-linux -> nfs-common (%s)" % e)
345
def feistyPostDistUpgradeCache(self):
346
""" this function works around quirks in the edgy->feisty upgrade """
347
logging.debug("running %s" % sys._getframe().f_code.co_name)
348
# ndiswrapper changed again *sigh*
349
for (fr, to) in [("ndiswrapper-utils-1.8","ndiswrapper-utils-1.9")]:
350
if self.controller.cache.has_key(fr) and self.controller.cache.has_key(to):
351
if self.controller.cache[fr].is_installed and not self.controller.cache[to].marked_install:
353
self.controller.cache.mark_install(to,"%s->%s quirk upgrade rule" % (fr, to))
354
except SystemError as e:
355
logging.warning("Failed to apply %s->%s install (%s)" % (fr, to, e))
358
def edgyPostDistUpgradeCache(self):
359
""" this function works around quirks in the dapper->edgy upgrade """
360
logging.debug("running %s" % sys._getframe().f_code.co_name)
361
for pkg in self.controller.cache:
362
# deal with the python2.4-$foo -> python-$foo transition
363
if (pkg.name.startswith("python2.4-") and
365
not pkg.marked_upgrade):
366
basepkg = "python-"+pkg.name[len("python2.4-"):]
367
if (self.controller.cache.has_key(basepkg) and
368
self.controller.cache[basepkg].candidateDownloadable and
369
not self.controller.cache[basepkg].marked_install):
371
self.controller.cache.mark_install(basepkg,
372
"python2.4->python upgrade rule")
373
except SystemError as e:
374
logging.debug("Failed to apply python2.4->python install: %s (%s)" % (basepkg, e))
375
# xserver-xorg-input-$foo gives us trouble during the upgrade too
376
if (pkg.name.startswith("xserver-xorg-input-") and
378
not pkg.marked_upgrade):
380
self.controller.cache.mark_install(pkg.name, "xserver-xorg-input fixup rule")
381
except SystemError as e:
382
logging.debug("Failed to apply fixup: %s (%s)" % (pkg.name, e))
384
# deal with held-backs that are unneeded
385
for pkgname in ["hpijs", "bzr", "tomboy"]:
386
if (self.controller.cache.has_key(pkgname) and self.controller.cache[pkgname].is_installed and
387
self.controller.cache[pkgname].isUpgradable and not self.controller.cache[pkgname].marked_upgrade):
389
self.controller.cache.mark_install(pkgname,"%s quirk upgrade rule" % pkgname)
390
except SystemError as e:
391
logging.debug("Failed to apply %s install (%s)" % (pkgname,e))
392
# libgl1-mesa-dri from xgl.compiz.info (and friends) breaks the
393
# upgrade, work around this here by downgrading the package
394
if self.controller.cache.has_key("libgl1-mesa-dri"):
395
pkg = self.controller.cache["libgl1-mesa-dri"]
396
# the version from the compiz repo has a "6.5.1+cvs20060824" ver
397
if (pkg.candidateVersion == pkg.installedVersion and
398
"+cvs2006" in pkg.candidateVersion):
399
for ver in pkg._pkg.VersionList:
400
# the "official" edgy version has "6.5.1~20060817-0ubuntu3"
401
if "~2006" in ver.VerStr:
402
# ensure that it is from a trusted repo
403
for (VerFileIter, index) in ver.FileList:
404
indexfile = self.controller.cache._list.FindIndex(VerFileIter)
405
if indexfile and indexfile.IsTrusted:
406
logging.info("Forcing downgrade of libgl1-mesa-dri for xgl.compz.info installs")
407
self.controller.cache._depcache.SetCandidateVer(pkg._pkg, ver)
410
# deal with general if $foo is installed, install $bar
411
for (fr, to) in [("xserver-xorg-driver-all","xserver-xorg-video-all")]:
412
if self.controller.cache.has_key(fr) and self.controller.cache.has_key(to):
413
if self.controller.cache[fr].is_installed and not self.controller.cache[to].marked_install:
415
self.controller.cache.mark_install(to,"%s->%s quirk upgrade rule" % (fr, to))
416
except SystemError as e:
417
logging.debug("Failed to apply %s->%s install (%s)" % (fr, to, e))
419
def dapperPostDistUpgradeCache(self):
420
""" this function works around quirks in the breezy->dapper upgrade """
421
logging.debug("running %s" % sys._getframe().f_code.co_name)
422
if (self.controller.cache.has_key("nvidia-glx") and self.controller.cache["nvidia-glx"].is_installed and
423
self.controller.cache.has_key("nvidia-settings") and self.controller.cache["nvidia-settings"].is_installed):
424
logging.debug("nvidia-settings and nvidia-glx is installed")
425
self.controller.cache.mark_remove("nvidia-settings")
426
self.controller.cache.mark_install("nvidia-glx")
428
# run right before the first packages get installed
429
def StartUpgrade(self):
431
self._removeOldApportCrashes()
432
self._removeBadMaintainerScripts()
433
self._killUpdateNotifier()
434
self._killKBluetooth()
435
self._killScreensaver()
436
self._pokeScreensaver()
437
self._stopDocvertConverter()
438
def oneiricStartUpgrade(self):
439
logging.debug("oneiric StartUpgrade quirks")
441
if (os.path.exists("/usr/sbin/update-grub") and
442
not os.path.exists("/etc/kernel/postinst.d/zz-update-grub")):
443
# create a version of zz-update-grub to avoid depending on
444
# the upgrade order. if that file is missing, we may end
445
# up generating a broken grub.cfg
446
targetdir = "/etc/kernel/postinst.d"
447
if not os.path.exists(targetdir):
448
os.makedirs(targetdir)
449
logging.debug("copying zz-update-grub into %s" % targetdir)
450
shutil.copy("zz-update-grub", targetdir)
451
os.chmod(os.path.join(targetdir, "zz-update-grub"), 0o755)
452
# enable multiarch permanently
453
if apt.apt_pkg.config.find("Apt::Architecture") == "amd64":
454
self._enable_multiarch(foreign_arch="i386")
456
def from_hardyStartUpgrade(self):
457
logging.debug("from_hardyStartUpgrade quirks")
459
def jauntyStartUpgrade(self):
460
self._createPycentralPkgRemove()
461
# hal/NM triggers problem, if the old (intrepid) hal gets
462
# triggered for a restart this causes NM to drop all connections
463
# because (old) hal thinks it has no devices anymore (LP: #327053)
464
ap = "/var/lib/dpkg/info/hal.postinst"
465
if os.path.exists(ap):
466
# intrepid md5 of hal.postinst (jaunty one is different)
467
# md5 jaunty 22c146857d751181cfe299a171fc11c9
468
md5sum = "146145275900af343d990a4dea968d7c"
469
if md5(open(ap).read()).hexdigest() == md5sum:
470
logging.debug("removing bad script '%s'" % ap)
474
def _get_pci_ids(self):
475
""" return a set of pci ids of the system (using lspci -n) """
478
p = subprocess.Popen(["lspci","-n"],stdout=subprocess.PIPE)
481
for line in p.communicate()[0].split("\n"):
483
lspci.add(line.split()[2])
486
def _test_and_warn_on_i8xx(self):
487
I8XX_PCI_IDS = ["8086:7121", # i810
495
lspci = self._get_pci_ids()
496
if set(I8XX_PCI_IDS).intersection(lspci):
497
res = self._view.askYesNoQuestion(
498
_("Your graphics hardware may not be fully supported in "
499
"Ubuntu 12.04 LTS."),
500
_("The support in Ubuntu 12.04 LTS for your Intel "
501
"graphics hardware is limited "
502
"and you may encounter problems after the upgrade. "
503
"For more information see "
504
"https://wiki.ubuntu.com/X/Bugs/UpdateManagerWarningForI8xx "
505
"Do you want to continue with the upgrade?")
508
self.controller.abort()
510
def _test_and_warn_on_nvidia_and_no_sse(self):
513
# check if we have sse
514
cache = self.controller.cache
515
for pkgname in ["nvidia-glx-180", "nvidia-glx-185", "nvidia-glx-195"]:
516
if (cache.has_key(pkgname) and
517
cache[pkgname].marked_install and
518
self._checkVideoDriver("nvidia")):
519
logging.debug("found %s video driver" % pkgname)
520
if not self._cpuHasSSESupport():
521
logging.warning("nvidia driver that needs SSE but cpu has no SSE support")
522
res = self._view.askYesNoQuestion(_("Upgrading may reduce desktop "
523
"effects, and performance in games "
524
"and other graphically intensive "
526
_("This computer is currently using "
527
"the NVIDIA 'nvidia' "
529
"No version of this driver is "
530
"available that works with your "
531
"video card in Ubuntu "
532
"10.04 LTS.\n\nDo you want to continue?"))
534
self.controller.abort()
535
# if the user continue, do not install the broken driver
536
# so that we can transiton him to the free "nv" one after
538
self.controller.cache[pkgname].mark_keep()
541
def _test_and_warn_on_old_nvidia(self):
542
""" nvidia-glx-71 and -96 are no longer in the archive since 8.10 """
543
# now check for nvidia and show a warning if needed
544
cache = self.controller.cache
545
for pkgname in ["nvidia-glx-71","nvidia-glx-96"]:
546
if (cache.has_key(pkgname) and
547
cache[pkgname].marked_install and
548
self._checkVideoDriver("nvidia")):
549
logging.debug("found %s video driver" % pkgname)
550
res = self._view.askYesNoQuestion(_("Upgrading may reduce desktop "
551
"effects, and performance in games "
552
"and other graphically intensive "
554
_("This computer is currently using "
555
"the NVIDIA 'nvidia' "
557
"No version of this driver is "
558
"available that works with your "
559
"video card in Ubuntu "
560
"10.04 LTS.\n\nDo you want to continue?"))
562
self.controller.abort()
563
# if the user continue, do not install the broken driver
564
# so that we can transiton him to the free "nv" one after
566
self.controller.cache[pkgname].mark_keep()
568
def _test_and_warn_on_dropped_fglrx_support(self):
570
Some cards are no longer supported by fglrx. Check if that
573
# this is to deal with the fact that support for some of the cards
574
# that fglrx used to support got dropped
575
if (self._checkVideoDriver("fglrx") and
576
not self._supportInModaliases("fglrx")):
577
res = self._view.askYesNoQuestion(_("Upgrading may reduce desktop "
578
"effects, and performance in games "
579
"and other graphically intensive "
581
_("This computer is currently using "
582
"the AMD 'fglrx' graphics driver. "
583
"No version of this driver is "
584
"available that works with your "
585
"hardware in Ubuntu "
586
"10.04 LTS.\n\nDo you want to continue?"))
588
self.controller.abort()
589
# if the user wants to continue we remove the fglrx driver
590
# here because its no use (no support for this card)
591
logging.debug("remove xorg-driver-fglrx,xorg-driver-fglrx-envy,fglrx-kernel-source")
592
l=self.controller.config.getlist("Distro","PostUpgradePurge")
593
l.append("xorg-driver-fglrx")
594
l.append("xorg-driver-fglrx-envy")
595
l.append("fglrx-kernel-source")
596
l.append("fglrx-amdcccle")
597
l.append("xorg-driver-fglrx-dev")
598
l.append("libamdxvba1")
599
self.controller.config.set("Distro","PostUpgradePurge",",".join(l))
601
def _test_and_fail_on_non_i686(self):
603
Test and fail if the cpu is not i686 or more or if its a newer
604
CPU but does not have the cmov feature (LP: #587186)
607
if self.arch == "i386":
608
logging.debug("checking for i586 CPU")
609
if not self._cpu_is_i686_and_has_cmov():
610
logging.error("not a i686 or no cmov")
611
summary = _("No i686 CPU")
612
msg = _("Your system uses an i586 CPU or a CPU that does "
613
"not have the 'cmov' extension. "
614
"All packages were built with "
615
"optimizations requiring i686 as the "
616
"minimal architecture. It is not possible to "
617
"upgrade your system to a new Ubuntu release "
618
"with this hardware.")
619
self._view.error(summary, msg)
620
self.controller.abort()
622
def _cpu_is_i686_and_has_cmov(self, cpuinfo_path="/proc/cpuinfo"):
623
if not os.path.exists(cpuinfo_path):
624
logging.error("cannot open %s ?!?" % cpuinfo_path)
626
cpuinfo = open(cpuinfo_path).read()
628
if re.search("^cpu family\s*:\s*[345]\s*", cpuinfo, re.MULTILINE):
629
logging.debug("found cpu family [345], no i686+")
631
# check flags for cmov
632
match = re.search("^flags\s*:\s*(.*)", cpuinfo, re.MULTILINE)
634
if not "cmov" in match.group(1).split():
635
logging.debug("found flags '%s'" % match.group(1))
636
logging.debug("can not find cmov in flags")
641
def _test_and_fail_on_non_arm_v6(self):
643
Test and fail if the cpu is not a arm v6 or greater,
644
from 9.10 on we do no longer support those CPUs
646
if self.arch == "armel":
647
if not self._checkArmCPU():
648
self._view.error(_("No ARMv6 CPU"),
649
_("Your system uses an ARM CPU that is older "
650
"than the ARMv6 architecture. "
651
"All packages in karmic were built with "
652
"optimizations requiring ARMv6 as the "
653
"minimal architecture. It is not possible to "
654
"upgrade your system to a new Ubuntu release "
655
"with this hardware."))
656
self.controller.abort()
658
def _test_and_warn_if_vserver(self):
660
upstart and vserver environments are not a good match, warn
663
# verver test (LP: #454783), see if there is a init around
667
logging.warn("no init found")
668
res = self._view.askYesNoQuestion(
669
_("No init available"),
670
_("Your system appears to be a virtualised environment "
671
"without an init daemon, e.g. Linux-VServer. "
672
"Ubuntu 10.04 LTS cannot function within this type of "
673
"environment, requiring an update to your virtual "
674
"machine configuration first.\n\n"
675
"Are you sure you want to continue?"))
677
self.controller.abort()
678
self._view.processEvents()
680
def _kubuntuDesktopTransition(self):
682
check if a key depends of kubuntu-kde4-desktop is installed
683
and transition in this case as well
686
frompkg = "kubuntu-kde4-desktop"
687
topkg = "kubuntu-desktop"
688
if self.config.getlist(frompkg,"KeyDependencies"):
690
for pkg in self.config.getlist(frompkg,"KeyDependencies"):
691
deps_found &= (self.controller.cache.has_key(pkg) and
692
self.controller.cache[pkg].is_installed)
694
logging.debug("transitioning %s to %s (via key depends)" % (frompkg, topkg))
695
self.controller.cache[topkg].mark_install()
697
def _mysqlClusterCheck(self):
699
check if ndb clustering is used and do not upgrade mysql
700
if it is (LP: #450837)
702
logging.debug("_mysqlClusterCheck")
703
if (self.controller.cache.has_key("mysql-server") and
704
self.controller.cache["mysql-server"].is_installed):
705
# taken from the mysql-server-5.1.preinst
706
ret = subprocess.call([
707
"egrep", "-q", "-i", "-r",
708
"^[^#]*ndb.connectstring|^[:space:]*\[[:space:]*ndb_mgmd",
710
logging.debug("egrep returned %s" % ret)
711
# if clustering is used, do not upgrade to 5.1 and
712
# remove mysql-{server,client}
713
# metapackage and upgrade the 5.0 packages
715
logging.debug("mysql clustering in use, do not upgrade to 5.1")
716
for pkg in ("mysql-server", "mysql-client"):
717
self.controller.cache.mark_remove(pkg, "clustering in use")
718
# mark mysql-{server,client}-5.0 as manual install (#453513)
719
depcache = self.controller.cache._depcache
720
for pkg in ["mysql-server-5.0", "mysql-client-5.0"]:
721
if pkg.is_installed and depcache.IsAutoInstalled(pkg._pkg):
722
logging.debug("marking '%s' manual installed" % pkg.name)
725
depcache.Mark_install(pkg._pkg, autoInstDeps, fromUser)
727
self.controller.cache.mark_upgrade("mysql-server", "no clustering in use")
729
def _checkArmCPU(self):
731
parse /proc/cpuinfo and search for ARMv6 or greater
733
logging.debug("checking for ARM CPU version")
734
if not os.path.exists("/proc/cpuinfo"):
735
logging.error("cannot open /proc/cpuinfo ?!?")
737
cpuinfo = open("/proc/cpuinfo")
738
if re.search("^Processor\s*:\s*ARMv[45]", cpuinfo.read(), re.MULTILINE):
742
def _dealWithLanguageSupportTransition(self):
744
In karmic the language-support-translations-* metapackages
745
are gone and the direct dependencies will get marked for
746
auto removal - mark them as manual instead
748
logging.debug("language-support-translations-* transition")
749
for pkg in self.controller.cache:
750
depcache = self.controller.cache._depcache
751
if (pkg.name.startswith("language-support-translations") and
753
for dp_or in pkg.installedDependencies:
754
for dpname in dp_or.or_dependencies:
755
dp = self.controller.cache[dpname.name]
756
if dp.is_installed and depcache.IsAutoInstalled(dp._pkg):
757
logging.debug("marking '%s' manual installed" % dp.name)
760
depcache.mark_install(dp._pkg, autoInstDeps, fromUser)
762
def _checkLanguageSupport(self):
764
check if the language support is fully installed and if
765
not generate a update-notifier note on next login
767
if not os.path.exists("/usr/bin/check-language-support"):
768
logging.debug("no check-language-support available")
770
p = subprocess.Popen(["check-language-support"],stdout=subprocess.PIPE)
771
for pkgname in p.communicate()[0].split():
772
if (self.controller.cache.has_key(pkgname) and
773
not self.controller.cache[pkgname].is_installed):
774
logging.debug("language support package '%s' missing" % pkgname)
775
# check if kde/gnome and copy language-selector note
776
base = "/usr/share/language-support/"
777
target = "/var/lib/update-notifier/user.d"
778
for p in ("incomplete-language-support-gnome.note",
779
"incomplete-language-support-qt.note"):
780
if os.path.exists(os.path.join(base,p)):
781
shutil.copy(os.path.join(base,p), target)
784
def _checkAndInstallBroadcom(self):
786
check for the 'wl' kernel module and install bcmwl-kernel-source
787
if the module is loaded
789
logging.debug("checking for 'wl' module")
791
self.controller.cache.mark_install("bcmwl-kernel-source",
792
"'wl' module found in lsmod")
794
def _stopApparmor(self):
795
""" /etc/init.d/apparmor stop (see bug #559433)"""
796
if os.path.exists("/etc/init.d/apparmor"):
797
logging.debug("/etc/init.d/apparmor stop")
798
subprocess.call(["/etc/init.d/apparmor","stop"])
799
def _stopDocvertConverter(self):
800
" /etc/init.d/docvert-converter stop (see bug #450569)"
801
if os.path.exists("/etc/init.d/docvert-converter"):
802
logging.debug("/etc/init.d/docvert-converter stop")
803
subprocess.call(["/etc/init.d/docvert-converter","stop"])
804
def _killUpdateNotifier(self):
805
"kill update-notifier"
806
# kill update-notifier now to suppress reboot required
807
if os.path.exists("/usr/bin/killall"):
808
logging.debug("killing update-notifier")
809
subprocess.call(["killall","-q","update-notifier"])
810
def _killKBluetooth(self):
811
"""killall kblueplugd kbluetooth (riddel requested it)"""
812
if os.path.exists("/usr/bin/killall"):
813
logging.debug("killing kblueplugd kbluetooth4")
814
subprocess.call(["killall", "-q", "kblueplugd", "kbluetooth4"])
815
def _killScreensaver(self):
816
"""killall gnome-screensaver """
817
if os.path.exists("/usr/bin/killall"):
818
logging.debug("killing gnome-screensaver")
819
subprocess.call(["killall", "-q", "gnome-screensaver"])
820
def _pokeScreensaver(self):
821
if os.path.exists("/usr/bin/xdg-screensaver") and os.environ.get('DISPLAY') :
822
logging.debug("setup poke timer for the scrensaver")
824
self._poke = subprocess.Popen(
825
"while true; do /usr/bin/xdg-screensaver reset >/dev/null 2>&1; sleep 30; done",
827
atexit.register(self._stopPokeScreensaver)
829
logging.exception("failed to setup screensaver poke")
830
def _stopPokeScreensaver(self):
834
self._poke.terminate()
835
res = self._poke.wait()
837
logging.exception("failed to stop screensaver poke")
840
def _removeBadMaintainerScripts(self):
841
" remove bad/broken maintainer scripts (last resort) "
842
# apache: workaround #95325 (edgy->feisty)
843
# pango-libthai #103384 (edgy->feisty)
844
bad_scripts = ["/var/lib/dpkg/info/apache2-common.prerm",
845
"/var/lib/dpkg/info/pango-libthai.postrm",
847
for ap in bad_scripts:
848
if os.path.exists(ap):
849
logging.debug("removing bad script '%s'" % ap)
852
def _createPycentralPkgRemove(self):
854
intrepid->jaunty, create /var/lib/pycentral/pkgremove flag file
855
to help python-central so that it removes all preinst links
858
logging.debug("adding pkgremove file")
859
if not os.path.exists("/var/lib/pycentral/"):
860
os.makedirs("/var/lib/pycentral")
861
open("/var/lib/pycentral/pkgremove","w")
863
def _removeOldApportCrashes(self):
864
" remove old apport crash files "
866
for f in glob.glob("/var/crash/*.crash"):
867
logging.debug("removing old crash file '%s'" % f)
869
except Exception as e:
870
logging.warning("error during unlink of old crash files (%s)" % e)
872
def _cpuHasSSESupport(self, cpuinfo="/proc/cpuinfo"):
873
" helper that checks if the given cpu has sse support "
874
if not os.path.exists(cpuinfo):
876
for line in open(cpuinfo):
877
if line.startswith("flags") and not " sse" in line:
881
def _usesEvmsInMounts(self):
882
" check if evms is used in /proc/mounts "
883
logging.debug("running _usesEvmsInMounts")
884
for line in open("/proc/mounts"):
886
if line == '' or line.startswith("#"):
889
(device, mount_point, fstype, options, a, b) = line.split()
891
logging.error("can't parse line '%s'" % line)
894
logging.debug("found evms device in line '%s', skipping " % line)
898
def _checkAndRemoveEvms(self):
899
" check if evms is in use and if not, remove it "
900
logging.debug("running _checkAndRemoveEvms")
901
if self._usesEvmsInMounts():
903
# if not in use, nuke it
904
for pkg in ["evms","libevms-2.5","libevms-dev",
905
"evms-ncurses", "evms-ha",
907
"evms-gui", "evms-cli",
909
if self.controller.cache.has_key(pkg) and self.controller.cache[pkg].is_installed:
910
self.controller.cache[pkg].mark_delete()
913
def _addRelatimeToFstab(self):
914
" add the relatime option to ext2/ext3 filesystems on upgrade "
915
logging.debug("_addRelatime")
918
for line in open("/etc/fstab"):
920
if line == '' or line.startswith("#"):
924
(device, mount_point, fstype, options, a, b) = line.split()
926
logging.error("can't parse line '%s'" % line)
929
if (("ext2" in fstype or
930
"ext3" in fstype) and
931
(not "noatime" in options) and
932
(not "relatime" in options) ):
933
logging.debug("adding 'relatime' to line '%s' " % line)
934
line = line.replace(options,"%s,relatime" % options)
935
logging.debug("replaced line is '%s' " % line)
938
# we have converted a line
940
logging.debug("writing new /etc/fstab")
941
f=open("/etc/fstab.intrepid","w")
942
f.write("\n".join(lines))
943
# add final newline (see LP: #279093)
946
os.rename("/etc/fstab.intrepid","/etc/fstab")
949
def _ntfsFstabFixup(self, fstab="/etc/fstab"):
950
"""change PASS 1 to 0 for ntfs entries (#441242)"""
951
logging.debug("_ntfsFstabFixup")
954
for line in open(fstab):
956
if line == '' or line.startswith("#"):
960
(device, mount_point, fstype, options, fdump, fpass) = line.split()
962
logging.error("can't parse line '%s'" % line)
965
if ("ntfs" in fstype and fpass == "1"):
966
logging.debug("changing PASS for ntfs to 0 for '%s' " % line)
968
line = line[:-1] + "0"
970
logging.error("unexpected value in line")
971
logging.debug("replaced line is '%s' " % line)
974
# we have converted a line
977
logging.debug("writing new /etc/fstab")
978
f=open(fstab + suffix, "w")
979
f.write("\n".join(lines))
980
# add final newline (see LP: #279093)
983
os.rename(fstab+suffix, fstab)
987
def _rewriteFstab(self):
988
" convert /dev/{hd?,scd0} to /dev/cdrom for the feisty upgrade "
989
logging.debug("_rewriteFstab()")
992
# we have one cdrom to convert
993
for line in open("/etc/fstab"):
995
if line == '' or line.startswith("#"):
999
(device, mount_point, fstype, options, a, b) = line.split()
1001
logging.error("can't parse line '%s'" % line)
1004
# edgy kernel has /dev/cdrom -> /dev/hd?
1005
# feisty kernel (for a lot of chipsets) /dev/cdrom -> /dev/scd0
1006
# this breaks static mounting (LP#86424)
1008
# we convert here to /dev/cdrom only if current /dev/cdrom
1009
# points to the device in /etc/fstab already. this ensures
1010
# that we don't break anything or that we get it wrong
1011
# for systems with two (or more) cdroms. this is ok, because
1012
# we convert under the old kernel
1013
if ("iso9660" in fstype and
1014
device != "/dev/cdrom" and
1015
os.path.exists("/dev/cdrom") and
1016
os.path.realpath("/dev/cdrom") == device
1018
logging.debug("replacing '%s' " % line)
1019
line = line.replace(device,"/dev/cdrom")
1020
logging.debug("replaced line is '%s' " % line)
1023
# we have converted a line (otherwise we would have exited already)
1025
logging.debug("writing new /etc/fstab")
1026
shutil.copy("/etc/fstab","/etc/fstab.edgy")
1027
f=open("/etc/fstab","w")
1028
f.write("\n".join(lines))
1029
# add final newline (see LP: #279093)
1034
def _checkAdminGroup(self):
1035
" check if the current sudo user is in the admin group "
1036
logging.debug("_checkAdminGroup")
1039
admin_group = grp.getgrnam("admin").gr_mem
1040
except KeyError as e:
1041
logging.warning("System has no admin group (%s)" % e)
1042
subprocess.call(["addgroup","--system","admin"])
1045
admin_group = grp.getgrnam("admin").gr_mem
1046
except KeyError as e:
1047
logging.warning("adding the admin group failed (%s)" % e)
1049
# if the current SUDO_USER is not in the admin group
1050
# we add him - this is no security issue because
1051
# the user is already root so adding him to the admin group
1052
# does not change anything
1053
if (os.environ.has_key("SUDO_USER") and
1054
not os.environ["SUDO_USER"] in admin_group):
1055
admin_user = os.environ["SUDO_USER"]
1056
logging.info("SUDO_USER=%s is not in admin group" % admin_user)
1057
cmd = ["usermod","-a","-G","admin",admin_user]
1058
res = subprocess.call(cmd)
1059
logging.debug("cmd: %s returned %i" % (cmd, res))
1061
def _checkVideoDriver(self, name):
1062
" check if the given driver is in use in xorg.conf "
1063
XORG="/etc/X11/xorg.conf"
1064
if not os.path.exists(XORG):
1066
for line in open(XORG):
1067
s=line.split("#")[0].strip()
1068
# check for fglrx driver entry
1069
if (s.lower().startswith("driver") and
1070
s.endswith('"%s"' % name)):
1074
def _applyPatches(self, patchdir="./patches"):
1076
helper that applies the patches in patchdir. the format is
1077
_path_to_file.md5sum
1079
and it will apply the diff to that file if the md5sum
1082
if not os.path.exists(patchdir):
1083
logging.debug("no patchdir")
1085
for f in os.listdir(patchdir):
1086
# skip, not a patch file, they all end with .$md5sum
1088
logging.debug("skipping '%s' (no '.')" % f)
1090
logging.debug("check if patch '%s' needs to be applied" % f)
1091
(encoded_path, md5sum, result_md5sum) = f.rsplit(".", 2)
1092
# FIXME: this is not clever and needs quoting support for
1093
# filenames with "_" in the name
1094
path = encoded_path.replace("_","/")
1095
logging.debug("target for '%s' is '%s' -> '%s'" % (
1096
f, encoded_path, path))
1097
# target does not exist
1098
if not os.path.exists(path):
1099
logging.debug("target '%s' does not exist" % path)
1101
# check the input md5sum, this is not strictly needed as patch()
1102
# will verify the result md5sum and discard the result if that
1103
# does not match but this will remove a misleading error in the
1106
md5.update(open(path).read())
1107
if md5.hexdigest() == result_md5sum:
1108
logging.debug("already at target hash, skipping '%s'" % path)
1110
elif md5.hexdigest() != md5sum:
1111
logging.warn("unexpected target md5sum, skipping: '%s'" % path)
1114
from .DistUpgradePatcher import patch
1116
patch(path, os.path.join(patchdir, f), result_md5sum)
1117
logging.info("applied '%s' successfully" % f)
1119
logging.exception("ed failed for '%s'" % f)
1121
def _supportInModaliases(self, pkgname, lspci=None):
1123
Check if pkgname will work on this hardware
1125
This helper will check with the modaliasesdir if the given
1126
pkg will work on this hardware (or the hardware given
1127
via the lspci argument)
1129
# get lspci info (if needed)
1131
lspci = self._get_pci_ids()
1133
if (not pkgname in self.controller.cache or
1134
not self.controller.cache[pkgname].candidate):
1135
logging.warn("can not find '%s' in cache")
1137
pkg = self.controller.cache[pkgname]
1138
for (module, pciid_list) in self._parse_modaliases_from_pkg_header(pkg.candidate.record):
1139
for pciid in pciid_list:
1140
m = re.match("pci:v0000(.+)d0000(.+)sv.*", pciid)
1142
matchid = "%s:%s" % (m.group(1), m.group(2))
1143
if matchid.lower() in lspci:
1144
logging.debug("found system pciid '%s' in modaliases" % matchid)
1146
logging.debug("checking for %s support in modaliases but none found" % pkgname)
1149
def _parse_modaliases_from_pkg_header(self, pkgrecord):
1150
""" return a list of (module1, (pciid, ...), (module2, (pciid, ...)))"""
1151
if not "Modaliases" in pkgrecord:
1155
for m in pkgrecord["Modaliases"].split(")"):
1159
(module, pciids) = m.split("(")
1160
modules.append ((module, [x.strip() for x in pciids.split(",")]))
1163
def _kernel386TransitionCheck(self):
1164
""" test if the current kernel is 386 and if the system is
1165
capable of using a generic one instead (#353534)
1167
logging.debug("_kernel386TransitionCheck")
1168
# we test first if one of 386 is installed
1169
# if so, check if the system could also work with -generic
1170
# (we get that from base-installer) and try to installed
1172
for pkgname in ["linux-386", "linux-image-386"]:
1173
if (self.controller.cache.has_key(pkgname) and
1174
self.controller.cache[pkgname].is_installed):
1175
working_kernels = self.controller.cache.getKernelsFromBaseInstaller()
1176
upgrade_to = ["linux-generic", "linux-image-generic"]
1177
for pkgname in upgrade_to:
1178
if pkgname in working_kernels:
1179
logging.debug("386 kernel installed, but generic kernel will work on this machine")
1180
if self.controller.cache.mark_install(pkgname, "386 -> generic transition"):
1184
def _add_extras_repository(self):
1185
logging.debug("_add_extras_repository")
1186
cache = self.controller.cache
1187
if not "ubuntu-extras-keyring" in cache:
1188
logging.debug("no ubuntu-extras-keyring, no need to add repo")
1190
if not (cache["ubuntu-extras-keyring"].marked_install or
1191
cache["ubuntu-extras-keyring"].installed):
1192
logging.debug("ubuntu-extras-keyring not installed/marked_install")
1195
import aptsources.sourceslist
1196
sources = aptsources.sourceslist.SourcesList()
1197
for entry in sources:
1198
if "extras.ubuntu.com" in entry.uri:
1199
logging.debug("found extras.ubuntu.com, no need to add it")
1202
logging.info("no extras.ubuntu.com, adding it to sources.list")
1203
sources.add("deb","http://extras.ubuntu.com/ubuntu",
1204
self.controller.toDist, ["main"],
1205
"Third party developers repository")
1208
logging.exception("error adding extras.ubuntu.com")
1210
def _gutenprint_fixup(self):
1211
""" foomatic-db-gutenprint get removed during the upgrade,
1212
replace it with the compressed ijsgutenprint-ppds
1213
(context is foomatic-db vs foomatic-db-compressed-ppds)
1216
cache = self.controller.cache
1217
if ("foomatic-db-gutenprint" in cache and
1218
cache["foomatic-db-gutenprint"].marked_delete and
1219
"ijsgutenprint-ppds" in cache):
1220
logging.info("installing ijsgutenprint-ppds")
1222
"ijsgutenprint-ppds",
1223
"foomatic-db-gutenprint -> ijsgutenprint-ppds rule")
1225
logging.exception("_gutenprint_fixup failed")
1227
def _enable_multiarch(self, foreign_arch="i386"):
1228
""" enable multiarch via /etc/dpkg/dpkg.cfg.d/multiarch """
1229
cfg = "/etc/dpkg/dpkg.cfg.d/multiarch"
1230
if not os.path.exists(cfg):
1232
os.makedirs("/etc/dpkg/dpkg.cfg.d/")
1235
open(cfg, "w").write("foreign-architecture %s\n" % foreign_arch)
1237
def _add_kdegames_card_extra_if_installed(self):
1238
""" test if kdegames-card-data is installed and if so,
1239
add kdegames-card-data-extra so that users do not
1240
loose functionality (LP: #745396)
1243
cache = self.controller.cache
1244
if not ("kdegames-card-data" in cache or
1245
"kdegames-card-data-extra" in cache):
1247
if (cache["kdegames-card-data"].is_installed or
1248
cache["kdegames-card-data"].marked_install):
1250
"kdegames-card-data-extra",
1251
"kdegames-card-data -> k-c-d-extra transition")
1253
logging.exception("_add_kdegames_card_extra_if_installed failed")
1255
def ensure_recommends_are_installed_on_desktops(self):
1256
""" ensure that on a desktop install recommends are installed
1260
if not self.controller.serverMode:
1261
if not apt.apt_pkg.config.find_b("Apt::Install-Recommends"):
1262
logging.warn("Apt::Install-Recommends was disabled, enabling it just for the upgrade")
1263
apt.apt_pkg.config.set("Apt::Install-Recommends", "1")