]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_proc.c
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
24 * Copyright (c) 1982, 1986, 1989, 1991, 1993
25 * The Regents of the University of California. All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
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.
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
55 * @(#)kern_proc.c 8.4 (Berkeley) 1/4/94
58 * 04-Aug-97 Umesh Vaishampayan (umeshv@apple.com)
59 * Added current_proc_EXTERNAL() function for the use of kernel
62 * 05-Jun-95 Mac Gillon (mgillon) at NeXT
63 * New version based on 3.3NS and 4.4
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/kernel.h>
70 #include <sys/proc_internal.h>
73 #include <sys/file_internal.h>
74 #include <ufs/ufs/quota.h>
76 #include <sys/malloc.h>
78 #include <sys/ioctl.h>
80 #include <sys/signalvar.h>
81 #include <sys/syslog.h>
82 #include <sys/kernel_types.h>
85 * Structure associated with user cacheing.
88 LIST_ENTRY(uidinfo
) ui_hash
;
92 #define UIHASH(uid) (&uihashtbl[(uid) & uihash])
93 LIST_HEAD(uihashhead
, uidinfo
) *uihashtbl
;
94 u_long uihash
; /* size of hash table - 1 */
99 struct pidhashhead
*pidhashtbl
;
101 struct pgrphashhead
*pgrphashtbl
;
103 struct proclist allproc
;
104 struct proclist zombproc
;
105 extern struct tty cons
;
107 /* Name to give to core files */
108 __private_extern__
char corefilename
[MAXPATHLEN
+1] = {"/cores/core.%P"};
110 static void orphanpg(struct pgrp
*pg
);
113 * Initialize global process hashing structures.
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
);
127 * Change the count associated with number of processes
128 * a given user is using.
131 chgproccnt(uid
, diff
)
135 register struct uidinfo
*uip
;
136 register struct uihashhead
*uipp
;
139 for (uip
= uipp
->lh_first
; uip
!= 0; uip
= uip
->ui_hash
.le_next
)
140 if (uip
->ui_uid
== uid
)
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
);
155 panic("chgproccnt: lost user");
157 MALLOC_ZONE(uip
, struct uidinfo
*, sizeof(*uip
), M_PROC
, M_WAITOK
);
159 panic("chgproccnt: M_PROC zone depleted");
160 LIST_INSERT_HEAD(uipp
, uip
, ui_hash
);
162 uip
->ui_proccnt
= diff
;
167 * Is p an inferior of the current process?
171 register struct proc
*p
;
174 for (; p
!= current_proc(); p
= p
->p_pptr
)
180 * Is p an inferior of t ?
183 isinferior(struct proc
*p
, struct proc
*t
)
186 /* if p==t they are not inferior */
189 for (; p
!= t
; p
= p
->p_pptr
)
196 proc_isinferior(int pid1
, int pid2
)
201 if (((p
= pfind(pid1
)) != (struct proc
*)0 ) && ((t
= pfind(pid2
)) != (struct proc
*)0))
202 return (isinferior(p
, t
));
213 proc_rele(__unused proc_t p
)
221 return(current_proc());
234 if (p
->p_pptr
!= (struct proc
*)0)
235 return(p
->p_pptr
->p_pid
);
242 struct proc
*p
= current_proc();
250 struct proc
*p
= current_proc();
252 return(p
->p_pptr
->p_pid
);
258 proc_name(int pid
, char * buf
, int size
)
262 if ((p
= pfind(pid
))!= (struct proc
*)0) {
263 strncpy(buf
, &p
->p_comm
[0], size
);
269 proc_selfname(char * buf
, int size
)
273 if ((p
= current_proc())!= (struct proc
*)0) {
274 strncpy(buf
, &p
->p_comm
[0], size
);
280 proc_signal(int pid
, int signum
)
284 if ((p
= pfind(pid
))!= (struct proc
*)0) {
290 proc_issignal(int pid
, sigset_t mask
)
294 if ((p
= pfind(pid
))!= (struct proc
*)0) {
295 return(proc_pendingsignals(p
, mask
));
301 proc_noremotehang(proc_t p
)
306 retval
= p
->p_flag
& P_NOREMOTEHANG
;
307 return(retval
? 1: 0);
312 proc_exiting(proc_t p
)
317 retval
= p
->p_flag
& P_WEXIT
;
318 return(retval
? 1: 0);
323 proc_forcequota(proc_t p
)
328 retval
= p
->p_flag
& P_FORCEQUOTA
;
329 return(retval
? 1: 0);
339 retval
= p
->p_flag
& P_TBE
;
340 return(retval
? 1: 0);
347 return(suser(p
->p_ucred
, NULL
));
359 proc_is64bit(proc_t p
)
361 return(IS_64BIT_PROCESS(p
));
364 /* LP64todo - figure out how to identify 64-bit processes if NULL procp */
366 IS_64BIT_PROCESS(proc_t p
)
368 if (p
&& (p
->p_flag
& P_LP64
))
376 * Locate a process by number
382 register struct proc
*p
;
387 for (p
= PIDHASH(pid
)->lh_first
; p
!= 0; p
= p
->p_hash
.le_next
)
394 * Locate a zombie by PID
396 __private_extern__
struct proc
*
400 register struct proc
*p
;
402 for (p
= zombproc
.lh_first
; p
!= 0; p
= p
->p_list
.le_next
)
409 * Locate a process group by number
415 register struct pgrp
*pgrp
;
417 for (pgrp
= PGRPHASH(pgid
)->lh_first
; pgrp
!= 0; pgrp
= pgrp
->pg_hash
.le_next
)
418 if (pgrp
->pg_id
== pgid
)
425 * Move p to a new or existing process group (and session)
428 enterpgrp(p
, pgid
, mksess
)
429 register struct proc
*p
;
433 register struct pgrp
*pgrp
= pgfind(pgid
);
436 if (pgrp
!= NULL
&& mksess
) /* firewalls */
437 panic("enterpgrp: setsid into non-empty pgrp");
439 panic("enterpgrp: session leader attempted setpgrp");
442 pid_t savepid
= p
->p_pid
;
448 if (p
->p_pid
!= pgid
)
449 panic("enterpgrp: new pgrp and pid != pgid");
451 MALLOC_ZONE(pgrp
, struct pgrp
*, sizeof(struct pgrp
), M_PGRP
,
454 panic("enterpgrp: M_PGRP zone depleted");
455 if ((np
= pfind(savepid
)) == NULL
|| np
!= p
) {
456 FREE_ZONE(pgrp
, sizeof(struct pgrp
), M_PGRP
);
460 register struct session
*sess
;
465 MALLOC_ZONE(sess
, struct session
*,
466 sizeof(struct session
), M_SESSION
, M_WAITOK
);
468 panic("enterpgrp: M_SESSION zone depleted");
470 sess
->s_sid
= p
->p_pid
;
472 sess
->s_ttyvp
= 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
;
479 if (p
!= current_proc())
480 panic("enterpgrp: mksession and p != curproc");
483 pgrp
->pg_session
= p
->p_session
;
484 pgrp
->pg_session
->s_count
++;
487 LIST_INIT(&pgrp
->pg_members
);
488 LIST_INSERT_HEAD(PGRPHASH(pgid
), pgrp
, pg_hash
);
490 } else if (pgrp
== p
->p_pgrp
)
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.
499 fixjobc(p
, p
->p_pgrp
, 0);
501 LIST_REMOVE(p
, p_pglist
);
502 if (p
->p_pgrp
->pg_members
.lh_first
== 0)
505 LIST_INSERT_HEAD(&pgrp
->pg_members
, p
, p_pglist
);
510 * remove process from process group
514 register struct proc
*p
;
517 LIST_REMOVE(p
, p_pglist
);
518 if (p
->p_pgrp
->pg_members
.lh_first
== 0)
525 * delete a process group
529 register struct pgrp
*pgrp
;
532 int removettypgrp
= 0;
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
;
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
))
544 FREE_ZONE(pgrp
->pg_session
, sizeof(struct session
), M_SESSION
);
546 FREE_ZONE(pgrp
, sizeof *pgrp
, M_PGRP
);
551 struct session
*sess
;
553 if (--sess
->s_count
== 0)
554 FREE_ZONE(sess
, sizeof (struct session
), M_SESSION
);
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.
568 fixjobc(struct proc
*p
, struct pgrp
*pgrp
, int entering
)
570 register struct pgrp
*hispgrp
;
571 register struct session
*mysession
= pgrp
->pg_session
;
574 * Check p's parent to see whether p qualifies its own process
575 * group; if so, adjust count for p's process group.
577 if ((hispgrp
= p
->p_pptr
->p_pgrp
) != pgrp
&&
578 hispgrp
->pg_session
== mysession
) {
581 else if (--pgrp
->pg_jobc
== 0)
586 * Check this process' children to see whether they qualify
587 * their process groups; if so, adjust counts for children's
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
) {
596 else if (--hispgrp
->pg_jobc
== 0)
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.
607 orphanpg(struct pgrp
*pg
)
609 register struct proc
*p
;
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
) {
625 void pgrpdump(void); /* forward declare here (called from debugger) */
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
);
653 /* XXX should be __private_extern__ */
655 proc_is_classic(struct proc
*p
)
657 return (p
->p_flag
& P_CLASSIC
) ? 1 : 0;
660 /* XXX Why does this function exist? Need to kill it off... */
662 current_proc_EXTERNAL(void)
664 return (current_proc());
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)
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).
678 __private_extern__
char *
679 proc_core_name(const char *name
, uid_t uid
, pid_t pid
)
681 const char *format
, *appendstr
;
683 char id_buf
[11]; /* Buffer for pid/uid -- max 4B */
686 format
= corefilename
;
687 MALLOC(temp
, char *, MAXPATHLEN
, M_TEMP
, M_NOWAIT
| M_ZERO
);
690 for (i
= 0, n
= 0; n
< MAXPATHLEN
&& format
[i
]; i
++) {
692 case '%': /* Format character */
698 case 'N': /* process name */
701 case 'P': /* process id */
702 sprintf(id_buf
, "%u", pid
);
705 case 'U': /* user id */
706 sprintf(id_buf
, "%u", uid
);
712 "Unknown format character %c in `%s'\n",
715 l
= strlen(appendstr
);
716 if ((n
+ l
) >= MAXPATHLEN
)
718 bcopy(appendstr
, temp
+ n
, l
);
722 temp
[n
++] = format
[i
];
725 if (format
[i
] != '\0')
729 log(LOG_ERR
, "pid %ld (%s), uid (%lu): corename is too long\n",
730 (long)pid
, name
, (u_long
)uid
);