]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_proc.c
xnu-792.tar.gz
[apple/xnu.git] / bsd / kern / kern_proc.c
index 125fde90a30ec564f9733dcda1bf16f1a3282be8..89a60a915f0a8bf191cc5ff7c9bcdd009e95ace4 100644 (file)
@@ -3,22 +3,19 @@
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * 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 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. 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
+ * 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
+ * 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@
  */
 #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>
@@ -82,6 +78,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.
@@ -104,6 +102,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.
@@ -151,6 +155,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;
@@ -174,9 +180,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 */
@@ -188,6 +192,186 @@ 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());
+}
+
+
+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
  */
@@ -206,6 +390,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
  */
@@ -251,6 +450,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);
@@ -263,6 +464,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;
@@ -325,13 +528,21 @@ void
 pgdelete(pgrp)
        register struct pgrp *pgrp;
 {
+       struct tty * ttyp;
+       int removettypgrp = 0;
 
+       ttyp = pgrp->pg_session->s_ttyp;
        if (pgrp->pg_session->s_ttyp != NULL && 
-           pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
+           pgrp->pg_session->s_ttyp->t_pgrp == pgrp) {
                pgrp->pg_session->s_ttyp->t_pgrp = NULL;
+               removettypgrp = 1;
+       }
        LIST_REMOVE(pgrp, pg_hash);
-       if (--pgrp->pg_session->s_count == 0)
+       if (--pgrp->pg_session->s_count == 0) {
+               if (removettypgrp && (ttyp == &cons) && (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);
 }
 
@@ -343,8 +554,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"
@@ -356,10 +565,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;
@@ -369,11 +575,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
@@ -383,11 +590,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);
+               }
 }
 
 /* 
@@ -396,8 +604,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;
 
@@ -415,15 +622,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",
@@ -441,7 +650,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_CLASSIC) ? 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);
+}