1 #include "stdinc.h" 2 3 #include "9.h" 4 5 static struct { 6 VtLock* lock; 7 8 Con* con; 9 int confd[2]; 10 ushort tag; 11 } cbox; 12 13 static ulong 14 cmd9pStrtoul(char* s) 15 { 16 if(strcmp(s, "~0") == 0) 17 return ~0UL; 18 return strtoul(s, 0, 0); 19 } 20 21 static uvlong 22 cmd9pStrtoull(char* s) 23 { 24 if(strcmp(s, "~0") == 0) 25 return ~0ULL; 26 return strtoull(s, 0, 0); 27 } 28 29 static int 30 cmd9pTag(Fcall*, int, char **argv) 31 { 32 cbox.tag = strtoul(argv[0], 0, 0)-1; 33 34 return 1; 35 } 36 37 static int 38 cmd9pTwstat(Fcall* f, int, char **argv) 39 { 40 Dir d; 41 static uchar buf[DIRMAX]; 42 43 memset(&d, 0, sizeof d); 44 nulldir(&d); 45 d.name = argv[1]; 46 d.uid = argv[2]; 47 d.gid = argv[3]; 48 d.mode = cmd9pStrtoul(argv[4]); 49 d.mtime = cmd9pStrtoul(argv[5]); 50 d.length = cmd9pStrtoull(argv[6]); 51 52 f->fid = strtol(argv[0], 0, 0); 53 f->stat = buf; 54 f->nstat = convD2M(&d, buf, sizeof buf); 55 if(f->nstat < BIT16SZ){ 56 vtSetError("Twstat: convD2M failed (internal error)"); 57 return 0; 58 } 59 60 return 1; 61 } 62 63 static int 64 cmd9pTstat(Fcall* f, int, char** argv) 65 { 66 f->fid = strtol(argv[0], 0, 0); 67 68 return 1; 69 } 70 71 static int 72 cmd9pTremove(Fcall* f, int, char** argv) 73 { 74 f->fid = strtol(argv[0], 0, 0); 75 76 return 1; 77 } 78 79 static int 80 cmd9pTclunk(Fcall* f, int, char** argv) 81 { 82 f->fid = strtol(argv[0], 0, 0); 83 84 return 1; 85 } 86 87 static int 88 cmd9pTwrite(Fcall* f, int, char** argv) 89 { 90 f->fid = strtol(argv[0], 0, 0); 91 f->offset = strtoll(argv[1], 0, 0); 92 f->data = argv[2]; 93 f->count = strlen(argv[2]); 94 95 return 1; 96 } 97 98 static int 99 cmd9pTread(Fcall* f, int, char** argv) 100 { 101 f->fid = strtol(argv[0], 0, 0); 102 f->offset = strtoll(argv[1], 0, 0); 103 f->count = strtol(argv[2], 0, 0); 104 105 return 1; 106 } 107 108 static int 109 cmd9pTcreate(Fcall* f, int, char** argv) 110 { 111 f->fid = strtol(argv[0], 0, 0); 112 f->name = argv[1]; 113 f->perm = strtol(argv[2], 0, 8); 114 f->mode = strtol(argv[3], 0, 0); 115 116 return 1; 117 } 118 119 static int 120 cmd9pTopen(Fcall* f, int, char** argv) 121 { 122 f->fid = strtol(argv[0], 0, 0); 123 f->mode = strtol(argv[1], 0, 0); 124 125 return 1; 126 } 127 128 static int 129 cmd9pTwalk(Fcall* f, int argc, char** argv) 130 { 131 int i; 132 133 if(argc < 2){ 134 vtSetError("usage: Twalk tag fid newfid [name...]"); 135 return 0; 136 } 137 f->fid = strtol(argv[0], 0, 0); 138 f->newfid = strtol(argv[1], 0, 0); 139 f->nwname = argc-2; 140 if(f->nwname > MAXWELEM){ 141 vtSetError("Twalk: too many names"); 142 return 0; 143 } 144 for(i = 0; i < argc-2; i++) 145 f->wname[i] = argv[2+i]; 146 147 return 1; 148 } 149 150 static int 151 cmd9pTflush(Fcall* f, int, char** argv) 152 { 153 f->oldtag = strtol(argv[0], 0, 0); 154 155 return 1; 156 } 157 158 static int 159 cmd9pTattach(Fcall* f, int, char** argv) 160 { 161 f->fid = strtol(argv[0], 0, 0); 162 f->afid = strtol(argv[1], 0, 0); 163 f->uname = argv[2]; 164 f->aname = argv[3]; 165 166 return 1; 167 } 168 169 static int 170 cmd9pTauth(Fcall* f, int, char** argv) 171 { 172 f->afid = strtol(argv[0], 0, 0); 173 f->uname = argv[1]; 174 f->aname = argv[2]; 175 176 return 1; 177 } 178 179 static int 180 cmd9pTversion(Fcall* f, int, char** argv) 181 { 182 f->msize = strtoul(argv[0], 0, 0); 183 if(f->msize > cbox.con->msize){ 184 vtSetError("msize too big"); 185 return 0; 186 } 187 f->version = argv[1]; 188 189 return 1; 190 } 191 192 typedef struct Cmd9p Cmd9p; 193 struct Cmd9p { 194 char* name; 195 int type; 196 int argc; 197 char* usage; 198 int (*f)(Fcall*, int, char**); 199 }; 200 201 static Cmd9p cmd9pTmsg[] = { 202 "Tversion", Tversion, 2, "msize version", cmd9pTversion, 203 "Tauth", Tauth, 3, "afid uname aname", cmd9pTauth, 204 "Tflush", Tflush, 1, "oldtag", cmd9pTflush, 205 "Tattach", Tattach, 4, "fid afid uname aname", cmd9pTattach, 206 "Twalk", Twalk, 0, "fid newfid [name...]", cmd9pTwalk, 207 "Topen", Topen, 2, "fid mode", cmd9pTopen, 208 "Tcreate", Tcreate, 4, "fid name perm mode", cmd9pTcreate, 209 "Tread", Tread, 3, "fid offset count", cmd9pTread, 210 "Twrite", Twrite, 3, "fid offset data", cmd9pTwrite, 211 "Tclunk", Tclunk, 1, "fid", cmd9pTclunk, 212 "Tremove", Tremove, 1, "fid", cmd9pTremove, 213 "Tstat", Tstat, 1, "fid", cmd9pTstat, 214 "Twstat", Twstat, 7, "fid name uid gid mode mtime length", cmd9pTwstat, 215 "nexttag", 0, 0, "", cmd9pTag, 216 }; 217 218 static int 219 cmd9p(int argc, char* argv[]) 220 { 221 int i, n; 222 Fcall f, t; 223 uchar *buf; 224 char *usage; 225 u32int msize; 226 227 usage = "usage: 9p T-message ..."; 228 229 ARGBEGIN{ 230 default: 231 return cliError(usage); 232 }ARGEND 233 if(argc < 1) 234 return cliError(usage); 235 236 for(i = 0; i < nelem(cmd9pTmsg); i++){ 237 if(strcmp(cmd9pTmsg[i].name, argv[0]) == 0) 238 break; 239 } 240 if(i == nelem(cmd9pTmsg)) 241 return cliError(usage); 242 argc--; 243 argv++; 244 if(cmd9pTmsg[i].argc && argc != cmd9pTmsg[i].argc){ 245 vtSetError("usage: %s %s", 246 cmd9pTmsg[i].name, cmd9pTmsg[i].usage); 247 return 0; 248 } 249 250 memset(&t, 0, sizeof(t)); 251 t.type = cmd9pTmsg[i].type; 252 if(t.type == Tversion) 253 t.tag = NOTAG; 254 else 255 t.tag = ++cbox.tag; 256 msize = cbox.con->msize; 257 if(!cmd9pTmsg[i].f(&t, argc, argv)) 258 return 0; 259 buf = vtMemAlloc(msize); 260 n = convS2M(&t, buf, msize); 261 if(n <= BIT16SZ){ 262 vtSetError("%s: convS2M error", cmd9pTmsg[i].name); 263 vtMemFree(buf); 264 return 0; 265 } 266 if(write(cbox.confd[0], buf, n) != n){ 267 vtSetError("%s: write error: %r", cmd9pTmsg[i].name); 268 vtMemFree(buf); 269 return 0; 270 } 271 consPrint("\t-> %F\n", &t); 272 273 if((n = read9pmsg(cbox.confd[0], buf, msize)) <= 0){ 274 vtSetError("%s: read error: %r", cmd9pTmsg[i].name); 275 vtMemFree(buf); 276 return 0; 277 } 278 if(convM2S(buf, n, &f) == 0){ 279 vtSetError("%s: convM2S error", cmd9pTmsg[i].name); 280 vtMemFree(buf); 281 return 0; 282 } 283 consPrint("\t<- %F\n", &f); 284 285 vtMemFree(buf); 286 return 1; 287 } 288 289 static int 290 cmdDot(int argc, char* argv[]) 291 { 292 long l; 293 Dir *dir; 294 int fd, r; 295 vlong length; 296 char *f, *p, *s, *usage; 297 298 usage = "usage: . file"; 299 300 ARGBEGIN{ 301 default: 302 return cliError(usage); 303 }ARGEND 304 if(argc != 1) 305 return cliError(usage); 306 307 if((dir = dirstat(argv[0])) == nil) 308 return cliError(". dirstat %s: %r", argv[0]); 309 length = dir->length; 310 free(dir); 311 312 r = 0; 313 if(length != 0){ 314 /* 315 * Read the whole file in. 316 */ 317 if((fd = open(argv[0], OREAD)) < 0) 318 return cliError(". open %s: %r", argv[0]); 319 f = vtMemAlloc(dir->length+1); 320 if((l = read(fd, f, length)) < 0){ 321 vtMemFree(f); 322 close(fd); 323 return cliError(". read %s: %r", argv[0]); 324 } 325 close(fd); 326 f[l] = '\0'; 327 328 /* 329 * Call cliExec() for each line. 330 */ 331 for(p = s = f; *p != '\0'; p++){ 332 if(*p == '\n'){ 333 *p = '\0'; 334 if((r = cliExec(s)) == 0) 335 break; 336 s = p+1; 337 } 338 } 339 vtMemFree(f); 340 } 341 342 return r; 343 } 344 345 static int 346 cmdDflag(int argc, char* argv[]) 347 { 348 char *usage; 349 350 usage = "usage: dflag"; 351 352 ARGBEGIN{ 353 default: 354 return cliError(usage); 355 }ARGEND 356 if(argc) 357 return cliError(usage); 358 359 Dflag ^= 1; 360 consPrint("dflag %d\n", Dflag); 361 362 return 1; 363 } 364 365 static int 366 cmdEcho(int argc, char* argv[]) 367 { 368 char *usage; 369 int i, nflag; 370 371 nflag = 0; 372 usage = "usage: echo [-n] ..."; 373 374 ARGBEGIN{ 375 default: 376 return cliError(usage); 377 case 'n': 378 nflag = 1; 379 break; 380 }ARGEND 381 382 for(i = 0; i < argc; i++){ 383 if(i != 0) 384 consPrint(" %s", argv[i]); 385 else 386 consPrint(argv[i]); 387 } 388 if(!nflag) 389 consPrint("\n"); 390 391 return 1; 392 } 393 394 int 395 cmdInit(void) 396 { 397 cbox.lock = vtLockAlloc(); 398 cbox.confd[0] = cbox.confd[1] = -1; 399 400 cliAddCmd(".", cmdDot); 401 cliAddCmd("9p", cmd9p); 402 cliAddCmd("dflag", cmdDflag); 403 cliAddCmd("echo", cmdEcho); 404 405 if(pipe(cbox.confd) < 0) 406 return 0; 407 if((cbox.con = conAlloc(cbox.confd[1], "console")) == nil){ 408 close(cbox.confd[0]); 409 close(cbox.confd[1]); 410 cbox.confd[0] = cbox.confd[1] = -1; 411 return 0; 412 413 } 414 cbox.con->isconsole = 1; 415 416 return 1; 417 } 418