qubes-installer-qubes-os/anaconda/pyanaconda/storage/dasd.py
2013-01-24 01:45:53 +01:00

236 lines
8.0 KiB
Python

#
# 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 <http://www.gnu.org/licenses/>.
#
# Red Hat Author(s): David Cantrell <dcantrell@redhat.com>
#
from pyanaconda import iutil
import sys
import os
from pyanaconda.storage.errors import DasdFormatError
from pyanaconda.storage.devices import deviceNameToDiskByPath
from pyanaconda.constants import *
from pyanaconda.flags import flags
from pyanaconda.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)
def getDasdPorts():
""" Return comma delimited string of valid DASD ports. """
ports = []
f = open("/proc/dasd/devices", "r")
lines = map(lambda x: x.strip(), f.readlines())
f.close()
for line in lines:
if "unknown" in line:
continue
if "(FBA )" in line or "(ECKD)" in line:
ports.append(line.split('(')[0])
return ','.join(ports)
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._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):
""" Look for any unformatted DASDs in the system and offer the user
the option for format them with dasdfmt or exit the installer.
"""
if self.started:
return
self.started = True
out = "/dev/tty5"
err = "/dev/tty5"
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 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()
if status in ["unformatted"] and device not in exclusiveDisks:
bypath = deviceNameToDiskByPath(device)
if not bypath:
bypath = "/dev/" + device
log.info(" %s (%s) status is %s, needs dasdfmt" % (device,
bypath,
status,))
self._dasdlist.append((device, bypath))
if not len(self._dasdlist):
log.info(" no unformatted DASD devices found")
return
askUser = True
if zeroMbr:
askUser = False
elif not intf and not zeroMbr:
log.info(" non-interactive kickstart install without zerombr "
"command, unable to run dasdfmt, exiting installer")
sys.exit(0)
c = len(self._dasdlist)
if intf and askUser:
devs = ''
for dasd, bypath in self._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 self._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 self._dasdlist:
log.info("Running dasdfmt on %s" % (bypath,))
arglist = argv + ["/dev/" + dasd]
try:
if intf and self.totalCylinders:
ret = iutil.execWithCallback(self.dasdfmt, arglist,
stdout=out, stderr=err,
callback=update,
callback_data=pw,
echo=False)
rc = ret.rc
elif intf:
ret = iutil.execWithPulseProgress(self.dasdfmt, arglist,
stdout=out, stderr=err,
progress=pw)
rc = ret.rc
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):
""" Write /etc/dasd.conf to target system for all DASD devices
configured during installation.
"""
if self._devices == []:
return
f = open(os.path.realpath(ROOT_PATH + "/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 one more cylinder done
self._completedCylinders += 1.0
callback_data.set(self._completedCylinders / self.totalCylinders)
# Create DASD singleton
DASD = DASD()
# vim:tw=78:ts=4:et:sw=4