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