# # Support methods for CD/DVD and ISO image installations. # # Copyright 2007 Red Hat, Inc. # # This software may be freely redistributed under the terms of the GNU # library public license. # # You should have received a copy of the GNU Library Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # import isys import os, os.path, stat, string, sys from constants import * import rhpl from rhpl.translate import _ import logging log = logging.getLogger("anaconda") # this sucks, but we want to consider s390x as s390x in here but generally # don't. *sigh* if os.uname()[4] == "s390x": _arch = "s390x" else: _arch = rhpl.getArch() def findIsoImages(path, messageWindow): flush = os.stat(path) files = os.listdir(path) arch = _arch discImages = {} for file in files: what = path + '/' + file if not isys.isIsoImage(what): continue try: isys.losetup("/dev/loop2", what, readOnly = 1) except SystemError: continue try: isys.mount("/dev/loop2", "/mnt/cdimage", fstype = "iso9660", readOnly = 1) for num in range(1, 10): if os.access("/mnt/cdimage/.discinfo", os.R_OK): f = open("/mnt/cdimage/.discinfo") try: f.readline() # skip timestamp f.readline() # skip release description discArch = string.strip(f.readline()) # read architecture discNum = getDiscNums(f.readline().strip()) except: discArch = None discNum = [ 0 ] f.close() if num not in discNum or discArch != arch: continue # if it's disc1, it needs to have images/stage2.img if (num == 1 and not os.access("/mnt/cdimage/images/stage2.img", os.R_OK)): log.warning("%s doesn't have a stage2.img, skipping" %(what,)) continue # we only install binary packages, so let's look for a # product/ dir and hope that this avoids getting # discs from the src.rpm set if not os.path.isdir("/mnt/cdimage/%s" %(productPath,)): log.warning("%s doesn't have binary RPMS, skipping" %(what,)) continue # warn user if images appears to be wrong size if os.stat(what)[stat.ST_SIZE] % 2048: rc = messageWindow(_("Warning"), _("The ISO image %s has a size which is not " "a multiple of 2048 bytes. This may mean " "it was corrupted on transfer to this computer." "\n\n" "It is recommended that you exit and abort your " "installation, but you can choose to continue if " "you think this is in error.") % (file,), type="custom", custom_icon="warning", custom_buttons= [_("_Exit installer"), _("_Continue")]) if rc == 0: sys.exit(0) discImages[num] = file isys.umount("/mnt/cdimage", removeDir=0) except SystemError: pass isys.unlosetup("/dev/loop2") return discImages def getDiscNums(line): # get the disc numbers for this disc nums = line.split(",") discNums = [] for num in nums: discNums.append(int(num)) return discNums def getMediaId(path): if os.access("%s/.discinfo" % path, os.R_OK): f = open("%s/.discinfo" % path) newStamp = f.readline().strip() f.close() return newStamp else: return None # This mounts the directory containing the iso images, and places the # mount point in isodir. def mountDirectory(isodir, methodstr, messageWindow): if methodstr.startswith("hd://"): method = methodstr[5:] (device, fstype, path) = method.split(":", 3) device = method[0:method.index(":")] else: return # First check to see if isodir is mounted. f = open("/proc/mounts", "r") lines = f.readlines() f.close() for l in lines: s = string.split(l) if s[0] == "/dev/" + device: # It is, so there's no need to try again. return try: isys.mount(device, isodir, fstype = fstype) except SystemError, msg: log.error("couldn't mount ISO source directory: %s" % msg) messageWindow(_("Couldn't Mount ISO Source"), _("An error occurred mounting the source " "device %s. This may happen if your ISO " "images are located on an advanced storage " "device like LVM or RAID, or if there was a " "problem mounting a partition. Click exit " "to abort the installation.") % (self.device,), type="custom", custom_icon="error", custom_buttons=[_("_Exit")]) sys.exit(0) def mountImage(isodir, tree, discnum, messageWindow, discImages={}): if os.path.ismount(tree): raise SystemError, "trying to mount already-mounted iso image!" if discImages == {}: discImages = findIsoImages(isodir, messageWindow) while True: try: isoImage = "%s/%s" % (isodir, discImages[discnum]) isys.losetup("/dev/loop1", isoImage, readOnly = 1) isys.mount("/dev/loop1", tree, fstype = 'iso9660', readOnly = 1); break except: ans = messageWindow(_("Missing ISO 9660 Image"), _("The installer has tried to mount " "image #%s, but cannot find it on " "the hard drive.\n\n" "Please copy this image to the " "drive and click Retry. Click Exit " " to abort the installation.") % (discnum,), type="custom", custom_icon="warning", custom_buttons=[_("_Exit"), _("_Retry")]) if ans == 0: sys.exit(0) elif ans == 1: discImages = findIsoImages(isodir, messageWindow) return discImages # given groupset containing information about selected packages, use # the disc number info in the headers to come up with message describing # the required CDs # # dialog returns a value of 0 if user selected to abort install def presentRequiredMediaMessage(anaconda): reqcds = anaconda.backend.getRequiredMedia() # if only one CD required no need to pop up a message if len(reqcds) < 2: return # check what discs our currently mounted one provides if os.access("/.discinfo" % anaconda.backend.ayum.tree, os.R_OK): discNums = [] try: f = open("%s/.discinfo", anaconda.backend.ayum.tree) stamp = f.readline().strip() descr = f.readline().strip() arch = f.readline().strip() discNums = getDiscNums(f.readline().strip()) f.close() except Exception, e: log.critical("Exception reading discinfo: %s" %(e,)) log.info("discNums is %s" %(discNums,)) haveall = 0 s = sets.Set(reqcds) t = sets.Set(discNums) if s.issubset(t): haveall = 1 if haveall == 1: return reqcds.sort() reqcdstr = "" for cdnum in reqcds: if cdnum == -99: # non-CD bits continue reqcdstr += "\t\t%s %s disc #%d\n" % (product.productName, product.productVersion, cdnum,) return anaconda.intf.messageWindow( _("Required Install Media"), _("The software you have selected to " "install will require the following discs:\n\n" "%s\nPlease " "have these ready before proceeding with " "the installation. If you need to abort " "the installation and exit please " "select \"Reboot\".") % (reqcdstr,), type="custom", custom_icon="warning", custom_buttons=[_("_Reboot"), _("_Back"), _("_Continue")]) def umountDirectory(self): try: isys.umount("/tmp/isodir", removeDir=0) except: pass def umountImage(tree, currentMedia): if currentMedia is not None: isys.umount(tree, removeDir=0) isys.unlosetup("/dev/loop1") def unmountCD(path, messageWindow): if not path: return while True: try: isys.umount(path, removeDir=0) break except Exception, e: log.error("exception in _unmountCD: %s" %(e,)) messageWindow(_("Error"), _("An error occurred unmounting the disc. " "Please make sure you're not accessing " "%s from the shell on tty2 " "and then click OK to retry.") % (path,)) def verifyMedia(tree, discnum, timestamp): if os.access("%s/.discinfo" % tree, os.R_OK): f = open("%s/.discinfo" % tree) newStamp = f.readline().strip() try: descr = f.readline().strip() except: descr = None try: arch = f.readline().strip() except: arch = None try: discs = getDiscNums(f.readline().strip()) except: discs = [ 0 ] f.close() if (newStamp == timestamp and arch == _arch and discnum in discs): return True return False