1*7488Skre /* kern_proc.c 4.27 82/07/22 */ 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" 22*7488Skre #include "../h/quota.h" 2336Sbill 2436Sbill /* 2536Sbill * exec system call, with and without environments. 2636Sbill */ 2736Sbill struct execa { 2836Sbill char *fname; 2936Sbill char **argp; 3036Sbill char **envp; 3136Sbill }; 3236Sbill 3336Sbill exec() 3436Sbill { 3536Sbill ((struct execa *)u.u_ap)->envp = NULL; 3636Sbill exece(); 3736Sbill } 3836Sbill 3936Sbill exece() 4036Sbill { 4136Sbill register nc; 4236Sbill register char *cp; 4336Sbill register struct buf *bp; 4436Sbill register struct execa *uap; 4536Sbill int na, ne, ucp, ap, c; 462301Skre int indir, uid, gid; 472301Skre char *sharg; 4836Sbill struct inode *ip; 4936Sbill swblk_t bno; 506568Smckusic char cfname[MAXNAMLEN + 1]; 512301Skre char cfarg[SHSIZE]; 5236Sbill 535991Swnj if ((ip = namei(uchar, 0, 1)) == NULL) 5436Sbill return; 5536Sbill bno = 0; 5636Sbill bp = 0; 572301Skre indir = 0; 582301Skre uid = u.u_uid; 592301Skre gid = u.u_gid; 602301Skre if (ip->i_mode & ISUID) 612301Skre uid = ip->i_uid; 622301Skre if (ip->i_mode & ISGID) 632301Skre gid = ip->i_gid; 642301Skre 652301Skre again: 664827Swnj if (access(ip, IEXEC)) 6736Sbill goto bad; 684827Swnj if ((u.u_procp->p_flag&STRC) && access(ip, IREAD)) 692330Swnj goto bad; 704827Swnj if ((ip->i_mode & IFMT) != IFREG || 7136Sbill (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) { 7236Sbill u.u_error = EACCES; 7336Sbill goto bad; 7436Sbill } 752301Skre 7636Sbill /* 772301Skre * Read in first few bytes of file for segment sizes, ux_mag: 782301Skre * 407 = plain executable 792301Skre * 410 = RO text 802301Skre * 413 = demand paged RO text 812301Skre * Also an ASCII line beginning with #! is 822301Skre * the file name of a ``shell'' and arguments may be prepended 832301Skre * to the argument list if given here. 842301Skre * 852301Skre * SHELL NAMES ARE LIMITED IN LENGTH. 862301Skre * 872301Skre * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM 882301Skre * THE ASCII LINE. 892301Skre */ 902301Skre u.u_base = (caddr_t)&u.u_exdata; 912301Skre u.u_count = sizeof(u.u_exdata); 922301Skre u.u_offset = 0; 932301Skre u.u_segflg = 1; 942301Skre readi(ip); 952301Skre u.u_segflg = 0; 964827Swnj if (u.u_error) 972301Skre goto bad; 984982Swnj if (u.u_count > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) && 994982Swnj u.u_exdata.ux_shell[0] != '#') { 1002301Skre u.u_error = ENOEXEC; 1012301Skre goto bad; 1022301Skre } 1032301Skre switch (u.u_exdata.ux_mag) { 1042301Skre 1052301Skre case 0407: 1062301Skre u.u_exdata.ux_dsize += u.u_exdata.ux_tsize; 1072301Skre u.u_exdata.ux_tsize = 0; 1082301Skre break; 1092301Skre 1102301Skre case 0413: 1112301Skre case 0410: 1122301Skre if (u.u_exdata.ux_tsize == 0) { 1132301Skre u.u_error = ENOEXEC; 1142301Skre goto bad; 1152301Skre } 1162301Skre break; 1172301Skre 1182301Skre default: 1192301Skre if (u.u_exdata.ux_shell[0] != '#' || 1202301Skre u.u_exdata.ux_shell[1] != '!' || 1212301Skre indir) { 1222301Skre u.u_error = ENOEXEC; 1232301Skre goto bad; 1242301Skre } 1252301Skre cp = &u.u_exdata.ux_shell[2]; /* skip "#!" */ 1262301Skre while (cp < &u.u_exdata.ux_shell[SHSIZE]) { 1272301Skre if (*cp == '\t') 1282301Skre *cp = ' '; 1292301Skre else if (*cp == '\n') { 1302301Skre *cp = '\0'; 1312301Skre break; 1322301Skre } 1332301Skre cp++; 1342301Skre } 1352301Skre if (*cp != '\0') { 1362301Skre u.u_error = ENOEXEC; 1372301Skre goto bad; 1382301Skre } 1392301Skre cp = &u.u_exdata.ux_shell[2]; 1402301Skre while (*cp == ' ') 1412301Skre cp++; 1422301Skre u.u_dirp = cp; 1432301Skre while (*cp && *cp != ' ') 1442301Skre cp++; 1452301Skre sharg = NULL; 1462301Skre if (*cp) { 1472301Skre *cp++ = '\0'; 1482301Skre while (*cp == ' ') 1492301Skre cp++; 1502301Skre if (*cp) { 1512301Skre bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE); 1522301Skre sharg = cfarg; 1532301Skre } 1542301Skre } 1556568Smckusic bcopy((caddr_t)u.u_dent.d_name, (caddr_t)cfname, 1566568Smckusic u.u_dent.d_namlen + 1); 1572301Skre indir = 1; 1582301Skre iput(ip); 1595991Swnj ip = namei(schar, 0, 1); 1602301Skre if (ip == NULL) 1612301Skre return; 1622301Skre goto again; 1632301Skre } 1642301Skre 1652301Skre /* 16636Sbill * Collect arguments on "file" in swap space. 16736Sbill */ 16836Sbill na = 0; 16936Sbill ne = 0; 17036Sbill nc = 0; 17136Sbill uap = (struct execa *)u.u_ap; 1722780Swnj if ((bno = rmalloc(argmap, ctod(clrnd((int) btoc(NCARGS))))) == 0) { 17336Sbill swkill(u.u_procp, "exece"); 17436Sbill goto bad; 17536Sbill } 17636Sbill if (bno % CLSIZE) 1772780Swnj panic("execa rmalloc"); 17836Sbill if (uap->argp) for (;;) { 17936Sbill ap = NULL; 1803621Sroot if (indir && (na == 1 || na == 2 && sharg)) 1812301Skre ap = (int)uap->fname; 1822301Skre else if (uap->argp) { 18336Sbill ap = fuword((caddr_t)uap->argp); 18436Sbill uap->argp++; 18536Sbill } 18636Sbill if (ap==NULL && uap->envp) { 18736Sbill uap->argp = NULL; 18836Sbill if ((ap = fuword((caddr_t)uap->envp)) == NULL) 18936Sbill break; 19036Sbill uap->envp++; 19136Sbill ne++; 19236Sbill } 1936568Smckusic if (ap == NULL) 19436Sbill break; 19536Sbill na++; 1964827Swnj if (ap == -1) 19736Sbill u.u_error = EFAULT; 19836Sbill do { 19936Sbill if (nc >= NCARGS-1) 20036Sbill u.u_error = E2BIG; 2012301Skre if (indir && na == 2 && sharg != NULL) 2022301Skre c = *sharg++ & 0377; 2032301Skre else if ((c = fubyte((caddr_t)ap++)) < 0) 20436Sbill u.u_error = EFAULT; 20583Sbill if (u.u_error) { 20683Sbill if (bp) 20783Sbill brelse(bp); 20883Sbill bp = 0; 20936Sbill goto badarg; 21083Sbill } 2116568Smckusic if (nc % (CLSIZE*NBPG) == 0) { 21236Sbill if (bp) 21336Sbill bdwrite(bp); 2146568Smckusic bp = getblk(argdev, bno + nc / NBPG, 2156568Smckusic CLSIZE*NBPG); 21636Sbill cp = bp->b_un.b_addr; 21736Sbill } 21836Sbill nc++; 21936Sbill *cp++ = c; 2206568Smckusic } while (c > 0); 22136Sbill } 22236Sbill if (bp) 22336Sbill bdwrite(bp); 22436Sbill bp = 0; 22536Sbill nc = (nc + NBPW-1) & ~(NBPW-1); 2266568Smckusic if (indir) { 2276568Smckusic u.u_dent.d_namlen = strlen(cfname); 2286568Smckusic bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name, 2296568Smckusic u.u_dent.d_namlen + 1); 2306568Smckusic } 2312301Skre getxfile(ip, nc + (na+4)*NBPW, uid, gid); 232912Sbill if (u.u_error) { 23336Sbill badarg: 2346568Smckusic for (c = 0; c < nc; c += CLSIZE*NBPG) 2356568Smckusic if (bp = baddr(argdev, bno + c / NBPG, CLSIZE*NBPG)) { 23636Sbill bp->b_flags |= B_AGE; /* throw away */ 23736Sbill bp->b_flags &= ~B_DELWRI; /* cancel io */ 23836Sbill brelse(bp); 23936Sbill bp = 0; 24036Sbill } 24136Sbill goto bad; 24236Sbill } 24336Sbill 24436Sbill /* 24536Sbill * copy back arglist 24636Sbill */ 24736Sbill ucp = USRSTACK - nc - NBPW; 24836Sbill ap = ucp - na*NBPW - 3*NBPW; 24936Sbill u.u_ar0[SP] = ap; 250132Sbill (void) suword((caddr_t)ap, na-ne); 25136Sbill nc = 0; 25236Sbill for (;;) { 25336Sbill ap += NBPW; 25436Sbill if (na==ne) { 255132Sbill (void) suword((caddr_t)ap, 0); 25636Sbill ap += NBPW; 25736Sbill } 25836Sbill if (--na < 0) 25936Sbill break; 260132Sbill (void) suword((caddr_t)ap, ucp); 26136Sbill do { 2626568Smckusic if (nc % (CLSIZE*NBPG) == 0) { 26336Sbill if (bp) 26436Sbill brelse(bp); 2656568Smckusic bp = bread(argdev, bno + nc / NBPG, 2666568Smckusic CLSIZE*NBPG); 26736Sbill bp->b_flags |= B_AGE; /* throw away */ 26836Sbill bp->b_flags &= ~B_DELWRI; /* cancel io */ 26936Sbill cp = bp->b_un.b_addr; 27036Sbill } 271132Sbill (void) subyte((caddr_t)ucp++, (c = *cp++)); 27236Sbill nc++; 27336Sbill } while(c&0377); 27436Sbill } 275132Sbill (void) suword((caddr_t)ap, 0); 276132Sbill (void) suword((caddr_t)ucp, 0); 27736Sbill setregs(); 27836Sbill bad: 27936Sbill if (bp) 28036Sbill brelse(bp); 28136Sbill if (bno) 2822780Swnj rmfree(argmap, ctod(clrnd((int) btoc(NCARGS))), bno); 28336Sbill iput(ip); 28436Sbill } 28536Sbill 28636Sbill /* 28736Sbill * Read in and set up memory for executed file. 28836Sbill */ 2892301Skre getxfile(ip, nargc, uid, gid) 29036Sbill register struct inode *ip; 29136Sbill { 29236Sbill register size_t ts, ds, ss; 2932301Skre int pagi; 29436Sbill 2952301Skre if (u.u_exdata.ux_mag == 0413) 29636Sbill pagi = SPAGI; 2972301Skre else 2982301Skre pagi = 0; 2994827Swnj if (u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && 3004827Swnj ip->i_count!=1) { 301890Sbill register struct file *fp; 302890Sbill 3034827Swnj for (fp = file; fp < fileNFILE; fp++) { 3044827Swnj if (fp->f_flag & FSOCKET) 3054827Swnj continue; 306890Sbill if (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 373912Sbill /* 374912Sbill * set SUID/SGID protections, if no tracing 375912Sbill */ 376912Sbill if ((u.u_procp->p_flag&STRC)==0) { 3774827Swnj u.u_uid = uid; 3784827Swnj u.u_procp->p_uid = uid; 3792301Skre u.u_gid = gid; 3805856Swnj u.u_grps[gid/(sizeof(int)*8)] |= 1 << (gid%(sizeof(int)*8)); 381912Sbill } else 382912Sbill psignal(u.u_procp, SIGTRAP); 38336Sbill u.u_tsize = ts; 38436Sbill u.u_dsize = ds; 38536Sbill u.u_ssize = ss; 38636Sbill bad: 387912Sbill return; 38836Sbill } 38936Sbill 39036Sbill /* 39136Sbill * Clear registers on exec 39236Sbill */ 39336Sbill setregs() 39436Sbill { 395173Sbill register int (**rp)(); 39636Sbill register i; 397188Sbill long sigmask; 39836Sbill 3996464Swnj for (rp = &u.u_signal[1], sigmask = 1L; rp < &u.u_signal[NSIG]; 400188Sbill sigmask <<= 1, rp++) { 401188Sbill switch (*rp) { 402188Sbill 403188Sbill case SIG_IGN: 404188Sbill case SIG_DFL: 405188Sbill case SIG_HOLD: 406188Sbill continue; 407188Sbill 408188Sbill default: 409188Sbill /* 410206Sbill * Normal or deferring catch; revert to default. 411188Sbill */ 412206Sbill (void) spl6(); 413206Sbill *rp = SIG_DFL; 414188Sbill if ((int)*rp & 1) 415188Sbill u.u_procp->p_siga0 |= sigmask; 416188Sbill else 4176327Swnj u.u_procp->p_siga0 &= ~sigmask; 418188Sbill if ((int)*rp & 2) 419188Sbill u.u_procp->p_siga1 |= sigmask; 420188Sbill else 421188Sbill u.u_procp->p_siga1 &= ~sigmask; 422206Sbill (void) spl0(); 423188Sbill continue; 424188Sbill } 425188Sbill } 42636Sbill /* 4274827Swnj for (rp = &u.u_ar0[0]; rp < &u.u_ar0[16];) 42836Sbill *rp++ = 0; 42936Sbill */ 43036Sbill u.u_ar0[PC] = u.u_exdata.ux_entloc + 2; /* skip over entry mask */ 4314827Swnj for (i=0; i<NOFILE; i++) { 43236Sbill if (u.u_pofile[i]&EXCLOSE) { 4335581Swnj closef(u.u_ofile[i], 1); 43436Sbill u.u_ofile[i] = NULL; 435188Sbill u.u_pofile[i] &= ~EXCLOSE; 43636Sbill } 43736Sbill } 4384827Swnj 43936Sbill /* 44036Sbill * Remember file name for accounting. 44136Sbill */ 44236Sbill u.u_acflag &= ~AFORK; 4436568Smckusic bcopy((caddr_t)u.u_dent.d_name, (caddr_t)u.u_comm, 4446568Smckusic u.u_dent.d_namlen + 1); 44536Sbill } 44636Sbill 44736Sbill /* 4484827Swnj * Exit system call: pass back caller's arg 44936Sbill */ 45036Sbill rexit() 45136Sbill { 45236Sbill register struct a { 45336Sbill int rval; 45436Sbill } *uap; 45536Sbill 45636Sbill uap = (struct a *)u.u_ap; 45736Sbill exit((uap->rval & 0377) << 8); 45836Sbill } 45936Sbill 46036Sbill /* 46136Sbill * Release resources. 46236Sbill * Save u. area for parent to look at. 46336Sbill * Enter zombie state. 46436Sbill * Wake up parent and init processes, 46536Sbill * and dispose of children. 46636Sbill */ 46736Sbill exit(rv) 46836Sbill { 46936Sbill register int i; 47036Sbill register struct proc *p, *q; 47136Sbill register struct file *f; 47236Sbill register int x; 47336Sbill 47436Sbill #ifdef PGINPROF 47536Sbill vmsizmon(); 47636Sbill #endif 47736Sbill p = u.u_procp; 47836Sbill p->p_flag &= ~(STRC|SULOCK); 47936Sbill p->p_flag |= SWEXIT; 48036Sbill p->p_clktim = 0; 481188Sbill (void) spl6(); 482188Sbill if ((int)SIG_IGN & 1) 483188Sbill p->p_siga0 = ~0; 484188Sbill else 485188Sbill p->p_siga0 = 0; 486188Sbill if ((int)SIG_IGN & 2) 487188Sbill p->p_siga1 = ~0; 488188Sbill else 489206Sbill p->p_siga1 = 0; 490188Sbill (void) spl0(); 4911399Sbill p->p_cpticks = 0; 4921399Sbill p->p_pctcpu = 0; 4934827Swnj for (i=0; i<NSIG; i++) 494173Sbill u.u_signal[i] = SIG_IGN; 49536Sbill /* 49636Sbill * Release virtual memory. If we resulted from 49736Sbill * a vfork(), instead give the resources back to 49836Sbill * the parent. 49936Sbill */ 50036Sbill if ((p->p_flag & SVFORK) == 0) 50136Sbill vrelvm(); 50236Sbill else { 50336Sbill p->p_flag &= ~SVFORK; 50436Sbill wakeup((caddr_t)p); 50536Sbill while ((p->p_flag & SVFDONE) == 0) 50636Sbill sleep((caddr_t)p, PZERO - 1); 50736Sbill p->p_flag &= ~SVFDONE; 50836Sbill } 5094827Swnj for (i=0; i<NOFILE; i++) { 51036Sbill f = u.u_ofile[i]; 51136Sbill u.u_ofile[i] = NULL; 5125581Swnj closef(f, 1); 51336Sbill } 5144827Swnj ilock(u.u_cdir); 51536Sbill iput(u.u_cdir); 51636Sbill if (u.u_rdir) { 5174827Swnj ilock(u.u_rdir); 51836Sbill iput(u.u_rdir); 51936Sbill } 520363Sbill u.u_limit[LIM_FSIZE] = INFINITY; 52136Sbill acct(); 522*7488Skre #ifdef QUOTA 523*7488Skre qclean(); 524*7488Skre #endif 52536Sbill vrelpt(u.u_procp); 52636Sbill vrelu(u.u_procp, 0); 5275630Swnj (void) spl5(); /* hack for mem alloc race XXX */ 52836Sbill multprog--; 529931Sbill p->p_stat = SZOMB; 530307Sbill noproc = 1; 53136Sbill i = PIDHASH(p->p_pid); 53236Sbill x = p - proc; 53336Sbill if (pidhash[i] == x) 53436Sbill pidhash[i] = p->p_idhash; 53536Sbill else { 53636Sbill for (i = pidhash[i]; i != 0; i = proc[i].p_idhash) 53736Sbill if (proc[i].p_idhash == x) { 53836Sbill proc[i].p_idhash = p->p_idhash; 53936Sbill goto done; 54036Sbill } 54136Sbill panic("exit"); 54236Sbill } 5431409Sbill if (p->p_pid == 1) 5441409Sbill panic("init died"); 54536Sbill done: 54636Sbill ((struct xproc *)p)->xp_xstat = rv; /* overlay */ 54736Sbill ((struct xproc *)p)->xp_vm = u.u_vm; /* overlay */ 54836Sbill vmsadd(&((struct xproc *)p)->xp_vm, &u.u_cvm); 5494827Swnj for (q = proc; q < procNPROC; q++) 5504827Swnj if (q->p_pptr == p) { 551*7488Skre if (q->p_osptr) 552*7488Skre q->p_osptr->p_ysptr = q->p_ysptr; 553*7488Skre if (q->p_ysptr) 554*7488Skre q->p_ysptr->p_osptr = q->p_osptr; 555*7488Skre if (proc[1].p_cptr) 556*7488Skre proc[1].p_cptr->p_ysptr = q; 557*7488Skre q->p_osptr = proc[1].p_cptr; 558*7488Skre q->p_ysptr = NULL; 559*7488Skre proc[1].p_cptr = q; 560*7488Skre 561188Sbill q->p_pptr = &proc[1]; 562188Sbill q->p_ppid = 1; 56336Sbill wakeup((caddr_t)&proc[1]); 564188Sbill /* 565212Sbill * Traced processes are killed 566188Sbill * since their existence means someone is screwing up. 567354Sbill * Stopped processes are sent a hangup and a continue. 568212Sbill * This is designed to be ``safe'' for setuid 569212Sbill * processes since they must be willing to tolerate 570212Sbill * hangups anyways. 571188Sbill */ 572212Sbill if (q->p_flag&STRC) { 573188Sbill q->p_flag &= ~STRC; 574188Sbill psignal(q, SIGKILL); 575212Sbill } else if (q->p_stat == SSTOP) { 576212Sbill psignal(q, SIGHUP); 577212Sbill psignal(q, SIGCONT); 578188Sbill } 579215Sbill /* 580215Sbill * Protect this process from future 5815619Swnj * tty signals, clear TSTP/TTIN/TTOU if pending. 582215Sbill */ 5831788Sbill (void) spgrp(q, -1); 58436Sbill } 5856464Swnj psignal(p->p_pptr, SIGCHLD); 586188Sbill wakeup((caddr_t)p->p_pptr); 58736Sbill swtch(); 58836Sbill } 58936Sbill 59036Sbill wait() 59136Sbill { 592188Sbill struct vtimes vm; 593188Sbill struct vtimes *vp; 59436Sbill 595188Sbill if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) { 596188Sbill wait1(0, (struct vtimes *)0); 597188Sbill return; 598188Sbill } 599188Sbill vp = (struct vtimes *)u.u_ar0[R1]; 600188Sbill wait1(u.u_ar0[R0], &vm); 601188Sbill if (u.u_error) 602188Sbill return; 603188Sbill (void) copyout((caddr_t)&vm, (caddr_t)vp, sizeof (struct vtimes)); 60436Sbill } 60536Sbill 60636Sbill /* 60736Sbill * Wait system call. 60836Sbill * Search for a terminated (zombie) child, 60936Sbill * finally lay it to rest, and collect its status. 61036Sbill * Look also for stopped (traced) children, 61136Sbill * and pass back status from them. 61236Sbill */ 613188Sbill wait1(options, vp) 614188Sbill register options; 61536Sbill struct vtimes *vp; 61636Sbill { 61736Sbill register f; 618*7488Skre register struct proc *p, *q; 61936Sbill 62036Sbill f = 0; 62136Sbill loop: 6224827Swnj for (p = proc; p < procNPROC; p++) 6234827Swnj if (p->p_pptr == u.u_procp) { 62436Sbill f++; 6254827Swnj if (p->p_stat == SZOMB) { 62636Sbill u.u_r.r_val1 = p->p_pid; 62736Sbill u.u_r.r_val2 = ((struct xproc *)p)->xp_xstat; 62836Sbill ((struct xproc *)p)->xp_xstat = 0; 62936Sbill if (vp) 63036Sbill *vp = ((struct xproc *)p)->xp_vm; 63136Sbill vmsadd(&u.u_cvm, &((struct xproc *)p)->xp_vm); 63236Sbill ((struct xproc *)p)->xp_vm = zvms; 63336Sbill p->p_stat = NULL; 63436Sbill p->p_pid = 0; 63536Sbill p->p_ppid = 0; 636*7488Skre if (q = p->p_ysptr) 637*7488Skre q->p_osptr = p->p_osptr; 638*7488Skre if (q = p->p_osptr) 639*7488Skre q->p_ysptr = p->p_ysptr; 640*7488Skre if ((q = p->p_pptr)->p_cptr == p) 641*7488Skre q->p_cptr = p->p_osptr; 642188Sbill p->p_pptr = 0; 643*7488Skre p->p_ysptr = 0; 644*7488Skre p->p_osptr = 0; 645*7488Skre p->p_cptr = 0; 64636Sbill p->p_sig = 0; 647188Sbill p->p_siga0 = 0; 648188Sbill p->p_siga1 = 0; 64936Sbill p->p_pgrp = 0; 65036Sbill p->p_flag = 0; 65136Sbill p->p_wchan = 0; 652188Sbill p->p_cursig = 0; 65336Sbill return; 65436Sbill } 655188Sbill if (p->p_stat == SSTOP && (p->p_flag&SWTED)==0 && 656188Sbill (p->p_flag&STRC || options&WUNTRACED)) { 657188Sbill p->p_flag |= SWTED; 658188Sbill u.u_r.r_val1 = p->p_pid; 659188Sbill u.u_r.r_val2 = (p->p_cursig<<8) | WSTOPPED; 660188Sbill return; 66136Sbill } 66236Sbill } 663188Sbill if (f==0) { 664188Sbill u.u_error = ECHILD; 665188Sbill return; 66636Sbill } 667188Sbill if (options&WNOHANG) { 668188Sbill u.u_r.r_val1 = 0; 669188Sbill return; 670188Sbill } 671912Sbill if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { 672188Sbill u.u_eosys = RESTARTSYS; 673188Sbill return; 674188Sbill } 675188Sbill sleep((caddr_t)u.u_procp, PWAIT); 676188Sbill goto loop; 67736Sbill } 67836Sbill 67936Sbill /* 68036Sbill * fork system call. 68136Sbill */ 68236Sbill fork() 68336Sbill { 68436Sbill 68536Sbill u.u_cdmap = zdmap; 68636Sbill u.u_csmap = zdmap; 68736Sbill if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 68836Sbill u.u_r.r_val2 = 0; 68936Sbill return; 69036Sbill } 69136Sbill fork1(0); 69236Sbill } 69336Sbill 69436Sbill fork1(isvfork) 69536Sbill { 69636Sbill register struct proc *p1, *p2; 697*7488Skre #ifndef QUOTA 69836Sbill register a; 69936Sbill 70036Sbill a = 0; 701*7488Skre #else 702*7488Skre if (u.u_quota != NOQUOT && u.u_quota->q_plim && 703*7488Skre u.u_quota->q_cnt >= u.u_quota->q_plim) { 704*7488Skre u.u_error = EPROCLIM; 705*7488Skre return; 706*7488Skre } 707*7488Skre #endif 70836Sbill p2 = NULL; 7094827Swnj for (p1 = proc; p1 < procNPROC; p1++) { 710*7488Skre #ifdef QUOTA 711*7488Skre if (p1->p_stat == NULL) { 712*7488Skre p2 = p1; 713*7488Skre break; 714*7488Skre } 715*7488Skre #else 71636Sbill if (p1->p_stat==NULL && p2==NULL) 71736Sbill p2 = p1; 71836Sbill else { 71936Sbill if (p1->p_uid==u.u_uid && p1->p_stat!=NULL) 72036Sbill a++; 72136Sbill } 722*7488Skre #endif 72336Sbill } 72436Sbill /* 72536Sbill * Disallow if 72636Sbill * No processes at all; 72736Sbill * not su and too many procs owned; or 72836Sbill * not su and would take last slot. 72936Sbill */ 7302938Swnj if (p2==NULL) 7312938Swnj tablefull("proc"); 732*7488Skre #ifdef QUOTA 733*7488Skre if (p2==NULL || (u.u_uid!=0 && p2==procNPROC-1)) { 734*7488Skre #else 7352741Swnj if (p2==NULL || (u.u_uid!=0 && (p2==procNPROC-1 || a>MAXUPRC))) { 736*7488Skre #endif 73736Sbill u.u_error = EAGAIN; 73836Sbill if (!isvfork) { 739132Sbill (void) vsexpand(0, &u.u_cdmap, 1); 740132Sbill (void) vsexpand(0, &u.u_csmap, 1); 74136Sbill } 74236Sbill goto out; 74336Sbill } 74436Sbill p1 = u.u_procp; 7454827Swnj if (newproc(isvfork)) { 74636Sbill u.u_r.r_val1 = p1->p_pid; 74736Sbill u.u_r.r_val2 = 1; /* child */ 74836Sbill u.u_start = time; 74936Sbill u.u_acflag = AFORK; 750*7488Skre #ifdef QUOTA 751*7488Skre u.u_qflags &= ~QUF_LOGIN; 752*7488Skre #endif 75336Sbill return; 75436Sbill } 75536Sbill u.u_r.r_val1 = p2->p_pid; 75636Sbill 75736Sbill out: 75836Sbill u.u_r.r_val2 = 0; 75936Sbill } 76036Sbill 76136Sbill /* 76236Sbill * break system call. 76336Sbill * -- bad planning: "break" is a dirty word in C. 76436Sbill */ 76536Sbill sbreak() 76636Sbill { 76736Sbill struct a { 76836Sbill char *nsiz; 76936Sbill }; 77036Sbill register int n, d; 77136Sbill 77236Sbill /* 77336Sbill * set n to new data size 77436Sbill * set d to new-old 77536Sbill */ 77636Sbill 77736Sbill n = btoc(((struct a *)u.u_ap)->nsiz); 77836Sbill if (!u.u_sep) 77936Sbill n -= ctos(u.u_tsize) * stoc(1); 78036Sbill if (n < 0) 78136Sbill n = 0; 78236Sbill d = clrnd(n - u.u_dsize); 783368Sbill if (ctob(u.u_dsize+d) > u.u_limit[LIM_DATA]) { 784363Sbill u.u_error = ENOMEM; 785363Sbill return; 786363Sbill } 78736Sbill if (chksize(u.u_tsize, u.u_dsize+d, u.u_ssize)) 78836Sbill return; 78936Sbill if (swpexpand(u.u_dsize+d, u.u_ssize, &u.u_dmap, &u.u_smap)==0) 79036Sbill return; 79136Sbill expand(d, P0BR); 79236Sbill } 793