ref: f88a55e79b5bf656e7f9578d1318a955b9a4963a
dir: /sys/src/cmd/cwfs/con.c/
#include "all.h" static Command command[100]; static Flag flag[35]; static char statsdef[20]; /* default stats list */ static int whoflag; static void consserve1(void *); static void installcmds(void); static void tzinit(char*); void consserve(void) { int i; snprint(cons.chan->whochan, sizeof(cons.chan->whochan), "console"); installcmds(); con_session(); cmd_exec("cfs"); cmd_exec("users"); cmd_exec("version"); for(i = 0; command[i].arg0; i++) if(strcmp("cwcmd", command[i].arg0) == 0){ cmd_exec("cwcmd touchsb"); break; } /* switch console output to the cmd pipe */ dup(0, 1); newproc(consserve1, 0, "con"); } /* console commands process */ static void consserve1(void *) { char *conline; while(conline = Brdline(&bin, '\n')){ conline[Blinelen(&bin)-1] = '\0'; cmd_exec(conline); } } static int cmdcmp(void *va, void *vb) { Command *a, *b; a = va; b = vb; return strcmp(a->arg0, b->arg0); } void cmd_install(char *arg0, char *help, void (*func)(int, char*[])) { int i; qlock(&cons); for(i=0; command[i].arg0; i++) ; if(i >= nelem(command)-2) { qunlock(&cons); print("cmd_install: too many commands\n"); return; } command[i+1].arg0 = 0; command[i].help = help; command[i].func = func; command[i].arg0 = arg0; qsort(command, i+1, sizeof(Command), cmdcmp); qunlock(&cons); } void cmd_exec(char *arg) { char line[2*Maxword], *s; char *argv[10]; int argc, i, c; if(strlen(arg) >= nelem(line)-2) { print("cmd_exec: line too long\n"); return; } strcpy(line, arg); argc = 0; s = line; c = *s++; for(;;) { while(isascii(c) && isspace(c)) c = *s++; if(c == 0) break; if(argc >= nelem(argv)-2) { print("cmd_exec: too many args\n"); return; } argv[argc++] = s-1; while((!isascii(c) || !isspace(c)) && c != '\0') c = *s++; s[-1] = 0; } if(argc <= 0) return; for(i=0; s=command[i].arg0; i++) if(strcmp(argv[0], s) == 0) { (*command[i].func)(argc, argv); return; } print("cmd_exec: unknown command: %s\n", argv[0]); } static void cmd_halt(int, char *[]) { wlock(&mainlock); /* halt */ sync("halt"); exit(); } static void cmd_duallow(int argc, char *argv[]) { int uid; if(argc <= 1) { duallow = 0; return; } uid = strtouid(argv[1]); if(uid < 0) uid = number(argv[1], -2, 10); if(uid < 0) { print("bad uid %s\n", argv[1]); return; } duallow = uid; } static void cmd_stats(int argc, char *argv[]) { int i, c; char buf[30], *s, *p, *q; if(argc <= 1) { if(statsdef[0] == 0) strcpy(statsdef, "a"); sprint(buf, "stats s%s", statsdef); cmd_exec(buf); return; } strcpy(buf, "stat"); p = strchr(buf, 0); p[1] = 0; q = 0; for(i = 1; i < argc; i++) for(s = argv[i]; c = *s; s++) { if(c == 's') continue; if(c == '-') { q = statsdef; continue; } if(q) { *q++ = c; *q = 0; } *p = c; cmd_exec(buf); } } static void cmd_stata(int, char *[]) { int i; print("cons stats\n"); // print("\twork =%7W%7W%7W rps\n", cons.work+0, cons.work+1, cons.work+2); // print("\trate =%7W%7W%7W tBps\n", cons.rate+0, cons.rate+1, cons.rate+2); // print("\thits =%7W%7W%7W iops\n", cons.bhit+0, cons.bhit+1, cons.bhit+2); // print("\tread =%7W%7W%7W iops\n", cons.bread+0, cons.bread+1, cons.bread+2); // print("\trah =%7W%7W%7W iops\n", cons.brahead+0, cons.brahead+1, cons.brahead+2); // print("\tinit =%7W%7W%7W iops\n", cons.binit+0, cons.binit+1, cons.binit+2); print("\tbufs = %3ld sm %3ld lg %ld res\n", cons.nsmall, cons.nlarge, cons.nreseq); for(i=0; i<nelem(mballocs); i++) if(mballocs[i]) print("\t[%d]=%d\n", i, mballocs[i]); print("\tioerr= %3ld wr %3ld ww %3ld dr %3ld dw\n", cons.nwormre, cons.nwormwe, cons.nwrenre, cons.nwrenwe); print("\tcache= %9ld hit %9ld miss\n", cons.nwormhit, cons.nwormmiss); } static int flagcmp(void *va, void *vb) { Flag *a, *b; a = va; b = vb; return strcmp(a->arg0, b->arg0); } ulong flag_install(char *arg, char *help) { int i; qlock(&cons); for(i=0; flag[i].arg0; i++) ; if(i >= 32) { qunlock(&cons); print("flag_install: too many flags\n"); return 0; } flag[i+1].arg0 = 0; flag[i].arg0 = arg; flag[i].help = help; flag[i].flag = 1<<i; qsort(flag, i+1, sizeof(Flag), flagcmp); qunlock(&cons); return 1<<i; } void cmd_flag(int argc, char *argv[]) { int f, n, i, j; char *s; Chan *cp; if(argc <= 1) { for(i=0; flag[i].arg0; i++) print("%.4lux %s %s\n", flag[i].flag, flag[i].arg0, flag[i].help); if(cons.flags) print("flag[*] = %.4lux\n", cons.flags); for(cp = chans; cp; cp = cp->next) if(cp->flags) print("flag[%3d] = %.4lux\n", cp->chan, cp->flags); return; } f = 0; n = -1; for(i=1; i<argc; i++) { for(j=0; s=flag[j].arg0; j++) if(strcmp(s, argv[i]) == 0) goto found; j = number(argv[i], -1, 10); if(j < 0) { print("bad flag argument: %s\n", argv[i]); continue; } n = j; continue; found: f |= flag[j].flag; } if(n < 0) { cons.flags ^= f; if(f == 0) cons.flags = 0; print("flag = %.8lux\n", cons.flags); return; } for(cp = chans; cp; cp = cp->next) if(cp->chan == n) { cp->flags ^= f; if(f == 0) cp->flags = 0; print("flag[%3d] = %.8lux\n", cp->chan, cp->flags); return; } print("no such channel\n"); } static void cmd_who(int argc, char *argv[]) { Chan *cp; int i, c; c = 0; for(cp = chans; cp; cp = cp->next) { if(cp->whotime == 0 && !(cons.flags & whoflag)) { c++; continue; } if(argc > 1) { for(i=1; i<argc; i++) if(strcmp(argv[i], cp->whoname) == 0) break; if(i >= argc) { c++; continue; } } print("%3d: %10s %24s", cp->chan, cp->whoname, cp->whochan); if(cp->whoprint) cp->whoprint(cp); print("\n"); } if(c > 0) print("%d chans not listed\n", c); } static void cmd_hangup(int argc, char *argv[]) { Chan *cp; int n; if(argc < 2) { print("usage: hangup chan-number\n"); return; } n = number(argv[1], -1, 10); for(cp = chans; cp; cp = cp->next) { if(cp->whotime == 0) { if(cp->chan == n) print("that chan is hung up\n"); continue; } if(cp->chan == n) chanhangup(cp, "console command"); } } static void cmd_sync(int, char *[]) { wlock(&mainlock); /* sync */ sync("command"); wunlock(&mainlock); } static void cmd_help(int argc, char *argv[]) { char *arg; int i, j; for(i=0; arg=command[i].arg0; i++) { if(argc > 1) { for(j=1; j<argc; j++) if(strcmp(argv[j], arg) == 0) goto found; continue; } found: print("\t%s %s\n", arg, command[i].help); } } void cmd_fstat(int argc, char *argv[]) { int i; for(i=1; i<argc; i++) { if(walkto(argv[i])) { print("cant stat %s\n", argv[i]); continue; } con_fstat(FID2); } } void cmd_create(int argc, char *argv[]) { int uid, gid; long perm; char elem[NAMELEN], *p; if(argc < 5) { print("usage: create path uid gid mode [lad]\n"); return; } p = utfrrune(argv[1], '/'); if(p) { *p++ = 0; if(walkto(argv[1])) { print("create failed in walkto: %s\n", p); return; } } else { if(walkto("/")) return; p = argv[1]; } if(strlen(p) >= NAMELEN) { print("name too long %s\n", p); return; } memset(elem, 0, sizeof(elem)); strcpy(elem, p); uid = strtouid(argv[2]); if(uid < -1) uid = number(argv[2], -2, 10); if(uid < -1) { print("bad uid %s\n", argv[2]); return; } gid = strtouid(argv[3]); if(gid < -1) gid = number(argv[3], -2, 10); if(gid < -1) { print("bad gid %s\n", argv[3]); return; } perm = number(argv[4], 0777, 8) & 0777; if(argc > 5) { if(strchr(argv[5], 'l')) perm |= DMEXCL; if(strchr(argv[5], 'a')) perm |= DMAPPEND; if(strchr(argv[5], 'd')) perm |= DMDIR; if(strchr(argv[5], 't')) perm |= DMTMP; } if(con_create(FID2, elem, uid, gid, perm, 0)) print("create failed: %s/%s\n", argv[1], p); } static void cmd_clri(int argc, char *argv[]) { int i; for(i=1; i<argc; i++) { if(walkto(argv[i])) { print("cant remove %s\n", argv[i]); continue; } con_clri(FID2); } } static void cmd_allow(int argc, char *argv[]) { char *name; int uid; uid = -1; name = "any user"; if(argc > 1){ name = argv[1]; uid = strtouid(name); if(uid < 0) uid = number(name, -2, 10); if(uid < 0) { print("bad uid %s\n", name); return; } } print("allowed %s\n", name); allowed = uid; } static void cmd_disallow(int, char**) { allowed = 0; } void ckblock(Device *d, Off a, int typ, Off qpath) { Iobuf *p; if(a) { p = getbuf(d, a, Brd); if(p) { checktag(p, typ, qpath); putbuf(p); } } } void doclean(Iobuf *p, Dentry *d, int n, Off a) { int i, mod, typ; Off qpath; mod = 0; qpath = d->qid.path; typ = Tfile; if(d->mode & DDIR){ qpath ^= QPDIR; typ = Tdir; } for(i=0; i<NDBLOCK; i++) { print("dblock[%d] = %lld\n", i, (Wideoff)d->dblock[i]); ckblock(p->dev, d->dblock[i], typ, qpath); if(i == n) { d->dblock[i] = a; mod = 1; print("dblock[%d] modified %lld\n", i, (Wideoff)a); } } /* add NDBLOCK so user can cite block address by index */ for (i = 0; i < NIBLOCK; i++) { print("iblocks[%d] = %lld\n", NDBLOCK+i, (Wideoff)d->iblocks[i]); ckblock(p->dev, d->iblocks[i], Tind1+i, qpath); if(NDBLOCK+i == n) { d->iblocks[i] = a; mod = 1; print("iblocks[%d] modified %lld\n", NDBLOCK+i, (Wideoff)a); } } if(mod) p->flags |= Bmod|Bimm; } static void cmd_clean(int argc, char *argv[]) { int n; Off a; Iobuf *p; Dentry *d; File *f; p = 0; f = 0; while(argc > 1) { n = -1; if(argc > 2) n = number(argv[2], -1, 10); a = 0; if(argc > 3) a = number(argv[3], 0, 10); if(walkto(argv[1])) { print("cant remove %s\n", argv[1]); break; } f = filep(cons.chan, FID2, 0); if(!f) break; if(n >= 0 && f->fs->dev->type == Devro) { print("readonly %s\n", argv[1]); break; } p = getbuf(f->fs->dev, f->addr, Brd); d = getdir(p, f->slot); if(!d || !(d->mode & DALLOC)) { print("not alloc %s\n", argv[1]); break; } doclean(p, d, n, a); break; } if(f) qunlock(f); if(p) putbuf(p); } static void cmd_remove(int argc, char *argv[]) { int i; for(i=1; i<argc; i++) { if(walkto(argv[i])) { print("cant remove %s\n", argv[i]); continue; } con_remove(FID2); } } static void cmd_version(int, char *[]) { tzinit("/adm/timezone/local"); print("%d-bit %s as of %T\n", sizeof(Off)*8 - 1, service, fs_mktime); print("\tlast boot %T\n", boottime); } static void cmd_cfs(int argc, char *argv[]) { Filsys *fs; char *name; name = "main"; if(argc > 1) name = argv[1]; fs = fsstr(name); if(fs == 0) { print("%s: unknown file system\n", name); if(cons.curfs) return; fs = &filsys[0]; } if(con_attach(FID1, "adm", fs->name)) panic("FID1 attach to root"); cons.curfs = fs; print("current fs is \"%s\"\n", cons.curfs->name); } static void cmd_prof(int argc, char *argv[]) { int n; long m, o; char *p; if(cons.profbuf == 0) { print("no buffer\n"); return; } n = !cons.profile; if(argc > 1) n = number(argv[1], n, 10); if(n && !cons.profile) { print("clr and start\n"); memset(cons.profbuf, 0, cons.nprofbuf*sizeof(cons.profbuf[0])); cons.profile = 1; return; } if(!n && cons.profile) { cons.profile = 0; print("stop and write\n"); if(walkto("/adm/kprofdata")) goto bad; if(con_open(FID2, OWRITE|OTRUNC)) { bad: print("cant open /adm/kprofdata\n"); return; } p = (char*)cons.profbuf; for(m=0; m<cons.nprofbuf; m++) { n = cons.profbuf[m]; p[0] = n>>24; p[1] = n>>16; p[2] = n>>8; p[3] = n>>0; p += 4; } m = cons.nprofbuf*sizeof(cons.profbuf[0]); o = 0; while(m > 0) { n = 8192; if(n > m) n = m; con_write(FID2, (char*)cons.profbuf+o, o, n); m -= n; o += n; } return; } } static void tzinit(char *file) { char buf[1024]; Off o; int f, n; f = create("/env/timezone", OEXCL|OWRITE, 0666); if(f < 0) return; if(walkto(file) || con_open(FID2, 0)) { print("tzinit: cannot access %s\n", file); close(f); remove("/env/timezone"); return; } for(o = 0; (n = con_read(FID2, buf, o, sizeof(buf))) > 0; o += n) write(f, buf, n); close(f); } static void cmd_time(int argc, char *argv[]) { int i, len; char *cmd; vlong t1, t2; t1 = nsec(); len = 0; for(i=1; i<argc; i++) len += 1 + strlen(argv[i]); cmd = malloc(len + 1); cmd[0] = 0; for(i=1; i<argc; i++) { strcat(cmd, " "); strcat(cmd, argv[i]); } cmd_exec(cmd); t2 = nsec(); free(cmd); print("time = %lld ns\n", t2-t1); } void cmd_noattach(int, char *[]) { noattach = !noattach; print("attach %s\n", noattach ? "disabled" : "enabled"); } void cmd_files(int, char *[]) { long i, n; Chan *cp; for(cp = chans; cp; cp = cp->next) cp->nfile = 0; lock(&flock); n = 0; for(i=0; i<conf.nfile; i++) if(files[i].cp) { n++; files[i].cp->nfile++; } print("%ld out of %ld files used\n", n, conf.nfile); unlock(&flock); n = 0; for(cp = chans; cp; cp = cp->next) if(cp->nfile) { print("%3d: %5d\n", cp->chan, cp->nfile); n += cp->nfile; } print("%ld out of %ld files used\n", n, conf.nfile); } void cmd_chatty(int argc, char *argv[]) { if(argc < 2) { print("cmd_chatty: usage: chatty n\n"); return; } chatty = atoi(argv[1]); } static void installcmds(void) { cmd_install("allow", "[uid] -- disable permission checking", cmd_allow); cmd_install("cfs", "[file] -- set current filesystem", cmd_cfs); cmd_install("chatty", "n -- set chattiness", cmd_chatty); cmd_install("clean", "file [bno [addr]] -- block print/fix", cmd_clean); cmd_install("check", "[options]", cmd_check); cmd_install("clri", "[file ...] -- purge files/dirs", cmd_clri); cmd_install("create", "path uid gid perm [lad] -- make a file/dir", cmd_create); cmd_install("disallow", "-- (re)enable permission checking", cmd_disallow); cmd_install("duallow", "uid -- duallow", cmd_duallow); cmd_install("flag", "-- print set flags", cmd_flag); cmd_install("fstat", "path -- print info on a file/dir", cmd_fstat); cmd_install("halt", "-- return to boot rom", cmd_halt); cmd_install("help", "", cmd_help); cmd_install("newuser", "username -- add user to /adm/users", cmd_newuser); cmd_install("profile", "[01] -- fs profile", cmd_prof); cmd_install("remove", "[file ...] -- remove files/dirs", cmd_remove); cmd_install("stata", "-- overall stats", cmd_stata); cmd_install("stats", "[[-]flags ...] -- various stats", cmd_stats); cmd_install("sync", "", cmd_sync); cmd_install("time", "command -- time another command", cmd_time); cmd_install("users", "[file] -- read /adm/users", cmd_users); cmd_install("version", "-- print time of mk and boot", cmd_version); cmd_install("who", "[user ...] -- print attaches", cmd_who); cmd_install("hangup", "chan -- clunk files", cmd_hangup); cmd_install("printconf", "-- print configuration", cmd_printconf); cmd_install("noattach", "-- toggle noattach flag", cmd_noattach); cmd_install("files", "-- report on files structure", cmd_files); chatflag = flag_install("chat", "-- verbose"); errorflag = flag_install("error", "-- on errors"); whoflag = flag_install("allchans", "-- on who"); authdebugflag = flag_install("authdebug", "-- report authentications"); authdisableflag = flag_install("authdisable", "-- disable authentication"); } int walkto(char *name) { char elem[NAMELEN], *p; int n; if(con_clone(FID1, FID2)) return 1; for(;;) { p = utfrune(name, '/'); if(p == nil) p = strchr(name, '\0'); if(p == name) { if(*name == '\0') return 0; name = p+1; continue; } n = p-name; if(n > NAMELEN) return 1; memset(elem, 0, sizeof(elem)); memmove(elem, name, n); if(con_walk(FID2, elem)) return 1; name = p; } } /* needs to parse and return vlongs to cope with new larger block numbers */ vlong number(char *arg, int def, int base) { int c, sign, any; vlong n; if(arg == nil) return def; sign = 0; any = 0; n = 0; for (c = *arg; isascii(c) && isspace(c) && c != '\n'; c = *arg) arg++; if(c == '-') { sign = 1; arg++; c = *arg; } while (isascii(c) && (isdigit(c) || base == 16 && isxdigit(c))) { 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'; arg++; c = *arg; any = 1; } if(!any) return def; if(sign) n = -n; return n; }