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