1*8116Sroot /* kern_proc.c 4.38 82/09/08 */ 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" 98030Sroot #include "../h/kernel.h" 1036Sbill #include "../h/proc.h" 1136Sbill #include "../h/buf.h" 1236Sbill #include "../h/reg.h" 1336Sbill #include "../h/inode.h" 1436Sbill #include "../h/seg.h" 1536Sbill #include "../h/acct.h" 16215Sbill #include "/usr/include/wait.h" 1736Sbill #include "../h/pte.h" 1836Sbill #include "../h/vm.h" 1936Sbill #include "../h/text.h" 20188Sbill #include "../h/psl.h" 21890Sbill #include "../h/file.h" 227488Skre #include "../h/quota.h" 237497Sroot #include "../h/descrip.h" 247713Sroot #include "../h/uio.h" 258030Sroot #include "../h/mbuf.h" 2636Sbill 278030Sroot gethostid() 288030Sroot { 298030Sroot 308099Sroot u.u_r.r_val1 = hostid; 318030Sroot } 328030Sroot 338030Sroot sethostid() 348030Sroot { 358099Sroot struct a { 368099Sroot int hostid; 378099Sroot } *uap = (struct a *)u.u_ap; 388030Sroot 398099Sroot if (suser()) 408099Sroot hostid = uap->hostid; 418030Sroot } 428030Sroot 438099Sroot gethostname() 448099Sroot { 458099Sroot register struct a { 468099Sroot char *hostname; 478099Sroot int len; 488099Sroot } *uap = (struct a *)u.u_ap; 498099Sroot register u_int len; 508099Sroot 518099Sroot len = uap->len; 528099Sroot if (len > hostnamelen) 538099Sroot len = hostnamelen; 548099Sroot if (copyout((caddr_t)hostname, (caddr_t)uap->hostname, len)) 558099Sroot u.u_error = EFAULT; 568099Sroot } 578099Sroot 588099Sroot sethostname() 598099Sroot { 608099Sroot register struct a { 618099Sroot char *hostname; 628099Sroot u_int len; 638099Sroot } *uap = (struct a *)u.u_ap; 648099Sroot 658099Sroot if (!suser()) 668099Sroot return; 678099Sroot if (uap->len > sizeof (hostname) - 1) { 688099Sroot u.u_error = EINVAL; 698099Sroot return; 708099Sroot } 718099Sroot hostnamelen = uap->len; 728099Sroot if (copyin((caddr_t)uap->hostname, hostname, uap->len)) 738099Sroot u.u_error = EFAULT; 748099Sroot hostname[hostnamelen] = 0; 758099Sroot } 768099Sroot 7736Sbill /* 7836Sbill * exec system call, with and without environments. 7936Sbill */ 8036Sbill struct execa { 8136Sbill char *fname; 8236Sbill char **argp; 8336Sbill char **envp; 8436Sbill }; 8536Sbill 868030Sroot execv() 8736Sbill { 8836Sbill ((struct execa *)u.u_ap)->envp = NULL; 898030Sroot execve(); 9036Sbill } 9136Sbill 928030Sroot execve() 9336Sbill { 9436Sbill register nc; 9536Sbill register char *cp; 9636Sbill register struct buf *bp; 9736Sbill register struct execa *uap; 9836Sbill int na, ne, ucp, ap, c; 992301Skre int indir, uid, gid; 1002301Skre char *sharg; 10136Sbill struct inode *ip; 10236Sbill swblk_t bno; 1036568Smckusic char cfname[MAXNAMLEN + 1]; 1042301Skre char cfarg[SHSIZE]; 1057748Sroot int resid; 10636Sbill 1075991Swnj if ((ip = namei(uchar, 0, 1)) == NULL) 10836Sbill return; 10936Sbill bno = 0; 11036Sbill bp = 0; 1112301Skre indir = 0; 1122301Skre uid = u.u_uid; 1132301Skre gid = u.u_gid; 1142301Skre if (ip->i_mode & ISUID) 1152301Skre uid = ip->i_uid; 1162301Skre if (ip->i_mode & ISGID) 1172301Skre gid = ip->i_gid; 1182301Skre 1192301Skre again: 1204827Swnj if (access(ip, IEXEC)) 12136Sbill goto bad; 1224827Swnj if ((u.u_procp->p_flag&STRC) && access(ip, IREAD)) 1232330Swnj goto bad; 1244827Swnj if ((ip->i_mode & IFMT) != IFREG || 12536Sbill (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) { 12636Sbill u.u_error = EACCES; 12736Sbill goto bad; 12836Sbill } 1292301Skre 13036Sbill /* 1312301Skre * Read in first few bytes of file for segment sizes, ux_mag: 1322301Skre * 407 = plain executable 1332301Skre * 410 = RO text 1342301Skre * 413 = demand paged RO text 1352301Skre * Also an ASCII line beginning with #! is 1362301Skre * the file name of a ``shell'' and arguments may be prepended 1372301Skre * to the argument list if given here. 1382301Skre * 1392301Skre * SHELL NAMES ARE LIMITED IN LENGTH. 1402301Skre * 1412301Skre * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM 1422301Skre * THE ASCII LINE. 1432301Skre */ 1447816Sroot u.u_error = rdwri(UIO_READ, ip, (caddr_t)&u.u_exdata, sizeof (u.u_exdata), 1457748Sroot 0, 1, &resid); 1464827Swnj if (u.u_error) 1472301Skre goto bad; 1487748Sroot u.u_count = resid; 1497816Sroot #ifndef lint 1504982Swnj if (u.u_count > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) && 1514982Swnj u.u_exdata.ux_shell[0] != '#') { 1522301Skre u.u_error = ENOEXEC; 1532301Skre goto bad; 1542301Skre } 1557816Sroot #endif 1562301Skre switch (u.u_exdata.ux_mag) { 1572301Skre 1582301Skre case 0407: 1592301Skre u.u_exdata.ux_dsize += u.u_exdata.ux_tsize; 1602301Skre u.u_exdata.ux_tsize = 0; 1612301Skre break; 1622301Skre 1632301Skre case 0413: 1642301Skre case 0410: 1652301Skre if (u.u_exdata.ux_tsize == 0) { 1662301Skre u.u_error = ENOEXEC; 1672301Skre goto bad; 1682301Skre } 1692301Skre break; 1702301Skre 1712301Skre default: 1722301Skre if (u.u_exdata.ux_shell[0] != '#' || 1732301Skre u.u_exdata.ux_shell[1] != '!' || 1742301Skre indir) { 1752301Skre u.u_error = ENOEXEC; 1762301Skre goto bad; 1772301Skre } 1782301Skre cp = &u.u_exdata.ux_shell[2]; /* skip "#!" */ 1792301Skre while (cp < &u.u_exdata.ux_shell[SHSIZE]) { 1802301Skre if (*cp == '\t') 1812301Skre *cp = ' '; 1822301Skre else if (*cp == '\n') { 1832301Skre *cp = '\0'; 1842301Skre break; 1852301Skre } 1862301Skre cp++; 1872301Skre } 1882301Skre if (*cp != '\0') { 1892301Skre u.u_error = ENOEXEC; 1902301Skre goto bad; 1912301Skre } 1922301Skre cp = &u.u_exdata.ux_shell[2]; 1932301Skre while (*cp == ' ') 1942301Skre cp++; 1952301Skre u.u_dirp = cp; 1962301Skre while (*cp && *cp != ' ') 1972301Skre cp++; 1982301Skre sharg = NULL; 1992301Skre if (*cp) { 2002301Skre *cp++ = '\0'; 2012301Skre while (*cp == ' ') 2022301Skre cp++; 2032301Skre if (*cp) { 2042301Skre bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE); 2052301Skre sharg = cfarg; 2062301Skre } 2072301Skre } 2086568Smckusic bcopy((caddr_t)u.u_dent.d_name, (caddr_t)cfname, 2097816Sroot (unsigned)(u.u_dent.d_namlen + 1)); 2102301Skre indir = 1; 2112301Skre iput(ip); 2125991Swnj ip = namei(schar, 0, 1); 2132301Skre if (ip == NULL) 2142301Skre return; 2152301Skre goto again; 2162301Skre } 2172301Skre 2182301Skre /* 21936Sbill * Collect arguments on "file" in swap space. 22036Sbill */ 22136Sbill na = 0; 22236Sbill ne = 0; 22336Sbill nc = 0; 22436Sbill uap = (struct execa *)u.u_ap; 2252780Swnj if ((bno = rmalloc(argmap, ctod(clrnd((int) btoc(NCARGS))))) == 0) { 22636Sbill swkill(u.u_procp, "exece"); 22736Sbill goto bad; 22836Sbill } 22936Sbill if (bno % CLSIZE) 2302780Swnj panic("execa rmalloc"); 23136Sbill if (uap->argp) for (;;) { 23236Sbill ap = NULL; 2333621Sroot if (indir && (na == 1 || na == 2 && sharg)) 2342301Skre ap = (int)uap->fname; 2352301Skre else if (uap->argp) { 23636Sbill ap = fuword((caddr_t)uap->argp); 23736Sbill uap->argp++; 23836Sbill } 23936Sbill if (ap==NULL && uap->envp) { 24036Sbill uap->argp = NULL; 24136Sbill if ((ap = fuword((caddr_t)uap->envp)) == NULL) 24236Sbill break; 24336Sbill uap->envp++; 24436Sbill ne++; 24536Sbill } 2466568Smckusic if (ap == NULL) 24736Sbill break; 24836Sbill na++; 2494827Swnj if (ap == -1) 25036Sbill u.u_error = EFAULT; 25136Sbill do { 25236Sbill if (nc >= NCARGS-1) 25336Sbill u.u_error = E2BIG; 2542301Skre if (indir && na == 2 && sharg != NULL) 2552301Skre c = *sharg++ & 0377; 2562301Skre else if ((c = fubyte((caddr_t)ap++)) < 0) 25736Sbill u.u_error = EFAULT; 25883Sbill if (u.u_error) { 25983Sbill if (bp) 26083Sbill brelse(bp); 26183Sbill bp = 0; 26236Sbill goto badarg; 26383Sbill } 2646568Smckusic if (nc % (CLSIZE*NBPG) == 0) { 26536Sbill if (bp) 26636Sbill bdwrite(bp); 2676568Smckusic bp = getblk(argdev, bno + nc / NBPG, 2686568Smckusic CLSIZE*NBPG); 26936Sbill cp = bp->b_un.b_addr; 27036Sbill } 27136Sbill nc++; 27236Sbill *cp++ = c; 2736568Smckusic } while (c > 0); 27436Sbill } 27536Sbill if (bp) 27636Sbill bdwrite(bp); 27736Sbill bp = 0; 27836Sbill nc = (nc + NBPW-1) & ~(NBPW-1); 2796568Smckusic if (indir) { 2806568Smckusic u.u_dent.d_namlen = strlen(cfname); 2816568Smckusic bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name, 2827816Sroot (unsigned)(u.u_dent.d_namlen + 1)); 2836568Smckusic } 2842301Skre getxfile(ip, nc + (na+4)*NBPW, uid, gid); 285912Sbill if (u.u_error) { 28636Sbill badarg: 2876568Smckusic for (c = 0; c < nc; c += CLSIZE*NBPG) 2886568Smckusic if (bp = baddr(argdev, bno + c / NBPG, CLSIZE*NBPG)) { 28936Sbill bp->b_flags |= B_AGE; /* throw away */ 29036Sbill bp->b_flags &= ~B_DELWRI; /* cancel io */ 29136Sbill brelse(bp); 29236Sbill bp = 0; 29336Sbill } 29436Sbill goto bad; 29536Sbill } 29636Sbill 29736Sbill /* 29836Sbill * copy back arglist 29936Sbill */ 30036Sbill ucp = USRSTACK - nc - NBPW; 30136Sbill ap = ucp - na*NBPW - 3*NBPW; 30236Sbill u.u_ar0[SP] = ap; 303132Sbill (void) suword((caddr_t)ap, na-ne); 30436Sbill nc = 0; 30536Sbill for (;;) { 30636Sbill ap += NBPW; 30736Sbill if (na==ne) { 308132Sbill (void) suword((caddr_t)ap, 0); 30936Sbill ap += NBPW; 31036Sbill } 31136Sbill if (--na < 0) 31236Sbill break; 313132Sbill (void) suword((caddr_t)ap, ucp); 31436Sbill do { 3156568Smckusic if (nc % (CLSIZE*NBPG) == 0) { 31636Sbill if (bp) 31736Sbill brelse(bp); 3186568Smckusic bp = bread(argdev, bno + nc / NBPG, 3196568Smckusic CLSIZE*NBPG); 32036Sbill bp->b_flags |= B_AGE; /* throw away */ 32136Sbill bp->b_flags &= ~B_DELWRI; /* cancel io */ 32236Sbill cp = bp->b_un.b_addr; 32336Sbill } 324132Sbill (void) subyte((caddr_t)ucp++, (c = *cp++)); 32536Sbill nc++; 32636Sbill } while(c&0377); 32736Sbill } 328132Sbill (void) suword((caddr_t)ap, 0); 329132Sbill (void) suword((caddr_t)ucp, 0); 33036Sbill setregs(); 33136Sbill bad: 33236Sbill if (bp) 33336Sbill brelse(bp); 33436Sbill if (bno) 3352780Swnj rmfree(argmap, ctod(clrnd((int) btoc(NCARGS))), bno); 33636Sbill iput(ip); 33736Sbill } 33836Sbill 33936Sbill /* 34036Sbill * Read in and set up memory for executed file. 34136Sbill */ 3422301Skre getxfile(ip, nargc, uid, gid) 34336Sbill register struct inode *ip; 34436Sbill { 34536Sbill register size_t ts, ds, ss; 3462301Skre int pagi; 34736Sbill 3482301Skre if (u.u_exdata.ux_mag == 0413) 34936Sbill pagi = SPAGI; 3502301Skre else 3512301Skre pagi = 0; 3524827Swnj if (u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && 3534827Swnj ip->i_count!=1) { 354890Sbill register struct file *fp; 355890Sbill 3564827Swnj for (fp = file; fp < fileNFILE; fp++) { 3577497Sroot if (fp->f_type == DTYPE_FILE && 3587497Sroot fp->f_inode == ip && (fp->f_flag&FWRITE)) { 359890Sbill u.u_error = ETXTBSY; 360890Sbill goto bad; 361890Sbill } 3624827Swnj } 36336Sbill } 36436Sbill 36536Sbill /* 3664827Swnj * Compute text and data sizes and make sure not too large. 36736Sbill */ 36836Sbill ts = clrnd(btoc(u.u_exdata.ux_tsize)); 36936Sbill ds = clrnd(btoc((u.u_exdata.ux_dsize+u.u_exdata.ux_bsize))); 37036Sbill ss = clrnd(SSIZE + btoc(nargc)); 371912Sbill if (chksize(ts, ds, ss)) 372912Sbill goto bad; 3734827Swnj 3744827Swnj /* 3754827Swnj * Make sure enough space to start process. 3764827Swnj */ 377912Sbill u.u_cdmap = zdmap; 378912Sbill u.u_csmap = zdmap; 379912Sbill if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL) 380912Sbill goto bad; 38136Sbill 382912Sbill /* 383912Sbill * At this point, committed to the new image! 384912Sbill * Release virtual memory resources of old process, and 385912Sbill * initialize the virtual memory of the new process. 386912Sbill * If we resulted from vfork(), instead wakeup our 387912Sbill * parent who will set SVFDONE when he has taken back 388912Sbill * our resources. 389912Sbill */ 390912Sbill if ((u.u_procp->p_flag & SVFORK) == 0) 391912Sbill vrelvm(); 392912Sbill else { 393912Sbill u.u_procp->p_flag &= ~SVFORK; 394912Sbill u.u_procp->p_flag |= SKEEP; 395912Sbill wakeup((caddr_t)u.u_procp); 396912Sbill while ((u.u_procp->p_flag & SVFDONE) == 0) 397912Sbill sleep((caddr_t)u.u_procp, PZERO - 1); 398912Sbill u.u_procp->p_flag &= ~(SVFDONE|SKEEP); 399912Sbill } 4003592Swnj u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SNUSIG); 401912Sbill u.u_procp->p_flag |= pagi; 402912Sbill u.u_dmap = u.u_cdmap; 403912Sbill u.u_smap = u.u_csmap; 404912Sbill vgetvm(ts, ds, ss); 405912Sbill 4067748Sroot if (pagi == 0) 4077816Sroot u.u_error = 4087816Sroot rdwri(UIO_READ, ip, 4097816Sroot (char*)ctob(ts), (int)u.u_exdata.ux_dsize, 4107816Sroot (int)(sizeof(u.u_exdata)+u.u_exdata.ux_tsize), 4117816Sroot 0, (int *)0); 412912Sbill xalloc(ip, pagi); 413912Sbill if (pagi && u.u_procp->p_textp) 414912Sbill vinifod((struct fpte *)dptopte(u.u_procp, 0), 415912Sbill PG_FTEXT, u.u_procp->p_textp->x_iptr, 416912Sbill 1 + ts/CLSIZE, (int)btoc(u.u_exdata.ux_dsize)); 41736Sbill 418912Sbill /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */ 419912Sbill mtpr(TBIA, 0); 42036Sbill 4217530Sroot if (u.u_error) 4227530Sroot swkill(u.u_procp, "i/o error mapping pages"); 423912Sbill /* 424912Sbill * set SUID/SGID protections, if no tracing 425912Sbill */ 426912Sbill if ((u.u_procp->p_flag&STRC)==0) { 4274827Swnj u.u_uid = uid; 4284827Swnj u.u_procp->p_uid = uid; 4292301Skre u.u_gid = gid; 4307865Sroot entergroup(gid); 431912Sbill } else 432912Sbill psignal(u.u_procp, SIGTRAP); 43336Sbill u.u_tsize = ts; 43436Sbill u.u_dsize = ds; 43536Sbill u.u_ssize = ss; 43636Sbill bad: 437912Sbill return; 43836Sbill } 43936Sbill 44036Sbill /* 44136Sbill * Clear registers on exec 44236Sbill */ 44336Sbill setregs() 44436Sbill { 445173Sbill register int (**rp)(); 44636Sbill register i; 447188Sbill long sigmask; 44836Sbill 4496464Swnj for (rp = &u.u_signal[1], sigmask = 1L; rp < &u.u_signal[NSIG]; 450188Sbill sigmask <<= 1, rp++) { 451188Sbill switch (*rp) { 452188Sbill 453188Sbill case SIG_IGN: 454188Sbill case SIG_DFL: 455188Sbill case SIG_HOLD: 456188Sbill continue; 457188Sbill 458188Sbill default: 459188Sbill /* 460206Sbill * Normal or deferring catch; revert to default. 461188Sbill */ 462206Sbill (void) spl6(); 463206Sbill *rp = SIG_DFL; 464188Sbill if ((int)*rp & 1) 465188Sbill u.u_procp->p_siga0 |= sigmask; 466188Sbill else 4676327Swnj u.u_procp->p_siga0 &= ~sigmask; 468188Sbill if ((int)*rp & 2) 469188Sbill u.u_procp->p_siga1 |= sigmask; 470188Sbill else 471188Sbill u.u_procp->p_siga1 &= ~sigmask; 472206Sbill (void) spl0(); 473188Sbill continue; 474188Sbill } 475188Sbill } 47636Sbill /* 4774827Swnj for (rp = &u.u_ar0[0]; rp < &u.u_ar0[16];) 47836Sbill *rp++ = 0; 47936Sbill */ 48036Sbill u.u_ar0[PC] = u.u_exdata.ux_entloc + 2; /* skip over entry mask */ 4814827Swnj for (i=0; i<NOFILE; i++) { 48236Sbill if (u.u_pofile[i]&EXCLOSE) { 4837697Ssam closef(u.u_ofile[i], 1, u.u_pofile[i]); 48436Sbill u.u_ofile[i] = NULL; 4857697Ssam u.u_pofile[i] = 0; 48636Sbill } 48736Sbill } 4884827Swnj 48936Sbill /* 49036Sbill * Remember file name for accounting. 49136Sbill */ 49236Sbill u.u_acflag &= ~AFORK; 4936568Smckusic bcopy((caddr_t)u.u_dent.d_name, (caddr_t)u.u_comm, 4947816Sroot (unsigned)(u.u_dent.d_namlen + 1)); 49536Sbill } 49636Sbill 49736Sbill /* 4984827Swnj * Exit system call: pass back caller's arg 49936Sbill */ 50036Sbill rexit() 50136Sbill { 50236Sbill register struct a { 50336Sbill int rval; 50436Sbill } *uap; 50536Sbill 50636Sbill uap = (struct a *)u.u_ap; 50736Sbill exit((uap->rval & 0377) << 8); 50836Sbill } 50936Sbill 51036Sbill /* 51136Sbill * Release resources. 51236Sbill * Save u. area for parent to look at. 51336Sbill * Enter zombie state. 51436Sbill * Wake up parent and init processes, 51536Sbill * and dispose of children. 51636Sbill */ 51736Sbill exit(rv) 51836Sbill { 51936Sbill register int i; 52036Sbill register struct proc *p, *q; 52136Sbill register int x; 52236Sbill 52336Sbill #ifdef PGINPROF 52436Sbill vmsizmon(); 52536Sbill #endif 52636Sbill p = u.u_procp; 52736Sbill p->p_flag &= ~(STRC|SULOCK); 52836Sbill p->p_flag |= SWEXIT; 529188Sbill (void) spl6(); 530188Sbill if ((int)SIG_IGN & 1) 531188Sbill p->p_siga0 = ~0; 532188Sbill else 533188Sbill p->p_siga0 = 0; 534188Sbill if ((int)SIG_IGN & 2) 535188Sbill p->p_siga1 = ~0; 536188Sbill else 537206Sbill p->p_siga1 = 0; 538188Sbill (void) spl0(); 5391399Sbill p->p_cpticks = 0; 5401399Sbill p->p_pctcpu = 0; 5414827Swnj for (i=0; i<NSIG; i++) 542173Sbill u.u_signal[i] = SIG_IGN; 543*8116Sroot untimeout(unrto, p); 54436Sbill /* 54536Sbill * Release virtual memory. If we resulted from 54636Sbill * a vfork(), instead give the resources back to 54736Sbill * the parent. 54836Sbill */ 54936Sbill if ((p->p_flag & SVFORK) == 0) 55036Sbill vrelvm(); 55136Sbill else { 55236Sbill p->p_flag &= ~SVFORK; 55336Sbill wakeup((caddr_t)p); 55436Sbill while ((p->p_flag & SVFDONE) == 0) 55536Sbill sleep((caddr_t)p, PZERO - 1); 55636Sbill p->p_flag &= ~SVFDONE; 55736Sbill } 5587697Ssam for (i = 0; i < NOFILE; i++) { 5597697Ssam #ifdef notdef 5607697Ssam /* why was this like this? */ 56136Sbill f = u.u_ofile[i]; 56236Sbill u.u_ofile[i] = NULL; 5635581Swnj closef(f, 1); 5647697Ssam #else 5657697Ssam closef(u.u_ofile[i], 1, u.u_pofile[i]); 5667697Ssam u.u_ofile[i] = NULL; 5677697Ssam u.u_pofile[i] = 0; 5687697Ssam #endif 56936Sbill } 5704827Swnj ilock(u.u_cdir); 57136Sbill iput(u.u_cdir); 57236Sbill if (u.u_rdir) { 5734827Swnj ilock(u.u_rdir); 57436Sbill iput(u.u_rdir); 57536Sbill } 5768030Sroot u.u_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; 57736Sbill acct(); 5787488Skre #ifdef QUOTA 5797488Skre qclean(); 5807488Skre #endif 58136Sbill vrelpt(u.u_procp); 58236Sbill vrelu(u.u_procp, 0); 5835630Swnj (void) spl5(); /* hack for mem alloc race XXX */ 58436Sbill multprog--; 585931Sbill p->p_stat = SZOMB; 586307Sbill noproc = 1; 58736Sbill i = PIDHASH(p->p_pid); 58836Sbill x = p - proc; 58936Sbill if (pidhash[i] == x) 59036Sbill pidhash[i] = p->p_idhash; 59136Sbill else { 59236Sbill for (i = pidhash[i]; i != 0; i = proc[i].p_idhash) 59336Sbill if (proc[i].p_idhash == x) { 59436Sbill proc[i].p_idhash = p->p_idhash; 59536Sbill goto done; 59636Sbill } 59736Sbill panic("exit"); 59836Sbill } 5991409Sbill if (p->p_pid == 1) 6001409Sbill panic("init died"); 60136Sbill done: 6028030Sroot p->p_xstat = rv; 6038030Sroot { struct mbuf *m = m_getclr(M_DONTWAIT); p->p_ru = mtod(m, struct rusage *); } 6048030Sroot *p->p_ru = u.u_ru; 6058030Sroot ruadd(p->p_ru, &u.u_cru); 6064827Swnj for (q = proc; q < procNPROC; q++) 6074827Swnj if (q->p_pptr == p) { 6087488Skre if (q->p_osptr) 6097488Skre q->p_osptr->p_ysptr = q->p_ysptr; 6107488Skre if (q->p_ysptr) 6117488Skre q->p_ysptr->p_osptr = q->p_osptr; 6127488Skre if (proc[1].p_cptr) 6137488Skre proc[1].p_cptr->p_ysptr = q; 6147488Skre q->p_osptr = proc[1].p_cptr; 6157488Skre q->p_ysptr = NULL; 6167488Skre proc[1].p_cptr = q; 6177488Skre 618188Sbill q->p_pptr = &proc[1]; 619188Sbill q->p_ppid = 1; 62036Sbill wakeup((caddr_t)&proc[1]); 621188Sbill /* 622212Sbill * Traced processes are killed 623188Sbill * since their existence means someone is screwing up. 624354Sbill * Stopped processes are sent a hangup and a continue. 625212Sbill * This is designed to be ``safe'' for setuid 626212Sbill * processes since they must be willing to tolerate 627212Sbill * hangups anyways. 628188Sbill */ 629212Sbill if (q->p_flag&STRC) { 630188Sbill q->p_flag &= ~STRC; 631188Sbill psignal(q, SIGKILL); 632212Sbill } else if (q->p_stat == SSTOP) { 633212Sbill psignal(q, SIGHUP); 634212Sbill psignal(q, SIGCONT); 635188Sbill } 636215Sbill /* 637215Sbill * Protect this process from future 6385619Swnj * tty signals, clear TSTP/TTIN/TTOU if pending. 639215Sbill */ 6401788Sbill (void) spgrp(q, -1); 64136Sbill } 6426464Swnj psignal(p->p_pptr, SIGCHLD); 643188Sbill wakeup((caddr_t)p->p_pptr); 64436Sbill swtch(); 64536Sbill } 64636Sbill 6478099Sroot owait() 64836Sbill { 6498030Sroot struct rusage ru, *rup; 65036Sbill 651188Sbill if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) { 6528030Sroot wait1(0, (struct rusage *)0); 653188Sbill return; 654188Sbill } 6558030Sroot rup = (struct rusage *)u.u_ar0[R1]; 6568030Sroot wait1(u.u_ar0[R0], &ru); 657188Sbill if (u.u_error) 658188Sbill return; 6598030Sroot (void) copyout((caddr_t)&ru, (caddr_t)rup, sizeof (struct rusage)); 66036Sbill } 66136Sbill 66236Sbill /* 66336Sbill * Wait system call. 66436Sbill * Search for a terminated (zombie) child, 66536Sbill * finally lay it to rest, and collect its status. 66636Sbill * Look also for stopped (traced) children, 66736Sbill * and pass back status from them. 66836Sbill */ 6698030Sroot wait1(options, ru) 6708030Sroot register int options; 6718030Sroot struct rusage *ru; 67236Sbill { 67336Sbill register f; 6747488Skre register struct proc *p, *q; 67536Sbill 67636Sbill f = 0; 67736Sbill loop: 6784827Swnj for (p = proc; p < procNPROC; p++) 6794827Swnj if (p->p_pptr == u.u_procp) { 68036Sbill f++; 6814827Swnj if (p->p_stat == SZOMB) { 68236Sbill u.u_r.r_val1 = p->p_pid; 6838030Sroot u.u_r.r_val2 = p->p_xstat; 6848030Sroot p->p_xstat = 0; 6858030Sroot if (ru) 6868030Sroot *ru = *p->p_ru; 6878030Sroot ruadd(&u.u_cru, p->p_ru); 6888030Sroot m_free(dtom(p->p_ru)); 6898030Sroot p->p_ru = 0; 69036Sbill p->p_stat = NULL; 69136Sbill p->p_pid = 0; 69236Sbill p->p_ppid = 0; 6937488Skre if (q = p->p_ysptr) 6947488Skre q->p_osptr = p->p_osptr; 6957488Skre if (q = p->p_osptr) 6967488Skre q->p_ysptr = p->p_ysptr; 6977488Skre if ((q = p->p_pptr)->p_cptr == p) 6987488Skre q->p_cptr = p->p_osptr; 699188Sbill p->p_pptr = 0; 7007488Skre p->p_ysptr = 0; 7017488Skre p->p_osptr = 0; 7027488Skre p->p_cptr = 0; 70336Sbill p->p_sig = 0; 704188Sbill p->p_siga0 = 0; 705188Sbill p->p_siga1 = 0; 70636Sbill p->p_pgrp = 0; 70736Sbill p->p_flag = 0; 70836Sbill p->p_wchan = 0; 709188Sbill p->p_cursig = 0; 71036Sbill return; 71136Sbill } 712188Sbill if (p->p_stat == SSTOP && (p->p_flag&SWTED)==0 && 713188Sbill (p->p_flag&STRC || options&WUNTRACED)) { 714188Sbill p->p_flag |= SWTED; 715188Sbill u.u_r.r_val1 = p->p_pid; 716188Sbill u.u_r.r_val2 = (p->p_cursig<<8) | WSTOPPED; 717188Sbill return; 71836Sbill } 71936Sbill } 720188Sbill if (f==0) { 721188Sbill u.u_error = ECHILD; 722188Sbill return; 72336Sbill } 724188Sbill if (options&WNOHANG) { 725188Sbill u.u_r.r_val1 = 0; 726188Sbill return; 727188Sbill } 728*8116Sroot if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) { 729188Sbill u.u_eosys = RESTARTSYS; 730188Sbill return; 731188Sbill } 732188Sbill sleep((caddr_t)u.u_procp, PWAIT); 733188Sbill goto loop; 73436Sbill } 73536Sbill 73636Sbill /* 73736Sbill * fork system call. 73836Sbill */ 73936Sbill fork() 74036Sbill { 74136Sbill 74236Sbill u.u_cdmap = zdmap; 74336Sbill u.u_csmap = zdmap; 74436Sbill if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 74536Sbill u.u_r.r_val2 = 0; 74636Sbill return; 74736Sbill } 74836Sbill fork1(0); 74936Sbill } 75036Sbill 75136Sbill fork1(isvfork) 75236Sbill { 75336Sbill register struct proc *p1, *p2; 7547488Skre #ifndef QUOTA 75536Sbill register a; 75636Sbill 75736Sbill a = 0; 7587488Skre #else 7597488Skre if (u.u_quota != NOQUOT && u.u_quota->q_plim && 7607488Skre u.u_quota->q_cnt >= u.u_quota->q_plim) { 7617488Skre u.u_error = EPROCLIM; 7627488Skre return; 7637488Skre } 7647488Skre #endif 76536Sbill p2 = NULL; 7664827Swnj for (p1 = proc; p1 < procNPROC; p1++) { 7677488Skre #ifdef QUOTA 7687488Skre if (p1->p_stat == NULL) { 7697488Skre p2 = p1; 7707488Skre break; 7717488Skre } 7727488Skre #else 77336Sbill if (p1->p_stat==NULL && p2==NULL) 77436Sbill p2 = p1; 77536Sbill else { 77636Sbill if (p1->p_uid==u.u_uid && p1->p_stat!=NULL) 77736Sbill a++; 77836Sbill } 7797488Skre #endif 78036Sbill } 78136Sbill /* 78236Sbill * Disallow if 78336Sbill * No processes at all; 78436Sbill * not su and too many procs owned; or 78536Sbill * not su and would take last slot. 78636Sbill */ 7872938Swnj if (p2==NULL) 7882938Swnj tablefull("proc"); 7897488Skre #ifdef QUOTA 7907488Skre if (p2==NULL || (u.u_uid!=0 && p2==procNPROC-1)) { 7917488Skre #else 7922741Swnj if (p2==NULL || (u.u_uid!=0 && (p2==procNPROC-1 || a>MAXUPRC))) { 7937488Skre #endif 79436Sbill u.u_error = EAGAIN; 79536Sbill if (!isvfork) { 796132Sbill (void) vsexpand(0, &u.u_cdmap, 1); 797132Sbill (void) vsexpand(0, &u.u_csmap, 1); 79836Sbill } 79936Sbill goto out; 80036Sbill } 80136Sbill p1 = u.u_procp; 8024827Swnj if (newproc(isvfork)) { 80336Sbill u.u_r.r_val1 = p1->p_pid; 80436Sbill u.u_r.r_val2 = 1; /* child */ 8058030Sroot u.u_start = time.tv_sec; 80636Sbill u.u_acflag = AFORK; 8077488Skre #ifdef QUOTA 8087488Skre u.u_qflags &= ~QUF_LOGIN; 8097488Skre #endif 81036Sbill return; 81136Sbill } 81236Sbill u.u_r.r_val1 = p2->p_pid; 81336Sbill 81436Sbill out: 81536Sbill u.u_r.r_val2 = 0; 81636Sbill } 81736Sbill 8187497Sroot spgrp(top, npgrp) 8197497Sroot register struct proc *top; 8207497Sroot { 8217497Sroot register struct proc *pp, *p; 8227497Sroot int f = 0; 8237497Sroot 8247497Sroot for (p = top; npgrp == -1 || u.u_uid == p->p_uid || 8257497Sroot !u.u_uid || inferior(p); p = pp) { 8267497Sroot if (npgrp == -1) { 8277497Sroot #define bit(a) (1<<(a-1)) 8287497Sroot p->p_sig &= ~(bit(SIGTSTP)|bit(SIGTTIN)|bit(SIGTTOU)); 8297497Sroot } else 8307497Sroot p->p_pgrp = npgrp; 8317497Sroot f++; 8327497Sroot /* 8337497Sroot * Search for children. 8347497Sroot */ 8357497Sroot for (pp = proc; pp < procNPROC; pp++) 8367497Sroot if (pp->p_pptr == p) 8377497Sroot goto cont; 8387497Sroot /* 8397497Sroot * Search for siblings. 8407497Sroot */ 8417497Sroot for (; p != top; p = p->p_pptr) 8427497Sroot for (pp = p + 1; pp < procNPROC; pp++) 8437497Sroot if (pp->p_pptr == p->p_pptr) 8447497Sroot goto cont; 8457497Sroot break; 8467497Sroot cont: 8477497Sroot ; 8487497Sroot } 8497497Sroot return (f); 8507497Sroot } 8517497Sroot 85236Sbill /* 8537497Sroot * Is p an inferior of the current process? 85436Sbill */ 8557497Sroot inferior(p) 8567816Sroot register struct proc *p; 85736Sbill { 85836Sbill 8597497Sroot for (; p != u.u_procp; p = p->p_pptr) 8607497Sroot if (p->p_ppid == 0) 8617497Sroot return (0); 8627497Sroot return (1); 86336Sbill } 8647816Sroot 8657816Sroot struct proc * 8667816Sroot pfind(pid) 8677816Sroot int pid; 8687816Sroot { 8697816Sroot register struct proc *p; 8707816Sroot 8717816Sroot for (p = &proc[pidhash[PIDHASH(pid)]]; p != &proc[0]; p = &proc[p->p_idhash]) 8727816Sroot if (p->p_pid == pid) 8737816Sroot return (p); 8747816Sroot return ((struct proc *)0); 8757816Sroot } 8768099Sroot 8778099Sroot /* 8788099Sroot * Create a new process-- the internal version of 8798099Sroot * sys fork. 8808099Sroot * It returns 1 in the new process, 0 in the old. 8818099Sroot */ 8828099Sroot newproc(isvfork) 8838099Sroot int isvfork; 8848099Sroot { 8858099Sroot register struct proc *p; 8868099Sroot register struct proc *rpp, *rip; 8878099Sroot register int n; 8888099Sroot register struct file *fp; 8898099Sroot 8908099Sroot p = NULL; 8918099Sroot /* 8928099Sroot * First, just locate a slot for a process 8938099Sroot * and copy the useful info from this process into it. 8948099Sroot * The panic "cannot happen" because fork has already 8958099Sroot * checked for the existence of a slot. 8968099Sroot */ 8978099Sroot retry: 8988099Sroot mpid++; 8998099Sroot if (mpid >= 30000) { 9008099Sroot mpid = 0; 9018099Sroot goto retry; 9028099Sroot } 9038099Sroot for (rpp = proc; rpp < procNPROC; rpp++) { 9048099Sroot if (rpp->p_stat == NULL && p==NULL) 9058099Sroot p = rpp; 9068099Sroot if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 9078099Sroot goto retry; 9088099Sroot } 9098099Sroot if ((rpp = p) == NULL) 9108099Sroot panic("no procs"); 9118099Sroot 9128099Sroot /* 9138099Sroot * Make a proc table entry for the new process. 9148099Sroot */ 9158099Sroot rip = u.u_procp; 9168099Sroot #ifdef QUOTA 9178099Sroot (rpp->p_quota = rip->p_quota)->q_cnt++; 9188099Sroot #endif 9198099Sroot rpp->p_stat = SIDL; 9208099Sroot timerclear(&rpp->p_realtimer.it_value); 9218099Sroot rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SNUSIG)); 9228099Sroot if (isvfork) { 9238099Sroot rpp->p_flag |= SVFORK; 9248099Sroot rpp->p_ndx = rip->p_ndx; 9258099Sroot } else 9268099Sroot rpp->p_ndx = rpp - proc; 9278099Sroot rpp->p_uid = rip->p_uid; 9288099Sroot rpp->p_pgrp = rip->p_pgrp; 9298099Sroot rpp->p_nice = rip->p_nice; 9308099Sroot rpp->p_textp = isvfork ? 0 : rip->p_textp; 9318099Sroot rpp->p_pid = mpid; 9328099Sroot rpp->p_ppid = rip->p_pid; 9338099Sroot rpp->p_pptr = rip; 9348099Sroot rpp->p_osptr = rip->p_cptr; 9358099Sroot if (rip->p_cptr) 9368099Sroot rip->p_cptr->p_ysptr = rpp; 9378099Sroot rpp->p_ysptr = NULL; 9388099Sroot rpp->p_cptr = NULL; 9398099Sroot rip->p_cptr = rpp; 9408099Sroot rpp->p_time = 0; 9418099Sroot rpp->p_cpu = 0; 9428099Sroot rpp->p_siga0 = rip->p_siga0; 9438099Sroot rpp->p_siga1 = rip->p_siga1; 9448099Sroot /* take along any pending signals, like stops? */ 9458099Sroot if (isvfork) { 9468099Sroot rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 9478099Sroot rpp->p_szpt = clrnd(ctopt(UPAGES)); 9488099Sroot forkstat.cntvfork++; 9498099Sroot forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 9508099Sroot } else { 9518099Sroot rpp->p_tsize = rip->p_tsize; 9528099Sroot rpp->p_dsize = rip->p_dsize; 9538099Sroot rpp->p_ssize = rip->p_ssize; 9548099Sroot rpp->p_szpt = rip->p_szpt; 9558099Sroot forkstat.cntfork++; 9568099Sroot forkstat.sizfork += rip->p_dsize + rip->p_ssize; 9578099Sroot } 9588099Sroot rpp->p_rssize = 0; 9598099Sroot rpp->p_maxrss = rip->p_maxrss; 9608099Sroot rpp->p_wchan = 0; 9618099Sroot rpp->p_slptime = 0; 9628099Sroot rpp->p_pctcpu = 0; 9638099Sroot rpp->p_cpticks = 0; 9648099Sroot n = PIDHASH(rpp->p_pid); 9658099Sroot p->p_idhash = pidhash[n]; 9668099Sroot pidhash[n] = rpp - proc; 9678099Sroot multprog++; 9688099Sroot 9698099Sroot /* 9708099Sroot * Increase reference counts on shared objects. 9718099Sroot */ 9728099Sroot for (n = 0; n < NOFILE; n++) { 9738099Sroot fp = u.u_ofile[n]; 9748099Sroot if (fp == NULL) 9758099Sroot continue; 9768099Sroot fp->f_count++; 9778099Sroot if (u.u_pofile[n]&RDLOCK) 9788099Sroot fp->f_inode->i_rdlockc++; 9798099Sroot if (u.u_pofile[n]&WRLOCK) 9808099Sroot fp->f_inode->i_wrlockc++; 9818099Sroot } 9828099Sroot u.u_cdir->i_count++; 9838099Sroot if (u.u_rdir) 9848099Sroot u.u_rdir->i_count++; 9858099Sroot 9868099Sroot /* 9878099Sroot * Partially simulate the environment 9888099Sroot * of the new process so that when it is actually 9898099Sroot * created (by copying) it will look right. 9908099Sroot * This begins the section where we must prevent the parent 9918099Sroot * from being swapped. 9928099Sroot */ 9938099Sroot rip->p_flag |= SKEEP; 9948099Sroot if (procdup(rpp, isvfork)) 9958099Sroot return (1); 9968099Sroot 9978099Sroot /* 9988099Sroot * Make child runnable and add to run queue. 9998099Sroot */ 10008099Sroot (void) spl6(); 10018099Sroot rpp->p_stat = SRUN; 10028099Sroot setrq(rpp); 10038099Sroot (void) spl0(); 10048099Sroot 10058099Sroot /* 10068099Sroot * Cause child to take a non-local goto as soon as it runs. 10078099Sroot * On older systems this was done with SSWAP bit in proc 10088099Sroot * table; on VAX we use u.u_pcb.pcb_sswap so don't need 10098099Sroot * to do rpp->p_flag |= SSWAP. Actually do nothing here. 10108099Sroot */ 10118099Sroot /* rpp->p_flag |= SSWAP; */ 10128099Sroot 10138099Sroot /* 10148099Sroot * Now can be swapped. 10158099Sroot */ 10168099Sroot rip->p_flag &= ~SKEEP; 10178099Sroot 10188099Sroot /* 10198099Sroot * If vfork make chain from parent process to child 10208099Sroot * (where virtal memory is temporarily). Wait for 10218099Sroot * child to finish, steal virtual memory back, 10228099Sroot * and wakeup child to let it die. 10238099Sroot */ 10248099Sroot if (isvfork) { 10258099Sroot u.u_procp->p_xlink = rpp; 10268099Sroot u.u_procp->p_flag |= SNOVM; 10278099Sroot while (rpp->p_flag & SVFORK) 10288099Sroot sleep((caddr_t)rpp, PZERO - 1); 10298099Sroot if ((rpp->p_flag & SLOAD) == 0) 10308099Sroot panic("newproc vfork"); 10318099Sroot uaccess(rpp, Vfmap, &vfutl); 10328099Sroot u.u_procp->p_xlink = 0; 10338099Sroot vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 10348099Sroot u.u_procp->p_flag &= ~SNOVM; 10358099Sroot rpp->p_ndx = rpp - proc; 10368099Sroot rpp->p_flag |= SVFDONE; 10378099Sroot wakeup((caddr_t)rpp); 10388099Sroot } 10398099Sroot 10408099Sroot /* 10418099Sroot * 0 return means parent. 10428099Sroot */ 10438099Sroot return (0); 10448099Sroot } 1045