1*7530Sroot /* kern_proc.c 4.29 82/07/25 */ 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" 227488Skre #include "../h/quota.h" 237497Sroot #include "../h/descrip.h" 2436Sbill 2536Sbill /* 2636Sbill * exec system call, with and without environments. 2736Sbill */ 2836Sbill struct execa { 2936Sbill char *fname; 3036Sbill char **argp; 3136Sbill char **envp; 3236Sbill }; 3336Sbill 3436Sbill exec() 3536Sbill { 3636Sbill ((struct execa *)u.u_ap)->envp = NULL; 3736Sbill exece(); 3836Sbill } 3936Sbill 4036Sbill exece() 4136Sbill { 4236Sbill register nc; 4336Sbill register char *cp; 4436Sbill register struct buf *bp; 4536Sbill register struct execa *uap; 4636Sbill int na, ne, ucp, ap, c; 472301Skre int indir, uid, gid; 482301Skre char *sharg; 4936Sbill struct inode *ip; 5036Sbill swblk_t bno; 516568Smckusic char cfname[MAXNAMLEN + 1]; 522301Skre char cfarg[SHSIZE]; 5336Sbill 545991Swnj if ((ip = namei(uchar, 0, 1)) == NULL) 5536Sbill return; 5636Sbill bno = 0; 5736Sbill bp = 0; 582301Skre indir = 0; 592301Skre uid = u.u_uid; 602301Skre gid = u.u_gid; 612301Skre if (ip->i_mode & ISUID) 622301Skre uid = ip->i_uid; 632301Skre if (ip->i_mode & ISGID) 642301Skre gid = ip->i_gid; 652301Skre 662301Skre again: 674827Swnj if (access(ip, IEXEC)) 6836Sbill goto bad; 694827Swnj if ((u.u_procp->p_flag&STRC) && access(ip, IREAD)) 702330Swnj goto bad; 714827Swnj if ((ip->i_mode & IFMT) != IFREG || 7236Sbill (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) { 7336Sbill u.u_error = EACCES; 7436Sbill goto bad; 7536Sbill } 762301Skre 7736Sbill /* 782301Skre * Read in first few bytes of file for segment sizes, ux_mag: 792301Skre * 407 = plain executable 802301Skre * 410 = RO text 812301Skre * 413 = demand paged RO text 822301Skre * Also an ASCII line beginning with #! is 832301Skre * the file name of a ``shell'' and arguments may be prepended 842301Skre * to the argument list if given here. 852301Skre * 862301Skre * SHELL NAMES ARE LIMITED IN LENGTH. 872301Skre * 882301Skre * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM 892301Skre * THE ASCII LINE. 902301Skre */ 912301Skre u.u_base = (caddr_t)&u.u_exdata; 922301Skre u.u_count = sizeof(u.u_exdata); 932301Skre u.u_offset = 0; 942301Skre u.u_segflg = 1; 952301Skre readi(ip); 962301Skre u.u_segflg = 0; 974827Swnj if (u.u_error) 982301Skre goto bad; 994982Swnj if (u.u_count > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) && 1004982Swnj u.u_exdata.ux_shell[0] != '#') { 1012301Skre u.u_error = ENOEXEC; 1022301Skre goto bad; 1032301Skre } 1042301Skre switch (u.u_exdata.ux_mag) { 1052301Skre 1062301Skre case 0407: 1072301Skre u.u_exdata.ux_dsize += u.u_exdata.ux_tsize; 1082301Skre u.u_exdata.ux_tsize = 0; 1092301Skre break; 1102301Skre 1112301Skre case 0413: 1122301Skre case 0410: 1132301Skre if (u.u_exdata.ux_tsize == 0) { 1142301Skre u.u_error = ENOEXEC; 1152301Skre goto bad; 1162301Skre } 1172301Skre break; 1182301Skre 1192301Skre default: 1202301Skre if (u.u_exdata.ux_shell[0] != '#' || 1212301Skre u.u_exdata.ux_shell[1] != '!' || 1222301Skre indir) { 1232301Skre u.u_error = ENOEXEC; 1242301Skre goto bad; 1252301Skre } 1262301Skre cp = &u.u_exdata.ux_shell[2]; /* skip "#!" */ 1272301Skre while (cp < &u.u_exdata.ux_shell[SHSIZE]) { 1282301Skre if (*cp == '\t') 1292301Skre *cp = ' '; 1302301Skre else if (*cp == '\n') { 1312301Skre *cp = '\0'; 1322301Skre break; 1332301Skre } 1342301Skre cp++; 1352301Skre } 1362301Skre if (*cp != '\0') { 1372301Skre u.u_error = ENOEXEC; 1382301Skre goto bad; 1392301Skre } 1402301Skre cp = &u.u_exdata.ux_shell[2]; 1412301Skre while (*cp == ' ') 1422301Skre cp++; 1432301Skre u.u_dirp = cp; 1442301Skre while (*cp && *cp != ' ') 1452301Skre cp++; 1462301Skre sharg = NULL; 1472301Skre if (*cp) { 1482301Skre *cp++ = '\0'; 1492301Skre while (*cp == ' ') 1502301Skre cp++; 1512301Skre if (*cp) { 1522301Skre bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE); 1532301Skre sharg = cfarg; 1542301Skre } 1552301Skre } 1566568Smckusic bcopy((caddr_t)u.u_dent.d_name, (caddr_t)cfname, 1576568Smckusic u.u_dent.d_namlen + 1); 1582301Skre indir = 1; 1592301Skre iput(ip); 1605991Swnj ip = namei(schar, 0, 1); 1612301Skre if (ip == NULL) 1622301Skre return; 1632301Skre goto again; 1642301Skre } 1652301Skre 1662301Skre /* 16736Sbill * Collect arguments on "file" in swap space. 16836Sbill */ 16936Sbill na = 0; 17036Sbill ne = 0; 17136Sbill nc = 0; 17236Sbill uap = (struct execa *)u.u_ap; 1732780Swnj if ((bno = rmalloc(argmap, ctod(clrnd((int) btoc(NCARGS))))) == 0) { 17436Sbill swkill(u.u_procp, "exece"); 17536Sbill goto bad; 17636Sbill } 17736Sbill if (bno % CLSIZE) 1782780Swnj panic("execa rmalloc"); 17936Sbill if (uap->argp) for (;;) { 18036Sbill ap = NULL; 1813621Sroot if (indir && (na == 1 || na == 2 && sharg)) 1822301Skre ap = (int)uap->fname; 1832301Skre else if (uap->argp) { 18436Sbill ap = fuword((caddr_t)uap->argp); 18536Sbill uap->argp++; 18636Sbill } 18736Sbill if (ap==NULL && uap->envp) { 18836Sbill uap->argp = NULL; 18936Sbill if ((ap = fuword((caddr_t)uap->envp)) == NULL) 19036Sbill break; 19136Sbill uap->envp++; 19236Sbill ne++; 19336Sbill } 1946568Smckusic if (ap == NULL) 19536Sbill break; 19636Sbill na++; 1974827Swnj if (ap == -1) 19836Sbill u.u_error = EFAULT; 19936Sbill do { 20036Sbill if (nc >= NCARGS-1) 20136Sbill u.u_error = E2BIG; 2022301Skre if (indir && na == 2 && sharg != NULL) 2032301Skre c = *sharg++ & 0377; 2042301Skre else if ((c = fubyte((caddr_t)ap++)) < 0) 20536Sbill u.u_error = EFAULT; 20683Sbill if (u.u_error) { 20783Sbill if (bp) 20883Sbill brelse(bp); 20983Sbill bp = 0; 21036Sbill goto badarg; 21183Sbill } 2126568Smckusic if (nc % (CLSIZE*NBPG) == 0) { 21336Sbill if (bp) 21436Sbill bdwrite(bp); 2156568Smckusic bp = getblk(argdev, bno + nc / NBPG, 2166568Smckusic CLSIZE*NBPG); 21736Sbill cp = bp->b_un.b_addr; 21836Sbill } 21936Sbill nc++; 22036Sbill *cp++ = c; 2216568Smckusic } while (c > 0); 22236Sbill } 22336Sbill if (bp) 22436Sbill bdwrite(bp); 22536Sbill bp = 0; 22636Sbill nc = (nc + NBPW-1) & ~(NBPW-1); 2276568Smckusic if (indir) { 2286568Smckusic u.u_dent.d_namlen = strlen(cfname); 2296568Smckusic bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name, 2306568Smckusic u.u_dent.d_namlen + 1); 2316568Smckusic } 2322301Skre getxfile(ip, nc + (na+4)*NBPW, uid, gid); 233912Sbill if (u.u_error) { 23436Sbill badarg: 2356568Smckusic for (c = 0; c < nc; c += CLSIZE*NBPG) 2366568Smckusic if (bp = baddr(argdev, bno + c / NBPG, CLSIZE*NBPG)) { 23736Sbill bp->b_flags |= B_AGE; /* throw away */ 23836Sbill bp->b_flags &= ~B_DELWRI; /* cancel io */ 23936Sbill brelse(bp); 24036Sbill bp = 0; 24136Sbill } 24236Sbill goto bad; 24336Sbill } 24436Sbill 24536Sbill /* 24636Sbill * copy back arglist 24736Sbill */ 24836Sbill ucp = USRSTACK - nc - NBPW; 24936Sbill ap = ucp - na*NBPW - 3*NBPW; 25036Sbill u.u_ar0[SP] = ap; 251132Sbill (void) suword((caddr_t)ap, na-ne); 25236Sbill nc = 0; 25336Sbill for (;;) { 25436Sbill ap += NBPW; 25536Sbill if (na==ne) { 256132Sbill (void) suword((caddr_t)ap, 0); 25736Sbill ap += NBPW; 25836Sbill } 25936Sbill if (--na < 0) 26036Sbill break; 261132Sbill (void) suword((caddr_t)ap, ucp); 26236Sbill do { 2636568Smckusic if (nc % (CLSIZE*NBPG) == 0) { 26436Sbill if (bp) 26536Sbill brelse(bp); 2666568Smckusic bp = bread(argdev, bno + nc / NBPG, 2676568Smckusic CLSIZE*NBPG); 26836Sbill bp->b_flags |= B_AGE; /* throw away */ 26936Sbill bp->b_flags &= ~B_DELWRI; /* cancel io */ 27036Sbill cp = bp->b_un.b_addr; 27136Sbill } 272132Sbill (void) subyte((caddr_t)ucp++, (c = *cp++)); 27336Sbill nc++; 27436Sbill } while(c&0377); 27536Sbill } 276132Sbill (void) suword((caddr_t)ap, 0); 277132Sbill (void) suword((caddr_t)ucp, 0); 27836Sbill setregs(); 27936Sbill bad: 28036Sbill if (bp) 28136Sbill brelse(bp); 28236Sbill if (bno) 2832780Swnj rmfree(argmap, ctod(clrnd((int) btoc(NCARGS))), bno); 28436Sbill iput(ip); 28536Sbill } 28636Sbill 28736Sbill /* 28836Sbill * Read in and set up memory for executed file. 28936Sbill */ 2902301Skre getxfile(ip, nargc, uid, gid) 29136Sbill register struct inode *ip; 29236Sbill { 29336Sbill register size_t ts, ds, ss; 2942301Skre int pagi; 29536Sbill 2962301Skre if (u.u_exdata.ux_mag == 0413) 29736Sbill pagi = SPAGI; 2982301Skre else 2992301Skre pagi = 0; 3004827Swnj if (u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && 3014827Swnj ip->i_count!=1) { 302890Sbill register struct file *fp; 303890Sbill 3044827Swnj for (fp = file; fp < fileNFILE; fp++) { 3057497Sroot if (fp->f_type == DTYPE_FILE && 3067497Sroot fp->f_inode == ip && (fp->f_flag&FWRITE)) { 307890Sbill u.u_error = ETXTBSY; 308890Sbill goto bad; 309890Sbill } 3104827Swnj } 31136Sbill } 31236Sbill 31336Sbill /* 3144827Swnj * Compute text and data sizes and make sure not too large. 31536Sbill */ 31636Sbill ts = clrnd(btoc(u.u_exdata.ux_tsize)); 31736Sbill ds = clrnd(btoc((u.u_exdata.ux_dsize+u.u_exdata.ux_bsize))); 31836Sbill ss = clrnd(SSIZE + btoc(nargc)); 319912Sbill if (chksize(ts, ds, ss)) 320912Sbill goto bad; 3214827Swnj 3224827Swnj /* 3234827Swnj * Make sure enough space to start process. 3244827Swnj */ 325912Sbill u.u_cdmap = zdmap; 326912Sbill u.u_csmap = zdmap; 327912Sbill if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL) 328912Sbill goto bad; 32936Sbill 330912Sbill /* 331912Sbill * At this point, committed to the new image! 332912Sbill * Release virtual memory resources of old process, and 333912Sbill * initialize the virtual memory of the new process. 334912Sbill * If we resulted from vfork(), instead wakeup our 335912Sbill * parent who will set SVFDONE when he has taken back 336912Sbill * our resources. 337912Sbill */ 338912Sbill u.u_prof.pr_scale = 0; 339912Sbill if ((u.u_procp->p_flag & SVFORK) == 0) 340912Sbill vrelvm(); 341912Sbill else { 342912Sbill u.u_procp->p_flag &= ~SVFORK; 343912Sbill u.u_procp->p_flag |= SKEEP; 344912Sbill wakeup((caddr_t)u.u_procp); 345912Sbill while ((u.u_procp->p_flag & SVFDONE) == 0) 346912Sbill sleep((caddr_t)u.u_procp, PZERO - 1); 347912Sbill u.u_procp->p_flag &= ~(SVFDONE|SKEEP); 348912Sbill } 3493592Swnj u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SNUSIG); 350912Sbill u.u_procp->p_flag |= pagi; 351912Sbill u.u_dmap = u.u_cdmap; 352912Sbill u.u_smap = u.u_csmap; 353912Sbill vgetvm(ts, ds, ss); 354912Sbill 355912Sbill if (pagi == 0) { 35636Sbill /* 357912Sbill * Read in data segment. 35836Sbill */ 359912Sbill u.u_base = (char *)ctob(ts); 360912Sbill u.u_offset = sizeof(u.u_exdata)+u.u_exdata.ux_tsize; 361912Sbill u.u_count = u.u_exdata.ux_dsize; 362912Sbill readi(ip); 363912Sbill } 364912Sbill xalloc(ip, pagi); 365912Sbill if (pagi && u.u_procp->p_textp) 366912Sbill vinifod((struct fpte *)dptopte(u.u_procp, 0), 367912Sbill PG_FTEXT, u.u_procp->p_textp->x_iptr, 368912Sbill 1 + ts/CLSIZE, (int)btoc(u.u_exdata.ux_dsize)); 36936Sbill 370912Sbill /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */ 371912Sbill mtpr(TBIA, 0); 37236Sbill 373*7530Sroot if (u.u_error) 374*7530Sroot swkill(u.u_procp, "i/o error mapping pages"); 375912Sbill /* 376912Sbill * set SUID/SGID protections, if no tracing 377912Sbill */ 378912Sbill if ((u.u_procp->p_flag&STRC)==0) { 3794827Swnj u.u_uid = uid; 3804827Swnj u.u_procp->p_uid = uid; 3812301Skre u.u_gid = gid; 3825856Swnj u.u_grps[gid/(sizeof(int)*8)] |= 1 << (gid%(sizeof(int)*8)); 383912Sbill } else 384912Sbill psignal(u.u_procp, SIGTRAP); 38536Sbill u.u_tsize = ts; 38636Sbill u.u_dsize = ds; 38736Sbill u.u_ssize = ss; 38836Sbill bad: 389912Sbill return; 39036Sbill } 39136Sbill 39236Sbill /* 39336Sbill * Clear registers on exec 39436Sbill */ 39536Sbill setregs() 39636Sbill { 397173Sbill register int (**rp)(); 39836Sbill register i; 399188Sbill long sigmask; 40036Sbill 4016464Swnj for (rp = &u.u_signal[1], sigmask = 1L; rp < &u.u_signal[NSIG]; 402188Sbill sigmask <<= 1, rp++) { 403188Sbill switch (*rp) { 404188Sbill 405188Sbill case SIG_IGN: 406188Sbill case SIG_DFL: 407188Sbill case SIG_HOLD: 408188Sbill continue; 409188Sbill 410188Sbill default: 411188Sbill /* 412206Sbill * Normal or deferring catch; revert to default. 413188Sbill */ 414206Sbill (void) spl6(); 415206Sbill *rp = SIG_DFL; 416188Sbill if ((int)*rp & 1) 417188Sbill u.u_procp->p_siga0 |= sigmask; 418188Sbill else 4196327Swnj u.u_procp->p_siga0 &= ~sigmask; 420188Sbill if ((int)*rp & 2) 421188Sbill u.u_procp->p_siga1 |= sigmask; 422188Sbill else 423188Sbill u.u_procp->p_siga1 &= ~sigmask; 424206Sbill (void) spl0(); 425188Sbill continue; 426188Sbill } 427188Sbill } 42836Sbill /* 4294827Swnj for (rp = &u.u_ar0[0]; rp < &u.u_ar0[16];) 43036Sbill *rp++ = 0; 43136Sbill */ 43236Sbill u.u_ar0[PC] = u.u_exdata.ux_entloc + 2; /* skip over entry mask */ 4334827Swnj for (i=0; i<NOFILE; i++) { 43436Sbill if (u.u_pofile[i]&EXCLOSE) { 4355581Swnj closef(u.u_ofile[i], 1); 43636Sbill u.u_ofile[i] = NULL; 437188Sbill u.u_pofile[i] &= ~EXCLOSE; 43836Sbill } 43936Sbill } 4404827Swnj 44136Sbill /* 44236Sbill * Remember file name for accounting. 44336Sbill */ 44436Sbill u.u_acflag &= ~AFORK; 4456568Smckusic bcopy((caddr_t)u.u_dent.d_name, (caddr_t)u.u_comm, 4466568Smckusic u.u_dent.d_namlen + 1); 44736Sbill } 44836Sbill 44936Sbill /* 4504827Swnj * Exit system call: pass back caller's arg 45136Sbill */ 45236Sbill rexit() 45336Sbill { 45436Sbill register struct a { 45536Sbill int rval; 45636Sbill } *uap; 45736Sbill 45836Sbill uap = (struct a *)u.u_ap; 45936Sbill exit((uap->rval & 0377) << 8); 46036Sbill } 46136Sbill 46236Sbill /* 46336Sbill * Release resources. 46436Sbill * Save u. area for parent to look at. 46536Sbill * Enter zombie state. 46636Sbill * Wake up parent and init processes, 46736Sbill * and dispose of children. 46836Sbill */ 46936Sbill exit(rv) 47036Sbill { 47136Sbill register int i; 47236Sbill register struct proc *p, *q; 47336Sbill register struct file *f; 47436Sbill register int x; 47536Sbill 47636Sbill #ifdef PGINPROF 47736Sbill vmsizmon(); 47836Sbill #endif 47936Sbill p = u.u_procp; 48036Sbill p->p_flag &= ~(STRC|SULOCK); 48136Sbill p->p_flag |= SWEXIT; 48236Sbill p->p_clktim = 0; 483188Sbill (void) spl6(); 484188Sbill if ((int)SIG_IGN & 1) 485188Sbill p->p_siga0 = ~0; 486188Sbill else 487188Sbill p->p_siga0 = 0; 488188Sbill if ((int)SIG_IGN & 2) 489188Sbill p->p_siga1 = ~0; 490188Sbill else 491206Sbill p->p_siga1 = 0; 492188Sbill (void) spl0(); 4931399Sbill p->p_cpticks = 0; 4941399Sbill p->p_pctcpu = 0; 4954827Swnj for (i=0; i<NSIG; i++) 496173Sbill u.u_signal[i] = SIG_IGN; 49736Sbill /* 49836Sbill * Release virtual memory. If we resulted from 49936Sbill * a vfork(), instead give the resources back to 50036Sbill * the parent. 50136Sbill */ 50236Sbill if ((p->p_flag & SVFORK) == 0) 50336Sbill vrelvm(); 50436Sbill else { 50536Sbill p->p_flag &= ~SVFORK; 50636Sbill wakeup((caddr_t)p); 50736Sbill while ((p->p_flag & SVFDONE) == 0) 50836Sbill sleep((caddr_t)p, PZERO - 1); 50936Sbill p->p_flag &= ~SVFDONE; 51036Sbill } 5114827Swnj for (i=0; i<NOFILE; i++) { 51236Sbill f = u.u_ofile[i]; 51336Sbill u.u_ofile[i] = NULL; 5145581Swnj closef(f, 1); 51536Sbill } 5164827Swnj ilock(u.u_cdir); 51736Sbill iput(u.u_cdir); 51836Sbill if (u.u_rdir) { 5194827Swnj ilock(u.u_rdir); 52036Sbill iput(u.u_rdir); 52136Sbill } 522363Sbill u.u_limit[LIM_FSIZE] = INFINITY; 52336Sbill acct(); 5247488Skre #ifdef QUOTA 5257488Skre qclean(); 5267488Skre #endif 52736Sbill vrelpt(u.u_procp); 52836Sbill vrelu(u.u_procp, 0); 5295630Swnj (void) spl5(); /* hack for mem alloc race XXX */ 53036Sbill multprog--; 531931Sbill p->p_stat = SZOMB; 532307Sbill noproc = 1; 53336Sbill i = PIDHASH(p->p_pid); 53436Sbill x = p - proc; 53536Sbill if (pidhash[i] == x) 53636Sbill pidhash[i] = p->p_idhash; 53736Sbill else { 53836Sbill for (i = pidhash[i]; i != 0; i = proc[i].p_idhash) 53936Sbill if (proc[i].p_idhash == x) { 54036Sbill proc[i].p_idhash = p->p_idhash; 54136Sbill goto done; 54236Sbill } 54336Sbill panic("exit"); 54436Sbill } 5451409Sbill if (p->p_pid == 1) 5461409Sbill panic("init died"); 54736Sbill done: 54836Sbill ((struct xproc *)p)->xp_xstat = rv; /* overlay */ 54936Sbill ((struct xproc *)p)->xp_vm = u.u_vm; /* overlay */ 55036Sbill vmsadd(&((struct xproc *)p)->xp_vm, &u.u_cvm); 5514827Swnj for (q = proc; q < procNPROC; q++) 5524827Swnj if (q->p_pptr == p) { 5537488Skre if (q->p_osptr) 5547488Skre q->p_osptr->p_ysptr = q->p_ysptr; 5557488Skre if (q->p_ysptr) 5567488Skre q->p_ysptr->p_osptr = q->p_osptr; 5577488Skre if (proc[1].p_cptr) 5587488Skre proc[1].p_cptr->p_ysptr = q; 5597488Skre q->p_osptr = proc[1].p_cptr; 5607488Skre q->p_ysptr = NULL; 5617488Skre proc[1].p_cptr = q; 5627488Skre 563188Sbill q->p_pptr = &proc[1]; 564188Sbill q->p_ppid = 1; 56536Sbill wakeup((caddr_t)&proc[1]); 566188Sbill /* 567212Sbill * Traced processes are killed 568188Sbill * since their existence means someone is screwing up. 569354Sbill * Stopped processes are sent a hangup and a continue. 570212Sbill * This is designed to be ``safe'' for setuid 571212Sbill * processes since they must be willing to tolerate 572212Sbill * hangups anyways. 573188Sbill */ 574212Sbill if (q->p_flag&STRC) { 575188Sbill q->p_flag &= ~STRC; 576188Sbill psignal(q, SIGKILL); 577212Sbill } else if (q->p_stat == SSTOP) { 578212Sbill psignal(q, SIGHUP); 579212Sbill psignal(q, SIGCONT); 580188Sbill } 581215Sbill /* 582215Sbill * Protect this process from future 5835619Swnj * tty signals, clear TSTP/TTIN/TTOU if pending. 584215Sbill */ 5851788Sbill (void) spgrp(q, -1); 58636Sbill } 5876464Swnj psignal(p->p_pptr, SIGCHLD); 588188Sbill wakeup((caddr_t)p->p_pptr); 58936Sbill swtch(); 59036Sbill } 59136Sbill 59236Sbill wait() 59336Sbill { 594188Sbill struct vtimes vm; 595188Sbill struct vtimes *vp; 59636Sbill 597188Sbill if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) { 598188Sbill wait1(0, (struct vtimes *)0); 599188Sbill return; 600188Sbill } 601188Sbill vp = (struct vtimes *)u.u_ar0[R1]; 602188Sbill wait1(u.u_ar0[R0], &vm); 603188Sbill if (u.u_error) 604188Sbill return; 605188Sbill (void) copyout((caddr_t)&vm, (caddr_t)vp, sizeof (struct vtimes)); 60636Sbill } 60736Sbill 60836Sbill /* 60936Sbill * Wait system call. 61036Sbill * Search for a terminated (zombie) child, 61136Sbill * finally lay it to rest, and collect its status. 61236Sbill * Look also for stopped (traced) children, 61336Sbill * and pass back status from them. 61436Sbill */ 615188Sbill wait1(options, vp) 616188Sbill register options; 61736Sbill struct vtimes *vp; 61836Sbill { 61936Sbill register f; 6207488Skre register struct proc *p, *q; 62136Sbill 62236Sbill f = 0; 62336Sbill loop: 6244827Swnj for (p = proc; p < procNPROC; p++) 6254827Swnj if (p->p_pptr == u.u_procp) { 62636Sbill f++; 6274827Swnj if (p->p_stat == SZOMB) { 62836Sbill u.u_r.r_val1 = p->p_pid; 62936Sbill u.u_r.r_val2 = ((struct xproc *)p)->xp_xstat; 63036Sbill ((struct xproc *)p)->xp_xstat = 0; 63136Sbill if (vp) 63236Sbill *vp = ((struct xproc *)p)->xp_vm; 63336Sbill vmsadd(&u.u_cvm, &((struct xproc *)p)->xp_vm); 63436Sbill ((struct xproc *)p)->xp_vm = zvms; 63536Sbill p->p_stat = NULL; 63636Sbill p->p_pid = 0; 63736Sbill p->p_ppid = 0; 6387488Skre if (q = p->p_ysptr) 6397488Skre q->p_osptr = p->p_osptr; 6407488Skre if (q = p->p_osptr) 6417488Skre q->p_ysptr = p->p_ysptr; 6427488Skre if ((q = p->p_pptr)->p_cptr == p) 6437488Skre q->p_cptr = p->p_osptr; 644188Sbill p->p_pptr = 0; 6457488Skre p->p_ysptr = 0; 6467488Skre p->p_osptr = 0; 6477488Skre p->p_cptr = 0; 64836Sbill p->p_sig = 0; 649188Sbill p->p_siga0 = 0; 650188Sbill p->p_siga1 = 0; 65136Sbill p->p_pgrp = 0; 65236Sbill p->p_flag = 0; 65336Sbill p->p_wchan = 0; 654188Sbill p->p_cursig = 0; 65536Sbill return; 65636Sbill } 657188Sbill if (p->p_stat == SSTOP && (p->p_flag&SWTED)==0 && 658188Sbill (p->p_flag&STRC || options&WUNTRACED)) { 659188Sbill p->p_flag |= SWTED; 660188Sbill u.u_r.r_val1 = p->p_pid; 661188Sbill u.u_r.r_val2 = (p->p_cursig<<8) | WSTOPPED; 662188Sbill return; 66336Sbill } 66436Sbill } 665188Sbill if (f==0) { 666188Sbill u.u_error = ECHILD; 667188Sbill return; 66836Sbill } 669188Sbill if (options&WNOHANG) { 670188Sbill u.u_r.r_val1 = 0; 671188Sbill return; 672188Sbill } 673912Sbill if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { 674188Sbill u.u_eosys = RESTARTSYS; 675188Sbill return; 676188Sbill } 677188Sbill sleep((caddr_t)u.u_procp, PWAIT); 678188Sbill goto loop; 67936Sbill } 68036Sbill 68136Sbill /* 68236Sbill * fork system call. 68336Sbill */ 68436Sbill fork() 68536Sbill { 68636Sbill 68736Sbill u.u_cdmap = zdmap; 68836Sbill u.u_csmap = zdmap; 68936Sbill if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 69036Sbill u.u_r.r_val2 = 0; 69136Sbill return; 69236Sbill } 69336Sbill fork1(0); 69436Sbill } 69536Sbill 69636Sbill fork1(isvfork) 69736Sbill { 69836Sbill register struct proc *p1, *p2; 6997488Skre #ifndef QUOTA 70036Sbill register a; 70136Sbill 70236Sbill a = 0; 7037488Skre #else 7047488Skre if (u.u_quota != NOQUOT && u.u_quota->q_plim && 7057488Skre u.u_quota->q_cnt >= u.u_quota->q_plim) { 7067488Skre u.u_error = EPROCLIM; 7077488Skre return; 7087488Skre } 7097488Skre #endif 71036Sbill p2 = NULL; 7114827Swnj for (p1 = proc; p1 < procNPROC; p1++) { 7127488Skre #ifdef QUOTA 7137488Skre if (p1->p_stat == NULL) { 7147488Skre p2 = p1; 7157488Skre break; 7167488Skre } 7177488Skre #else 71836Sbill if (p1->p_stat==NULL && p2==NULL) 71936Sbill p2 = p1; 72036Sbill else { 72136Sbill if (p1->p_uid==u.u_uid && p1->p_stat!=NULL) 72236Sbill a++; 72336Sbill } 7247488Skre #endif 72536Sbill } 72636Sbill /* 72736Sbill * Disallow if 72836Sbill * No processes at all; 72936Sbill * not su and too many procs owned; or 73036Sbill * not su and would take last slot. 73136Sbill */ 7322938Swnj if (p2==NULL) 7332938Swnj tablefull("proc"); 7347488Skre #ifdef QUOTA 7357488Skre if (p2==NULL || (u.u_uid!=0 && p2==procNPROC-1)) { 7367488Skre #else 7372741Swnj if (p2==NULL || (u.u_uid!=0 && (p2==procNPROC-1 || a>MAXUPRC))) { 7387488Skre #endif 73936Sbill u.u_error = EAGAIN; 74036Sbill if (!isvfork) { 741132Sbill (void) vsexpand(0, &u.u_cdmap, 1); 742132Sbill (void) vsexpand(0, &u.u_csmap, 1); 74336Sbill } 74436Sbill goto out; 74536Sbill } 74636Sbill p1 = u.u_procp; 7474827Swnj if (newproc(isvfork)) { 74836Sbill u.u_r.r_val1 = p1->p_pid; 74936Sbill u.u_r.r_val2 = 1; /* child */ 75036Sbill u.u_start = time; 75136Sbill u.u_acflag = AFORK; 7527488Skre #ifdef QUOTA 7537488Skre u.u_qflags &= ~QUF_LOGIN; 7547488Skre #endif 75536Sbill return; 75636Sbill } 75736Sbill u.u_r.r_val1 = p2->p_pid; 75836Sbill 75936Sbill out: 76036Sbill u.u_r.r_val2 = 0; 76136Sbill } 76236Sbill 7637497Sroot spgrp(top, npgrp) 7647497Sroot register struct proc *top; 7657497Sroot { 7667497Sroot register struct proc *pp, *p; 7677497Sroot int f = 0; 7687497Sroot 7697497Sroot for (p = top; npgrp == -1 || u.u_uid == p->p_uid || 7707497Sroot !u.u_uid || inferior(p); p = pp) { 7717497Sroot if (npgrp == -1) { 7727497Sroot #define bit(a) (1<<(a-1)) 7737497Sroot p->p_sig &= ~(bit(SIGTSTP)|bit(SIGTTIN)|bit(SIGTTOU)); 7747497Sroot } else 7757497Sroot p->p_pgrp = npgrp; 7767497Sroot f++; 7777497Sroot /* 7787497Sroot * Search for children. 7797497Sroot */ 7807497Sroot for (pp = proc; pp < procNPROC; pp++) 7817497Sroot if (pp->p_pptr == p) 7827497Sroot goto cont; 7837497Sroot /* 7847497Sroot * Search for siblings. 7857497Sroot */ 7867497Sroot for (; p != top; p = p->p_pptr) 7877497Sroot for (pp = p + 1; pp < procNPROC; pp++) 7887497Sroot if (pp->p_pptr == p->p_pptr) 7897497Sroot goto cont; 7907497Sroot break; 7917497Sroot cont: 7927497Sroot ; 7937497Sroot } 7947497Sroot return (f); 7957497Sroot } 7967497Sroot 79736Sbill /* 7987497Sroot * Is p an inferior of the current process? 79936Sbill */ 8007497Sroot inferior(p) 8017497Sroot register struct proc *p; 80236Sbill { 80336Sbill 8047497Sroot for (; p != u.u_procp; p = p->p_pptr) 8057497Sroot if (p->p_ppid == 0) 8067497Sroot return (0); 8077497Sroot return (1); 80836Sbill } 809