--- pygrub.xcp-orig 2012-02-09 10:39:29.000000000 -0600 +++ pygrub.xcp-ufs-debug 2012-02-09 10:41:44.000000000 -0600 @@ -12,8 +12,13 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # +# 2012-02-08 - John D. "Trix" Farrar - 0.6.1-bbkt +# Using XCF version of pygrub, incorporated patches from: +# http://people.freebsd.org/~adrian/xen/bsd_pygrub/ +# which seem to be based on an older version of "0.6" +# Also included a patch to add a --debug switch for easier troubleshooting. -import os, sys, atexit, string, struct, tempfile, re +import os, sys, atexit, string, struct, tempfile, re, traceback import copy import logging import platform @@ -26,7 +31,7 @@ import grub.LiloConf import grub.ExtLinuxConf -PYGRUB_VER = 0.6 +PYGRUB_VER = "0.6.1bbkt" def enable_cursor(ison): if ison: @@ -74,6 +79,105 @@ raise RuntimeError, "No root slice found" +# +# Find the root slice in a FreeBSD disklabel. +# + +# Some magic constants for the BSD disklabel +BSD_LABEL_DISKMAGIC=0x82564557 +BSD_LABEL_LABELSECTOR=1 +BSD_LABEL_LABELOFFSET=0 +BSD_LABEL_MAXPARTITIONS=8 +BSD_LABEL_BBSIZE=8192 +BSD_LABEL_LABEL_PART=2 +BSD_LABEL_RAW_PART=2 + +# Magic offsets in the label +BSD_LABEL_OFFSET_MAGIC=0 # u_int32_t +BSD_LABEL_OFFSET_SECTORSIZE=40 # u_int32_t - number of bytes per sector +BSD_LABEL_OFFSET_PARTITIONTABLE=148 # structure * MAXPARTITIONS +BSD_LABEL_OFFSET_NPARTITIONS=138 # u_int16_t + +# Magic offsets in the -partition- section +BSD_LABEL_PARTITION_SIZE=0 # u_int32_t - size in sectors +BSD_LABEL_PARTITION_OFFSET=4 # u_int32_t - offset in sectors +BSD_LABEL_PARTITION_FSTYPE=12 # u_int8_t - partition type + +# How big is the partition structure? +BSD_LABEL_PARTITION_STRUCT_SIZE=16 + +# BSD label partition types that we care about +BSD_FS_BSDFFS=7 + +# Get the partition size from the given freebsd disklabel +# partbuf contains the beginning of the disklabel +def get_freebsd_partition_size(partbuf, partid): + i = BSD_LABEL_OFFSET_PARTITIONTABLE + (partid * BSD_LABEL_PARTITION_STRUCT_SIZE) + return struct.unpack(">sys.stderr, "get_freebsd_slice: file : %s" % file + print >>sys.stderr, "get_freebsd_slice: offset: %s" % offset + + fd = os.open(file, os.O_RDONLY) + os.lseek(fd, offset + (SECTOR_SIZE * BSD_LABEL_LABELSECTOR) + BSD_LABEL_LABELOFFSET, 0) + buf = os.read(fd, 1024) + + # Check the magic - is it a valid disklabel? if not, barf + bsd_d_magic = struct.unpack(">sys.stderr, "bsd magic: %s" % bsd_d_magic + print >>sys.stderr, "needed magic: %s" % BSD_LABEL_DISKMAGIC + if bsd_d_magic <> BSD_LABEL_DISKMAGIC: + raise RuntimeError, "FreeBSD label diskmagic incorrect" + + # Get sectorsize - does it make sense? If not, barf + bsd_d_secsize = struct.unpack(">sys.stderr, "bsd sector size: %s" % bsd_d_secsize + + # Get the first partition - is it the right type? If not, barf + bsd_d_npartitions = struct.unpack(">sys.stderr, "bsd number of partitions: %s" % bsd_d_npartitions + + # Grab the filesystem offset in sectors + bsd_d_part_offset = get_freebsd_partition_offset(buf, 0) + bsd_d_part_size = get_freebsd_partition_size(buf, 0) + bsd_d_part_fstype = get_freebsd_partition_fstype(buf, 0) + print >>sys.stderr, "bsd partition 0 offset: %s" % bsd_d_part_offset + print >>sys.stderr, "bsd partition 0 size : %s" % bsd_d_part_size + print >>sys.stderr, "bsd partition 0 type : %s" % bsd_d_part_fstype + + if bsd_d_part_fstype <> BSD_FS_BSDFFS: + raise RuntimeError, "First BSD partition is not type BSDFFS (7)" + + # XXX one should now verify that the given partition size and offset fall within the disk size.. + + # Calculate the filesystem offset, return that + return (bsd_d_part_offset * bsd_d_secsize) + + def get_fs_offset_gpt(file): fd = os.open(file, os.O_RDONLY) # assume the first partition is an EFI system partition. @@ -81,9 +185,11 @@ buf = os.read(fd, 512) return struct.unpack(">sys.stderr, "BAIL! I don't know what to do!" + sys.exit(1) + if type == FDISK_PART_GPT: offset = get_fs_offset_gpt(file) @@ -620,7 +733,7 @@ ["quiet", "interactive", "not-really", "help", "output=", "entry=", "kernel=", "ramdisk=", "args=", "default_args=", - "extra_args=", "vm="]) + "extra_args=", "vm=", "debug"]) except getopt.GetoptError: usage() sys.exit(1) @@ -633,6 +746,7 @@ output = None entry = None interactive = True + debug = False not_really = False default_args = "" extra_args = "" @@ -654,6 +768,8 @@ sys.exit() elif o in ("-n", "--not-really"): not_really = True + elif o in ("--debug"): + debug = True elif o in ("--output",): output = a elif o in ("--kernel",): @@ -671,6 +787,9 @@ elif o in ("--extra_args",): extra_args = a + if debug: + logging.basicConfig(level=logging.DEBUG) + if output is None or output == "-": fd = sys.stdout.fileno() else: @@ -700,6 +819,11 @@ except: # IOErrors raised by fsimage.open # RuntimeErrors raised by run_grub if no menu.lst present + if debug: + traceback.print_exc() + print >>sys.stderr, "Filename: %s" % file + print >>sys.stderr, "Offset : %s" % offset + print >>sys.stderr, "Options : %s" % bootfsoptions fs = None continue else: @@ -738,6 +862,8 @@ except: # IOErrors raised by fsimage.open # RuntimeErrors raised by run_grub if no menu.lst present + if debug: + traceback.print_exc() fs = None continue