]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_proc.c
55072bf67d8f89e8e1d021c12062e17eab38ce1b
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
30 * Copyright (c) 1982, 1986, 1989, 1991, 1993
31 * The Regents of the University of California. All rights reserved.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * @(#)kern_proc.c 8.4 (Berkeley) 1/4/94
64 * 04-Aug-97 Umesh Vaishampayan (umeshv@apple.com)
65 * Added current_proc_EXTERNAL() function for the use of kernel
68 * 05-Jun-95 Mac Gillon (mgillon) at NeXT
69 * New version based on 3.3NS and 4.4
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/kernel.h>
76 #include <sys/proc_internal.h>
79 #include <sys/file_internal.h>
80 #include <ufs/ufs/quota.h>
82 #include <sys/malloc.h>
84 #include <sys/ioctl.h>
86 #include <sys/signalvar.h>
87 #include <sys/syslog.h>
88 #include <sys/kernel_types.h>
91 * Structure associated with user cacheing.
94 LIST_ENTRY(uidinfo
) ui_hash
;
98 #define UIHASH(uid) (&uihashtbl[(uid) & uihash])
99 LIST_HEAD(uihashhead
, uidinfo
) *uihashtbl
;
100 u_long uihash
; /* size of hash table - 1 */
103 * Other process lists
105 struct pidhashhead
*pidhashtbl
;
107 struct pgrphashhead
*pgrphashtbl
;
109 struct proclist allproc
;
110 struct proclist zombproc
;
111 extern struct tty cons
;
113 /* Name to give to core files */
114 __private_extern__
char corefilename
[MAXPATHLEN
+1] = {"/cores/core.%P"};
116 static void orphanpg(struct pgrp
*pg
);
119 * Initialize global process hashing structures.
126 LIST_INIT(&zombproc
);
127 pidhashtbl
= hashinit(maxproc
/ 4, M_PROC
, &pidhash
);
128 pgrphashtbl
= hashinit(maxproc
/ 4, M_PROC
, &pgrphash
);
129 uihashtbl
= hashinit(maxproc
/ 16, M_PROC
, &uihash
);
133 * Change the count associated with number of processes
134 * a given user is using.
137 chgproccnt(uid
, diff
)
141 register struct uidinfo
*uip
;
142 register struct uihashhead
*uipp
;
145 for (uip
= uipp
->lh_first
; uip
!= 0; uip
= uip
->ui_hash
.le_next
)
146 if (uip
->ui_uid
== uid
)
149 uip
->ui_proccnt
+= diff
;
150 if (uip
->ui_proccnt
> 0)
151 return (uip
->ui_proccnt
);
152 if (uip
->ui_proccnt
< 0)
153 panic("chgproccnt: procs < 0");
154 LIST_REMOVE(uip
, ui_hash
);
155 FREE_ZONE(uip
, sizeof *uip
, M_PROC
);
161 panic("chgproccnt: lost user");
163 MALLOC_ZONE(uip
, struct uidinfo
*, sizeof(*uip
), M_PROC
, M_WAITOK
);
165 panic("chgproccnt: M_PROC zone depleted");
166 LIST_INSERT_HEAD(uipp
, uip
, ui_hash
);
168 uip
->ui_proccnt
= diff
;
173 * Is p an inferior of the current process?
177 register struct proc
*p
;
180 for (; p
!= current_proc(); p
= p
->p_pptr
)
186 * Is p an inferior of t ?
189 isinferior(struct proc
*p
, struct proc
*t
)
192 /* if p==t they are not inferior */
195 for (; p
!= t
; p
= p
->p_pptr
)
202 proc_isinferior(int pid1
, int pid2
)
207 if (((p
= pfind(pid1
)) != (struct proc
*)0 ) && ((t
= pfind(pid2
)) != (struct proc
*)0))
208 return (isinferior(p
, t
));
219 proc_rele(__unused proc_t p
)
227 return(current_proc());
231 proc_findref(int pid
)
233 boolean_t funnel_state
;
236 funnel_state
= thread_funnel_set(kernel_flock
,TRUE
);
239 if (p
!= proc_refinternal(p
, 1))
242 thread_funnel_set(kernel_flock
, funnel_state
);
247 proc_dropref(proc_t p
)
250 proc_dropinternal(p
, 0);
255 proc_refinternal(proc_t p
, int funneled
)
259 boolean_t funnel_state
= TRUE
; /* need to init just to avoid warnings and build failure */
262 funnel_state
= thread_funnel_set(kernel_flock
,TRUE
);
264 if ((p
!= PROC_NULL
) &&(p
->p_stat
!= SZOMB
) && ((p
->p_lflag
& (P_LREFDRAINWAIT
| P_LREFDRAIN
| P_LREFDEAD
)) == 0))
270 thread_funnel_set(kernel_flock
,funnel_state
);
275 proc_dropinternal(proc_t p
, int funneled
)
277 boolean_t funnel_state
= TRUE
; /* need to init just to avoid warnings and build failure */
280 funnel_state
= thread_funnel_set(kernel_flock
,TRUE
);
282 if (p
->p_internalref
> 0) {
284 if ((p
->p_internalref
== 0) && ((p
->p_lflag
& P_LREFDRAINWAIT
) == P_LREFDRAINWAIT
)) {
285 p
->p_lflag
&= ~P_LREFDRAINWAIT
;
286 wakeup(&p
->p_internalref
);
289 printf("proc_dropreg -ve ref\n");
292 thread_funnel_set(kernel_flock
,funnel_state
);
305 if (p
->p_pptr
!= (struct proc
*)0)
306 return(p
->p_pptr
->p_pid
);
313 struct proc
*p
= current_proc();
321 struct proc
*p
= current_proc();
323 return(p
->p_pptr
->p_pid
);
329 proc_name(int pid
, char * buf
, int size
)
333 if ((p
= pfind(pid
))!= (struct proc
*)0) {
334 strncpy(buf
, &p
->p_comm
[0], size
);
340 proc_selfname(char * buf
, int size
)
344 if ((p
= current_proc())!= (struct proc
*)0) {
345 strncpy(buf
, &p
->p_comm
[0], size
);
351 proc_signal(int pid
, int signum
)
355 if ((p
= pfind(pid
))!= (struct proc
*)0) {
361 proc_issignal(int pid
, sigset_t mask
)
365 if ((p
= pfind(pid
))!= (struct proc
*)0) {
366 return(proc_pendingsignals(p
, mask
));
372 proc_noremotehang(proc_t p
)
377 retval
= p
->p_flag
& P_NOREMOTEHANG
;
378 return(retval
? 1: 0);
383 proc_exiting(proc_t p
)
388 retval
= p
->p_flag
& P_WEXIT
;
389 return(retval
? 1: 0);
394 proc_forcequota(proc_t p
)
399 retval
= p
->p_flag
& P_FORCEQUOTA
;
400 return(retval
? 1: 0);
410 retval
= p
->p_flag
& P_TBE
;
411 return(retval
? 1: 0);
418 return(suser(p
->p_ucred
, NULL
));
430 proc_is64bit(proc_t p
)
432 return(IS_64BIT_PROCESS(p
));
435 /* LP64todo - figure out how to identify 64-bit processes if NULL procp */
437 IS_64BIT_PROCESS(proc_t p
)
439 if (p
&& (p
->p_flag
& P_LP64
))
447 * Locate a process by number
453 register struct proc
*p
;
458 for (p
= PIDHASH(pid
)->lh_first
; p
!= 0; p
= p
->p_hash
.le_next
)
465 * Locate a zombie by PID
467 __private_extern__
struct proc
*
471 register struct proc
*p
;
473 for (p
= zombproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
)
480 * Locate a process group by number
486 register struct pgrp
*pgrp
;
488 for (pgrp
= PGRPHASH(pgid
)->lh_first
; pgrp
!= 0; pgrp
= pgrp
->pg_hash
.le_next
)
489 if (pgrp
->pg_id
== pgid
)
496 * Move p to a new or existing process group (and session)
499 enterpgrp(p
, pgid
, mksess
)
500 register struct proc
*p
;
504 register struct pgrp
*pgrp
= pgfind(pgid
);
507 if (pgrp
!= NULL
&& mksess
) /* firewalls */
508 panic("enterpgrp: setsid into non-empty pgrp");
510 panic("enterpgrp: session leader attempted setpgrp");
513 pid_t savepid
= p
->p_pid
;
519 if (p
->p_pid
!= pgid
)
520 panic("enterpgrp: new pgrp and pid != pgid");
522 MALLOC_ZONE(pgrp
, struct pgrp
*, sizeof(struct pgrp
), M_PGRP
,
525 panic("enterpgrp: M_PGRP zone depleted");
526 if ((np
= pfind(savepid
)) == NULL
|| np
!= p
) {
527 FREE_ZONE(pgrp
, sizeof(struct pgrp
), M_PGRP
);
531 register struct session
*sess
;
536 MALLOC_ZONE(sess
, struct session
*,
537 sizeof(struct session
), M_SESSION
, M_WAITOK
);
539 panic("enterpgrp: M_SESSION zone depleted");
541 sess
->s_sid
= p
->p_pid
;
543 sess
->s_ttyvp
= NULL
;
545 bcopy(p
->p_session
->s_login
, sess
->s_login
,
546 sizeof(sess
->s_login
));
547 p
->p_flag
&= ~P_CONTROLT
;
548 pgrp
->pg_session
= sess
;
550 if (p
!= current_proc())
551 panic("enterpgrp: mksession and p != curproc");
554 pgrp
->pg_session
= p
->p_session
;
555 pgrp
->pg_session
->s_count
++;
558 LIST_INIT(&pgrp
->pg_members
);
559 LIST_INSERT_HEAD(PGRPHASH(pgid
), pgrp
, pg_hash
);
561 } else if (pgrp
== p
->p_pgrp
)
565 * Adjust eligibility of affected pgrps to participate in job control.
566 * Increment eligibility counts before decrementing, otherwise we
567 * could reach 0 spuriously during the first call.
570 fixjobc(p
, p
->p_pgrp
, 0);
572 LIST_REMOVE(p
, p_pglist
);
573 if (p
->p_pgrp
->pg_members
.lh_first
== 0)
576 LIST_INSERT_HEAD(&pgrp
->pg_members
, p
, p_pglist
);
581 * remove process from process group
585 register struct proc
*p
;
588 LIST_REMOVE(p
, p_pglist
);
589 if (p
->p_pgrp
->pg_members
.lh_first
== 0)
596 * delete a process group
600 register struct pgrp
*pgrp
;
604 ttyp
= pgrp
->pg_session
->s_ttyp
;
605 if (ttyp
!= NULL
&& pgrp
->pg_session
->s_ttyp
->t_pgrp
== pgrp
) {
606 pgrp
->pg_session
->s_ttyp
->t_pgrp
= NULL
;
608 LIST_REMOVE(pgrp
, pg_hash
);
609 if (--pgrp
->pg_session
->s_count
== 0) {
610 if (ttyp
!= NULL
&& (ttyp
->t_session
== pgrp
->pg_session
))
612 FREE_ZONE(pgrp
->pg_session
, sizeof(struct session
), M_SESSION
);
614 FREE_ZONE(pgrp
, sizeof *pgrp
, M_PGRP
);
619 struct session
*sess
;
621 if (--sess
->s_count
== 0)
622 FREE_ZONE(sess
, sizeof (struct session
), M_SESSION
);
626 * Adjust pgrp jobc counters when specified process changes process group.
627 * We count the number of processes in each process group that "qualify"
628 * the group for terminal job control (those with a parent in a different
629 * process group of the same session). If that count reaches zero, the
630 * process group becomes orphaned. Check both the specified process'
631 * process group and that of its children.
632 * entering == 0 => p is leaving specified group.
633 * entering == 1 => p is entering specified group.
636 fixjobc(struct proc
*p
, struct pgrp
*pgrp
, int entering
)
638 register struct pgrp
*hispgrp
;
639 register struct session
*mysession
= pgrp
->pg_session
;
642 * Check p's parent to see whether p qualifies its own process
643 * group; if so, adjust count for p's process group.
645 if ((hispgrp
= p
->p_pptr
->p_pgrp
) != pgrp
&&
646 hispgrp
->pg_session
== mysession
) {
649 else if (--pgrp
->pg_jobc
== 0)
654 * Check this process' children to see whether they qualify
655 * their process groups; if so, adjust counts for children's
658 for (p
= p
->p_children
.lh_first
; p
!= 0; p
= p
->p_sibling
.le_next
)
659 if ((hispgrp
= p
->p_pgrp
) != pgrp
&&
660 hispgrp
->pg_session
== mysession
&&
661 p
->p_stat
!= SZOMB
) {
664 else if (--hispgrp
->pg_jobc
== 0)
670 * A process group has become orphaned;
671 * if there are any stopped processes in the group,
672 * hang-up all process in that group.
675 orphanpg(struct pgrp
*pg
)
677 register struct proc
*p
;
679 for (p
= pg
->pg_members
.lh_first
; p
!= 0; p
= p
->p_pglist
.le_next
) {
680 if (p
->p_stat
== SSTOP
) {
681 for (p
= pg
->pg_members
.lh_first
; p
!= 0;
682 p
= p
->p_pglist
.le_next
) {
693 void pgrpdump(void); /* forward declare here (called from debugger) */
702 for (i
= 0; i
<= pgrphash
; i
++) {
703 if ((pgrp
= pgrphashtbl
[i
].lh_first
) != NULL
) {
704 printf("\tindx %d\n", i
);
705 for (; pgrp
!= 0; pgrp
= pgrp
->pg_hash
.le_next
) {
706 printf("\tpgrp 0x%08x, pgid %d, sess %p, sesscnt %d, mem %p\n",
707 pgrp
, pgrp
->pg_id
, pgrp
->pg_session
,
708 pgrp
->pg_session
->s_count
,
709 pgrp
->pg_members
.lh_first
);
710 for (p
= pgrp
->pg_members
.lh_first
; p
!= 0;
711 p
= p
->p_pglist
.le_next
) {
712 printf("\t\tpid %d addr 0x%08x pgrp 0x%08x\n",
713 p
->p_pid
, p
, p
->p_pgrp
);
721 /* XXX should be __private_extern__ */
723 proc_is_classic(struct proc
*p
)
725 return (p
->p_flag
& P_CLASSIC
) ? 1 : 0;
728 /* XXX Why does this function exist? Need to kill it off... */
730 current_proc_EXTERNAL(void)
732 return (current_proc());
736 * proc_core_name(name, uid, pid)
737 * Expand the name described in corefilename, using name, uid, and pid.
738 * corefilename is a printf-like string, with three format specifiers:
739 * %N name of process ("name")
740 * %P process id (pid)
742 * For example, "%N.core" is the default; they can be disabled completely
743 * by using "/dev/null", or all core files can be stored in "/cores/%U/%N-%P".
744 * This is controlled by the sysctl variable kern.corefile (see above).
746 __private_extern__
char *
747 proc_core_name(const char *name
, uid_t uid
, pid_t pid
)
749 const char *format
, *appendstr
;
751 char id_buf
[11]; /* Buffer for pid/uid -- max 4B */
754 format
= corefilename
;
755 MALLOC(temp
, char *, MAXPATHLEN
, M_TEMP
, M_NOWAIT
| M_ZERO
);
758 for (i
= 0, n
= 0; n
< MAXPATHLEN
&& format
[i
]; i
++) {
760 case '%': /* Format character */
766 case 'N': /* process name */
769 case 'P': /* process id */
770 sprintf(id_buf
, "%u", pid
);
773 case 'U': /* user id */
774 sprintf(id_buf
, "%u", uid
);
780 "Unknown format character %c in `%s'\n",
783 l
= strlen(appendstr
);
784 if ((n
+ l
) >= MAXPATHLEN
)
786 bcopy(appendstr
, temp
+ n
, l
);
790 temp
[n
++] = format
[i
];
793 if (format
[i
] != '\0')
797 log(LOG_ERR
, "pid %ld (%s), uid (%lu): corename is too long\n",
798 (long)pid
, name
, (u_long
)uid
);