xref: /netbsd-src/sys/kern/kern_proc.c (revision 6ea46cb5e46c49111a6ecf3bcbe3c7e2730fe9f6)
1 /*	$NetBSD: kern_proc.c,v 1.10 1994/08/30 03:05:38 mycroft Exp $	*/
2 
3 /*
4  * Copyright (c) 1982, 1986, 1989, 1991, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *	@(#)kern_proc.c	8.4 (Berkeley) 1/4/94
36  */
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/map.h>
41 #include <sys/kernel.h>
42 #include <sys/proc.h>
43 #include <sys/buf.h>
44 #include <sys/acct.h>
45 #include <sys/wait.h>
46 #include <sys/file.h>
47 #include <ufs/ufs/quota.h>
48 #include <sys/uio.h>
49 #include <sys/malloc.h>
50 #include <sys/mbuf.h>
51 #include <sys/ioctl.h>
52 #include <sys/tty.h>
53 
54 /*
55  * Structure associated with user cacheing.
56  */
57 struct uidinfo {
58 	LIST_ENTRY(uidinfo) ui_hash;
59 	uid_t	ui_uid;
60 	long	ui_proccnt;
61 };
62 #define	UIHASH(uid)	(&uihashtbl[(uid) & uihash])
63 LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
64 u_long uihash;		/* size of hash table - 1 */
65 
66 /*
67  * Other process lists
68  */
69 struct pidhashhead *pidhashtbl;
70 u_long pidhash;
71 struct pgrphashhead *pgrphashtbl;
72 u_long pgrphash;
73 struct proclist allproc;
74 struct proclist zombproc;
75 
76 /*
77  * Initialize global process hashing structures.
78  */
79 procinit()
80 {
81 
82 	LIST_INIT(&allproc);
83 	LIST_INIT(&zombproc);
84 	pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash);
85 	pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash);
86 	uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash);
87 }
88 
89 /*
90  * Change the count associated with number of processes
91  * a given user is using.
92  */
93 int
94 chgproccnt(uid, diff)
95 	uid_t	uid;
96 	int	diff;
97 {
98 	register struct uidinfo *uip;
99 	register struct uihashhead *uipp;
100 
101 	uipp = UIHASH(uid);
102 	for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next)
103 		if (uip->ui_uid == uid)
104 			break;
105 	if (uip) {
106 		uip->ui_proccnt += diff;
107 		if (uip->ui_proccnt > 0)
108 			return (uip->ui_proccnt);
109 		if (uip->ui_proccnt < 0)
110 			panic("chgproccnt: procs < 0");
111 		LIST_REMOVE(uip, ui_hash);
112 		FREE(uip, M_PROC);
113 		return (0);
114 	}
115 	if (diff <= 0) {
116 		if (diff == 0)
117 			return(0);
118 		panic("chgproccnt: lost user");
119 	}
120 	MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK);
121 	LIST_INSERT_HEAD(uipp, uip, ui_hash);
122 	uip->ui_uid = uid;
123 	uip->ui_proccnt = diff;
124 	return (diff);
125 }
126 
127 /*
128  * Is p an inferior of the current process?
129  */
130 inferior(p)
131 	register struct proc *p;
132 {
133 
134 	for (; p != curproc; p = p->p_pptr)
135 		if (p->p_pid == 0)
136 			return (0);
137 	return (1);
138 }
139 
140 /*
141  * Locate a process by number
142  */
143 struct proc *
144 pfind(pid)
145 	register pid_t pid;
146 {
147 	register struct proc *p;
148 
149 	for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next)
150 		if (p->p_pid == pid)
151 			return (p);
152 	return (NULL);
153 }
154 
155 /*
156  * Locate a process group by number
157  */
158 struct pgrp *
159 pgfind(pgid)
160 	register pid_t pgid;
161 {
162 	register struct pgrp *pgrp;
163 
164 	for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0; pgrp = pgrp->pg_hash.le_next)
165 		if (pgrp->pg_id == pgid)
166 			return (pgrp);
167 	return (NULL);
168 }
169 
170 /*
171  * Move p to a new or existing process group (and session)
172  */
173 enterpgrp(p, pgid, mksess)
174 	register struct proc *p;
175 	pid_t pgid;
176 	int mksess;
177 {
178 	register struct pgrp *pgrp = pgfind(pgid);
179 	int n;
180 
181 #ifdef DIAGNOSTIC
182 	if (pgrp != NULL && mksess)	/* firewalls */
183 		panic("enterpgrp: setsid into non-empty pgrp");
184 	if (SESS_LEADER(p))
185 		panic("enterpgrp: session leader attempted setpgrp");
186 #endif
187 	if (pgrp == NULL) {
188 		pid_t savepid = p->p_pid;
189 		struct proc *np;
190 		/*
191 		 * new process group
192 		 */
193 #ifdef DIAGNOSTIC
194 		if (p->p_pid != pgid)
195 			panic("enterpgrp: new pgrp and pid != pgid");
196 #endif
197 		MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
198 		    M_WAITOK);
199 		if ((np = pfind(savepid)) == NULL || np != p)
200 			return (ESRCH);
201 		if (mksess) {
202 			register struct session *sess;
203 
204 			/*
205 			 * new session
206 			 */
207 			MALLOC(sess, struct session *, sizeof(struct session),
208 			    M_SESSION, M_WAITOK);
209 			sess->s_leader = p;
210 			sess->s_count = 1;
211 			sess->s_ttyvp = NULL;
212 			sess->s_ttyp = NULL;
213 			bcopy(p->p_session->s_login, sess->s_login,
214 			    sizeof(sess->s_login));
215 			p->p_flag &= ~P_CONTROLT;
216 			pgrp->pg_session = sess;
217 #ifdef DIAGNOSTIC
218 			if (p != curproc)
219 				panic("enterpgrp: mksession and p != curproc");
220 #endif
221 		} else {
222 			pgrp->pg_session = p->p_session;
223 			pgrp->pg_session->s_count++;
224 		}
225 		pgrp->pg_id = pgid;
226 		LIST_INIT(&pgrp->pg_members);
227 		LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
228 		pgrp->pg_jobc = 0;
229 	} else if (pgrp == p->p_pgrp)
230 		return (0);
231 
232 	/*
233 	 * Adjust eligibility of affected pgrps to participate in job control.
234 	 * Increment eligibility counts before decrementing, otherwise we
235 	 * could reach 0 spuriously during the first call.
236 	 */
237 	fixjobc(p, pgrp, 1);
238 	fixjobc(p, p->p_pgrp, 0);
239 
240 	LIST_REMOVE(p, p_pglist);
241 	if (p->p_pgrp->pg_members.lh_first == 0)
242 		pgdelete(p->p_pgrp);
243 	p->p_pgrp = pgrp;
244 	LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist);
245 	return (0);
246 }
247 
248 /*
249  * remove process from process group
250  */
251 leavepgrp(p)
252 	register struct proc *p;
253 {
254 
255 	LIST_REMOVE(p, p_pglist);
256 	if (p->p_pgrp->pg_members.lh_first == 0)
257 		pgdelete(p->p_pgrp);
258 	p->p_pgrp = 0;
259 	return (0);
260 }
261 
262 /*
263  * delete a process group
264  */
265 pgdelete(pgrp)
266 	register struct pgrp *pgrp;
267 {
268 
269 	if (pgrp->pg_session->s_ttyp != NULL &&
270 	    pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
271 		pgrp->pg_session->s_ttyp->t_pgrp = NULL;
272 	LIST_REMOVE(pgrp, pg_hash);
273 	if (--pgrp->pg_session->s_count == 0)
274 		FREE(pgrp->pg_session, M_SESSION);
275 	FREE(pgrp, M_PGRP);
276 }
277 
278 static void orphanpg();
279 
280 /*
281  * Adjust pgrp jobc counters when specified process changes process group.
282  * We count the number of processes in each process group that "qualify"
283  * the group for terminal job control (those with a parent in a different
284  * process group of the same session).  If that count reaches zero, the
285  * process group becomes orphaned.  Check both the specified process'
286  * process group and that of its children.
287  * entering == 0 => p is leaving specified group.
288  * entering == 1 => p is entering specified group.
289  */
290 void
291 fixjobc(p, pgrp, entering)
292 	register struct proc *p;
293 	register struct pgrp *pgrp;
294 	int entering;
295 {
296 	register struct pgrp *hispgrp;
297 	register struct session *mysession = pgrp->pg_session;
298 
299 	/*
300 	 * Check p's parent to see whether p qualifies its own process
301 	 * group; if so, adjust count for p's process group.
302 	 */
303 	if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
304 	    hispgrp->pg_session == mysession)
305 		if (entering)
306 			pgrp->pg_jobc++;
307 		else if (--pgrp->pg_jobc == 0)
308 			orphanpg(pgrp);
309 
310 	/*
311 	 * Check this process' children to see whether they qualify
312 	 * their process groups; if so, adjust counts for children's
313 	 * process groups.
314 	 */
315 	for (p = p->p_children.lh_first; p != 0; p = p->p_sibling.le_next)
316 		if ((hispgrp = p->p_pgrp) != pgrp &&
317 		    hispgrp->pg_session == mysession &&
318 		    p->p_stat != SZOMB)
319 			if (entering)
320 				hispgrp->pg_jobc++;
321 			else if (--hispgrp->pg_jobc == 0)
322 				orphanpg(hispgrp);
323 }
324 
325 /*
326  * A process group has become orphaned;
327  * if there are any stopped processes in the group,
328  * hang-up all process in that group.
329  */
330 static void
331 orphanpg(pg)
332 	struct pgrp *pg;
333 {
334 	register struct proc *p;
335 
336 	for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) {
337 		if (p->p_stat == SSTOP) {
338 			for (p = pg->pg_members.lh_first; p != 0;
339 			    p = p->p_pglist.le_next) {
340 				psignal(p, SIGHUP);
341 				psignal(p, SIGCONT);
342 			}
343 			return;
344 		}
345 	}
346 }
347 
348 #ifdef DEBUG
349 pgrpdump()
350 {
351 	register struct pgrp *pgrp;
352 	register struct proc *p;
353 	register i;
354 
355 	for (i = 0; i <= pgrphash; i++) {
356 		if (pgrp = pgrphashtbl[i].lh_first) {
357 			printf("\tindx %d\n", i);
358 			for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) {
359 				printf("\tpgrp %x, pgid %d, sess %x, sesscnt %d, mem %x\n",
360 				    pgrp, pgrp->pg_id, pgrp->pg_session,
361 				    pgrp->pg_session->s_count,
362 				    pgrp->pg_members.lh_first);
363 				for (p = pgrp->pg_members.lh_first; p != 0;
364 				    p = p->p_pglist.le_next) {
365 					printf("\t\tpid %d addr %x pgrp %x\n",
366 					    p->p_pid, p, p->p_pgrp);
367 				}
368 			}
369 		}
370 	}
371 }
372 #endif /* DEBUG */
373