]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_proc.c
xnu-201.19.tar.gz
[apple/xnu.git] / bsd / kern / kern_proc.c
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 */
86 struct uidinfo {
87 LIST_ENTRY(uidinfo) ui_hash;
88 uid_t ui_uid;
89 long ui_proccnt;
90 };
91 #define UIHASH(uid) (&uihashtbl[(uid) & uihash])
92 LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
93 u_long uihash; /* size of hash table - 1 */
94
95 /*
96 * Other process lists
97 */
98 struct pidhashhead *pidhashtbl;
99 u_long pidhash;
100 struct pgrphashhead *pgrphashtbl;
101 u_long pgrphash;
102 struct proclist allproc;
103 struct proclist zombproc;
104
105 /*
106 * Initialize global process hashing structures.
107 */
108 void
109 procinit()
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 */
123 int
124 chgproccnt(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 */
160 int
161 inferior(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 */
174 struct proc *
175 pfind(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 */
192 struct pgrp *
193 pgfind(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 */
208 int
209 enterpgrp(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 */
286 int
287 leavepgrp(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 */
301 void
302 pgdelete(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
315 void
316 sessrele(sess)
317 struct session *sess;
318 {
319 if (--sess->s_count == 0)
320 FREE_ZONE(sess, sizeof (struct session), M_SESSION);
321 }
322
323 static 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 */
335 void
336 fixjobc(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 */
375 static void
376 orphanpg(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
395 void
396 pgrpdump()
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
421 struct proc * current_proc_EXTERNAL()
422 {
423 return (current_proc());
424 }