1*9990Ssam /* kern_proc.c 4.55 82/12/28 */ 236Sbill 39753Ssam #include "../machine/reg.h" 49753Ssam #include "../machine/pte.h" 59753Ssam #include "../machine/psl.h" 69753Ssam 736Sbill #include "../h/param.h" 836Sbill #include "../h/systm.h" 936Sbill #include "../h/map.h" 1036Sbill #include "../h/dir.h" 1136Sbill #include "../h/user.h" 128030Sroot #include "../h/kernel.h" 1336Sbill #include "../h/proc.h" 1436Sbill #include "../h/buf.h" 1536Sbill #include "../h/inode.h" 1636Sbill #include "../h/seg.h" 1736Sbill #include "../h/acct.h" 188968Sroot #include <wait.h> 1936Sbill #include "../h/vm.h" 2036Sbill #include "../h/text.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" 269159Ssam #include "../h/nami.h" 2736Sbill 288030Sroot gethostid() 298030Sroot { 308030Sroot 318099Sroot u.u_r.r_val1 = hostid; 328030Sroot } 338030Sroot 348030Sroot sethostid() 358030Sroot { 368099Sroot struct a { 378099Sroot int hostid; 388099Sroot } *uap = (struct a *)u.u_ap; 398030Sroot 408099Sroot if (suser()) 418099Sroot hostid = uap->hostid; 428030Sroot } 438030Sroot 448099Sroot gethostname() 458099Sroot { 468099Sroot register struct a { 478099Sroot char *hostname; 488099Sroot int len; 498099Sroot } *uap = (struct a *)u.u_ap; 508099Sroot register u_int len; 518099Sroot 528099Sroot len = uap->len; 538099Sroot if (len > hostnamelen) 548099Sroot len = hostnamelen; 558099Sroot if (copyout((caddr_t)hostname, (caddr_t)uap->hostname, len)) 568099Sroot u.u_error = EFAULT; 578099Sroot } 588099Sroot 598099Sroot sethostname() 608099Sroot { 618099Sroot register struct a { 628099Sroot char *hostname; 638099Sroot u_int len; 648099Sroot } *uap = (struct a *)u.u_ap; 658099Sroot 668099Sroot if (!suser()) 678099Sroot return; 688099Sroot if (uap->len > sizeof (hostname) - 1) { 698099Sroot u.u_error = EINVAL; 708099Sroot return; 718099Sroot } 728099Sroot hostnamelen = uap->len; 738099Sroot if (copyin((caddr_t)uap->hostname, hostname, uap->len)) 748099Sroot u.u_error = EFAULT; 758099Sroot hostname[hostnamelen] = 0; 768099Sroot } 778099Sroot 7836Sbill /* 7936Sbill * exec system call, with and without environments. 8036Sbill */ 8136Sbill struct execa { 8236Sbill char *fname; 8336Sbill char **argp; 8436Sbill char **envp; 8536Sbill }; 8636Sbill 878030Sroot execv() 8836Sbill { 8936Sbill ((struct execa *)u.u_ap)->envp = NULL; 908030Sroot execve(); 9136Sbill } 9236Sbill 938030Sroot execve() 9436Sbill { 9536Sbill register nc; 9636Sbill register char *cp; 9736Sbill register struct buf *bp; 9836Sbill register struct execa *uap; 9936Sbill int na, ne, ucp, ap, c; 1002301Skre int indir, uid, gid; 1012301Skre char *sharg; 10236Sbill struct inode *ip; 10336Sbill swblk_t bno; 1046568Smckusic char cfname[MAXNAMLEN + 1]; 1052301Skre char cfarg[SHSIZE]; 1067748Sroot int resid; 10736Sbill 1089159Ssam if ((ip = namei(uchar, LOOKUP, 1)) == NULL) 10936Sbill return; 11036Sbill bno = 0; 11136Sbill bp = 0; 1122301Skre indir = 0; 1132301Skre uid = u.u_uid; 1142301Skre gid = u.u_gid; 1152301Skre if (ip->i_mode & ISUID) 1162301Skre uid = ip->i_uid; 1172301Skre if (ip->i_mode & ISGID) 1182301Skre gid = ip->i_gid; 1192301Skre 1202301Skre again: 1214827Swnj if (access(ip, IEXEC)) 12236Sbill goto bad; 1234827Swnj if ((u.u_procp->p_flag&STRC) && access(ip, IREAD)) 1242330Swnj goto bad; 1254827Swnj if ((ip->i_mode & IFMT) != IFREG || 12636Sbill (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) { 12736Sbill u.u_error = EACCES; 12836Sbill goto bad; 12936Sbill } 1302301Skre 13136Sbill /* 1322301Skre * Read in first few bytes of file for segment sizes, ux_mag: 1332301Skre * 407 = plain executable 1342301Skre * 410 = RO text 1352301Skre * 413 = demand paged RO text 1362301Skre * Also an ASCII line beginning with #! is 1372301Skre * the file name of a ``shell'' and arguments may be prepended 1382301Skre * to the argument list if given here. 1392301Skre * 1402301Skre * SHELL NAMES ARE LIMITED IN LENGTH. 1412301Skre * 1422301Skre * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM 1432301Skre * THE ASCII LINE. 1442301Skre */ 1459753Ssam u.u_exdata.ux_shell[0] = 0; /* for zero length files */ 1467816Sroot u.u_error = rdwri(UIO_READ, ip, (caddr_t)&u.u_exdata, sizeof (u.u_exdata), 1477748Sroot 0, 1, &resid); 1484827Swnj if (u.u_error) 1492301Skre goto bad; 1507748Sroot u.u_count = resid; 1517816Sroot #ifndef lint 1524982Swnj if (u.u_count > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) && 1534982Swnj u.u_exdata.ux_shell[0] != '#') { 1542301Skre u.u_error = ENOEXEC; 1552301Skre goto bad; 1562301Skre } 1577816Sroot #endif 1582301Skre switch (u.u_exdata.ux_mag) { 1592301Skre 1602301Skre case 0407: 1612301Skre u.u_exdata.ux_dsize += u.u_exdata.ux_tsize; 1622301Skre u.u_exdata.ux_tsize = 0; 1632301Skre break; 1642301Skre 1652301Skre case 0413: 1662301Skre case 0410: 1672301Skre if (u.u_exdata.ux_tsize == 0) { 1682301Skre u.u_error = ENOEXEC; 1692301Skre goto bad; 1702301Skre } 1712301Skre break; 1722301Skre 1732301Skre default: 1742301Skre if (u.u_exdata.ux_shell[0] != '#' || 1752301Skre u.u_exdata.ux_shell[1] != '!' || 1762301Skre indir) { 1772301Skre u.u_error = ENOEXEC; 1782301Skre goto bad; 1792301Skre } 1802301Skre cp = &u.u_exdata.ux_shell[2]; /* skip "#!" */ 1812301Skre while (cp < &u.u_exdata.ux_shell[SHSIZE]) { 1822301Skre if (*cp == '\t') 1832301Skre *cp = ' '; 1842301Skre else if (*cp == '\n') { 1852301Skre *cp = '\0'; 1862301Skre break; 1872301Skre } 1882301Skre cp++; 1892301Skre } 1902301Skre if (*cp != '\0') { 1912301Skre u.u_error = ENOEXEC; 1922301Skre goto bad; 1932301Skre } 1942301Skre cp = &u.u_exdata.ux_shell[2]; 1952301Skre while (*cp == ' ') 1962301Skre cp++; 1972301Skre u.u_dirp = cp; 1982301Skre while (*cp && *cp != ' ') 1992301Skre cp++; 2002301Skre sharg = NULL; 2012301Skre if (*cp) { 2022301Skre *cp++ = '\0'; 2032301Skre while (*cp == ' ') 2042301Skre cp++; 2052301Skre if (*cp) { 2062301Skre bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE); 2072301Skre sharg = cfarg; 2082301Skre } 2092301Skre } 2106568Smckusic bcopy((caddr_t)u.u_dent.d_name, (caddr_t)cfname, 2117816Sroot (unsigned)(u.u_dent.d_namlen + 1)); 2122301Skre indir = 1; 2132301Skre iput(ip); 2149159Ssam ip = namei(schar, LOOKUP, 1); 2152301Skre if (ip == NULL) 2162301Skre return; 2172301Skre goto again; 2182301Skre } 2192301Skre 2202301Skre /* 22136Sbill * Collect arguments on "file" in swap space. 22236Sbill */ 22336Sbill na = 0; 22436Sbill ne = 0; 22536Sbill nc = 0; 22636Sbill uap = (struct execa *)u.u_ap; 2278665S if ((bno = rmalloc(argmap, (long)ctod(clrnd((int)btoc(NCARGS))))) == 0) { 22836Sbill swkill(u.u_procp, "exece"); 22936Sbill goto bad; 23036Sbill } 23136Sbill if (bno % CLSIZE) 2322780Swnj panic("execa rmalloc"); 23336Sbill if (uap->argp) for (;;) { 23436Sbill ap = NULL; 2353621Sroot if (indir && (na == 1 || na == 2 && sharg)) 2362301Skre ap = (int)uap->fname; 2372301Skre else if (uap->argp) { 23836Sbill ap = fuword((caddr_t)uap->argp); 23936Sbill uap->argp++; 24036Sbill } 24136Sbill if (ap==NULL && uap->envp) { 24236Sbill uap->argp = NULL; 24336Sbill if ((ap = fuword((caddr_t)uap->envp)) == NULL) 24436Sbill break; 24536Sbill uap->envp++; 24636Sbill ne++; 24736Sbill } 2486568Smckusic if (ap == NULL) 24936Sbill break; 25036Sbill na++; 2514827Swnj if (ap == -1) 25236Sbill u.u_error = EFAULT; 25336Sbill do { 25436Sbill if (nc >= NCARGS-1) 25536Sbill u.u_error = E2BIG; 2562301Skre if (indir && na == 2 && sharg != NULL) 2572301Skre c = *sharg++ & 0377; 2582301Skre else if ((c = fubyte((caddr_t)ap++)) < 0) 25936Sbill u.u_error = EFAULT; 26083Sbill if (u.u_error) { 26183Sbill if (bp) 26283Sbill brelse(bp); 26383Sbill bp = 0; 26436Sbill goto badarg; 26583Sbill } 2666568Smckusic if (nc % (CLSIZE*NBPG) == 0) { 26736Sbill if (bp) 26836Sbill bdwrite(bp); 2698968Sroot bp = getblk(argdev, bno + ctod(nc / NBPG), 2706568Smckusic CLSIZE*NBPG); 27136Sbill cp = bp->b_un.b_addr; 27236Sbill } 27336Sbill nc++; 27436Sbill *cp++ = c; 2756568Smckusic } while (c > 0); 27636Sbill } 27736Sbill if (bp) 27836Sbill bdwrite(bp); 27936Sbill bp = 0; 28036Sbill nc = (nc + NBPW-1) & ~(NBPW-1); 2816568Smckusic if (indir) { 2826568Smckusic u.u_dent.d_namlen = strlen(cfname); 2836568Smckusic bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name, 2847816Sroot (unsigned)(u.u_dent.d_namlen + 1)); 2856568Smckusic } 2862301Skre getxfile(ip, nc + (na+4)*NBPW, uid, gid); 287912Sbill if (u.u_error) { 28836Sbill badarg: 2899006Sroot for (c = 0; c < nc; c += CLSIZE*NBPG) { 2909006Sroot bp = baddr(argdev, bno + ctod(c / NBPG), CLSIZE*NBPG); 2918968Sroot if (bp) { 29236Sbill bp->b_flags |= B_AGE; /* throw away */ 29336Sbill bp->b_flags &= ~B_DELWRI; /* cancel io */ 29436Sbill brelse(bp); 29536Sbill bp = 0; 29636Sbill } 2979006Sroot } 29836Sbill goto bad; 29936Sbill } 30036Sbill 30136Sbill /* 30236Sbill * copy back arglist 30336Sbill */ 30436Sbill ucp = USRSTACK - nc - NBPW; 30536Sbill ap = ucp - na*NBPW - 3*NBPW; 30636Sbill u.u_ar0[SP] = ap; 307132Sbill (void) suword((caddr_t)ap, na-ne); 30836Sbill nc = 0; 30936Sbill for (;;) { 31036Sbill ap += NBPW; 31136Sbill if (na==ne) { 312132Sbill (void) suword((caddr_t)ap, 0); 31336Sbill ap += NBPW; 31436Sbill } 31536Sbill if (--na < 0) 31636Sbill break; 317132Sbill (void) suword((caddr_t)ap, ucp); 31836Sbill do { 3196568Smckusic if (nc % (CLSIZE*NBPG) == 0) { 32036Sbill if (bp) 32136Sbill brelse(bp); 3229866Ssam bp = bread(argdev, bno + ctod(nc / NBPG), 3236568Smckusic CLSIZE*NBPG); 32436Sbill bp->b_flags |= B_AGE; /* throw away */ 32536Sbill bp->b_flags &= ~B_DELWRI; /* cancel io */ 32636Sbill cp = bp->b_un.b_addr; 32736Sbill } 328132Sbill (void) subyte((caddr_t)ucp++, (c = *cp++)); 32936Sbill nc++; 33036Sbill } while(c&0377); 33136Sbill } 332132Sbill (void) suword((caddr_t)ap, 0); 333132Sbill (void) suword((caddr_t)ucp, 0); 33436Sbill setregs(); 33536Sbill bad: 33636Sbill if (bp) 33736Sbill brelse(bp); 33836Sbill if (bno) 3398816Sroot rmfree(argmap, (long)ctod(clrnd((int) btoc(NCARGS))), bno); 34036Sbill iput(ip); 34136Sbill } 34236Sbill 34336Sbill /* 34436Sbill * Read in and set up memory for executed file. 34536Sbill */ 3462301Skre getxfile(ip, nargc, uid, gid) 34736Sbill register struct inode *ip; 34836Sbill { 34936Sbill register size_t ts, ds, ss; 3502301Skre int pagi; 35136Sbill 3522301Skre if (u.u_exdata.ux_mag == 0413) 35336Sbill pagi = SPAGI; 3542301Skre else 3552301Skre pagi = 0; 3564827Swnj if (u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && 3574827Swnj ip->i_count!=1) { 358890Sbill register struct file *fp; 359890Sbill 3604827Swnj for (fp = file; fp < fileNFILE; fp++) { 3617497Sroot if (fp->f_type == DTYPE_FILE && 3629743Ssam fp->f_count > 0 && 3637497Sroot fp->f_inode == ip && (fp->f_flag&FWRITE)) { 364890Sbill u.u_error = ETXTBSY; 365890Sbill goto bad; 366890Sbill } 3674827Swnj } 36836Sbill } 36936Sbill 37036Sbill /* 3714827Swnj * Compute text and data sizes and make sure not too large. 37236Sbill */ 37336Sbill ts = clrnd(btoc(u.u_exdata.ux_tsize)); 37436Sbill ds = clrnd(btoc((u.u_exdata.ux_dsize+u.u_exdata.ux_bsize))); 37536Sbill ss = clrnd(SSIZE + btoc(nargc)); 376912Sbill if (chksize(ts, ds, ss)) 377912Sbill goto bad; 3784827Swnj 3794827Swnj /* 3804827Swnj * Make sure enough space to start process. 3814827Swnj */ 382912Sbill u.u_cdmap = zdmap; 383912Sbill u.u_csmap = zdmap; 384912Sbill if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL) 385912Sbill goto bad; 38636Sbill 387912Sbill /* 388912Sbill * At this point, committed to the new image! 389912Sbill * Release virtual memory resources of old process, and 390912Sbill * initialize the virtual memory of the new process. 391912Sbill * If we resulted from vfork(), instead wakeup our 392912Sbill * parent who will set SVFDONE when he has taken back 393912Sbill * our resources. 394912Sbill */ 395912Sbill if ((u.u_procp->p_flag & SVFORK) == 0) 396912Sbill vrelvm(); 397912Sbill else { 398912Sbill u.u_procp->p_flag &= ~SVFORK; 399912Sbill u.u_procp->p_flag |= SKEEP; 400912Sbill wakeup((caddr_t)u.u_procp); 401912Sbill while ((u.u_procp->p_flag & SVFDONE) == 0) 402912Sbill sleep((caddr_t)u.u_procp, PZERO - 1); 403912Sbill u.u_procp->p_flag &= ~(SVFDONE|SKEEP); 404912Sbill } 4053592Swnj u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SNUSIG); 406912Sbill u.u_procp->p_flag |= pagi; 407912Sbill u.u_dmap = u.u_cdmap; 408912Sbill u.u_smap = u.u_csmap; 409912Sbill vgetvm(ts, ds, ss); 410912Sbill 4117748Sroot if (pagi == 0) 4127816Sroot u.u_error = 4137816Sroot rdwri(UIO_READ, ip, 4148968Sroot (char *)ctob(dptov(u.u_procp, 0)), 4158968Sroot (int)u.u_exdata.ux_dsize, 4167816Sroot (int)(sizeof(u.u_exdata)+u.u_exdata.ux_tsize), 4177816Sroot 0, (int *)0); 418912Sbill xalloc(ip, pagi); 419912Sbill if (pagi && u.u_procp->p_textp) 420912Sbill vinifod((struct fpte *)dptopte(u.u_procp, 0), 421912Sbill PG_FTEXT, u.u_procp->p_textp->x_iptr, 4228665S (long)(1 + ts/CLSIZE), (int)btoc(u.u_exdata.ux_dsize)); 42336Sbill 4248968Sroot #ifdef vax 425912Sbill /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */ 4268443Sroot #include "../vax/mtpr.h" /* XXX */ 427912Sbill mtpr(TBIA, 0); 4288968Sroot #endif 42936Sbill 4307530Sroot if (u.u_error) 4317530Sroot swkill(u.u_procp, "i/o error mapping pages"); 432912Sbill /* 433912Sbill * set SUID/SGID protections, if no tracing 434912Sbill */ 435912Sbill if ((u.u_procp->p_flag&STRC)==0) { 4364827Swnj u.u_uid = uid; 4374827Swnj u.u_procp->p_uid = uid; 4382301Skre u.u_gid = gid; 4398665S (void) entergroup(gid); 440912Sbill } else 441912Sbill psignal(u.u_procp, SIGTRAP); 44236Sbill u.u_tsize = ts; 44336Sbill u.u_dsize = ds; 44436Sbill u.u_ssize = ss; 44536Sbill bad: 446912Sbill return; 44736Sbill } 44836Sbill 44936Sbill /* 45036Sbill * Clear registers on exec 45136Sbill */ 45236Sbill setregs() 45336Sbill { 454173Sbill register int (**rp)(); 45536Sbill register i; 456188Sbill long sigmask; 45736Sbill 4586464Swnj for (rp = &u.u_signal[1], sigmask = 1L; rp < &u.u_signal[NSIG]; 459188Sbill sigmask <<= 1, rp++) { 460188Sbill switch (*rp) { 461188Sbill 462188Sbill case SIG_IGN: 463188Sbill case SIG_DFL: 464188Sbill case SIG_HOLD: 465188Sbill continue; 466188Sbill 467188Sbill default: 468188Sbill /* 469206Sbill * Normal or deferring catch; revert to default. 470188Sbill */ 471206Sbill (void) spl6(); 472206Sbill *rp = SIG_DFL; 473188Sbill if ((int)*rp & 1) 474188Sbill u.u_procp->p_siga0 |= sigmask; 475188Sbill else 4766327Swnj u.u_procp->p_siga0 &= ~sigmask; 477188Sbill if ((int)*rp & 2) 478188Sbill u.u_procp->p_siga1 |= sigmask; 479188Sbill else 480188Sbill u.u_procp->p_siga1 &= ~sigmask; 481206Sbill (void) spl0(); 482188Sbill continue; 483188Sbill } 484188Sbill } 4858968Sroot #ifdef vax 48636Sbill /* 4874827Swnj for (rp = &u.u_ar0[0]; rp < &u.u_ar0[16];) 48836Sbill *rp++ = 0; 48936Sbill */ 4908968Sroot u.u_ar0[PC] = u.u_exdata.ux_entloc+2; 4918968Sroot #endif 4928968Sroot #ifdef sun 4938968Sroot { register struct regs *r = (struct regs *)u.u_ar0; 4948968Sroot for (i = 0; i < 8; i++) { 4958968Sroot r->r_dreg[i] = 0; 4968968Sroot if (&r->r_areg[i] != &r->r_sp) 4978968Sroot r->r_areg[i] = 0; 4988968Sroot } 4998968Sroot r->r_sr = PSL_USERSET; 5008968Sroot r->r_pc = u.u_exdata.ux_entloc; 5018968Sroot } 5028968Sroot #endif 5034827Swnj for (i=0; i<NOFILE; i++) { 5049591Ssam if (u.u_pofile[i]&UF_EXCLOSE) { 5057697Ssam closef(u.u_ofile[i], 1, u.u_pofile[i]); 50636Sbill u.u_ofile[i] = NULL; 5077697Ssam u.u_pofile[i] = 0; 50836Sbill } 5098968Sroot u.u_pofile[i] &= ~UF_MAPPED; 51036Sbill } 5114827Swnj 51236Sbill /* 51336Sbill * Remember file name for accounting. 51436Sbill */ 51536Sbill u.u_acflag &= ~AFORK; 5166568Smckusic bcopy((caddr_t)u.u_dent.d_name, (caddr_t)u.u_comm, 5177816Sroot (unsigned)(u.u_dent.d_namlen + 1)); 5188968Sroot #ifdef sun 5198968Sroot u.u_eosys = REALLYRETURN; 5208968Sroot #endif 52136Sbill } 52236Sbill 52336Sbill /* 5244827Swnj * Exit system call: pass back caller's arg 52536Sbill */ 52636Sbill rexit() 52736Sbill { 52836Sbill register struct a { 52936Sbill int rval; 53036Sbill } *uap; 53136Sbill 53236Sbill uap = (struct a *)u.u_ap; 53336Sbill exit((uap->rval & 0377) << 8); 53436Sbill } 53536Sbill 53636Sbill /* 53736Sbill * Release resources. 53836Sbill * Save u. area for parent to look at. 53936Sbill * Enter zombie state. 54036Sbill * Wake up parent and init processes, 54136Sbill * and dispose of children. 54236Sbill */ 54336Sbill exit(rv) 54436Sbill { 54536Sbill register int i; 54636Sbill register struct proc *p, *q; 54736Sbill register int x; 5489632Ssam struct mbuf *m = m_getclr(M_WAIT, MT_ZOMBIE); 54936Sbill 55036Sbill #ifdef PGINPROF 55136Sbill vmsizmon(); 55236Sbill #endif 55336Sbill p = u.u_procp; 55436Sbill p->p_flag &= ~(STRC|SULOCK); 55536Sbill p->p_flag |= SWEXIT; 556188Sbill (void) spl6(); 557188Sbill if ((int)SIG_IGN & 1) 558188Sbill p->p_siga0 = ~0; 559188Sbill else 560188Sbill p->p_siga0 = 0; 561188Sbill if ((int)SIG_IGN & 2) 562188Sbill p->p_siga1 = ~0; 563188Sbill else 564206Sbill p->p_siga1 = 0; 565188Sbill (void) spl0(); 5661399Sbill p->p_cpticks = 0; 5671399Sbill p->p_pctcpu = 0; 5684827Swnj for (i=0; i<NSIG; i++) 569173Sbill u.u_signal[i] = SIG_IGN; 5708623Sroot untimeout(realitexpire, (caddr_t)p); 57136Sbill /* 57236Sbill * Release virtual memory. If we resulted from 57336Sbill * a vfork(), instead give the resources back to 57436Sbill * the parent. 57536Sbill */ 57636Sbill if ((p->p_flag & SVFORK) == 0) 57736Sbill vrelvm(); 57836Sbill else { 57936Sbill p->p_flag &= ~SVFORK; 58036Sbill wakeup((caddr_t)p); 58136Sbill while ((p->p_flag & SVFDONE) == 0) 58236Sbill sleep((caddr_t)p, PZERO - 1); 58336Sbill p->p_flag &= ~SVFDONE; 58436Sbill } 5857697Ssam for (i = 0; i < NOFILE; i++) { 5869558Ssam struct file *f; 5879558Ssam int p; 5889558Ssam 58936Sbill f = u.u_ofile[i]; 59036Sbill u.u_ofile[i] = NULL; 5919558Ssam p = u.u_pofile[i]; 5927697Ssam u.u_pofile[i] = 0; 5939558Ssam closef(f, 1, p); 59436Sbill } 5954827Swnj ilock(u.u_cdir); 59636Sbill iput(u.u_cdir); 59736Sbill if (u.u_rdir) { 5984827Swnj ilock(u.u_rdir); 59936Sbill iput(u.u_rdir); 60036Sbill } 6018030Sroot u.u_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; 60236Sbill acct(); 6037488Skre #ifdef QUOTA 6047488Skre qclean(); 6057488Skre #endif 6068968Sroot #ifdef sun 6078968Sroot ctxfree(&u); 6088968Sroot #endif 60936Sbill vrelpt(u.u_procp); 61036Sbill vrelu(u.u_procp, 0); 6115630Swnj (void) spl5(); /* hack for mem alloc race XXX */ 61236Sbill multprog--; 613931Sbill p->p_stat = SZOMB; 614307Sbill noproc = 1; 61536Sbill i = PIDHASH(p->p_pid); 61636Sbill x = p - proc; 61736Sbill if (pidhash[i] == x) 61836Sbill pidhash[i] = p->p_idhash; 61936Sbill else { 62036Sbill for (i = pidhash[i]; i != 0; i = proc[i].p_idhash) 62136Sbill if (proc[i].p_idhash == x) { 62236Sbill proc[i].p_idhash = p->p_idhash; 62336Sbill goto done; 62436Sbill } 62536Sbill panic("exit"); 62636Sbill } 6271409Sbill if (p->p_pid == 1) 6281409Sbill panic("init died"); 62936Sbill done: 6308030Sroot p->p_xstat = rv; 6319558Ssam if (m == 0) 6329558Ssam panic("exit: m_getclr"); 6338827Sroot p->p_ru = mtod(m, struct rusage *); 6348030Sroot *p->p_ru = u.u_ru; 6358030Sroot ruadd(p->p_ru, &u.u_cru); 6364827Swnj for (q = proc; q < procNPROC; q++) 6374827Swnj if (q->p_pptr == p) { 6387488Skre if (q->p_osptr) 6397488Skre q->p_osptr->p_ysptr = q->p_ysptr; 6407488Skre if (q->p_ysptr) 6417488Skre q->p_ysptr->p_osptr = q->p_osptr; 6427488Skre if (proc[1].p_cptr) 6437488Skre proc[1].p_cptr->p_ysptr = q; 6447488Skre q->p_osptr = proc[1].p_cptr; 6457488Skre q->p_ysptr = NULL; 6467488Skre proc[1].p_cptr = q; 6477488Skre 648188Sbill q->p_pptr = &proc[1]; 649188Sbill q->p_ppid = 1; 65036Sbill wakeup((caddr_t)&proc[1]); 651188Sbill /* 652212Sbill * Traced processes are killed 653188Sbill * since their existence means someone is screwing up. 654354Sbill * Stopped processes are sent a hangup and a continue. 655212Sbill * This is designed to be ``safe'' for setuid 656212Sbill * processes since they must be willing to tolerate 657212Sbill * hangups anyways. 658188Sbill */ 659212Sbill if (q->p_flag&STRC) { 660188Sbill q->p_flag &= ~STRC; 661188Sbill psignal(q, SIGKILL); 662212Sbill } else if (q->p_stat == SSTOP) { 663212Sbill psignal(q, SIGHUP); 664212Sbill psignal(q, SIGCONT); 665188Sbill } 666215Sbill /* 667215Sbill * Protect this process from future 6685619Swnj * tty signals, clear TSTP/TTIN/TTOU if pending. 669215Sbill */ 6701788Sbill (void) spgrp(q, -1); 67136Sbill } 6726464Swnj psignal(p->p_pptr, SIGCHLD); 673188Sbill wakeup((caddr_t)p->p_pptr); 67436Sbill swtch(); 67536Sbill } 67636Sbill 677*9990Ssam wait() 678*9990Ssam { 679*9990Ssam struct rusage ru, *rup; 680*9990Ssam 681*9990Ssam if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) { 682*9990Ssam u.u_error = wait1(0, (struct rusage *)0); 683*9990Ssam return; 684*9990Ssam } 685*9990Ssam rup = (struct rusage *)u.u_ar0[R1]; 686*9990Ssam u.u_error = wait1(u.u_ar0[R0], &ru); 687*9990Ssam if (u.u_error) 688*9990Ssam return; 689*9990Ssam (void) copyout((caddr_t)&ru, (caddr_t)rup, sizeof (struct rusage)); 690*9990Ssam } 691*9990Ssam 692*9990Ssam #ifndef NOCOMPAT 6939753Ssam #include "../h/vtimes.h" 6948151Sroot 6958099Sroot owait() 69636Sbill { 6978151Sroot struct rusage ru; 6988151Sroot struct vtimes *vtp, avt; 69936Sbill 700188Sbill if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) { 701*9990Ssam u.u_error = wait1(0, (struct rusage *)0); 702188Sbill return; 703188Sbill } 7048151Sroot vtp = (struct vtimes *)u.u_ar0[R1]; 705*9990Ssam u.u_error = wait1(u.u_ar0[R0], &ru); 706188Sbill if (u.u_error) 707188Sbill return; 7088151Sroot getvtimes(&ru, &avt); 7098151Sroot (void) copyout((caddr_t)&avt, (caddr_t)vtp, sizeof (struct vtimes)); 71036Sbill } 711*9990Ssam #endif 71236Sbill 71336Sbill /* 71436Sbill * Wait system call. 71536Sbill * Search for a terminated (zombie) child, 71636Sbill * finally lay it to rest, and collect its status. 71736Sbill * Look also for stopped (traced) children, 71836Sbill * and pass back status from them. 71936Sbill */ 7208030Sroot wait1(options, ru) 7218030Sroot register int options; 7228030Sroot struct rusage *ru; 72336Sbill { 72436Sbill register f; 7257488Skre register struct proc *p, *q; 72636Sbill 72736Sbill f = 0; 72836Sbill loop: 7294827Swnj for (p = proc; p < procNPROC; p++) 7304827Swnj if (p->p_pptr == u.u_procp) { 73136Sbill f++; 7324827Swnj if (p->p_stat == SZOMB) { 73336Sbill u.u_r.r_val1 = p->p_pid; 7348030Sroot u.u_r.r_val2 = p->p_xstat; 7358030Sroot p->p_xstat = 0; 7368030Sroot if (ru) 7378030Sroot *ru = *p->p_ru; 7388030Sroot ruadd(&u.u_cru, p->p_ru); 7398665S (void) m_free(dtom(p->p_ru)); 7408030Sroot p->p_ru = 0; 74136Sbill p->p_stat = NULL; 74236Sbill p->p_pid = 0; 74336Sbill p->p_ppid = 0; 7447488Skre if (q = p->p_ysptr) 7457488Skre q->p_osptr = p->p_osptr; 7467488Skre if (q = p->p_osptr) 7477488Skre q->p_ysptr = p->p_ysptr; 7487488Skre if ((q = p->p_pptr)->p_cptr == p) 7497488Skre q->p_cptr = p->p_osptr; 750188Sbill p->p_pptr = 0; 7517488Skre p->p_ysptr = 0; 7527488Skre p->p_osptr = 0; 7537488Skre p->p_cptr = 0; 75436Sbill p->p_sig = 0; 755188Sbill p->p_siga0 = 0; 756188Sbill p->p_siga1 = 0; 75736Sbill p->p_pgrp = 0; 75836Sbill p->p_flag = 0; 75936Sbill p->p_wchan = 0; 760188Sbill p->p_cursig = 0; 761*9990Ssam return (0); 76236Sbill } 763188Sbill if (p->p_stat == SSTOP && (p->p_flag&SWTED)==0 && 764188Sbill (p->p_flag&STRC || options&WUNTRACED)) { 765188Sbill p->p_flag |= SWTED; 766188Sbill u.u_r.r_val1 = p->p_pid; 767188Sbill u.u_r.r_val2 = (p->p_cursig<<8) | WSTOPPED; 768*9990Ssam return (0); 76936Sbill } 77036Sbill } 771*9990Ssam if (f == 0) { 772*9990Ssam return (ECHILD); 77336Sbill } 774188Sbill if (options&WNOHANG) { 775188Sbill u.u_r.r_val1 = 0; 776*9990Ssam return (0); 777188Sbill } 7788116Sroot if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) { 779188Sbill u.u_eosys = RESTARTSYS; 780*9990Ssam return (0); 781188Sbill } 782188Sbill sleep((caddr_t)u.u_procp, PWAIT); 783188Sbill goto loop; 78436Sbill } 78536Sbill 78636Sbill /* 78736Sbill * fork system call. 78836Sbill */ 78936Sbill fork() 79036Sbill { 79136Sbill 79236Sbill u.u_cdmap = zdmap; 79336Sbill u.u_csmap = zdmap; 79436Sbill if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 79536Sbill u.u_r.r_val2 = 0; 79636Sbill return; 79736Sbill } 79836Sbill fork1(0); 79936Sbill } 80036Sbill 80136Sbill fork1(isvfork) 80236Sbill { 80336Sbill register struct proc *p1, *p2; 8047488Skre #ifndef QUOTA 80536Sbill register a; 80636Sbill 80736Sbill a = 0; 8087488Skre #else 8097488Skre if (u.u_quota != NOQUOT && u.u_quota->q_plim && 8107488Skre u.u_quota->q_cnt >= u.u_quota->q_plim) { 8117488Skre u.u_error = EPROCLIM; 8127488Skre return; 8137488Skre } 8147488Skre #endif 81536Sbill p2 = NULL; 8164827Swnj for (p1 = proc; p1 < procNPROC; p1++) { 8177488Skre #ifdef QUOTA 8187488Skre if (p1->p_stat == NULL) { 8197488Skre p2 = p1; 8207488Skre break; 8217488Skre } 8227488Skre #else 82336Sbill if (p1->p_stat==NULL && p2==NULL) 82436Sbill p2 = p1; 82536Sbill else { 82636Sbill if (p1->p_uid==u.u_uid && p1->p_stat!=NULL) 82736Sbill a++; 82836Sbill } 8297488Skre #endif 83036Sbill } 83136Sbill /* 83236Sbill * Disallow if 83336Sbill * No processes at all; 83436Sbill * not su and too many procs owned; or 83536Sbill * not su and would take last slot. 83636Sbill */ 8372938Swnj if (p2==NULL) 8382938Swnj tablefull("proc"); 8397488Skre #ifdef QUOTA 8407488Skre if (p2==NULL || (u.u_uid!=0 && p2==procNPROC-1)) { 8417488Skre #else 8422741Swnj if (p2==NULL || (u.u_uid!=0 && (p2==procNPROC-1 || a>MAXUPRC))) { 8437488Skre #endif 84436Sbill u.u_error = EAGAIN; 84536Sbill if (!isvfork) { 846132Sbill (void) vsexpand(0, &u.u_cdmap, 1); 847132Sbill (void) vsexpand(0, &u.u_csmap, 1); 84836Sbill } 84936Sbill goto out; 85036Sbill } 85136Sbill p1 = u.u_procp; 8524827Swnj if (newproc(isvfork)) { 85336Sbill u.u_r.r_val1 = p1->p_pid; 85436Sbill u.u_r.r_val2 = 1; /* child */ 8558030Sroot u.u_start = time.tv_sec; 85636Sbill u.u_acflag = AFORK; 8577488Skre #ifdef QUOTA 8587488Skre u.u_qflags &= ~QUF_LOGIN; 8597488Skre #endif 86036Sbill return; 86136Sbill } 86236Sbill u.u_r.r_val1 = p2->p_pid; 86336Sbill 86436Sbill out: 86536Sbill u.u_r.r_val2 = 0; 86636Sbill } 86736Sbill 8687497Sroot spgrp(top, npgrp) 8697497Sroot register struct proc *top; 8707497Sroot { 8717497Sroot register struct proc *pp, *p; 8727497Sroot int f = 0; 8737497Sroot 8747497Sroot for (p = top; npgrp == -1 || u.u_uid == p->p_uid || 8757497Sroot !u.u_uid || inferior(p); p = pp) { 8767497Sroot if (npgrp == -1) { 8777497Sroot #define bit(a) (1<<(a-1)) 8787497Sroot p->p_sig &= ~(bit(SIGTSTP)|bit(SIGTTIN)|bit(SIGTTOU)); 8797497Sroot } else 8807497Sroot p->p_pgrp = npgrp; 8817497Sroot f++; 8827497Sroot /* 8837497Sroot * Search for children. 8847497Sroot */ 8857497Sroot for (pp = proc; pp < procNPROC; pp++) 8867497Sroot if (pp->p_pptr == p) 8877497Sroot goto cont; 8887497Sroot /* 8897497Sroot * Search for siblings. 8907497Sroot */ 8917497Sroot for (; p != top; p = p->p_pptr) 8927497Sroot for (pp = p + 1; pp < procNPROC; pp++) 8937497Sroot if (pp->p_pptr == p->p_pptr) 8947497Sroot goto cont; 8957497Sroot break; 8967497Sroot cont: 8977497Sroot ; 8987497Sroot } 8997497Sroot return (f); 9007497Sroot } 9017497Sroot 90236Sbill /* 9037497Sroot * Is p an inferior of the current process? 90436Sbill */ 9057497Sroot inferior(p) 9067816Sroot register struct proc *p; 90736Sbill { 90836Sbill 9097497Sroot for (; p != u.u_procp; p = p->p_pptr) 9107497Sroot if (p->p_ppid == 0) 9117497Sroot return (0); 9127497Sroot return (1); 91336Sbill } 9147816Sroot 9157816Sroot struct proc * 9167816Sroot pfind(pid) 9177816Sroot int pid; 9187816Sroot { 9197816Sroot register struct proc *p; 9207816Sroot 9217816Sroot for (p = &proc[pidhash[PIDHASH(pid)]]; p != &proc[0]; p = &proc[p->p_idhash]) 9227816Sroot if (p->p_pid == pid) 9237816Sroot return (p); 9247816Sroot return ((struct proc *)0); 9257816Sroot } 9268099Sroot 9278099Sroot /* 9288099Sroot * Create a new process-- the internal version of 9298099Sroot * sys fork. 9308099Sroot * It returns 1 in the new process, 0 in the old. 9318099Sroot */ 9328099Sroot newproc(isvfork) 9338099Sroot int isvfork; 9348099Sroot { 9358099Sroot register struct proc *p; 9368099Sroot register struct proc *rpp, *rip; 9378099Sroot register int n; 9388099Sroot register struct file *fp; 9398099Sroot 9408099Sroot p = NULL; 9418099Sroot /* 9428099Sroot * First, just locate a slot for a process 9438099Sroot * and copy the useful info from this process into it. 9448099Sroot * The panic "cannot happen" because fork has already 9458099Sroot * checked for the existence of a slot. 9468099Sroot */ 9478099Sroot retry: 9488099Sroot mpid++; 9498099Sroot if (mpid >= 30000) { 9508099Sroot mpid = 0; 9518099Sroot goto retry; 9528099Sroot } 9538099Sroot for (rpp = proc; rpp < procNPROC; rpp++) { 9548099Sroot if (rpp->p_stat == NULL && p==NULL) 9558099Sroot p = rpp; 9568099Sroot if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 9578099Sroot goto retry; 9588099Sroot } 9598099Sroot if ((rpp = p) == NULL) 9608099Sroot panic("no procs"); 9618099Sroot 9628099Sroot /* 9638099Sroot * Make a proc table entry for the new process. 9648099Sroot */ 9658099Sroot rip = u.u_procp; 9668099Sroot #ifdef QUOTA 9678099Sroot (rpp->p_quota = rip->p_quota)->q_cnt++; 9688099Sroot #endif 9698099Sroot rpp->p_stat = SIDL; 9708099Sroot timerclear(&rpp->p_realtimer.it_value); 9718099Sroot rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SNUSIG)); 9728099Sroot if (isvfork) { 9738099Sroot rpp->p_flag |= SVFORK; 9748099Sroot rpp->p_ndx = rip->p_ndx; 9758099Sroot } else 9768099Sroot rpp->p_ndx = rpp - proc; 9778099Sroot rpp->p_uid = rip->p_uid; 9788099Sroot rpp->p_pgrp = rip->p_pgrp; 9798099Sroot rpp->p_nice = rip->p_nice; 9808099Sroot rpp->p_textp = isvfork ? 0 : rip->p_textp; 9818099Sroot rpp->p_pid = mpid; 9828099Sroot rpp->p_ppid = rip->p_pid; 9838099Sroot rpp->p_pptr = rip; 9848099Sroot rpp->p_osptr = rip->p_cptr; 9858099Sroot if (rip->p_cptr) 9868099Sroot rip->p_cptr->p_ysptr = rpp; 9878099Sroot rpp->p_ysptr = NULL; 9888099Sroot rpp->p_cptr = NULL; 9898099Sroot rip->p_cptr = rpp; 9908099Sroot rpp->p_time = 0; 9918099Sroot rpp->p_cpu = 0; 9928099Sroot rpp->p_siga0 = rip->p_siga0; 9938099Sroot rpp->p_siga1 = rip->p_siga1; 9948099Sroot /* take along any pending signals, like stops? */ 9958099Sroot if (isvfork) { 9968099Sroot rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 9978099Sroot rpp->p_szpt = clrnd(ctopt(UPAGES)); 9988099Sroot forkstat.cntvfork++; 9998099Sroot forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 10008099Sroot } else { 10018099Sroot rpp->p_tsize = rip->p_tsize; 10028099Sroot rpp->p_dsize = rip->p_dsize; 10038099Sroot rpp->p_ssize = rip->p_ssize; 10048099Sroot rpp->p_szpt = rip->p_szpt; 10058099Sroot forkstat.cntfork++; 10068099Sroot forkstat.sizfork += rip->p_dsize + rip->p_ssize; 10078099Sroot } 10088099Sroot rpp->p_rssize = 0; 10098099Sroot rpp->p_maxrss = rip->p_maxrss; 10108099Sroot rpp->p_wchan = 0; 10118099Sroot rpp->p_slptime = 0; 10128099Sroot rpp->p_pctcpu = 0; 10138099Sroot rpp->p_cpticks = 0; 10148099Sroot n = PIDHASH(rpp->p_pid); 10158099Sroot p->p_idhash = pidhash[n]; 10168099Sroot pidhash[n] = rpp - proc; 10178099Sroot multprog++; 10188099Sroot 10198099Sroot /* 10208099Sroot * Increase reference counts on shared objects. 10218099Sroot */ 10228099Sroot for (n = 0; n < NOFILE; n++) { 10238099Sroot fp = u.u_ofile[n]; 10248099Sroot if (fp == NULL) 10258099Sroot continue; 10268099Sroot fp->f_count++; 10279591Ssam if (u.u_pofile[n]&UF_SHLOCK) 10289159Ssam fp->f_inode->i_shlockc++; 10299591Ssam if (u.u_pofile[n]&UF_EXLOCK) 10309159Ssam fp->f_inode->i_exlockc++; 10318099Sroot } 10328099Sroot u.u_cdir->i_count++; 10338099Sroot if (u.u_rdir) 10348099Sroot u.u_rdir->i_count++; 10358099Sroot 10368099Sroot /* 10378099Sroot * Partially simulate the environment 10388099Sroot * of the new process so that when it is actually 10398099Sroot * created (by copying) it will look right. 10408099Sroot * This begins the section where we must prevent the parent 10418099Sroot * from being swapped. 10428099Sroot */ 10438099Sroot rip->p_flag |= SKEEP; 10448099Sroot if (procdup(rpp, isvfork)) 10458099Sroot return (1); 10468099Sroot 10478099Sroot /* 10488099Sroot * Make child runnable and add to run queue. 10498099Sroot */ 10508099Sroot (void) spl6(); 10518099Sroot rpp->p_stat = SRUN; 10528099Sroot setrq(rpp); 10538099Sroot (void) spl0(); 10548099Sroot 10558099Sroot /* 10568099Sroot * Cause child to take a non-local goto as soon as it runs. 10578099Sroot * On older systems this was done with SSWAP bit in proc 10588099Sroot * table; on VAX we use u.u_pcb.pcb_sswap so don't need 10598099Sroot * to do rpp->p_flag |= SSWAP. Actually do nothing here. 10608099Sroot */ 10618099Sroot /* rpp->p_flag |= SSWAP; */ 10628099Sroot 10638099Sroot /* 10648099Sroot * Now can be swapped. 10658099Sroot */ 10668099Sroot rip->p_flag &= ~SKEEP; 10678099Sroot 10688099Sroot /* 10698099Sroot * If vfork make chain from parent process to child 10708099Sroot * (where virtal memory is temporarily). Wait for 10718099Sroot * child to finish, steal virtual memory back, 10728099Sroot * and wakeup child to let it die. 10738099Sroot */ 10748099Sroot if (isvfork) { 10758099Sroot u.u_procp->p_xlink = rpp; 10768099Sroot u.u_procp->p_flag |= SNOVM; 10778099Sroot while (rpp->p_flag & SVFORK) 10788099Sroot sleep((caddr_t)rpp, PZERO - 1); 10798099Sroot if ((rpp->p_flag & SLOAD) == 0) 10808099Sroot panic("newproc vfork"); 10818099Sroot uaccess(rpp, Vfmap, &vfutl); 10828099Sroot u.u_procp->p_xlink = 0; 10838099Sroot vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 10848099Sroot u.u_procp->p_flag &= ~SNOVM; 10858099Sroot rpp->p_ndx = rpp - proc; 10868099Sroot rpp->p_flag |= SVFDONE; 10878099Sroot wakeup((caddr_t)rpp); 10888099Sroot } 10898099Sroot 10908099Sroot /* 10918099Sroot * 0 return means parent. 10928099Sroot */ 10938099Sroot return (0); 10948099Sroot } 1095