#
# upgrade.py - Existing install probe and upgrade procedure
#
# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc.
# All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
# Author(s): Matt Wilson
#
import isys
import os
import iutil
import time
import sys
import os.path
import string
import selinux
from flags import flags
from constants import *
from product import productName
from storage import findExistingRootDevices, FSSet
from storage.formats import getFormat
import rhpl
import rhpl.arch
import gettext
_ = lambda x: gettext.ldgettext("anaconda", x)
import rpm
import logging
log = logging.getLogger("anaconda")
def guessGuestArch(rootdir):
"""root path -> None|"architecture"
Guess the architecture of installed system
"""
ts = rpm.ts(rootdir)
packages = ["filesystem", "initscripts"]
#get information from packages
for pkg in packages:
try:
mi=ts.dbMatch("name",pkg)
for hdr in mi:
return hdr["arch"]
except:
pass
return None
def isUpgradingArch(anaconda):
"""anaconda -> (bool, oldarch)
Check if the upgrade should change architecture of instalation"""
try:
rpmplatform = open(anaconda.rootPath+"/etc/rpm/platform").readline().strip()
rpmarch = rpmplatform[:rpmplatform.index("-")]
return rhpl.arch.canonArch!=rpmarch, rpmarch
except IOError:
#try some fallback methods
rpmarch = guessGuestArch(anaconda.rootPath)
if rpmarch:
return rhpl.arch.canonArch!=rpmarch, rpmarch
else:
return False, "unknown"
def queryUpgradeArch(anaconda):
archupgrade, oldrpmarch = isUpgradingArch(anaconda) #Check if we are to upgrade the architecture of previous product
if anaconda.dir == DISPATCH_FORWARD or not archupgrade:
return DISPATCH_FORWARD
rc = anaconda.intf.messageWindow(_("Proceed with upgrade?"),
_("You have choosen the upgrade for %s "
"architecture, but the installed system "
"is for %s architecture. "
"\n\n" % (rhpl.arch.canonArch, oldrpmarch,)) +
_("Would you like to upgrade "
" the installed system to the %s architecture?" % (rhpl.arch.canonArch,)),
type="custom", custom_icon=["error","error"],
custom_buttons=[_("_Exit installer"), _("_Continue")])
if rc == 0:
sys.exit(0)
flags.updateRpmPlatform = True
return DISPATCH_FORWARD
def queryUpgradeContinue(anaconda):
if anaconda.dir == DISPATCH_FORWARD:
return
rc = anaconda.intf.messageWindow(_("Proceed with upgrade?"),
_("The file systems of the Linux installation "
"you have chosen to upgrade have already been "
"mounted. You cannot go back past this point. "
"\n\n") +
_("Would you like to continue with the upgrade?"),
type="custom", custom_icon=["error","error"],
custom_buttons=[_("_Exit installer"), _("_Continue")])
if rc == 0:
sys.exit(0)
return DISPATCH_FORWARD
def findRootParts(anaconda):
if anaconda.dir == DISPATCH_BACK:
return
if anaconda.id.rootParts is None:
anaconda.id.rootParts = findExistingRoots(anaconda)
root_device = None
# ks.cfg can pass device as raw device, label or uuid. no quotes allowed
if anaconda.isKickstart and anaconda.id.ksdata.upgrade.root_device is not None:
root_device=anaconda.id.ksdata.upgrade.root_device
anaconda.id.upgradeRoot = []
for (dev, label) in anaconda.id.rootParts:
anaconda.id.upgradeRoot.append( (dev, fs) )
if anaconda.id.rootParts is not None and len(anaconda.id.rootParts) > 0:
anaconda.dispatch.skipStep("findinstall", skip = 0)
if productName.find("Red Hat Enterprise Linux") == -1:
anaconda.dispatch.skipStep("installtype", skip = 1)
else:
anaconda.dispatch.skipStep("findinstall", skip = 1)
anaconda.dispatch.skipStep("installtype", skip = 0)
def findExistingRoots(anaconda, upgradeany = 0):
if not flags.setupFilesystems:
(prod, ver) = partedUtils.getReleaseString (anaconda.rootPath)
if flags.cmdline.has_key("upgradeany") or upgradeany == 1 or anaconda.id.instClass.productUpgradable(prod, ver):
return [(anaconda.rootPath, "")]
return []
return rootparts
def bindMountDevDirectory(instPath):
getFormat("bind",
device="/dev",
mountpoint="/dev",
exists=True).mount(chroot=instPath)
# returns None if no filesystem exist to migrate
def upgradeMigrateFind(anaconda):
migents = anaconda.id.fsset.getMigratableEntries()
if not migents or len(migents) < 1:
anaconda.dispatch.skipStep("upgrademigratefs")
else:
anaconda.dispatch.skipStep("upgrademigratefs", skip = 0)
# returns None if no more swap is needed
def upgradeSwapSuggestion(anaconda):
# mem is in kb -- round it up to the nearest 4Mb
mem = iutil.memInstalled()
rem = mem % 16384
if rem:
mem = mem + (16384 - rem)
mem = mem / 1024
anaconda.dispatch.skipStep("addswap", 0)
# don't do this if we have more then 250 MB
if mem > 250:
anaconda.dispatch.skipStep("addswap", 1)
return
swap = iutil.swapAmount() / 1024
# if we have twice as much swap as ram and at least 192 megs
# total, we're safe
if (swap >= (mem * 1.5)) and (swap + mem >= 192):
anaconda.dispatch.skipStep("addswap", 1)
return
# if our total is 512 megs or more, we should be safe
if (swap + mem >= 512):
anaconda.dispatch.skipStep("addswap", 1)
return
fsList = []
for device in anaconda.id.fsset.devices:
if not device.format:
continue
if device.format.mountable and device.format.linuxNative:
if flags.setupFilesystems and not device.format.status:
continue
space = isys.pathSpaceAvailable(anaconda.rootPath + device.format.mountpoint)
if space > 16:
info = (device, space)
fsList.append(info)
suggestion = mem * 2 - swap
if (swap + mem + suggestion) < 192:
suggestion = 192 - (swap + mem)
if suggestion < 32:
suggestion = 32
suggSize = 0
suggMnt = None
for (device, size) in fsList:
if (size > suggSize) and (size > (suggestion + 100)):
suggDev = device
anaconda.id.upgradeSwapInfo = (fsList, suggestion, suggDev)
# XXX handle going backwards
def upgradeMountFilesystems(anaconda):
# mount everything and turn on swap
if flags.setupFilesystems:
try:
mountExistingSystem(anaconda,
anaconda.id.upgradeRoot[0],
allowDirty = 0)
except Exception:
anaconda.intf.messageWindow(_("Mount failed"),
_("One or more of the file systems listed in the "
"/etc/fstab on your Linux system cannot be mounted. "
"Please fix this problem and try to upgrade again."))
sys.exit(0)
checkLinks = ( '/etc', '/var', '/var/lib', '/var/lib/rpm',
'/boot', '/tmp', '/var/tmp', '/root',
'/bin/sh', '/usr/tmp')
badLinks = []
for n in checkLinks:
if not os.path.islink(anaconda.rootPath + n): continue
l = os.readlink(anaconda.rootPath + n)
if l[0] == '/':
badLinks.append(n)
if badLinks:
message = _("The following files are absolute symbolic "
"links, which we do not support during an "
"upgrade. Please change them to relative "
"symbolic links and restart the upgrade.\n\n")
for n in badLinks:
message = message + '\t' + n + '\n'
anaconda.intf.messageWindow(_("Absolute Symlinks"), message)
sys.exit(0)
# fix for 80446
badLinks = []
mustBeLinks = ( '/usr/tmp', )
for n in mustBeLinks:
if not os.path.islink(anaconda.rootPath + n):
badLinks.append(n)
if badLinks:
message = _("The following are directories which should instead "
"be symbolic links, which will cause problems with the "
"upgrade. Please return them to their original state "
"as symbolic links and restart the upgrade.\n\n")
for n in badLinks:
message = message + '\t' + n + '\n'
anaconda.intf.messageWindow(_("Invalid Directories"), message)
sys.exit(0)
bindMountDevDirectory(anaconda.rootPath)
else:
if not os.access (anaconda.rootPath + "/etc/fstab", os.R_OK):
anaconda.intf.messageWindow(_("Warning"),
_("%s not found")
% (anaconda.rootPath + "/etc/fstab",),
type="ok")
return DISPATCH_BACK
anaconda.id.storage.fsset.parseFSTab(chroot=anaconda.rootPath)
if flags.setupFilesystems:
anaconda.id.storage.fsset.turnOnSwap(upgrading=True)
anaconda.id.storage.fsset.mkDevRoot(anaconda.rootPath)
# if they've been booting with selinux disabled, then we should
# disable it during the install as well (#242510)
try:
if os.path.exists(anaconda.rootPath + "/.autorelabel"):
ctx = selinux.getfilecon(anaconda.rootPath + "/.autorelabel")[1]
if not ctx or ctx == "unlabeled":
flags.selinux = False
log.info("Disabled SELinux for upgrade based on /.autorelabel")
except Exception, e:
log.warning("error checking selinux state: %s" %(e,))
def setSteps(anaconda):
dispatch = anaconda.dispatch
dispatch.setStepList(
"language",
"keyboard",
"welcome",
"installtype",
"storageinit",
"findrootparts",
"findinstall",
"upgrademount",
"upgrademigfind",
"upgrademigratefs",
"upgradearchitecture",
"upgradecontinue",
"reposetup",
"upgbootloader",
"checkdeps",
"dependencies",
"confirmupgrade",
"postselection",
"install",
"preinstallconfig",
"installpackages",
"postinstallconfig",
"instbootloader",
"dopostaction",
"methodcomplete",
"postscripts",
"copylogs",
"complete"
)
if not iutil.isX86():
dispatch.skipStep("bootloader")
if not iutil.isX86():
dispatch.skipStep("upgbootloader")