blob: 3dde81c4dcb56a6850d08401c8bf2464007531da [file] [log] [blame]
#include "stdinc.h"
#include "9.h"
static struct {
QLock lock;
Con* con;
int confd[2];
ushort tag;
} cbox;
static ulong
cmd9pStrtoul(char* s)
{
if(strcmp(s, "~0") == 0)
return ~0UL;
return strtoul(s, 0, 0);
}
static uvlong
cmd9pStrtoull(char* s)
{
if(strcmp(s, "~0") == 0)
return ~0ULL;
return strtoull(s, 0, 0);
}
static int
cmd9pTag(Fcall* f, int i, char **argv)
{
USED(f);
USED(i);
cbox.tag = strtoul(argv[0], 0, 0)-1;
return 1;
}
static int
cmd9pTwstat(Fcall* f, int i, char **argv)
{
Dir d;
static uchar buf[DIRMAX];
USED(i);
memset(&d, 0, sizeof d);
nulldir(&d);
d.name = argv[1];
d.uid = argv[2];
d.gid = argv[3];
d.mode = cmd9pStrtoul(argv[4]);
d.mtime = cmd9pStrtoul(argv[5]);
d.length = cmd9pStrtoull(argv[6]);
f->fid = strtol(argv[0], 0, 0);
f->stat = buf;
f->nstat = convD2M(&d, buf, sizeof buf);
if(f->nstat < BIT16SZ){
werrstr("Twstat: convD2M failed (internal error)");
return 0;
}
return 1;
}
static int
cmd9pTstat(Fcall* f, int i, char** argv)
{
USED(i);
f->fid = strtol(argv[0], 0, 0);
return 1;
}
static int
cmd9pTremove(Fcall* f, int i, char** argv)
{
USED(i);
f->fid = strtol(argv[0], 0, 0);
return 1;
}
static int
cmd9pTclunk(Fcall* f, int i, char** argv)
{
USED(i);
f->fid = strtol(argv[0], 0, 0);
return 1;
}
static int
cmd9pTwrite(Fcall* f, int i, char** argv)
{
USED(i);
f->fid = strtol(argv[0], 0, 0);
f->offset = strtoll(argv[1], 0, 0);
f->data = argv[2];
f->count = strlen(argv[2]);
return 1;
}
static int
cmd9pTread(Fcall* f, int i, char** argv)
{
USED(i);
f->fid = strtol(argv[0], 0, 0);
f->offset = strtoll(argv[1], 0, 0);
f->count = strtol(argv[2], 0, 0);
return 1;
}
static int
cmd9pTcreate(Fcall* f, int i, char** argv)
{
USED(i);
f->fid = strtol(argv[0], 0, 0);
f->name = argv[1];
f->perm = strtol(argv[2], 0, 8);
f->mode = strtol(argv[3], 0, 0);
return 1;
}
static int
cmd9pTopen(Fcall* f, int i, char** argv)
{
USED(i);
f->fid = strtol(argv[0], 0, 0);
f->mode = strtol(argv[1], 0, 0);
return 1;
}
static int
cmd9pTwalk(Fcall* f, int argc, char** argv)
{
int i;
if(argc < 2){
werrstr("usage: Twalk tag fid newfid [name...]");
return 0;
}
f->fid = strtol(argv[0], 0, 0);
f->newfid = strtol(argv[1], 0, 0);
f->nwname = argc-2;
if(f->nwname > MAXWELEM){
werrstr("Twalk: too many names");
return 0;
}
for(i = 0; i < argc-2; i++)
f->wname[i] = argv[2+i];
return 1;
}
static int
cmd9pTflush(Fcall* f, int i, char** argv)
{
USED(i);
f->oldtag = strtol(argv[0], 0, 0);
return 1;
}
static int
cmd9pTattach(Fcall* f, int i, char** argv)
{
USED(i);
f->fid = strtol(argv[0], 0, 0);
f->afid = strtol(argv[1], 0, 0);
f->uname = argv[2];
f->aname = argv[3];
return 1;
}
static int
cmd9pTauth(Fcall* f, int i, char** argv)
{
USED(i);
f->afid = strtol(argv[0], 0, 0);
f->uname = argv[1];
f->aname = argv[2];
return 1;
}
static int
cmd9pTversion(Fcall* f, int i, char** argv)
{
USED(i);
f->msize = strtoul(argv[0], 0, 0);
if(f->msize > cbox.con->msize){
werrstr("msize too big");
return 0;
}
f->version = argv[1];
return 1;
}
typedef struct Cmd9p Cmd9p;
struct Cmd9p {
char* name;
int type;
int argc;
char* usage;
int (*f)(Fcall*, int, char**);
};
static Cmd9p cmd9pTmsg[] = {
"Tversion", Tversion, 2, "msize version", cmd9pTversion,
"Tauth", Tauth, 3, "afid uname aname", cmd9pTauth,
"Tflush", Tflush, 1, "oldtag", cmd9pTflush,
"Tattach", Tattach, 4, "fid afid uname aname", cmd9pTattach,
"Twalk", Twalk, 0, "fid newfid [name...]", cmd9pTwalk,
"Topen", Topen, 2, "fid mode", cmd9pTopen,
"Tcreate", Tcreate, 4, "fid name perm mode", cmd9pTcreate,
"Tread", Tread, 3, "fid offset count", cmd9pTread,
"Twrite", Twrite, 3, "fid offset data", cmd9pTwrite,
"Tclunk", Tclunk, 1, "fid", cmd9pTclunk,
"Tremove", Tremove, 1, "fid", cmd9pTremove,
"Tstat", Tstat, 1, "fid", cmd9pTstat,
"Twstat", Twstat, 7, "fid name uid gid mode mtime length", cmd9pTwstat,
"nexttag", 0, 0, "", cmd9pTag,
};
static int
cmd9p(int argc, char* argv[])
{
int i, n;
Fcall f, t;
uchar *buf;
char *usage;
u32int msize;
usage = "usage: 9p T-message ...";
ARGBEGIN{
default:
return cliError(usage);
}ARGEND
if(argc < 1)
return cliError(usage);
for(i = 0; i < nelem(cmd9pTmsg); i++){
if(strcmp(cmd9pTmsg[i].name, argv[0]) == 0)
break;
}
if(i == nelem(cmd9pTmsg))
return cliError(usage);
argc--;
argv++;
if(cmd9pTmsg[i].argc && argc != cmd9pTmsg[i].argc){
werrstr("usage: %s %s",
cmd9pTmsg[i].name, cmd9pTmsg[i].usage);
return 0;
}
memset(&t, 0, sizeof(t));
t.type = cmd9pTmsg[i].type;
if(t.type == Tversion)
t.tag = NOTAG;
else
t.tag = ++cbox.tag;
msize = cbox.con->msize;
if(!cmd9pTmsg[i].f(&t, argc, argv))
return 0;
buf = vtmalloc(msize);
n = convS2M(&t, buf, msize);
if(n <= BIT16SZ){
werrstr("%s: convS2M error", cmd9pTmsg[i].name);
vtfree(buf);
return 0;
}
if(write(cbox.confd[0], buf, n) != n){
werrstr("%s: write error: %r", cmd9pTmsg[i].name);
vtfree(buf);
return 0;
}
consPrint("\t-> %F\n", &t);
if((n = read9pmsg(cbox.confd[0], buf, msize)) <= 0){
werrstr("%s: read error: %r", cmd9pTmsg[i].name);
vtfree(buf);
return 0;
}
if(convM2S(buf, n, &f) == 0){
werrstr("%s: convM2S error", cmd9pTmsg[i].name);
vtfree(buf);
return 0;
}
consPrint("\t<- %F\n", &f);
vtfree(buf);
return 1;
}
static int
cmdDot(int argc, char* argv[])
{
long l;
Dir *dir;
int fd, r;
vlong length;
char *f, *p, *s, *usage;
usage = "usage: . file";
ARGBEGIN{
default:
return cliError(usage);
}ARGEND
if(argc != 1)
return cliError(usage);
if((dir = dirstat(argv[0])) == nil)
return cliError(". dirstat %s: %r", argv[0]);
length = dir->length;
free(dir);
r = 1;
if(length != 0){
/*
* Read the whole file in.
*/
if((fd = open(argv[0], OREAD)) < 0)
return cliError(". open %s: %r", argv[0]);
f = vtmalloc(dir->length+1);
if((l = read(fd, f, length)) < 0){
vtfree(f);
close(fd);
return cliError(". read %s: %r", argv[0]);
}
close(fd);
f[l] = '\0';
/*
* Call cliExec() for each line.
*/
for(p = s = f; *p != '\0'; p++){
if(*p == '\n'){
*p = '\0';
if(cliExec(s) == 0){
r = 0;
consPrint("%s: %r\n", s);
}
s = p+1;
}
}
vtfree(f);
}
if(r == 0)
werrstr("errors in . %#q", argv[0]);
return r;
}
static int
cmdDflag(int argc, char* argv[])
{
char *usage;
usage = "usage: dflag";
ARGBEGIN{
default:
return cliError(usage);
}ARGEND
if(argc)
return cliError(usage);
Dflag ^= 1;
consPrint("dflag %d\n", Dflag);
return 1;
}
static int
cmdEcho(int argc, char* argv[])
{
char *usage;
int i, nflag;
nflag = 0;
usage = "usage: echo [-n] ...";
ARGBEGIN{
default:
return cliError(usage);
case 'n':
nflag = 1;
break;
}ARGEND
for(i = 0; i < argc; i++){
if(i != 0)
consPrint(" %s", argv[i]);
else
consPrint(argv[i]);
}
if(!nflag)
consPrint("\n");
return 1;
}
static int
cmdBind(int argc, char* argv[])
{
ulong flag = 0;
char *usage;
usage = "usage: bind [-b|-a|-c|-bc|-ac] new old";
ARGBEGIN{
case 'a':
flag |= MAFTER;
break;
case 'b':
flag |= MBEFORE;
break;
case 'c':
flag |= MCREATE;
break;
default:
return cliError(usage);
}ARGEND
if(argc != 2 || (flag&MAFTER)&&(flag&MBEFORE))
return cliError(usage);
#ifndef PLAN9PORT
if(bind(argv[0], argv[1], flag) < 0){
/* try to give a less confusing error than the default */
if(access(argv[0], 0) < 0)
return cliError("bind: %s: %r", argv[0]);
else if(access(argv[1], 0) < 0)
return cliError("bind: %s: %r", argv[1]);
else
return cliError("bind %s %s: %r", argv[0], argv[1]);
}
#endif
return 1;
}
int
cmdInit(void)
{
cbox.confd[0] = cbox.confd[1] = -1;
cliAddCmd(".", cmdDot);
cliAddCmd("9p", cmd9p);
cliAddCmd("dflag", cmdDflag);
cliAddCmd("echo", cmdEcho);
cliAddCmd("bind", cmdBind);
if(pipe(cbox.confd) < 0)
return 0;
if((cbox.con = conAlloc(cbox.confd[1], "console", 0)) == nil){
close(cbox.confd[0]);
close(cbox.confd[1]);
cbox.confd[0] = cbox.confd[1] = -1;
return 0;
}
cbox.con->isconsole = 1;
return 1;
}