debuggers.hg

changeset 21854:c4a83e3cc6b4

pygrub: look in every partition for something to boot

pygrub: look in every partition for something to boot, in case
the OS installer (SLES 10 sp1 in particular) forgets to mark the
boot partition as active.

Signed-off-by: Tim Deegan <Tim.Deegan@citrix.com>
Acked-by: David Markey <admin@dmarkey.com>
author Ian Jackson <Ian.Jackson@eu.citrix.com>
date Thu Jul 15 18:18:16 2010 +0100 (2010-07-15)
parents 6fdb00dc93a5
children 1f7c2418e58c 91ce0b0953ca
files tools/pygrub/src/pygrub
line diff
     1.1 --- a/tools/pygrub/src/pygrub	Thu Jul 15 16:32:50 2010 +0100
     1.2 +++ b/tools/pygrub/src/pygrub	Thu Jul 15 18:18:16 2010 +0100
     1.3 @@ -50,21 +50,6 @@ def is_disk_image(file):
     1.4          return True
     1.5      return False
     1.6  
     1.7 -def get_active_partition(file):
     1.8 -    """Find the offset for the start of the first active partition "
     1.9 -    "in the disk image file."""
    1.10 -
    1.11 -    fd = os.open(file, os.O_RDONLY)
    1.12 -    buf = os.read(fd, 512)
    1.13 -    for poff in (446, 462, 478, 494): # partition offsets
    1.14 -        # active partition has 0x80 as the first byte
    1.15 -        if struct.unpack("<c", buf[poff:poff+1]) == ('\x80',):
    1.16 -            return buf[poff:poff+16]
    1.17 -
    1.18 -    # if there's not a partition marked as active, fall back to
    1.19 -    # the first partition
    1.20 -    return buf[446:446+16]
    1.21 -
    1.22  SECTOR_SIZE=512
    1.23  DK_LABEL_LOC=1
    1.24  DKL_MAGIC=0xdabe
    1.25 @@ -101,25 +86,44 @@ FDISK_PART_SOLARIS=0xbf
    1.26  FDISK_PART_SOLARIS_OLD=0x82
    1.27  FDISK_PART_GPT=0xee
    1.28  
    1.29 -def get_fs_offset(file):
    1.30 +def get_partition_offsets(file):
    1.31      if not is_disk_image(file):
    1.32 -        return 0
    1.33 +        # No MBR: assume whole disk filesystem, which is like a 
    1.34 +        # single partition starting at 0
    1.35 +        return [0]
    1.36  
    1.37 -    partbuf = get_active_partition(file)
    1.38 -    if len(partbuf) == 0:
    1.39 -        raise RuntimeError, "Unable to find active partition on disk"
    1.40 +    part_offs = []
    1.41  
    1.42 -    offset = struct.unpack("<L", partbuf[8:12])[0] * SECTOR_SIZE
    1.43 +    fd = os.open(file, os.O_RDONLY)
    1.44 +    buf = os.read(fd, 512)
    1.45 +    for poff in (446, 462, 478, 494): # partition offsets
    1.46  
    1.47 -    type = struct.unpack("<B", partbuf[4:5])[0]
    1.48 -
    1.49 -    if type == FDISK_PART_SOLARIS or type == FDISK_PART_SOLARIS_OLD:
    1.50 -        offset += get_solaris_slice(file, offset)
    1.51 +        # MBR contains a 16 byte descriptor per partition
    1.52 +        partbuf = buf[poff:poff+16]
    1.53 +        offset  = struct.unpack("<L", partbuf[8:12])[0] * SECTOR_SIZE
    1.54 +        type    = struct.unpack("<B", partbuf[4:5])[0]
    1.55 +        
    1.56 +        # offset == 0 implies this partition is not enabled
    1.57 +        if offset == 0:
    1.58 +            continue
    1.59  
    1.60 -    if type == FDISK_PART_GPT:
    1.61 -        offset = get_fs_offset_gpt(file)
    1.62 -    
    1.63 -    return offset
    1.64 +        if type == FDISK_PART_SOLARIS or type == FDISK_PART_SOLARIS_OLD:
    1.65 +            try:
    1.66 +                offset += get_solaris_slice(file, offset)
    1.67 +            except RuntimeError:
    1.68 +                continue # no solaris magic at that offset, ignore partition
    1.69 +
    1.70 +        if type == FDISK_PART_GPT:
    1.71 +            offset = get_fs_offset_gpt(file)
    1.72 +
    1.73 +        # Active partition has 0x80 as the first byte.
    1.74 +        # If active, prepend to front of list, otherwise append to back.
    1.75 +        if struct.unpack("<c", buf[poff:poff+1]) == ('\x80',):
    1.76 +            part_offs.insert(0, offset)
    1.77 +        else:
    1.78 +            part_offs.append(offset)
    1.79 +
    1.80 +    return part_offs
    1.81  
    1.82  class GrubLineEditor(curses.textpad.Textbox):
    1.83      def __init__(self, screen, startx, starty, line = ""):
    1.84 @@ -734,17 +738,40 @@ if __name__ == "__main__":
    1.85      bootfsargs = '"%s"' % incfg["args"]
    1.86      bootfsgroup = re.findall('zfs-bootfs=(.*?)[\s\,\"]', bootfsargs)
    1.87      if bootfsgroup:
    1.88 -        fs = fsimage.open(file, get_fs_offset(file), bootfsgroup[0])
    1.89 +        bootfsoptions = bootfsgroup[0]
    1.90      else:
    1.91 -        fs = fsimage.open(file, get_fs_offset(file))
    1.92 +        bootfsoptions = ""
    1.93 +
    1.94 +    # get list of offsets into file which start partitions
    1.95 +    part_offs = get_partition_offsets(file)
    1.96  
    1.97 -    chosencfg = sniff_solaris(fs, incfg)
    1.98 +    for offset in part_offs:
    1.99 +        try:
   1.100 +            fs = fsimage.open(file, offset, bootfsoptions)
   1.101 +
   1.102 +            chosencfg = sniff_solaris(fs, incfg)
   1.103 +
   1.104 +            if not chosencfg["kernel"]:
   1.105 +                chosencfg = sniff_netware(fs, incfg)
   1.106  
   1.107 -    if not chosencfg["kernel"]:
   1.108 -        chosencfg = sniff_netware(fs, incfg)
   1.109 +            if not chosencfg["kernel"]:
   1.110 +                chosencfg = run_grub(file, entry, fs, incfg["args"])
   1.111 +
   1.112 +            # Break as soon as we've found the kernel so that we continue
   1.113 +            # to use this fsimage object
   1.114 +            if chosencfg["kernel"]:
   1.115 +                break
   1.116 +            fs = None
   1.117  
   1.118 -    if not chosencfg["kernel"]:
   1.119 -        chosencfg = run_grub(file, entry, fs, incfg["args"])
   1.120 +        except:
   1.121 +            # IOErrors raised by fsimage.open
   1.122 +            # RuntimeErrors raised by run_grub if no menu.lst present
   1.123 +            fs = None
   1.124 +            continue
   1.125 +
   1.126 +    # Did looping through partitions find us a kernel?
   1.127 +    if not fs:
   1.128 +        raise RuntimeError, "Unable to find partition containing kernel"
   1.129  
   1.130      if not_really:
   1.131          bootcfg["kernel"] = "<kernel:%s>" % chosencfg["kernel"]