xref: /csrg-svn/sys/kern/kern_proc.c (revision 8030)
1*8030Sroot /*	kern_proc.c	4.36	82/09/04	*/
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"
9*8030Sroot #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"
25*8030Sroot #include "../h/mbuf.h"
2636Sbill 
27*8030Sroot gethostid()
28*8030Sroot {
29*8030Sroot 
30*8030Sroot }
31*8030Sroot 
32*8030Sroot sethostid()
33*8030Sroot {
34*8030Sroot 
35*8030Sroot }
36*8030Sroot 
3736Sbill /*
3836Sbill  * exec system call, with and without environments.
3936Sbill  */
4036Sbill struct execa {
4136Sbill 	char	*fname;
4236Sbill 	char	**argp;
4336Sbill 	char	**envp;
4436Sbill };
4536Sbill 
46*8030Sroot execv()
4736Sbill {
4836Sbill 	((struct execa *)u.u_ap)->envp = NULL;
49*8030Sroot 	execve();
5036Sbill }
5136Sbill 
52*8030Sroot execve()
5336Sbill {
5436Sbill 	register nc;
5536Sbill 	register char *cp;
5636Sbill 	register struct buf *bp;
5736Sbill 	register struct execa *uap;
5836Sbill 	int na, ne, ucp, ap, c;
592301Skre 	int indir, uid, gid;
602301Skre 	char *sharg;
6136Sbill 	struct inode *ip;
6236Sbill 	swblk_t bno;
636568Smckusic 	char cfname[MAXNAMLEN + 1];
642301Skre 	char cfarg[SHSIZE];
657748Sroot 	int resid;
6636Sbill 
675991Swnj 	if ((ip = namei(uchar, 0, 1)) == NULL)
6836Sbill 		return;
6936Sbill 	bno = 0;
7036Sbill 	bp = 0;
712301Skre 	indir = 0;
722301Skre 	uid = u.u_uid;
732301Skre 	gid = u.u_gid;
742301Skre 	if (ip->i_mode & ISUID)
752301Skre 		uid = ip->i_uid;
762301Skre 	if (ip->i_mode & ISGID)
772301Skre 		gid = ip->i_gid;
782301Skre 
792301Skre   again:
804827Swnj 	if (access(ip, IEXEC))
8136Sbill 		goto bad;
824827Swnj 	if ((u.u_procp->p_flag&STRC) && access(ip, IREAD))
832330Swnj 		goto bad;
844827Swnj 	if ((ip->i_mode & IFMT) != IFREG ||
8536Sbill 	   (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) {
8636Sbill 		u.u_error = EACCES;
8736Sbill 		goto bad;
8836Sbill 	}
892301Skre 
9036Sbill 	/*
912301Skre 	 * Read in first few bytes of file for segment sizes, ux_mag:
922301Skre 	 *	407 = plain executable
932301Skre 	 *	410 = RO text
942301Skre 	 *	413 = demand paged RO text
952301Skre 	 * Also an ASCII line beginning with #! is
962301Skre 	 * the file name of a ``shell'' and arguments may be prepended
972301Skre 	 * to the argument list if given here.
982301Skre 	 *
992301Skre 	 * SHELL NAMES ARE LIMITED IN LENGTH.
1002301Skre 	 *
1012301Skre 	 * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM
1022301Skre 	 * THE ASCII LINE.
1032301Skre 	 */
1047816Sroot 	u.u_error = rdwri(UIO_READ, ip, (caddr_t)&u.u_exdata, sizeof (u.u_exdata),
1057748Sroot 	    0, 1, &resid);
1064827Swnj 	if (u.u_error)
1072301Skre 		goto bad;
1087748Sroot 	u.u_count = resid;
1097816Sroot #ifndef lint
1104982Swnj 	if (u.u_count > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) &&
1114982Swnj 	    u.u_exdata.ux_shell[0] != '#') {
1122301Skre 		u.u_error = ENOEXEC;
1132301Skre 		goto bad;
1142301Skre 	}
1157816Sroot #endif
1162301Skre 	switch (u.u_exdata.ux_mag) {
1172301Skre 
1182301Skre 	case 0407:
1192301Skre 		u.u_exdata.ux_dsize += u.u_exdata.ux_tsize;
1202301Skre 		u.u_exdata.ux_tsize = 0;
1212301Skre 		break;
1222301Skre 
1232301Skre 	case 0413:
1242301Skre 	case 0410:
1252301Skre 		if (u.u_exdata.ux_tsize == 0) {
1262301Skre 			u.u_error = ENOEXEC;
1272301Skre 			goto bad;
1282301Skre 		}
1292301Skre 		break;
1302301Skre 
1312301Skre 	default:
1322301Skre 		if (u.u_exdata.ux_shell[0] != '#' ||
1332301Skre 		    u.u_exdata.ux_shell[1] != '!' ||
1342301Skre 		    indir) {
1352301Skre 			u.u_error = ENOEXEC;
1362301Skre 			goto bad;
1372301Skre 		}
1382301Skre 		cp = &u.u_exdata.ux_shell[2];		/* skip "#!" */
1392301Skre 		while (cp < &u.u_exdata.ux_shell[SHSIZE]) {
1402301Skre 			if (*cp == '\t')
1412301Skre 				*cp = ' ';
1422301Skre 			else if (*cp == '\n') {
1432301Skre 				*cp = '\0';
1442301Skre 				break;
1452301Skre 			}
1462301Skre 			cp++;
1472301Skre 		}
1482301Skre 		if (*cp != '\0') {
1492301Skre 			u.u_error = ENOEXEC;
1502301Skre 			goto bad;
1512301Skre 		}
1522301Skre 		cp = &u.u_exdata.ux_shell[2];
1532301Skre 		while (*cp == ' ')
1542301Skre 			cp++;
1552301Skre 		u.u_dirp = cp;
1562301Skre 		while (*cp && *cp != ' ')
1572301Skre 			cp++;
1582301Skre 		sharg = NULL;
1592301Skre 		if (*cp) {
1602301Skre 			*cp++ = '\0';
1612301Skre 			while (*cp == ' ')
1622301Skre 				cp++;
1632301Skre 			if (*cp) {
1642301Skre 				bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE);
1652301Skre 				sharg = cfarg;
1662301Skre 			}
1672301Skre 		}
1686568Smckusic 		bcopy((caddr_t)u.u_dent.d_name, (caddr_t)cfname,
1697816Sroot 		    (unsigned)(u.u_dent.d_namlen + 1));
1702301Skre 		indir = 1;
1712301Skre 		iput(ip);
1725991Swnj 		ip = namei(schar, 0, 1);
1732301Skre 		if (ip == NULL)
1742301Skre 			return;
1752301Skre 		goto again;
1762301Skre 	}
1772301Skre 
1782301Skre 	/*
17936Sbill 	 * Collect arguments on "file" in swap space.
18036Sbill 	 */
18136Sbill 	na = 0;
18236Sbill 	ne = 0;
18336Sbill 	nc = 0;
18436Sbill 	uap = (struct execa *)u.u_ap;
1852780Swnj 	if ((bno = rmalloc(argmap, ctod(clrnd((int) btoc(NCARGS))))) == 0) {
18636Sbill 		swkill(u.u_procp, "exece");
18736Sbill 		goto bad;
18836Sbill 	}
18936Sbill 	if (bno % CLSIZE)
1902780Swnj 		panic("execa rmalloc");
19136Sbill 	if (uap->argp) for (;;) {
19236Sbill 		ap = NULL;
1933621Sroot 		if (indir && (na == 1 || na == 2 && sharg))
1942301Skre 			ap = (int)uap->fname;
1952301Skre 		else if (uap->argp) {
19636Sbill 			ap = fuword((caddr_t)uap->argp);
19736Sbill 			uap->argp++;
19836Sbill 		}
19936Sbill 		if (ap==NULL && uap->envp) {
20036Sbill 			uap->argp = NULL;
20136Sbill 			if ((ap = fuword((caddr_t)uap->envp)) == NULL)
20236Sbill 				break;
20336Sbill 			uap->envp++;
20436Sbill 			ne++;
20536Sbill 		}
2066568Smckusic 		if (ap == NULL)
20736Sbill 			break;
20836Sbill 		na++;
2094827Swnj 		if (ap == -1)
21036Sbill 			u.u_error = EFAULT;
21136Sbill 		do {
21236Sbill 			if (nc >= NCARGS-1)
21336Sbill 				u.u_error = E2BIG;
2142301Skre 			if (indir && na == 2 && sharg != NULL)
2152301Skre 				c = *sharg++ & 0377;
2162301Skre 			else if ((c = fubyte((caddr_t)ap++)) < 0)
21736Sbill 				u.u_error = EFAULT;
21883Sbill 			if (u.u_error) {
21983Sbill 				if (bp)
22083Sbill 					brelse(bp);
22183Sbill 				bp = 0;
22236Sbill 				goto badarg;
22383Sbill 			}
2246568Smckusic 			if (nc % (CLSIZE*NBPG) == 0) {
22536Sbill 				if (bp)
22636Sbill 					bdwrite(bp);
2276568Smckusic 				bp = getblk(argdev, bno + nc / NBPG,
2286568Smckusic 				    CLSIZE*NBPG);
22936Sbill 				cp = bp->b_un.b_addr;
23036Sbill 			}
23136Sbill 			nc++;
23236Sbill 			*cp++ = c;
2336568Smckusic 		} while (c > 0);
23436Sbill 	}
23536Sbill 	if (bp)
23636Sbill 		bdwrite(bp);
23736Sbill 	bp = 0;
23836Sbill 	nc = (nc + NBPW-1) & ~(NBPW-1);
2396568Smckusic 	if (indir) {
2406568Smckusic 		u.u_dent.d_namlen = strlen(cfname);
2416568Smckusic 		bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name,
2427816Sroot 		    (unsigned)(u.u_dent.d_namlen + 1));
2436568Smckusic 	}
2442301Skre 	getxfile(ip, nc + (na+4)*NBPW, uid, gid);
245912Sbill 	if (u.u_error) {
24636Sbill badarg:
2476568Smckusic 		for (c = 0; c < nc; c += CLSIZE*NBPG)
2486568Smckusic 			if (bp = baddr(argdev, bno + c / NBPG, CLSIZE*NBPG)) {
24936Sbill 				bp->b_flags |= B_AGE;		/* throw away */
25036Sbill 				bp->b_flags &= ~B_DELWRI;	/* cancel io */
25136Sbill 				brelse(bp);
25236Sbill 				bp = 0;
25336Sbill 			}
25436Sbill 		goto bad;
25536Sbill 	}
25636Sbill 
25736Sbill 	/*
25836Sbill 	 * copy back arglist
25936Sbill 	 */
26036Sbill 	ucp = USRSTACK - nc - NBPW;
26136Sbill 	ap = ucp - na*NBPW - 3*NBPW;
26236Sbill 	u.u_ar0[SP] = ap;
263132Sbill 	(void) suword((caddr_t)ap, na-ne);
26436Sbill 	nc = 0;
26536Sbill 	for (;;) {
26636Sbill 		ap += NBPW;
26736Sbill 		if (na==ne) {
268132Sbill 			(void) suword((caddr_t)ap, 0);
26936Sbill 			ap += NBPW;
27036Sbill 		}
27136Sbill 		if (--na < 0)
27236Sbill 			break;
273132Sbill 		(void) suword((caddr_t)ap, ucp);
27436Sbill 		do {
2756568Smckusic 			if (nc % (CLSIZE*NBPG) == 0) {
27636Sbill 				if (bp)
27736Sbill 					brelse(bp);
2786568Smckusic 				bp = bread(argdev, bno + nc / NBPG,
2796568Smckusic 				    CLSIZE*NBPG);
28036Sbill 				bp->b_flags |= B_AGE;		/* throw away */
28136Sbill 				bp->b_flags &= ~B_DELWRI;	/* cancel io */
28236Sbill 				cp = bp->b_un.b_addr;
28336Sbill 			}
284132Sbill 			(void) subyte((caddr_t)ucp++, (c = *cp++));
28536Sbill 			nc++;
28636Sbill 		} while(c&0377);
28736Sbill 	}
288132Sbill 	(void) suword((caddr_t)ap, 0);
289132Sbill 	(void) suword((caddr_t)ucp, 0);
29036Sbill 	setregs();
29136Sbill bad:
29236Sbill 	if (bp)
29336Sbill 		brelse(bp);
29436Sbill 	if (bno)
2952780Swnj 		rmfree(argmap, ctod(clrnd((int) btoc(NCARGS))), bno);
29636Sbill 	iput(ip);
29736Sbill }
29836Sbill 
29936Sbill /*
30036Sbill  * Read in and set up memory for executed file.
30136Sbill  */
3022301Skre getxfile(ip, nargc, uid, gid)
30336Sbill register struct inode *ip;
30436Sbill {
30536Sbill 	register size_t ts, ds, ss;
3062301Skre 	int pagi;
30736Sbill 
3082301Skre 	if (u.u_exdata.ux_mag == 0413)
30936Sbill 		pagi = SPAGI;
3102301Skre 	else
3112301Skre 		pagi = 0;
3124827Swnj 	if (u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 &&
3134827Swnj 	    ip->i_count!=1) {
314890Sbill 		register struct file *fp;
315890Sbill 
3164827Swnj 		for (fp = file; fp < fileNFILE; fp++) {
3177497Sroot 			if (fp->f_type == DTYPE_FILE &&
3187497Sroot 			    fp->f_inode == ip && (fp->f_flag&FWRITE)) {
319890Sbill 				u.u_error = ETXTBSY;
320890Sbill 				goto bad;
321890Sbill 			}
3224827Swnj 		}
32336Sbill 	}
32436Sbill 
32536Sbill 	/*
3264827Swnj 	 * Compute text and data sizes and make sure not too large.
32736Sbill 	 */
32836Sbill 	ts = clrnd(btoc(u.u_exdata.ux_tsize));
32936Sbill 	ds = clrnd(btoc((u.u_exdata.ux_dsize+u.u_exdata.ux_bsize)));
33036Sbill 	ss = clrnd(SSIZE + btoc(nargc));
331912Sbill 	if (chksize(ts, ds, ss))
332912Sbill 		goto bad;
3334827Swnj 
3344827Swnj 	/*
3354827Swnj 	 * Make sure enough space to start process.
3364827Swnj 	 */
337912Sbill 	u.u_cdmap = zdmap;
338912Sbill 	u.u_csmap = zdmap;
339912Sbill 	if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL)
340912Sbill 		goto bad;
34136Sbill 
342912Sbill 	/*
343912Sbill 	 * At this point, committed to the new image!
344912Sbill 	 * Release virtual memory resources of old process, and
345912Sbill 	 * initialize the virtual memory of the new process.
346912Sbill 	 * If we resulted from vfork(), instead wakeup our
347912Sbill 	 * parent who will set SVFDONE when he has taken back
348912Sbill 	 * our resources.
349912Sbill 	 */
350912Sbill 	if ((u.u_procp->p_flag & SVFORK) == 0)
351912Sbill 		vrelvm();
352912Sbill 	else {
353912Sbill 		u.u_procp->p_flag &= ~SVFORK;
354912Sbill 		u.u_procp->p_flag |= SKEEP;
355912Sbill 		wakeup((caddr_t)u.u_procp);
356912Sbill 		while ((u.u_procp->p_flag & SVFDONE) == 0)
357912Sbill 			sleep((caddr_t)u.u_procp, PZERO - 1);
358912Sbill 		u.u_procp->p_flag &= ~(SVFDONE|SKEEP);
359912Sbill 	}
3603592Swnj 	u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SNUSIG);
361912Sbill 	u.u_procp->p_flag |= pagi;
362912Sbill 	u.u_dmap = u.u_cdmap;
363912Sbill 	u.u_smap = u.u_csmap;
364912Sbill 	vgetvm(ts, ds, ss);
365912Sbill 
3667748Sroot 	if (pagi == 0)
3677816Sroot 		u.u_error =
3687816Sroot 		    rdwri(UIO_READ, ip,
3697816Sroot 			(char*)ctob(ts), (int)u.u_exdata.ux_dsize,
3707816Sroot 			(int)(sizeof(u.u_exdata)+u.u_exdata.ux_tsize),
3717816Sroot 			0, (int *)0);
372912Sbill 	xalloc(ip, pagi);
373912Sbill 	if (pagi && u.u_procp->p_textp)
374912Sbill 		vinifod((struct fpte *)dptopte(u.u_procp, 0),
375912Sbill 		    PG_FTEXT, u.u_procp->p_textp->x_iptr,
376912Sbill 		    1 + ts/CLSIZE, (int)btoc(u.u_exdata.ux_dsize));
37736Sbill 
378912Sbill 	/* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */
379912Sbill 	mtpr(TBIA, 0);
38036Sbill 
3817530Sroot 	if (u.u_error)
3827530Sroot 		swkill(u.u_procp, "i/o error mapping pages");
383912Sbill 	/*
384912Sbill 	 * set SUID/SGID protections, if no tracing
385912Sbill 	 */
386912Sbill 	if ((u.u_procp->p_flag&STRC)==0) {
3874827Swnj 		u.u_uid = uid;
3884827Swnj 		u.u_procp->p_uid = uid;
3892301Skre 		u.u_gid = gid;
3907865Sroot 		entergroup(gid);
391912Sbill 	} else
392912Sbill 		psignal(u.u_procp, SIGTRAP);
39336Sbill 	u.u_tsize = ts;
39436Sbill 	u.u_dsize = ds;
39536Sbill 	u.u_ssize = ss;
39636Sbill bad:
397912Sbill 	return;
39836Sbill }
39936Sbill 
40036Sbill /*
40136Sbill  * Clear registers on exec
40236Sbill  */
40336Sbill setregs()
40436Sbill {
405173Sbill 	register int (**rp)();
40636Sbill 	register i;
407188Sbill 	long sigmask;
40836Sbill 
4096464Swnj 	for (rp = &u.u_signal[1], sigmask = 1L; rp < &u.u_signal[NSIG];
410188Sbill 	    sigmask <<= 1, rp++) {
411188Sbill 		switch (*rp) {
412188Sbill 
413188Sbill 		case SIG_IGN:
414188Sbill 		case SIG_DFL:
415188Sbill 		case SIG_HOLD:
416188Sbill 			continue;
417188Sbill 
418188Sbill 		default:
419188Sbill 			/*
420206Sbill 			 * Normal or deferring catch; revert to default.
421188Sbill 			 */
422206Sbill 			(void) spl6();
423206Sbill 			*rp = SIG_DFL;
424188Sbill 			if ((int)*rp & 1)
425188Sbill 				u.u_procp->p_siga0 |= sigmask;
426188Sbill 			else
4276327Swnj 				u.u_procp->p_siga0 &= ~sigmask;
428188Sbill 			if ((int)*rp & 2)
429188Sbill 				u.u_procp->p_siga1 |= sigmask;
430188Sbill 			else
431188Sbill 				u.u_procp->p_siga1 &= ~sigmask;
432206Sbill 			(void) spl0();
433188Sbill 			continue;
434188Sbill 		}
435188Sbill 	}
43636Sbill /*
4374827Swnj 	for (rp = &u.u_ar0[0]; rp < &u.u_ar0[16];)
43836Sbill 		*rp++ = 0;
43936Sbill */
44036Sbill 	u.u_ar0[PC] = u.u_exdata.ux_entloc + 2; /* skip over entry mask */
4414827Swnj 	for (i=0; i<NOFILE; i++) {
44236Sbill 		if (u.u_pofile[i]&EXCLOSE) {
4437697Ssam 			closef(u.u_ofile[i], 1, u.u_pofile[i]);
44436Sbill 			u.u_ofile[i] = NULL;
4457697Ssam 			u.u_pofile[i] = 0;
44636Sbill 		}
44736Sbill 	}
4484827Swnj 
44936Sbill 	/*
45036Sbill 	 * Remember file name for accounting.
45136Sbill 	 */
45236Sbill 	u.u_acflag &= ~AFORK;
4536568Smckusic 	bcopy((caddr_t)u.u_dent.d_name, (caddr_t)u.u_comm,
4547816Sroot 	    (unsigned)(u.u_dent.d_namlen + 1));
45536Sbill }
45636Sbill 
45736Sbill /*
4584827Swnj  * Exit system call: pass back caller's arg
45936Sbill  */
46036Sbill rexit()
46136Sbill {
46236Sbill 	register struct a {
46336Sbill 		int	rval;
46436Sbill 	} *uap;
46536Sbill 
46636Sbill 	uap = (struct a *)u.u_ap;
46736Sbill 	exit((uap->rval & 0377) << 8);
46836Sbill }
46936Sbill 
47036Sbill /*
47136Sbill  * Release resources.
47236Sbill  * Save u. area for parent to look at.
47336Sbill  * Enter zombie state.
47436Sbill  * Wake up parent and init processes,
47536Sbill  * and dispose of children.
47636Sbill  */
47736Sbill exit(rv)
47836Sbill {
47936Sbill 	register int i;
48036Sbill 	register struct proc *p, *q;
48136Sbill 	register int x;
48236Sbill 
48336Sbill #ifdef PGINPROF
48436Sbill 	vmsizmon();
48536Sbill #endif
48636Sbill 	p = u.u_procp;
48736Sbill 	p->p_flag &= ~(STRC|SULOCK);
48836Sbill 	p->p_flag |= SWEXIT;
489*8030Sroot 	timerclear(&p->p_seltimer);
490188Sbill 	(void) spl6();
491188Sbill 	if ((int)SIG_IGN & 1)
492188Sbill 		p->p_siga0 = ~0;
493188Sbill 	else
494188Sbill 		p->p_siga0 = 0;
495188Sbill 	if ((int)SIG_IGN & 2)
496188Sbill 		p->p_siga1 = ~0;
497188Sbill 	else
498206Sbill 		p->p_siga1 = 0;
499188Sbill 	(void) spl0();
5001399Sbill 	p->p_cpticks = 0;
5011399Sbill 	p->p_pctcpu = 0;
5024827Swnj 	for (i=0; i<NSIG; i++)
503173Sbill 		u.u_signal[i] = SIG_IGN;
50436Sbill 	/*
50536Sbill 	 * Release virtual memory.  If we resulted from
50636Sbill 	 * a vfork(), instead give the resources back to
50736Sbill 	 * the parent.
50836Sbill 	 */
50936Sbill 	if ((p->p_flag & SVFORK) == 0)
51036Sbill 		vrelvm();
51136Sbill 	else {
51236Sbill 		p->p_flag &= ~SVFORK;
51336Sbill 		wakeup((caddr_t)p);
51436Sbill 		while ((p->p_flag & SVFDONE) == 0)
51536Sbill 			sleep((caddr_t)p, PZERO - 1);
51636Sbill 		p->p_flag &= ~SVFDONE;
51736Sbill 	}
5187697Ssam 	for (i = 0; i < NOFILE; i++) {
5197697Ssam #ifdef notdef
5207697Ssam 		/* why was this like this? */
52136Sbill 		f = u.u_ofile[i];
52236Sbill 		u.u_ofile[i] = NULL;
5235581Swnj 		closef(f, 1);
5247697Ssam #else
5257697Ssam 		closef(u.u_ofile[i], 1, u.u_pofile[i]);
5267697Ssam 		u.u_ofile[i] = NULL;
5277697Ssam 		u.u_pofile[i] = 0;
5287697Ssam #endif
52936Sbill 	}
5304827Swnj 	ilock(u.u_cdir);
53136Sbill 	iput(u.u_cdir);
53236Sbill 	if (u.u_rdir) {
5334827Swnj 		ilock(u.u_rdir);
53436Sbill 		iput(u.u_rdir);
53536Sbill 	}
536*8030Sroot 	u.u_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
53736Sbill 	acct();
5387488Skre #ifdef QUOTA
5397488Skre 	qclean();
5407488Skre #endif
54136Sbill 	vrelpt(u.u_procp);
54236Sbill 	vrelu(u.u_procp, 0);
5435630Swnj 	(void) spl5();		/* hack for mem alloc race XXX */
54436Sbill 	multprog--;
545931Sbill 	p->p_stat = SZOMB;
546307Sbill 	noproc = 1;
54736Sbill 	i = PIDHASH(p->p_pid);
54836Sbill 	x = p - proc;
54936Sbill 	if (pidhash[i] == x)
55036Sbill 		pidhash[i] = p->p_idhash;
55136Sbill 	else {
55236Sbill 		for (i = pidhash[i]; i != 0; i = proc[i].p_idhash)
55336Sbill 			if (proc[i].p_idhash == x) {
55436Sbill 				proc[i].p_idhash = p->p_idhash;
55536Sbill 				goto done;
55636Sbill 			}
55736Sbill 		panic("exit");
55836Sbill 	}
5591409Sbill 	if (p->p_pid == 1)
5601409Sbill 		panic("init died");
56136Sbill done:
562*8030Sroot 	p->p_xstat = rv;
563*8030Sroot 	{ struct mbuf *m = m_getclr(M_DONTWAIT); p->p_ru = mtod(m, struct rusage *); }
564*8030Sroot 	*p->p_ru = u.u_ru;
565*8030Sroot 	ruadd(p->p_ru, &u.u_cru);
5664827Swnj 	for (q = proc; q < procNPROC; q++)
5674827Swnj 		if (q->p_pptr == p) {
5687488Skre 			if (q->p_osptr)
5697488Skre 				q->p_osptr->p_ysptr = q->p_ysptr;
5707488Skre 			if (q->p_ysptr)
5717488Skre 				q->p_ysptr->p_osptr = q->p_osptr;
5727488Skre 			if (proc[1].p_cptr)
5737488Skre 				proc[1].p_cptr->p_ysptr = q;
5747488Skre 			q->p_osptr = proc[1].p_cptr;
5757488Skre 			q->p_ysptr = NULL;
5767488Skre 			proc[1].p_cptr = q;
5777488Skre 
578188Sbill 			q->p_pptr = &proc[1];
579188Sbill 			q->p_ppid = 1;
58036Sbill 			wakeup((caddr_t)&proc[1]);
581188Sbill 			/*
582212Sbill 			 * Traced processes are killed
583188Sbill 			 * since their existence means someone is screwing up.
584354Sbill 			 * Stopped processes are sent a hangup and a continue.
585212Sbill 			 * This is designed to be ``safe'' for setuid
586212Sbill 			 * processes since they must be willing to tolerate
587212Sbill 			 * hangups anyways.
588188Sbill 			 */
589212Sbill 			if (q->p_flag&STRC) {
590188Sbill 				q->p_flag &= ~STRC;
591188Sbill 				psignal(q, SIGKILL);
592212Sbill 			} else if (q->p_stat == SSTOP) {
593212Sbill 				psignal(q, SIGHUP);
594212Sbill 				psignal(q, SIGCONT);
595188Sbill 			}
596215Sbill 			/*
597215Sbill 			 * Protect this process from future
5985619Swnj 			 * tty signals, clear TSTP/TTIN/TTOU if pending.
599215Sbill 			 */
6001788Sbill 			(void) spgrp(q, -1);
60136Sbill 		}
6026464Swnj 	psignal(p->p_pptr, SIGCHLD);
603188Sbill 	wakeup((caddr_t)p->p_pptr);
60436Sbill 	swtch();
60536Sbill }
60636Sbill 
60736Sbill wait()
60836Sbill {
609*8030Sroot 	struct rusage ru, *rup;
61036Sbill 
611188Sbill 	if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) {
612*8030Sroot 		wait1(0, (struct rusage *)0);
613188Sbill 		return;
614188Sbill 	}
615*8030Sroot 	rup = (struct rusage *)u.u_ar0[R1];
616*8030Sroot 	wait1(u.u_ar0[R0], &ru);
617188Sbill 	if (u.u_error)
618188Sbill 		return;
619*8030Sroot 	(void) copyout((caddr_t)&ru, (caddr_t)rup, sizeof (struct rusage));
62036Sbill }
62136Sbill 
62236Sbill /*
62336Sbill  * Wait system call.
62436Sbill  * Search for a terminated (zombie) child,
62536Sbill  * finally lay it to rest, and collect its status.
62636Sbill  * Look also for stopped (traced) children,
62736Sbill  * and pass back status from them.
62836Sbill  */
629*8030Sroot wait1(options, ru)
630*8030Sroot 	register int options;
631*8030Sroot 	struct rusage *ru;
63236Sbill {
63336Sbill 	register f;
6347488Skre 	register struct proc *p, *q;
63536Sbill 
63636Sbill 	f = 0;
63736Sbill loop:
6384827Swnj 	for (p = proc; p < procNPROC; p++)
6394827Swnj 	if (p->p_pptr == u.u_procp) {
64036Sbill 		f++;
6414827Swnj 		if (p->p_stat == SZOMB) {
64236Sbill 			u.u_r.r_val1 = p->p_pid;
643*8030Sroot 			u.u_r.r_val2 = p->p_xstat;
644*8030Sroot 			p->p_xstat = 0;
645*8030Sroot 			if (ru)
646*8030Sroot 				*ru = *p->p_ru;
647*8030Sroot 			ruadd(&u.u_cru, p->p_ru);
648*8030Sroot 			m_free(dtom(p->p_ru));
649*8030Sroot 			p->p_ru = 0;
65036Sbill 			p->p_stat = NULL;
65136Sbill 			p->p_pid = 0;
65236Sbill 			p->p_ppid = 0;
6537488Skre 			if (q = p->p_ysptr)
6547488Skre 				q->p_osptr = p->p_osptr;
6557488Skre 			if (q = p->p_osptr)
6567488Skre 				q->p_ysptr = p->p_ysptr;
6577488Skre 			if ((q = p->p_pptr)->p_cptr == p)
6587488Skre 				q->p_cptr = p->p_osptr;
659188Sbill 			p->p_pptr = 0;
6607488Skre 			p->p_ysptr = 0;
6617488Skre 			p->p_osptr = 0;
6627488Skre 			p->p_cptr = 0;
66336Sbill 			p->p_sig = 0;
664188Sbill 			p->p_siga0 = 0;
665188Sbill 			p->p_siga1 = 0;
66636Sbill 			p->p_pgrp = 0;
66736Sbill 			p->p_flag = 0;
66836Sbill 			p->p_wchan = 0;
669188Sbill 			p->p_cursig = 0;
67036Sbill 			return;
67136Sbill 		}
672188Sbill 		if (p->p_stat == SSTOP && (p->p_flag&SWTED)==0 &&
673188Sbill 		    (p->p_flag&STRC || options&WUNTRACED)) {
674188Sbill 			p->p_flag |= SWTED;
675188Sbill 			u.u_r.r_val1 = p->p_pid;
676188Sbill 			u.u_r.r_val2 = (p->p_cursig<<8) | WSTOPPED;
677188Sbill 			return;
67836Sbill 		}
67936Sbill 	}
680188Sbill 	if (f==0) {
681188Sbill 		u.u_error = ECHILD;
682188Sbill 		return;
68336Sbill 	}
684188Sbill 	if (options&WNOHANG) {
685188Sbill 		u.u_r.r_val1 = 0;
686188Sbill 		return;
687188Sbill 	}
688912Sbill 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
689188Sbill 		u.u_eosys = RESTARTSYS;
690188Sbill 		return;
691188Sbill 	}
692188Sbill 	sleep((caddr_t)u.u_procp, PWAIT);
693188Sbill 	goto loop;
69436Sbill }
69536Sbill 
69636Sbill /*
69736Sbill  * fork system call.
69836Sbill  */
69936Sbill fork()
70036Sbill {
70136Sbill 
70236Sbill 	u.u_cdmap = zdmap;
70336Sbill 	u.u_csmap = zdmap;
70436Sbill 	if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) {
70536Sbill 		u.u_r.r_val2 = 0;
70636Sbill 		return;
70736Sbill 	}
70836Sbill 	fork1(0);
70936Sbill }
71036Sbill 
71136Sbill fork1(isvfork)
71236Sbill {
71336Sbill 	register struct proc *p1, *p2;
7147488Skre #ifndef	QUOTA
71536Sbill 	register a;
71636Sbill 
71736Sbill 	a = 0;
7187488Skre #else
7197488Skre 	if (u.u_quota != NOQUOT && u.u_quota->q_plim &&
7207488Skre 	    u.u_quota->q_cnt >= u.u_quota->q_plim) {
7217488Skre 		u.u_error = EPROCLIM;
7227488Skre 		return;
7237488Skre 	}
7247488Skre #endif
72536Sbill 	p2 = NULL;
7264827Swnj 	for (p1 = proc; p1 < procNPROC; p1++) {
7277488Skre #ifdef QUOTA
7287488Skre 		if (p1->p_stat == NULL) {
7297488Skre 			p2 = p1;
7307488Skre 			break;
7317488Skre 		}
7327488Skre #else
73336Sbill 		if (p1->p_stat==NULL && p2==NULL)
73436Sbill 			p2 = p1;
73536Sbill 		else {
73636Sbill 			if (p1->p_uid==u.u_uid && p1->p_stat!=NULL)
73736Sbill 				a++;
73836Sbill 		}
7397488Skre #endif
74036Sbill 	}
74136Sbill 	/*
74236Sbill 	 * Disallow if
74336Sbill 	 *  No processes at all;
74436Sbill 	 *  not su and too many procs owned; or
74536Sbill 	 *  not su and would take last slot.
74636Sbill 	 */
7472938Swnj 	if (p2==NULL)
7482938Swnj 		tablefull("proc");
7497488Skre #ifdef QUOTA
7507488Skre 	if (p2==NULL || (u.u_uid!=0 && p2==procNPROC-1)) {
7517488Skre #else
7522741Swnj 	if (p2==NULL || (u.u_uid!=0 && (p2==procNPROC-1 || a>MAXUPRC))) {
7537488Skre #endif
75436Sbill 		u.u_error = EAGAIN;
75536Sbill 		if (!isvfork) {
756132Sbill 			(void) vsexpand(0, &u.u_cdmap, 1);
757132Sbill 			(void) vsexpand(0, &u.u_csmap, 1);
75836Sbill 		}
75936Sbill 		goto out;
76036Sbill 	}
76136Sbill 	p1 = u.u_procp;
7624827Swnj 	if (newproc(isvfork)) {
76336Sbill 		u.u_r.r_val1 = p1->p_pid;
76436Sbill 		u.u_r.r_val2 = 1;  /* child */
765*8030Sroot 		u.u_start = time.tv_sec;
76636Sbill 		u.u_acflag = AFORK;
7677488Skre #ifdef QUOTA
7687488Skre 		u.u_qflags &= ~QUF_LOGIN;
7697488Skre #endif
77036Sbill 		return;
77136Sbill 	}
77236Sbill 	u.u_r.r_val1 = p2->p_pid;
77336Sbill 
77436Sbill out:
77536Sbill 	u.u_r.r_val2 = 0;
77636Sbill }
77736Sbill 
7787497Sroot spgrp(top, npgrp)
7797497Sroot register struct proc *top;
7807497Sroot {
7817497Sroot 	register struct proc *pp, *p;
7827497Sroot 	int f = 0;
7837497Sroot 
7847497Sroot 	for (p = top; npgrp == -1 || u.u_uid == p->p_uid ||
7857497Sroot 	    !u.u_uid || inferior(p); p = pp) {
7867497Sroot 		if (npgrp == -1) {
7877497Sroot #define	bit(a)	(1<<(a-1))
7887497Sroot 			p->p_sig &= ~(bit(SIGTSTP)|bit(SIGTTIN)|bit(SIGTTOU));
7897497Sroot 		} else
7907497Sroot 			p->p_pgrp = npgrp;
7917497Sroot 		f++;
7927497Sroot 		/*
7937497Sroot 		 * Search for children.
7947497Sroot 		 */
7957497Sroot 		for (pp = proc; pp < procNPROC; pp++)
7967497Sroot 			if (pp->p_pptr == p)
7977497Sroot 				goto cont;
7987497Sroot 		/*
7997497Sroot 		 * Search for siblings.
8007497Sroot 		 */
8017497Sroot 		for (; p != top; p = p->p_pptr)
8027497Sroot 			for (pp = p + 1; pp < procNPROC; pp++)
8037497Sroot 				if (pp->p_pptr == p->p_pptr)
8047497Sroot 					goto cont;
8057497Sroot 		break;
8067497Sroot 	cont:
8077497Sroot 		;
8087497Sroot 	}
8097497Sroot 	return (f);
8107497Sroot }
8117497Sroot 
81236Sbill /*
8137497Sroot  * Is p an inferior of the current process?
81436Sbill  */
8157497Sroot inferior(p)
8167816Sroot 	register struct proc *p;
81736Sbill {
81836Sbill 
8197497Sroot 	for (; p != u.u_procp; p = p->p_pptr)
8207497Sroot 		if (p->p_ppid == 0)
8217497Sroot 			return (0);
8227497Sroot 	return (1);
82336Sbill }
8247816Sroot 
8257816Sroot struct proc *
8267816Sroot pfind(pid)
8277816Sroot 	int pid;
8287816Sroot {
8297816Sroot 	register struct proc *p;
8307816Sroot 
8317816Sroot 	for (p = &proc[pidhash[PIDHASH(pid)]]; p != &proc[0]; p = &proc[p->p_idhash])
8327816Sroot 		if (p->p_pid == pid)
8337816Sroot 			return (p);
8347816Sroot 	return ((struct proc *)0);
8357816Sroot }
836