BLS support for plan9.ini parsing and local file systems - vx32 - Local 9vx git repository for patches.
       
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
 (DIR) commit 537b928eef0c6c96a53832be60f06fae0206680c
 (DIR) parent b1304f7ab2facdaec4d97b480535c1633d03247c
 (HTM) Author: Jesus Galan Lopez (yiyus) <yiyu.jgl@gmail.com>
       Date:   Tue, 25 May 2010 08:06:52 +0200
       
       BLS support for plan9.ini parsing and local file systems
       
       Diffstat:
         src/9vx/Makefrag                    |      20 +++++++++++++++++++-
         src/9vx/a/devsd.c                   |      16 +++++++++++++++-
         src/9vx/a/dosfs.h                   |      62 +++++++++++++++++++++++++++++++
         src/9vx/a/fns.ed                    |       3 +++
         src/9vx/a/fns.h                     |       3 +++
         src/9vx/a/fs.h                      |      38 +++++++++++++++++++++++++++++++
         src/9vx/a/kfs.h                     |      57 +++++++++++++++++++++++++++++++
         src/9vx/a/part.c                    |     341 +++++++++++++++++++++++++++++++
         src/9vx/a/sd.h                      |       5 +++++
         src/9vx/bootcode.9                  |       0 
         src/9vx/conf.c                      |     352 +++++++++++++++++++++++++++++++
         src/9vx/fossil.9                    |       0 
         src/9vx/ipconfig.9                  |       0 
         src/9vx/main.c                      |      18 +++++++++++++++++-
         src/9vx/sdloop.c                    |      53 +++++++++++++++++++++++++++++--
         src/9vx/venti.9                     |       0 
       
       16 files changed, 962 insertions(+), 6 deletions(-)
       ---
 (DIR) diff --git a/src/9vx/Makefrag b/src/9vx/Makefrag
       @@ -26,6 +26,7 @@ all: 9vx/9vx
        PLAN9_OBJS = \
                $(addprefix 9vx/, \
                        bootcode.o \
       +                conf.o \
                        devaudio.o \
                        devaudio-$(PLAN9AUDIO).o \
                        devfs-posix.o \
       @@ -36,6 +37,8 @@ PLAN9_OBJS = \
                        devram.o \
                        devtab.o \
                        factotum.o \
       +                fossil.o \
       +                ipconfig.o \
                        kprocdev.o \
                        label.o \
                        main.o \
       @@ -47,6 +50,7 @@ PLAN9_OBJS = \
                        time.o \
                        trap.o \
                        tty.o \
       +                venti.o \
                        vx32.o \
                )
        
       @@ -91,6 +95,7 @@ PLAN9_A_OBJS = \
                        page.o \
                        parse.o \
                        parseip.o \
       +                part.o \
                        pgrp.o \
                        print.o \
                        proc.o \
       @@ -176,6 +181,15 @@ PLAN9_DEPS = \
        9vx/factotum.S: 9vx/data2s 9vx/factotum.9
                ./9vx/data2s factotum < 9vx/factotum.9 >$@_ && mv $@_ $@
        
       +9vx/fossil.S: 9vx/data2s 9vx/fossil.9
       +        ./9vx/data2s fossil < 9vx/fossil.9 >$@_ && mv $@_ $@
       +
       +9vx/ipconfig.S: 9vx/data2s 9vx/ipconfig.9
       +        ./9vx/data2s ipconfig < 9vx/ipconfig.9 > $@_ && mv $@_ $@
       +
       +9vx/venti.S: 9vx/data2s 9vx/venti.9
       +        ./9vx/data2s venti < 9vx/venti.9 > $@_ && mv $@_ $@
       +
        9vx/a/errstr.h: 9vx/a/error.h
                sed 's/extern //; s!;.*/\* ! = "!; s! \*\/!";!' 9vx/a/error.h >9vx/a/errstr.h
        
       @@ -199,7 +213,11 @@ CLEAN_FILES += \
                9vx/a/errstr.h \
                9vx/9vx \
                9vx/data2s \
       -        9vx/bootcode.S
       +        9vx/bootcode.S \
       +        9vx/factotum.S \
       +        9vx/fossil.S \
       +        9vx/ipconfig.S \
       +        9vx/venti.S
        
        include 9vx/libdraw/Makefrag
        include 9vx/libmemlayer/Makefrag
 (DIR) diff --git a/src/9vx/a/devsd.c b/src/9vx/a/devsd.c
       @@ -72,7 +72,7 @@ enum {
                                                 ((p)<<PartSHIFT)|((t)<<TypeSHIFT))
        
        
       -static void
       +void
        sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
        {
                SDpart *pp;
       @@ -135,6 +135,19 @@ sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
                pp->valid = 1;
        }
        
       +SDpart*
       +sdfindpart(SDunit *unit, char *name)
       +{
       +        int i;
       +
       +        for(i=0; i<unit->npart; i++) {
       +                if(strcmp(unit->part[i].perm.name, name) == 0){
       +                        return &unit->part[i];
       +                }
       +        }
       +        return nil;
       +}
       +
        static void
        sddelpart(SDunit* unit, char* name)
        {
       @@ -198,6 +211,7 @@ sdinitpart(SDunit* unit)
                if(unit->sectors){
                        sdincvers(unit);
                        sdaddpart(unit, "data", 0, unit->sectors);
       +                partition(unit);
        #if 0
                        /*
                         * Use partitions passed from boot program,
 (DIR) diff --git a/src/9vx/a/dosfs.h b/src/9vx/a/dosfs.h
       @@ -0,0 +1,62 @@
       +ttypedef struct Dosboot        Dosboot;
       +ttypedef struct Dos        Dos;
       +ttypedef struct Dosdir        Dosdir;
       +ttypedef struct Dosfile        Dosfile;
       +ttypedef struct Dospart        Dospart;
       +
       +struct Dospart
       +{
       +        uchar flag;                /* active flag */
       +        uchar shead;                /* starting head */
       +        uchar scs[2];                /* starting cylinder/sector */
       +        uchar type;                /* partition type */
       +        uchar ehead;                /* ending head */
       +        uchar ecs[2];                /* ending cylinder/sector */
       +        uchar start[4];                /* starting sector */
       +        uchar len[4];                /* length in sectors */
       +};
       +
       +#define FAT12        0x01
       +#define FAT16        0x04
       +#define EXTEND        0x05
       +#define FATHUGE        0x06
       +#define FAT32        0x0b
       +#define FAT32X        0x0c
       +#define EXTHUGE        0x0f
       +#define DMDDO        0x54
       +#define PLAN9        0x39
       +#define LEXTEND 0x85
       +
       +struct Dosfile{
       +        Dos        *dos;                /* owning dos file system */
       +        char        name[8];
       +        char        ext[3];
       +        uchar        attr;
       +        long        length;
       +        long        pstart;                /* physical start cluster address */
       +        long        pcurrent;        /* physical current cluster address */
       +        long        lcurrent;        /* logical current cluster address */
       +        long        offset;
       +};
       +
       +struct Dos{
       +        long        start;                /* start of file system */
       +        int        sectsize;        /* in bytes */
       +        int        clustsize;        /* in sectors */
       +        int        clustbytes;        /* in bytes */
       +        int        nresrv;                /* sectors */
       +        int        nfats;                /* usually 2 */
       +        int        rootsize;        /* number of entries */
       +        int        volsize;        /* in sectors */
       +        int        mediadesc;
       +        int        fatsize;        /* in sectors */
       +        int        fatclusters;
       +        int        fatbits;        /* 12 or 16 */
       +        long        fataddr;        /* sector number */
       +        long        rootaddr;
       +        long        rootclust;
       +        long        dataaddr;
       +        long        freeptr;
       +};
       +
       +extern int        dosinit(Fs*);
 (DIR) diff --git a/src/9vx/a/fns.ed b/src/9vx/a/fns.ed
       @@ -16,4 +16,7 @@ int        tailkmesg(char*, int);
        void        trap(Ureg*);
        void        uartecho(char*, int);
        void        uartinit(int);
       +
       +#define GSHORT(p)        (((p)[1]<<8)|(p)[0])
       +#define GLONG(p)        ((GSHORT(p+2)<<16)|GSHORT(p))
        .
 (DIR) diff --git a/src/9vx/a/fns.h b/src/9vx/a/fns.h
       @@ -167,6 +167,9 @@ void        *uvalidaddr(ulong addr, ulong len, int write);
        int        isuaddr(void*);
        void        setsigsegv(int invx32);
        
       +#define GSHORT(p)        (((p)[1]<<8)|(p)[0])
       +#define GLONG(p)        ((GSHORT(p+2)<<16)|GSHORT(p))
       +
        void        plock(Psleep*);
        void        punlock(Psleep*);
        void        pwakeup(Psleep*);
 (DIR) diff --git a/src/9vx/a/fs.h b/src/9vx/a/fs.h
       @@ -0,0 +1,38 @@
       +ttypedef struct File File;
       +ttypedef struct Fs Fs;
       +
       +#include "dosfs.h"
       +#include "kfs.h"
       +
       +struct File{
       +        union{
       +                Dosfile        dos;
       +                Kfsfile        kfs;
       +                int walked;
       +        };
       +        Fs        *fs;
       +        char        *path;
       +};
       +
       +struct Fs{
       +        union {
       +                Dos dos;
       +                Kfs kfs;
       +        };
       +        int        dev;                                /* device id */
       +        long        (*diskread)(Fs*, void*, long);        /* disk read routine */
       +        vlong        (*diskseek)(Fs*, vlong);        /* disk seek routine */
       +        long        (*read)(File*, void*, long);
       +        int        (*walk)(File*, char*);
       +        File        root;
       +};
       +
       +/*
       +extern int chatty;
       +extern int dotini(Fs*);
       +extern int fswalk(Fs*, char*, File*);
       +extern int fsread(File*, void*, long);
       +extern int fsboot(Fs*, char*, Boot*);
       +*/
       +
       +#define BADPTR(x) ((ulong)x < 0x80000000)
 (DIR) diff --git a/src/9vx/a/kfs.h b/src/9vx/a/kfs.h
       @@ -0,0 +1,57 @@
       +ttypedef struct Qid9p1 Qid9p1;
       +ttypedef struct Dentry Dentry;
       +ttypedef struct Kfsfile Kfsfile;
       +ttypedef struct Kfs Kfs;
       +
       +/* DONT TOUCH, this is the disk structure */
       +struct        Qid9p1
       +{
       +        long        path;
       +        long        version;
       +};
       +
       +#define        NAMELEN                28                /* size of names */
       +#define        NDBLOCK                6                /* number of direct blocks in Dentry */
       +
       +/* DONT TOUCH, this is the disk structure */
       +struct        Dentry
       +{
       +        char        name[NAMELEN];
       +        short        uid;
       +        short        gid;
       +        ushort        mode;
       +/*
       +                #define        DALLOC        0x8000
       +                #define        DDIR        0x4000
       +                #define        DAPND        0x2000
       +                #define        DLOCK        0x1000
       +                #define        DREAD        0x4
       +                #define        DWRITE        0x2
       +                #define        DEXEC        0x1
       +*/
       +        Qid9p1        qid;
       +        long        size;
       +        long        dblock[NDBLOCK];
       +        long        iblock;
       +        long        diblock;
       +        long        atime;
       +        long        mtime;
       +};
       +
       +struct Kfsfile
       +{
       +        Dentry;
       +        long off;
       +};
       +
       +struct Kfs
       +{
       +        int        RBUFSIZE;
       +        int        BUFSIZE;
       +        int        DIRPERBUF;
       +        int        INDPERBUF;
       +        int        INDPERBUF2;
       +};
       +
       +extern int kfsinit(Fs*);
       +
 (DIR) diff --git a/src/9vx/a/part.c b/src/9vx/a/part.c
       @@ -0,0 +1,341 @@
       +#include        "u.h"
       +#include        "lib.h"
       +#include        "mem.h"
       +#include        "dat.h"
       +#include        "fns.h"
       +
       +#include        "sd.h"
       +#include        "fs.h"
       +
       +enum {
       +        Npart = 32
       +};
       +
       +uchar *mbrbuf, *partbuf;
       +int nbuf;
       +#define trace 0
       +
       +int
       +ttsdbio(SDunit *unit, SDpart *part, void *a, vlong off, int mbr)
       +{
       +        uchar *b;
       +
       +        if(unit->dev->ifc->bio(unit, 0, 0, a, 1, (off/unit->secsize) + part->start) != unit->secsize){
       +                if(trace)
       +                        print("%s: read %lud at %lld failed\n", unit->dev->name,
       +                                unit->secsize, (vlong)part->start*unit->secsize+off);
       +                return -1;
       +        }
       +        b = a;
       +        if(mbr && (b[0x1FE] != 0x55 || b[0x1FF] != 0xAA)){
       +                if(trace)
       +                        print("%s: bad magic %.2ux %.2ux at %lld\n",
       +                                unit->dev->name, b[0x1FE], b[0x1FF],
       +                                (vlong)part->start*unit->secsize+off);
       +                return -1;
       +        }
       +        return 0;
       +}
       +
       +/*
       + *  read partition table.  The partition table is just ascii strings.
       + */
       +#define MAGIC "plan9 partitions"
       +static void
       +oldp9part(SDunit *unit)
       +{
       +        SDpart *pp;
       +        char *field[3], *line[Npart+1];
       +        ulong n, start, end;
       +        int i;
       +
       +        /*
       +         *  We have some partitions already.
       +         */
       +        pp = &unit->part[unit->npart];
       +
       +        /*
       +         * We prefer partition tables on the second to last sector,
       +         * but some old disks use the last sector instead.
       +         */
       +        pp->start = unit->sectors - 2;
       +        pp->end = unit->sectors - 1;
       +
       +        if(tsdbio(unit, pp, partbuf, 0, 0) < 0)
       +                return;
       +
       +        if(strncmp((char*)partbuf, MAGIC, sizeof(MAGIC)-1) != 0) {
       +                /* not found on 2nd last sector; look on last sector */
       +                pp->start++;
       +                pp->end++;
       +                if(tsdbio(unit, pp, partbuf, 0, 0) < 0)
       +                        return;
       +                if(strncmp((char*)partbuf, MAGIC, sizeof(MAGIC)-1) != 0)
       +                        return;
       +                print("%s: using old plan9 partition table on last sector\n", unit->dev->name);
       +        }else
       +                print("%s: using old plan9 partition table on 2nd-to-last sector\n", unit->dev->name);
       +
       +        /* we found a partition table, so add a partition partition */
       +        unit->npart++;
       +        partbuf[unit->secsize-1] = '\0';
       +
       +        /*
       +         * parse partition table
       +         */
       +        n = getfields((char*)partbuf, line, Npart+1, 0, "\n");
       +        if(n && strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0){
       +                for(i = 1; i < n && unit->npart < SDnpart; i++){
       +                        if(getfields(line[i], field, 3, 0, " ") != 3)
       +                                break;
       +                        start = strtoull(field[1], 0, 0);
       +                        end = strtoull(field[2], 0, 0);
       +                        if(start >= end || end > unit->sectors)
       +                                break;
       +                        sdaddpart(unit, field[0], start, end);
       +                }
       +        }        
       +}
       +
       +static void
       +p9part(SDunit *unit, char *name)
       +{
       +        SDpart *p;
       +        char *field[4], *line[Npart+1];
       +        uvlong start, end;
       +        int i, n;
       +        
       +        p = sdfindpart(unit, name);
       +        if(p == nil)
       +                return;
       +
       +        if(tsdbio(unit, p, partbuf, unit->secsize, 0) < 0)
       +                return;
       +        partbuf[unit->secsize-1] = '\0';
       +
       +        if(strncmp((char*)partbuf, "part ", 5) != 0)
       +                return;
       +
       +        n = getfields((char*)partbuf, line, Npart+1, 0, "\n");
       +        if(n == 0)
       +                return;
       +        for(i = 0; i < n /* && unit->npart < SDnpart */; i++){
       +                if(strncmp(line[i], "part ", 5) != 0)
       +                        break;
       +                if(getfields(line[i], field, 4, 0, " ") != 4)
       +                        break;
       +                start = strtoull(field[2], 0, 0);
       +                end = strtoull(field[3], 0, 0);
       +                if(start >= end || end > unit->sectors)
       +                        break;
       +                sdaddpart(unit, field[1], p->start+start, p->start+end);
       +        }
       +}
       +
       +int
       +isdos(int t)
       +{
       +        return t==FAT12 || t==FAT16 || t==FATHUGE || t==FAT32 || t==FAT32X;
       +}
       +
       +int
       +isextend(int t)
       +{
       +        return t==EXTEND || t==EXTHUGE || t==LEXTEND;
       +}
       +
       +/* 
       + * Fetch the first dos and all plan9 partitions out of the MBR partition table.
       + * We return -1 if we did not find a plan9 partition.
       + */
       +static int
       +mbrpart(SDunit *unit)
       +{
       +        Dospart *dp;
       +        ulong taboffset, start, end;
       +        ulong firstxpart, nxtxpart;
       +        int havedos, i, nplan9;
       +        char name[10];
       +
       +        taboffset = 0;
       +        dp = (Dospart*)&mbrbuf[0x1BE];
       +        if(1) {
       +                /* get the MBR (allowing for DMDDO) */
       +                if(tsdbio(unit, &unit->part[0], mbrbuf, (vlong)taboffset*unit->secsize, 1) < 0)
       +                        return -1;
       +                for(i=0; i<4; i++)
       +                        if(dp[i].type == DMDDO) {
       +                                if(trace)
       +                                        print("DMDDO partition found\n");
       +                                taboffset = 63;
       +                                if(tsdbio(unit, &unit->part[0], mbrbuf, (vlong)taboffset*unit->secsize, 1) < 0)
       +                                        return -1;
       +                                i = -1;        /* start over */
       +                        }
       +        }
       +
       +        /*
       +         * Read the partitions, first from the MBR and then
       +         * from successive extended partition tables.
       +         */
       +        nplan9 = 0;
       +        havedos = 0;
       +        firstxpart = 0;
       +        for(;;) {
       +                if(tsdbio(unit, &unit->part[0], mbrbuf, (vlong)taboffset*unit->secsize, 1) < 0)
       +                        return -1;
       +                if(trace) {
       +                        if(firstxpart)
       +                                print("%s ext %lud ", unit->dev->name, taboffset);
       +                        else
       +                                print("%s mbr ", unit->dev->name);
       +                }
       +                nxtxpart = 0;
       +                for(i=0; i<4; i++) {
       +                        if(trace)
       +                                print("dp %d...", dp[i].type);
       +                        start = taboffset+GLONG(dp[i].start);
       +                        end = start+GLONG(dp[i].len);
       +
       +                        if(dp[i].type == PLAN9) {
       +                                if(nplan9 == 0)
       +                                        strcpy(name, "plan9");
       +                                else
       +                                        sprint(name, "plan9.%d", nplan9);
       +                                sdaddpart(unit, name, start, end);
       +                                p9part(unit, name);
       +                                nplan9++;
       +                        }
       +
       +                        /*
       +                         * We used to take the active partition (and then the first
       +                         * when none are active).  We have to take the first here,
       +                         * so that the partition we call ``dos'' agrees with the
       +                         * partition disk/fdisk calls ``dos''. 
       +                         */
       +                        if(havedos==0 && isdos(dp[i].type)){
       +                                havedos = 1;
       +                                sdaddpart(unit, "dos", start, end);
       +                        }
       +
       +                        /* nxtxpart is relative to firstxpart (or 0), not taboffset */
       +                        if(isextend(dp[i].type)){
       +                                nxtxpart = start-taboffset+firstxpart;
       +                                if(trace)
       +                                        print("link %lud...", nxtxpart);
       +                        }
       +                }
       +                if(trace)
       +                        print("\n");
       +
       +                if(!nxtxpart)
       +                        break;
       +                if(!firstxpart)
       +                        firstxpart = nxtxpart;
       +                taboffset = nxtxpart;
       +        }        
       +        return nplan9 ? 0 : -1;
       +}
       +
       +/*
       + * To facilitate booting from CDs, we create a partition for
       + * the boot floppy image embedded in a bootable CD.
       + */
       +static int
       +part9660(SDunit *unit)
       +{
       +        uchar buf[2048];
       +        ulong a, n;
       +        uchar *p;
       +
       +        if(unit->secsize != 2048)
       +                return -1;
       +
       +        if(unit->dev->ifc->bio(unit, 0, 0, buf, 2048/unit->secsize, (17*2048)/unit->secsize) < 0)
       +                return -1;
       +
       +        if(buf[0] || strcmp((char*)buf+1, "CD001\x01EL TORITO SPECIFICATION") != 0)
       +                return -1;
       +
       +        
       +        p = buf+0x47;
       +        a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
       +
       +        if(unit->dev->ifc->bio(unit, 0, 0, buf, 2048/unit->secsize, (a*2048)/unit->secsize) < 0)
       +                return -1;
       +
       +        if(memcmp(buf, "\x01\x00\x00\x00", 4) != 0
       +        || memcmp(buf+30, "\x55\xAA", 2) != 0
       +        || buf[0x20] != 0x88)
       +                return -1;
       +
       +        p = buf+0x28;
       +        a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
       +
       +        switch(buf[0x21]){
       +        case 0x01:
       +                n = 1200*1024;
       +                break;
       +        case 0x02:
       +                n = 1440*1024;
       +                break;
       +        case 0x03:
       +                n = 2880*1024;
       +                break;
       +        default:
       +                return -1;
       +        }
       +        n /= 2048;
       +
       +        print("found partition %s!cdboot; %lud+%lud\n", unit->dev->name, a, n);
       +        sdaddpart(unit, "cdboot", a, a+n);
       +        return 0;
       +}
       +
       +enum {
       +        NEW = 1<<0,
       +        OLD = 1<<1
       +};
       +
       +void
       +partition(SDunit *unit)
       +{
       +        int type;
       +        char *p;
       +
       +        if(unit->part == 0)
       +                return;
       +
       +        if(part9660(unit) == 0)
       +                return;
       +
       +        p = "new";
       +
       +        if(p != nil && strncmp(p, "new", 3) == 0)
       +                type = NEW;
       +        else if(p != nil && strncmp(p, "old", 3) == 0)
       +                type = OLD;
       +        else
       +                type = NEW|OLD;
       +
       +        if(nbuf < unit->secsize) {
       +                free(mbrbuf);
       +                free(partbuf);
       +                mbrbuf = malloc(unit->secsize);
       +                partbuf = malloc(unit->secsize);
       +                if(mbrbuf==nil || partbuf==nil) {
       +                        free(mbrbuf);
       +                        free(partbuf);
       +                        partbuf = mbrbuf = nil;
       +                        nbuf = 0;
       +                        return;
       +                }
       +                nbuf = unit->secsize;
       +        }
       +
       +        if((type & NEW) && mbrpart(unit) >= 0){
       +                /* nothing to do */;
       +        }
       +        else if(type & OLD)
       +                oldp9part(unit);
       +}
 (DIR) diff --git a/src/9vx/a/sd.h b/src/9vx/a/sd.h
       @@ -129,9 +129,14 @@ extern void sdadddevs(SDev*);
        extern int sdsetsense(SDreq*, int, int, int, int);
        extern int sdmodesense(SDreq*, uchar*, void*, int);
        extern int sdfakescsi(SDreq*, void*, int);
       +extern void sdaddpart(SDunit*, char*, uvlong, uvlong);
       +extern SDpart* sdfindpart(SDunit*, char*);
        
        /* sdscsi.c */
        extern int scsiverify(SDunit*);
        extern int scsionline(SDunit*);
        extern long scsibio(SDunit*, int, int, void*, long, uvlong);
        extern SDev* scsiid(SDev*, SDifc*);
       +
       +/* part.c */
       +extern void partition(SDunit*);
 (DIR) diff --git a/src/9vx/bootcode.9 b/src/9vx/bootcode.9
       Binary files differ.
 (DIR) diff --git a/src/9vx/conf.c b/src/9vx/conf.c
       @@ -0,0 +1,352 @@
       +#include "u.h"
       +#include "lib.h"
       +#include "mem.h"
       +#include "dat.h"
       +#include "fns.h"
       +#include "io.h"
       +
       +#include "fs.h"
       +
       +/*
       + * Where configuration info is left for the loaded programme.
       + * This will turn into a structure as more is done by the boot loader
       + * (e.g. why parse the .ini file twice?).
       + * There are 3584 bytes available at CONFADDR.
       + *
       + * The low-level boot routines in l.s leave data for us at CONFADDR,
       + * which we pick up before reading the plan9.ini file.
       + */
       +#define BOOTLINELEN        64
       +#define        BOOTARGSLEN        (3584-0x200-BOOTLINELEN)
       +#define        MAXCONF                100
       +
       +extern char **ini;
       +
       +ttypedef struct {
       +        char*        name;
       +        int        start;
       +        int        end;
       +} Mblock;
       +
       +ttypedef struct {
       +        char*        tag;
       +        Mblock*        mb;
       +} Mitem;
       +
       +static Mblock mblock[MAXCONF];
       +static int nmblock;
       +static Mitem mitem[MAXCONF];
       +static int nmitem;
       +static char* mdefault;
       +static char mdefaultbuf[10];
       +static int mtimeout;
       +
       +static void
       +getstr(char* prompt, char* buf, int n, char* def, int timeout)
       +{
       +        char *p;
       +        int i;
       +        char c;
       +
       +        if(def == nil)
       +                print("%s: ", prompt);
       +        else
       +                print("%s[default==%s]: ", prompt, def);
       +        for(p = buf, i = 0; i < n-1;){
       +                qread(kbdq, &c, 1);
       +                switch(c){
       +                case '\b':
       +                        if(i > 0){
       +                                --p;
       +                                --i;
       +                        }
       +                        break;
       +                case 0x15:
       +                        p = buf;
       +                        i = 0;
       +                        break;
       +                case '\n':
       +                        break;
       +                default:
       +                        *p++ = c;
       +                        ++i;
       +                        break;
       +                }
       +                if(c == '\n')
       +                        break;
       +        }
       +        *p = 0;
       +        if(i == 0)
       +                strcpy(buf, def);
       +}
       +
       +static char*
       +comma(char* line, char** residue)
       +{
       +        char *q, *r;
       +
       +        if((q = strchr(line, ',')) != nil){
       +                *q++ = 0;
       +                if(*q == ' ')
       +                        q++;
       +        }
       +        *residue = q;
       +
       +        if((r = strchr(line, ' ')) != nil)
       +                *r = 0;
       +
       +        if(*line == ' ')
       +                line++;
       +        return line;
       +}
       +
       +static Mblock*
       +findblock(char* name, char** residue)
       +{
       +        int i;
       +        char *p;
       +
       +        p = comma(name, residue);
       +        for(i = 0; i < nmblock; i++){
       +                if(strcmp(p, mblock[i].name) == 0)
       +                        return &mblock[i];
       +        }
       +        return nil;
       +}
       +
       +static Mitem*
       +finditem(char* name, char** residue)
       +{
       +        int i;
       +        char *p;
       +
       +        p = comma(name, residue);
       +        for(i = 0; i < nmitem; i++){
       +                if(strcmp(p, mitem[i].mb->name) == 0)
       +                        return &mitem[i];
       +        }
       +        return nil;
       +}
       +
       +static void
       +parsemenu(char* str, int len)
       +{
       +        Mitem *mi;
       +        Mblock *mb, *menu;
       +        char buf[20], scratch[BOOTARGSLEN], *p, *q, *line[MAXCONF];
       +        int i, inblock, n, show;
       +
       +        inblock = 0;
       +        menu = nil;
       +        memmove(scratch, str, len);
       +        n = getfields(scratch, line, MAXCONF, 0, "\n");
       +        if(n >= MAXCONF)
       +                print("warning: possibly too many lines in plan9.ini\n");
       +        for(i = 0; i < n; i++){
       +                p = line[i];
       +                if(inblock && *p == '['){
       +                        mblock[nmblock].end = i;
       +                        if(strcmp(mblock[nmblock].name, "menu") == 0)
       +                                menu = &mblock[nmblock];
       +                        nmblock++;
       +                        inblock = 0;
       +                }
       +                if(*p == '['){
       +                        if(nmblock == 0 && i != 0){
       +                                mblock[nmblock].name = "common";
       +                                mblock[nmblock].start = 0;
       +                                mblock[nmblock].end = i;
       +                                nmblock++;
       +                        }
       +                        q = strchr(p+1, ']');
       +                        if(q == nil || *(q+1) != 0){
       +                                print("malformed menu block header - %s\n", p);
       +                                return;
       +                        }
       +                        *q = 0;
       +                        mblock[nmblock].name = p+1;
       +                        mblock[nmblock].start = i+1;
       +                        inblock = 1;
       +                }
       +        }
       +
       +        if(inblock){
       +                mblock[nmblock].end = i;
       +                nmblock++;
       +        }
       +        if(menu == nil)
       +                return;
       +        if(nmblock < 2){
       +                print("incomplete menu specification\n");
       +                return;
       +        }
       +
       +        for(i = menu->start; i < menu->end; i++){
       +                p = line[i];
       +                if(strncmp(p, "menuitem=", 9) == 0){
       +                        p += 9;
       +                        if((mb = findblock(p, &q)) == nil){
       +                                print("no block for menuitem %s\n", p);
       +                                return;
       +                        }
       +                        if(q != nil)
       +                                mitem[nmitem].tag = q;
       +                        else
       +                                mitem[nmitem].tag = mb->name;
       +                        mitem[nmitem].mb = mb;
       +                        nmitem++;
       +                }
       +                else if(strncmp(p, "menudefault=", 12) == 0){
       +                        p += 12;
       +                        if((mi = finditem(p, &q)) == nil){
       +                                print("no item for menudefault %s\n", p);
       +                                return;
       +                        }
       +                        if(q != nil)
       +                                mtimeout = strtol(q, 0, 0);
       +                        sprint(mdefaultbuf, "%ld", mi-mitem+1);
       +                        mdefault = mdefaultbuf;
       +                }
       +                else if(strncmp(p, "menuconsole=", 12) == 0){
       +                        p += 12;
       +                        p = comma(p, &q);
       +                        /* consinit(p, q); */
       +                }
       +                else{
       +                        print("invalid line in [menu] block - %s\n", p);
       +                        return;
       +                }
       +        }
       +
       +again:
       +        print("\nPlan 9 Startup Menu:\n====================\n");
       +        for(i = 0; i < nmitem; i++)
       +                print("    %d. %s\n", i+1, mitem[i].tag);
       +        for(;;){
       +                getstr("Selection", buf, sizeof(buf), mdefault, mtimeout);
       +                mtimeout = 0;
       +                i = strtol(buf, &p, 0)-1;
       +                if(i < 0 || i >= nmitem)
       +                        goto again;
       +                switch(*p){
       +                case 'p':
       +                case 'P':
       +                        show = 1;
       +                        print("\n");
       +                        break;
       +                case 0:
       +                        show = 0;
       +                        break;
       +                default:
       +                        continue;
       +                        
       +                }
       +                mi = &mitem[i];
       +        
       +                p = str;
       +                p += sprint(p, "menuitem=%s\n", mi->mb->name);
       +                for(i = 0; i < nmblock; i++){
       +                        mb = &mblock[i];
       +                        if(mi->mb != mb && strcmp(mb->name, "common") != 0)
       +                                continue;
       +                        for(n = mb->start; n < mb->end; n++)
       +                                p += sprint(p, "%s\n", line[n]);
       +                }
       +
       +                if(show){
       +                        for(q = str; q < p; q += i){
       +                                if((i = print(q)) <= 0)
       +                                        break;
       +                        }
       +                        goto again;
       +                }
       +                break;
       +        }
       +        print("\n");
       +}
       +
       +/*
       + *  read configuration file
       + */
       +static char inibuf[BOOTARGSLEN];
       +
       +int
       +dotini(char *fn)
       +{
       +        int blankline, i, incomment, inspace, n, fd;
       +        char *cp, *p, *q, *line[MAXCONF];
       +
       +        if((fd = open(fn, OREAD)) < 0)
       +                return -1;
       +
       +        cp = inibuf;
       +        *cp = 0;
       +        n = read(fd, cp, BOOTARGSLEN-1);
       +        close(fd);
       +        if(n <= 0)
       +                return -1;
       +
       +        cp[n] = 0;
       +
       +        /*
       +         * Strip out '\r', change '\t' -> ' '.
       +         * Change runs of spaces into single spaces.
       +         * Strip out trailing spaces, blank lines.
       +         *
       +         * We do this before we make the copy so that if we 
       +         * need to change the copy, it is already fairly clean.
       +         * The main need is in the case when plan9.ini has been
       +         * padded with lots of trailing spaces, as is the case 
       +         * for those created during a distribution install.
       +         */
       +        p = cp;
       +        blankline = 1;
       +        incomment = inspace = 0;
       +        for(q = cp; *q; q++){
       +                if(*q == '\r')
       +                        continue;
       +                if(*q == '\t')
       +                        *q = ' ';
       +                if(*q == ' '){
       +                        inspace = 1;
       +                        continue;
       +                }
       +                if(*q == '\n'){
       +                        if(!blankline){
       +                                if(!incomment)
       +                                        *p++ = '\n';
       +                                blankline = 1;
       +                        }
       +                        incomment = inspace = 0;
       +                        continue;
       +                }
       +                if(inspace){
       +                        if(!blankline && !incomment)
       +                                *p++ = ' ';
       +                        inspace = 0;
       +                }
       +                if(blankline && *q == '#')
       +                        incomment = 1;
       +                blankline = 0;
       +                if(!incomment)
       +                        *p++ = *q;        
       +        }
       +        if(p > cp && p[-1] != '\n')
       +                *p++ = '\n';
       +        *p++ = 0;
       +        n = p-cp;
       +
       +        parsemenu(cp, n);
       +
       +        n = getfields(cp, line, MAXCONF, 0, "\n");
       +        for(i = 0; i < n; i++){
       +                cp = strchr(line[i], '=');
       +                if(cp == 0)
       +                        continue;
       +                *cp++ = 0;
       +                if(cp - line[i] >= NAMELEN+1)
       +                        *(line[i]+NAMELEN-1) = 0;
       +                ksetenv(line[i], cp, 0);
       +        }
       +        return 0;
       +}
 (DIR) diff --git a/src/9vx/fossil.9 b/src/9vx/fossil.9
       Binary files differ.
 (DIR) diff --git a/src/9vx/ipconfig.9 b/src/9vx/ipconfig.9
       Binary files differ.
 (DIR) diff --git a/src/9vx/main.c b/src/9vx/main.c
       @@ -42,6 +42,7 @@ char*        argv0;
        char*        conffile = "9vx";
        Conf        conf;
        
       +static char*        inifile;
        static int        bootboot;        /* run /boot/boot instead of bootscript */
        static int        initrc;        /* run rc instead of init */
        static char*        username;
       @@ -62,7 +63,8 @@ static char*        findroot(void);
        void
        usage(void)
        {
       -        fprint(2, "usage: 9vx [-gt] [-r root] [-u user]\n");
       +        // TODO(yy): add debug and other options by ron
       +        fprint(2, "usage: 9vx [-bgit] [-r root] [-u user] [-p ini file]\n");
                exit(1);
        }
        
       @@ -132,6 +134,9 @@ main(int argc, char **argv)
                case 'i':
                        initrc = 1;
                        break;
       +        case 'p':
       +                inifile = EARGF(usage());
       +                break;
                case 'r':
                        localroot = EARGF(usage());
                        break;
       @@ -304,6 +309,12 @@ bootinit(void)
                 */
                extern uchar factotumcode[];
                extern long factotumlen;
       +        extern uchar fossilcode[];
       +        extern long fossillen;
       +        extern uchar venticode[];
       +        extern long ventilen;
       +        extern uchar ipconfigcode[];
       +        extern long ipconfiglen;
        
                if(bootboot){
                        extern uchar bootcode[];
       @@ -314,6 +325,9 @@ bootinit(void)
                else
                        addbootfile("boot", (uchar*)bootscript, strlen(bootscript));
                addbootfile("factotum", factotumcode, factotumlen);
       +        addbootfile("fossil", fossilcode, fossillen);
       +        addbootfile("venti", venticode, ventilen);
       +        addbootfile("ipconfig", ipconfigcode, ipconfiglen);
        }
        
        static uchar *sp;        /* user stack of init proc */
       @@ -484,6 +498,8 @@ init0(void)
                        ksetenv("service", "terminal", 0);
                ksetenv("user", username, 0);
                ksetenv("sysname", "vx32", 0);
       +        if(inifile)
       +                dotini(inifile);
                
                /* if we're not running /boot/boot, mount / and create /srv/boot */
                if(!bootboot){
 (DIR) diff --git a/src/9vx/sdloop.c b/src/9vx/sdloop.c
       @@ -22,6 +22,7 @@ struct Ctlr{
                Chan        *c;
                int                mode;
                uvlong        qidpath;
       +        char                fn[20];
        };
        
        static        Lock        ctlrlock;
       @@ -30,9 +31,47 @@ static        Ctlr        *ctlrtail;
        
        SDifc sdloopifc;
        
       +static void
       +loopopen(Ctlr *c)
       +{
       +        if(c->c == nil)
       +                c->c = namec(c->fn, Aopen, c->mode, 0);
       +}
       +
        static SDev*
        looppnp(void)
        {
       +        struct stat sbuf;
       +        char c, c2;
       +        char fn[20];
       +
       +        for(c = 'a'; c <= 'j'; ++c){
       +                sprint(fn, "#Z/dev/sd%c", c);
       +                if(stat(fn+2, &sbuf) == 0)
       +                        loopdev(fn, ORDWR);
       +        }
       +        for(c = '0'; c <= '9'; ++c){
       +                sprintf(fn, "#Z/dev/sd%c",c);
       +                if(stat(fn+2, &sbuf) == 0)
       +                        loopdev(fn, ORDWR);
       +        }
       +        for(c = 'a'; c <= 'j'; ++c){
       +                sprint(fn, "#Z/dev/hd%c", c);
       +                if(stat(fn+2, &sbuf) == 0)
       +                        loopdev(fn, ORDWR);
       +        }
       +        for(c = '0'; c <= '9'; ++c){
       +                sprint(fn, "#Z/dev/wd%c", c);
       +                if(stat(fn+2, &sbuf) == 0)
       +                        loopdev(fn, ORDWR);
       +        }
       +        for(c = '0'; c <= '8'; ++c){
       +                for(c2 = '0'; c2 <= '8'; ++c2){
       +                        sprint(fn, "#Z/dev/cciss/c%cd%c", c, c2);
       +                        if(stat(fn+2, &sbuf) == 0)
       +                                loopdev(fn, ORDWR);
       +                }
       +        }
                return nil;
        }
        
       @@ -69,6 +108,7 @@ looponline(SDunit *unit)
        
                sdev = unit->dev;
                ctlr = sdev->ctlr;
       +        loopopen(ctlr);
                c = ctlr->c;
                n = devtab[c->type]->stat(c, buf, sizeof buf);
                if(convM2D(buf, n, &dir, nil) == 0)
       @@ -99,6 +139,7 @@ looprio(SDreq *r)
                unit = r->unit;
                sdev = unit->dev;
                ctlr = sdev->ctlr;
       +        loopopen(ctlr);
                cmd = r->cmd;
        
                if((status = sdfakescsi(r, nil, 0)) != SDnostatus){
       @@ -141,6 +182,7 @@ looprctl(SDunit *unit, char *p, int l)
                char *e, *op;
                
                ctlr = unit->dev->ctlr;
       +        loopopen(ctlr);
                e = p+l;
                op = p;
                
       @@ -170,7 +212,8 @@ loopclear1(Ctlr *ctlr)
                        ctlrtail = ctlr->prev;
                unlock(&ctlrlock);
                
       -        cclose(ctlr->c);
       +        if(ctlr->c)
       +                cclose(ctlr->c);
                free(ctlr);
        }
        
       @@ -187,6 +230,7 @@ looprtopctl(SDev *s, char *p, char *e)
                char *r;
        
                c = s->ctlr;
       +        loopopen(c);
                r = "ro";
                if(c->mode == ORDWR)
                        r = "rw";
       @@ -219,9 +263,9 @@ loopdev(char *name, int mode)
                Ctlr *volatile ctlr;
                SDev *volatile sdev;
        
       -        c = namec(name, Aopen, mode, 0);
                ctlr = nil;
                sdev = nil;
       +/*
                if(waserror()){
                        cclose(c);
                        if(ctlr)
       @@ -230,6 +274,7 @@ loopdev(char *name, int mode)
                                free(sdev);
                        nexterror();
                }
       +*/
        
                ctlr = smalloc(sizeof *ctlr);
                sdev = smalloc(sizeof *sdev);
       @@ -238,9 +283,11 @@ loopdev(char *name, int mode)
                sdev->nunit = 1;
                sdev->idno = '0';
                ctlr->sdev = sdev;
       -        ctlr->c = c;
       +        strcpy(ctlr->fn, name);
                ctlr->mode = mode;
       +/*
                poperror();
       +*/
        
                lock(&ctlrlock);
                ctlr->next = nil;
 (DIR) diff --git a/src/9vx/venti.9 b/src/9vx/venti.9
       Binary files differ.