Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include        "all.h"
#include        "9p1.h"

static  char    elem[NAMELEN];
static  Filsys* cur_fs;
static  char    conline[100];

void
consserve(void)
{
        con_session();
        cmd_exec("cfs");
        cmd_exec("user");
}

int
cmd_exec(char *arg)
{
        char *s, *c;
        int i;

        for(i=0; s = command[i].string; i++) {
                for(c=arg; *s; c++)
                        if(*c != *s++)
                                goto brk;
                if(*c == '\0' || *c == ' ' || *c == '\t'){
                        cons.arg = c;
                        (*command[i].func)();
                        return 1;
                }
        brk:;
        }
        return 0;
}

void
cmd_check(void)
{
        char *s;
        int flags;

        flags = 0;
        for(s = cons.arg; *s; s++){
                while(*s == ' ' || *s == '\t')
                        s++;
                if(*s == '\0')
                        break;
                switch(*s){
                /* rebuild the free list */
                case 'f':       flags |= Cfree;                 break;
                /* fix bad tags */
                case 't':       flags |= Ctag;                  break;
                /* fix bad tags and clear the contents of the block */
                case 'c':       flags |= Cream;                 break;
                /* delete all redundant references to a block */
                case 'd':       flags |= Cbad;                  break;
                /* read and check tags on all blocks */
                case 'r':       flags |= Crdall;                break;
                /* write all of the blocks you touch */
                case 'w':       flags |= Ctouch;                break;
                /* print all directories as they are read */
                case 'p':       flags |= Cpdir;                 break;
                /* print all files as they are read */
                case 'P':       flags |= Cpfile;                break;
                /* quiet, just report really nasty stuff */
                case 'q':       flags |= Cquiet;                break;
                }
        }
        check(cur_fs, flags);
}

enum
{
        Sset    = (1<<0),
        Setc    = (1<<1),
};
void
cmd_stats(void)
{
        cprint("work stats\n");
        cprint("        work = %A rps\n", (Filta){&cons.work, 1});
        cprint("        rate = %A tBps\n", (Filta){&cons.rate, 1000});
        cprint("        hits = %A iops\n", (Filta){&cons.bhit, 1});
        cprint("        read = %A iops\n", (Filta){&cons.bread, 1});
        cprint("        init = %A iops\n", (Filta){&cons.binit, 1});
/*      for(i = 0; i < MAXTAG; i++)
                cprint("        tag %G = %A iops\n", i, (Filta){&cons.tags[i], 1});
*/
}

void
cmd_sync(void)
{
        rlock(&mainlock);
        syncall();
        runlock(&mainlock);
}

void
cmd_halt(void)
{
        wlock(&mainlock);
        syncall();
        superok(cur_fs->dev, superaddr(cur_fs->dev), 1);
        print("kfs: file system halted\n");
}

void
cmd_start(void)
{
        superok(cur_fs->dev, superaddr(cur_fs->dev), 0);
        wunlock(&mainlock);
        print("kfs: file system started\n");
}

void
cmd_help(void)
{
        int i;

        for(i=0; command[i].string; i++)
                cprint("        %s %s\n", command[i].string, command[i].args);
        cprint("check options:\n"
                " r     read all blocks\n"
                " f     rebuild the free list\n"
                " t     fix all bad tags\n"
                " c     fix bad tags and zero the blocks\n"
                " d     delete all redundant references to blocks\n"
                " p     print directories as they are checked\n"
                " P     print all files as they are checked\n"
                " w     write all blocks that are read\n");
}

void
cmd_create(void)
{
        int uid, gid, err;
        long perm;
        char oelem[NAMELEN];
        char name[NAMELEN];

        if(err = con_clone(FID1, FID2)){
                cprint("clone failed: %s\n", errstring[err]);
                return;
        }
        if(skipbl(1)){
                cprint("skipbl\n");
                return;
        }
        oelem[0] = 0;
        while(nextelem()) {
                if(oelem[0])
                        if(err = con_walk(FID2, oelem)){
                                cprint("walk failed: %s\n", errstring[err]);
                                return;
                        }
                memmove(oelem, elem, NAMELEN);
        }
        if(skipbl(1))
                return;
        uid = strtouid(cname(name));
        if(uid == 0){
                cprint("unknown user %s\n", name);
                return;
        }
        gid = strtouid(cname(name));
        if(gid == 0){
                cprint("unknown group %s\n", name);
                return;
        }
        perm = number(0777, 8);
        skipbl(0);
        for(; *cons.arg; cons.arg++){
                if(*cons.arg == 'l')
                        perm |= PLOCK;
                else
                if(*cons.arg == 'a')
                        perm |= PAPND;
                else
                if(*cons.arg == 'd')
                        perm |= PDIR;
                else
                        break;
        }
        err = con_create(FID2, elem, uid, gid, perm, 0);
        if(err)
                cprint("can't create %s: %s\n", elem, errstring[err]);
}

void
cmd_clri(void)
{
        if(con_clone(FID1, FID2))
                return;
        if(skipbl(1))
                return;
        while(nextelem())
                if(con_walk(FID2, elem)){
                        cprint("can't walk %s\n", elem);
                        return;
                }
        con_clri(FID2);
}

void
cmd_rename(void)
{
        ulong perm;
        Dentry d;
        char stat[DIRREC];
        char oelem[NAMELEN], noelem[NAMELEN], nxelem[NAMELEN];
        int err;

        if(con_clone(FID1, FID2))
                return;
        if(skipbl(1))
                return;
        oelem[0] = 0;
        while(nextelem()) {
                if(oelem[0])
                        if(con_walk(FID2, oelem)){
                                cprint("file does not exits");
                                return;
                        }
                memmove(oelem, elem, NAMELEN);
        }
        if(skipbl(1))
                return;
        if(cons.arg[0]=='/'){
                if(con_clone(FID1, FID3))
                        return;
                noelem[0] = 0;
                while(nextelem()){
                        if(noelem[0])
                                if(con_walk(FID3, noelem)){
                                        cprint("target path %s does not exist", noelem);
                                        return;
                                }
                        memmove(noelem, elem, NAMELEN);
                }
                if(!con_walk(FID3, elem)){
                        cprint("target %s already exists\n", elem);
                        return;
                }
                if(con_walk(FID2, oelem)){
                        cprint("src %s does not exist\n", oelem);
                        return;
                }
                /*
                 * we know the target does not exist,
                 * the source does exist.
                 * to do the rename, create the target and then
                 * copy the directory entry directly.  then remove the source.
                 */
                if(err = con_stat(FID2, stat)){
                        cprint("can't stat file: %s\n", errstring[err]);
                        return;
                }
                convM2D9p1(stat, &d);
                perm = (d.mode&0777)|((d.mode&0x7000)<<17);
                if(err = con_create(FID3, elem, d.uid, d.gid, perm, (d.mode&DDIR)?OREAD:ORDWR)){
                        cprint("can't create %s: %s\n", elem, errstring[err]);
                        return;
                }
                if(err = con_swap(FID2, FID3)){
                        cprint("can't swap data: %s\n", errstring[err]);
                        return;
                }
                if(err = con_remove(FID2)){
                        cprint("can't remove file: %s\n", errstring[err]);
                        return;
                }               
        }else{
                cname(nxelem);
                if(strchr(nxelem, '/')){
                        cprint("bad rename target: not full path, but contains slashes\n");
                        return;
                }
                if(!con_walk(FID2, nxelem))
                        cprint("file %s already exists\n", nxelem);
                else if(con_walk(FID2, oelem))
                        cprint("file does not already exist\n");
                else if(err = con_stat(FID2, stat))
                        cprint("can't stat file: %s\n", errstring[err]);
                else{
                        convM2D9p1(stat, &d);
                        strncpy(d.name, nxelem, NAMELEN);
                        convD2M9p1(&d, stat);
                        if(err = con_wstat(FID2, stat))
                                cprint("can't move file: %s\n", errstring[err]);
                }
        }       
}

void
cmd_remove(void)
{
        if(con_clone(FID1, FID2))
                return;
        if(skipbl(1))
                return;
        while(nextelem())
                if(con_walk(FID2, elem)){
                        cprint("can't walk %s\n", elem);
                        return;
                }
        con_remove(FID2);
}

void
cmd_cfs(void)
{
        Filsys *fs;

        if(*cons.arg != ' ') {
                fs = &filesys[0];               /* default */
        } else {
                if(skipbl(1)){
                        cprint("skipbl\n");
                        return;
                }
                if(!nextelem())
                        fs = &filesys[0];       /* default */
                else
                        fs = fsstr(elem);
        }
        if(fs == 0) {
                cprint("unknown file system %s\n", elem);
                return;
        }
        if(con_attach(FID1, "adm", fs->name))
                panic("FID1 attach to root");
        cur_fs = fs;
}

/*
 * find out the length of a file
 * given the mesg version of a stat buffer
 * we call this because convM2D is different
 * for the file system than in the os
 */
static uvlong
statlen(char *ap)
{
        uchar *p;
        ulong ll, hl;

        p = (uchar*)ap;
        p += 3*28+5*4;
        ll = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
        hl = p[4] | (p[5]<<8) | (p[6]<<16) | (p[7]<<24);
        return ll | ((uvlong) hl << 32);
}

int
adduser(char *user, int isgroup)
{
        char stat[DIRREC];
        char msg[100];
        Uid *u;
        int i, c, nu;

        /*
         * check uniq of name
         * and get next uid
         */
        cmd_exec("cfs");
        cmd_exec("user");
        if(isgroup)
                nu = 9000;
        else
                nu = 0;
        for(i=0, u=uid; i<conf.nuid; i++,u++) {
                c = u->uid;
                if(c == 0)
                        break;
                if(strcmp(uidspace+u->offset, user) == 0)
                        return 1;
                if(c >= 9000 && !isgroup)
                        continue;
                if(c > nu)
                        nu = c;
        }
        nu++;
        if(isgroup){
                if(nu >= 0x10000) {
                        cprint("out of group ids\n");
                        return 0;
                }
        } else {
                if(nu >= 9000) {
                        cprint("out of user ids\n");
                        return 0;
                }
        }

        /*
         * write onto adm/users
         */
        if(con_clone(FID1, FID2)
        || con_path(FID2, "/adm/users")
        || con_open(FID2, 1)) {
                cprint("can't open /adm/users\n");
                return 0;
        }

        sprint(msg, "%d:%s:%s:\n", nu, user, user);
        cprint("add user %s", msg);
        c = strlen(msg);
        i = con_stat(FID2, stat);
        if(i){
                cprint("can't stat /adm/users: %s\n", errstring[i]);
                return 0;
        }
        i = con_write(FID2, msg, statlen(stat), c);
        if(i != c){
                cprint("short write on /adm/users: %d %d\n", c, i);
                return 0;
        }
        return 1;
}

void
cmd_newuser(void)
{
        char user[NAMELEN], param[NAMELEN], msg[100];
        int i, c;

        /*
         * get uid
         */
        cname(user);
        cname(param);
        for(i=0; i<NAMELEN; i++) {
                c = user[i];
                if(c == 0)
                        break;
                if(c >= '0' && c <= '9'
                || c >= 'a' && c <= 'z'
                || c >= 'A' && c <= 'Z')
                        continue;
                cprint("bad character in name: 0x%x\n", c);
                return;
        }
        if(i < 2) {
                cprint("name too short: %s\n", user);
                return;
        }
        if(i >= NAMELEN) {
                cprint("name too long: %s\n", user);
                return;
        }

        switch(param[0]){
        case 0:
                if(!adduser(user, 0))
                        return;
                cmd_exec("user");
                break;
        case ':':
                adduser(user, 1);
                cmd_exec("user");
                return;
        case '#':
                adduser(user, 0);
                cmd_exec("user");
                return;
        }

        /*
         * create directories
         */
        cmd_exec("user");
        sprint(msg, "create /usr/%s %s %s 775 d", user, user, user);
        cmd_exec(msg);
        sprint(msg, "create /usr/%s/tmp %s %s 775 d", user, user, user);
        cmd_exec(msg);
        sprint(msg, "create /usr/%s/lib %s %s 775 d", user, user, user);
        cmd_exec(msg);
        sprint(msg, "create /usr/%s/bin %s %s 775 d", user, user, user);
        cmd_exec(msg);
        sprint(msg, "create /usr/%s/bin/rc %s %s 775 d", user, user, user);
        cmd_exec(msg);
        sprint(msg, "create /usr/%s/bin/mips %s %s 775 d", user, user, user);
        cmd_exec(msg);
        sprint(msg, "create /usr/%s/bin/386 %s %s 775 d", user, user, user);
        cmd_exec(msg);
        sprint(msg, "create /usr/%s/bin/power %s %s 775 d", user, user, user);
        cmd_exec(msg);
        sprint(msg, "create /usr/%s/bin/alpha %s %s 775 d", user, user, user);
        cmd_exec(msg);
}

void
cmd_checkuser(void)
{
        uchar buf[DIRREC], *p;
        static char utime[4];

        if(con_clone(FID1, FID2)
        || con_path(FID2, "/adm/users")
        || con_open(FID2, 0)
        || con_stat(FID2, (char*)buf))
                return;
        p = buf + 3*NAMELEN + 4*4;
        if(memcmp(utime, p, 4) == 0)
                return;
        memmove(utime, p, 4);
        cmd_user();
}

void
cmd_allow(void)
{
        wstatallow = 1;
}

void
cmd_disallow(void)
{
        wstatallow = 0;
}

void
cmd_chat(void)
{
        chat = 1 - chat;
}

void
cmd_atime(void)
{
        noatime = !noatime;
        if(noatime)
                cprint("atimes will not be updated\n");
        else
                cprint("atimes will be updated\n");
}

void
cmd_noneattach(void)
{
        allownone = !allownone;
        if(allownone) 
                cprint("none can attach to new connections\n");
        else
                cprint("none can only attach on authenticated connections\n");
}

void
cmd_listen(void)
{
        char addr[NAMELEN];

        if(skipbl(0))
                strcpy(addr, "tcp!*!564");      /* 9fs */
        else
                cname(addr);

        if(netserve(addr))
                cprint("announce %s failed\n", addr);
        else
                cprint("announce %s\n", addr);
}

void
cmd_nowritegroup(void)
{
        writegroup = 0;
}

Command command[] =
{
        "allow",        cmd_allow,      "",
        "allowoff",     cmd_disallow,   "",
        "atime",                cmd_atime,      "",
        "cfs",          cmd_cfs,        "[filesys]",
        "chat",         cmd_chat,       "",
        "check",        cmd_check,      "[cdfpPqrtw]",
        "clri",         cmd_clri,       "filename",
        "create",       cmd_create,     "filename user group perm [ald]",
        "disallow",     cmd_disallow,   "",
        "halt",         cmd_halt,       "",
        "help",         cmd_help,       "",
        "listen",               cmd_listen,     "[address]",
        "newuser",      cmd_newuser,    "username",
        "noneattach",   cmd_noneattach, "",
        "nowritegroup", cmd_nowritegroup,       "",
        "remove",       cmd_remove,     "filename",
        "rename",       cmd_rename,     "file newname",
        "start",        cmd_start, "",
        "stats",        cmd_stats,      "[fw]",
        "sync",         cmd_sync,       "",
        "user",         cmd_user,       "",
        0
};

int
skipbl(int err)
{
        if(*cons.arg != ' ') {
                if(err)
                        cprint("syntax error\n");
                return 1;
        }
        while(*cons.arg == ' ')
                cons.arg++;
        return 0;
}

char*
_cname(char *name)
{
        int i, c;

        memset(name, 0, NAMELEN);
        for(i=0;; i++) {
                c = *cons.arg;
                switch(c) {
                case ' ':
                case '\t':
                case '\n':
                case '\0':
                        return name;
                }
                if(i < NAMELEN-1)
                        name[i] = c;
                cons.arg++;
        }
}

char*
cname(char *name)
{
        skipbl(0);
        return _cname(name);
}

int
nextelem(void)
{
        char *e;
        int i, c;

        e = elem;
        while(*cons.arg == '/')
                cons.arg++;
        c = *cons.arg;
        if(c == 0 || c == ' ')
                return 0;
        for(i = 0; c = *cons.arg; i++) {
                if(c == ' ' || c == '/')
                        break;
                if(i == NAMELEN) {
                        cprint("path name component too long\n");
                        return 0;
                }
                *e++ = c;
                cons.arg++;
        }
        *e = 0;
        return 1;
}

long
number(int d, int base)
{
        int c, sign, any;
        long n;

        sign = 0;
        any = 0;
        n = 0;

        c = *cons.arg;
        while(c == ' ') {
                cons.arg++;
                c = *cons.arg;
        }
        if(c == '-') {
                sign = 1;
                cons.arg++;
                c = *cons.arg;
        }
        while((c >= '0' && c <= '9') ||
              (base == 16 && c >= 'a' && c <= 'f') ||
              (base == 16 && c >= 'A' && c <= 'F')) {
                n *= base;
                if(c >= 'a' && c <= 'f')
                        n += c - 'a' + 10;
                else
                if(c >= 'A' && c <= 'F')
                        n += c - 'A' + 10;
                else
                        n += c - '0';
                cons.arg++;
                c = *cons.arg;
                any = 1;
        }
        if(!any)
                return d;
        if(sign)
                n = -n;
        return n;
}