summaryrefslogtreecommitdiffstats
path: root/plugins/grub.py
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/grub.py')
-rw-r--r--plugins/grub.py192
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