new option parsing - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
 (DIR) commit 91f17a2007af56e7a849bc5ea5f6f2d06c9f5185
 (DIR) parent e399db13cacb63f1a2c362e2548b6a4afd16e9f9
 (HTM) Author: Jesus Galan Lopez (yiyus) <yiyu.jgl@gmail.com>
       Date:   Fri, 24 Sep 2010 01:15:13 +0200
       
       new option parsing
       
       Diffstat:
         M src/9vx/a/lib.h                     |       1 +
         M src/9vx/conf.c                      |     272 ++++++++++++++++---------------
         M src/9vx/conf.h                      |      26 +++++++++++---------------
         M src/9vx/devfs-posix.c               |       4 ++--
         M src/9vx/main.c                      |     139 +++++++++++--------------------
       
       5 files changed, 205 insertions(+), 237 deletions(-)
       ---
 (DIR) diff --git a/src/9vx/a/lib.h b/src/9vx/a/lib.h
       @@ -22,6 +22,7 @@ extern        char*        cleanname(char*);
        extern        ulong        getcallerpc(void*);
        
        extern        int        getfields(char*, char**, int, int, char*);
       +extern        int        gettokens(char *, char **, int , char *);
        extern        int        tokenize(char*, char**, int);
        extern        int        dec64(uchar*, int, char*, int);
        
 (DIR) diff --git a/src/9vx/conf.c b/src/9vx/conf.c
       @@ -12,36 +12,55 @@
        #include        "etherif.h"
        #include         "vether.h"
        
       -/*
       - *  read configuration file
       - */
       -int
       -readini(char *fn)
       +char        filebuf[BOOTARGSLEN];
       +
       +void
       +setinioptions()
        {
       -        int blankline, incomment, inspace, n, fd;
       -        static int nfields = 0;
       -        static char *buf = inibuf;
       -        char *cp, *p, *q;
       +        static int i;
       +        char *name, *value;
        
       -        if(strcmp(fn, "-") == 0)
       -                fd = fileno(stdin);
       -        else if((fd = open(fn, OREAD)) < 0)
       -                return -1;
       +        for(; i < MAXCONF; i++){
       +                if(!inifield[i])
       +                        break;
       +                name = inifield[i];
       +                if(*name == '*')
       +                        name++;
       +                value = strchr(inifield[i], '=');
       +                if(value == 0)
       +                        continue;
       +                *value++ = 0;
       +                if(strcmp(name, "cpulimit") == 0)
       +                        cpulimit = atoi(value);
       +                else if(strcmp(name, "memsize") == 0)
       +                        memsize = atoi(value);
       +                else if(strcmp(name, "canopenfiles") == 0)
       +                        canopen = value;
       +                else if(strcmp(name, "ether") == 0)
       +                        //addether(name, value);
       +                        value = value;
       +                else if(strcmp(name, "initarg") == 0)
       +                        initarg = value;
       +                else if(strcmp(name, "localroot") == 0)
       +                        localroot = value;
       +                else if(strcmp(name, "user") == 0)
       +                        username = value;
       +                *(--value) = '=';
       +        }
       +}
        
       -        cp = buf;
       -        *buf = 0;
       -        while((n = read(fd, buf, BOOTARGSLEN-1)) > 0)
       -                if(n<0)
       -                        return -1;
       -                else
       -                        buf += n;
       -        close(fd);
       -        *buf = 0;
       +void
       +addini(char *buf)
       +{
       +        static int n = 0;
       +        int blankline, incomment, inspace, inquote;
       +        char *p, *q;
        
                /*
                 * Strip out '\r', change '\t' -> ' '.
                 * Change runs of spaces into single spaces.
                 * Strip out trailing spaces, blank lines.
       +         * The text between single quotes is not touched.
                 *
                 * We do this before we make the copy so that if we 
                 * need to change the copy, it is already fairly clean.
       @@ -49,10 +68,18 @@ readini(char *fn)
                 * padded with lots of trailing spaces, as is the case 
                 * for those created during a distribution install.
                 */
       -        p = cp;
       +        p = buf;
                blankline = 1;
       -        incomment = inspace = 0;
       -        for(q = cp; *q; q++){
       +        incomment = inquote =inspace = 0;
       +        for(q = buf; *q; q++){
       +                if(inquote){
       +                        if(*q == '\'')
       +                                inquote = 0;
       +                        *p++ = *q;
       +                        continue;
       +                }
       +                if(!incomment && *q == '\'')
       +                        inquote = 1;
                        if(*q == '\r')
                                continue;
                        if(*q == '\t')
       @@ -81,99 +108,103 @@ readini(char *fn)
                        if(!incomment)
                                *p++ = *q;        
                }
       -        if(p > cp && p[-1] != '\n')
       +        if(p > buf && p[-1] != '\n')
                        *p++ = '\n';
                *p++ = 0;
        
       -        nfields += gettokens(cp, &iniline[nfields], MAXCONF-nfields, "\n");
       -
       -        return 0;
       +        n += gettokens(buf, &inifield[n], MAXCONF-n, "\n");
       +        setinioptions();
        }
        
       -void
       -inifields(void (*fp)(char*, char*))
       +int
       +addinifile(char *file)
        {
       -        int i;
       -        char *cp;
       -        char *cq;
       +        static char *fb = filebuf;
       +        char *buf;
       +        int n, fd;
        
       -        for(i = 0; i < MAXCONF; i++){
       -                if(!iniline[i])
       -                        break;
       -                cp = strchr(iniline[i], '=');
       -                if(cp == 0)
       -                        continue;
       -                *cp++ = 0;
       -                if(*cp == '\''){
       -                        cp++;
       -                        if((cq = strrchr(cp, '\'')) > 0)
       -                                *cq = 0;
       -                }
       -                if(cp - iniline[i] >= NAMELEN+1)
       -                        *(iniline[i]+NAMELEN-1) = 0;
       -                (fp)(iniline[i], cp);
       -                *(cp-1) = '=';
       -        }
       +        if(strcmp(file, "-") == 0)
       +                fd = fileno(stdin);
       +        else if((fd = open(file, OREAD)) < 0)
       +                return -1;
       +
       +        buf = fb;
       +        *buf = 0;
       +        while((n = read(fd, buf, BOOTARGSLEN-1)) > 0)
       +                if(n<0)
       +                        return -1;
       +                else
       +                        buf += n;
       +        close(fd);
       +        *buf = 0;
       +        addini(fb);
       +        fb = buf;
       +        return n;
        }
        
       -void
       -iniopt(char *name, char *value)
       -{
       -        char *cp, *vedev;
       -        int vetap;
       -
       -        if(*name == '*')
       -                name++;
       -        if(strcmp(name, "nofork") == 0)
       -                nofork = 1;
       -        else if(strcmp(name, "nogui") == 0){
       -                nogui = 1;
       -                usetty = 1;
       +char*
       +fullpath(char *root) {
       +        char cwd[1024];
       +
       +        if(root[0] != '/'){
       +                if(getcwd(cwd, sizeof cwd) == nil)
       +                        panic("getcwd: %r");
       +                root = cleanname(smprint("%s/%s", cwd, root));
                }
       -        else if(strcmp(name, "initrc") == 0)
       -                initrc = 1;
       -        else if(strcmp(name, "usetty") == 0)
       -                usetty = 1;
       -        else if(strcmp(name, "cpulimit") == 0)
       -                cpulimit = atoi(value);
       -        else if(strcmp(name, "memsize") == 0)
       -                memmb = atoi(value);
       -        else if(strcmp(name, "netdev") == 0){
       -                if(strncmp(value, "tap", 3) == 0) {
       -                        vetap = 1;
       -                        value += 4;
       -                }
       -                vedev = value;
       -                cp = vedev;
       -                if((value = strchr(vedev, ' ')) != 0){
       -                        cp = strchr(value+1, '=');
       -                        *value=0;
       -                        *cp=0;
       -                }
       -                addve(*vedev == 0 ? nil : vedev, vetap);
       -                if(cp != vedev){
       -                        iniopt(value+1, cp+1);
       -                        *value=' ';
       -                        *cp='=';
       -                }
       +        return root;
       +}
       +
       +/* poor man's quotestrdup to avoid needing quote.c */
       +char*
       +quoted(char *in) {
       +        char *out, *p;
       +        int i, n;
       +
       +        n = 0;
       +        for(i = 0; i < strlen(in); i++)
       +                if(in[i] == '\'')
       +                        n++;
       +        out = malloc(strlen(in) + n + 2);
       +        p = out;
       +        if(*in != '\'')
       +        *p++ = '\'';
       +        for(i = 0; i < strlen(in); i++){
       +                if(in[i] == '\'')
       +                        *p++ = in[i];
       +                *p++ = in[i];
                }
       -        else if(strcmp(name, "macaddr") == 0)
       -                setmac(value);
       -        else if(strcmp(name, "localroot") == 0 && !localroot)
       -                localroot = value;
       -        else if(strcmp(name, "allowed") == 0 && !allowed)
       -                allowed = value;
       -        else if(strcmp(name, "user") == 0 && !username)
       -                username = value;
       -        else if(strcmp(name, "initcmd") == 0 && !initcmd)
       -                initcmd = value;
       +        *p++ = '\'';
       +        *p = 0;
       +        return out;
        }
        
        void
       -inienv(char *name, char *value)
       +setinienv()
        {
       -        if(*name != '*')
       +        int i;
       +        char *name, *value;
       +
       +        for(i = 0; i < MAXCONF; i++){
       +                if(!inifield[i])
       +                        break;
       +                name = inifield[i];
       +                value = strchr(inifield[i], '=');
       +                if(*name == '*' || value == 0 || value[0] == 0)
       +                        continue;
       +                *value++ = 0;
                        ksetenv(name, value, 0);
       +        }
       +        if(initarg){
       +                if(*initarg != '\'')
       +                        initarg = quoted(initarg);
       +                value = smprint("/386/init -t %s", initarg);
       +                ksetenv("init", value, 0);
       +        }
       +        if(localroot){
       +                value = smprint("local!#Z%s", fullpath(localroot));
       +                ksetenv("nobootprompt", value, 0);
       +        }
       +        ksetenv("user", username, 0);
        }
        
        /*
       @@ -184,30 +215,16 @@ printconfig(char *argv0){
                int i;
        
                print(argv0);
       -        if(inifile)
       -                print(" -p %s", inifile);
       -        if(nofork | nogui | initrc | usetty)
       -                print(" -%s%s%s%s", nofork ? "f " : "", nogui ? "g" : "",
       -                        initrc ? "i " : "", usetty ? "t " : "");
       -        if(cpulimit != 0)
       -                print(" -l %d", cpulimit);
       -        if(memmb != 0)
       -                print(" -m %d", memmb);
       -        for(i=0; i<nve; i++){
       -                print(" -n %s", ve[i].tap ? "tap ": "");
       -                if(ve[i].dev != nil)
       -                        print(" %s", ve[i].dev);
       -                if(ve[i].mac != nil)
       -                        print(" -a %s", ve[i].mac);
       +        if(usetty)
       +                print(" -%c", nogui ? 'g' : 't');
       +        for(i = 0; i < MAXCONF; i++){
       +                if(!inifield[i])
       +                        break;
       +                print("\t%s\n", inifield[i]);
                }
       -        if(allowed && strcmp(allowed, "/") != 0)
       -                print(" -z %s", allowed);
       +        if(initarg)
       +                print("\tinit=/386/init -t %s\n", initarg);
                if(localroot)
       -                print(" -r %s", localroot);
       -        print(" -u %s", username);
       -        if(initcmd)
       -                print(" -e %s", initcmd);
       -        for(i = 0; i < bootargc; i++)
       -                print(" %s", bootargv[i]);
       -        print("\n");
       -}
       -\ No newline at end of file
       +                print("\tnobootprompt=#Z%s\n", localroot);
       +        print("\tuser=%s\n", username);
       +}
 (DIR) diff --git a/src/9vx/conf.h b/src/9vx/conf.h
       @@ -2,24 +2,20 @@
        #define        BOOTARGSLEN        (3584-0x200-BOOTLINELEN)
        #define        MAXCONF                100
        
       -char        inibuf[BOOTARGSLEN];
       -char        *iniline[MAXCONF];
       -int        cpulimit;        /* max cpu usage */
       -int        initrc;        /* run rc instead of init */
       -int        nofork;        /* do not fork at init */
       -int        nogui;        /* do not start the gui */
       -int        usetty;        /* use tty for input/output */
       -int        memmb;        /* memory size in mb */
       +char        *inifield[MAXCONF];
       +int        nofork;
       +int        nogui;
       +int        usetty;
       +int        cpulimit;
       +int        memsize;
        int        bootargc;
        char**        bootargv;
       -char*        initcmd;
       -char*        inifile;
       +char*        canopen;
       +char*        initarg;
        char*        localroot;
       -char*        allowed;
        char*        username;
        
       -int        readini(char *fn);
       -void        inifields(void (*fp)(char*, char*));
       -void        iniopt(char*, char*);
       -void        inienv(char*, char*);
       +int        addinifile(char*);
       +void        addini(char*);
        void        printconfig(char*);
       +void        setinienv();
 (DIR) diff --git a/src/9vx/devfs-posix.c b/src/9vx/devfs-posix.c
       @@ -33,7 +33,7 @@ enum
                FsChar = 'Z',
        };
        
       -extern char *allowed;
       +extern char *canopen;
        extern Path *addelem(Path*, char*, Chan*);
        static char *uidtoname(int);
        static char *gidtoname(int);
       @@ -357,7 +357,7 @@ fsopen(Chan *c, int mode)
                        print("fsopen %s %#x\n", ufd->path->s, mode);
        
                /* protect files whose path does not begin with allowed */
       -        if(strncmp(ufd->path->s, allowed, strlen(allowed)) != 0)
       +        if(strncmp(ufd->path->s, canopen, strlen(canopen)) != 0)
                        error(Eperm);
        
                if(mode & ~(OTRUNC|ORCLOSE|3))
 (DIR) diff --git a/src/9vx/main.c b/src/9vx/main.c
       @@ -50,11 +50,7 @@ int        abortonfault;
        int        nocpuload;
        char*        argv0;
        char*        conffile = "9vx";
       -char*        defaultroot = "local!/boot/rootfs.bz2";
       -char*        defaultinit = "\
       -/386/bin/bind -a /386/bin /bin; \
       -/386/bin/bind -a /rc/bin /bin; \
       -/386/bin/rc -i";
       +char*        defaultboot = "local!/boot/rootfs.bz2";
        Conf        conf;
        
        static Mach mach0;
       @@ -69,13 +65,12 @@ static void        siginit(void);
        static void machkeyinit(void);
        
        static char*        getuser(void);
       -static char*        nobootprompt(char*);
        
        void
        usage(void)
        {
                // TODO(yy): add debug and other options by ron
       -        fprint(2, "usage: 9vx [-p file.ini] [-fgit] [-l cpulimit] [-m memsize] [-n [tap] netdev] [-a macaddr] [-z allowed] [-r root] [-u user] [-e initcmd] [bootargs]\n");
       +        fprint(2, "usage: 9vx [-gt] [-f inifile | inifields ... ] [-i initarg] [-r localroot] [-u user]\n");
                exit(1);
        }
        
       @@ -88,7 +83,7 @@ int
        main(int argc, char **argv)
        {
                int vetap;
       -        char *vedev;
       +        char *file;
        
                /* Minimal set up to make print work. */
        #ifndef TLS
       @@ -99,14 +94,13 @@ main(int argc, char **argv)
                quotefmtinstall();
        
                cpulimit = 0;
       -        inifile = nil;
       -        memset(iniline, 0, MAXCONF);
       -        memmb = 0;
       +        memset(inifield, 0, MAXCONF);
       +        memsize = 256;
       +        canopen = "/";
                nogui = 0;
                nofork = 0;
                nve = 0;
                usetty = 0;
       -        allowed = "/";
                ARGBEGIN{
                /* debugging options */
                case '1':
       @@ -118,6 +112,9 @@ main(int argc, char **argv)
                case 'B':
                        abortonfault++;
                        break;
       +        case 'F':
       +                nofork = 1;
       +                break;
                case 'K':
                        tracekdev++;
                        break;
       @@ -141,70 +138,56 @@ main(int argc, char **argv)
                        break;
                
                /* real options */
       -        case 'a':
       -                setmac(EARGF(usage()));
       -                break;
       -        case 'e':
       -                initcmd = EARGF(usage());
       -                break;
       -        case 'f':
       -                nofork = 1;
       -                break;
                case 'g':
                        nogui = 1;
                        usetty = 1;
                        break;
       -        case 'i':
       -                initrc = 1;
       -                break;
       -        case 'l':
       -                cpulimit = atoi(EARGF(usage()));
       +        case 't':
       +                usetty = 1;
                        break;
       -        case 'm':
       -                memmb = atoi(EARGF(usage()));
       +        default:
       +                goto iniargs;
       +        }ARGEND
       +
       +iniargs:
       +        while(argc > 0 && argv[0][0] != '-'){
       +                addini(strdup(argv[0]));
       +                argc--; argv++;
       +        }
       +        /*
       +         * ARGBEGIN will do: argv++; argc--;
       +         * but argv[0] is not argv0 now
       +         */
       +        argc++; argv--;
       +        ARGBEGIN{
       +        case 'f':
       +                file = EARGF(usage());
       +                if(addinifile(file) < 0)
       +                        panic("error reading config file %s", file);
                        break;
       -        case 'n':
       -                vetap = 0;
       -                vedev = ARGF();
       -                if(vedev != nil && strcmp(vedev, "tap") == 0){
       -                        vetap = 1;
       -                        vedev = ARGF();
       +        case 'i':
       +                /*
       +                 * Pass additional flag after -i is to init 
       +                 * This is convenient for -ic and -im
       +                 */
       +                if(_args[0] != 0){
       +                        initarg = smprint("-%c", _args[0]);
       +                        _args++;
                        }
       -                if(vedev == nil)
       -                        usage();
       -                addve(vedev, vetap);
       -                break;
       -        case 'p':
       -                inifile = EARGF(usage());
       +                else
       +                        initarg = EARGF(usage());
                        break;
                case 'r':
                        localroot = EARGF(usage());
                        break;
       -        case 't':
       -                usetty = 1;
       -                break;
                case 'u':
                        username = EARGF(usage());
                        break;
       -        case 'z':
       -                allowed = EARGF(usage());
       -                break;
                default:
                        usage();
                }ARGEND
       -
       -        if(inifile != nil && readini(inifile) != 0)
       -                panic("error reading config file %s", inifile);
       -
       -        bootargc = argc;
       -        bootargv = argv;
       -        /*
       -         * bootargs have preference over -r
       -         */
       -        if(bootargc > 0)
       -                localroot = nil;
       -
       -        inifields(&iniopt);
       +        if(argc > 0)
       +                goto iniargs;
        
                if(username == nil && (username = getuser()) == nil)
                        username = "tor";
       @@ -212,7 +195,7 @@ main(int argc, char **argv)
                if(eve == nil)
                        panic("strdup eve");
        
       -        mmusize(memmb);
       +        mmusize(memsize);
                mach0init();
                mmuinit();
                confinit();
       @@ -276,18 +259,6 @@ main(int argc, char **argv)
                return 0;  // Not reached
        }
        
       -char*
       -nobootprompt(char *root) {
       -        char cwd[1024];
       -
       -        if(root[0] != '/'){
       -                if(getcwd(cwd, sizeof cwd) == nil)
       -                        panic("getcwd: %r");
       -                root = cleanname(smprint("%s/%s", cwd, root));
       -        }
       -        return smprint("local!#Z%s", root);
       -}
       -
        static char*
        getuser(void)
        {
       @@ -457,7 +428,7 @@ bootargs(void *base)
                for(i = 0; i < bootargc && ac < 32; i++)
                        av[ac++] = pusharg(bootargv[i]);
                if(i == 0)
       -                av[ac++] = pusharg(defaultroot);
       +                av[ac++] = pusharg(defaultboot);
        
                /* 4 byte word align stack */
                sp = (uchar*)((uintptr)sp & ~3);
       @@ -527,26 +498,10 @@ init0(void)
                ksetenv("cputype", "386", 0);
                ksetenv("rootdir", "/root", 0);
                ksetenv("service", "terminal", 0);
       -        ksetenv("user", username, 0);
                ksetenv("sysname", "vx32", 0);
       -        inifields(&inienv);
       -
       -        if(initrc != 0){
       -                if(localroot == nil && inifile == nil && bootargc == 0){
       -                        ksetenv("nobootprompt", defaultroot, 0);
       -                        ksetenv("initcmd", defaultinit, 0);
       -                        ksetenv("init", "/386/bin/rc -c 'eval $initcmd", 0);
       -                }
       -                else
       -                        ksetenv("init", "/386/init -tm", 0);
       -        }
       -        else if(initcmd){
       -                ksetenv("initcmd", initcmd, 0);
       -                ksetenv("init", "/386/init -t '. /rc/bin/termrc; home=/usr/$user;\
       -                        test -d $home && cd; rc -c $initcmd; reboot'", 0);
       -        }
       -        if(localroot)
       -                ksetenv("nobootprompt", nobootprompt(localroot), 0);
       +        ksetenv("init", "/386/init -t", 0);
       +        ksetenv("user", username, 0);
       +        setinienv();
        
                poperror();