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