diff options
Diffstat (limited to 'plugins/grub.py')
-rw-r--r-- | plugins/grub.py | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/plugins/grub.py b/plugins/grub.py new file mode 100644 index 0000000..146ee6f --- /dev/null +++ b/plugins/grub.py @@ -0,0 +1,192 @@ +# First Aid Kit - diagnostic and repair tool for Linux +# Copyright (C) 2007 Martin Sivak <msivak@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. + +from pyfirstaidkit.plugins import Plugin,Flow +from pyfirstaidkit.reporting import PLUGIN +from pyfirstaidkit.returns import * +from pyfirstaidkit.configuration import Config,getConfigBits +from pyfirstaidkit.utils import spawnvch +from pyfirstaidkit.issue import SimpleIssue +import os.path +import difflib +import re +import copy + +cfgBits = getConfigBits("firstaidkit-plugin-grub") +import sys +sys.path.append(cfgBits.anaconda.path) +sys.path.append(cfgBits.booty.path) + +class Sample1Plugin(Plugin): + """This plugin checks the GRUB bootloader.""" + name = "GRUB plugin" + version = "0.0.1" + author = "Martin Sivak" + + flows = Flow.init(Plugin) + flows["install"] = Flow({ + Plugin.initial: {Return: "prepare"}, + "prepare" : {ReturnSuccess: "diagnose", ReturnFailure: "clean", None: "clean"}, + "diagnose" : {ReturnSuccess: "clean", ReturnFailure: "backup", None: "clean"}, + "backup" : {ReturnSuccess: "install", ReturnFailure: "clean", None: "clean"}, + "restore" : {ReturnSuccess: "clean", ReturnFailure: "clean", None: "clean"}, + "install" : {ReturnSuccess: "clean", ReturnFailure: "restore", None: "restore"}, + "clean" : {ReturnSuccess: Plugin.final, ReturnFailure: Plugin.final, None: "clean"} + }, description="Install the bootloader into the partition specified in parameters") + + @classmethod + def getDeps(cls): + return set(["experimental", "root", "filesystem", "arch-x86"]) + + def __init__(self, *args, **kwargs): + Plugin.__init__(self, *args, **kwargs) + self._partitions = set() #partitions in the system + self._drives = [] #drives in the system + self._bootable = [] #partitions with boot flag + self._linux = [] #Linux type partitions (0x83 Linux) + self._grub_dir = set() #directories with stage1, menu.lst and other needed files + self._grub = set() #devices with possible grub instalation + self._grub_map = {} #mapping from linux device names to grub device names + self._grub_mask = re.compile("""\(hd[0-9]*,[0-9]*\)""") + + self._issue_boot_flag = SimpleIssue("Bootable partition", "No bootable partition found in partition table and GRUB is not MBR installed") + self._issue_grub_dir = SimpleIssue("GRUB directory", "No GRUB directory was not found") + self._issue_grub_installed = SimpleIssue("GRUB installed", "No GRUB was found in bootable partitions or MBR") + + def prepare(self): + from bootloaderInfo import x86BootloaderInfo + self._bootloaderInfo = x86BootloaderInfo() + self._result=ReturnSuccess + + self._issue_boot_flag.set(reporting = self._reporting, origin = self, level = PLUGIN) + self._issue_grub_dir.set(reporting = self._reporting, origin = self, level = PLUGIN) + self._issue_grub_installed.set(reporting = self._reporting, origin = self, level = PLUGIN) + + def backup(self): + self._result=ReturnSuccess + + def restore(self): + self._result=ReturnSuccess + + def diagnose(self): + #Find partitions + self._reporting.debug(origin = self, level = PLUGIN, message = "Reading partition list") + self._partitions = set(map(lambda l: l.split()[3], file("/proc/partitions").readlines()[2:])) + + #and select only partitions with minor number 0 -> drives + self._drives = map(lambda l: l.split(), file("/proc/partitions").readlines()[2:]) + self._drives = filter(lambda l: l[1]=="0", self._drives) + self._drives = map(lambda l: l[3], self._drives) + + #get boot flags + self._reporting.debug(origin = self, level = PLUGIN, message = "Locating bootable partitions") + for d in self._drives: + fdisk = spawnvch(executable = "/sbin/fdisk", args = ["fdisk", "-l", "/dev/%s" % (d,)], chroot = Config.system.root) + ret = fdisk.wait() + if ret==0: + for l in fdisk.stdout.readlines(): + if l.startswith("/dev/%s" % (d,)): + data = l.split() + if data[1]=="*": #boot flag + self._reporting.info(origin = self, level = PLUGIN, message = "Bootable partition found: %s" % (data[0][5:],)) + self._bootable.append(data[0][5:]) #strip the "/dev/" beginning + if data[6]=="Linux": + self._linux.append(data[0][5:]) + self._reporting.debug(origin = self, level = PLUGIN, message = "Linux partition found: %s" % (data[0][5:],)) + else: + if data[5]=="Linux": + self._linux.append(data[0][5:]) + self._reporting.debug(origin = self, level = PLUGIN, message = "Linux partition found: %s" % (data[0][5:],)) + + if len(self._bootable) == 0: + self._issue_boot_flag.set(checked = True, happened = True, reporting = self._reporting, origin = self, level = PLUGIN) + + + #Find grub directories + self._reporting.debug(origin = self, level = PLUGIN, message = "Locating the grub directories") + grub = spawnvch(executable = "/sbin/grub", args = ["grub", "--batch"], chroot = Config.system.root) + (stdout, stderr) = grub.communicate("find /boot/grub/menu.lst\nfind /grub/menu.lst\n") + for l in stdout.split("\n"): + if self._grub_mask.search(l): + self._reporting.info(origin = self, level = PLUGIN, message = "Grub directory found at %s" % (l.strip(),)) + self._grub_dir.add(l.strip()) + + if len(self._grub_dir) == 0: + self._issue_grub_dir.set(checked = True, happened = True, reporting = self._reporting, origin = self, level = PLUGIN) + + #TODO Mount the required partitions from self._grub_dir and read the important files from there + for gdrive in self._grub_dir: + drive, partition = gdrive[3:-1].split(",") + devicename = "%s%d" % (self._bootloaderInfo.drivelist[drive], int(partition)+1) + #XXX here, check the mount + + #Read the device map + self._reporting.debug(origin = self, level = PLUGIN, message = "Reading device map") + try: + for l in file(os.path.join(Config.system.root, "/boot/grub/device.map"), "r").readlines(): + if l.startswith("#"): + continue + (v,k) = l.split() + self._grub_map[k] = v + except OSError, e: + self._reporting.warning(origin = self, level = PLUGIN, message = "Device map file not found: %s" % (str(e),)) + pass #the file is not there, bad but not a reason to crash + + #Find out where is the grub installed + try: + stage1mask = file(os.path.join(Config.system.root, "/boot/grub/stage1"), "r").read(512) + bootsectors = {} + for p in self._partitions: + self._reporting.debug(origin = self, level = PLUGIN, message = "Reading boot sector from %s" % (p,)) + bootsector = file(os.path.join("/dev", p), "r").read(512) + bootsectors[bootsector] = self._bootloaderInfo.grubbyPartitionName(p) + + for k in difflib.get_close_matches(stage1mask, bootsectors.keys()): + self._reporting.info(origin = self, level = PLUGIN, message = "Installed Grub probably found at %s" % (bootsectors[k],)) + self._grub.add(bootsectors[k]) + except OSError, e: + self._reporting.warning(origin = self, level = PLUGIN, message = "Stage1 image not found: %s" % (str(e),)) + pass #the file is not there, too bad but not a reason to crash the diagnose + + #if there is the grub configuration dir and the grub appears installed into MBR or bootable partition, then we are probably OK + if len(self._grub_dir)>0 and len(self._grub)>0 and len(set(self._grub).intersection(set(self._bootable+self._drives)))>0: + self._result=ReturnSuccess + self._issue_grub_installed.set(checked = True, happened = False, reporting = self._reporting, origin = self, level = PLUGIN) + self._issue_boot_flag.set(checked = True, happened = False, reporting = self._reporting, origin = self, level = PLUGIN) #if we can find bootable, than it didn't happen + self._dependencies.provide("boot-grub") + else: + self._issue_grub_installed.set(checked = True, happened = True, reporting = self._reporting, origin = self, level = PLUGIN) + self._result=ReturnFailure + + def fix(self): + self._result=ReturnFailure + self._issue_boot_flag.set(fixed = False, reporting = self._reporting, origin = self, level = PLUGIN) + self._issue_grub_dir.set(fixed = False, reporting = self._reporting, origin = self, level = PLUGIN) + self._issue_grub_installed.set(fixed = False, reporting = self._reporting, origin = self, level = PLUGIN) + + def install(self): + #install the grub to Config.operation.params partition + self._reporting.info(origin = self, level = PLUGIN, message = "Installing grub into %s (%s)" % (Config.operation.params, self._bootloaderInfo.grubbyPartitionName(Config.operation.params))) + grub = spawnvch(executable = "/sbin/grub", args = ["grub", "--batch"], chroot = Config.system.root) + (stdout, stderr) = grub.communicate("root %s\nsetup %s\n" % (self._grub_dir[0], self._bootloaderInfo.grubbyPartitionName(Config.operation.params))) + self._result=ReturnFailure + + def clean(self): + self._result=ReturnSuccess + +def get_plugin(): + return Sample1Plugin |