]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_proc.c
xnu-792.2.4.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_internal.h>
71 #include <sys/acct.h>
72 #include <sys/wait.h>
73 #include <sys/file_internal.h>
74 #include <ufs/ufs/quota.h>
75 #include <sys/uio.h>
76 #include <sys/malloc.h>
77 #include <sys/mbuf.h>
78 #include <sys/ioctl.h>
79 #include <sys/tty.h>
80 #include <sys/signalvar.h>
81 #include <sys/syslog.h>
82 #include <sys/kernel_types.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 extern struct tty cons;
106
107 /* Name to give to core files */
108 __private_extern__ char corefilename[MAXPATHLEN+1] = {"/cores/core.%P"};
109
110 static void orphanpg(struct pgrp *pg);
111
112 /*
113 * Initialize global process hashing structures.
114 */
115 void
116 procinit()
117 {
118
119 LIST_INIT(&allproc);
120 LIST_INIT(&zombproc);
121 pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash);
122 pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash);
123 uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash);
124 }
125
126 /*
127 * Change the count associated with number of processes
128 * a given user is using.
129 */
130 int
131 chgproccnt(uid, diff)
132 uid_t uid;
133 int diff;
134 {
135 register struct uidinfo *uip;
136 register struct uihashhead *uipp;
137
138 uipp = UIHASH(uid);
139 for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next)
140 if (uip->ui_uid == uid)
141 break;
142 if (uip) {
143 uip->ui_proccnt += diff;
144 if (uip->ui_proccnt > 0)
145 return (uip->ui_proccnt);
146 if (uip->ui_proccnt < 0)
147 panic("chgproccnt: procs < 0");
148 LIST_REMOVE(uip, ui_hash);
149 FREE_ZONE(uip, sizeof *uip, M_PROC);
150 return (0);
151 }
152 if (diff <= 0) {
153 if (diff == 0)
154 return(0);
155 panic("chgproccnt: lost user");
156 }
157 MALLOC_ZONE(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK);
158 if (uip == NULL)
159 panic("chgproccnt: M_PROC zone depleted");
160 LIST_INSERT_HEAD(uipp, uip, ui_hash);
161 uip->ui_uid = uid;
162 uip->ui_proccnt = diff;
163 return (diff);
164 }
165
166 /*
167 * Is p an inferior of the current process?
168 */
169 int
170 inferior(p)
171 register struct proc *p;
172 {
173
174 for (; p != current_proc(); p = p->p_pptr)
175 if (p->p_pid == 0)
176 return (0);
177 return (1);
178 }
179 /*
180 * Is p an inferior of t ?
181 */
182 int
183 isinferior(struct proc *p, struct proc *t)
184 {
185
186 /* if p==t they are not inferior */
187 if (p == t)
188 return(0);
189 for (; p != t; p = p->p_pptr)
190 if (p->p_pid == 0)
191 return (0);
192 return (1);
193 }
194
195 int
196 proc_isinferior(int pid1, int pid2)
197 {
198 proc_t p;
199 proc_t t;
200
201 if (((p = pfind(pid1)) != (struct proc *)0 ) && ((t = pfind(pid2)) != (struct proc *)0))
202 return (isinferior(p, t));
203 return(0);
204 }
205
206 proc_t
207 proc_find(int pid)
208 {
209 return(pfind(pid));
210 }
211
212 int
213 proc_rele(__unused proc_t p)
214 {
215 return(0);
216 }
217
218 proc_t
219 proc_self()
220 {
221 return(current_proc());
222 }
223
224
225 int
226 proc_pid(proc_t p)
227 {
228 return(p->p_pid);
229 }
230
231 int
232 proc_ppid(proc_t p)
233 {
234 if (p->p_pptr != (struct proc *)0)
235 return(p->p_pptr->p_pid);
236 return(0);
237 }
238
239 int
240 proc_selfpid(void)
241 {
242 struct proc *p = current_proc();
243 return(p->p_pid);
244 }
245
246
247 int
248 proc_selfppid(void)
249 {
250 struct proc *p = current_proc();
251 if (p->p_pptr)
252 return(p->p_pptr->p_pid);
253 else
254 return(0);
255 }
256
257 void
258 proc_name(int pid, char * buf, int size)
259 {
260 struct proc *p;
261
262 if ((p = pfind(pid))!= (struct proc *)0) {
263 strncpy(buf, &p->p_comm[0], size);
264 buf[size-1] = 0;
265 }
266 }
267
268 void
269 proc_selfname(char * buf, int size)
270 {
271 struct proc *p;
272
273 if ((p = current_proc())!= (struct proc *)0) {
274 strncpy(buf, &p->p_comm[0], size);
275 buf[size-1] = 0;
276 }
277 }
278
279 void
280 proc_signal(int pid, int signum)
281 {
282 proc_t p;
283
284 if ((p = pfind(pid))!= (struct proc *)0) {
285 psignal(p, signum);
286 }
287 }
288
289 int
290 proc_issignal(int pid, sigset_t mask)
291 {
292 proc_t p;
293
294 if ((p = pfind(pid))!= (struct proc *)0) {
295 return(proc_pendingsignals(p, mask));
296 }
297 return(0);
298 }
299
300 int
301 proc_noremotehang(proc_t p)
302 {
303 int retval = 0;
304
305 if (p)
306 retval = p->p_flag & P_NOREMOTEHANG;
307 return(retval? 1: 0);
308
309 }
310
311 int
312 proc_exiting(proc_t p)
313 {
314 int retval = 0;
315
316 if (p)
317 retval = p->p_flag & P_WEXIT;
318 return(retval? 1: 0);
319 }
320
321
322 int
323 proc_forcequota(proc_t p)
324 {
325 int retval = 0;
326
327 if (p)
328 retval = p->p_flag & P_FORCEQUOTA;
329 return(retval? 1: 0);
330
331 }
332
333 int
334 proc_tbe(proc_t p)
335 {
336 int retval = 0;
337
338 if (p)
339 retval = p->p_flag & P_TBE;
340 return(retval? 1: 0);
341
342 }
343
344 int
345 proc_suser(proc_t p)
346 {
347 return(suser(p->p_ucred, NULL));
348
349 }
350
351 kauth_cred_t
352 proc_ucred(proc_t p)
353 {
354 return(p->p_ucred);
355 }
356
357
358 int
359 proc_is64bit(proc_t p)
360 {
361 return(IS_64BIT_PROCESS(p));
362 }
363
364 /* LP64todo - figure out how to identify 64-bit processes if NULL procp */
365 int
366 IS_64BIT_PROCESS(proc_t p)
367 {
368 if (p && (p->p_flag & P_LP64))
369 return(1);
370 else
371 return(0);
372 }
373
374
375 /*
376 * Locate a process by number
377 */
378 struct proc *
379 pfind(pid)
380 register pid_t pid;
381 {
382 register struct proc *p;
383
384 if (!pid)
385 return (kernproc);
386
387 for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next)
388 if (p->p_pid == pid)
389 return (p);
390 return (NULL);
391 }
392
393 /*
394 * Locate a zombie by PID
395 */
396 __private_extern__ struct proc *
397 pzfind(pid)
398 register pid_t pid;
399 {
400 register struct proc *p;
401
402 for (p = zombproc.lh_first; p != 0; p = p->p_list.le_next)
403 if (p->p_pid == pid)
404 return (p);
405 return (NULL);
406 }
407
408 /*
409 * Locate a process group by number
410 */
411 struct pgrp *
412 pgfind(pgid)
413 register pid_t pgid;
414 {
415 register struct pgrp *pgrp;
416
417 for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0; pgrp = pgrp->pg_hash.le_next)
418 if (pgrp->pg_id == pgid)
419 return (pgrp);
420 return (NULL);
421 }
422
423
424 /*
425 * Move p to a new or existing process group (and session)
426 */
427 int
428 enterpgrp(p, pgid, mksess)
429 register struct proc *p;
430 pid_t pgid;
431 int mksess;
432 {
433 register struct pgrp *pgrp = pgfind(pgid);
434
435 #if DIAGNOSTIC
436 if (pgrp != NULL && mksess) /* firewalls */
437 panic("enterpgrp: setsid into non-empty pgrp");
438 if (SESS_LEADER(p))
439 panic("enterpgrp: session leader attempted setpgrp");
440 #endif
441 if (pgrp == NULL) {
442 pid_t savepid = p->p_pid;
443 struct proc *np;
444 /*
445 * new process group
446 */
447 #if DIAGNOSTIC
448 if (p->p_pid != pgid)
449 panic("enterpgrp: new pgrp and pid != pgid");
450 #endif
451 MALLOC_ZONE(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
452 M_WAITOK);
453 if (pgrp == NULL)
454 panic("enterpgrp: M_PGRP zone depleted");
455 if ((np = pfind(savepid)) == NULL || np != p) {
456 FREE_ZONE(pgrp, sizeof(struct pgrp), M_PGRP);
457 return (ESRCH);
458 }
459 if (mksess) {
460 register struct session *sess;
461
462 /*
463 * new session
464 */
465 MALLOC_ZONE(sess, struct session *,
466 sizeof(struct session), M_SESSION, M_WAITOK);
467 if (sess == NULL)
468 panic("enterpgrp: M_SESSION zone depleted");
469 sess->s_leader = p;
470 sess->s_sid = p->p_pid;
471 sess->s_count = 1;
472 sess->s_ttyvp = NULL;
473 sess->s_ttyp = NULL;
474 bcopy(p->p_session->s_login, sess->s_login,
475 sizeof(sess->s_login));
476 p->p_flag &= ~P_CONTROLT;
477 pgrp->pg_session = sess;
478 #if DIAGNOSTIC
479 if (p != current_proc())
480 panic("enterpgrp: mksession and p != curproc");
481 #endif
482 } else {
483 pgrp->pg_session = p->p_session;
484 pgrp->pg_session->s_count++;
485 }
486 pgrp->pg_id = pgid;
487 LIST_INIT(&pgrp->pg_members);
488 LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
489 pgrp->pg_jobc = 0;
490 } else if (pgrp == p->p_pgrp)
491 return (0);
492
493 /*
494 * Adjust eligibility of affected pgrps to participate in job control.
495 * Increment eligibility counts before decrementing, otherwise we
496 * could reach 0 spuriously during the first call.
497 */
498 fixjobc(p, pgrp, 1);
499 fixjobc(p, p->p_pgrp, 0);
500
501 LIST_REMOVE(p, p_pglist);
502 if (p->p_pgrp->pg_members.lh_first == 0)
503 pgdelete(p->p_pgrp);
504 p->p_pgrp = pgrp;
505 LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist);
506 return (0);
507 }
508
509 /*
510 * remove process from process group
511 */
512 int
513 leavepgrp(p)
514 register struct proc *p;
515 {
516
517 LIST_REMOVE(p, p_pglist);
518 if (p->p_pgrp->pg_members.lh_first == 0)
519 pgdelete(p->p_pgrp);
520 p->p_pgrp = 0;
521 return (0);
522 }
523
524 /*
525 * delete a process group
526 */
527 void
528 pgdelete(pgrp)
529 register struct pgrp *pgrp;
530 {
531 struct tty * ttyp;
532 int removettypgrp = 0;
533
534 ttyp = pgrp->pg_session->s_ttyp;
535 if (pgrp->pg_session->s_ttyp != NULL &&
536 pgrp->pg_session->s_ttyp->t_pgrp == pgrp) {
537 pgrp->pg_session->s_ttyp->t_pgrp = NULL;
538 removettypgrp = 1;
539 }
540 LIST_REMOVE(pgrp, pg_hash);
541 if (--pgrp->pg_session->s_count == 0) {
542 if (removettypgrp && (ttyp == &cons) && (ttyp->t_session == pgrp->pg_session))
543 ttyp->t_session = 0;
544 FREE_ZONE(pgrp->pg_session, sizeof(struct session), M_SESSION);
545 }
546 FREE_ZONE(pgrp, sizeof *pgrp, M_PGRP);
547 }
548
549 void
550 sessrele(sess)
551 struct session *sess;
552 {
553 if (--sess->s_count == 0)
554 FREE_ZONE(sess, sizeof (struct session), M_SESSION);
555 }
556
557 /*
558 * Adjust pgrp jobc counters when specified process changes process group.
559 * We count the number of processes in each process group that "qualify"
560 * the group for terminal job control (those with a parent in a different
561 * process group of the same session). If that count reaches zero, the
562 * process group becomes orphaned. Check both the specified process'
563 * process group and that of its children.
564 * entering == 0 => p is leaving specified group.
565 * entering == 1 => p is entering specified group.
566 */
567 void
568 fixjobc(struct proc *p, struct pgrp *pgrp, int entering)
569 {
570 register struct pgrp *hispgrp;
571 register struct session *mysession = pgrp->pg_session;
572
573 /*
574 * Check p's parent to see whether p qualifies its own process
575 * group; if so, adjust count for p's process group.
576 */
577 if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
578 hispgrp->pg_session == mysession) {
579 if (entering)
580 pgrp->pg_jobc++;
581 else if (--pgrp->pg_jobc == 0)
582 orphanpg(pgrp);
583 }
584
585 /*
586 * Check this process' children to see whether they qualify
587 * their process groups; if so, adjust counts for children's
588 * process groups.
589 */
590 for (p = p->p_children.lh_first; p != 0; p = p->p_sibling.le_next)
591 if ((hispgrp = p->p_pgrp) != pgrp &&
592 hispgrp->pg_session == mysession &&
593 p->p_stat != SZOMB) {
594 if (entering)
595 hispgrp->pg_jobc++;
596 else if (--hispgrp->pg_jobc == 0)
597 orphanpg(hispgrp);
598 }
599 }
600
601 /*
602 * A process group has become orphaned;
603 * if there are any stopped processes in the group,
604 * hang-up all process in that group.
605 */
606 static void
607 orphanpg(struct pgrp *pg)
608 {
609 register struct proc *p;
610
611 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) {
612 if (p->p_stat == SSTOP) {
613 for (p = pg->pg_members.lh_first; p != 0;
614 p = p->p_pglist.le_next) {
615 pt_setrunnable(p);
616 psignal(p, SIGHUP);
617 psignal(p, SIGCONT);
618 }
619 return;
620 }
621 }
622 }
623
624 #ifdef DEBUG
625 void pgrpdump(void); /* forward declare here (called from debugger) */
626
627 void
628 pgrpdump(void)
629 {
630 struct pgrp *pgrp;
631 struct proc *p;
632 u_long i;
633
634 for (i = 0; i <= pgrphash; i++) {
635 if ((pgrp = pgrphashtbl[i].lh_first) != NULL) {
636 printf("\tindx %d\n", i);
637 for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) {
638 printf("\tpgrp 0x%08x, pgid %d, sess %p, sesscnt %d, mem %p\n",
639 pgrp, pgrp->pg_id, pgrp->pg_session,
640 pgrp->pg_session->s_count,
641 pgrp->pg_members.lh_first);
642 for (p = pgrp->pg_members.lh_first; p != 0;
643 p = p->p_pglist.le_next) {
644 printf("\t\tpid %d addr 0x%08x pgrp 0x%08x\n",
645 p->p_pid, p, p->p_pgrp);
646 }
647 }
648 }
649 }
650 }
651 #endif /* DEBUG */
652
653 /* XXX should be __private_extern__ */
654 int
655 proc_is_classic(struct proc *p)
656 {
657 return (p->p_flag & P_CLASSIC) ? 1 : 0;
658 }
659
660 /* XXX Why does this function exist? Need to kill it off... */
661 struct proc *
662 current_proc_EXTERNAL(void)
663 {
664 return (current_proc());
665 }
666
667 /*
668 * proc_core_name(name, uid, pid)
669 * Expand the name described in corefilename, using name, uid, and pid.
670 * corefilename is a printf-like string, with three format specifiers:
671 * %N name of process ("name")
672 * %P process id (pid)
673 * %U user id (uid)
674 * For example, "%N.core" is the default; they can be disabled completely
675 * by using "/dev/null", or all core files can be stored in "/cores/%U/%N-%P".
676 * This is controlled by the sysctl variable kern.corefile (see above).
677 */
678 __private_extern__ char *
679 proc_core_name(const char *name, uid_t uid, pid_t pid)
680 {
681 const char *format, *appendstr;
682 char *temp;
683 char id_buf[11]; /* Buffer for pid/uid -- max 4B */
684 size_t i, l, n;
685
686 format = corefilename;
687 MALLOC(temp, char *, MAXPATHLEN, M_TEMP, M_NOWAIT | M_ZERO);
688 if (temp == NULL)
689 return (NULL);
690 for (i = 0, n = 0; n < MAXPATHLEN && format[i]; i++) {
691 switch (format[i]) {
692 case '%': /* Format character */
693 i++;
694 switch (format[i]) {
695 case '%':
696 appendstr = "%";
697 break;
698 case 'N': /* process name */
699 appendstr = name;
700 break;
701 case 'P': /* process id */
702 sprintf(id_buf, "%u", pid);
703 appendstr = id_buf;
704 break;
705 case 'U': /* user id */
706 sprintf(id_buf, "%u", uid);
707 appendstr = id_buf;
708 break;
709 default:
710 appendstr = "";
711 log(LOG_ERR,
712 "Unknown format character %c in `%s'\n",
713 format[i], format);
714 }
715 l = strlen(appendstr);
716 if ((n + l) >= MAXPATHLEN)
717 goto toolong;
718 bcopy(appendstr, temp + n, l);
719 n += l;
720 break;
721 default:
722 temp[n++] = format[i];
723 }
724 }
725 if (format[i] != '\0')
726 goto toolong;
727 return (temp);
728 toolong:
729 log(LOG_ERR, "pid %ld (%s), uid (%lu): corename is too long\n",
730 (long)pid, name, (u_long)uid);
731 FREE(temp, M_TEMP);
732 return (NULL);
733 }