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 = 1; 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(cliExec(s) == 0){ 335 r = 0; 336 consPrint("%s: %R\n", s); 337 } 338 s = p+1; 339 } 340 } 341 vtMemFree(f); 342 } 343 344 if(r == 0) 345 vtSetError("errors in . %#q", argv[0]); 346 return r; 347 } 348 349 static int 350 cmdDflag(int argc, char* argv[]) 351 { 352 char *usage; 353 354 usage = "usage: dflag"; 355 356 ARGBEGIN{ 357 default: 358 return cliError(usage); 359 }ARGEND 360 if(argc) 361 return cliError(usage); 362 363 Dflag ^= 1; 364 consPrint("dflag %d\n", Dflag); 365 366 return 1; 367 } 368 369 static int 370 cmdEcho(int argc, char* argv[]) 371 { 372 char *usage; 373 int i, nflag; 374 375 nflag = 0; 376 usage = "usage: echo [-n] ..."; 377 378 ARGBEGIN{ 379 default: 380 return cliError(usage); 381 case 'n': 382 nflag = 1; 383 break; 384 }ARGEND 385 386 for(i = 0; i < argc; i++){ 387 if(i != 0) 388 consPrint(" %s", argv[i]); 389 else 390 consPrint(argv[i]); 391 } 392 if(!nflag) 393 consPrint("\n"); 394 395 return 1; 396 } 397 398 int 399 cmdInit(void) 400 { 401 cbox.lock = vtLockAlloc(); 402 cbox.confd[0] = cbox.confd[1] = -1; 403 404 cliAddCmd(".", cmdDot); 405 cliAddCmd("9p", cmd9p); 406 cliAddCmd("dflag", cmdDflag); 407 cliAddCmd("echo", cmdEcho); 408 409 if(pipe(cbox.confd) < 0) 410 return 0; 411 if((cbox.con = conAlloc(cbox.confd[1], "console")) == nil){ 412 close(cbox.confd[0]); 413 close(cbox.confd[1]); 414 cbox.confd[0] = cbox.confd[1] = -1; 415 return 0; 416 417 } 418 cbox.con->isconsole = 1; 419 420 return 1; 421 } 422