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 #include <a.out.h> 9 10 int shargs(char*, int, char**); 11 12 Ref sysr1ref; 13 14 long 15 sysr1(ulong *arg) 16 { 17 long a; 18 19 a = *arg; 20 if(a > 0) 21 return incref(&sysr1ref); 22 if(a < 0) 23 return decref(&sysr1ref); 24 return sysr1ref.ref; 25 26 /* 27 extern int chandebug; 28 extern void dumpmount(void); 29 30 print("[%s %s %lud] r1 = %lud\n", up->user, up->text, up->pid, arg[0]); 31 chandebug=!chandebug; 32 if(chandebug) 33 dumpmount(); 34 35 return 0; 36 */ 37 } 38 39 long 40 sysrfork(ulong *arg) 41 { 42 Proc *p; 43 int n, i; 44 Fgrp *ofg; 45 Pgrp *opg; 46 Rgrp *org; 47 Egrp *oeg; 48 ulong pid, flag; 49 Mach *wm; 50 51 flag = arg[0]; 52 /* Check flags before we commit */ 53 if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG)) 54 error(Ebadarg); 55 if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG)) 56 error(Ebadarg); 57 if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG)) 58 error(Ebadarg); 59 60 if((flag&RFPROC) == 0) { 61 if(flag & (RFMEM|RFNOWAIT)) 62 error(Ebadarg); 63 if(flag & (RFFDG|RFCFDG)) { 64 ofg = up->fgrp; 65 if(flag & RFFDG) 66 up->fgrp = dupfgrp(ofg); 67 else 68 up->fgrp = dupfgrp(nil); 69 closefgrp(ofg); 70 } 71 if(flag & (RFNAMEG|RFCNAMEG)) { 72 opg = up->pgrp; 73 up->pgrp = newpgrp(); 74 if(flag & RFNAMEG) 75 pgrpcpy(up->pgrp, opg); 76 /* inherit noattach */ 77 up->pgrp->noattach = opg->noattach; 78 closepgrp(opg); 79 } 80 if(flag & RFNOMNT) 81 up->pgrp->noattach = 1; 82 if(flag & RFREND) { 83 org = up->rgrp; 84 up->rgrp = newrgrp(); 85 closergrp(org); 86 } 87 if(flag & (RFENVG|RFCENVG)) { 88 oeg = up->egrp; 89 up->egrp = smalloc(sizeof(Egrp)); 90 up->egrp->ref = 1; 91 if(flag & RFENVG) 92 envcpy(up->egrp, oeg); 93 closeegrp(oeg); 94 } 95 if(flag & RFNOTEG) 96 up->noteid = incref(¬eidalloc); 97 return 0; 98 } 99 100 p = newproc(); 101 102 p->fpsave = up->fpsave; 103 p->scallnr = up->scallnr; 104 p->s = up->s; 105 p->nerrlab = 0; 106 p->slash = up->slash; 107 p->dot = up->dot; 108 incref(p->dot); 109 110 memmove(p->note, up->note, sizeof(p->note)); 111 p->privatemem = up->privatemem; 112 p->noswap = up->noswap; 113 p->nnote = up->nnote; 114 p->notified = 0; 115 p->lastnote = up->lastnote; 116 p->notify = up->notify; 117 p->ureg = up->ureg; 118 p->dbgreg = 0; 119 120 /* Make a new set of memory segments */ 121 n = flag & RFMEM; 122 qlock(&p->seglock); 123 if(waserror()){ 124 qunlock(&p->seglock); 125 nexterror(); 126 } 127 for(i = 0; i < NSEG; i++) 128 if(up->seg[i]) 129 p->seg[i] = dupseg(up->seg, i, n); 130 qunlock(&p->seglock); 131 poperror(); 132 133 /* File descriptors */ 134 if(flag & (RFFDG|RFCFDG)) { 135 if(flag & RFFDG) 136 p->fgrp = dupfgrp(up->fgrp); 137 else 138 p->fgrp = dupfgrp(nil); 139 } 140 else { 141 p->fgrp = up->fgrp; 142 incref(p->fgrp); 143 } 144 145 /* Process groups */ 146 if(flag & (RFNAMEG|RFCNAMEG)) { 147 p->pgrp = newpgrp(); 148 if(flag & RFNAMEG) 149 pgrpcpy(p->pgrp, up->pgrp); 150 /* inherit noattach */ 151 p->pgrp->noattach = up->pgrp->noattach; 152 } 153 else { 154 p->pgrp = up->pgrp; 155 incref(p->pgrp); 156 } 157 if(flag & RFNOMNT) 158 up->pgrp->noattach = 1; 159 160 if(flag & RFREND) 161 p->rgrp = newrgrp(); 162 else { 163 incref(up->rgrp); 164 p->rgrp = up->rgrp; 165 } 166 167 /* Environment group */ 168 if(flag & (RFENVG|RFCENVG)) { 169 p->egrp = smalloc(sizeof(Egrp)); 170 p->egrp->ref = 1; 171 if(flag & RFENVG) 172 envcpy(p->egrp, up->egrp); 173 } 174 else { 175 p->egrp = up->egrp; 176 incref(p->egrp); 177 } 178 p->hang = up->hang; 179 p->procmode = up->procmode; 180 181 /* Craft a return frame which will cause the child to pop out of 182 * the scheduler in user mode with the return register zero 183 */ 184 forkchild(p, up->dbgreg); 185 186 p->parent = up; 187 p->parentpid = up->pid; 188 if(flag&RFNOWAIT) 189 p->parentpid = 0; 190 else { 191 lock(&up->exl); 192 up->nchild++; 193 unlock(&up->exl); 194 } 195 if((flag&RFNOTEG) == 0) 196 p->noteid = up->noteid; 197 198 p->fpstate = up->fpstate; 199 pid = p->pid; 200 memset(p->time, 0, sizeof(p->time)); 201 p->time[TReal] = MACHP(0)->ticks; 202 203 kstrdup(&p->text, up->text); 204 kstrdup(&p->user, up->user); 205 /* 206 * since the bss/data segments are now shareable, 207 * any mmu info about this process is now stale 208 * (i.e. has bad properties) and has to be discarded. 209 */ 210 flushmmu(); 211 p->basepri = up->basepri; 212 p->priority = up->basepri; 213 p->fixedpri = up->fixedpri; 214 p->mp = up->mp; 215 wm = up->wired; 216 if(wm) 217 procwired(p, wm->machno); 218 ready(p); 219 sched(); 220 return pid; 221 } 222 223 static ulong 224 l2be(long l) 225 { 226 uchar *cp; 227 228 cp = (uchar*)&l; 229 return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3]; 230 } 231 232 long 233 sysexec(ulong *arg) 234 { 235 Segment *s, *ts; 236 ulong t, d, b; 237 int i; 238 Chan *tc; 239 char **argv, **argp; 240 char *a, *charp, *args, *file; 241 char *progarg[sizeof(Exec)/2+1], *elem, progelem[64]; 242 ulong ssize, spage, nargs, nbytes, n, bssend; 243 int indir; 244 Exec exec; 245 char line[sizeof(Exec)]; 246 Fgrp *f; 247 Image *img; 248 ulong magic, text, entry, data, bss; 249 250 validaddr(arg[0], 1, 0); 251 file = (char*)arg[0]; 252 indir = 0; 253 elem = nil; 254 if(waserror()){ 255 free(elem); 256 nexterror(); 257 } 258 for(;;){ 259 tc = namec(file, Aopen, OEXEC, 0); 260 if(waserror()){ 261 cclose(tc); 262 nexterror(); 263 } 264 if(!indir) 265 kstrdup(&elem, up->genbuf); 266 267 n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0); 268 if(n < 2) 269 error(Ebadexec); 270 magic = l2be(exec.magic); 271 text = l2be(exec.text); 272 entry = l2be(exec.entry); 273 if(n==sizeof(Exec) && (magic == AOUT_MAGIC)){ 274 if((text&KZERO) == KZERO 275 || entry < UTZERO+sizeof(Exec) 276 || entry >= UTZERO+sizeof(Exec)+text) 277 error(Ebadexec); 278 break; /* for binary */ 279 } 280 281 /* 282 * Process #! /bin/sh args ... 283 */ 284 memmove(line, &exec, sizeof(Exec)); 285 if(indir || line[0]!='#' || line[1]!='!') 286 error(Ebadexec); 287 n = shargs(line, n, progarg); 288 if(n == 0) 289 error(Ebadexec); 290 indir = 1; 291 /* 292 * First arg becomes complete file name 293 */ 294 progarg[n++] = file; 295 progarg[n] = 0; 296 validaddr(arg[1], BY2WD, 1); 297 arg[1] += BY2WD; 298 file = progarg[0]; 299 if(strlen(elem) >= sizeof progelem) 300 error(Ebadexec); 301 strcpy(progelem, elem); 302 progarg[0] = progelem; 303 poperror(); 304 cclose(tc); 305 } 306 307 data = l2be(exec.data); 308 bss = l2be(exec.bss); 309 t = (UTZERO+sizeof(Exec)+text+(BY2PG-1)) & ~(BY2PG-1); 310 d = (t + data + (BY2PG-1)) & ~(BY2PG-1); 311 bssend = t + data + bss; 312 b = (bssend + (BY2PG-1)) & ~(BY2PG-1); 313 if(((t|d|b) & KZERO) == KZERO) 314 error(Ebadexec); 315 316 /* 317 * Args: pass 1: count 318 */ 319 nbytes = BY2WD; /* hole for profiling clock at top of stack */ 320 nargs = 0; 321 if(indir){ 322 argp = progarg; 323 while(*argp){ 324 a = *argp++; 325 nbytes += strlen(a) + 1; 326 nargs++; 327 } 328 } 329 evenaddr(arg[1]); 330 argp = (char**)arg[1]; 331 validaddr((ulong)argp, BY2WD, 0); 332 while(*argp){ 333 a = *argp++; 334 if(((ulong)argp&(BY2PG-1)) < BY2WD) 335 validaddr((ulong)argp, BY2WD, 0); 336 validaddr((ulong)a, 1, 0); 337 nbytes += (vmemchr(a, 0, 0x7FFFFFFF) - a) + 1; 338 nargs++; 339 } 340 ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1)); 341 342 /* 343 * 8-byte align SP for those (e.g. sparc) that need it. 344 * execregs() will subtract another 4 bytes for argc. 345 */ 346 if((ssize+4) & 7) 347 ssize += 4; 348 spage = (ssize+(BY2PG-1)) >> PGSHIFT; 349 350 /* 351 * Build the stack segment, putting it in kernel virtual for the moment 352 */ 353 if(spage > TSTKSIZ) 354 error(Enovmem); 355 356 qlock(&up->seglock); 357 if(waserror()){ 358 qunlock(&up->seglock); 359 nexterror(); 360 } 361 up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG); 362 363 /* 364 * Args: pass 2: assemble; the pages will be faulted in 365 */ 366 argv = (char**)(TSTKTOP - ssize); 367 charp = (char*)(TSTKTOP - nbytes); 368 args = charp; 369 if(indir) 370 argp = progarg; 371 else 372 argp = (char**)arg[1]; 373 374 for(i=0; i<nargs; i++){ 375 if(indir && *argp==0) { 376 indir = 0; 377 argp = (char**)arg[1]; 378 } 379 *argv++ = charp + (USTKTOP-TSTKTOP); 380 n = strlen(*argp) + 1; 381 memmove(charp, *argp++, n); 382 charp += n; 383 } 384 385 free(up->text); 386 up->text = elem; 387 elem = nil; /* so waserror() won't free elem */ 388 USED(elem); 389 390 /* copy args; easiest from new process's stack */ 391 n = charp - args; 392 if(n > 128) /* don't waste too much space on huge arg lists */ 393 n = 128; 394 a = up->args; 395 up->args = nil; 396 free(a); 397 up->args = smalloc(n); 398 memmove(up->args, args, n); 399 if(n>0 && up->args[n-1]!='\0'){ 400 /* make sure last arg is NUL-terminated */ 401 /* put NUL at UTF-8 character boundary */ 402 for(i=n-1; i>0; --i) 403 if(fullrune(up->args+i, n-i)) 404 break; 405 up->args[i] = 0; 406 n = i+1; 407 } 408 up->nargs = n; 409 410 /* 411 * Committed. 412 * Free old memory. 413 * Special segments are maintained across exec 414 */ 415 for(i = SSEG; i <= BSEG; i++) { 416 putseg(up->seg[i]); 417 /* prevent a second free if we have an error */ 418 up->seg[i] = 0; 419 } 420 for(i = BSEG+1; i < NSEG; i++) { 421 s = up->seg[i]; 422 if(s != 0 && (s->type&SG_CEXEC)) { 423 putseg(s); 424 up->seg[i] = 0; 425 } 426 } 427 428 /* 429 * Close on exec 430 */ 431 f = up->fgrp; 432 for(i=0; i<=f->maxfd; i++) 433 fdclose(i, CCEXEC); 434 435 /* Text. Shared. Attaches to cache image if possible */ 436 /* attachimage returns a locked cache image */ 437 img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (t-UTZERO)>>PGSHIFT); 438 ts = img->s; 439 up->seg[TSEG] = ts; 440 ts->flushme = 1; 441 ts->fstart = 0; 442 ts->flen = sizeof(Exec)+text; 443 unlock(img); 444 445 /* Data. Shared. */ 446 s = newseg(SG_DATA, t, (d-t)>>PGSHIFT); 447 up->seg[DSEG] = s; 448 449 /* Attached by hand */ 450 incref(img); 451 s->image = img; 452 s->fstart = ts->fstart+ts->flen; 453 s->flen = data; 454 455 /* BSS. Zero fill on demand */ 456 up->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT); 457 458 /* 459 * Move the stack 460 */ 461 s = up->seg[ESEG]; 462 up->seg[ESEG] = 0; 463 up->seg[SSEG] = s; 464 qunlock(&up->seglock); 465 poperror(); /* seglock */ 466 poperror(); /* elem */ 467 s->base = USTKTOP-USTKSIZE; 468 s->top = USTKTOP; 469 relocateseg(s, USTKTOP-TSTKTOP); 470 471 /* 472 * '/' processes are higher priority (hack to make /ip more responsive). 473 */ 474 if(devtab[tc->type]->dc == L'/') 475 up->basepri = PriRoot; 476 up->priority = up->basepri; 477 poperror(); 478 cclose(tc); 479 480 /* 481 * At this point, the mmu contains info about the old address 482 * space and needs to be flushed 483 */ 484 flushmmu(); 485 qlock(&up->debug); 486 up->nnote = 0; 487 up->notify = 0; 488 up->notified = 0; 489 up->privatemem = 0; 490 procsetup(up); 491 qunlock(&up->debug); 492 if(up->hang) 493 up->procctl = Proc_stopme; 494 495 return execregs(entry, ssize, nargs); 496 } 497 498 int 499 shargs(char *s, int n, char **ap) 500 { 501 int i; 502 503 s += 2; 504 n -= 2; /* skip #! */ 505 for(i=0; s[i]!='\n'; i++) 506 if(i == n-1) 507 return 0; 508 s[i] = 0; 509 *ap = 0; 510 i = 0; 511 for(;;) { 512 while(*s==' ' || *s=='\t') 513 s++; 514 if(*s == 0) 515 break; 516 i++; 517 *ap++ = s; 518 *ap = 0; 519 while(*s && *s!=' ' && *s!='\t') 520 s++; 521 if(*s == 0) 522 break; 523 else 524 *s++ = 0; 525 } 526 return i; 527 } 528 529 int 530 return0(void*) 531 { 532 return 0; 533 } 534 535 long 536 syssleep(ulong *arg) 537 { 538 539 int n; 540 541 n = arg[0]; 542 if(n <= 0) { 543 up->priority = 0; 544 sched(); 545 return 0; 546 } 547 if(n < TK2MS(1)) 548 n = TK2MS(1); 549 tsleep(&up->sleep, return0, 0, n); 550 return 0; 551 } 552 553 long 554 sysalarm(ulong *arg) 555 { 556 return procalarm(arg[0]); 557 } 558 559 long 560 sysexits(ulong *arg) 561 { 562 char *status; 563 char *inval = "invalid exit string"; 564 char buf[ERRMAX]; 565 566 status = (char*)arg[0]; 567 if(status){ 568 if(waserror()) 569 status = inval; 570 else{ 571 validaddr((ulong)status, 1, 0); 572 if(vmemchr(status, 0, ERRMAX) == 0){ 573 memmove(buf, status, ERRMAX); 574 buf[ERRMAX-1] = 0; 575 status = buf; 576 } 577 } 578 poperror(); 579 580 } 581 pexit(status, 1); 582 return 0; /* not reached */ 583 } 584 585 long 586 sys_wait(ulong *arg) 587 { 588 int pid; 589 Waitmsg w; 590 OWaitmsg *ow; 591 592 if(arg[0] == 0) 593 return pwait(nil); 594 595 validaddr(arg[0], sizeof(OWaitmsg), 1); 596 evenaddr(arg[0]); 597 pid = pwait(&w); 598 if(pid >= 0){ 599 ow = (OWaitmsg*)arg[0]; 600 readnum(0, ow->pid, NUMSIZE, w.pid, NUMSIZE); 601 readnum(0, ow->time+TUser*NUMSIZE, NUMSIZE, w.time[TUser], NUMSIZE); 602 readnum(0, ow->time+TSys*NUMSIZE, NUMSIZE, w.time[TSys], NUMSIZE); 603 readnum(0, ow->time+TReal*NUMSIZE, NUMSIZE, w.time[TReal], NUMSIZE); 604 strncpy(ow->msg, w.msg, sizeof(ow->msg)); 605 ow->msg[sizeof(ow->msg)-1] = '\0'; 606 } 607 return pid; 608 } 609 610 long 611 sysawait(ulong *arg) 612 { 613 int i; 614 int pid; 615 Waitmsg w; 616 ulong n; 617 618 n = arg[1]; 619 validaddr(arg[0], n, 1); 620 pid = pwait(&w); 621 if(pid < 0) 622 return -1; 623 i = snprint((char*)arg[0], n, "%d %lud %lud %lud %q", 624 w.pid, 625 w.time[TUser], w.time[TSys], w.time[TReal], 626 w.msg); 627 628 return i; 629 } 630 631 long 632 sysdeath(ulong*) 633 { 634 pprint("deprecated system call\n"); 635 pexit("Suicide", 0); 636 return 0; /* not reached */ 637 } 638 639 void 640 werrstr(char *fmt, ...) 641 { 642 va_list va; 643 644 if(up == nil) 645 return; 646 647 va_start(va, fmt); 648 vseprint(up->syserrstr, up->syserrstr+ERRMAX, fmt, va); 649 va_end(va); 650 } 651 652 static long 653 generrstr(char *buf, uint nbuf) 654 { 655 char tmp[ERRMAX]; 656 657 if(nbuf == 0) 658 error(Ebadarg); 659 validaddr((ulong)buf, nbuf, 1); 660 if(nbuf > sizeof tmp) 661 nbuf = sizeof tmp; 662 memmove(tmp, buf, nbuf); 663 /* make sure it's NUL-terminated */ 664 tmp[nbuf-1] = '\0'; 665 memmove(buf, up->syserrstr, nbuf); 666 buf[nbuf-1] = '\0'; 667 memmove(up->syserrstr, tmp, nbuf); 668 return 0; 669 } 670 671 long 672 syserrstr(ulong *arg) 673 { 674 return generrstr((char*)arg[0], arg[1]); 675 } 676 677 /* compatibility for old binaries */ 678 long 679 sys_errstr(ulong *arg) 680 { 681 return generrstr((char*)arg[0], 64); 682 } 683 684 long 685 sysnotify(ulong *arg) 686 { 687 if(arg[0] != 0) 688 validaddr(arg[0], sizeof(ulong), 0); 689 up->notify = (int(*)(void*, char*))(arg[0]); 690 return 0; 691 } 692 693 long 694 sysnoted(ulong *arg) 695 { 696 if(arg[0]!=NRSTR && !up->notified) 697 error(Egreg); 698 return 0; 699 } 700 701 long 702 syssegbrk(ulong *arg) 703 { 704 int i; 705 ulong addr; 706 Segment *s; 707 708 addr = arg[0]; 709 for(i = 0; i < NSEG; i++) { 710 s = up->seg[i]; 711 if(s == 0 || addr < s->base || addr >= s->top) 712 continue; 713 switch(s->type&SG_TYPE) { 714 case SG_TEXT: 715 case SG_DATA: 716 case SG_STACK: 717 error(Ebadarg); 718 default: 719 return ibrk(arg[1], i); 720 } 721 } 722 723 error(Ebadarg); 724 return 0; /* not reached */ 725 } 726 727 long 728 syssegattach(ulong *arg) 729 { 730 return segattach(up, arg[0], (char*)arg[1], arg[2], arg[3]); 731 } 732 733 long 734 syssegdetach(ulong *arg) 735 { 736 int i; 737 ulong addr; 738 Segment *s; 739 740 qlock(&up->seglock); 741 if(waserror()){ 742 qunlock(&up->seglock); 743 nexterror(); 744 } 745 746 s = 0; 747 addr = arg[0]; 748 for(i = 0; i < NSEG; i++) 749 if(s = up->seg[i]) { 750 qlock(&s->lk); 751 if((addr >= s->base && addr < s->top) || 752 (s->top == s->base && addr == s->base)) 753 goto found; 754 qunlock(&s->lk); 755 } 756 757 error(Ebadarg); 758 759 found: 760 /* Check we are not detaching the current stack segment */ 761 if((ulong)arg >= s->base && (ulong)arg < s->top) { 762 qunlock(&s->lk); 763 error(Ebadarg); 764 } 765 up->seg[i] = 0; 766 qunlock(&s->lk); 767 putseg(s); 768 qunlock(&up->seglock); 769 poperror(); 770 771 /* Ensure we flush any entries from the lost segment */ 772 flushmmu(); 773 return 0; 774 } 775 776 long 777 syssegfree(ulong *arg) 778 { 779 Segment *s; 780 ulong from, to; 781 782 from = arg[0]; 783 s = seg(up, from, 1); 784 if(s == nil) 785 error(Ebadarg); 786 to = (from + arg[1]) & ~(BY2PG-1); 787 from = PGROUND(from); 788 789 if(to > s->top) { 790 qunlock(&s->lk); 791 error(Ebadarg); 792 } 793 794 mfreeseg(s, from, (to - from) / BY2PG); 795 qunlock(&s->lk); 796 flushmmu(); 797 798 return 0; 799 } 800 801 /* For binary compatibility */ 802 long 803 sysbrk_(ulong *arg) 804 { 805 return ibrk(arg[0], BSEG); 806 } 807 808 long 809 sysrendezvous(ulong *arg) 810 { 811 ulong tag; 812 ulong val; 813 Proc *p, **l; 814 815 tag = arg[0]; 816 l = &REND(up->rgrp, tag); 817 up->rendval = ~0UL; 818 819 lock(up->rgrp); 820 for(p = *l; p; p = p->rendhash) { 821 if(p->rendtag == tag) { 822 *l = p->rendhash; 823 val = p->rendval; 824 p->rendval = arg[1]; 825 826 while(p->mach != 0) 827 ; 828 ready(p); 829 unlock(up->rgrp); 830 return val; 831 } 832 l = &p->rendhash; 833 } 834 835 /* Going to sleep here */ 836 up->rendtag = tag; 837 up->rendval = arg[1]; 838 up->rendhash = *l; 839 *l = up; 840 up->state = Rendezvous; 841 unlock(up->rgrp); 842 if (edf->isedf(up)) 843 edf->edfblock(up); 844 845 sched(); 846 847 return up->rendval; 848 } 849