diff options
| author | Joel Andres Granados <jgranado@redhat.com> | 2008-08-06 16:06:30 +0200 |
|---|---|---|
| committer | Joel Andres Granados <jgranado@redhat.com> | 2008-08-07 15:20:47 +0200 |
| commit | 7e334e5e4626d8696e8127e494c9eee2fcbb8474 (patch) | |
| tree | abf15a2c6edce89bfd0552307d91a5520363413e | |
| parent | 7f2d0899817cd7894b44ab014d1a0744691ac7d0 (diff) | |
| download | firstaidkit-7e334e5e4626d8696e8127e494c9eee2fcbb8474.tar.gz firstaidkit-7e334e5e4626d8696e8127e494c9eee2fcbb8474.tar.xz firstaidkit-7e334e5e4626d8696e8127e494c9eee2fcbb8474.zip | |
Initial commit for the Grub plugin.
Nothing was used from the original grub plugin. For now
they will both coexists in the code.
| -rw-r--r-- | firstaidkit.spec | 17 | ||||
| -rw-r--r-- | plugins/grub/__init__.py | 20 | ||||
| -rw-r--r-- | plugins/grub/grub.py | 261 | ||||
| -rw-r--r-- | plugins/grub/grubUtils.py | 406 | ||||
| -rw-r--r-- | plugins/grub/grubconf.py | 17 | ||||
| -rw-r--r-- | plugins/grub/minihal.py | 74 | ||||
| -rw-r--r-- | pyfirstaidkit/utils/__init__.py | 11 |
7 files changed, 801 insertions, 5 deletions
diff --git a/firstaidkit.spec b/firstaidkit.spec index a840e58..0848f43 100644 --- a/firstaidkit.spec +++ b/firstaidkit.spec @@ -91,7 +91,11 @@ configuration file xorg.conf. Group: Applications/System Summary: FirstAidKit plugin to diagnose or repair the GRUB instalation Requires: %{name} = %{version}-%{release} -Requires: anaconda, booty +#Requires: anaconda, booty + +Requires: dbus-python +Requires: grub +Requires: pyparted %description plugin-grub This FirstAidKit plugin automates the recovery from the GRUB bootloader problems. @@ -172,8 +176,10 @@ desktop-file-install --vendor="fedora" --dir=${RPM_BUILD_ROOT}%{_datadir}/applic %{__cp} -f plugins/rpm/*.py $RPM_BUILD_ROOT%{_libdir}/firstaidkit/plugins/rpm/ %{__install} -d $RPM_BUILD_ROOT%{_libdir}/firstaidkit/plugins/rpm_lowlevel %{__cp} -f plugins/rpm_lowlevel/*.py $RPM_BUILD_ROOT%{_libdir}/firstaidkit/plugins/rpm_lowlevel/ -%{__cp} -f plugins/grub.py $RPM_BUILD_ROOT%{_libdir}/firstaidkit/plugins/ -%{__install} -p etc/firstaidkit/firstaidkit-plugin-grub $RPM_BUILD_ROOT%{_sysconfdir}/firstaidkit +#%{__cp} -f plugins/grub.py $RPM_BUILD_ROOT%{_libdir}/firstaidkit/plugins/ +#%{__install} -p etc/firstaidkit/firstaidkit-plugin-grub $RPM_BUILD_ROOT%{_sysconfdir}/firstaidkit +%{__install} -d $RPM_BUILD_ROOT%{_libdir}/firstaidkit/plugins/grub +%{__cp} -f plugins/grub/*.py $RPM_BUILD_ROOT%{_libdir}/firstaidkit/plugins/grub %{__cp} -f plugins/mdadm_conf.py $RPM_BUILD_ROOT%{_libdir}/firstaidkit/plugins/ @@ -217,8 +223,9 @@ desktop-file-install --vendor="fedora" --dir=${RPM_BUILD_ROOT}%{_datadir}/applic %{_libdir}/firstaidkit/plugins/rpm/* %files plugin-grub -%{_libdir}/firstaidkit/plugins/grub.py* -%{_sysconfdir}/firstaidkit/firstaidkit-plugin-grub +#%{_libdir}/firstaidkit/plugins/grub.py* +#%{_sysconfdir}/firstaidkit/firstaidkit-plugin-grub +%{_libdir}/firstaidkit/plugins/grub/* %files plugin-mdadm-conf %{_libdir}/firstaidkit/plugins/mdadm_conf.py* diff --git a/plugins/grub/__init__.py b/plugins/grub/__init__.py new file mode 100644 index 0000000..dfeb749 --- /dev/null +++ b/plugins/grub/__init__.py @@ -0,0 +1,20 @@ +# First Aid Kit - diagnostic and repair tool for Linux +# Copyright (C) 2008 Joel Andres Granados <jgranado@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 grub +def get_plugin(): + return grub.Grub diff --git a/plugins/grub/grub.py b/plugins/grub/grub.py new file mode 100644 index 0000000..8056218 --- /dev/null +++ b/plugins/grub/grub.py @@ -0,0 +1,261 @@ +# First Aid Kit - diagnostic and repair tool for Linux +# Copyright (C) 2008 Joel Andres Granados <jgranado@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.returns import * +from pyfirstaidkit.utils import * +from pyfirstaidkit.reporting import PLUGIN +from pyfirstaidkit.issue import SimpleIssue +from pyfirstaidkit import Config +from pyfirstaidkit.errors import * + +from grubUtils import Dname +import grubUtils + +import os + +class Grub(Plugin): + """Plugin to detect and fix grub failure.""" + flows = Flow.init(Plugin) + name = "Grub" + version = "0.0.1" + author = "Joel Andres Granados" + + @classmethod + def getDeps(cls): + return set(["root", "experimental", "filesystem"]) + + def __init__(self, *args, **kwargs): + Plugin.__init__(self, *args, **kwargs) + + # The key is a dev name, the value is a list of partitions in drive. + self.devices = {} + + # The partitions where the grub directory and all the necessary files + # found. + self.grub_dir_parts = [] + + # The partitions where the grub binary is found in the first 446 bytes. + self.grub_bin_parts = [] + + # The devs where the grub binary is found in the first 446 bytes. + self.grub_bin_devs = [] + + # Initialize our list of related issues. + self.issue_grub_dir = SimpleIssue(self.name, "Missing grub dir or " \ + "dir files.") + self.issue_grub_image = SimpleIssue(self.name, "Bad grub stage1 image.") + + # Initialize the backup space. + self.backupSpace = self._backups.getBackup(str(self)) + + def prepare(self): + self._reporting.info("Initializing the search for all the grub " \ + "related elements.", origin = self) + + try: + # We end up with a structure where the keys are the drive names. + self.devices = grubUtils.get_all_devs() + + self._reporting.info("Searching for grub related files in the " \ + "system storage devices.", origin = self) + # We must search in all the possible partitions for the grub files: + # stage1, stage1.5, stage2.... When we find these directories we + # will be able to install grub from there. And the vmliuz (kernel + # image), initrd.img, the grub.conf is probably in these places as + # well. + for (dev, parts) in self.devices.iteritems(): + for part in parts: + try: + if grubUtils.grub_dir_in_partition(part): + self._reporting.info("Found grub dir in %s " \ + "partition." % part.path(), origin = self) + self.grub_dir_parts.append(part) + except Exception, e: + # If something happened while checking the partition + # it will not be taken into account. + self._reporting.error("There was an error while " \ + "searching partition %s. Error: %s." % \ + (part.path(), e) ,origin = self) + + self._reporting.info("Searching for the grub stage1 image.", \ + origin = self) + # We must search in all the possible partitions and devices for the + # grub binary. + for (dev, parts) in self.devices.iteritems(): + + # We look for grub in the device + try: + if grubUtils.grub_bin_in_dev(Dname(dev)): + self._reporting.info("Found grub stage1 image in %s " \ + "device" % Dname.asPath(dev), origin = self) + self.grub_bin_devs.append(grubUtils.Dname(dev)) + + except Exception, e: + self._reporting.error("There was an error searching for " \ + "the grub images in device %s. Error %s." % \ + (Dname.asPath(dev), e), origin = self) + + # No we look for the grub in the partitions. + for part in parts: + try: + if grubUtils.grub_bin_in_part(Dname(part)): + self._reporting.info("Found grub stage1 image " \ + "in %s partition" % Dname.asPath(dev), \ + origin = self) + self.grub_bin_parts.append(Dname(part)) + + except Exception, e: + self._reporting.error("There was an error searching " \ + "for grub images in partition %s. Error %s." % \ + (Dname.asPath(part), e), origin = self) + + self._result = ReturnSuccess + except Exception, e: + self._reporting.error("An error has ocurred while searching for " \ + "grubs elements. Error: %s" % e, origin = self) + self._result = ReturnFailure + + def diagnose(self): + # FIXME ATM we will not take care of the cases that are missing some + # stuff from the grub directory, like images and conffile. + # + # The diagnose is tricky because we have no way of knowing (yet) if + # the images found in the devices actually map correctly to the stuff + # that we found on the directories. This means that we will allways + # reinstall grub in the mbr (the changes will be revertable so its + # not that bad) unless we don't find any directory. If no dir is + # found, then we fail (fail in this case means postponing the decision + # until the fix step to actually ReturnFailure) + self._reporting.info("Diagnosing the current state of grub.", + origin = self) + if len(self.grub_dir_parts) < 0: + self._reporting.error("No grub directories where found.", + origin = self) + + self.issue_grub_dir.set(checked = True, happened = True, + reporting = self._reporting, origin = self) + self.issue_grub_image.set(checked = False, + reporting = self._reporting, origin = self) + + self._result = ReturnFailure + return + self.issue_grub_dir.set(checked = True, happened = False, + reporting = self._reporting, origin = self) + + # At this point we know that we are going to reinstall the grub. We + # inform the user about the state of the stage1 in the partitions but + # we do nothing else with this information. + if len(self.grub_bin_parts) == 0: + self._reporting.info("No valid grub image was found in any " \ + "partition in the system.", origin = self) + if len(self.grub_bin_devs) == 0: + self._reporting.info("No valid grub image was found in any " \ + "device in the system.", origin = self) + + # Only if there is no recognizable image do we consider it to be + # an issue. + if len(self.grub_bin_parts) == 0 and len(self.grub_bin_devs) == 0: + self.issue_grub_image.set(checked = True, happened = True, + reporting = self._reporting, origin = self) + else: + self.issue_grub_image.set(checked = True, happened = False, + reporting = self._reporting, origin = self) + + self._result = ReturnFailure + + + def backup(self): + # The grub process is related to the 446 firsta bytes of the partitions + # of the device. This means we must backup all the beginings fo the + # partitions and devices that we will possibly modify. + + # Since we are going to install the stage1 grub image in all the + # devices, we will backup all of them. + self._reporting.info("Going to backup all the first 446 bytes of " \ + "all storage devices in the system.", origin = self) + for (device, partitions) in self.devices.iteritems(): + fd = os.open(Dname.asPath(device), os.O_RDONLY) + first446btemp = os.read(fd, 446) + os.close(fd) + self.backupSpace.backupValue(first446btemp, Dname.asName(device)) + self._result = ReturnSuccess + + + def fix(self): + # We ar to fail if there is no dirs. + if len(self.grub_dir_parts) == 0: + self._reporting.error("No grub directories where found... exiting.", + origin = self) + self.issue_grub_image.set(fixed = False, \ + reporting = self._reporting, origin = self) + self.issue_grub_image.set(fixed = False, \ + reporting = self._reporting, origin = self) + + self._result = ReturnFailure + return + + # Choose and prepare one root in the system. + # FIXME: extend the root concept so it can handle varous roots in a + # system. For now we just select the first and hope it has + # everything. + + # Install the grub in all devs pointing at the special root part. + for (drive, partitions) in self.devices.iteritems(): + self._reporting.info("Trying to install grub on drive %s, " \ + "pointing to grub directory in %s."%(Dname.asName(drive), \ + self.grub_dir_parts[0].path()), origin = self) + try: + grubUtils.install_grub(self.grub_dir_parts[0], Dname(drive)) + except Exception, e: + self._reporting.error("Grub installation on drive %s, " \ + "pointing to grub directory in %s has failed." % \ + (Dname.asName(drive), self.grub_dir_parts[0].path()), \ + origin = self) + # If one installation fails its safer to just restore + # everything + self._result = ReturnFailure + return + + self._reporting.info("Grub has successfully installed in all the " \ + "devices.", origin = self) + self._result = ReturnSuccess + + def restore(self): + self._reporting.info("Starting the restore process....", level=PLUGIN, \ + origin = self) + for (device, partitions) in self.devices.iteritems(): + self._reporting.info("Restoring data from device %s" % \ + Dname.asPath(device), origin = self) + try: + # Get the value from the backup space + first446btemp = self.backupSpace.restoreValue( + Dname.asName(device)) + + # Copy the value over the existing stuff. + fd = os.open(Dname.asPath(device), os.O_WRONLY) + os.write(fd, first446btemp) + os.close(fd) + except Exception, e: + self._reporting.info("An error has occurred while trying to " \ + "recover %s device." % Dname.asName(device), \ + origin = self) + continue + self._result = ReturnSuccess + + def clean(self): + self._result = ReturnSuccess diff --git a/plugins/grub/grubUtils.py b/plugins/grub/grubUtils.py new file mode 100644 index 0000000..6a5578f --- /dev/null +++ b/plugins/grub/grubUtils.py @@ -0,0 +1,406 @@ +# First Aid Kit - diagnostic and repair tool for Linux +# Copyright (C) 2008 Joel Andres Granados <jgranado@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 pyfirstaidkit.utils as utils + +import os.path +import re +import subprocess +import tempfile + +import minihal +import parted + +# List of known or expected values for the system. +# +# Where the grub dir shoulc be with respect to the partition root. +locations = ["/boot/grub", "/grub"] + +# The files that are expected to make grub work. nfiles -> needed files. +nfiles = ["stage1", "stage2"] + +# Expected grub configuration file name. +conffile = "grub.conf" + +# Expected mounts file +mounts = "/proc/mounts" + +# Disks starting with these strings will be ignored when looking for system +# storage devices. +ignore_devs = ["sr"] + +def get_all_devs(): + """Get all the storage devices that exists currently on the system. + + We only want the device name and the partitions for each device. + We don't want the parted structures. + Return - dictionary with device name and all device partitions. + """ + + # Must use an inner function as the test does not consider the device + # number. Olny device type. + def is_dev_in_ignored(dev): + for ignored in ignore_devs: + if dev["device"].replace("/dev/","").startswith(ignored): + return True + return False + + retval = {} + for device in minihal.get_devices_by_type("storage"): + if device is None: + continue + + elif is_dev_in_ignored(device): + continue + + elif "storage.removable.media_available" in device.keys() and \ + device["storage.removable.media_available"] == False: + # We ignore stuff that has no media inserted. + continue + + else: + # parted will provide us with all the partitions. + partitions = [] + parteddev = parted.PedDevice.get(device["device"]) + disk = parted.PedDisk.new(parteddev) + part = disk.next_partition() + while part: + if part.num > 0: + partitions.append( + Dname("%s%s"%(device["device"],part.num))) + part = disk.next_partition(part) + # The key will be the device name and it will contain a list of + # parts. + retval[Dname.asName(device["device"])] = partitions + + return retval + +def grub_dir_in_partition(part): + """Search for the grub directory and all needed files in the partition + + It will search for the known locations and necessary files for in the + specified partition. + Return - list containing partitions with grub. + """ + def do_unmount(): + part_unmount(part) + if os.path.isdir(mountpoint): + os.rmdir(mountpoint) + + + # We search to see if the partition is mounted. If its not we must + # mount it in a temporary place to unmount it before we leave this + # function. + unmount=False + mountpoint = is_part_mounted(part) + if len(mountpoint) == 0: + # This means that its not mounted. And we must unmount it at the + # end. + unmount=True + + # Select a safe temporary directory where to mount it. + mountpoint = tempfile.mkdtemp(prefix=part.name()) + + # If the mount fails it will raise an excpetion. We must catch the + # exception when this function is called. Same goes for part_unmount. + try: + part_mount(part, mountpoint) + except: + # The partition was not mounted erase the directory if empty. + # leave if the directoy is not empty + os.rmdir(mountpoint) + return False + + # Search for the grub directorie in the mounted partition. + grubdir="" + for dir in locations: + if os.path.isdir(utils.join(mountpoint, dir)): + grubdir=utils.join(mountpoint, dir) + # We don't care if there is another directory in the same partition + # It is very unlikely and not an intelligent thing to do anyway. + break + + # At this point if we didn't find any of the locations, then grub is not + # in this partition. + if len(grubdir) == 0: + if unmount: + do_unmount() + return False + + # Now we have to search for the files in the grub directory. The list in + # nfiles is the needed files. So if one of the files is not found we + # consider that there is not enough context to fix the issue in this part. + # FIXME add some code that can replace the files that are missing. + foundfiles = 0 + for file in nfiles: + if os.path.isfile(utils.join(grubdir, file)): + foundfiles = foundfiles + 1 + + # If we don't have all the files we will not even consider this partition. + if len(nfiles) > foundfiles: + if unmount: + do_unmount() + return False + + # Search for the grub config file. + if not os.path.isfile(utils.join(grubdir, conffile)): + if unmount: + do_unmount + return False + + # FIXME need to implement the kernel and initrd image searching code. + # for now we trust that the images are actually there. + + if unmount: + do_unmount() + + return True + +def is_part_mounted(part): + """Search /proc/mounts for the presence of the partition. + + It searches for the "/dev/something" device. + If its not mounted it returns an empty mountpoint (not mounted). + If its mounted it returns the mount point. + """ + for line in file(mounts).readlines(): + if re.search(part.path(), line) != None: + # The mountpoint is in the second possition. + return line.split(" ")[1] + + return "" + +def part_mount(part, mountPoint, opts=None): + """Mount the partition at mountpoint""" + # Create the call + call = ["mount"] + if opts: + call.append(opts) + call.extend([part.path(), mountPoint]) + + # Call mount + proc = subprocess.Popen(call, stdout=subprocess.PIPE, \ + stderr=subprocess.PIPE) + (out, err) = proc.communicate() + retcode = proc.wait() + if retcode != 0 or len(err) > 0: + # The mount failed + raise Exception("%s" % (part.path(), err)) + else: + # This probably means that the mount succeded. + return True + +def part_unmount(part, opts=None): + """Unmount the partition that is mounted at mountPoint + + part - It can actually be the part path or the mountpoint + """ + + # If its not a dev path its a mountpoint. + if part.__class__.__name__ == "Dname": + umountarg = part.path() + else: + umountarg = part + + # Create the call + call = ["umount"] + if opts: + call.append(opts) + call.append(umountarg) + + # Call umount + proc = subprocess.Popen(call, stdout=subprocess.PIPE, \ + stderr=subprocess.PIPE) + (out, err) = proc.communicate() + retcode = proc.wait() + if retcode != 0 or len(err) > 0: + raise Exception("There was an error unmounting partition %s. " \ + "Error: %s." % (part.path(), err)) + else: + return True + +# The Strings contained in the grub stage one: +stage1strings = ["GRUB", "Geom", "Hard", "Disk", "Read", "Error"] + +def grub_bin_in_dev(dev): + """Will look in the first 446 bytes of the device for traces of grub. + + Will look for the strings that come with the grub stage1 image. The + strings are: "GRUB", "Geom", "Hard", "Disk", "Read" and "Error". These + strings must be compared considering the letter case. + dev - Dname object representing the storage device. + """ + if (os.path.exists(dev.path())): + + # Read the first 446 bytes of the dev. + fd = os.open(dev.path(), os.O_RDONLY) + first446b = os.read(fd, 446) + os.close(fd) + + # Search for all the strings + foundstrings = 0 + for string in stage1strings: + if re.search(string, first446b) != None: + foundstrings = foundstrings + 1 + + # Only if all the strings are present we give the goahead. + if foundstrings == len(stage1strings): + return True + + return False + + +def grub_bin_in_part(part): + """Will look in the first 446 bytes of the partition for traces of grub. + + Same conditions apply as in grub_bin_in_dev. + """ + return grub_bin_in_dev(part) + +# Input string for the grub batch mode. +# FIXME: Do we need lba, stage2 specification, prefix? +batch_grub_install = """ +root (%s) +setup (%s) +quit +""" +def install_grub(root, setup): + """Install stage1 grub image in the specified place. + + root - the root where the dir is. This can be a divice or partition. + It must be a Dname + setup - the dev where to install image. This can be device or partition. + It must be a Dname + + return - whatever the grub console puts on stdout. + """ + + # Construct the root string. + grubroot = root.grubName() + grubsetup = setup.grubName() + + # Run the command that installs the grub. + # FIXME: We are not taking into account the device map. + command = ["grub", "--batch"] + proc = subprocess.Popen(command, stdout = subprocess.PIPE, + stdin = subprocess.PIPE, stderr = subprocess.PIPE) + (out, err) = proc.communicate(batch_grub_install%(grubroot, grubsetup)) + + m = re.search("Error.*\\n", "%s%s"%(out,err)) + if m != None: + # raise an exception when grub shell returned an error. + raise Exception("There was an error while installing grub. Error %s " \ + % m.group(0)) + + return out + +# I really don't like the fact that you can have a variable that represents +# a device or partition and not know, until runtime, with total certainty, +# if its "/dev/something" or just "something". + +# The constant to transform a device leter to a grub hd number. ciconst +# (char int constant) +ciconst = ord('a') +class Dname: + """Class to represent device names. + + It will only represent device and partitiosn. + """ + # FIXME: extend this class to raid. + def __init__(self, name): + if name.__class__.__name__ == "Dname": + self.dname = name.dname + elif name.startswith("/dev/"): + self.dname = name[5:] + else: + self.dname = name + + @classmethod + def asPath(self, dev): + """return the device in the "/dev/somthing" form.""" + if dev.__class__.__name__ == "Dname": + return dev.path() + else: + temp = Dname(dev) + return temp.path() + + @classmethod + def asName(self, dev): + """return the device in the "somthing" form""" + if dev.__class__.__name__ == "Dname": + return dev.name() + else: + temp = Dname(dev) + return temp.name() + + @classmethod + def asGrubName(self, dev, parenthesis = False): + """return something that grub understands.""" + if dev.__class__.__name__ == "Dname": + return dev.grubName(parenthesis) + else: + temp = Dname(dev) + return temp.grubName(parenthesis) + + def path(self): + return utils.join("/dev/", self.dname) + + def name(self): + return self.dname + + def grubName(self, parenthesis = False): + """Change the kernel device name to something that grub understands + + It returns a string of the form hd[devicd],[partition] + """ + + # First we search for the number that ends the device string. + m = re.search("[0-9]+$", self.dname) + if m == None: + partnum = None + devnum = ord(self.dname[len(self.dname)-1]) - ciconst + else: + # The grub partition number scheme is a little different. Its safe + # to assume that its one less than the usual scheme. + partnum = int(m.group(0)) + temp = self.dname.strip(str(partnum)) + + # Follow grub scheme + partnum = partnum - 1 + + # We now get the letter that is before the number + devnum = ord(temp[len(temp)-1]) - ciconst + + # Must check to see if the values are in range. + if (partnum != None and partnum < 0) or (devnum < 0): + raise Exception("The conversion from kernel device scheme to " \ + "grub scheme failed.") + + # Decide weather to return with or withoug parenthesis. + if parenthesis: + openpar = "(" + closepar = ")" + else: + openpar = "" + closepar = "" + + # Create the gurb device string. + if partnum == None: + return "%shd%s%s"%(openpar, devnum, closepar) + else: + return "%shd%s,%s%s"%(openpar, devnum, partnum, closepar) + diff --git a/plugins/grub/grubconf.py b/plugins/grub/grubconf.py new file mode 100644 index 0000000..13808c0 --- /dev/null +++ b/plugins/grub/grubconf.py @@ -0,0 +1,17 @@ +# First Aid Kit - diagnostic and repair tool for Linux +# Copyright (C) 2008 Joel Andres Granados <jgranado@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. + diff --git a/plugins/grub/minihal.py b/plugins/grub/minihal.py new file mode 100644 index 0000000..2b5504e --- /dev/null +++ b/plugins/grub/minihal.py @@ -0,0 +1,74 @@ +# minihal.py: Simple wrapper around HAL +# +# Copyright (C) 2008 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/>. +# +# Author(s): Bill Nottingham <notting@redhat.com> +# This file is stolen from anaconda code :). In rescue mode there will be +# no replication of code as this file will not go into the rescue mode image. +# + +"""Simple wrapper around HAL""" + +import dbus + +def get_device(udi): + """Retrieve all properties of a particular device (by UDI)""" + try: + bus = dbus.SystemBus() + haldev = dbus.Interface(bus.get_object("org.freedesktop.Hal", udi), \ + "org.freedesktop.Hal.Device") + props = haldev.GetAllProperties() + except dbus.exceptions.DBusException: + return None + + if props.has_key('block.device'): + props['device'] = props['block.device'].encode("utf-8") + elif props.has_key('linux.device_file'): + props['device'] = props['linux.device_file'].encode("utf-8") + elif props.has_key('net.interface'): + props['device'] = props['net.interface'].encode("utf-8") + else: + props['device'] = None + + props['description'] = '' + if props.has_key('info.product'): + if props.has_key('info.vendor'): + props['description'] = '%s %s' % \ + (props['info.vendor'],props['info.product']) + else: + props['description'] = props['info.product'] + else: + props['description'] = props['info.udi'] + if props.has_key('net.originating_device'): + pdev = get_device(props['net.originating_device']) + props['description'] = pdev['description'] + + return props + +def get_devices_by_type(type): + """Retrieve all devices of a particular type""" + ret = [] + try: + bus = dbus.SystemBus() + hal = dbus.Interface(bus.get_object("org.freedesktop.Hal", \ + "/org/freedesktop/Hal/Manager"),"org.freedesktop.Hal.Manager") + except: + return ret + for udi in hal.FindDeviceByCapability(type): + dev = get_device(udi) + if dev: + ret.append(dev) + return ret diff --git a/pyfirstaidkit/utils/__init__.py b/pyfirstaidkit/utils/__init__.py index 94e9279..28eb37e 100644 --- a/pyfirstaidkit/utils/__init__.py +++ b/pyfirstaidkit/utils/__init__.py @@ -16,6 +16,7 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. import os +import os.path import sys import subprocess from backup import * @@ -44,4 +45,14 @@ Returns the subprocess.Popen object""" stderr = subprocess.PIPE) +def join(path1, path2): + """Avoids the os.path.join behavioir. + if a full path is given to os.path.join it ignores the prefious + arguments. The needed behavior is to join two paths with only + one separator. + path1 - being the begining of the path name and + path2 - being the end. + """ + # We strip the paths first and then join them. + return os.path.join(os.sep, path1.strip(os.sep), path2.strip(os.sep)) |
