1*5619Swnj /* kern_proc.c 4.19 82/01/24 */ 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); 51736Sbill multprog--; 518931Sbill p->p_stat = SZOMB; 519307Sbill noproc = 1; 52036Sbill i = PIDHASH(p->p_pid); 52136Sbill x = p - proc; 52236Sbill if (pidhash[i] == x) 52336Sbill pidhash[i] = p->p_idhash; 52436Sbill else { 52536Sbill for (i = pidhash[i]; i != 0; i = proc[i].p_idhash) 52636Sbill if (proc[i].p_idhash == x) { 52736Sbill proc[i].p_idhash = p->p_idhash; 52836Sbill goto done; 52936Sbill } 53036Sbill panic("exit"); 53136Sbill } 5321409Sbill if (p->p_pid == 1) 5331409Sbill panic("init died"); 53436Sbill done: 53536Sbill ((struct xproc *)p)->xp_xstat = rv; /* overlay */ 53636Sbill ((struct xproc *)p)->xp_vm = u.u_vm; /* overlay */ 53736Sbill vmsadd(&((struct xproc *)p)->xp_vm, &u.u_cvm); 5384827Swnj for (q = proc; q < procNPROC; q++) 5394827Swnj if (q->p_pptr == p) { 540188Sbill q->p_pptr = &proc[1]; 541188Sbill q->p_ppid = 1; 54236Sbill wakeup((caddr_t)&proc[1]); 543188Sbill /* 544212Sbill * Traced processes are killed 545188Sbill * since their existence means someone is screwing up. 546354Sbill * Stopped processes are sent a hangup and a continue. 547212Sbill * This is designed to be ``safe'' for setuid 548212Sbill * processes since they must be willing to tolerate 549212Sbill * hangups anyways. 550188Sbill */ 551212Sbill if (q->p_flag&STRC) { 552188Sbill q->p_flag &= ~STRC; 553188Sbill psignal(q, SIGKILL); 554212Sbill } else if (q->p_stat == SSTOP) { 555212Sbill psignal(q, SIGHUP); 556212Sbill psignal(q, SIGCONT); 557188Sbill } 558215Sbill /* 559215Sbill * Protect this process from future 560*5619Swnj * tty signals, clear TSTP/TTIN/TTOU if pending. 561215Sbill */ 5621788Sbill (void) spgrp(q, -1); 56336Sbill } 564188Sbill wakeup((caddr_t)p->p_pptr); 565188Sbill psignal(p->p_pptr, SIGCHLD); 56636Sbill swtch(); 56736Sbill } 56836Sbill 56936Sbill wait() 57036Sbill { 571188Sbill struct vtimes vm; 572188Sbill struct vtimes *vp; 57336Sbill 574188Sbill if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) { 575188Sbill wait1(0, (struct vtimes *)0); 576188Sbill return; 577188Sbill } 578188Sbill vp = (struct vtimes *)u.u_ar0[R1]; 579188Sbill wait1(u.u_ar0[R0], &vm); 580188Sbill if (u.u_error) 581188Sbill return; 582188Sbill (void) copyout((caddr_t)&vm, (caddr_t)vp, sizeof (struct vtimes)); 58336Sbill } 58436Sbill 58536Sbill /* 58636Sbill * Wait system call. 58736Sbill * Search for a terminated (zombie) child, 58836Sbill * finally lay it to rest, and collect its status. 58936Sbill * Look also for stopped (traced) children, 59036Sbill * and pass back status from them. 59136Sbill */ 592188Sbill wait1(options, vp) 593188Sbill register options; 59436Sbill struct vtimes *vp; 59536Sbill { 59636Sbill register f; 59736Sbill register struct proc *p; 59836Sbill 59936Sbill f = 0; 60036Sbill loop: 6014827Swnj for (p = proc; p < procNPROC; p++) 6024827Swnj if (p->p_pptr == u.u_procp) { 60336Sbill f++; 6044827Swnj if (p->p_stat == SZOMB) { 60536Sbill u.u_r.r_val1 = p->p_pid; 60636Sbill u.u_r.r_val2 = ((struct xproc *)p)->xp_xstat; 60736Sbill ((struct xproc *)p)->xp_xstat = 0; 60836Sbill if (vp) 60936Sbill *vp = ((struct xproc *)p)->xp_vm; 61036Sbill vmsadd(&u.u_cvm, &((struct xproc *)p)->xp_vm); 61136Sbill ((struct xproc *)p)->xp_vm = zvms; 61236Sbill p->p_stat = NULL; 61336Sbill p->p_pid = 0; 61436Sbill p->p_ppid = 0; 615188Sbill p->p_pptr = 0; 61636Sbill p->p_sig = 0; 617188Sbill p->p_siga0 = 0; 618188Sbill p->p_siga1 = 0; 61936Sbill p->p_pgrp = 0; 62036Sbill p->p_flag = 0; 62136Sbill p->p_wchan = 0; 622188Sbill p->p_cursig = 0; 62336Sbill return; 62436Sbill } 625188Sbill if (p->p_stat == SSTOP && (p->p_flag&SWTED)==0 && 626188Sbill (p->p_flag&STRC || options&WUNTRACED)) { 627188Sbill p->p_flag |= SWTED; 628188Sbill u.u_r.r_val1 = p->p_pid; 629188Sbill u.u_r.r_val2 = (p->p_cursig<<8) | WSTOPPED; 630188Sbill return; 63136Sbill } 63236Sbill } 633188Sbill if (f==0) { 634188Sbill u.u_error = ECHILD; 635188Sbill return; 63636Sbill } 637188Sbill if (options&WNOHANG) { 638188Sbill u.u_r.r_val1 = 0; 639188Sbill return; 640188Sbill } 641912Sbill if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { 642188Sbill u.u_eosys = RESTARTSYS; 643188Sbill return; 644188Sbill } 645188Sbill sleep((caddr_t)u.u_procp, PWAIT); 646188Sbill goto loop; 64736Sbill } 64836Sbill 64936Sbill /* 65036Sbill * fork system call. 65136Sbill */ 65236Sbill fork() 65336Sbill { 65436Sbill 65536Sbill u.u_cdmap = zdmap; 65636Sbill u.u_csmap = zdmap; 65736Sbill if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 65836Sbill u.u_r.r_val2 = 0; 65936Sbill return; 66036Sbill } 66136Sbill fork1(0); 66236Sbill } 66336Sbill 66436Sbill fork1(isvfork) 66536Sbill { 66636Sbill register struct proc *p1, *p2; 66736Sbill register a; 66836Sbill 66936Sbill a = 0; 67036Sbill p2 = NULL; 6714827Swnj for (p1 = proc; p1 < procNPROC; p1++) { 67236Sbill if (p1->p_stat==NULL && p2==NULL) 67336Sbill p2 = p1; 67436Sbill else { 67536Sbill if (p1->p_uid==u.u_uid && p1->p_stat!=NULL) 67636Sbill a++; 67736Sbill } 67836Sbill } 67936Sbill /* 68036Sbill * Disallow if 68136Sbill * No processes at all; 68236Sbill * not su and too many procs owned; or 68336Sbill * not su and would take last slot. 68436Sbill */ 6852938Swnj if (p2==NULL) 6862938Swnj tablefull("proc"); 6872741Swnj if (p2==NULL || (u.u_uid!=0 && (p2==procNPROC-1 || a>MAXUPRC))) { 68836Sbill u.u_error = EAGAIN; 68936Sbill if (!isvfork) { 690132Sbill (void) vsexpand(0, &u.u_cdmap, 1); 691132Sbill (void) vsexpand(0, &u.u_csmap, 1); 69236Sbill } 69336Sbill goto out; 69436Sbill } 69536Sbill p1 = u.u_procp; 6964827Swnj if (newproc(isvfork)) { 69736Sbill u.u_r.r_val1 = p1->p_pid; 69836Sbill u.u_r.r_val2 = 1; /* child */ 69936Sbill u.u_start = time; 70036Sbill u.u_acflag = AFORK; 70136Sbill return; 70236Sbill } 70336Sbill u.u_r.r_val1 = p2->p_pid; 70436Sbill 70536Sbill out: 70636Sbill u.u_r.r_val2 = 0; 70736Sbill } 70836Sbill 70936Sbill /* 71036Sbill * break system call. 71136Sbill * -- bad planning: "break" is a dirty word in C. 71236Sbill */ 71336Sbill sbreak() 71436Sbill { 71536Sbill struct a { 71636Sbill char *nsiz; 71736Sbill }; 71836Sbill register int n, d; 71936Sbill 72036Sbill /* 72136Sbill * set n to new data size 72236Sbill * set d to new-old 72336Sbill */ 72436Sbill 72536Sbill n = btoc(((struct a *)u.u_ap)->nsiz); 72636Sbill if (!u.u_sep) 72736Sbill n -= ctos(u.u_tsize) * stoc(1); 72836Sbill if (n < 0) 72936Sbill n = 0; 73036Sbill d = clrnd(n - u.u_dsize); 731368Sbill if (ctob(u.u_dsize+d) > u.u_limit[LIM_DATA]) { 732363Sbill u.u_error = ENOMEM; 733363Sbill return; 734363Sbill } 73536Sbill if (chksize(u.u_tsize, u.u_dsize+d, u.u_ssize)) 73636Sbill return; 73736Sbill if (swpexpand(u.u_dsize+d, u.u_ssize, &u.u_dmap, &u.u_smap)==0) 73836Sbill return; 73936Sbill expand(d, P0BR); 74036Sbill } 741