]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_proc.c
xnu-517.11.1.tar.gz
[apple/xnu.git] / bsd / kern / kern_proc.c
1 /*
2 * Copyright (c) 2000-2002 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 #include <sys/syslog.h>
83
84 /*
85 * Structure associated with user cacheing.
86 */
87 struct uidinfo {
88 LIST_ENTRY(uidinfo) ui_hash;
89 uid_t ui_uid;
90 long ui_proccnt;
91 };
92 #define UIHASH(uid) (&uihashtbl[(uid) & uihash])
93 LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
94 u_long uihash; /* size of hash table - 1 */
95
96 /*
97 * Other process lists
98 */
99 struct pidhashhead *pidhashtbl;
100 u_long pidhash;
101 struct pgrphashhead *pgrphashtbl;
102 u_long pgrphash;
103 struct proclist allproc;
104 struct proclist zombproc;
105
106 /* Name to give to core files */
107 __private_extern__ char corefilename[MAXPATHLEN+1] = {"/cores/core.%P"};
108
109 static void orphanpg(struct pgrp *pg);
110
111 /*
112 * Initialize global process hashing structures.
113 */
114 void
115 procinit()
116 {
117
118 LIST_INIT(&allproc);
119 LIST_INIT(&zombproc);
120 pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash);
121 pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash);
122 uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash);
123 }
124
125 /*
126 * Change the count associated with number of processes
127 * a given user is using.
128 */
129 int
130 chgproccnt(uid, diff)
131 uid_t uid;
132 int diff;
133 {
134 register struct uidinfo *uip;
135 register struct uihashhead *uipp;
136
137 uipp = UIHASH(uid);
138 for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next)
139 if (uip->ui_uid == uid)
140 break;
141 if (uip) {
142 uip->ui_proccnt += diff;
143 if (uip->ui_proccnt > 0)
144 return (uip->ui_proccnt);
145 if (uip->ui_proccnt < 0)
146 panic("chgproccnt: procs < 0");
147 LIST_REMOVE(uip, ui_hash);
148 FREE_ZONE(uip, sizeof *uip, M_PROC);
149 return (0);
150 }
151 if (diff <= 0) {
152 if (diff == 0)
153 return(0);
154 panic("chgproccnt: lost user");
155 }
156 MALLOC_ZONE(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK);
157 LIST_INSERT_HEAD(uipp, uip, ui_hash);
158 uip->ui_uid = uid;
159 uip->ui_proccnt = diff;
160 return (diff);
161 }
162
163 /*
164 * Is p an inferior of the current process?
165 */
166 int
167 inferior(p)
168 register struct proc *p;
169 {
170
171 for (; p != current_proc(); p = p->p_pptr)
172 if (p->p_pid == 0)
173 return (0);
174 return (1);
175 }
176 /*
177 * Is p an inferior of t ?
178 */
179 int
180 isinferior(struct proc *p, register struct proc *t)
181 {
182
183 /* if p==t they are not inferior */
184 if (p == t)
185 return(0);
186 for (; p != t; p = p->p_pptr)
187 if (p->p_pid == 0)
188 return (0);
189 return (1);
190 }
191
192 /*
193 * Locate a process by number
194 */
195 struct proc *
196 pfind(pid)
197 register pid_t pid;
198 {
199 register struct proc *p;
200
201 if (!pid)
202 return (kernproc);
203
204 for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next)
205 if (p->p_pid == pid)
206 return (p);
207 return (NULL);
208 }
209
210 /*
211 * Locate a zombie by PID
212 */
213 __private_extern__ struct proc *
214 pzfind(pid)
215 register pid_t pid;
216 {
217 register struct proc *p;
218
219 for (p = zombproc.lh_first; p != 0; p = p->p_list.le_next)
220 if (p->p_pid == pid)
221 return (p);
222 return (NULL);
223 }
224
225 /*
226 * Locate a process group by number
227 */
228 struct pgrp *
229 pgfind(pgid)
230 register pid_t pgid;
231 {
232 register struct pgrp *pgrp;
233
234 for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0; pgrp = pgrp->pg_hash.le_next)
235 if (pgrp->pg_id == pgid)
236 return (pgrp);
237 return (NULL);
238 }
239
240
241 /*
242 * Move p to a new or existing process group (and session)
243 */
244 int
245 enterpgrp(p, pgid, mksess)
246 register struct proc *p;
247 pid_t pgid;
248 int mksess;
249 {
250 register struct pgrp *pgrp = pgfind(pgid);
251
252 #if DIAGNOSTIC
253 if (pgrp != NULL && mksess) /* firewalls */
254 panic("enterpgrp: setsid into non-empty pgrp");
255 if (SESS_LEADER(p))
256 panic("enterpgrp: session leader attempted setpgrp");
257 #endif
258 if (pgrp == NULL) {
259 pid_t savepid = p->p_pid;
260 struct proc *np;
261 /*
262 * new process group
263 */
264 #if DIAGNOSTIC
265 if (p->p_pid != pgid)
266 panic("enterpgrp: new pgrp and pid != pgid");
267 #endif
268 MALLOC_ZONE(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
269 M_WAITOK);
270 if ((np = pfind(savepid)) == NULL || np != p) {
271 FREE_ZONE(pgrp, sizeof(struct pgrp), M_PGRP);
272 return (ESRCH);
273 }
274 if (mksess) {
275 register struct session *sess;
276
277 /*
278 * new session
279 */
280 MALLOC_ZONE(sess, struct session *,
281 sizeof(struct session), M_SESSION, M_WAITOK);
282 sess->s_leader = p;
283 sess->s_sid = p->p_pid;
284 sess->s_count = 1;
285 sess->s_ttyvp = NULL;
286 sess->s_ttyp = NULL;
287 bcopy(p->p_session->s_login, sess->s_login,
288 sizeof(sess->s_login));
289 p->p_flag &= ~P_CONTROLT;
290 pgrp->pg_session = sess;
291 #if DIAGNOSTIC
292 if (p != current_proc())
293 panic("enterpgrp: mksession and p != curproc");
294 #endif
295 } else {
296 pgrp->pg_session = p->p_session;
297 pgrp->pg_session->s_count++;
298 }
299 pgrp->pg_id = pgid;
300 LIST_INIT(&pgrp->pg_members);
301 LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
302 pgrp->pg_jobc = 0;
303 } else if (pgrp == p->p_pgrp)
304 return (0);
305
306 /*
307 * Adjust eligibility of affected pgrps to participate in job control.
308 * Increment eligibility counts before decrementing, otherwise we
309 * could reach 0 spuriously during the first call.
310 */
311 fixjobc(p, pgrp, 1);
312 fixjobc(p, p->p_pgrp, 0);
313
314 LIST_REMOVE(p, p_pglist);
315 if (p->p_pgrp->pg_members.lh_first == 0)
316 pgdelete(p->p_pgrp);
317 p->p_pgrp = pgrp;
318 LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist);
319 return (0);
320 }
321
322 /*
323 * remove process from process group
324 */
325 int
326 leavepgrp(p)
327 register struct proc *p;
328 {
329
330 LIST_REMOVE(p, p_pglist);
331 if (p->p_pgrp->pg_members.lh_first == 0)
332 pgdelete(p->p_pgrp);
333 p->p_pgrp = 0;
334 return (0);
335 }
336
337 /*
338 * delete a process group
339 */
340 void
341 pgdelete(pgrp)
342 register struct pgrp *pgrp;
343 {
344
345 if (pgrp->pg_session->s_ttyp != NULL &&
346 pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
347 pgrp->pg_session->s_ttyp->t_pgrp = NULL;
348 LIST_REMOVE(pgrp, pg_hash);
349 if (--pgrp->pg_session->s_count == 0)
350 FREE_ZONE(pgrp->pg_session, sizeof(struct session), M_SESSION);
351 FREE_ZONE(pgrp, sizeof *pgrp, M_PGRP);
352 }
353
354 void
355 sessrele(sess)
356 struct session *sess;
357 {
358 if (--sess->s_count == 0)
359 FREE_ZONE(sess, sizeof (struct session), M_SESSION);
360 }
361
362 /*
363 * Adjust pgrp jobc counters when specified process changes process group.
364 * We count the number of processes in each process group that "qualify"
365 * the group for terminal job control (those with a parent in a different
366 * process group of the same session). If that count reaches zero, the
367 * process group becomes orphaned. Check both the specified process'
368 * process group and that of its children.
369 * entering == 0 => p is leaving specified group.
370 * entering == 1 => p is entering specified group.
371 */
372 void
373 fixjobc(struct proc *p, struct pgrp *pgrp, int entering)
374 {
375 register struct pgrp *hispgrp;
376 register struct session *mysession = pgrp->pg_session;
377
378 /*
379 * Check p's parent to see whether p qualifies its own process
380 * group; if so, adjust count for p's process group.
381 */
382 if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
383 hispgrp->pg_session == mysession) {
384 if (entering)
385 pgrp->pg_jobc++;
386 else if (--pgrp->pg_jobc == 0)
387 orphanpg(pgrp);
388 }
389
390 /*
391 * Check this process' children to see whether they qualify
392 * their process groups; if so, adjust counts for children's
393 * process groups.
394 */
395 for (p = p->p_children.lh_first; p != 0; p = p->p_sibling.le_next)
396 if ((hispgrp = p->p_pgrp) != pgrp &&
397 hispgrp->pg_session == mysession &&
398 p->p_stat != SZOMB) {
399 if (entering)
400 hispgrp->pg_jobc++;
401 else if (--hispgrp->pg_jobc == 0)
402 orphanpg(hispgrp);
403 }
404 }
405
406 /*
407 * A process group has become orphaned;
408 * if there are any stopped processes in the group,
409 * hang-up all process in that group.
410 */
411 static void
412 orphanpg(struct pgrp *pg)
413 {
414 register struct proc *p;
415
416 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) {
417 if (p->p_stat == SSTOP) {
418 for (p = pg->pg_members.lh_first; p != 0;
419 p = p->p_pglist.le_next) {
420 pt_setrunnable(p);
421 psignal(p, SIGHUP);
422 psignal(p, SIGCONT);
423 }
424 return;
425 }
426 }
427 }
428
429 #ifdef DEBUG
430 void
431 pgrpdump()
432 {
433 register struct pgrp *pgrp;
434 register struct proc *p;
435 register i;
436
437 for (i = 0; i <= pgrphash; i++) {
438 if (pgrp = pgrphashtbl[i].lh_first) {
439 printf("\tindx %d\n", i);
440 for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) {
441 printf("\tpgrp 0x%08x, pgid %d, sess %p, sesscnt %d, mem %p\n",
442 pgrp, pgrp->pg_id, pgrp->pg_session,
443 pgrp->pg_session->s_count,
444 pgrp->pg_members.lh_first);
445 for (p = pgrp->pg_members.lh_first; p != 0;
446 p = p->p_pglist.le_next) {
447 printf("\t\tpid %d addr 0x%08x pgrp 0x%08x\n",
448 p->p_pid, p, p->p_pgrp);
449 }
450 }
451 }
452 }
453 }
454 #endif /* DEBUG */
455
456 /* XXX should be __private_extern__ */
457 int
458 proc_is_classic(struct proc *p)
459 {
460 return (p->p_flag & P_CLASSIC) ? 1 : 0;
461 }
462
463 /* XXX Why does this function exist? Need to kill it off... */
464 struct proc *
465 current_proc_EXTERNAL(void)
466 {
467 return (current_proc());
468 }
469
470 /*
471 * proc_core_name(name, uid, pid)
472 * Expand the name described in corefilename, using name, uid, and pid.
473 * corefilename is a printf-like string, with three format specifiers:
474 * %N name of process ("name")
475 * %P process id (pid)
476 * %U user id (uid)
477 * For example, "%N.core" is the default; they can be disabled completely
478 * by using "/dev/null", or all core files can be stored in "/cores/%U/%N-%P".
479 * This is controlled by the sysctl variable kern.corefile (see above).
480 */
481 __private_extern__ char *
482 proc_core_name(const char *name, uid_t uid, pid_t pid)
483 {
484 const char *format, *appendstr;
485 char *temp;
486 char id_buf[11]; /* Buffer for pid/uid -- max 4B */
487 size_t i, l, n;
488
489 format = corefilename;
490 MALLOC(temp, char *, MAXPATHLEN, M_TEMP, M_NOWAIT | M_ZERO);
491 if (temp == NULL)
492 return (NULL);
493 for (i = 0, n = 0; n < MAXPATHLEN && format[i]; i++) {
494 switch (format[i]) {
495 case '%': /* Format character */
496 i++;
497 switch (format[i]) {
498 case '%':
499 appendstr = "%";
500 break;
501 case 'N': /* process name */
502 appendstr = name;
503 break;
504 case 'P': /* process id */
505 sprintf(id_buf, "%u", pid);
506 appendstr = id_buf;
507 break;
508 case 'U': /* user id */
509 sprintf(id_buf, "%u", uid);
510 appendstr = id_buf;
511 break;
512 default:
513 appendstr = "";
514 log(LOG_ERR,
515 "Unknown format character %c in `%s'\n",
516 format[i], format);
517 }
518 l = strlen(appendstr);
519 if ((n + l) >= MAXPATHLEN)
520 goto toolong;
521 bcopy(appendstr, temp + n, l);
522 n += l;
523 break;
524 default:
525 temp[n++] = format[i];
526 }
527 }
528 if (format[i] != '\0')
529 goto toolong;
530 return (temp);
531 toolong:
532 log(LOG_ERR, "pid %ld (%s), uid (%lu): corename is too long\n",
533 (long)pid, name, (u_long)uid);
534 FREE(temp, M_TEMP);
535 return (NULL);
536 }