From: Mark Hamzy <hamzy@xxxxxxxxxx> Basically this is a back-port of d00ef216099104c03c400f56fb21e19089df4a7d. For those not capable of reading huge hashes, the previous sentence means this patch brings the RHEL 5.5 reIPL support in line with what we currently have upstream in both Fedora and RHEL-6 for rebooting (err, I mean re-"IPL"ing) s390x VMs after installation. --- anaconda | 10 +++ dispatch.py | 3 + installclass.py | 1 + iutil.py | 178 ++++++++++++++++++++++++++++++++++++++++++++++++ iw/congrats_gui.py | 13 +++- loader2/linuxrc.s390 | 28 +------- loader2/loader.c | 44 +++++++----- packages.py | 22 ++++++ textw/complete_text.py | 9 ++- upgradeclass.py | 1 + 10 files changed, 263 insertions(+), 46 deletions(-) diff --git a/anaconda b/anaconda index 82f8ad0..ca23c11 100755 --- a/anaconda +++ b/anaconda @@ -480,6 +480,8 @@ class Anaconda: self.rescue_mount = True self.rescue = False self.updateSrc = None + self.canReIPL = False + self.reIPLMessage = None def setDispatch(self): self.dispatch = dispatch.Dispatcher(self) @@ -988,3 +990,11 @@ if __name__ == "__main__": isys.ejectCdrom(drive) del anaconda.intf + + if rhpl.getArch() in ['s390', 's390x']: + if anaconda.canReIPL: + log.info("reipl configuration successful => reboot") + os.kill(os.getppid(), signal.SIGUSR2) + else: + log.info("reipl configuration failed => halt") + os.kill(os.getppid(), signal.SIGUSR1) diff --git a/dispatch.py b/dispatch.py index ddf7885..8c86677 100644 --- a/dispatch.py +++ b/dispatch.py @@ -42,6 +42,8 @@ from backend import doPostSelection, doRepoSetup, doBasePackageSelect from backend import doPreInstall, doPostInstall, doInstall from backend import writeConfiguration +from packages import doReIPL + import logging log = logging.getLogger("anaconda") @@ -82,6 +84,7 @@ installSteps = [ ("bootloadersetup", bootloaderSetupChoices, ), ("bootloader", ), ("bootloaderadvanced", ), + ("reipl", doReIPL, ), ("networkdevicecheck", networkDeviceCheck, ), ("network", ), ("timezone", ), diff --git a/installclass.py b/installclass.py index a1fd556..9a34363 100644 --- a/installclass.py +++ b/installclass.py @@ -142,6 +142,7 @@ class BaseInstallClass: "partitiondone", "bootloadersetup", "bootloader", + "reipl", "networkdevicecheck", "network", "timezone", diff --git a/iutil.py b/iutil.py index 289f5c7..8b3e6b9 100644 --- a/iutil.py +++ b/iutil.py @@ -14,12 +14,16 @@ # import os, isys, string, stat +import signal import os.path from errno import * import rhpl import warnings import subprocess from flags import flags +from constants import * +from rhpl.translate import _ +import re import logging log = logging.getLogger("anaconda") @@ -529,4 +533,178 @@ def getScsiDeviceByWwpnLunid(wwpn, lunid): tgt = "" return tgt +def writeReiplMethod(reipl_path, reipl_type): + filename = "%s/reipl_type" % (reipl_path,) + try: + f = open(filename, "w") + except Exception, e: + message = "Error: On open, cannot set reIPL method to %s (%s: %s)" % (reipl_type,filename,e,) + log.warning(message) + raise Exception (message) + + try: + f.write(reipl_type) + f.flush() + except Exception, e: + message = "Error: On write, cannot set reIPL method to %s (%s: %s)" % (reipl_type,filename,e,) + log.warning(message) + raise Exception (message) + + try: + f.close() + except Exception, e: + message = "Error: On close, cannot set reIPL method to %s (%s: %s)" % (reipl_type,filename,e,) + log.warning(message) + raise Exception (message) + +def reIPLonCCW(iplsubdev, reipl_path): + device = "<unknown>" + + try: + iplbits = re.split ('([0-9]+)', iplsubdev) + if len (iplbits) != 3: + message = "Error: %s splits into %s but not like we expect" % (iplsubdev,iplbits,) + log.warning(message) + raise Exception (message) + + device = os.readlink("/sys/block/" + iplbits[0] + "/device").split('/')[-1] + + writeReiplMethod(reipl_path, 'ccw') + + try: + f = open("%s/ccw/device" % (reipl_path,), "w") + f.write(device) + f.close() + except Exception, e: + message = "Error: Could not set %s as reIPL device (%s)" % (device,e,) + log.warning(message) + raise Exception (message) + + try: + f = open("%s/ccw/loadparm" % (reipl_path,), "w") + f.write("\n") + f.close() + except Exception, e: + message = "Error: Could not reset loadparm (%s)" % (e,) + log.warning(message) + raise Exception (message) + + try: + f = open("%s/ccw/parm" % (reipl_path,), "w") + f.write("\n") + f.close() + except Exception, e: + message = "Warning: Could not reset parm (%s)" % (e,) + log.warning(message) + # do NOT raise an exception since this might not exist or not be writable + + except Exception, e: + try: + message = e.args[0] + except: + message = e.__str__ () + return (message, + (_("After shutdown, please perform a manual IPL from DASD device %s to continue " + "installation") % (device,))) + + return None + +def reIPLonFCP(iplsubdev, reipl_path): + fcpvalue = { "device": "<unknown>", "wwpn": "<unknown>", "lun": "<unknown>" } + + try: + iplbits = re.split ('([0-9]+)', iplsubdev) + if len (iplbits) != 3: + message = "Error: %s splits into %s but not like we expect" % (iplsubdev,iplbits,) + log.warning(message) + raise Exception (message) + + syspath = "/sys/block/" + iplbits[0] + "/device" + + fcpprops = [ ("hba_id", "device"), ("wwpn", "wwpn"), ("fcp_lun", "lun") ] + + # Read in values to change. + # This way, if we can't set FCP mode, we can tell the user what to manually reboot to. + for (syspath_property, reipl_property) in fcpprops: + try: + f = open(syspath + "/" + syspath_property, "r") + value = f.read().strip() + fcpvalue[reipl_property] = value + f.close() + except Exception, e: + message = "Error: reading FCP property %s for reIPL (%s)" % (syspath_property,e,) + log.warning(message) + raise Exception (message) + + writeReiplMethod(reipl_path, 'fcp') + + # Write out necessary parameters. + for (syspath_property, reipl_property) in fcpprops: + try: + f = open("%s/fcp/%s" % (reipl_path, reipl_property,), "w") + f.write(fcpvalue[reipl_property]) + f.close() + except Exception, e: + message = "Error: writing FCP property %s for reIPL (%s)" % (reipl_property,e,) + log.warning(message) + raise Exception (message) + + defaultprops = [ ("bootprog", "0"), ("br_lba", "0") ] + + # Write out default parameters. + for (reipl_property, default_value) in defaultprops: + try: + f = open("%s/fcp/%s" % (reipl_path, reipl_property,), "w") + f.write (default_value) + f.close() + except Exception, e: + message = "Error: writing default FCP property %s for reIPL (%s)" % (reipl_property,e,) + log.warning(message) + raise Exception (message) + + except Exception, e: + try: + message = e.args[0] + except: + message = e.__str__ () + return (message, + (_("After shutdown, please perform a manual IPL from FCP %(device)s with WWPN %(wwpn)s " + "and LUN %(lun)s to continue installation") % (fcpvalue))) + + return None + +def reIPL(anaconda, loader_pid): + instruction = _("After shutdown, please perform a manual IPL from the device " + "now containing /boot to continue installation") + + reipl_path = "/sys/firmware/reipl" + + iplfs = anaconda.id.fsset.getEntryByMountPoint("/boot") + if iplfs is None: + iplfs = anaconda.id.fsset.getEntryByMountPoint("/") + + if iplfs is None: + message = _("Could not get information for mount point /boot or /") + log.warning(message) + return (message, instruction) + + try: + ipldev = iplfs.device.device + except: + ipldev = None + + if ipldev is None: + message = _("Error determining mount point type") + log.warning(message) + return (message, instruction) + + message = (_("The mount point /boot or / is on a disk that we are not familiar with"), instruction) + if ipldev.startswith("dasd"): + message = reIPLonCCW(ipldev, reipl_path) + elif ipldev.startswith("sd"): + message = reIPLonFCP(ipldev, reipl_path) + + # the final return is either None if reipl configuration worked (=> reboot), + # or a two-item list with errorMessage and rebootInstr (=> shutdown) + return message diff --git a/iw/congrats_gui.py b/iw/congrats_gui.py index 3cf9ffb..32c12ab 100644 --- a/iw/congrats_gui.py +++ b/iw/congrats_gui.py @@ -34,8 +34,10 @@ class CongratulationWindow (InstallWindow): # this mucks around a bit, but it's the weird case and it's # better than adding a lot of complication to the normal ics.cw.mainxml.get_widget("nextButton").hide() - ics.cw.mainxml.get_widget("rebootButton").show() - ics.cw.mainxml.get_widget("rebootButton").grab_focus() + + self.rebootButton = ics.cw.mainxml.get_widget("rebootButton") + self.rebootButton.show() + self.rebootButton.grab_focus() def getNext(self): # XXX - copy any screenshots over @@ -54,8 +56,13 @@ class CongratulationWindow (InstallWindow): hbox.pack_start (a, False, False, 36) bootstr = "" - if rhpl.getArch() == "s390": + if rhpl.getArch() in ['s390', 's390x']: floppystr = "" + if not anaconda.canReIPL: + self.rebootButton.set_label(_("Shutdown")) + if not anaconda.reIPLMessage is None: + floppystr = anaconda.reIPLMessage + else: floppystr = _("Remove any media used during the installation " "process and press the \"Reboot\" button to " diff --git a/loader2/linuxrc.s390 b/loader2/linuxrc.s390 index 2856f96..fae5187 100644 --- a/loader2/linuxrc.s390 +++ b/loader2/linuxrc.s390 @@ -83,35 +83,13 @@ function checkipv4() function doshutdown() { + echo $"about to exec shutdown" exec /sbin/shutdown exit 0 } function doreboot() { - # find out the location of /boot and use it to re-ipl - boot="$(cat /proc/mounts | grep " /mnt/sysimage/boot " | awk -F" " '{print $1}')" - if [ -z $boot ]; then - # use root if /boot not used - boot="$(cat /proc/mounts | grep " /mnt/sysimage " | awk -F" " '{print $1}')" - fi - - # lookup dasd disk - echo $boot | grep "dasd" > /dev/null - if [ $? -eq 0 ]; then - type="ccw" - boot="$(basename $boot)" - # strip partition number from dasd device - boot="$(echo ${boot%[0-9]})" - id="$(basename $(readlink /sys/block/$boot/device))" - echo $type > /sys/firmware/reipl/reipl_type - echo $id > /sys/firmware/reipl/$type/device - else - # scsi re-ipl only supported on newer machines - doshutdown - exit 0 - fi - echo $"about to exec shutdown -r" exec /sbin/shutdown -r exit 0 @@ -3149,7 +3127,9 @@ EOF /sbin/loader fi - doreboot + # A shutdown needs to be performed here to avoid a loop booting back into the installer + echo $"Finishing up with doshutdown" + doshutdown fi # testing diff --git a/loader2/loader.c b/loader2/loader.c index 4299ab3..5ef268b 100644 --- a/loader2/loader.c +++ b/loader2/loader.c @@ -118,6 +118,8 @@ uint64_t flags = LOADER_FLAGS_SELINUX | LOADER_FLAGS_NOFB; int num_link_checks = 5; int post_link_sleep = 0; +static pid_t init_pid = 1; + static struct installMethod installMethods[] = { { N_("Local CDROM"), "cdrom", 0, CLASS_CDROM, mountCdromImage }, { N_("Hard drive"), "hd", 0, CLASS_HD, mountHardDrive }, @@ -1384,6 +1386,11 @@ void loaderSegvHandler(int signum) { exit(1); } +void loaderUsrXHandler(int signum) { + logMessage(INFO, "Sending signal %d to process %d\n", signum, init_pid); + kill(init_pid, signum); +} + static int anaconda_trace_init(void) { #if 0 int fd; @@ -1455,6 +1462,26 @@ int main(int argc, char ** argv) { { 0, 0, 0, 0, 0, 0, 0 } }; + /* get init PID if we have it */ + if ((f = fopen("/var/run/init.pid", "r")) != NULL) { + char linebuf[256]; + memset(linebuf, '\0', sizeof(linebuf)); + + while (fgets(linebuf, sizeof(linebuf) - 1, f) != NULL) { + errno = 0; + init_pid = strtol((const char *) &linebuf, NULL, 10); + if (errno == EINVAL || errno == ERANGE) { + logMessage(ERROR, "%s (%d): %m", __func__, __LINE__); + init_pid = 1; + } + } + + fclose(f); + } + + signal(SIGUSR1, loaderUsrXHandler); + signal(SIGUSR2, loaderUsrXHandler); + /* Make sure sort order is right. */ setenv ("LC_COLLATE", "C", 1); @@ -1952,23 +1979,6 @@ int main(int argc, char ** argv) { waitpid(pid, &status, 0); } -#if defined(__s390__) || defined(__s390x__) - /* FIXME: we have to send a signal to linuxrc on s390 so that shutdown - * can happen. this is ugly */ - FILE * f; - f = fopen("/var/run/init.pid", "r"); - if (!f) { - logMessage(WARNING, "can't find init.pid, guessing that init is pid 1"); - pid = 1; - } else { - char * buf = malloc(256); - char *ret; - - ret = fgets(buf, 256, f); - pid = atoi(buf); - } - kill(pid, SIGUSR2); -#endif stop_fw_loader(&loaderData); return rc; } diff --git a/packages.py b/packages.py index c05f5fa..a1a6e56 100644 --- a/packages.py +++ b/packages.py @@ -409,3 +409,25 @@ def selectLanguageSupportGroups(grpset, instLanguage): if grp.usecount > 0: grpset.groups["language-support"].select() + +def doReIPL(anaconda): + if not rhpl.getArch() in ['s390', 's390x']: + return DISPATCH_NOOP + + messageInfo = iutil.reIPL(anaconda, os.getppid()) + + # @TBD seeing a bug here where anaconda.canReIPL and anaconda.reIPLMessage are + # not initialized even though they were in Anaconda.__init__() + if messageInfo is None: + anaconda.canReIPL = True + + anaconda.reIPLMessage = None + else: + anaconda.canReIPL = False + + (errorMessage, rebootInstr) = messageInfo + + # errorMessage intentionally not shown in UI + anaconda.reIPLMessage = rebootInstr + + return DISPATCH_FORWARD diff --git a/textw/complete_text.py b/textw/complete_text.py index 0eeae37..6ada0b9 100644 --- a/textw/complete_text.py +++ b/textw/complete_text.py @@ -22,10 +22,15 @@ class FinishedWindow: def __call__ (self, screen, anaconda): bootstr = "" + buttonstr = _("Reboot") - if rhpl.getArch() == "s390": + if rhpl.getArch() in ['s390', 's390x']: floppystr = _("Press <Enter> to end the installation process.\n\n") bottomstr = _("<Enter> to exit") + if not anaconda.canReIPL: + buttonstr = _("Shutdown") + if not anaconda.reIPLMessage is None: + floppystr = anaconda.reIPLMessage + "\n\n" + floppystr else: floppystr = _("Remove any media used during the installation " "process and press <Enter> to reboot your system." @@ -44,6 +49,6 @@ class FinishedWindow: "http://www.redhat.com/docs/.") %(productName,) rc = ButtonChoiceWindow (screen, _("Complete"), txt, - [ _("Reboot") ], help = "finished", width=60) + [ buttonstr ], help = "finished", width=60) return INSTALL_OK diff --git a/upgradeclass.py b/upgradeclass.py index 107ad61..121cce5 100644 --- a/upgradeclass.py +++ b/upgradeclass.py @@ -43,6 +43,7 @@ class InstallClass(baseclass): "upgradecontinue", "reposetup", "upgbootloader", + "reipl", "checkdeps", "dependencies", "confirmupgrade", -- 1.6.5.5 _______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list