Port-xen archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

NetBSD support in pygrub



Hi,

I patched tools/pygrub and tools/libfsimage to support NetBSD and FFSv2,
see attachment for a git diff against xen.
It doesn't provide a fancy GUI, but it provides minimal support for the
/boot.cfg file to retrieve the kernel and arguments.
I use it with xen-unstable and the xl toolstack, and "it works for me"
with netbsd-current and a ufs2 root filesystem.

There's just one minor nuisance (well, besides the code being rather
hackish) after pygrub finishes: I have to manually send a Control+] to
the VM console to force the boot to continue.
I'm not sure if this is a problem with my xen-unstable installation or
something I broke ...

Any feedback or pointers on how to resolve the console/boot issue would
be welcome.

diff --git a/tools/libfsimage/ufs/fsys_ufs.c b/tools/libfsimage/ufs/fsys_ufs.c
index be51411..41f2984 100644
--- a/tools/libfsimage/ufs/fsys_ufs.c
+++ b/tools/libfsimage/ufs/fsys_ufs.c
@@ -30,30 +30,42 @@
 /* These are the pools of buffers, etc. */
 
 #define SUPERBLOCK ((struct fs *)(FSYS_BUF + 0x2000))
-#define        INODE ((struct icommon *)(FSYS_BUF + 0x1000))
+#define FS_IS_UFS2 (SUPERBLOCK->fs_magic == UFS2_MAGIC)
+#define INODE ((struct icommon *)(FSYS_BUF + 0x1000))
+#define UFS2_INODE ((struct ufs2_dinode *)(FSYS_BUF + 0x1000))
+#define INODE_SIZE ((FS_IS_UFS2) ? sizeof(struct ufs2_dinode) : sizeof(struct 
icommon))
 #define DIRENT (FSYS_BUF + 0x4000)
 #define MAXBSIZE ((FSYS_BUFLEN - 0x4000) / 2)
 #define INDIRBLK1 ((grub_daddr32_t *)(FSYS_BUF + 0x4000)) /* 2+ indir blk */
-#define        INDIRBLK0 ((grub_daddr32_t *)(FSYS_BUF+ 0x4000 + MAXBSIZE))  /* 
1st indirect blk */
+#define INDIRBLK0 ((grub_daddr32_t *)(FSYS_BUF+ 0x4000 + MAXBSIZE))  /* 1st 
indirect blk */
+#define UFS2_INDIRBLK1 ((int64_t *)(FSYS_BUF + 0x4000)) /* 2+ indir blk */
+#define UFS2_INDIRBLK0 ((int64_t *)(FSYS_BUF+ 0x4000 + MAXBSIZE))  /* 1st 
indirect blk */
 
 #define        indirblk0 (*fsig_int1(ffi))
 #define        indirblk1 (*fsig_int2(ffi))
 
 static int openi(fsi_file_t *, grub_ino_t);
 static grub_ino_t dlook(fsi_file_t *, grub_ino_t, char *);
-static grub_daddr32_t sbmap(fsi_file_t *, grub_daddr32_t);
+static int64_t sbmap(fsi_file_t *, int64_t);
 
 /* read superblock and check fs magic */
 static int
 ufs_mount(fsi_file_t *ffi, const char *options)
 {
-       if (/*! IS_PC_SLICE_TYPE_SOLARIS(current_slice) || */
-           !devread(ffi, UFS_SBLOCK, 0, UFS_SBSIZE, (char *)SUPERBLOCK) ||
-           SUPERBLOCK->fs_magic != UFS_MAGIC ||
-           MAXBSIZE < SUPERBLOCK->fs_bsize)
-               return 0;
-
-       return 1;
+       const int sblocksearch[] = {0, UFS_SBLOCK, UFS2_SBLOCK, UFS2_PIGGY};
+       int i;
+       int found=0;
+       for (i = 0; i < (sizeof(sblocksearch)/sizeof(int)); i++)
+       {
+               if (devread(ffi, sblocksearch[i], 0, UFS_SBSIZE, (char 
*)SUPERBLOCK) &&
+                       ( SUPERBLOCK->fs_magic == UFS_MAGIC ||
+                       SUPERBLOCK->fs_magic == UFS2_MAGIC ) &&
+                       MAXBSIZE >= SUPERBLOCK->fs_bsize) {
+                       found=1;
+                       break;
+               }
+       }
+       return found;
 }
 
 
@@ -95,8 +107,13 @@ ufs_dir(fsi_file_t *ffi, char *dirname)
        if  (! openi(ffi, inode))
                return (0);
        filepos = 0;
-       filemax = INODE->ic_sizelo;
-       return (inode && ((INODE->ic_smode & IFMT) == IFREG));
+       if (FS_IS_UFS2) {
+               filemax = UFS2_INODE->di_size;
+               return (inode && ((UFS2_INODE->di_mode & IFMT) == IFREG));
+       } else  {
+               filemax = INODE->ic_sizelo;
+               return (inode && ((INODE->ic_smode & IFMT) == IFREG));
+       }
 }
 
 /*
@@ -105,11 +122,13 @@ ufs_dir(fsi_file_t *ffi, char *dirname)
 static int
 ufs_read(fsi_file_t *ffi, char *buf, int len)
 {
-       int off, size, ret = 0, ok;
-       grub_daddr32_t lblk, dblk;
-
-       while (len) {
-               off = blkoff(SUPERBLOCK, filepos);
+       int64_t off, size, ret = 0, ok;
+       int64_t lblk, dblk;
+       while (len) {
+               if (FS_IS_UFS2)
+                       off = ufs2_blkoff(SUPERBLOCK, filepos);
+               else
+                       off = blkoff(SUPERBLOCK, filepos);
                lblk = lblkno(SUPERBLOCK, filepos);
                size = SUPERBLOCK->fs_bsize;
                size -= off;
@@ -152,12 +171,17 @@ openi(fsi_file_t *ffi, grub_ino_t inode)
 {
        grub_daddr32_t dblk;
        int off;
+       grub_uint32_t size;
 
        /* get block and byte offset into the block */
        dblk = fsbtodb(SUPERBLOCK, itod(SUPERBLOCK, inode));
-       off = itoo(SUPERBLOCK, inode) * sizeof (struct icommon);
+       if (FS_IS_UFS2)
+               size = sizeof(struct ufs2_dinode);
+       else
+               size = sizeof(struct icommon);
+       off = itoo(SUPERBLOCK, inode) * size;
 
-       return (devread(ffi, dblk, off, sizeof (struct icommon), (char 
*)INODE));
+       return (devread(ffi, dblk, off, size, (char *)INODE));
 }
 
 /*
@@ -165,16 +189,21 @@ openi(fsi_file_t *ffi, grub_ino_t inode)
  * Returns 0 when block doesn't exist and <0 when block isn't initialized
  * (i.e belongs to a hole in the file).
  */
-grub_daddr32_t
-sbmap(fsi_file_t *ffi, grub_daddr32_t bn)
+int64_t
+sbmap(fsi_file_t *ffi, int64_t bn)
 {
-       int level, bound, i, index;
-       grub_daddr32_t nb, blkno;
+       int level, bound, i, index;
+       int64_t nb, blkno;
        grub_daddr32_t *db = INODE->ic_db;
+       int64_t *db2 = UFS2_INODE->di_db;
+       char *ib_ptr;
 
        /* blocks 0..UFS_NDADDR are direct blocks */
        if (bn < UFS_NDADDR) {
-               return db[bn];
+               if (FS_IS_UFS2)
+                       return db2[bn];
+               else
+                       return db[bn];
        }
 
        /* determine how many levels of indirection. */
@@ -187,41 +216,59 @@ sbmap(fsi_file_t *ffi, grub_daddr32_t bn)
                bound *= UFS_NINDIR(SUPERBLOCK);
        }
        if (level >= UFS_NIADDR)        /* bn too big */
-               return ((grub_daddr32_t)0);
+               return ((int64_t)0);
 
        /* fetch the first indirect block */
-       nb = INODE->ic_ib[level];
+       if (FS_IS_UFS2)
+               nb = UFS2_INODE->di_ib[level];
+       else
+               nb = INODE->ic_ib[level];
+
        if (nb == 0) {
-               return ((grub_daddr32_t)0);
+               return ((int64_t)0);
        }
        if (indirblk0 != nb) {
+               if (FS_IS_UFS2)
+                       ib_ptr = (char *)UFS2_INDIRBLK0;
+               else
+                       ib_ptr = (char *)INDIRBLK0;
                indirblk0 = 0;
                blkno = fsbtodb(SUPERBLOCK, nb);
                if (!devread(ffi, blkno, 0, SUPERBLOCK->fs_bsize,
-                   (char *)INDIRBLK0))
+                   ib_ptr))
                        return (0);
                indirblk0 = nb;
        }
        bound /= UFS_NINDIR(SUPERBLOCK);
        index = (bn / bound) % UFS_NINDIR(SUPERBLOCK);
-       nb = INDIRBLK0[index];
+       if (FS_IS_UFS2)
+               nb = UFS2_INDIRBLK0[index];
+       else
+               nb = INDIRBLK0[index];
 
        /* fetch through the indirect blocks */
        for (i = 1; i <= level; i++) {
                if (indirblk1 != nb) {
+                       if (FS_IS_UFS2)
+                               ib_ptr = (char *)UFS2_INDIRBLK1;
+                       else
+                               ib_ptr = (char *)INDIRBLK1;
+
                        blkno = fsbtodb(SUPERBLOCK, nb);
                        if (!devread(ffi, blkno, 0, SUPERBLOCK->fs_bsize,
-                           (char *)INDIRBLK1))
+                           ib_ptr))
                                return (0);
                        indirblk1 = nb;
                }
                bound /= UFS_NINDIR(SUPERBLOCK);
                index = (bn / bound) % UFS_NINDIR(SUPERBLOCK);
-               nb = INDIRBLK1[index];
+               if (FS_IS_UFS2)
+                       nb = UFS2_INDIRBLK1[index];
+               else
+                       nb = INDIRBLK1[index];
                if (nb == 0)
-                       return ((grub_daddr32_t)0);
+                       return ((int64_t)0);
        }
-
        return (nb);
 }
 
@@ -232,19 +279,24 @@ dlook(fsi_file_t *ffi, grub_ino_t dir_ino, char *name)
        int loc, off;
        grub_daddr32_t lbn, dbn, dblk;
        struct direct *dp;
+       int64_t size;
 
        if ((INODE->ic_smode & IFMT) != IFDIR)
                return 0;
 
        loc = 0;
-       while (loc < INODE->ic_sizelo) {
+       if (FS_IS_UFS2)
+               size = UFS2_INODE->di_size;
+       else
+               size = INODE->ic_sizelo;
+       while (loc < size) {
                /* offset into block */
                off = blkoff(SUPERBLOCK, loc);
                if (off == 0) {         /* need to read in a new block */
                        /* get logical block number */
                        lbn = lblkno(SUPERBLOCK, loc);
                        /* resolve indrect blocks */
-                       dbn = sbmap(ffi, lbn);
+            dbn = sbmap(ffi, lbn);
                        if (dbn == 0)
                                return (0);
 
diff --git a/tools/libfsimage/ufs/ufs.h b/tools/libfsimage/ufs/ufs.h
index 4e7c736..b250cca 100644
--- a/tools/libfsimage/ufs/ufs.h
+++ b/tools/libfsimage/ufs/ufs.h
@@ -2,17 +2,65 @@
  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by Marshall
+ * Kirk McKusick and Network Associates Laboratories, the Security
+ * Research Division of Network Associates, Inc. under DARPA/SPAWAR
+ * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
+ * research program
+ *
+ * Copyright (c) 1982, 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)dinode.h    8.9 (Berkeley) 3/29/95
+ */
 
 #ifndef _GRUB_UFS_H
 #define _GRUB_UFS_H_
 
 /* ufs specific constants */
 #define UFS_SBLOCK     16
+#define UFS2_SBLOCK (65536 / 512)
+#define UFS2_PIGGY     262144
 #define UFS_SBSIZE     8192
 #define        UFS_MAGIC       0x011954
+#define UFS2_MAGIC  0x19540119
 #define        ROOTINO         2       /* i number of all roots */
 #define UFS_NDADDR     12      /* direct blocks */
 #define        UFS_NIADDR      3       /* indirect blocks */
+#define UFS_NXADDR     2
 #define        MAXMNTLEN       512
 #define        MAXCSBUFS       32
 #define        MAXNAMELEN      256
@@ -173,6 +221,33 @@ struct fs {
        grub_uchar_t    fs_space[1];    /* list of blocks for each rotation */
        /* actually longer */
 };
+/* UFS2 on-disk format */
+struct ufs2_dinode {
+       u_int16_t       di_mode;        /*   0: IFMT, permissions; see below. */
+       int16_t         di_nlink;       /*   2: File link count. */
+       u_int32_t       di_uid;         /*   4: File owner. */
+       u_int32_t       di_gid;         /*   8: File group. */
+       u_int32_t       di_blksize;     /*  12: Inode blocksize. */
+       u_int64_t       di_size;        /*  16: File byte count. */
+       u_int64_t       di_blocks;      /*  24: Bytes actually held. */
+       int64_t         di_atime;       /*  32: Last access time. */
+       int64_t         di_mtime;       /*  40: Last modified time. */
+       int64_t         di_ctime;       /*  48: Last inode change time. */
+       int64_t         di_birthtime;   /*  56: Inode creation time. */
+       int32_t         di_mtimensec;   /*  64: Last modified time. */
+       int32_t         di_atimensec;   /*  68: Last access time. */
+       int32_t         di_ctimensec;   /*  72: Last inode change time. */
+       int32_t         di_birthnsec;   /*  76: Inode creation time. */
+       int32_t         di_gen;         /*  80: Generation number. */
+       u_int32_t       di_kernflags;   /*  84: Kernel flags. */
+       u_int32_t       di_flags;       /*  88: Status flags (chflags). */
+       int32_t         di_extsize;     /*  92: External attributes block. */
+       int64_t         di_extb[UFS_NXADDR];/* 96: External attributes block. */
+       int64_t         di_db[UFS_NDADDR]; /* 112: Direct disk blocks. */
+       int64_t         di_ib[UFS_NIADDR]; /* 208: Indirect disk blocks. */
+       u_int64_t       di_modrev;      /* 232: i_modrev for NFSv4 */
+       int64_t         di_spare[2];    /* 240: Reserved; currently unused */
+};
 
 struct icommon {
        grub_o_mode_t   ic_smode;       /* 0: mode and type of file */
@@ -214,15 +289,18 @@ struct direct {
 /* block conversion macros */
 #define        UFS_NINDIR(fs)  ((fs)->fs_nindir)       /* # of indirects */
 #define blkoff(fs, loc)        ((int)((loc & ~(fs)->fs_bmask)))
+#define ufs2_blkoff(fs, loc)   ((int64_t)(loc & *((int64_t 
*)(&((fs)->fs_qbmask)))))
 #define lblkno(fs, loc) ((grub_int32_t)((loc) >> (fs)->fs_bshift))
 /* frag to blk */
-#define fsbtodb(fs, b) (((grub_daddr32_t)(b)) << (fs)->fs_fsbtodb)
+#define fsbtodb(fs, b) (((b)) << (fs)->fs_fsbtodb)
 #define blkstofrags(fs, b) ((b) << (fs)->fs_fragshift)
 
 /* cynlinder group macros */
 #define cgbase(fs, c)  ((grub_daddr32_t)((fs)->fs_fpg * (c)))
 #define        cgimin(fs, c)   (cgstart(fs, c) + (fs)->fs_iblkno) /* inode 
block */
-#define cgstart(fs, c) \
+#define cgstart(fs, c) ((fs)->fs_magic == UFS2_MAGIC \
+                                                       ? 
cgstart_ufs2((fs),(c)) : cgstart_ufs1((fs),(c)))
+#define cgstart_ufs1(fs, c) \
   (cgbase(fs, c) + (fs)->fs_cgoffset * ((c) & ~((fs)->fs_cgmask)))
-
+#define cgstart_ufs2(fs, c) cgbase((fs), (c))
 #endif /* !_GRUB_UFS_H */
diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub
old mode 100644
new mode 100755
index 363fbc7..2c618be
--- a/tools/pygrub/src/pygrub
+++ b/tools/pygrub/src/pygrub
@@ -80,7 +80,85 @@ def get_solaris_slice(file, offset):
         if slicetag == V_ROOT:
             return slicesect * SECTOR_SIZE
 
-    raise RuntimeError, "No root slice found"      
+    raise RuntimeError, "No root slice found"
+
+
+NETBSD_DISKLABEL_MAGIC=0x82564557
+NETBSD_DISKLABEL_MAXPARTITIONS=22
+NETBSD_FSTYPE_UNUSED, NETBSD_FSTYPE_SWAP, NETBSD_FSTYPE_BSDFFS = 0, 1, 7
+
+from collections import namedtuple
+NBDisklabel = namedtuple("NBDisklabel", '\
+        d_magic \
+        d_type \
+        d_subtype \
+        d_typename \
+        d_un \
+        d_un_pad \
+        d_secsize \
+        d_nsectors \
+        d_ntracks \
+        d_ncylinders \
+        d_secpercyl \
+        d_secperunit \
+        d_sparespertrack \
+        d_sparespercyl \
+        d_acylinders \
+        d_rpm \
+        d_interleave \
+        d_trackskew \
+        d_cylskew \
+        d_headswitch \
+        d_trkseek \
+        d_flags \
+        d_drivedata0 \
+        d_drivedata1 \
+        d_drivedata2 \
+        d_drivedata3 \
+        d_drivedata4 \
+        d_spare0 \
+        d_spare1 \
+        d_spare2 \
+        d_spare3 \
+        d_spare4 \
+        d_magic2 \
+        d_checksum \
+        d_npartitions \
+        d_bbsize \
+        d_sbsize')
+NBPartition = namedtuple("NBPartition", '\
+        p_size \
+        p_offset \
+        p_u2_fsize_cdsession \
+        p_fstype \
+        p_frag \
+        p_u1_cpg_sgs')
+def get_netbsd_partition(file, offset):
+    """find the root partion in a NetBSD disklabel"""
+    #see sys/sys/disklabel.h
+    struct_partition="<IIIBBH"
+    struct_disklabel="<IHH16sQQIIIIIIHHIHHHHIII5I5IIHHII"
+    dkl_size = struct.calcsize(struct_disklabel)
+    part_size = struct.calcsize(struct_partition)
+
+    fd=os.open(file, os.O_RDONLY)
+    os.lseek(fd, offset + SECTOR_SIZE, 0)
+    buf = os.read(fd, SECTOR_SIZE)
+    os.close(fd)
+
+    rawdat = struct.unpack(struct_disklabel, buf[0 : dkl_size])
+    dkl = NBDisklabel._make(rawdat)
+    if dkl.d_magic != NETBSD_DISKLABEL_MAGIC \
+       or dkl.d_magic2 != NETBSD_DISKLABEL_MAGIC:
+        raise RuntimeError, "Invalid NetBSD disklabel magic"
+    for i in range(dkl.d_npartitions):
+        part_off = dkl_size + i * part_size
+        rawdat = struct.unpack(struct_partition, buf[part_off : part_off + 
part_size])
+        part = NBPartition._make(rawdat)
+        if part.p_fstype == NETBSD_FSTYPE_BSDFFS and part.p_size > 0:
+            if part.p_size > dkl.d_secperunit:
+                print "get_netbsd_partition: warning: # of partition sectors  
exceeds disklabel sectors"
+            return part.p_offset * dkl.d_secsize
 
 def get_fs_offset_gpt(file):
     fd = os.open(file, os.O_RDONLY)
@@ -100,13 +178,26 @@ def get_fs_offset_gpt(file):
 FDISK_PART_SOLARIS=0xbf
 FDISK_PART_SOLARIS_OLD=0x82
 FDISK_PART_GPT=0xee
+FDISK_PART_NETBSD=0xa9
 
 def get_partition_offsets(file):
     image_type = identify_disk_image(file)
     if image_type == DISK_TYPE_RAW:
-        # No MBR: assume whole disk filesystem, which is like a 
+        # No MBR: assume whole disk filesystem, which is like a
         # single partition starting at 0
-        return [0]
+        try:
+            # NetBSD 6.1 doesn't bother to add a valid MBR, check if there's a 
disklabel
+            # in the second sector
+            fd=os.open(file, os.O_RDONLY)
+            os.lseek(fd, SECTOR_SIZE, 0)
+            buf = os.read(fd, SECTOR_SIZE)
+            os.close(fd)
+            dkl_magic  = struct.unpack("<L", buf[0:4])[0]
+            if dkl_magic != NETBSD_DISKLABEL_MAGIC:
+                raise
+            return  [ get_netbsd_partition(file, 0)]
+        except:
+            return [0]
     elif image_type == DISK_TYPE_HYBRIDISO:
         # A HybridISO contains an ISO filesystem at 0 in addition
         # to the DOS partition table
@@ -114,7 +205,7 @@ def get_partition_offsets(file):
     elif image_type == DISK_TYPE_DOS:
         part_offs = []
     else:
-        raise ValueError('Unhandled image type returnd by 
identify_disk_image(): %d' % (image_type,))
+        raise ValueError('Unhandled image type returned by 
identify_disk_image(): %d' % (image_type,))
 
     fd = os.open(file, os.O_RDONLY)
     buf = os.read(fd, 512)
@@ -136,6 +227,11 @@ def get_partition_offsets(file):
             except RuntimeError:
                 continue # no solaris magic at that offset, ignore partition
 
+        if type == FDISK_PART_NETBSD:
+            try:
+                offset =  get_netbsd_partition(file, offset)
+            except RuntimeError:
+                continue # ignore partition
         if type == FDISK_PART_GPT:
             for offset in get_fs_offset_gpt(file):
                 part_offs.append(offset)
@@ -690,6 +786,82 @@ def sniff_netware(fs, cfg):
         cfg["kernel"] = "/nwserver/xnloader.sys"
 
     return cfg
+def netbsd_parse_bootcfg(cfgbuf, cfg):
+    """ parse NetBSD's boot.cfg and return a dictionary with appropriate keys: 
kernel, ramdisk and args """
+    lines =  cfgbuf.split("\n")
+    kernel=""
+    args=""
+    ramdisk=""
+    menus=[]
+    default=None
+
+    for l in lines:
+        l = l.strip()
+        if len(l) > 0:
+            #ignore comments
+            if l.startswith('#'):
+                continue
+            entry = l.split("=", 1)
+            #new menu entry
+            if entry[0] == "menu":
+                text_cmds = entry[1].split(":")
+                cmds = text_cmds[1]
+                menus.append(cmds)
+            #default menu entry
+            if entry[0] == "default":
+                default = int(entry[1].strip())
+            #always load given kernel module
+            if entry[0] == "load":
+                ramdisk = entry[1].strip()
+    if default is None:
+        return False
+
+    cmds = menus[default - 1]
+    #parse the default boot command sequence
+    for c in cmds.split(";"):
+        #e.g.: boot -as, or netbsd -12s
+        if c.startswith("boot"):
+            boot_args = c.replace("boot", '', 1).strip()
+            for arg in boot_args.split(" "):
+                if arg.startswith("-"):
+                    args += arg + " "
+                else:
+                    kernel = arg
+        if c.startswith("load"):
+            ramdisk = c.replace("load", '', 1).strip()
+    if kernel != "":
+        cfg["kernel"] = kernel
+    if ramdisk != "":
+        cfg["ramdisk"] = ramdisk
+    if args != "":
+        #XXX we need to keep root=xbd0a
+        cfg["args"] += " " + args
+    return True
+
+def sniff_netbsd(fs, cfg):
+    default_kernel="/netbsd"
+    default_args="root=xbd0 " #XXX should we get this from the MBR/disklabel ?
+    if not fs.file_exists("/boot.cfg"):
+        if not fs.file_exists("/netbsd"):
+            return cfg
+        cfg["kernel"] = default_kernel
+        cfg["args"] = default_args
+        return cfg
+    else:
+        cfg["kernel"] = default_kernel
+        cfg["args"] = default_args
+        bootf = fs.open_file("/boot.cfg")
+        offset = 0
+        boot_cfg = ""
+        while True:
+            buf  = bootf.read(FS_READ_MAX, offset)
+            if len(buf) == 0:
+                del bootf
+                break
+            offset += len(buf)
+            boot_cfg += buf
+        cfg_ok =  netbsd_parse_bootcfg(boot_cfg, cfg)
+        return cfg
 
 def format_sxp(kernel, ramdisk, args):
     s = "linux (kernel %s)" % kernel
@@ -858,6 +1030,9 @@ if __name__ == "__main__":
             chosencfg = sniff_solaris(fs, incfg)
 
             if not chosencfg["kernel"]:
+                chosencfg = sniff_netbsd(fs, incfg)
+
+            if not chosencfg["kernel"]:
                 chosencfg = sniff_netware(fs, incfg)
 
             if not chosencfg["kernel"]:


Home | Main Index | Thread Index | Old Index