9p.c (9683B)
1 #include <u.h> 2 #include <signal.h> 3 #include <libc.h> 4 #include <bio.h> 5 #include <fcall.h> 6 #include <9pclient.h> 7 #include <auth.h> 8 #include <thread.h> 9 10 char *addr; 11 12 void 13 usage(void) 14 { 15 fprint(2, "usage: 9p [-n] [-a address] [-A aname] cmd args...\n"); 16 fprint(2, "possible cmds:\n"); 17 fprint(2, " read name\n"); 18 fprint(2, " readfd name\n"); 19 fprint(2, " write [-l] name\n"); 20 fprint(2, " writefd name\n"); 21 fprint(2, " stat name\n"); 22 fprint(2, " rdwr name\n"); 23 fprint(2, " ls [-ldn] name\n"); 24 fprint(2, "without -a, name elem/path means /path on server unix!$ns/elem\n"); 25 threadexitsall("usage"); 26 } 27 28 CFsys *(*nsmnt)(char*, char*) = nsamount; 29 CFsys *(*fsmnt)(int, char*) = fsamount; 30 31 char *aname; 32 void xread(int, char**); 33 void xwrite(int, char**); 34 void xreadfd(int, char**); 35 void xwritefd(int, char**); 36 void xstat(int, char**); 37 void xls(int, char**); 38 void xrdwr(int, char**); 39 void xrm(int, char**); 40 void xcreate(int, char**); 41 void xcon(int, char**); 42 43 struct { 44 char *s; 45 void (*f)(int, char**); 46 } cmds[] = { 47 "con", xcon, 48 "read", xread, 49 "write", xwrite, 50 "readfd", xreadfd, 51 "writefd", xwritefd, 52 "stat", xstat, 53 "rdwr", xrdwr, 54 "ls", xls, 55 "rm", xrm, 56 "create", xcreate, 57 }; 58 59 void 60 threadmain(int argc, char **argv) 61 { 62 char *cmd; 63 int i; 64 65 ARGBEGIN{ 66 case 'A': 67 aname = EARGF(usage()); 68 break; 69 case 'a': 70 addr = EARGF(usage()); 71 if(strchr(addr, '!') == nil) 72 addr = netmkaddr(addr, "tcp", "9fs"); 73 break; 74 case 'n': 75 nsmnt = nsmount; 76 fsmnt = fsmount; 77 break; 78 case 'D': 79 chatty9pclient = 1; 80 break; 81 default: 82 usage(); 83 }ARGEND 84 85 signal(SIGINT, SIG_DFL); 86 87 if(argc < 1) 88 usage(); 89 90 cmd = argv[0]; 91 for(i=0; i<nelem(cmds); i++){ 92 if(strcmp(cmds[i].s, cmd) == 0){ 93 cmds[i].f(argc, argv); 94 threadexitsall(0); 95 } 96 } 97 usage(); 98 } 99 100 CFsys* 101 xparse(char *name, char **path) 102 { 103 int fd; 104 char *p; 105 CFsys *fs; 106 107 if(addr == nil){ 108 p = strchr(name, '/'); 109 if(p == nil) 110 p = name+strlen(name); 111 else 112 *p++ = 0; 113 *path = p; 114 fs = nsmnt(name, aname); 115 if(fs == nil) 116 sysfatal("mount: %r"); 117 }else{ 118 *path = name; 119 if((fd = dial(addr, nil, nil, nil)) < 0) 120 sysfatal("dial: %r"); 121 if((fs = fsmnt(fd, aname)) == nil) 122 sysfatal("mount: %r"); 123 } 124 return fs; 125 } 126 127 CFid* 128 xopen(char *name, int mode) 129 { 130 CFid *fid; 131 CFsys *fs; 132 133 fs = xparse(name, &name); 134 fid = fsopen(fs, name, mode); 135 if(fid == nil) 136 sysfatal("fsopen %s: %r", name); 137 return fid; 138 } 139 140 int 141 xopenfd(char *name, int mode) 142 { 143 CFsys *fs; 144 145 fs = xparse(name, &name); 146 return fsopenfd(fs, name, mode); 147 } 148 149 void 150 xread(int argc, char **argv) 151 { 152 char buf[4096]; 153 int n; 154 CFid *fid; 155 156 ARGBEGIN{ 157 default: 158 usage(); 159 }ARGEND 160 161 if(argc != 1) 162 usage(); 163 164 fid = xopen(argv[0], OREAD); 165 while((n = fsread(fid, buf, sizeof buf)) > 0) 166 if(write(1, buf, n) < 0) 167 sysfatal("write error: %r"); 168 fsclose(fid); 169 if(n < 0) 170 sysfatal("read error: %r"); 171 threadexitsall(0); 172 } 173 174 void 175 xreadfd(int argc, char **argv) 176 { 177 char buf[4096]; 178 int n; 179 int fd; 180 181 ARGBEGIN{ 182 default: 183 usage(); 184 }ARGEND 185 186 if(argc != 1) 187 usage(); 188 189 fd = xopenfd(argv[0], OREAD); 190 while((n = read(fd, buf, sizeof buf)) > 0) 191 if(write(1, buf, n) < 0) 192 sysfatal("write error: %r"); 193 if(n < 0) 194 sysfatal("read error: %r"); 195 threadexitsall(0); 196 } 197 198 void 199 xwrite(int argc, char **argv) 200 { 201 char buf[4096]; 202 int n, did; 203 CFid *fid; 204 Biobuf *b; 205 char *p; 206 int byline; 207 208 byline = 0; 209 ARGBEGIN{ 210 case 'l': 211 byline = 1; 212 break; 213 default: 214 usage(); 215 }ARGEND 216 217 if(argc != 1) 218 usage(); 219 220 did = 0; 221 fid = xopen(argv[0], OWRITE|OTRUNC); 222 if(byline){ 223 n = 0; 224 b = malloc(sizeof *b); 225 if(b == nil) 226 sysfatal("out of memory"); 227 Binit(b, 0, OREAD); 228 while((p = Brdstr(b, '\n', 0)) != nil){ 229 n = strlen(p); 230 did = 1; 231 if(fswrite(fid, p, n) != n) 232 fprint(2, "write: %r\n"); 233 } 234 free(b); 235 }else{ 236 while((n = read(0, buf, sizeof buf)) > 0){ 237 did = 1; 238 if(fswrite(fid, buf, n) != n) 239 sysfatal("write error: %r"); 240 } 241 } 242 if(n == 0 && !did){ 243 if(fswrite(fid, buf, 0) != 0) 244 sysfatal("write error: %r"); 245 } 246 if(n < 0) 247 sysfatal("read error: %r"); 248 fsclose(fid); 249 threadexitsall(0); 250 } 251 252 void 253 xwritefd(int argc, char **argv) 254 { 255 char buf[4096]; 256 int n; 257 int fd; 258 259 ARGBEGIN{ 260 default: 261 usage(); 262 }ARGEND 263 264 if(argc != 1) 265 usage(); 266 267 fd = xopenfd(argv[0], OWRITE|OTRUNC); 268 while((n = read(0, buf, sizeof buf)) > 0) 269 if(write(fd, buf, n) != n) 270 sysfatal("write error: %r"); 271 if(n < 0) 272 sysfatal("read error: %r"); 273 threadexitsall(0); 274 } 275 276 void 277 xstat(int argc, char **argv) 278 { 279 Dir *d; 280 CFsys *fs; 281 char *name; 282 283 ARGBEGIN{ 284 default: 285 usage(); 286 }ARGEND 287 288 if(argc != 1) 289 usage(); 290 291 name = argv[0]; 292 fs = xparse(name, &name); 293 if((d = fsdirstat(fs, name)) == 0) 294 sysfatal("dirstat: %r"); 295 fmtinstall('D', dirfmt); 296 fmtinstall('M', dirmodefmt); 297 print("%D\n", d); 298 threadexitsall(0); 299 } 300 301 void 302 xrdwr(int argc, char **argv) 303 { 304 char buf[4096]; 305 char *p; 306 int n; 307 CFid *fid; 308 Biobuf *b; 309 310 ARGBEGIN{ 311 default: 312 usage(); 313 }ARGEND 314 315 if(argc != 1) 316 usage(); 317 318 if((b = Bfdopen(0, OREAD)) == nil) 319 sysfatal("out of memory"); 320 fid = xopen(argv[0], ORDWR); 321 for(;;){ 322 fsseek(fid, 0, 0); 323 if((n = fsread(fid, buf, sizeof buf)) < 0) 324 fprint(2, "read: %r\n"); 325 else{ 326 if(write(1, buf, n) < 0 || write(1, "\n", 1) < 0) 327 sysfatal("write error: %r"); 328 } 329 if((p = Brdstr(b, '\n', 1)) == nil) 330 break; 331 n = strlen(p); 332 if(fswrite(fid, p, n) != n) 333 fprint(2, "write: %r\n"); 334 free(p); 335 } 336 fsclose(fid); 337 Bterm(b); 338 threadexitsall(0); 339 } 340 341 void 342 xcreate(int argc, char **argv) 343 { 344 int i; 345 CFsys *fs; 346 CFid *fid; 347 char *p; 348 349 ARGBEGIN{ 350 default: 351 usage(); 352 }ARGEND 353 354 if(argc == 0) 355 usage(); 356 357 for(i=0; i<argc; i++){ 358 fs = xparse(argv[i], &p); 359 if((fid=fscreate(fs, p, OREAD, 0666)) == nil) 360 fprint(2, "create %s: %r\n", argv[i]); 361 else 362 fsclose(fid); 363 fsunmount(fs); 364 } 365 } 366 367 void 368 xrm(int argc, char **argv) 369 { 370 int i; 371 CFsys *fs; 372 char *p; 373 374 ARGBEGIN{ 375 default: 376 usage(); 377 }ARGEND 378 379 if(argc == 0) 380 usage(); 381 382 for(i=0; i<argc; i++){ 383 fs = xparse(argv[i], &p); 384 if(fsremove(fs, p) < 0) 385 fprint(2, "remove %s: %r\n", argv[i]); 386 fsunmount(fs); 387 } 388 } 389 390 void 391 rdcon(void *v) 392 { 393 int n; 394 char buf[4096]; 395 CFid *fid; 396 397 fid = v; 398 for(;;){ 399 n = read(0, buf, sizeof buf); 400 if(n <= 0) 401 threadexitsall(0); 402 if(buf[0] == 'R'-'A'+1) 403 threadexitsall(0); 404 if(fswrite(fid, buf, n) != n) 405 fprint(2, "write: %r\n"); 406 } 407 } 408 409 void 410 xcon(int argc, char **argv) 411 { 412 char buf[4096], *r, *w, *e; 413 int n, nocr; 414 CFid *fid; 415 416 nocr = 1; 417 418 ARGBEGIN{ 419 case 'r': 420 nocr = 0; 421 break; 422 default: 423 usage(); 424 }ARGEND 425 426 if(argc != 1) 427 usage(); 428 429 fid = xopen(argv[0], ORDWR); 430 proccreate(rdcon, fid, 32768); 431 for(;;){ 432 n = fsread(fid, buf, sizeof buf); 433 if(n <= 0) 434 threadexitsall(0); 435 if(nocr){ 436 for(r=w=buf, e=buf+n; r<e; r++) 437 if(*r != '\r') 438 *w++ = *r; 439 n = w-buf; 440 } 441 if(write(1, buf, n) != n) 442 threadexitsall(0); 443 } 444 fsclose(fid); 445 threadexitsall(0); 446 } 447 448 static char *mon[] = 449 { 450 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 451 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 452 }; 453 454 455 int 456 timefmt(Fmt *fmt) 457 { 458 ulong u; 459 static ulong time0; 460 Tm *tm; 461 462 if(time0 == 0) 463 time0 = time(0); 464 u = va_arg(fmt->args, ulong); 465 tm = localtime(u); 466 if((long)(time0-u) < 6*30*86400) 467 return fmtprint(fmt, "%s %2d %02d:%02d", 468 mon[tm->mon], tm->mday, tm->hour, tm->min); 469 return fmtprint(fmt, "%s %2d %5d", 470 mon[tm->mon], tm->mday, tm->year+1900); 471 } 472 473 static int 474 dircmp(const void *va, const void *vb) 475 { 476 Dir *a, *b; 477 478 a = (Dir*)va; 479 b = (Dir*)vb; 480 return strcmp(a->name, b->name); 481 } 482 483 static int 484 timecmp(const void *va, const void *vb) 485 { 486 Dir *a, *b; 487 488 a = (Dir*)va; 489 b = (Dir*)vb; 490 if(a->mtime < b->mtime) 491 return -1; 492 else if(a->mtime > b->mtime) 493 return 1; 494 else 495 return 0; 496 } 497 498 char *dot[] = { "." }; 499 500 void 501 xls(int argc, char **argv) 502 { 503 char *err, *name, *xname, *f[4], buf[4096]; 504 int i, j, l, sort; 505 int lflag, dflag, tflag, n, len[4]; 506 Dir *d; 507 CFid *fid; 508 CFsys *fs; 509 510 err = nil; 511 sort = 1; 512 lflag = dflag = tflag = 0; 513 ARGBEGIN{ 514 case 'n': 515 sort = 0; 516 break; 517 case 'l': 518 lflag = 1; 519 break; 520 case 'd': 521 dflag = 1; 522 break; 523 case 't': 524 tflag = 1; 525 break; 526 }ARGEND 527 528 fmtinstall('D', dirfmt); 529 fmtinstall('M', dirmodefmt); 530 quotefmtinstall(); 531 fmtinstall('T', timefmt); 532 533 if(argc == 0){ 534 argv = dot; 535 argc = 1; 536 } 537 for(i=0; i<argc; i++){ 538 name = argv[i]; 539 fs = xparse(name, &xname); 540 if((d = fsdirstat(fs, xname)) == nil){ 541 fprint(2, "dirstat %s: %r\n", name); 542 fsunmount(fs); 543 err = "errors"; 544 continue; 545 } 546 if((d->mode&DMDIR) && !dflag){ 547 if((fid = fsopen(fs, xname, OREAD)) == nil){ 548 fprint(2, "open %s: %r\n", name); 549 fsunmount(fs); 550 free(d); 551 err = "errors"; 552 continue; 553 } 554 free(d); 555 n = fsdirreadall(fid, &d); 556 fsclose(fid); 557 if(n < 0){ 558 fprint(2, "dirreadall %s: %r\n", name); 559 fsunmount(fs); 560 err = "errors"; 561 continue; 562 } 563 if(sort){ 564 if(tflag) 565 qsort(d, n, sizeof d[0], timecmp); 566 else 567 qsort(d, n, sizeof d[0], dircmp); 568 } 569 for(j=0; j<4; j++) 570 len[j] = 0; 571 for(i=0; i<n; i++){ 572 d[i].type = 'M'; 573 d[i].dev = 0; 574 snprint(buf, sizeof buf, "%d %s %s %lld", 575 d[i].dev, d[i].uid, d[i].gid, d[i].length); 576 getfields(buf, f, 4, 0, " "); 577 for(j=0; j<4; j++){ 578 l = strlen(f[j]); 579 if(l > len[j]) 580 len[j] = l; 581 } 582 } 583 for(i=0; i<n; i++){ 584 if(!lflag){ 585 print("%q\n", d[i].name); 586 continue; 587 } 588 print("%M %C %*d %*s %*s %*lld %T %q\n", 589 d[i].mode, d[i].type, len[0], d[i].dev, 590 -len[1], d[i].uid, -len[2], d[i].gid, 591 len[3], d[i].length, d[i].mtime, d[i].name); 592 } 593 }else{ 594 d->type = 'M'; 595 d->dev = 0; 596 if(lflag) 597 print("%M %C %d %s %s %lld %T %q\n", 598 d->mode, d->type, d->dev, 599 d->uid, d->gid, d->length, d->mtime, d->name); 600 else 601 print("%q\n", d->name); 602 } 603 free(d); 604 } 605 threadexitsall(err); 606 }