# # dasd.py - DASD class # # Copyright (C) 2009, 2010 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 . # # Red Hat Author(s): David Cantrell # import iutil import isys import sys import os from storage.errors import DasdFormatError from storage.devices import deviceNameToDiskByPath from constants import * from flags import flags from baseudev import udev_trigger import logging log = logging.getLogger("anaconda") import gettext _ = lambda x: gettext.ldgettext("anaconda", x) P_ = lambda x, y, z: gettext.ldngettext("anaconda", x, y, z) class DASD: """ Controlling class for DASD interaction before the storage code in anaconda has initialized. The DASD class can determine if any DASD devices on the system are unformatted and can perform a dasdfmt on them. """ def __init__(self): self._dasdlist = [] self._ldldasdlist = [] self._devices = [] # list of DASDDevice objects self.totalCylinders = 0 self._completedCylinders = 0.0 self._maxFormatJobs = 0 self.dasdfmt = "/sbin/dasdfmt" self.commonArgv = ["-y", "-d", "cdl", "-b", "4096"] self.started = False def __call__(self): return self def startup(self, intf, exclusiveDisks, zeroMbr, cdl): """ Look for any unformatted DASDs in the system and offer the user the option for format them with dasdfmt or exit the installer. Also check if any DASDs are LDL formatted and show a warning to users, since these disks will not be usable during installation. """ if self.started: return self.started = True if not iutil.isS390(): return # Trigger udev data about the dasd devices on the system udev_trigger(action="change", name="dasd*") log.info("Checking for unformatted and LDL DASD devices:") for device in os.listdir("/sys/block"): if not device.startswith("dasd"): continue statusfile = "/sys/block/%s/device/status" % (device,) if not os.path.isfile(statusfile): continue f = open(statusfile, "r") status = f.read().strip() f.close() bypath = deviceNameToDiskByPath(device) if not bypath: bypath = "/dev/" + device if status in ["unformatted"] and device not in exclusiveDisks: log.info(" %s (%s) status is %s, needs dasdfmt" % (device, bypath, status,)) self._dasdlist.append((device, bypath)) elif isys.isLdlDasd(device): log.info(" %s (%s) is an LDL DASD, needs dasdfmt" % (device, bypath)) self._ldldasdlist.append((device, bypath)) if not intf and (not zeroMbr or not cdl): log.info(" non-interactive kickstart install without zerombr " "or clearpart --cdl " "command, unable to run dasdfmt, exiting installer") sys.exit(0) # now onto formatting our DASDs if not len(self._dasdlist): log.info(" no unformatted DASD devices found") else: self.format_dasds(intf, not zeroMbr, self._dasdlist) if not len(self._ldldasdlist): log.info(" no LDL DASD devices found") else: self.format_dasds(intf, not cdl, self._ldldasdlist) def format_dasds(self, intf, askUser, dasdlist): """ Iterate through a given list of DASDs and run dasdfmt on them. """ out = "/dev/tty5" err = "/dev/tty5" c = len(dasdlist) if intf and askUser: devs = '' for dasd, bypath in dasdlist: devs += "%s\n" % (bypath,) rc = intf.questionInitializeDASD(c, devs) if rc == 1: log.info(" not running dasdfmt, continuing installation") return # gather total cylinder count argv = ["-t", "-v"] + self.commonArgv for dasd, bypath in dasdlist: buf = iutil.execWithCapture(self.dasdfmt, argv + ["/dev/" + dasd], stderr=err) for line in buf.splitlines(): if line.startswith("Drive Geometry: "): # line will look like this: # Drive Geometry: 3339 Cylinders * 15 Heads = 50085 Tracks cyls = long(filter(lambda s: s, line.split(' '))[2]) self.totalCylinders += cyls break # format DASDs argv = ["-P"] + self.commonArgv update = self._updateProgressWindow title = P_("Formatting DASD Device", "Formatting DASD Devices", c) msg = P_("Preparing %d DASD device for use with Linux..." % c, "Preparing %d DASD devices for use with Linux..." % c, c) if intf: if self.totalCylinders: pw = intf.progressWindow(title, msg, 1.0) else: pw = intf.progressWindow(title, msg, 100, pulse=True) for dasd, bypath in dasdlist: log.info("Running dasdfmt on %s" % (bypath,)) arglist = argv + ["/dev/" + dasd] try: if intf and self.totalCylinders: rc = iutil.execWithCallback(self.dasdfmt, arglist, stdout=out, stderr=err, callback=update, callback_data=pw, echo=False) elif intf: rc = iutil.execWithPulseProgress(self.dasdfmt, arglist, stdout=out, stderr=err, progress=pw) else: rc = iutil.execWithRedirect(self.dasdfmt, arglist, stdout=out, stderr=err) except Exception as e: raise DasdFormatError(e, bypath) if rc: raise DasdFormatError("dasdfmt failed: %s" % rc, bypath) if intf: pw.pop() def addDASD(self, dasd): """ Adds a DASDDevice to the internal list of DASDs. """ if dasd: self._devices.append(dasd) def clear_device_list(self): """ Clear the device list to force re-populate on next access. """ self._devices = [] def write(self, instPath): """ Write /etc/dasd.conf to target system for all DASD devices configured during installation. """ if self._devices == []: return f = open(os.path.realpath(instPath + "/etc/dasd.conf"), "w") for dasd in self._devices: fields = [dasd.busid] + dasd.getOpts() f.write("%s\n" % (" ".join(fields),)) f.close() def _updateProgressWindow(self, data, callback_data=None): """ Reads progress output from dasdfmt and collects the number of cylinders completed so the progress window can update. """ if not callback_data: return if data == '\n': # each newline we see in this output means 10 more cylinders done self._completedCylinders += 10.0 callback_data.set(self._completedCylinders / self.totalCylinders) # Create DASD singleton DASD = DASD() # vim:tw=78:ts=4:et:sw=4