kern_proc.c revision 1.9 1 /* $NetBSD: kern_proc.c,v 1.9 1994/06/29 06:32:36 cgd 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 struct uidinfo *ui_next;
59 struct uidinfo **ui_prev;
60 uid_t ui_uid;
61 long ui_proccnt;
62 } **uihashtbl;
63 u_long uihash; /* size of hash table - 1 */
64 #define UIHASH(uid) ((uid) & uihash)
65
66 /*
67 * Allocate a hash table.
68 */
69 usrinfoinit()
70 {
71
72 uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash);
73 }
74
75 /*
76 * Change the count associated with number of processes
77 * a given user is using.
78 */
79 int
80 chgproccnt(uid, diff)
81 uid_t uid;
82 int diff;
83 {
84 register struct uidinfo **uipp, *uip, *uiq;
85
86 uipp = &uihashtbl[UIHASH(uid)];
87 for (uip = *uipp; uip; uip = uip->ui_next)
88 if (uip->ui_uid == uid)
89 break;
90 if (uip) {
91 uip->ui_proccnt += diff;
92 if (uip->ui_proccnt > 0)
93 return (uip->ui_proccnt);
94 if (uip->ui_proccnt < 0)
95 panic("chgproccnt: procs < 0");
96 if (uiq = uip->ui_next)
97 uiq->ui_prev = uip->ui_prev;
98 *uip->ui_prev = uiq;
99 FREE(uip, M_PROC);
100 return (0);
101 }
102 if (diff <= 0) {
103 if (diff == 0)
104 return(0);
105 panic("chgproccnt: lost user");
106 }
107 MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK);
108 if (uiq = *uipp)
109 uiq->ui_prev = &uip->ui_next;
110 uip->ui_next = uiq;
111 uip->ui_prev = uipp;
112 *uipp = uip;
113 uip->ui_uid = uid;
114 uip->ui_proccnt = diff;
115 return (diff);
116 }
117
118 /*
119 * Is p an inferior of the current process?
120 */
121 inferior(p)
122 register struct proc *p;
123 {
124
125 for (; p != curproc; p = p->p_pptr)
126 if (p->p_pid == 0)
127 return (0);
128 return (1);
129 }
130
131 /*
132 * Locate a process by number
133 */
134 struct proc *
135 pfind(pid)
136 register pid_t pid;
137 {
138 register struct proc *p;
139
140 for (p = pidhash[PIDHASH(pid)]; p != NULL; p = p->p_hash)
141 if (p->p_pid == pid)
142 return (p);
143 return (NULL);
144 }
145
146 /*
147 * Locate a process group by number
148 */
149 struct pgrp *
150 pgfind(pgid)
151 register pid_t pgid;
152 {
153 register struct pgrp *pgrp;
154
155 for (pgrp = pgrphash[PIDHASH(pgid)];
156 pgrp != NULL; pgrp = pgrp->pg_hforw)
157 if (pgrp->pg_id == pgid)
158 return (pgrp);
159 return (NULL);
160 }
161
162 /*
163 * Move p to a new or existing process group (and session)
164 */
165 enterpgrp(p, pgid, mksess)
166 register struct proc *p;
167 pid_t pgid;
168 int mksess;
169 {
170 register struct pgrp *pgrp = pgfind(pgid);
171 register struct proc **pp;
172 int n;
173
174 #ifdef DIAGNOSTIC
175 if (pgrp != NULL && mksess) /* firewalls */
176 panic("enterpgrp: setsid into non-empty pgrp");
177 if (SESS_LEADER(p))
178 panic("enterpgrp: session leader attempted setpgrp");
179 #endif
180 if (pgrp == NULL) {
181 pid_t savepid = p->p_pid;
182 struct proc *np;
183 /*
184 * new process group
185 */
186 #ifdef DIAGNOSTIC
187 if (p->p_pid != pgid)
188 panic("enterpgrp: new pgrp and pid != pgid");
189 #endif
190 MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
191 M_WAITOK);
192 if ((np = pfind(savepid)) == NULL || np != p)
193 return (ESRCH);
194 if (mksess) {
195 register struct session *sess;
196
197 /*
198 * new session
199 */
200 MALLOC(sess, struct session *, sizeof(struct session),
201 M_SESSION, M_WAITOK);
202 sess->s_leader = p;
203 sess->s_count = 1;
204 sess->s_ttyvp = NULL;
205 sess->s_ttyp = NULL;
206 bcopy(p->p_session->s_login, sess->s_login,
207 sizeof(sess->s_login));
208 p->p_flag &= ~P_CONTROLT;
209 pgrp->pg_session = sess;
210 #ifdef DIAGNOSTIC
211 if (p != curproc)
212 panic("enterpgrp: mksession and p != curproc");
213 #endif
214 } else {
215 pgrp->pg_session = p->p_session;
216 pgrp->pg_session->s_count++;
217 }
218 pgrp->pg_id = pgid;
219 pgrp->pg_hforw = pgrphash[n = PIDHASH(pgid)];
220 pgrphash[n] = pgrp;
221 pgrp->pg_jobc = 0;
222 pgrp->pg_mem = NULL;
223 } else if (pgrp == p->p_pgrp)
224 return (0);
225
226 /*
227 * Adjust eligibility of affected pgrps to participate in job control.
228 * Increment eligibility counts before decrementing, otherwise we
229 * could reach 0 spuriously during the first call.
230 */
231 fixjobc(p, pgrp, 1);
232 fixjobc(p, p->p_pgrp, 0);
233
234 /*
235 * unlink p from old process group
236 */
237 for (pp = &p->p_pgrp->pg_mem; *pp; pp = &(*pp)->p_pgrpnxt) {
238 if (*pp == p) {
239 *pp = p->p_pgrpnxt;
240 break;
241 }
242 }
243 #ifdef DIAGNOSTIC
244 if (pp == NULL)
245 panic("enterpgrp: can't find p on old pgrp");
246 #endif
247 /*
248 * delete old if empty
249 */
250 if (p->p_pgrp->pg_mem == 0)
251 pgdelete(p->p_pgrp);
252 /*
253 * link into new one
254 */
255 p->p_pgrp = pgrp;
256 p->p_pgrpnxt = pgrp->pg_mem;
257 pgrp->pg_mem = p;
258 return (0);
259 }
260
261 /*
262 * remove process from process group
263 */
264 leavepgrp(p)
265 register struct proc *p;
266 {
267 register struct proc **pp = &p->p_pgrp->pg_mem;
268
269 for (; *pp; pp = &(*pp)->p_pgrpnxt) {
270 if (*pp == p) {
271 *pp = p->p_pgrpnxt;
272 break;
273 }
274 }
275 #ifdef DIAGNOSTIC
276 if (pp == NULL)
277 panic("leavepgrp: can't find p in pgrp");
278 #endif
279 if (!p->p_pgrp->pg_mem)
280 pgdelete(p->p_pgrp);
281 p->p_pgrp = 0;
282 return (0);
283 }
284
285 /*
286 * delete a process group
287 */
288 pgdelete(pgrp)
289 register struct pgrp *pgrp;
290 {
291 register struct pgrp **pgp = &pgrphash[PIDHASH(pgrp->pg_id)];
292
293 if (pgrp->pg_session->s_ttyp != NULL &&
294 pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
295 pgrp->pg_session->s_ttyp->t_pgrp = NULL;
296 for (; *pgp; pgp = &(*pgp)->pg_hforw) {
297 if (*pgp == pgrp) {
298 *pgp = pgrp->pg_hforw;
299 break;
300 }
301 }
302 #ifdef DIAGNOSTIC
303 if (pgp == NULL)
304 panic("pgdelete: can't find pgrp on hash chain");
305 #endif
306 if (--pgrp->pg_session->s_count == 0)
307 FREE(pgrp->pg_session, M_SESSION);
308 FREE(pgrp, M_PGRP);
309 }
310
311 static void orphanpg();
312
313 /*
314 * Adjust pgrp jobc counters when specified process changes process group.
315 * We count the number of processes in each process group that "qualify"
316 * the group for terminal job control (those with a parent in a different
317 * process group of the same session). If that count reaches zero, the
318 * process group becomes orphaned. Check both the specified process'
319 * process group and that of its children.
320 * entering == 0 => p is leaving specified group.
321 * entering == 1 => p is entering specified group.
322 */
323 void
324 fixjobc(p, pgrp, entering)
325 register struct proc *p;
326 register struct pgrp *pgrp;
327 int entering;
328 {
329 register struct pgrp *hispgrp;
330 register struct session *mysession = pgrp->pg_session;
331
332 /*
333 * Check p's parent to see whether p qualifies its own process
334 * group; if so, adjust count for p's process group.
335 */
336 if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
337 hispgrp->pg_session == mysession)
338 if (entering)
339 pgrp->pg_jobc++;
340 else if (--pgrp->pg_jobc == 0)
341 orphanpg(pgrp);
342
343 /*
344 * Check this process' children to see whether they qualify
345 * their process groups; if so, adjust counts for children's
346 * process groups.
347 */
348 for (p = p->p_cptr; p; p = p->p_osptr)
349 if ((hispgrp = p->p_pgrp) != pgrp &&
350 hispgrp->pg_session == mysession &&
351 p->p_stat != SZOMB)
352 if (entering)
353 hispgrp->pg_jobc++;
354 else if (--hispgrp->pg_jobc == 0)
355 orphanpg(hispgrp);
356 }
357
358 /*
359 * A process group has become orphaned;
360 * if there are any stopped processes in the group,
361 * hang-up all process in that group.
362 */
363 static void
364 orphanpg(pg)
365 struct pgrp *pg;
366 {
367 register struct proc *p;
368
369 for (p = pg->pg_mem; p; p = p->p_pgrpnxt) {
370 if (p->p_stat == SSTOP) {
371 for (p = pg->pg_mem; p; p = p->p_pgrpnxt) {
372 psignal(p, SIGHUP);
373 psignal(p, SIGCONT);
374 }
375 return;
376 }
377 }
378 }
379
380 #ifdef debug
381 /* DEBUG */
382 pgrpdump()
383 {
384 register struct pgrp *pgrp;
385 register struct proc *p;
386 register i;
387
388 for (i=0; i<PIDHSZ; i++) {
389 if (pgrphash[i]) {
390 printf("\tindx %d\n", i);
391 for (pgrp=pgrphash[i]; pgrp; pgrp=pgrp->pg_hforw) {
392 printf("\tpgrp %x, pgid %d, sess %x, sesscnt %d, mem %x\n",
393 pgrp, pgrp->pg_id, pgrp->pg_session,
394 pgrp->pg_session->s_count, pgrp->pg_mem);
395 for (p=pgrp->pg_mem; p; p=p->p_pgrpnxt) {
396 printf("\t\tpid %d addr %x pgrp %x\n",
397 p->p_pid, p, p->p_pgrp);
398 }
399 }
400
401 }
402 }
403 }
404 #endif /* debug */
405