1*5991Swnj /* kern_proc.c 4.23 82/02/27 */ 236Sbill 336Sbill #include "../h/param.h" 436Sbill #include "../h/systm.h" 536Sbill #include "../h/map.h" 636Sbill #include "../h/mtpr.h" 736Sbill #include "../h/dir.h" 836Sbill #include "../h/user.h" 936Sbill #include "../h/proc.h" 1036Sbill #include "../h/buf.h" 1136Sbill #include "../h/reg.h" 1236Sbill #include "../h/inode.h" 1336Sbill #include "../h/seg.h" 1436Sbill #include "../h/acct.h" 15215Sbill #include "/usr/include/wait.h" 1636Sbill #include "../h/pte.h" 1736Sbill #include "../h/vm.h" 1836Sbill #include "../h/text.h" 19188Sbill #include "../h/psl.h" 20879Sbill #include "../h/vlimit.h" 21890Sbill #include "../h/file.h" 2236Sbill 2336Sbill /* 2436Sbill * exec system call, with and without environments. 2536Sbill */ 2636Sbill struct execa { 2736Sbill char *fname; 2836Sbill char **argp; 2936Sbill char **envp; 3036Sbill }; 3136Sbill 3236Sbill exec() 3336Sbill { 3436Sbill ((struct execa *)u.u_ap)->envp = NULL; 3536Sbill exece(); 3636Sbill } 3736Sbill 3836Sbill exece() 3936Sbill { 4036Sbill register nc; 4136Sbill register char *cp; 4236Sbill register struct buf *bp; 4336Sbill register struct execa *uap; 4436Sbill int na, ne, ucp, ap, c; 452301Skre int indir, uid, gid; 462301Skre char *sharg; 4736Sbill struct inode *ip; 4836Sbill swblk_t bno; 492301Skre char cfname[DIRSIZ]; 502301Skre char cfarg[SHSIZE]; 5136Sbill 52*5991Swnj if ((ip = namei(uchar, 0, 1)) == NULL) 5336Sbill return; 5436Sbill bno = 0; 5536Sbill bp = 0; 562301Skre indir = 0; 572301Skre uid = u.u_uid; 582301Skre gid = u.u_gid; 592301Skre if (ip->i_mode & ISUID) 602301Skre uid = ip->i_uid; 612301Skre if (ip->i_mode & ISGID) 622301Skre gid = ip->i_gid; 632301Skre 642301Skre again: 654827Swnj if (access(ip, IEXEC)) 6636Sbill goto bad; 674827Swnj if ((u.u_procp->p_flag&STRC) && access(ip, IREAD)) 682330Swnj goto bad; 694827Swnj if ((ip->i_mode & IFMT) != IFREG || 7036Sbill (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) { 7136Sbill u.u_error = EACCES; 7236Sbill goto bad; 7336Sbill } 742301Skre 7536Sbill /* 762301Skre * Read in first few bytes of file for segment sizes, ux_mag: 772301Skre * 407 = plain executable 782301Skre * 410 = RO text 792301Skre * 413 = demand paged RO text 802301Skre * Also an ASCII line beginning with #! is 812301Skre * the file name of a ``shell'' and arguments may be prepended 822301Skre * to the argument list if given here. 832301Skre * 842301Skre * SHELL NAMES ARE LIMITED IN LENGTH. 852301Skre * 862301Skre * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM 872301Skre * THE ASCII LINE. 882301Skre */ 892301Skre u.u_base = (caddr_t)&u.u_exdata; 902301Skre u.u_count = sizeof(u.u_exdata); 912301Skre u.u_offset = 0; 922301Skre u.u_segflg = 1; 932301Skre readi(ip); 942301Skre u.u_segflg = 0; 954827Swnj if (u.u_error) 962301Skre goto bad; 974982Swnj if (u.u_count > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) && 984982Swnj u.u_exdata.ux_shell[0] != '#') { 992301Skre u.u_error = ENOEXEC; 1002301Skre goto bad; 1012301Skre } 1022301Skre switch (u.u_exdata.ux_mag) { 1032301Skre 1042301Skre case 0407: 1052301Skre u.u_exdata.ux_dsize += u.u_exdata.ux_tsize; 1062301Skre u.u_exdata.ux_tsize = 0; 1072301Skre break; 1082301Skre 1092301Skre case 0413: 1102301Skre case 0410: 1112301Skre if (u.u_exdata.ux_tsize == 0) { 1122301Skre u.u_error = ENOEXEC; 1132301Skre goto bad; 1142301Skre } 1152301Skre break; 1162301Skre 1172301Skre default: 1182301Skre if (u.u_exdata.ux_shell[0] != '#' || 1192301Skre u.u_exdata.ux_shell[1] != '!' || 1202301Skre indir) { 1212301Skre u.u_error = ENOEXEC; 1222301Skre goto bad; 1232301Skre } 1242301Skre cp = &u.u_exdata.ux_shell[2]; /* skip "#!" */ 1252301Skre while (cp < &u.u_exdata.ux_shell[SHSIZE]) { 1262301Skre if (*cp == '\t') 1272301Skre *cp = ' '; 1282301Skre else if (*cp == '\n') { 1292301Skre *cp = '\0'; 1302301Skre break; 1312301Skre } 1322301Skre cp++; 1332301Skre } 1342301Skre if (*cp != '\0') { 1352301Skre u.u_error = ENOEXEC; 1362301Skre goto bad; 1372301Skre } 1382301Skre cp = &u.u_exdata.ux_shell[2]; 1392301Skre while (*cp == ' ') 1402301Skre cp++; 1412301Skre u.u_dirp = cp; 1422301Skre while (*cp && *cp != ' ') 1432301Skre cp++; 1442301Skre sharg = NULL; 1452301Skre if (*cp) { 1462301Skre *cp++ = '\0'; 1472301Skre while (*cp == ' ') 1482301Skre cp++; 1492301Skre if (*cp) { 1502301Skre bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE); 1512301Skre sharg = cfarg; 1522301Skre } 1532301Skre } 1542301Skre bcopy((caddr_t)u.u_dbuf, (caddr_t)cfname, DIRSIZ); 1552301Skre indir = 1; 1562301Skre iput(ip); 157*5991Swnj ip = namei(schar, 0, 1); 1582301Skre if (ip == NULL) 1592301Skre return; 1602301Skre goto again; 1612301Skre } 1622301Skre 1632301Skre /* 16436Sbill * Collect arguments on "file" in swap space. 16536Sbill */ 16636Sbill na = 0; 16736Sbill ne = 0; 16836Sbill nc = 0; 16936Sbill uap = (struct execa *)u.u_ap; 1702780Swnj if ((bno = rmalloc(argmap, ctod(clrnd((int) btoc(NCARGS))))) == 0) { 17136Sbill swkill(u.u_procp, "exece"); 17236Sbill goto bad; 17336Sbill } 17436Sbill if (bno % CLSIZE) 1752780Swnj panic("execa rmalloc"); 17636Sbill if (uap->argp) for (;;) { 17736Sbill ap = NULL; 1783621Sroot if (indir && (na == 1 || na == 2 && sharg)) 1792301Skre ap = (int)uap->fname; 1802301Skre else if (uap->argp) { 18136Sbill ap = fuword((caddr_t)uap->argp); 18236Sbill uap->argp++; 18336Sbill } 18436Sbill if (ap==NULL && uap->envp) { 18536Sbill uap->argp = NULL; 18636Sbill if ((ap = fuword((caddr_t)uap->envp)) == NULL) 18736Sbill break; 18836Sbill uap->envp++; 18936Sbill ne++; 19036Sbill } 19136Sbill if (ap==NULL) 19236Sbill break; 19336Sbill na++; 1944827Swnj if (ap == -1) 19536Sbill u.u_error = EFAULT; 19636Sbill do { 19736Sbill if (nc >= NCARGS-1) 19836Sbill u.u_error = E2BIG; 1992301Skre if (indir && na == 2 && sharg != NULL) 2002301Skre c = *sharg++ & 0377; 2012301Skre else if ((c = fubyte((caddr_t)ap++)) < 0) 20236Sbill u.u_error = EFAULT; 20383Sbill if (u.u_error) { 20483Sbill if (bp) 20583Sbill brelse(bp); 20683Sbill bp = 0; 20736Sbill goto badarg; 20883Sbill } 20936Sbill if ((nc&BMASK) == 0) { 21036Sbill if (bp) 21136Sbill bdwrite(bp); 212307Sbill bp = getblk(argdev, 213307Sbill (daddr_t)(dbtofsb(bno)+(nc>>BSHIFT))); 21436Sbill cp = bp->b_un.b_addr; 21536Sbill } 21636Sbill nc++; 21736Sbill *cp++ = c; 21836Sbill } while (c>0); 21936Sbill } 22036Sbill if (bp) 22136Sbill bdwrite(bp); 22236Sbill bp = 0; 22336Sbill nc = (nc + NBPW-1) & ~(NBPW-1); 2242301Skre if (indir) 2252301Skre bcopy((caddr_t)cfname, (caddr_t)u.u_dbuf, DIRSIZ); 2262301Skre getxfile(ip, nc + (na+4)*NBPW, uid, gid); 227912Sbill if (u.u_error) { 22836Sbill badarg: 22936Sbill for (c = 0; c < nc; c += BSIZE) 230307Sbill if (bp = baddr(argdev, dbtofsb(bno)+(c>>BSHIFT))) { 23136Sbill bp->b_flags |= B_AGE; /* throw away */ 23236Sbill bp->b_flags &= ~B_DELWRI; /* cancel io */ 23336Sbill brelse(bp); 23436Sbill bp = 0; 23536Sbill } 23636Sbill goto bad; 23736Sbill } 23836Sbill 23936Sbill /* 24036Sbill * copy back arglist 24136Sbill */ 24236Sbill ucp = USRSTACK - nc - NBPW; 24336Sbill ap = ucp - na*NBPW - 3*NBPW; 24436Sbill u.u_ar0[SP] = ap; 245132Sbill (void) suword((caddr_t)ap, na-ne); 24636Sbill nc = 0; 24736Sbill for (;;) { 24836Sbill ap += NBPW; 24936Sbill if (na==ne) { 250132Sbill (void) suword((caddr_t)ap, 0); 25136Sbill ap += NBPW; 25236Sbill } 25336Sbill if (--na < 0) 25436Sbill break; 255132Sbill (void) suword((caddr_t)ap, ucp); 25636Sbill do { 25736Sbill if ((nc&BMASK) == 0) { 25836Sbill if (bp) 25936Sbill brelse(bp); 260307Sbill bp = bread(argdev, 261307Sbill (daddr_t)(dbtofsb(bno)+(nc>>BSHIFT))); 26236Sbill bp->b_flags |= B_AGE; /* throw away */ 26336Sbill bp->b_flags &= ~B_DELWRI; /* cancel io */ 26436Sbill cp = bp->b_un.b_addr; 26536Sbill } 266132Sbill (void) subyte((caddr_t)ucp++, (c = *cp++)); 26736Sbill nc++; 26836Sbill } while(c&0377); 26936Sbill } 270132Sbill (void) suword((caddr_t)ap, 0); 271132Sbill (void) suword((caddr_t)ucp, 0); 27236Sbill setregs(); 27336Sbill bad: 27436Sbill if (bp) 27536Sbill brelse(bp); 27636Sbill if (bno) 2772780Swnj rmfree(argmap, ctod(clrnd((int) btoc(NCARGS))), bno); 27836Sbill iput(ip); 27936Sbill } 28036Sbill 28136Sbill /* 28236Sbill * Read in and set up memory for executed file. 28336Sbill */ 2842301Skre getxfile(ip, nargc, uid, gid) 28536Sbill register struct inode *ip; 28636Sbill { 28736Sbill register size_t ts, ds, ss; 2882301Skre int pagi; 28936Sbill 2902301Skre if (u.u_exdata.ux_mag == 0413) 29136Sbill pagi = SPAGI; 2922301Skre else 2932301Skre pagi = 0; 2944827Swnj if (u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && 2954827Swnj ip->i_count!=1) { 296890Sbill register struct file *fp; 297890Sbill 2984827Swnj for (fp = file; fp < fileNFILE; fp++) { 2994827Swnj if (fp->f_flag & FSOCKET) 3004827Swnj continue; 301890Sbill if (fp->f_inode == ip && (fp->f_flag&FWRITE)) { 302890Sbill u.u_error = ETXTBSY; 303890Sbill goto bad; 304890Sbill } 3054827Swnj } 30636Sbill } 30736Sbill 30836Sbill /* 3094827Swnj * Compute text and data sizes and make sure not too large. 31036Sbill */ 31136Sbill ts = clrnd(btoc(u.u_exdata.ux_tsize)); 31236Sbill ds = clrnd(btoc((u.u_exdata.ux_dsize+u.u_exdata.ux_bsize))); 31336Sbill ss = clrnd(SSIZE + btoc(nargc)); 314912Sbill if (chksize(ts, ds, ss)) 315912Sbill goto bad; 3164827Swnj 3174827Swnj /* 3184827Swnj * Make sure enough space to start process. 3194827Swnj */ 320912Sbill u.u_cdmap = zdmap; 321912Sbill u.u_csmap = zdmap; 322912Sbill if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL) 323912Sbill goto bad; 32436Sbill 325912Sbill /* 326912Sbill * At this point, committed to the new image! 327912Sbill * Release virtual memory resources of old process, and 328912Sbill * initialize the virtual memory of the new process. 329912Sbill * If we resulted from vfork(), instead wakeup our 330912Sbill * parent who will set SVFDONE when he has taken back 331912Sbill * our resources. 332912Sbill */ 333912Sbill u.u_prof.pr_scale = 0; 334912Sbill if ((u.u_procp->p_flag & SVFORK) == 0) 335912Sbill vrelvm(); 336912Sbill else { 337912Sbill u.u_procp->p_flag &= ~SVFORK; 338912Sbill u.u_procp->p_flag |= SKEEP; 339912Sbill wakeup((caddr_t)u.u_procp); 340912Sbill while ((u.u_procp->p_flag & SVFDONE) == 0) 341912Sbill sleep((caddr_t)u.u_procp, PZERO - 1); 342912Sbill u.u_procp->p_flag &= ~(SVFDONE|SKEEP); 343912Sbill } 3443592Swnj u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SNUSIG); 345912Sbill u.u_procp->p_flag |= pagi; 346912Sbill u.u_dmap = u.u_cdmap; 347912Sbill u.u_smap = u.u_csmap; 348912Sbill vgetvm(ts, ds, ss); 349912Sbill 350912Sbill if (pagi == 0) { 35136Sbill /* 352912Sbill * Read in data segment. 35336Sbill */ 354912Sbill u.u_base = (char *)ctob(ts); 355912Sbill u.u_offset = sizeof(u.u_exdata)+u.u_exdata.ux_tsize; 356912Sbill u.u_count = u.u_exdata.ux_dsize; 357912Sbill readi(ip); 358912Sbill } 359912Sbill xalloc(ip, pagi); 360912Sbill if (pagi && u.u_procp->p_textp) 361912Sbill vinifod((struct fpte *)dptopte(u.u_procp, 0), 362912Sbill PG_FTEXT, u.u_procp->p_textp->x_iptr, 363912Sbill 1 + ts/CLSIZE, (int)btoc(u.u_exdata.ux_dsize)); 36436Sbill 365912Sbill /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */ 366912Sbill mtpr(TBIA, 0); 36736Sbill 368912Sbill /* 369912Sbill * set SUID/SGID protections, if no tracing 370912Sbill */ 371912Sbill if ((u.u_procp->p_flag&STRC)==0) { 3724827Swnj u.u_uid = uid; 3734827Swnj u.u_procp->p_uid = uid; 3742301Skre u.u_gid = gid; 3755856Swnj u.u_grps[gid/(sizeof(int)*8)] |= 1 << (gid%(sizeof(int)*8)); 376912Sbill } else 377912Sbill psignal(u.u_procp, SIGTRAP); 37836Sbill u.u_tsize = ts; 37936Sbill u.u_dsize = ds; 38036Sbill u.u_ssize = ss; 38136Sbill bad: 382912Sbill return; 38336Sbill } 38436Sbill 38536Sbill /* 38636Sbill * Clear registers on exec 38736Sbill */ 38836Sbill setregs() 38936Sbill { 390173Sbill register int (**rp)(); 39136Sbill register i; 392188Sbill long sigmask; 39336Sbill 3944827Swnj for (rp = &u.u_signal[0], sigmask = 1L; rp < &u.u_signal[NSIG]; 395188Sbill sigmask <<= 1, rp++) { 396188Sbill switch (*rp) { 397188Sbill 398188Sbill case SIG_IGN: 399188Sbill case SIG_DFL: 400188Sbill case SIG_HOLD: 401188Sbill continue; 402188Sbill 403188Sbill default: 404188Sbill /* 405206Sbill * Normal or deferring catch; revert to default. 406188Sbill */ 407206Sbill (void) spl6(); 408206Sbill *rp = SIG_DFL; 409188Sbill if ((int)*rp & 1) 410188Sbill u.u_procp->p_siga0 |= sigmask; 411188Sbill else 412188Sbill u.u_procp->p_siga1 &= ~sigmask; 413188Sbill if ((int)*rp & 2) 414188Sbill u.u_procp->p_siga1 |= sigmask; 415188Sbill else 416188Sbill u.u_procp->p_siga1 &= ~sigmask; 417206Sbill (void) spl0(); 418188Sbill continue; 419188Sbill } 420188Sbill } 42136Sbill /* 4224827Swnj for (rp = &u.u_ar0[0]; rp < &u.u_ar0[16];) 42336Sbill *rp++ = 0; 42436Sbill */ 42536Sbill u.u_ar0[PC] = u.u_exdata.ux_entloc + 2; /* skip over entry mask */ 4264827Swnj for (i=0; i<NOFILE; i++) { 42736Sbill if (u.u_pofile[i]&EXCLOSE) { 4285581Swnj closef(u.u_ofile[i], 1); 42936Sbill u.u_ofile[i] = NULL; 430188Sbill u.u_pofile[i] &= ~EXCLOSE; 43136Sbill } 43236Sbill } 4334827Swnj 43436Sbill /* 43536Sbill * Remember file name for accounting. 43636Sbill */ 43736Sbill u.u_acflag &= ~AFORK; 43836Sbill bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_comm, DIRSIZ); 43936Sbill } 44036Sbill 44136Sbill /* 4424827Swnj * Exit system call: pass back caller's arg 44336Sbill */ 44436Sbill rexit() 44536Sbill { 44636Sbill register struct a { 44736Sbill int rval; 44836Sbill } *uap; 44936Sbill 45036Sbill uap = (struct a *)u.u_ap; 45136Sbill exit((uap->rval & 0377) << 8); 45236Sbill } 45336Sbill 45436Sbill /* 45536Sbill * Release resources. 45636Sbill * Save u. area for parent to look at. 45736Sbill * Enter zombie state. 45836Sbill * Wake up parent and init processes, 45936Sbill * and dispose of children. 46036Sbill */ 46136Sbill exit(rv) 46236Sbill { 46336Sbill register int i; 46436Sbill register struct proc *p, *q; 46536Sbill register struct file *f; 46636Sbill register int x; 46736Sbill 46836Sbill #ifdef PGINPROF 46936Sbill vmsizmon(); 47036Sbill #endif 47136Sbill p = u.u_procp; 47236Sbill p->p_flag &= ~(STRC|SULOCK); 47336Sbill p->p_flag |= SWEXIT; 47436Sbill p->p_clktim = 0; 475188Sbill (void) spl6(); 476188Sbill if ((int)SIG_IGN & 1) 477188Sbill p->p_siga0 = ~0; 478188Sbill else 479188Sbill p->p_siga0 = 0; 480188Sbill if ((int)SIG_IGN & 2) 481188Sbill p->p_siga1 = ~0; 482188Sbill else 483206Sbill p->p_siga1 = 0; 484188Sbill (void) spl0(); 4851399Sbill p->p_cpticks = 0; 4861399Sbill p->p_pctcpu = 0; 4874827Swnj for (i=0; i<NSIG; i++) 488173Sbill u.u_signal[i] = SIG_IGN; 48936Sbill /* 49036Sbill * Release virtual memory. If we resulted from 49136Sbill * a vfork(), instead give the resources back to 49236Sbill * the parent. 49336Sbill */ 49436Sbill if ((p->p_flag & SVFORK) == 0) 49536Sbill vrelvm(); 49636Sbill else { 49736Sbill p->p_flag &= ~SVFORK; 49836Sbill wakeup((caddr_t)p); 49936Sbill while ((p->p_flag & SVFDONE) == 0) 50036Sbill sleep((caddr_t)p, PZERO - 1); 50136Sbill p->p_flag &= ~SVFDONE; 50236Sbill } 5034827Swnj for (i=0; i<NOFILE; i++) { 50436Sbill f = u.u_ofile[i]; 50536Sbill u.u_ofile[i] = NULL; 5065581Swnj closef(f, 1); 50736Sbill } 5084827Swnj ilock(u.u_cdir); 50936Sbill iput(u.u_cdir); 51036Sbill if (u.u_rdir) { 5114827Swnj ilock(u.u_rdir); 51236Sbill iput(u.u_rdir); 51336Sbill } 514363Sbill u.u_limit[LIM_FSIZE] = INFINITY; 51536Sbill acct(); 51636Sbill vrelpt(u.u_procp); 51736Sbill vrelu(u.u_procp, 0); 5185630Swnj (void) spl5(); /* hack for mem alloc race XXX */ 51936Sbill multprog--; 520931Sbill p->p_stat = SZOMB; 521307Sbill noproc = 1; 52236Sbill i = PIDHASH(p->p_pid); 52336Sbill x = p - proc; 52436Sbill if (pidhash[i] == x) 52536Sbill pidhash[i] = p->p_idhash; 52636Sbill else { 52736Sbill for (i = pidhash[i]; i != 0; i = proc[i].p_idhash) 52836Sbill if (proc[i].p_idhash == x) { 52936Sbill proc[i].p_idhash = p->p_idhash; 53036Sbill goto done; 53136Sbill } 53236Sbill panic("exit"); 53336Sbill } 5341409Sbill if (p->p_pid == 1) 5351409Sbill panic("init died"); 53636Sbill done: 53736Sbill ((struct xproc *)p)->xp_xstat = rv; /* overlay */ 53836Sbill ((struct xproc *)p)->xp_vm = u.u_vm; /* overlay */ 53936Sbill vmsadd(&((struct xproc *)p)->xp_vm, &u.u_cvm); 5404827Swnj for (q = proc; q < procNPROC; q++) 5414827Swnj if (q->p_pptr == p) { 542188Sbill q->p_pptr = &proc[1]; 543188Sbill q->p_ppid = 1; 54436Sbill wakeup((caddr_t)&proc[1]); 545188Sbill /* 546212Sbill * Traced processes are killed 547188Sbill * since their existence means someone is screwing up. 548354Sbill * Stopped processes are sent a hangup and a continue. 549212Sbill * This is designed to be ``safe'' for setuid 550212Sbill * processes since they must be willing to tolerate 551212Sbill * hangups anyways. 552188Sbill */ 553212Sbill if (q->p_flag&STRC) { 554188Sbill q->p_flag &= ~STRC; 555188Sbill psignal(q, SIGKILL); 556212Sbill } else if (q->p_stat == SSTOP) { 557212Sbill psignal(q, SIGHUP); 558212Sbill psignal(q, SIGCONT); 559188Sbill } 560215Sbill /* 561215Sbill * Protect this process from future 5625619Swnj * tty signals, clear TSTP/TTIN/TTOU if pending. 563215Sbill */ 5641788Sbill (void) spgrp(q, -1); 56536Sbill } 566188Sbill wakeup((caddr_t)p->p_pptr); 567188Sbill psignal(p->p_pptr, SIGCHLD); 56836Sbill swtch(); 56936Sbill } 57036Sbill 57136Sbill wait() 57236Sbill { 573188Sbill struct vtimes vm; 574188Sbill struct vtimes *vp; 57536Sbill 576188Sbill if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) { 577188Sbill wait1(0, (struct vtimes *)0); 578188Sbill return; 579188Sbill } 580188Sbill vp = (struct vtimes *)u.u_ar0[R1]; 581188Sbill wait1(u.u_ar0[R0], &vm); 582188Sbill if (u.u_error) 583188Sbill return; 584188Sbill (void) copyout((caddr_t)&vm, (caddr_t)vp, sizeof (struct vtimes)); 58536Sbill } 58636Sbill 58736Sbill /* 58836Sbill * Wait system call. 58936Sbill * Search for a terminated (zombie) child, 59036Sbill * finally lay it to rest, and collect its status. 59136Sbill * Look also for stopped (traced) children, 59236Sbill * and pass back status from them. 59336Sbill */ 594188Sbill wait1(options, vp) 595188Sbill register options; 59636Sbill struct vtimes *vp; 59736Sbill { 59836Sbill register f; 59936Sbill register struct proc *p; 60036Sbill 60136Sbill f = 0; 60236Sbill loop: 6034827Swnj for (p = proc; p < procNPROC; p++) 6044827Swnj if (p->p_pptr == u.u_procp) { 60536Sbill f++; 6064827Swnj if (p->p_stat == SZOMB) { 60736Sbill u.u_r.r_val1 = p->p_pid; 60836Sbill u.u_r.r_val2 = ((struct xproc *)p)->xp_xstat; 60936Sbill ((struct xproc *)p)->xp_xstat = 0; 61036Sbill if (vp) 61136Sbill *vp = ((struct xproc *)p)->xp_vm; 61236Sbill vmsadd(&u.u_cvm, &((struct xproc *)p)->xp_vm); 61336Sbill ((struct xproc *)p)->xp_vm = zvms; 61436Sbill p->p_stat = NULL; 61536Sbill p->p_pid = 0; 61636Sbill p->p_ppid = 0; 617188Sbill p->p_pptr = 0; 61836Sbill p->p_sig = 0; 619188Sbill p->p_siga0 = 0; 620188Sbill p->p_siga1 = 0; 62136Sbill p->p_pgrp = 0; 62236Sbill p->p_flag = 0; 62336Sbill p->p_wchan = 0; 624188Sbill p->p_cursig = 0; 62536Sbill return; 62636Sbill } 627188Sbill if (p->p_stat == SSTOP && (p->p_flag&SWTED)==0 && 628188Sbill (p->p_flag&STRC || options&WUNTRACED)) { 629188Sbill p->p_flag |= SWTED; 630188Sbill u.u_r.r_val1 = p->p_pid; 631188Sbill u.u_r.r_val2 = (p->p_cursig<<8) | WSTOPPED; 632188Sbill return; 63336Sbill } 63436Sbill } 635188Sbill if (f==0) { 636188Sbill u.u_error = ECHILD; 637188Sbill return; 63836Sbill } 639188Sbill if (options&WNOHANG) { 640188Sbill u.u_r.r_val1 = 0; 641188Sbill return; 642188Sbill } 643912Sbill if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { 644188Sbill u.u_eosys = RESTARTSYS; 645188Sbill return; 646188Sbill } 647188Sbill sleep((caddr_t)u.u_procp, PWAIT); 648188Sbill goto loop; 64936Sbill } 65036Sbill 65136Sbill /* 65236Sbill * fork system call. 65336Sbill */ 65436Sbill fork() 65536Sbill { 65636Sbill 65736Sbill u.u_cdmap = zdmap; 65836Sbill u.u_csmap = zdmap; 65936Sbill if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 66036Sbill u.u_r.r_val2 = 0; 66136Sbill return; 66236Sbill } 66336Sbill fork1(0); 66436Sbill } 66536Sbill 66636Sbill fork1(isvfork) 66736Sbill { 66836Sbill register struct proc *p1, *p2; 66936Sbill register a; 67036Sbill 67136Sbill a = 0; 67236Sbill p2 = NULL; 6734827Swnj for (p1 = proc; p1 < procNPROC; p1++) { 67436Sbill if (p1->p_stat==NULL && p2==NULL) 67536Sbill p2 = p1; 67636Sbill else { 67736Sbill if (p1->p_uid==u.u_uid && p1->p_stat!=NULL) 67836Sbill a++; 67936Sbill } 68036Sbill } 68136Sbill /* 68236Sbill * Disallow if 68336Sbill * No processes at all; 68436Sbill * not su and too many procs owned; or 68536Sbill * not su and would take last slot. 68636Sbill */ 6872938Swnj if (p2==NULL) 6882938Swnj tablefull("proc"); 6892741Swnj if (p2==NULL || (u.u_uid!=0 && (p2==procNPROC-1 || a>MAXUPRC))) { 69036Sbill u.u_error = EAGAIN; 69136Sbill if (!isvfork) { 692132Sbill (void) vsexpand(0, &u.u_cdmap, 1); 693132Sbill (void) vsexpand(0, &u.u_csmap, 1); 69436Sbill } 69536Sbill goto out; 69636Sbill } 69736Sbill p1 = u.u_procp; 6984827Swnj if (newproc(isvfork)) { 69936Sbill u.u_r.r_val1 = p1->p_pid; 70036Sbill u.u_r.r_val2 = 1; /* child */ 70136Sbill u.u_start = time; 70236Sbill u.u_acflag = AFORK; 70336Sbill return; 70436Sbill } 70536Sbill u.u_r.r_val1 = p2->p_pid; 70636Sbill 70736Sbill out: 70836Sbill u.u_r.r_val2 = 0; 70936Sbill } 71036Sbill 71136Sbill /* 71236Sbill * break system call. 71336Sbill * -- bad planning: "break" is a dirty word in C. 71436Sbill */ 71536Sbill sbreak() 71636Sbill { 71736Sbill struct a { 71836Sbill char *nsiz; 71936Sbill }; 72036Sbill register int n, d; 72136Sbill 72236Sbill /* 72336Sbill * set n to new data size 72436Sbill * set d to new-old 72536Sbill */ 72636Sbill 72736Sbill n = btoc(((struct a *)u.u_ap)->nsiz); 72836Sbill if (!u.u_sep) 72936Sbill n -= ctos(u.u_tsize) * stoc(1); 73036Sbill if (n < 0) 73136Sbill n = 0; 73236Sbill d = clrnd(n - u.u_dsize); 733368Sbill if (ctob(u.u_dsize+d) > u.u_limit[LIM_DATA]) { 734363Sbill u.u_error = ENOMEM; 735363Sbill return; 736363Sbill } 73736Sbill if (chksize(u.u_tsize, u.u_dsize+d, u.u_ssize)) 73836Sbill return; 73936Sbill if (swpexpand(u.u_dsize+d, u.u_ssize, &u.u_dmap, &u.u_smap)==0) 74036Sbill return; 74136Sbill expand(d, P0BR); 74236Sbill } 743