]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_proc.c
xnu-792.13.8.tar.gz
[apple/xnu.git] / bsd / kern / kern_proc.c
index 97f98cc1d370a27362e5326812ac7b4543695c4b..d36493cace448e56baa53139a0c7f7d10abd3831 100644 (file)
@@ -1,23 +1,31 @@
 /*
  * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
+ * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
- * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
+ * This file contains Original Code and/or Modifications of Original Code 
+ * as defined in and that are subject to the Apple Public Source License 
+ * Version 2.0 (the 'License'). You may not use this file except in 
+ * compliance with the License.  The rights granted to you under the 
+ * License may not be used to create, or enable the creation or 
+ * redistribution of, unlawful or unlicensed copies of an Apple operating 
+ * system, or to circumvent, violate, or enable the circumvention or 
+ * violation of, any terms of an Apple operating system software license 
+ * agreement.
+ *
+ * Please obtain a copy of the License at 
+ * http://www.opensource.apple.com/apsl/ and read it before using this 
+ * file.
+ *
+ * The Original Code and all software distributed under the License are 
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
+ * Please see the License for the specific language governing rights and 
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
  */
 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
 /*
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
-#include <sys/proc.h>
-#include <sys/buf.h>
+#include <sys/proc_internal.h>
 #include <sys/acct.h>
 #include <sys/wait.h>
-#include <sys/file.h>
+#include <sys/file_internal.h>
 #include <ufs/ufs/quota.h>
 #include <sys/uio.h>
 #include <sys/malloc.h>
@@ -79,6 +86,8 @@
 #include <sys/ioctl.h>
 #include <sys/tty.h>
 #include <sys/signalvar.h>
+#include <sys/syslog.h>
+#include <sys/kernel_types.h>
 
 /*
  * Structure associated with user cacheing.
@@ -101,6 +110,12 @@ struct pgrphashhead *pgrphashtbl;
 u_long pgrphash;
 struct proclist allproc;
 struct proclist zombproc;
+extern struct tty cons;
+
+/* Name to give to core files */
+__private_extern__ char corefilename[MAXPATHLEN+1] = {"/cores/core.%P"};
+
+static void orphanpg(struct pgrp *pg);
 
 /*
  * Initialize global process hashing structures.
@@ -148,6 +163,8 @@ chgproccnt(uid, diff)
                panic("chgproccnt: lost user");
        }
        MALLOC_ZONE(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK);
+       if (uip == NULL)
+               panic("chgproccnt: M_PROC zone depleted");
        LIST_INSERT_HEAD(uipp, uip, ui_hash);
        uip->ui_uid = uid;
        uip->ui_proccnt = diff;
@@ -171,9 +188,7 @@ inferior(p)
  * Is p an inferior of t ?
  */
 int
-isinferior(p, t)
-       register struct proc *p;
-       register struct proc *t;
+isinferior(struct proc *p, struct proc *t)
 {
 
        /* if p==t they are not inferior */
@@ -185,6 +200,251 @@ isinferior(p, t)
        return (1);
 }
 
+int
+proc_isinferior(int pid1, int pid2)
+{
+       proc_t p;
+       proc_t t;
+
+       if (((p = pfind(pid1)) != (struct proc *)0 ) && ((t = pfind(pid2)) != (struct proc *)0))
+               return (isinferior(p, t));
+       return(0);
+}
+
+proc_t
+proc_find(int pid)
+{
+       return(pfind(pid));
+}
+
+int 
+proc_rele(__unused proc_t p)
+{
+       return(0);
+}
+
+proc_t
+proc_self()
+{
+       return(current_proc());
+}
+
+proc_t
+proc_findref(int pid)
+{
+       boolean_t funnel_state;
+       proc_t p;
+
+       funnel_state = thread_funnel_set(kernel_flock,TRUE);
+       p = pfind(pid);
+       
+       if (p != proc_refinternal(p, 1))
+               p = PROC_NULL;
+               
+       thread_funnel_set(kernel_flock, funnel_state);
+       return(p);
+}
+
+void
+proc_dropref(proc_t p)
+{
+
+       proc_dropinternal(p, 0);
+}
+
+
+proc_t
+proc_refinternal(proc_t p, int funneled)
+{
+
+       proc_t p1 = p;
+       boolean_t funnel_state = TRUE;  /* need to init just to avoid warnings and build failure */
+
+       if (funneled == 0)
+               funnel_state = thread_funnel_set(kernel_flock,TRUE);
+       
+       if ((p != PROC_NULL) &&(p->p_stat != SZOMB) && ((p->p_lflag & (P_LREFDRAINWAIT | P_LREFDRAIN | P_LREFDEAD)) == 0))
+               p->p_internalref++;
+       else 
+               p1 = PROC_NULL;
+
+       if (funneled == 0)
+               thread_funnel_set(kernel_flock,funnel_state);
+       return(p1);
+}
+
+void
+proc_dropinternal(proc_t p, int funneled)
+{
+       boolean_t funnel_state = TRUE; /* need to init just to avoid warnings and build failure */
+
+       if (funneled == 0)
+               funnel_state = thread_funnel_set(kernel_flock,TRUE);
+
+       if (p->p_internalref > 0) {
+               p->p_internalref--;
+               if ((p->p_internalref == 0) && ((p->p_lflag & P_LREFDRAINWAIT) == P_LREFDRAINWAIT)) {
+                       p->p_lflag &= ~P_LREFDRAINWAIT;
+                       wakeup(&p->p_internalref);
+               }
+       } else
+               printf("proc_dropreg -ve ref\n");
+
+       if (funneled == 0)
+               thread_funnel_set(kernel_flock,funnel_state);
+}
+
+
+int
+proc_pid(proc_t p)
+{
+       return(p->p_pid);
+}
+
+int 
+proc_ppid(proc_t p)
+{
+       if (p->p_pptr != (struct proc *)0) 
+               return(p->p_pptr->p_pid);
+       return(0);
+}
+
+int 
+proc_selfpid(void)
+{
+       struct proc *p = current_proc();
+       return(p->p_pid);
+}
+
+
+int 
+proc_selfppid(void)
+{
+       struct proc *p = current_proc();
+       if (p->p_pptr)
+               return(p->p_pptr->p_pid);
+       else
+               return(0);
+}
+
+void
+proc_name(int pid, char * buf, int size)
+{
+       struct proc  *p;
+
+       if ((p = pfind(pid))!= (struct proc *)0) {
+               strncpy(buf, &p->p_comm[0], size);
+               buf[size-1] = 0;
+       }
+}
+
+void
+proc_selfname(char * buf, int  size)
+{
+       struct proc  *p;
+
+       if ((p = current_proc())!= (struct proc *)0) {
+               strncpy(buf, &p->p_comm[0], size);
+               buf[size-1] = 0;
+       }
+}
+
+void
+proc_signal(int pid, int signum)
+{
+       proc_t p;
+
+       if ((p = pfind(pid))!= (struct proc *)0) {
+                       psignal(p, signum);
+       }       
+}
+
+int
+proc_issignal(int pid, sigset_t mask)
+{
+       proc_t p;
+
+       if ((p = pfind(pid))!= (struct proc *)0) {
+               return(proc_pendingsignals(p, mask));
+       }       
+       return(0);
+}
+
+int
+proc_noremotehang(proc_t p)
+{
+       int retval = 0;
+
+       if (p)
+               retval = p->p_flag & P_NOREMOTEHANG;
+       return(retval? 1: 0);
+
+}
+
+int
+proc_exiting(proc_t p)
+{
+       int retval = 0;
+
+       if (p)
+               retval = p->p_flag & P_WEXIT;
+       return(retval? 1: 0);
+}
+
+
+int
+proc_forcequota(proc_t p)
+{
+       int retval = 0;
+
+       if (p)
+               retval = p->p_flag & P_FORCEQUOTA;
+       return(retval? 1: 0);
+
+}
+
+int
+proc_tbe(proc_t p)
+{
+       int retval = 0;
+
+       if (p)
+               retval = p->p_flag & P_TBE;
+       return(retval? 1: 0);
+
+}
+
+int
+proc_suser(proc_t p)
+{
+       return(suser(p->p_ucred, NULL));
+       
+}
+
+kauth_cred_t
+proc_ucred(proc_t p)
+{
+       return(p->p_ucred);
+}
+
+
+int
+proc_is64bit(proc_t p)
+{
+       return(IS_64BIT_PROCESS(p));
+}
+
+/* LP64todo - figure out how to identify 64-bit processes if NULL procp */
+int
+IS_64BIT_PROCESS(proc_t p)
+{
+       if (p && (p->p_flag & P_LP64))
+               return(1);
+       else
+               return(0);
+}
+
+
 /*
  * Locate a process by number
  */
@@ -203,6 +463,21 @@ pfind(pid)
        return (NULL);
 }
 
+/*
+ * Locate a zombie by PID
+ */
+__private_extern__ struct proc *
+pzfind(pid)
+       register pid_t pid;
+{
+       register struct proc *p;
+
+       for (p = zombproc.lh_first; p != 0; p = p->p_list.le_next)
+               if (p->p_pid == pid)
+                       return (p);
+       return (NULL);
+}
+
 /*
  * Locate a process group by number
  */
@@ -248,6 +523,8 @@ enterpgrp(p, pgid, mksess)
 #endif
                MALLOC_ZONE(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
                    M_WAITOK);
+               if (pgrp == NULL)
+                       panic("enterpgrp: M_PGRP zone depleted");
                if ((np = pfind(savepid)) == NULL || np != p) {
                        FREE_ZONE(pgrp, sizeof(struct pgrp), M_PGRP);
                        return (ESRCH);
@@ -260,6 +537,8 @@ enterpgrp(p, pgid, mksess)
                         */
                        MALLOC_ZONE(sess, struct session *,
                                sizeof(struct session), M_SESSION, M_WAITOK);
+                       if (sess == NULL)
+                               panic("enterpgrp: M_SESSION zone depleted");
                        sess->s_leader = p;
                        sess->s_sid = p->p_pid;
                        sess->s_count = 1;
@@ -322,13 +601,18 @@ void
 pgdelete(pgrp)
        register struct pgrp *pgrp;
 {
+       struct tty * ttyp;
 
-       if (pgrp->pg_session->s_ttyp != NULL && 
-           pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
+       ttyp = pgrp->pg_session->s_ttyp;
+       if (ttyp != NULL && pgrp->pg_session->s_ttyp->t_pgrp == pgrp) {
                pgrp->pg_session->s_ttyp->t_pgrp = NULL;
+       }
        LIST_REMOVE(pgrp, pg_hash);
-       if (--pgrp->pg_session->s_count == 0)
+       if (--pgrp->pg_session->s_count == 0) {
+               if (ttyp != NULL && (ttyp->t_session == pgrp->pg_session))
+                       ttyp->t_session = 0;
                FREE_ZONE(pgrp->pg_session, sizeof(struct session), M_SESSION);
+       }
        FREE_ZONE(pgrp, sizeof *pgrp, M_PGRP);
 }
 
@@ -340,8 +624,6 @@ sessrele(sess)
                FREE_ZONE(sess, sizeof (struct session), M_SESSION);
 }
 
-static void orphanpg();
-
 /*
  * Adjust pgrp jobc counters when specified process changes process group.
  * We count the number of processes in each process group that "qualify"
@@ -353,10 +635,7 @@ static void orphanpg();
  * entering == 1 => p is entering specified group.
  */
 void
-fixjobc(p, pgrp, entering)
-       register struct proc *p;
-       register struct pgrp *pgrp;
-       int entering;
+fixjobc(struct proc *p, struct pgrp *pgrp, int entering)
 {
        register struct pgrp *hispgrp;
        register struct session *mysession = pgrp->pg_session;
@@ -366,11 +645,12 @@ fixjobc(p, pgrp, entering)
         * group; if so, adjust count for p's process group.
         */
        if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
-           hispgrp->pg_session == mysession)
+           hispgrp->pg_session == mysession) {
                if (entering)
                        pgrp->pg_jobc++;
                else if (--pgrp->pg_jobc == 0)
                        orphanpg(pgrp);
+       }
 
        /*
         * Check this process' children to see whether they qualify
@@ -380,11 +660,12 @@ fixjobc(p, pgrp, entering)
        for (p = p->p_children.lh_first; p != 0; p = p->p_sibling.le_next)
                if ((hispgrp = p->p_pgrp) != pgrp &&
                    hispgrp->pg_session == mysession &&
-                   p->p_stat != SZOMB)
+                   p->p_stat != SZOMB) {
                        if (entering)
                                hispgrp->pg_jobc++;
                        else if (--hispgrp->pg_jobc == 0)
                                orphanpg(hispgrp);
+               }
 }
 
 /* 
@@ -393,8 +674,7 @@ fixjobc(p, pgrp, entering)
  * hang-up all process in that group.
  */
 static void
-orphanpg(pg)
-       struct pgrp *pg;
+orphanpg(struct pgrp *pg)
 {
        register struct proc *p;
 
@@ -412,15 +692,17 @@ orphanpg(pg)
 }
 
 #ifdef DEBUG
+void pgrpdump(void);   /* forward declare here (called from debugger) */
+
 void
-pgrpdump()
+pgrpdump(void)
 {
-       register struct pgrp *pgrp;
-       register struct proc *p;
-       register i;
+       struct pgrp *pgrp;
+       struct proc *p;
+       u_long i;
 
        for (i = 0; i <= pgrphash; i++) {
-               if (pgrp = pgrphashtbl[i].lh_first) {
+               if ((pgrp = pgrphashtbl[i].lh_first) != NULL) {
                        printf("\tindx %d\n", i);
                        for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) {
                                printf("\tpgrp 0x%08x, pgid %d, sess %p, sesscnt %d, mem %p\n",
@@ -438,7 +720,84 @@ pgrpdump()
 }
 #endif /* DEBUG */
 
-struct proc * current_proc_EXTERNAL()
+/* XXX should be __private_extern__ */
+int
+proc_is_classic(struct proc *p)
+{
+    return (p->p_flag & P_TRANSLATED) ? 1 : 0;
+}
+
+/* XXX Why does this function exist?  Need to kill it off... */
+struct proc *
+current_proc_EXTERNAL(void)
 {
        return (current_proc());
 }
+
+/*
+ * proc_core_name(name, uid, pid)
+ * Expand the name described in corefilename, using name, uid, and pid.
+ * corefilename is a printf-like string, with three format specifiers:
+ *     %N      name of process ("name")
+ *     %P      process id (pid)
+ *     %U      user id (uid)
+ * For example, "%N.core" is the default; they can be disabled completely
+ * by using "/dev/null", or all core files can be stored in "/cores/%U/%N-%P".
+ * This is controlled by the sysctl variable kern.corefile (see above).
+ */
+__private_extern__ char *
+proc_core_name(const char *name, uid_t uid, pid_t pid)
+{
+       const char *format, *appendstr;
+       char *temp;
+       char id_buf[11];                /* Buffer for pid/uid -- max 4B */
+       size_t i, l, n;
+
+       format = corefilename;
+       MALLOC(temp, char *, MAXPATHLEN, M_TEMP, M_NOWAIT | M_ZERO);
+       if (temp == NULL)
+               return (NULL);
+       for (i = 0, n = 0; n < MAXPATHLEN && format[i]; i++) {
+               switch (format[i]) {
+               case '%':       /* Format character */
+                       i++;
+                       switch (format[i]) {
+                       case '%':
+                               appendstr = "%";
+                               break;
+                       case 'N':       /* process name */
+                               appendstr = name;
+                               break;
+                       case 'P':       /* process id */
+                               sprintf(id_buf, "%u", pid);
+                               appendstr = id_buf;
+                               break;
+                       case 'U':       /* user id */
+                               sprintf(id_buf, "%u", uid);
+                               appendstr = id_buf;
+                               break;
+                       default:
+                               appendstr = "";
+                               log(LOG_ERR,
+                                   "Unknown format character %c in `%s'\n",
+                                   format[i], format);
+                       }
+                       l = strlen(appendstr);
+                       if ((n + l) >= MAXPATHLEN)
+                               goto toolong;
+                       bcopy(appendstr, temp + n, l);
+                       n += l;
+                       break;
+               default:
+                       temp[n++] = format[i];
+               }
+       }
+       if (format[i] != '\0')
+               goto toolong;
+       return (temp);
+toolong:
+       log(LOG_ERR, "pid %ld (%s), uid (%lu): corename is too long\n",
+           (long)pid, name, (u_long)uid);
+       FREE(temp, M_TEMP);
+       return (NULL);
+}