1*5630Swnj /* kern_proc.c 4.21 82/01/30 */ 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 5236Sbill if ((ip = namei(uchar, 0)) == 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); 1572301Skre ip = namei(schar, 0); 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; 375912Sbill } else 376912Sbill psignal(u.u_procp, SIGTRAP); 37736Sbill u.u_tsize = ts; 37836Sbill u.u_dsize = ds; 37936Sbill u.u_ssize = ss; 38036Sbill bad: 381912Sbill return; 38236Sbill } 38336Sbill 38436Sbill /* 38536Sbill * Clear registers on exec 38636Sbill */ 38736Sbill setregs() 38836Sbill { 389173Sbill register int (**rp)(); 39036Sbill register i; 391188Sbill long sigmask; 39236Sbill 3934827Swnj for (rp = &u.u_signal[0], sigmask = 1L; rp < &u.u_signal[NSIG]; 394188Sbill sigmask <<= 1, rp++) { 395188Sbill switch (*rp) { 396188Sbill 397188Sbill case SIG_IGN: 398188Sbill case SIG_DFL: 399188Sbill case SIG_HOLD: 400188Sbill continue; 401188Sbill 402188Sbill default: 403188Sbill /* 404206Sbill * Normal or deferring catch; revert to default. 405188Sbill */ 406206Sbill (void) spl6(); 407206Sbill *rp = SIG_DFL; 408188Sbill if ((int)*rp & 1) 409188Sbill u.u_procp->p_siga0 |= sigmask; 410188Sbill else 411188Sbill u.u_procp->p_siga1 &= ~sigmask; 412188Sbill if ((int)*rp & 2) 413188Sbill u.u_procp->p_siga1 |= sigmask; 414188Sbill else 415188Sbill u.u_procp->p_siga1 &= ~sigmask; 416206Sbill (void) spl0(); 417188Sbill continue; 418188Sbill } 419188Sbill } 42036Sbill /* 4214827Swnj for (rp = &u.u_ar0[0]; rp < &u.u_ar0[16];) 42236Sbill *rp++ = 0; 42336Sbill */ 42436Sbill u.u_ar0[PC] = u.u_exdata.ux_entloc + 2; /* skip over entry mask */ 4254827Swnj for (i=0; i<NOFILE; i++) { 42636Sbill if (u.u_pofile[i]&EXCLOSE) { 4275581Swnj closef(u.u_ofile[i], 1); 42836Sbill u.u_ofile[i] = NULL; 429188Sbill u.u_pofile[i] &= ~EXCLOSE; 43036Sbill } 43136Sbill } 4324827Swnj 43336Sbill /* 43436Sbill * Remember file name for accounting. 43536Sbill */ 43636Sbill u.u_acflag &= ~AFORK; 43736Sbill bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_comm, DIRSIZ); 43836Sbill } 43936Sbill 44036Sbill /* 4414827Swnj * Exit system call: pass back caller's arg 44236Sbill */ 44336Sbill rexit() 44436Sbill { 44536Sbill register struct a { 44636Sbill int rval; 44736Sbill } *uap; 44836Sbill 44936Sbill uap = (struct a *)u.u_ap; 45036Sbill exit((uap->rval & 0377) << 8); 45136Sbill } 45236Sbill 45336Sbill /* 45436Sbill * Release resources. 45536Sbill * Save u. area for parent to look at. 45636Sbill * Enter zombie state. 45736Sbill * Wake up parent and init processes, 45836Sbill * and dispose of children. 45936Sbill */ 46036Sbill exit(rv) 46136Sbill { 46236Sbill register int i; 46336Sbill register struct proc *p, *q; 46436Sbill register struct file *f; 46536Sbill register int x; 46636Sbill 46736Sbill #ifdef PGINPROF 46836Sbill vmsizmon(); 46936Sbill #endif 47036Sbill p = u.u_procp; 47136Sbill p->p_flag &= ~(STRC|SULOCK); 47236Sbill p->p_flag |= SWEXIT; 47336Sbill p->p_clktim = 0; 474188Sbill (void) spl6(); 475188Sbill if ((int)SIG_IGN & 1) 476188Sbill p->p_siga0 = ~0; 477188Sbill else 478188Sbill p->p_siga0 = 0; 479188Sbill if ((int)SIG_IGN & 2) 480188Sbill p->p_siga1 = ~0; 481188Sbill else 482206Sbill p->p_siga1 = 0; 483188Sbill (void) spl0(); 4841399Sbill p->p_cpticks = 0; 4851399Sbill p->p_pctcpu = 0; 4864827Swnj for (i=0; i<NSIG; i++) 487173Sbill u.u_signal[i] = SIG_IGN; 48836Sbill /* 48936Sbill * Release virtual memory. If we resulted from 49036Sbill * a vfork(), instead give the resources back to 49136Sbill * the parent. 49236Sbill */ 49336Sbill if ((p->p_flag & SVFORK) == 0) 49436Sbill vrelvm(); 49536Sbill else { 49636Sbill p->p_flag &= ~SVFORK; 49736Sbill wakeup((caddr_t)p); 49836Sbill while ((p->p_flag & SVFDONE) == 0) 49936Sbill sleep((caddr_t)p, PZERO - 1); 50036Sbill p->p_flag &= ~SVFDONE; 50136Sbill } 5024827Swnj for (i=0; i<NOFILE; i++) { 50336Sbill f = u.u_ofile[i]; 50436Sbill u.u_ofile[i] = NULL; 5055581Swnj closef(f, 1); 50636Sbill } 5074827Swnj ilock(u.u_cdir); 50836Sbill iput(u.u_cdir); 50936Sbill if (u.u_rdir) { 5104827Swnj ilock(u.u_rdir); 51136Sbill iput(u.u_rdir); 51236Sbill } 513363Sbill u.u_limit[LIM_FSIZE] = INFINITY; 51436Sbill acct(); 51536Sbill vrelpt(u.u_procp); 51636Sbill vrelu(u.u_procp, 0); 517*5630Swnj (void) spl5(); /* hack for mem alloc race XXX */ 51836Sbill multprog--; 519931Sbill p->p_stat = SZOMB; 520307Sbill noproc = 1; 52136Sbill i = PIDHASH(p->p_pid); 52236Sbill x = p - proc; 52336Sbill if (pidhash[i] == x) 52436Sbill pidhash[i] = p->p_idhash; 52536Sbill else { 52636Sbill for (i = pidhash[i]; i != 0; i = proc[i].p_idhash) 52736Sbill if (proc[i].p_idhash == x) { 52836Sbill proc[i].p_idhash = p->p_idhash; 52936Sbill goto done; 53036Sbill } 53136Sbill panic("exit"); 53236Sbill } 5331409Sbill if (p->p_pid == 1) 5341409Sbill panic("init died"); 53536Sbill done: 53636Sbill ((struct xproc *)p)->xp_xstat = rv; /* overlay */ 53736Sbill ((struct xproc *)p)->xp_vm = u.u_vm; /* overlay */ 53836Sbill vmsadd(&((struct xproc *)p)->xp_vm, &u.u_cvm); 5394827Swnj for (q = proc; q < procNPROC; q++) 5404827Swnj if (q->p_pptr == p) { 541188Sbill q->p_pptr = &proc[1]; 542188Sbill q->p_ppid = 1; 54336Sbill wakeup((caddr_t)&proc[1]); 544188Sbill /* 545212Sbill * Traced processes are killed 546188Sbill * since their existence means someone is screwing up. 547354Sbill * Stopped processes are sent a hangup and a continue. 548212Sbill * This is designed to be ``safe'' for setuid 549212Sbill * processes since they must be willing to tolerate 550212Sbill * hangups anyways. 551188Sbill */ 552212Sbill if (q->p_flag&STRC) { 553188Sbill q->p_flag &= ~STRC; 554188Sbill psignal(q, SIGKILL); 555212Sbill } else if (q->p_stat == SSTOP) { 556212Sbill psignal(q, SIGHUP); 557212Sbill psignal(q, SIGCONT); 558188Sbill } 559215Sbill /* 560215Sbill * Protect this process from future 5615619Swnj * tty signals, clear TSTP/TTIN/TTOU if pending. 562215Sbill */ 5631788Sbill (void) spgrp(q, -1); 56436Sbill } 565188Sbill wakeup((caddr_t)p->p_pptr); 566188Sbill psignal(p->p_pptr, SIGCHLD); 56736Sbill swtch(); 56836Sbill } 56936Sbill 57036Sbill wait() 57136Sbill { 572188Sbill struct vtimes vm; 573188Sbill struct vtimes *vp; 57436Sbill 575188Sbill if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) { 576188Sbill wait1(0, (struct vtimes *)0); 577188Sbill return; 578188Sbill } 579188Sbill vp = (struct vtimes *)u.u_ar0[R1]; 580188Sbill wait1(u.u_ar0[R0], &vm); 581188Sbill if (u.u_error) 582188Sbill return; 583188Sbill (void) copyout((caddr_t)&vm, (caddr_t)vp, sizeof (struct vtimes)); 58436Sbill } 58536Sbill 58636Sbill /* 58736Sbill * Wait system call. 58836Sbill * Search for a terminated (zombie) child, 58936Sbill * finally lay it to rest, and collect its status. 59036Sbill * Look also for stopped (traced) children, 59136Sbill * and pass back status from them. 59236Sbill */ 593188Sbill wait1(options, vp) 594188Sbill register options; 59536Sbill struct vtimes *vp; 59636Sbill { 59736Sbill register f; 59836Sbill register struct proc *p; 59936Sbill 60036Sbill f = 0; 60136Sbill loop: 6024827Swnj for (p = proc; p < procNPROC; p++) 6034827Swnj if (p->p_pptr == u.u_procp) { 60436Sbill f++; 6054827Swnj if (p->p_stat == SZOMB) { 60636Sbill u.u_r.r_val1 = p->p_pid; 60736Sbill u.u_r.r_val2 = ((struct xproc *)p)->xp_xstat; 60836Sbill ((struct xproc *)p)->xp_xstat = 0; 60936Sbill if (vp) 61036Sbill *vp = ((struct xproc *)p)->xp_vm; 61136Sbill vmsadd(&u.u_cvm, &((struct xproc *)p)->xp_vm); 61236Sbill ((struct xproc *)p)->xp_vm = zvms; 61336Sbill p->p_stat = NULL; 61436Sbill p->p_pid = 0; 61536Sbill p->p_ppid = 0; 616188Sbill p->p_pptr = 0; 61736Sbill p->p_sig = 0; 618188Sbill p->p_siga0 = 0; 619188Sbill p->p_siga1 = 0; 62036Sbill p->p_pgrp = 0; 62136Sbill p->p_flag = 0; 62236Sbill p->p_wchan = 0; 623188Sbill p->p_cursig = 0; 62436Sbill return; 62536Sbill } 626188Sbill if (p->p_stat == SSTOP && (p->p_flag&SWTED)==0 && 627188Sbill (p->p_flag&STRC || options&WUNTRACED)) { 628188Sbill p->p_flag |= SWTED; 629188Sbill u.u_r.r_val1 = p->p_pid; 630188Sbill u.u_r.r_val2 = (p->p_cursig<<8) | WSTOPPED; 631188Sbill return; 63236Sbill } 63336Sbill } 634188Sbill if (f==0) { 635188Sbill u.u_error = ECHILD; 636188Sbill return; 63736Sbill } 638188Sbill if (options&WNOHANG) { 639188Sbill u.u_r.r_val1 = 0; 640188Sbill return; 641188Sbill } 642912Sbill if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { 643188Sbill u.u_eosys = RESTARTSYS; 644188Sbill return; 645188Sbill } 646188Sbill sleep((caddr_t)u.u_procp, PWAIT); 647188Sbill goto loop; 64836Sbill } 64936Sbill 65036Sbill /* 65136Sbill * fork system call. 65236Sbill */ 65336Sbill fork() 65436Sbill { 65536Sbill 65636Sbill u.u_cdmap = zdmap; 65736Sbill u.u_csmap = zdmap; 65836Sbill if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 65936Sbill u.u_r.r_val2 = 0; 66036Sbill return; 66136Sbill } 66236Sbill fork1(0); 66336Sbill } 66436Sbill 66536Sbill fork1(isvfork) 66636Sbill { 66736Sbill register struct proc *p1, *p2; 66836Sbill register a; 66936Sbill 67036Sbill a = 0; 67136Sbill p2 = NULL; 6724827Swnj for (p1 = proc; p1 < procNPROC; p1++) { 67336Sbill if (p1->p_stat==NULL && p2==NULL) 67436Sbill p2 = p1; 67536Sbill else { 67636Sbill if (p1->p_uid==u.u_uid && p1->p_stat!=NULL) 67736Sbill a++; 67836Sbill } 67936Sbill } 68036Sbill /* 68136Sbill * Disallow if 68236Sbill * No processes at all; 68336Sbill * not su and too many procs owned; or 68436Sbill * not su and would take last slot. 68536Sbill */ 6862938Swnj if (p2==NULL) 6872938Swnj tablefull("proc"); 6882741Swnj if (p2==NULL || (u.u_uid!=0 && (p2==procNPROC-1 || a>MAXUPRC))) { 68936Sbill u.u_error = EAGAIN; 69036Sbill if (!isvfork) { 691132Sbill (void) vsexpand(0, &u.u_cdmap, 1); 692132Sbill (void) vsexpand(0, &u.u_csmap, 1); 69336Sbill } 69436Sbill goto out; 69536Sbill } 69636Sbill p1 = u.u_procp; 6974827Swnj if (newproc(isvfork)) { 69836Sbill u.u_r.r_val1 = p1->p_pid; 69936Sbill u.u_r.r_val2 = 1; /* child */ 70036Sbill u.u_start = time; 70136Sbill u.u_acflag = AFORK; 70236Sbill return; 70336Sbill } 70436Sbill u.u_r.r_val1 = p2->p_pid; 70536Sbill 70636Sbill out: 70736Sbill u.u_r.r_val2 = 0; 70836Sbill } 70936Sbill 71036Sbill /* 71136Sbill * break system call. 71236Sbill * -- bad planning: "break" is a dirty word in C. 71336Sbill */ 71436Sbill sbreak() 71536Sbill { 71636Sbill struct a { 71736Sbill char *nsiz; 71836Sbill }; 71936Sbill register int n, d; 72036Sbill 72136Sbill /* 72236Sbill * set n to new data size 72336Sbill * set d to new-old 72436Sbill */ 72536Sbill 72636Sbill n = btoc(((struct a *)u.u_ap)->nsiz); 72736Sbill if (!u.u_sep) 72836Sbill n -= ctos(u.u_tsize) * stoc(1); 72936Sbill if (n < 0) 73036Sbill n = 0; 73136Sbill d = clrnd(n - u.u_dsize); 732368Sbill if (ctob(u.u_dsize+d) > u.u_limit[LIM_DATA]) { 733363Sbill u.u_error = ENOMEM; 734363Sbill return; 735363Sbill } 73636Sbill if (chksize(u.u_tsize, u.u_dsize+d, u.u_ssize)) 73736Sbill return; 73836Sbill if (swpexpand(u.u_dsize+d, u.u_ssize, &u.u_dmap, &u.u_smap)==0) 73936Sbill return; 74036Sbill expand(d, P0BR); 74136Sbill } 742