1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "../port/error.h" 7 8 /* 9 * The sys*() routines needn't poperror() as they return directly to syscall(). 10 */ 11 12 int 13 newfd(Chan *c) 14 { 15 Fgrp *f = u->p->fgrp; 16 int i; 17 18 lock(f); 19 for(i=0; i<NFD; i++) 20 if(f->fd[i] == 0){ 21 if(i > f->maxfd) 22 f->maxfd = i; 23 f->fd[i] = c; 24 unlock(f); 25 return i; 26 } 27 unlock(f); 28 exhausted("file descriptors"); 29 return 0; 30 } 31 32 Chan* 33 fdtochan(int fd, int mode, int chkmnt, int iref) 34 { 35 Chan *c; 36 Fgrp *f; 37 38 c = 0; 39 f = u->p->fgrp; 40 41 lock(f); 42 if(fd<0 || NFD<=fd || (c = f->fd[fd])==0) { 43 unlock(f); 44 error(Ebadfd); 45 } 46 if(iref) 47 incref(c); 48 unlock(f); 49 50 if(chkmnt && (c->flag&CMSG)) { 51 if(iref) 52 close(c); 53 error(Ebadusefd); 54 } 55 56 if(mode<0 || c->mode==ORDWR) 57 return c; 58 59 if((mode&OTRUNC) && c->mode==OREAD) { 60 if(iref) 61 close(c); 62 error(Ebadusefd); 63 } 64 65 if((mode&~OTRUNC) != c->mode) { 66 if(iref) 67 close(c); 68 error(Ebadusefd); 69 } 70 71 return c; 72 } 73 74 int 75 openmode(ulong o) 76 { 77 if(o >= (OTRUNC|OCEXEC|ORCLOSE|OEXEC)) 78 error(Ebadarg); 79 o &= ~(OTRUNC|OCEXEC|ORCLOSE); 80 if(o > OEXEC) 81 error(Ebadarg); 82 if(o == OEXEC) 83 return OREAD; 84 return o; 85 } 86 87 long 88 syspipe(ulong *arg) 89 { 90 int fd[2]; 91 Chan *c[2]; 92 Dev *d; 93 Fgrp *f = u->p->fgrp; 94 95 validaddr(arg[0], 2*BY2WD, 1); 96 evenaddr(arg[0]); 97 d = &devtab[devno('|', 0)]; 98 c[0] = (*d->attach)(0); 99 c[1] = 0; 100 fd[0] = -1; 101 fd[1] = -1; 102 if(waserror()){ 103 close(c[0]); 104 if(c[1]) 105 close(c[1]); 106 if(fd[0] >= 0) 107 f->fd[fd[0]]=0; 108 if(fd[1] >= 0) 109 f->fd[fd[1]]=0; 110 nexterror(); 111 } 112 c[1] = (*d->clone)(c[0], 0); 113 (*d->walk)(c[0], "data"); 114 (*d->walk)(c[1], "data1"); 115 c[0] = (*d->open)(c[0], ORDWR); 116 c[1] = (*d->open)(c[1], ORDWR); 117 fd[0] = newfd(c[0]); 118 fd[1] = newfd(c[1]); 119 ((long*)arg[0])[0] = fd[0]; 120 ((long*)arg[0])[1] = fd[1]; 121 poperror(); 122 return 0; 123 } 124 125 long 126 sysdup(ulong *arg) 127 { 128 int fd; 129 Chan *c, *oc; 130 Fgrp *f = u->p->fgrp; 131 132 /* 133 * Close after dup'ing, so date > #d/1 works 134 */ 135 c = fdtochan(arg[0], -1, 0, 1); 136 fd = arg[1]; 137 if(fd != -1){ 138 if(fd<0 || NFD<=fd) { 139 close(c); 140 error(Ebadfd); 141 } 142 lock(f); 143 if(fd > f->maxfd) 144 f->maxfd = fd; 145 146 oc = f->fd[fd]; 147 f->fd[fd] = c; 148 unlock(f); 149 if(oc) 150 close(oc); 151 }else{ 152 if(waserror()) { 153 close(c); 154 nexterror(); 155 } 156 fd = newfd(c); 157 poperror(); 158 } 159 160 return fd; 161 } 162 163 long 164 sysopen(ulong *arg) 165 { 166 int fd; 167 Chan *c = 0; 168 169 openmode(arg[1]); /* error check only */ 170 if(waserror()){ 171 if(c) 172 close(c); 173 nexterror(); 174 } 175 validaddr(arg[0], 1, 0); 176 c = namec((char*)arg[0], Aopen, arg[1], 0); 177 fd = newfd(c); 178 poperror(); 179 return fd; 180 } 181 182 void 183 fdclose(int fd, int flag) 184 { 185 int i; 186 Chan *c; 187 Fgrp *f = u->p->fgrp; 188 189 lock(f); 190 c = f->fd[fd]; 191 if(c == 0){ 192 /* can happen for users with shared fd tables */ 193 unlock(f); 194 return; 195 } 196 if(flag){ 197 if(c==0 || !(c->flag&flag)){ 198 unlock(f); 199 return; 200 } 201 } 202 f->fd[fd] = 0; 203 if(fd == f->maxfd) 204 for(i=fd; --i>=0 && f->fd[i]==0; ) 205 f->maxfd = i; 206 207 unlock(f); 208 close(c); 209 } 210 211 long 212 sysclose(ulong *arg) 213 { 214 fdtochan(arg[0], -1, 0, 0); 215 fdclose(arg[0], 0); 216 217 return 0; 218 } 219 220 long 221 unionread(Chan *c, void *va, long n) 222 { 223 long nr; 224 Chan *nc; 225 Pgrp *pg; 226 227 pg = u->p->pgrp; 228 rlock(&pg->ns); 229 230 for(;;) { 231 /* Error causes component of union to be skipped */ 232 if(waserror()) 233 goto next; 234 235 nc = clone(c->mnt->to, 0); 236 poperror(); 237 238 if(c->mountid != c->mnt->mountid) { 239 pprint("unionread: changed underfoot?\n"); 240 runlock(&pg->ns); 241 close(nc); 242 return 0; 243 } 244 245 if(waserror()) { 246 close(nc); 247 goto next; 248 } 249 250 nc = (*devtab[nc->type].open)(nc, OREAD); 251 nc->offset = c->offset; 252 nr = (*devtab[nc->type].read)(nc, va, n, nc->offset); 253 /* devdirread e.g. changes it */ 254 c->offset = nc->offset; 255 poperror(); 256 257 close(nc); 258 if(nr > 0) { 259 runlock(&pg->ns); 260 return nr; 261 } 262 /* Advance to next element */ 263 next: 264 c->mnt = c->mnt->next; 265 if(c->mnt == 0) 266 break; 267 c->mountid = c->mnt->mountid; 268 c->offset = 0; 269 } 270 runlock(&pg->ns); 271 return 0; 272 } 273 274 long 275 sysread(ulong *arg) 276 { 277 int dir; 278 long n; 279 Chan *c; 280 281 validaddr(arg[1], arg[2], 1); 282 c = fdtochan(arg[0], OREAD, 1, 1); 283 if(waserror()) { 284 close(c); 285 nexterror(); 286 } 287 288 n = arg[2]; 289 dir = c->qid.path&CHDIR; 290 291 if(dir) { 292 n -= n%DIRLEN; 293 if(c->offset%DIRLEN || n==0) 294 error(Etoosmall); 295 } 296 297 if(dir && c->mnt) 298 n = unionread(c, (void*)arg[1], n); 299 else 300 n = (*devtab[c->type].read)(c, (void*)arg[1], n, c->offset); 301 302 lock(c); 303 c->offset += n; 304 unlock(c); 305 306 poperror(); 307 close(c); 308 309 return n; 310 } 311 312 long 313 syswrite(ulong *arg) 314 { 315 Chan *c; 316 long n; 317 318 validaddr(arg[1], arg[2], 0); 319 c = fdtochan(arg[0], OWRITE, 1, 1); 320 if(waserror()) { 321 close(c); 322 nexterror(); 323 } 324 325 if(c->qid.path & CHDIR) 326 error(Eisdir); 327 328 n = (*devtab[c->type].write)(c, (void*)arg[1], arg[2], c->offset); 329 330 lock(c); 331 c->offset += n; 332 unlock(c); 333 334 poperror(); 335 close(c); 336 337 return n; 338 } 339 340 long 341 sysseek(ulong *arg) 342 { 343 Chan *c; 344 char buf[DIRLEN]; 345 Dir dir; 346 long off; 347 348 c = fdtochan(arg[0], -1, 1, 0); 349 if(c->qid.path & CHDIR) 350 error(Eisdir); 351 352 if(devchar[c->type] == '|') 353 error(Eisstream); 354 355 off = 0; 356 switch(arg[2]){ 357 case 0: 358 off = c->offset = arg[1]; 359 break; 360 361 case 1: 362 lock(c); /* lock for read/write update */ 363 c->offset += (long)arg[1]; 364 off = c->offset; 365 unlock(c); 366 break; 367 368 case 2: 369 (*devtab[c->type].stat)(c, buf); 370 convM2D(buf, &dir); 371 c->offset = dir.length + (long)arg[1]; 372 off = c->offset; 373 break; 374 } 375 return off; 376 } 377 378 long 379 sysfstat(ulong *arg) 380 { 381 Chan *c; 382 383 validaddr(arg[1], DIRLEN, 1); 384 evenaddr(arg[1]); 385 c = fdtochan(arg[0], -1, 0, 1); 386 if(waserror()) { 387 close(c); 388 nexterror(); 389 } 390 (*devtab[c->type].stat)(c, (char*)arg[1]); 391 poperror(); 392 close(c); 393 return 0; 394 } 395 396 long 397 sysstat(ulong *arg) 398 { 399 Chan *c; 400 401 validaddr(arg[1], DIRLEN, 1); 402 evenaddr(arg[1]); 403 validaddr(arg[0], 1, 0); 404 c = namec((char*)arg[0], Aaccess, 0, 0); 405 if(waserror()){ 406 close(c); 407 nexterror(); 408 } 409 (*devtab[c->type].stat)(c, (char*)arg[1]); 410 poperror(); 411 close(c); 412 return 0; 413 } 414 415 long 416 syschdir(ulong *arg) 417 { 418 Chan *c; 419 420 validaddr(arg[0], 1, 0); 421 c = namec((char*)arg[0], Atodir, 0, 0); 422 close(u->dot); 423 u->dot = c; 424 return 0; 425 } 426 427 long 428 bindmount(ulong *arg, int ismount) 429 { 430 Chan *c0, *c1, *bc; 431 ulong flag; 432 long ret; 433 int fd; 434 struct{ 435 Chan *chan; 436 char *spec; 437 }bogus; 438 439 flag = arg[2]; 440 fd = arg[0]; 441 if(flag>MMASK || (flag&MORDER)==(MBEFORE|MAFTER)) 442 error(Ebadarg); 443 if(ismount){ 444 bc = fdtochan(fd, 2, 0, 1); 445 if(waserror()) { 446 close(bc); 447 nexterror(); 448 } 449 bogus.chan = bc; 450 451 validaddr(arg[3], 1, 0); 452 if(vmemchr((char*)arg[3], '\0', NAMELEN) == 0) 453 error(Ebadarg); 454 455 bogus.spec = (char*)arg[3]; 456 457 ret = devno('M', 0); 458 c0 = (*devtab[ret].attach)((char*)&bogus); 459 460 poperror(); 461 close(bc); 462 } 463 else { 464 validaddr(arg[0], 1, 0); 465 c0 = namec((char*)arg[0], Aaccess, 0, 0); 466 } 467 if(waserror()){ 468 close(c0); 469 nexterror(); 470 } 471 validaddr(arg[1], 1, 0); 472 c1 = namec((char*)arg[1], Amount, 0, 0); 473 if(waserror()){ 474 close(c1); 475 nexterror(); 476 } 477 if((c0->qid.path^c1->qid.path) & CHDIR) 478 error(Emount); 479 if(flag && !(c0->qid.path&CHDIR)) 480 error(Emount); 481 ret = mount(c0, c1, flag); 482 poperror(); 483 close(c1); 484 poperror(); 485 close(c0); 486 if(ismount) 487 fdclose(fd, 0); 488 return ret; 489 } 490 491 long 492 sysbind(ulong *arg) 493 { 494 return bindmount(arg, 0); 495 } 496 497 long 498 sysmount(ulong *arg) 499 { 500 return bindmount(arg, 1); 501 } 502 503 long 504 sysunmount(ulong *arg) 505 { 506 Chan *cmount, *cmounted; 507 508 cmounted = 0; 509 510 validaddr(arg[1], 1, 0); 511 cmount = namec((char *)arg[1], Amount, 0, 0); 512 513 if(arg[0]) { 514 if(waserror()) { 515 close(cmount); 516 nexterror(); 517 } 518 validaddr(arg[0], 1, 0); 519 cmounted = namec((char*)arg[0], Aopen, OREAD, 0); 520 poperror(); 521 } 522 523 if(waserror()) { 524 close(cmount); 525 if(cmounted) 526 close(cmounted); 527 nexterror(); 528 } 529 unmount(cmount, cmounted); 530 close(cmount); 531 if(cmounted) 532 close(cmounted); 533 poperror(); 534 return 0; 535 } 536 537 long 538 syscreate(ulong *arg) 539 { 540 int fd; 541 Chan *c = 0; 542 543 openmode(arg[1]); /* error check only */ 544 if(waserror()) { 545 if(c) 546 close(c); 547 nexterror(); 548 } 549 validaddr(arg[0], 1, 0); 550 c = namec((char*)arg[0], Acreate, arg[1], arg[2]); 551 fd = newfd(c); 552 poperror(); 553 return fd; 554 } 555 556 long 557 sysremove(ulong *arg) 558 { 559 Chan *c; 560 561 validaddr(arg[0], 1, 0); 562 c = namec((char*)arg[0], Aaccess, 0, 0); 563 if(waserror()){ 564 c->type = 0; /* see below */ 565 close(c); 566 nexterror(); 567 } 568 (*devtab[c->type].remove)(c); 569 /* 570 * Remove clunks the fid, but we need to recover the Chan 571 * so fake it up. rootclose() is known to be a nop. 572 */ 573 c->type = 0; 574 poperror(); 575 close(c); 576 return 0; 577 } 578 579 long 580 syswstat(ulong *arg) 581 { 582 Chan *c; 583 584 validaddr(arg[1], DIRLEN, 0); 585 nameok((char*)arg[1]); 586 validaddr(arg[0], 1, 0); 587 c = namec((char*)arg[0], Aaccess, 0, 0); 588 if(waserror()){ 589 close(c); 590 nexterror(); 591 } 592 (*devtab[c->type].wstat)(c, (char*)arg[1]); 593 poperror(); 594 close(c); 595 return 0; 596 } 597 598 long 599 sysfwstat(ulong *arg) 600 { 601 Chan *c; 602 603 validaddr(arg[1], DIRLEN, 0); 604 nameok((char*)arg[1]); 605 c = fdtochan(arg[0], -1, 1, 1); 606 if(waserror()) { 607 close(c); 608 nexterror(); 609 } 610 (*devtab[c->type].wstat)(c, (char*)arg[1]); 611 poperror(); 612 close(c); 613 return 0; 614 } 615