]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_proc.c
2eba097efe12f1ffb9bb2ebb54a2dcf19df9e05d
   2  * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_OSREFERENCE_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  
  10  * License may not be used to create, or enable the creation or  
  11  * redistribution of, unlawful or unlicensed copies of an Apple operating  
  12  * system, or to circumvent, violate, or enable the circumvention or  
  13  * violation of, any terms of an Apple operating system software license  
  16  * Please obtain a copy of the License at  
  17  * http://www.opensource.apple.com/apsl/ and read it before using this  
  20  * The Original Code and all software distributed under the License are  
  21  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER  
  22  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,  
  23  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,  
  24  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.  
  25  * Please see the License for the specific language governing rights and  
  26  * limitations under the License. 
  28  * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ 
  30 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ 
  32  * Copyright (c) 1982, 1986, 1989, 1991, 1993 
  33  *      The Regents of the University of California.  All rights reserved. 
  35  * Redistribution and use in source and binary forms, with or without 
  36  * modification, are permitted provided that the following conditions 
  38  * 1. Redistributions of source code must retain the above copyright 
  39  *    notice, this list of conditions and the following disclaimer. 
  40  * 2. Redistributions in binary form must reproduce the above copyright 
  41  *    notice, this list of conditions and the following disclaimer in the 
  42  *    documentation and/or other materials provided with the distribution. 
  43  * 3. All advertising materials mentioning features or use of this software 
  44  *    must display the following acknowledgement: 
  45  *      This product includes software developed by the University of 
  46  *      California, Berkeley and its contributors. 
  47  * 4. Neither the name of the University nor the names of its contributors 
  48  *    may be used to endorse or promote products derived from this software 
  49  *    without specific prior written permission. 
  51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 
  52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 
  55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
  56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
  57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
  59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
  60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  63  *      @(#)kern_proc.c 8.4 (Berkeley) 1/4/94 
  66  *  04-Aug-97  Umesh Vaishampayan (umeshv@apple.com) 
  67  *      Added current_proc_EXTERNAL() function for the use of kernel 
  70  *  05-Jun-95 Mac Gillon (mgillon) at NeXT 
  71  *      New version based on 3.3NS and 4.4 
  75 #include <sys/param.h> 
  76 #include <sys/systm.h> 
  77 #include <sys/kernel.h> 
  78 #include <sys/proc_internal.h> 
  81 #include <sys/file_internal.h> 
  82 #include <ufs/ufs/quota.h> 
  84 #include <sys/malloc.h> 
  86 #include <sys/ioctl.h> 
  88 #include <sys/signalvar.h> 
  89 #include <sys/syslog.h> 
  90 #include <sys/kernel_types.h> 
  93  * Structure associated with user cacheing. 
  96         LIST_ENTRY(uidinfo
) ui_hash
; 
 100 #define UIHASH(uid)     (&uihashtbl[(uid) & uihash]) 
 101 LIST_HEAD(uihashhead
, uidinfo
) *uihashtbl
; 
 102 u_long uihash
;          /* size of hash table - 1 */ 
 105  * Other process lists 
 107 struct pidhashhead 
*pidhashtbl
; 
 109 struct pgrphashhead 
*pgrphashtbl
; 
 111 struct proclist allproc
; 
 112 struct proclist zombproc
; 
 113 extern struct tty cons
; 
 115 /* Name to give to core files */ 
 116 __private_extern__ 
char corefilename
[MAXPATHLEN
+1] = {"/cores/core.%P"}; 
 118 static void orphanpg(struct pgrp 
*pg
); 
 121  * Initialize global process hashing structures. 
 128         LIST_INIT(&zombproc
); 
 129         pidhashtbl 
= hashinit(maxproc 
/ 4, M_PROC
, &pidhash
); 
 130         pgrphashtbl 
= hashinit(maxproc 
/ 4, M_PROC
, &pgrphash
); 
 131         uihashtbl 
= hashinit(maxproc 
/ 16, M_PROC
, &uihash
); 
 135  * Change the count associated with number of processes 
 136  * a given user is using. 
 139 chgproccnt(uid
, diff
) 
 143         register struct uidinfo 
*uip
; 
 144         register struct uihashhead 
*uipp
; 
 147         for (uip 
= uipp
->lh_first
; uip 
!= 0; uip 
= uip
->ui_hash
.le_next
) 
 148                 if (uip
->ui_uid 
== uid
) 
 151                 uip
->ui_proccnt 
+= diff
; 
 152                 if (uip
->ui_proccnt 
> 0) 
 153                         return (uip
->ui_proccnt
); 
 154                 if (uip
->ui_proccnt 
< 0) 
 155                         panic("chgproccnt: procs < 0"); 
 156                 LIST_REMOVE(uip
, ui_hash
); 
 157                 FREE_ZONE(uip
, sizeof *uip
, M_PROC
); 
 163                 panic("chgproccnt: lost user"); 
 165         MALLOC_ZONE(uip
, struct uidinfo 
*, sizeof(*uip
), M_PROC
, M_WAITOK
); 
 167                 panic("chgproccnt: M_PROC zone depleted"); 
 168         LIST_INSERT_HEAD(uipp
, uip
, ui_hash
); 
 170         uip
->ui_proccnt 
= diff
; 
 175  * Is p an inferior of the current process? 
 179         register struct proc 
*p
; 
 182         for (; p 
!= current_proc(); p 
= p
->p_pptr
) 
 188  * Is p an inferior of t ? 
 191 isinferior(struct proc 
*p
, struct proc 
*t
) 
 194         /* if p==t they are not inferior */ 
 197         for (; p 
!= t
; p 
= p
->p_pptr
) 
 204 proc_isinferior(int pid1
, int pid2
) 
 209         if (((p 
= pfind(pid1
)) != (struct proc 
*)0 ) && ((t 
= pfind(pid2
)) != (struct proc 
*)0)) 
 210                 return (isinferior(p
, t
)); 
 221 proc_rele(__unused proc_t p
) 
 229         return(current_proc()); 
 233 proc_findref(int pid
) 
 235         boolean_t funnel_state
; 
 238         funnel_state 
= thread_funnel_set(kernel_flock
,TRUE
); 
 241         if (p 
!= proc_refinternal(p
, 1)) 
 244         thread_funnel_set(kernel_flock
, funnel_state
); 
 249 proc_dropref(proc_t p
) 
 252         proc_dropinternal(p
, 0); 
 257 proc_refinternal(proc_t p
, int funneled
) 
 261         boolean_t funnel_state 
= TRUE
;  /* need to init just to avoid warnings and build failure */ 
 264                 funnel_state 
= thread_funnel_set(kernel_flock
,TRUE
); 
 266         if ((p 
!= PROC_NULL
) &&(p
->p_stat 
!= SZOMB
) && ((p
->p_lflag 
& (P_LREFDRAINWAIT 
| P_LREFDRAIN 
| P_LREFDEAD
)) == 0)) 
 272                 thread_funnel_set(kernel_flock
,funnel_state
); 
 277 proc_dropinternal(proc_t p
, int funneled
) 
 279         boolean_t funnel_state 
= TRUE
; /* need to init just to avoid warnings and build failure */ 
 282                 funnel_state 
= thread_funnel_set(kernel_flock
,TRUE
); 
 284         if (p
->p_internalref 
> 0) { 
 286                 if ((p
->p_internalref 
== 0) && ((p
->p_lflag 
& P_LREFDRAINWAIT
) == P_LREFDRAINWAIT
)) { 
 287                         p
->p_lflag 
&= ~P_LREFDRAINWAIT
; 
 288                         wakeup(&p
->p_internalref
); 
 291                 printf("proc_dropreg -ve ref\n"); 
 294                 thread_funnel_set(kernel_flock
,funnel_state
); 
 307         if (p
->p_pptr 
!= (struct proc 
*)0)  
 308                 return(p
->p_pptr
->p_pid
); 
 315         struct proc 
*p 
= current_proc(); 
 323         struct proc 
*p 
= current_proc(); 
 325                 return(p
->p_pptr
->p_pid
); 
 331 proc_name(int pid
, char * buf
, int size
) 
 335         if ((p 
= pfind(pid
))!= (struct proc 
*)0) { 
 336                 strncpy(buf
, &p
->p_comm
[0], size
); 
 342 proc_selfname(char * buf
, int  size
) 
 346         if ((p 
= current_proc())!= (struct proc 
*)0) { 
 347                 strncpy(buf
, &p
->p_comm
[0], size
); 
 353 proc_signal(int pid
, int signum
) 
 357         if ((p 
= pfind(pid
))!= (struct proc 
*)0) { 
 363 proc_issignal(int pid
, sigset_t mask
) 
 367         if ((p 
= pfind(pid
))!= (struct proc 
*)0) { 
 368                 return(proc_pendingsignals(p
, mask
)); 
 374 proc_noremotehang(proc_t p
) 
 379                 retval 
= p
->p_flag 
& P_NOREMOTEHANG
; 
 380         return(retval
? 1: 0); 
 385 proc_exiting(proc_t p
) 
 390                 retval 
= p
->p_flag 
& P_WEXIT
; 
 391         return(retval
? 1: 0); 
 396 proc_forcequota(proc_t p
) 
 401                 retval 
= p
->p_flag 
& P_FORCEQUOTA
; 
 402         return(retval
? 1: 0); 
 412                 retval 
= p
->p_flag 
& P_TBE
; 
 413         return(retval
? 1: 0); 
 420         return(suser(p
->p_ucred
, NULL
)); 
 432 proc_is64bit(proc_t p
) 
 434         return(IS_64BIT_PROCESS(p
)); 
 437 /* LP64todo - figure out how to identify 64-bit processes if NULL procp */ 
 439 IS_64BIT_PROCESS(proc_t p
) 
 441         if (p 
&& (p
->p_flag 
& P_LP64
)) 
 449  * Locate a process by number 
 455         register struct proc 
*p
; 
 460         for (p 
= PIDHASH(pid
)->lh_first
; p 
!= 0; p 
= p
->p_hash
.le_next
) 
 467  * Locate a zombie by PID 
 469 __private_extern__ 
struct proc 
* 
 473         register struct proc 
*p
; 
 475         for (p 
= zombproc
.lh_first
; p 
!= 0; p 
= p
->p_list
.le_next
) 
 482  * Locate a process group by number 
 488         register struct pgrp 
*pgrp
; 
 490         for (pgrp 
= PGRPHASH(pgid
)->lh_first
; pgrp 
!= 0; pgrp 
= pgrp
->pg_hash
.le_next
) 
 491                 if (pgrp
->pg_id 
== pgid
) 
 498  * Move p to a new or existing process group (and session) 
 501 enterpgrp(p
, pgid
, mksess
) 
 502         register struct proc 
*p
; 
 506         register struct pgrp 
*pgrp 
= pgfind(pgid
); 
 509         if (pgrp 
!= NULL 
&& mksess
)     /* firewalls */ 
 510                 panic("enterpgrp: setsid into non-empty pgrp"); 
 512                 panic("enterpgrp: session leader attempted setpgrp"); 
 515                 pid_t savepid 
= p
->p_pid
; 
 521                 if (p
->p_pid 
!= pgid
) 
 522                         panic("enterpgrp: new pgrp and pid != pgid"); 
 524                 MALLOC_ZONE(pgrp
, struct pgrp 
*, sizeof(struct pgrp
), M_PGRP
, 
 527                         panic("enterpgrp: M_PGRP zone depleted"); 
 528                 if ((np 
= pfind(savepid
)) == NULL 
|| np 
!= p
) { 
 529                         FREE_ZONE(pgrp
, sizeof(struct pgrp
), M_PGRP
); 
 533                         register struct session 
*sess
; 
 538                         MALLOC_ZONE(sess
, struct session 
*, 
 539                                 sizeof(struct session
), M_SESSION
, M_WAITOK
); 
 541                                 panic("enterpgrp: M_SESSION zone depleted"); 
 543                         sess
->s_sid 
= p
->p_pid
; 
 545                         sess
->s_ttyvp 
= NULL
; 
 547                         bcopy(p
->p_session
->s_login
, sess
->s_login
, 
 548                             sizeof(sess
->s_login
)); 
 549                         p
->p_flag 
&= ~P_CONTROLT
; 
 550                         pgrp
->pg_session 
= sess
; 
 552                         if (p 
!= current_proc()) 
 553                                 panic("enterpgrp: mksession and p != curproc"); 
 556                         pgrp
->pg_session 
= p
->p_session
; 
 557                         pgrp
->pg_session
->s_count
++; 
 560                 LIST_INIT(&pgrp
->pg_members
); 
 561                 LIST_INSERT_HEAD(PGRPHASH(pgid
), pgrp
, pg_hash
); 
 563         } else if (pgrp 
== p
->p_pgrp
) 
 567          * Adjust eligibility of affected pgrps to participate in job control. 
 568          * Increment eligibility counts before decrementing, otherwise we 
 569          * could reach 0 spuriously during the first call. 
 572         fixjobc(p
, p
->p_pgrp
, 0); 
 574         LIST_REMOVE(p
, p_pglist
); 
 575         if (p
->p_pgrp
->pg_members
.lh_first 
== 0) 
 578         LIST_INSERT_HEAD(&pgrp
->pg_members
, p
, p_pglist
); 
 583  * remove process from process group 
 587         register struct proc 
*p
; 
 590         LIST_REMOVE(p
, p_pglist
); 
 591         if (p
->p_pgrp
->pg_members
.lh_first 
== 0) 
 598  * delete a process group 
 602         register struct pgrp 
*pgrp
; 
 606         ttyp 
= pgrp
->pg_session
->s_ttyp
; 
 607         if (ttyp 
!= NULL 
&& pgrp
->pg_session
->s_ttyp
->t_pgrp 
== pgrp
) { 
 608                 pgrp
->pg_session
->s_ttyp
->t_pgrp 
= NULL
; 
 610         LIST_REMOVE(pgrp
, pg_hash
); 
 611         if (--pgrp
->pg_session
->s_count 
== 0) { 
 612                 if (ttyp 
!= NULL 
&& (ttyp
->t_session 
== pgrp
->pg_session
)) 
 614                 FREE_ZONE(pgrp
->pg_session
, sizeof(struct session
), M_SESSION
); 
 616         FREE_ZONE(pgrp
, sizeof *pgrp
, M_PGRP
); 
 621         struct session 
*sess
; 
 623         if (--sess
->s_count 
== 0) 
 624                 FREE_ZONE(sess
, sizeof (struct session
), M_SESSION
); 
 628  * Adjust pgrp jobc counters when specified process changes process group. 
 629  * We count the number of processes in each process group that "qualify" 
 630  * the group for terminal job control (those with a parent in a different 
 631  * process group of the same session).  If that count reaches zero, the 
 632  * process group becomes orphaned.  Check both the specified process' 
 633  * process group and that of its children. 
 634  * entering == 0 => p is leaving specified group. 
 635  * entering == 1 => p is entering specified group. 
 638 fixjobc(struct proc 
*p
, struct pgrp 
*pgrp
, int entering
) 
 640         register struct pgrp 
*hispgrp
; 
 641         register struct session 
*mysession 
= pgrp
->pg_session
; 
 644          * Check p's parent to see whether p qualifies its own process 
 645          * group; if so, adjust count for p's process group. 
 647         if ((hispgrp 
= p
->p_pptr
->p_pgrp
) != pgrp 
&& 
 648             hispgrp
->pg_session 
== mysession
) { 
 651                 else if (--pgrp
->pg_jobc 
== 0) 
 656          * Check this process' children to see whether they qualify 
 657          * their process groups; if so, adjust counts for children's 
 660         for (p 
= p
->p_children
.lh_first
; p 
!= 0; p 
= p
->p_sibling
.le_next
) 
 661                 if ((hispgrp 
= p
->p_pgrp
) != pgrp 
&& 
 662                     hispgrp
->pg_session 
== mysession 
&& 
 663                     p
->p_stat 
!= SZOMB
) { 
 666                         else if (--hispgrp
->pg_jobc 
== 0) 
 672  * A process group has become orphaned; 
 673  * if there are any stopped processes in the group, 
 674  * hang-up all process in that group. 
 677 orphanpg(struct pgrp 
*pg
) 
 679         register struct proc 
*p
; 
 681         for (p 
= pg
->pg_members
.lh_first
; p 
!= 0; p 
= p
->p_pglist
.le_next
) { 
 682                 if (p
->p_stat 
== SSTOP
) { 
 683                         for (p 
= pg
->pg_members
.lh_first
; p 
!= 0; 
 684                             p 
= p
->p_pglist
.le_next
) { 
 695 void pgrpdump(void);    /* forward declare here (called from debugger) */ 
 704         for (i 
= 0; i 
<= pgrphash
; i
++) { 
 705                 if ((pgrp 
= pgrphashtbl
[i
].lh_first
) != NULL
) { 
 706                         printf("\tindx %d\n", i
); 
 707                         for (; pgrp 
!= 0; pgrp 
= pgrp
->pg_hash
.le_next
) { 
 708                                 printf("\tpgrp 0x%08x, pgid %d, sess %p, sesscnt %d, mem %p\n", 
 709                                     pgrp
, pgrp
->pg_id
, pgrp
->pg_session
, 
 710                                     pgrp
->pg_session
->s_count
, 
 711                                     pgrp
->pg_members
.lh_first
); 
 712                                 for (p 
= pgrp
->pg_members
.lh_first
; p 
!= 0; 
 713                                     p 
= p
->p_pglist
.le_next
) { 
 714                                         printf("\t\tpid %d addr 0x%08x pgrp 0x%08x\n",  
 715                                             p
->p_pid
, p
, p
->p_pgrp
); 
 723 /* XXX should be __private_extern__ */ 
 725 proc_is_classic(struct proc 
*p
) 
 727     return (p
->p_flag 
& P_CLASSIC
) ? 1 : 0; 
 730 /* XXX Why does this function exist?  Need to kill it off... */ 
 732 current_proc_EXTERNAL(void) 
 734         return (current_proc()); 
 738  * proc_core_name(name, uid, pid) 
 739  * Expand the name described in corefilename, using name, uid, and pid. 
 740  * corefilename is a printf-like string, with three format specifiers: 
 741  *      %N      name of process ("name") 
 742  *      %P      process id (pid) 
 744  * For example, "%N.core" is the default; they can be disabled completely 
 745  * by using "/dev/null", or all core files can be stored in "/cores/%U/%N-%P". 
 746  * This is controlled by the sysctl variable kern.corefile (see above). 
 748 __private_extern__ 
char * 
 749 proc_core_name(const char *name
, uid_t uid
, pid_t pid
) 
 751         const char *format
, *appendstr
; 
 753         char id_buf
[11];                /* Buffer for pid/uid -- max 4B */ 
 756         format 
= corefilename
; 
 757         MALLOC(temp
, char *, MAXPATHLEN
, M_TEMP
, M_NOWAIT 
| M_ZERO
); 
 760         for (i 
= 0, n 
= 0; n 
< MAXPATHLEN 
&& format
[i
]; i
++) { 
 762                 case '%':       /* Format character */ 
 768                         case 'N':       /* process name */ 
 771                         case 'P':       /* process id */ 
 772                                 sprintf(id_buf
, "%u", pid
); 
 775                         case 'U':       /* user id */ 
 776                                 sprintf(id_buf
, "%u", uid
); 
 782                                     "Unknown format character %c in `%s'\n", 
 785                         l 
= strlen(appendstr
); 
 786                         if ((n 
+ l
) >= MAXPATHLEN
) 
 788                         bcopy(appendstr
, temp 
+ n
, l
); 
 792                         temp
[n
++] = format
[i
]; 
 795         if (format
[i
] != '\0') 
 799         log(LOG_ERR
, "pid %ld (%s), uid (%lu): corename is too long\n", 
 800             (long)pid
, name
, (u_long
)uid
);