|
Server : Apache/2.2.17 (Unix) mod_ssl/2.2.17 OpenSSL/0.9.8e-fips-rhel5 DAV/2 PHP/5.2.17 System : Linux localhost 2.6.18-419.el5 #1 SMP Fri Feb 24 22:47:42 UTC 2017 x86_64 User : nobody ( 99) PHP Version : 5.2.17 Disable Function : NONE Directory : /usr/share/kdump/ |
Upload File : |
#
# firstboot_kdump.py - kdump configuration page for firstboot
# Copyright 2006 Red Hat, Inc.
# Author: Jarod Wilson <jwilson@redhat.com>
# Contributors:
# Neil Horman <nhorman@redhat.com>
# Dave Lehman <dlehman@redhat.com>
#
#
# 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, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import sys
sys.path.append('/usr/share/system-config-kdump/')
from gtk import *
import string
import os
import os.path
import time
import gtk
import gobject
import functions
import commands
import rhpl.executil as executil
from firstboot import start_process
from rhpl.translate import _, N_
from rhpl import translate
translate.textdomain("kexec-tools")
class childWindow:
# runPriority determines the order in which this module runs in firstboot
runPriority = 70
moduleName = _("Kdump")
windowName = moduleName
needsReboot = False
# possible bootloaders we'll need to adjust
# bootloader : (config file, kdump offset, kernel path)
bootloaders = { "grub" : ("/boot/grub/grub.conf", 16, "/boot"),
"yaboot" : ("/boot/etc/yaboot.conf", 32, "/boot"),
"elilo" : ("/boot/efi/EFI/redhat/elilo.conf", 256, "/boot/efi/EFI/redhat") }
bootloader = None
offset = 0
# list of architectures without kdump support
unsupportedArches = [ "ppc", "s390", "s390x", "i386", "i586" ]
# list of platforms that have a separate kernel-kdump
kernelKdumpArches = [ "ppc64" ]
kernelKdumpInstalled = False
# toggle sensitivity of kdump config bits
def showHide(self, status):
self.totalMem.set_sensitive(status)
self.kdumpMem.set_sensitive(status)
self.systemUsableMem.set_sensitive(status)
self.labelTotal.set_sensitive(status)
self.labelKdump.set_sensitive(status)
self.labelSys.set_sensitive(status)
self.kdumpEnabled = status
def on_enableKdumpCheck_toggled(self, *args):
showHideStatus = self.enableKdumpCheck.get_active()
self.showHide(showHideStatus)
def updateAvail(self, widget, spin):
self.remMem = self.availMem - spin.get_value_as_int()
self.systemUsableMem.set_text("%s" % self.remMem)
def getBootloader(self):
for (name, (conf, offset, kpath)) in self.bootloaders.items():
if os.access(conf, os.W_OK):
self.bootloader = name
return self.bootloader
# convert hex memory values into MB of RAM so we can
# read /proc/iomem and show something a human understands
def hex2mb(self, hex):
divisor = 1048575
mb = int(hex,16) / divisor
return mb
def launch(self, doDebug = None):
self.doDebug = doDebug
if doDebug:
print "initializing kdump module"
# What kernel are we running?
self.runningKernel = os.popen("/bin/uname -r").read().strip()
# What arch are we running on?
self.arch = os.popen("/bin/uname -m").read().strip()
# Check for a xen kernel, we do things a bit different w/xen
self.xenKernel = False
if os.access("/proc/xen", os.R_OK):
self.xenKernel = True
# Fedora or RHEL?
releaseFile = '/etc/redhat-release'
self.distro = 'rhel'
lines = open(releaseFile).readlines()
for line in lines:
if line.find("Fedora") != -1:
self.distro = 'fedora'
break
# If we need kernel-kdump, check to see if its already installed
if self.arch in self.kernelKdumpArches:
self.kernelKdump = "/boot/vmlinux-%skdump" % self.runningKernel
if os.access(self.kernelKdump, os.R_OK):
self.kernelKdumpInstalled = True
# Ascertain how much memory is in the system
memInfo = open("/proc/meminfo").readlines()
self.availMem = 0
for line in memInfo:
if line.startswith("MemTotal:"):
self.availMem = int(line.split()[1]) / 1024
break
# Check to see if kdump memory is already reserved
# Read from /proc/iomem so we're portable across xen and non-xen
self.kdumpMem = 0
self.kdumpOffset = 0
self.kdumpMemInitial = 0
self.origCrashKernel = ""
self.kdumpEnabled = False
# PowerPC64 doesn't list crashkernel reservation in /proc/iomem
if self.arch != 'ppc64':
ioMem = open("/proc/iomem").readlines()
for line in ioMem:
if line.find("Crash kernel") != -1:
hexCKstart = line.strip().split("-")[0]
hexCKend = line.strip().split("-")[1].split(":")[0].strip()
self.kdumpOffset = self.hex2mb(hexCKstart)
self.kdumpMem = self.hex2mb(hexCKend) - self.kdumpOffset
break
else:
cmdLine = open("/proc/cmdline").read()
if cmdLine.find("crashkernel=") > -1:
crashString = filter(lambda t: t.startswith("crashkernel="),
cmdLine.split())[0].split("=")[1]
(self.kdumpMem, self.kdumpOffset) = \
[int(m[:-1]) for m in crashString.split("@")]
# i686 xen requires kernel-PAE for kdump if any memory
# is mapped above 4GB
self.xenKdumpKernel = "kernel"
if self.arch == "i686" and self.xenKernel:
for line in ioMem:
if line.find("System RAM") != -1:
rangeEnd = line.strip().split("-")[1].split(":")[0].strip()
if rangeEnd >= 0x100000000L:
self.xenKdumpKernel = "kernel-PAE"
break
# Fix up memory calculations, if need be
if self.kdumpMem != 0:
self.kdumpEnabled = True
self.availMem += self.kdumpMem
self.kdumpMemInitial = self.kdumpMem
self.origCrashKernel = "%dM@%dM" % (self.kdumpMem, self.kdumpOffset)
if doDebug:
print "crashkernel region of %sM at offset %sM found" \
% (self.kdumpMem, self.kdumpOffset)
if self.arch != 'ppc64':
print "(hex offset %s to %s)" % (hexCKstart, hexCKend)
self.initialState = self.kdumpEnabled
# Do some sanity-checking and try to present only sane options.
#
# Defaults
lowerBound = 128
defRes = 128
minUsable = 256
step = 64
self.enoughMem = True
if self.arch == 'ia64':
# ia64 usually needs at *least* 256M, page-aligned... :(
lowerBound = 128
defRes = 256
minUsable = 512
elif self.arch == 'ppc64':
# ppc64 often fails w/128M lately, and we want at least 1G
# of RAM for normal use, due to 64k page size... :\
lowerBound = 128
defRes = 256
minUsable = 1024
upperBound = (self.availMem - minUsable) - (self.availMem % step)
if upperBound < lowerBound:
self.enoughMem = False
lowerBound = 0
elif upperBound < defRes:
defRes = lowerBound
# Set spinner to lowerBound unless already set on kernel command line
if self.kdumpMem == 0:
self.kdumpMem = defRes
else:
# round down to a multiple of step value
self.kdumpMem = self.kdumpMem - (self.kdumpMem % step)
# kdump enable/disable checkbox
self.enableKdumpCheck = gtk.CheckButton(_("_Enable kdump?"))
self.enableKdumpCheck.set_alignment(xalign=0, yalign=0)
# detected total amount of system memory
self.totalMem = gtk.Label(_("%s" % self.availMem))
self.labelTotal = gtk.Label(_("_Total System Memory (MB):"))
self.labelTotal.set_use_underline(True)
self.labelTotal.set_mnemonic_widget(self.totalMem)
self.labelTotal.set_alignment(0.0, 0.5)
self.labelTotal.set_width_chars(32)
# how much ram to reserve for kdump
self.memSpin = gtk.Adjustment(self.kdumpMem, lowerBound, upperBound, step, step, 64)
self.kdumpMem = gtk.SpinButton(self.memSpin, 0, 0)
self.kdumpMem.set_update_policy(gtk.UPDATE_IF_VALID)
self.kdumpMem.set_numeric(True)
self.memSpin.connect("value_changed", self.updateAvail, self.kdumpMem)
self.labelKdump = gtk.Label(_("_Kdump Memory (MB):"))
self.labelKdump.set_use_underline(True)
self.labelKdump.set_mnemonic_widget(self.kdumpMem)
self.labelKdump.set_alignment(0.0, 0.5)
# remaining usable system memory
self.resMem = eval(string.strip(self.kdumpMem.get_text()))
self.remMem = self.availMem - self.resMem
self.systemUsableMem = gtk.Label(_("%s" % self.remMem))
self.labelSys = gtk.Label(_("_Usable System Memory (MB):"))
self.labelSys.set_use_underline(True)
self.labelSys.set_mnemonic_widget(self.systemUsableMem)
self.labelSys.set_alignment(0.0, 0.5)
self.vbox = gtk.VBox()
self.vbox.set_size_request(400, 200)
title_pix = functions.imageFromFile("workstation.png")
internalVBox = gtk.VBox()
internalVBox.set_border_width(10)
internalVBox.set_spacing(10)
label = gtk.Label(_("Kdump is a kernel crash dumping mechanism. In the event of a "
"system crash, kdump will capture information from your system "
"that can be invaluable in determining the cause of the crash. "
"Note that kdump does require reserving a portion of system "
"memory that will be unavailable for other uses."))
label.set_line_wrap(True)
label.set_alignment(0.0, 0.5)
label.set_size_request(500, -1)
internalVBox.pack_start(label, False, True)
table = gtk.Table(2, 4)
table.attach(self.enableKdumpCheck, 0, 2, 0, 1, gtk.FILL, gtk.FILL, 5, 5)
table.attach(self.labelTotal, 0, 1, 1, 2, gtk.FILL)
table.attach(self.totalMem, 1, 2, 1, 2, gtk.SHRINK, gtk.FILL, 5, 5)
table.attach(self.labelKdump, 0, 1, 2, 3, gtk.FILL)
table.attach(self.kdumpMem, 1, 2, 2, 3, gtk.SHRINK, gtk.FILL, 5, 5)
table.attach(self.labelSys, 0, 1, 3, 4, gtk.FILL)
table.attach(self.systemUsableMem, 1, 2, 3, 4, gtk.SHRINK, gtk.FILL, 5, 5)
# disable until user clicks check box, if not already enabled
if self.initialState is False:
self.showHide(False)
else:
self.enableKdumpCheck.set_active(True)
internalVBox.pack_start(table, True, 15)
# toggle sensitivity of Mem items
self.enableKdumpCheck.connect("toggled", self.on_enableKdumpCheck_toggled)
self.vbox.pack_start(internalVBox, False, 15)
return self.vbox, title_pix, self.moduleName
def grabFocus(self):
self.enableKdumpCheck.grab_focus()
def apply(self, *args):
if self.kdumpEnabled:
totalSysMem = self.totalMem.get_text()
totalSysMem = eval(string.strip(totalSysMem))
reservedMem = self.kdumpMem.get_value_as_int()
remainingMem = totalSysMem - reservedMem
else:
reservedMem = self.kdumpMemInitial
if self.doDebug:
print "Running kernel %s on %s architecture" % (self.runningKernel, self.arch)
if self.enableKdumpCheck.get_active():
print "System Mem: %s MB Kdump Mem: %s MB Avail Mem: %s MB" % (totalSysMem, reservedMem, remainingMem)
else:
print "Kdump will be disabled"
# If we're running on non-ia64 xen, we still need a non-xen kernel to kexec
# into for kdump to be able to capture a core (ia64 xen not supported yet)
# FIXME: can we set this up automagically if we already have a
# non-xen kernel available?
if self.xenKernel and self.kdumpEnabled and self.arch == 'ia64':
self.showErrorMessage(_("Sorry, ia64 xen kernels do not support kdump at this time."))
self.enableKdumpCheck.set_active(False)
self.showHide(False)
return 0
elif self.xenKernel and self.kdumpEnabled:
self.showErrorMessage(_("WARNING: xen kdump support requires a non-xen %s RPM to perform actual crash dump capture. Please be sure you have the non-xen %s RPM of the same version as your xen kernel installed." % (self.xenKdumpKernel, self.xenKdumpKernel)))
# If the user simply doesn't have enough memory for kdump to be viable/supportable, tell 'em
if self.enoughMem is False and self.kdumpEnabled:
self.showErrorMessage(_("Sorry, your system does not have enough memory for kdump to be viable!"))
self.enableKdumpCheck.set_active(False)
self.showHide(False)
return 0
# If there's no kdump support on this arch, let the user know and don't configure
elif self.arch in self.unsupportedArches:
self.showErrorMessage(_("Sorry, the %s architecture does not support kdump at this time!" % self.arch))
self.enableKdumpCheck.set_active(False)
self.showHide(False)
return 0
# If running on an arch w/a separate kernel-kdump (i.e., non-relocatable kernel), check to
# see that its installed, otherwise, alert the user they need to install it, and give them
# the chance to abort configuration.
if self.arch in self.kernelKdumpArches and self.kernelKdumpInstalled is False:
kernelKdumpNote = "\n\nNote that the %s architecture does not feature a relocatable kernel at this time, and thus requires a separate kernel-kdump package to be installed for kdump to function. This can be installed via 'yum install kernel-kdump' at your convenience.\n\n" % self.arch
else:
kernelKdumpNote = ""
# Don't alert if nothing has changed
if self.initialState != self.kdumpEnabled or reservedMem != self.kdumpMemInitial:
dlg = gtk.MessageDialog(None, 0, gtk.MESSAGE_INFO,
gtk.BUTTONS_YES_NO,
(_("Changing Kdump settings requires rebooting the "
"system to reallocate memory accordingly. %sWould you "
"like to continue with this change and reboot the "
"system after firstboot is complete?" % kernelKdumpNote)))
dlg.set_position(gtk.WIN_POS_CENTER)
dlg.show_all()
rc = dlg.run()
dlg.destroy()
if rc == gtk.RESPONSE_NO:
self.needsReboot = False
return None
else:
self.needsReboot = True
# Find bootloader if it exists, and update accordingly
if self.getBootloader() == None:
self.showErrorMessage(_("Error! No bootloader config file found, aborting configuration!"))
self.enableKdumpCheck.set_active(False)
self.showHide(False)
return 0
else:
self.kpath = self.bootloaders[self.bootloader][2]
# x86_64 typically use a 16M offset, but w/xen, we need 32M atm
if self.arch == 'x86_64' and self.xenKernel:
self.offset = 32
else:
self.offset = self.bootloaders[self.bootloader][1]
# Are we adding or removing the crashkernel param?
if self.kdumpEnabled and not self.xenKernel:
# crashkernel goes on the kernel line, --args puts it there for us
grubbyCmd = "/sbin/grubby --%s --update-kernel=%s/vmlinuz-%s --args=crashkernel=%iM@%iM" \
% (self.bootloader, self.kpath, self.runningKernel, reservedMem, self.offset)
chkconfigStatus = "on"
elif self.kdumpEnabled and self.xenKernel:
# crashkernel goes on the xen line, --mbargs puts it there for us
grubbyCmd = "/sbin/grubby --%s --update-kernel=%s/vmlinuz-%s --mbargs=crashkernel=%iM@%iM" \
% (self.bootloader, self.kpath, self.runningKernel, reservedMem, self.offset)
chkconfigStatus = "on"
elif self.xenKernel:
grubbyCmd = "/sbin/grubby --%s --update-kernel=%s/vmlinuz-%s --remove-mbargs=crashkernel=%s" \
% (self.bootloader, self.kpath, self.runningKernel, self.origCrashKernel)
chkconfigStatus = "off"
else:
grubbyCmd = "/sbin/grubby --%s --update-kernel=%s/vmlinuz-%s --remove-args=crashkernel=%s" \
% (self.bootloader, self.kpath, self.runningKernel, self.origCrashKernel)
chkconfigStatus = "off"
if self.doDebug:
print "Using %s bootloader with %iM offset" % (self.bootloader, self.offset)
print "Grubby command would be:\n %s" % grubbyCmd
else:
os.system(grubbyCmd)
os.system("/sbin/chkconfig kdump %s" % chkconfigStatus)
if self.bootloader == 'yaboot':
os.system('/sbin/ybin')
else:
self.needsReboot = False
return 0
def showErrorMessage(self, text):
dlg = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, text)
dlg.set_position(gtk.WIN_POS_CENTER)
dlg.set_modal(True)
rc = dlg.run()
dlg.destroy()
return None