summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael I. Bushnell <mib@gnu.org>1994-03-22 18:36:52 +0000
committerMichael I. Bushnell <mib@gnu.org>1994-03-22 18:36:52 +0000
commita2e14dc11cdd72f366a0e0058375ab5a34bc15af (patch)
treea6e9e84032a8d25715c1981f5baa32b291939247
parente6516d3d37826282d434bfd455722c507e7cd417 (diff)
Initial revision
-rw-r--r--proc/Makefile71
-rw-r--r--proc/hash.c292
-rw-r--r--proc/host.c204
-rw-r--r--proc/info.c403
-rw-r--r--proc/main.c70
-rw-r--r--proc/mgt.c573
-rw-r--r--proc/msg.c120
-rw-r--r--proc/notify.c58
-rw-r--r--proc/pgrp.c313
-rw-r--r--proc/proc.h184
-rw-r--r--proc/wait.c314
11 files changed, 2602 insertions, 0 deletions
diff --git a/proc/Makefile b/proc/Makefile
new file mode 100644
index 00000000..e1ed85d6
--- /dev/null
+++ b/proc/Makefile
@@ -0,0 +1,71 @@
+# Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# The GNU Hurd is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with the GNU Hurd; see the file COPYING. If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := proc
+
+include ../Makeconf
+
+PROCMIGOPTS="-DPROCESS_INTRAN=pstruct_t reqport_find (process_t)" \
+ "-DPROCESS_IMPORTS=import \"proc.h\";" \
+ "-DSERVERPREFIX=S_"
+
+OBJS = proc_wait.o proc_hash.o proc_host.o \
+ proc_info.o proc_main.o proc_mgt.o \
+ proc_notify.o proc_pgrp.o proc_msg.o \
+ processServer.o notifyServer.o process_replyUser.o msgUser.o \
+ interruptServer.o
+
+SRCS = proc_wait.c proc_hash.c proc_host.c proc_info.c proc_main.c proc_mgt.c \
+ proc_notify.c proc_pgrp.c proc_coll.c proc_msg.c
+
+DIST_FILES = $(SRCS) proc.h Makefile
+
+all: proc
+
+proc: $(OBJS)
+ $(link)
+
+$(OBJS): proc.h proc_S.h
+proc_notify.o: notify_S.h
+proc_wait.o: process_reply.h msg.h interrupt_S.h
+
+proc_S.h processServer.c: $(headers)/hurd/process.defs $(headers)/hurd/hurd_types.defs
+ $(CPP) $(CPPFLAGS) $(PROCMIGOPTS) $(headers)/hurd/process.defs \
+ | $(MIGCOM) -sheader proc_S.h -user /dev/null -header /dev/null
+
+process_reply.h process_replyUser.c: $(headers)/hurd/process_reply.defs $(hurd/hurd_types.defs)
+ $(CPP) $(CPPFLAGS) $(headers)/hurd/process_reply.defs \
+ | $(MIGCOM) -server /dev/null
+
+interrupt_S.h interruptServer.c: $(headers)/hurd/interrupt.defs
+ $(CPP) $(CPPFLAGS) $(PROCMIGOPTS) $(headers)/hurd/interrupt.defs \
+ | $(MIGCOM) -sheader interrupt_S.h -user /dev/null -header /dev/null
+
+notify_S.h notifyServer.c:
+ $(CPP) $(CPPFLAGS) $(headers)/mach/notify.defs \
+ | $(MIGCOM) -sheader notify_S.h -header /dev/null -user /dev/null
+
+# The reason for -Dout= is to prevent errors for get_init_port,
+# get_init_ports, get_init_int, get_init_ints, get_dtable, and get_fd.
+# We don't use those, so we're safe in breaking them.
+msg.h msgUser.c: $(headers)/hurd/msg.defs $(headers)/hurd/hurd_types.defs
+ $(CPP) $(CPPFLAGS) -Droutine=simpleroutine -Dout= $(headers)/hurd/msg.defs \
+ | $(MIGCOM) -prefix nowait_ -server /dev/null
+
+clean:
+ rm -f *.o *Server.c notify_S.h proc_S.h proc process_reply.h \
+ process_replyUser.c msg.h msgUser.c
diff --git a/proc/hash.c b/proc/hash.c
new file mode 100644
index 00000000..d183c0ea
--- /dev/null
+++ b/proc/hash.c
@@ -0,0 +1,292 @@
+/* Hash table functions
+ Copyright (C) 1993, 1994 Free Software Foundation
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell. */
+
+#include <mach.h>
+#include <sys/types.h>
+#include <hurd/hurd_types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+
+#include "proc.h"
+
+#define HASH(pg) (id % ht->size)
+#define REHASH(pg, h) ((id + (h * h)) % ht->size)
+
+struct htable
+{
+ void **tab;
+ int *ids;
+ int size;
+};
+#define HASH_DEL ((void *) -1)
+
+static struct htable pghash, pidhash, taskhash, porthash, sidhash, collhash;
+static struct htable pgcollhash, sesscollhash;
+
+/* Add ITEM to the hash table HT. LOCP is the address of a pointer located
+ in ITEM; *LOCP will be set to the address of ITEM's hash table pointer.
+ The lookup key of ITEM is ID. */
+static void
+addhash (struct htable *ht,
+ void *item,
+ void ***locp,
+ int id)
+{
+ int h, firsth = -1;
+ void **oldlist;
+ int *oldids;
+ int oldsize;
+ int i;
+
+ for (h = HASH (id);
+ (ht->tab[h] != 0 && ht->tab[h] != HASH_DEL && h != firsth);
+ firsth = (firsth == -1) ? h : firsth, h = REHASH (id, firsth))
+ ;
+
+ if (ht->tab[h] == 0
+ || ht->tab[h] == HASH_DEL)
+ {
+ ht->tab[h] = item;
+ ht->ids[h] = id;
+ *locp = &ht->tab[h];
+ return;
+ }
+
+ /* We have to rehash this again? */
+ oldlist = ht->tab;
+ oldsize = ht->size;
+ oldids = ht->ids;
+
+ ht->size = nextprime (2 * ht->size);
+ ht->tab = malloc (ht->size * sizeof (void *));
+ ht->ids = malloc (ht->size * sizeof (int));
+ bzero (ht->tab, (ht->size * sizeof (void *)));
+
+ if (oldlist)
+ for (i = 0; i < oldsize; i++)
+ if (oldlist[i] != 0
+ && oldlist[i] != HASH_DEL)
+ addhash (ht, oldlist[i], locp, oldids[i]);
+ addhash (ht, item, locp, id);
+
+ if (oldlist)
+ {
+ free (oldlist);
+ free (oldids);
+ }
+}
+
+/* Find and return the item in hash table HT with key ID. */
+static void *
+findhash (struct htable *ht,
+ int id)
+{
+ int h, firsth = -1;
+ void *ret;
+
+ for (h = HASH (id);
+ (ht->tab[h] != 0 && ht->ids[h] != id && h != firsth);
+ firsth = (firsth == -1) ? h : firsth, h = REHASH (id, firsth))
+ ;
+
+ if (ht->ids[h] == id)
+ ret = ht->tab[h];
+ else
+ ret = 0;
+ return ret;
+}
+
+/* Find the process corresponding to a given pid. */
+struct proc *
+pid_find (pid_t pid)
+{
+ return findhash (&pidhash, pid);
+}
+
+/* Find the process corresponding to a given task. */
+struct proc *
+task_find (task_t task)
+{
+ return findhash (&taskhash, task) ? : add_tasks (task);
+}
+
+/* Find the process corresponding to a given task, but
+ if we don't already know about it, just return 0. */
+struct proc *
+task_find_nocreate (task_t task)
+{
+ return findhash (&taskhash, task);
+}
+
+/* Find the process corresponding to a given request port. */
+struct proc *
+reqport_find (mach_port_t reqport)
+{
+ return findhash (&porthash, reqport);
+}
+
+/* Find the process group corresponding to a given pgid. */
+struct pgrp *
+pgrp_find (pid_t pgid)
+{
+ return findhash (&pghash, pgid);
+}
+
+/* Find the session corresponding to a given sid. */
+struct session *
+session_find (pid_t sid)
+{
+ return findhash (&sidhash, sid);
+}
+
+/* Find the process collection corresponding to a gived refport. */
+struct coll *
+coll_find (mach_port_t refport)
+{
+ return findhash (&collhash, refport);
+}
+
+/* Add a new process to the various hash tables. */
+void
+add_proc_to_hash (struct proc *p)
+{
+ addhash (&pidhash, p, &p->p_pidhashloc, p->p_pid);
+ addhash (&taskhash, p, &p->p_taskhashloc, p->p_task);
+ addhash (&porthash, p, &p->p_porthashloc, p->p_reqport);
+}
+
+/* Add a new process group to the various hash tables. */
+void
+add_pgrp_to_hash (struct pgrp *pg)
+{
+ addhash (&pghash, pg, &pg->pg_hashloc, pg->pg_pgid);
+ if (pg->pg_fakecoll)
+ addhash (&pgcollhash, pg, &pg->pg_fakecollhashloc, pg->pg_fakecoll);
+ else
+ pg->pg_fakecollhashloc = 0;
+}
+
+/* A process group's fake collection port has changed; update
+ the hash tables apporpriately. */
+void
+add_pgrp_fakecoll_to_hash (struct pgrp *pg)
+{
+ if (pg->pg_fakecollhashloc)
+ *pg->pg_fakecollhashloc = HASH_DEL;
+ addhash (&pgcollhash, pg, &pg->pg_fakecollhashloc, pg->pg_fakecoll);
+}
+
+/* Add a new process collection to the various hash tables. */
+void
+add_coll_to_hash (struct coll *c)
+{
+ addhash (&collhash, c, &c->c_hashloc, c->c_refport);
+}
+
+/* Add a new session to the various hash tables. */
+void
+add_session_to_hash (struct session *s)
+{
+ addhash (&sidhash, s, &s->s_hashloc, s->s_sid);
+ if (s->s_fakecoll)
+ addhash (&sesscollhash, s, &s->s_fakecollhashloc, s->s_fakecoll);
+ else
+ s->s_fakecollhashloc = 0;
+}
+
+/* A session's fake collection port has changes; update the hash tables
+ appropriately. */
+void
+add_session_fakecoll_to_hash (struct session *s)
+{
+ if (s->s_fakecollhashloc)
+ *s->s_fakecollhashloc = HASH_DEL;
+ addhash (&sesscollhash, s, &s->s_fakecollhashloc, s->s_fakecoll);
+}
+
+
+/* Remove a process group from the various hash tables. */
+void
+remove_pgrp_from_hash (struct pgrp *pg)
+{
+ *pg->pg_hashloc = HASH_DEL;
+ if (pg->pg_fakecollhashloc)
+ *pg->pg_fakecollhashloc = HASH_DEL;
+}
+
+/* Remove a process from the various hash tables. */
+void
+remove_proc_from_hash (struct proc *p)
+{
+ *p->p_pidhashloc = HASH_DEL;
+ *p->p_taskhashloc = HASH_DEL;
+ *p->p_porthashloc = HASH_DEL;
+}
+
+/* Remove a process collection from the various hash tables. */
+void
+remove_coll_from_hash (struct coll *c)
+{
+ *c->c_hashloc = HASH_DEL;
+}
+
+/* Remove a session from the various hash tables. */
+void
+remove_session_from_hash (struct session *s)
+{
+ *s->s_hashloc = HASH_DEL;
+ if (s->s_fakecollhashloc)
+ *s->s_fakecollhashloc = HASH_DEL;
+}
+
+/* Call function FUN of two args for each process. FUN's first arg is
+ the process, its second arg is ARG. */
+void
+prociterate (void (*fun) (struct proc *, void *), void *arg)
+{
+ int i;
+
+ for (i = 0; i < pidhash.size; i++)
+ if (pidhash.tab[i] && pidhash.tab[i] != HASH_DEL)
+ (*fun)(pidhash.tab[i], arg);
+}
+
+/* Call function FUN of two args for each process collection. FUN's first
+ arg is the collection, its second arg is ARG. */
+void
+colliterate (void (*fun) (struct coll *, void *), void *arg)
+{
+ int i;
+
+ for (i = 0; i < collhash.size; i++)
+ if (collhash.tab[i] && collhash.tab[i] != HASH_DEL)
+ (*fun)(collhash.tab[i], arg);
+}
+
+/* Tell if a pid is available for use */
+int
+pidfree (pid_t pid)
+{
+ return (!pid_find (pid) && !pgrp_find (pid)
+ && !session_find (pid) && !zombie_check_pid (pid));
+}
+
diff --git a/proc/host.c b/proc/host.c
new file mode 100644
index 00000000..ccd53477
--- /dev/null
+++ b/proc/host.c
@@ -0,0 +1,204 @@
+/* Proc server host management calls
+ Copyright (C) 1992, 1993, 1994 Free Software Foundation
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell. */
+
+#include <mach.h>
+#include <sys/types.h>
+#include <hurd/hurd_types.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <mach/notify.h>
+#include <string.h>
+#include <hurd/exec.h>
+
+#include "proc.h"
+#include "proc_S.h"
+
+static long hostid;
+static char *hostname;
+static int hostnamelen;
+static mach_port_t *std_port_array;
+static int *std_int_array;
+static int n_std_ports, n_std_ints;
+
+struct execdata_notify
+{
+ mach_port_t notify_port;
+ struct execdata_notify *next;
+} *execdata_notifys;
+
+/* Implement proc_sethostid as described in <hurd/proc.defs>. */
+error_t
+S_proc_sethostid (struct proc *p,
+ int newhostid)
+{
+ if (! check_uid (p, 0))
+ return EPERM;
+
+ hostid = newhostid;
+
+ return 0;
+}
+
+/* Implement proc_gethostid as described in <hurd/proc.defs>. */
+error_t
+S_proc_gethostid (struct proc *p,
+ int *outhostid)
+{
+ *outhostid = hostid;
+ return 0;
+}
+
+/* Implement proc_sethostname as described in <hurd/proc.defs>. */
+error_t
+S_proc_sethostname (struct proc *p,
+ char *newhostname,
+ u_int newhostnamelen)
+{
+ if (! check_uid (p, 0))
+ return EPERM;
+
+ if (hostname)
+ free (hostname);
+
+ hostname = malloc (newhostnamelen + 1);
+ hostnamelen = newhostnamelen;
+
+ bcopy (newhostname, hostname, newhostnamelen);
+ hostname[newhostnamelen] = '\0';
+
+ return 0;
+}
+
+/* Implement proc_gethostname as described in <hurd/proc.defs>. */
+error_t
+S_proc_gethostname (struct proc *p,
+ char **outhostname,
+ u_int *outhostnamelen)
+{
+ if (*outhostnamelen > hostnamelen + 1)
+ vm_allocate (mach_task_self (), (vm_address_t *)outhostname,
+ hostnamelen, 1);
+ *outhostnamelen = hostnamelen + 1;
+ bcopy (hostname, *outhostname, hostnamelen + 1);
+ return 0;
+}
+
+/* Implement proc_getprivports as described in <hurd/proc.defs>. */
+error_t
+S_proc_getprivports (struct proc *p,
+ mach_port_t *hostpriv,
+ mach_port_t *devpriv)
+{
+ if (! check_uid (p, 0))
+ return EPERM;
+
+ *hostpriv = master_host_port;
+ *devpriv = master_device_port;
+ return 0;
+}
+
+/* Implement proc_setexecdata as described in <hurd/proc.defs>. */
+error_t
+S_proc_setexecdata (struct proc *p,
+ mach_port_t *ports,
+ u_int nports,
+ int *ints,
+ u_int nints)
+{
+ int i;
+ struct execdata_notify *n;
+
+ if (!check_uid (p, 0))
+ return EPERM;
+
+ if (std_port_array)
+ {
+ for (i = 0; i < n_std_ports; i++)
+ mach_port_deallocate (mach_task_self (), std_port_array[i]);
+ free (std_port_array);
+ }
+ if (std_int_array)
+ free (std_int_array);
+
+ std_port_array = malloc (sizeof (mach_port_t) * nports);
+ n_std_ports = nports;
+ bcopy (ports, std_port_array, sizeof (mach_port_t) * nports);
+
+ std_int_array = malloc (sizeof (int) * nints);
+ n_std_ints = nints;
+ bcopy (ints, std_int_array, sizeof (int) * nints);
+
+ for (n = execdata_notifys; n; n = n->next)
+ exec_setexecdata (n->notify_port, std_port_array, MACH_MSG_TYPE_COPY_SEND,
+ n_std_ports, std_int_array, n_std_ints);
+
+ return 0;
+}
+
+/* Implement proc_getexecdata as described in <hurd/proc.defs>. */
+error_t
+S_proc_getexecdata (struct proc *p,
+ mach_port_t **ports,
+ mach_msg_type_name_t *portspoly,
+ u_int *nports,
+ int **ints,
+ u_int *nints)
+{
+ /* XXX memory leak here */
+
+ if (*nports < n_std_ports)
+ *ports = malloc (n_std_ports * sizeof (mach_port_t));
+ bcopy (std_port_array, *ports, n_std_ports * sizeof (mach_port_t));
+ *nports = n_std_ports;
+
+ if (*nints < n_std_ints)
+ *ints = malloc (n_std_ints * sizeof (mach_port_t));
+ bcopy (std_int_array, *ints, n_std_ints * sizeof (int));
+ *nints = n_std_ints;
+
+ return 0;
+}
+
+/* Implement proc_execdata_notify as described in <hurd/proc.defs>. */
+error_t
+S_proc_execdata_notify (struct proc *p,
+ mach_port_t notify)
+{
+ struct execdata_notify *n = malloc (sizeof (struct execdata_notify));
+ mach_port_t foo;
+
+ n->notify_port = notify;
+ n->next = execdata_notifys;
+ execdata_notifys = n;
+
+ mach_port_request_notification (mach_task_self (), notify,
+ MACH_NOTIFY_DEAD_NAME, 1,
+ generic_port, MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &foo);
+
+ if (foo)
+ mach_port_deallocate (mach_task_self (), foo);
+
+ exec_setexecdata (n->notify_port, std_port_array, MACH_MSG_TYPE_COPY_SEND,
+ n_std_ports, std_int_array, n_std_ints);
+ return 0;
+}
+
diff --git a/proc/info.c b/proc/info.c
new file mode 100644
index 00000000..416c2b7f
--- /dev/null
+++ b/proc/info.c
@@ -0,0 +1,403 @@
+/* Process information queries
+ Copyright (C) 1992, 1993, 1994 Free Software Foundation
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell. */
+
+#include <mach.h>
+#include <sys/types.h>
+#include <hurd/hurd_types.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/resource.h>
+
+#include "proc.h"
+#include "proc_S.h"
+
+/* Implement S_proc_pid2task as described in <hurd/proc.defs>. */
+error_t
+S_proc_pid2task (struct proc *callerp,
+ pid_t pid,
+ task_t *t)
+{
+ struct proc *p = pid_find (pid);
+
+ if (!p)
+ return ESRCH;
+
+ if (!check_uid (callerp, p->p_owner))
+ return EPERM;
+
+ *t = p->p_task;
+
+ return 0;
+}
+
+/* Implement proc_task2pid as described in <hurd/proc.defs>. */
+error_t
+S_proc_task2pid (struct proc *callerp,
+ task_t t,
+ pid_t *pid)
+{
+ struct proc *p = task_find (t);
+
+ if (!p)
+ return ESRCH;
+
+ *pid = p->p_pid;
+ mach_port_deallocate (mach_task_self (), t);
+ return 0;
+}
+
+/* Implement proc_task2proc as described in <hurd/proc.defs>. */
+error_t
+S_proc_task2proc (struct proc *callerp,
+ task_t t,
+ mach_port_t *outproc)
+{
+ struct proc *p = task_find (t);
+
+ if (!p)
+ return ESRCH;
+
+ *outproc = p->p_reqport;
+ mach_port_deallocate (mach_task_self (), t);
+ return 0;
+}
+
+/* Implement proc_proc2task as described in <hurd/proc.defs>. */
+error_t
+S_proc_proc2task (struct proc *p,
+ task_t *t)
+{
+ *t = p->p_task;
+ return 0;
+}
+
+/* Implement proc_pid2proc as described in <hurd/proc.defs>. */
+error_t
+S_proc_pid2proc (struct proc *callerp,
+ pid_t pid,
+ mach_port_t *outproc)
+{
+ struct proc *p = pid_find (pid);
+
+ if (!p)
+ return ESRCH;
+
+ if (!check_uid (callerp, p->p_owner))
+ return EPERM;
+
+ *outproc = p->p_reqport;
+ return 0;
+}
+
+#ifdef notyet
+
+/* Read a string starting at address ADDR in task T; set *STR to point at
+ newly malloced storage holding it. */
+static error_t
+get_string (task_t t,
+ vm_address_t addr,
+ char **str)
+{
+ /* This version assumes that a string is never more than one
+ page in length. */
+
+ vm_address_t readaddr;
+ vm_address_t data;
+ u_int readlen;
+ error_t err;
+ char *c;
+
+ readaddr = trunc_page (addr);
+ err = vm_read (t, readaddr, vm_page_size * 2, &data, &readlen);
+ if (err == KERN_INVALID_ADDRESS)
+ err = vm_read (t, readaddr, vm_page_size, &data, &readlen);
+ if (err)
+ return err;
+
+ /* Scan for a null */
+ for (c = (char *)(data + (addr - readaddr));
+ c < (char *)(data + readlen);
+ c++)
+ if (*(char *)c == '\0')
+ {
+ c++; /* include the null */
+ *str = malloc (c - (char *)(data + (addr - readaddr)));
+ bcopy ((char *)(data + (addr - readaddr)), *str,
+ c - (char *)(data + (addr - readaddr)));
+ }
+
+ if (*str == 0)
+ err = KERN_INVALID_ADDRESS;
+
+ vm_deallocate (mach_task_self (), data, (vm_address_t)&readlen);
+ return err;
+}
+
+/* Read a vector of addresses (stored as are argv and envp) from tast TASK
+ found at address ADDR. Set *VEC to point to newly malloced storage holding
+ the addresses. */
+static error_t
+get_vector (task_t task,
+ vm_address_t addr,
+ int **vec)
+{
+ vm_address_t readaddr;
+ vm_address_t data = 0;
+ u_int readlen;
+ error_t err;
+ vm_address_t *t;
+
+ readaddr = trunc_page (addr);
+ err = vm_read (task, readaddr, vm_page_size * 2, &data, &readlen);
+ if (err == KERN_INVALID_ADDRESS)
+ err = vm_read (task, readaddr, vm_page_size, &data, &readlen);
+ if (err)
+ return err;
+
+ /* Scan for a null */
+ /* This will lose sometimes on machines with unfortunate alignment
+ restrictions. XXX */
+ for (t = (int *)(data + (addr - readaddr));
+ t < (vm_address_t *)(data + readlen);
+ t += sizeof (int))
+ if (*(int *)t == 0)
+ {
+ t += 4; /* include the null */
+ *vec = malloc ((char *)t - (char *)(data + (addr - readaddr))
+ + sizeof (int));
+ bcopy ((char *)(data + (addr - readaddr)), *vec,
+ (char *)t - (char *)(data + (addr - readaddr)));
+ }
+
+ if (*vec == 0)
+ err = KERN_INVALID_ADDRESS;
+
+ vm_deallocate (mach_task_self (), data, (vm_address_t)readlen);
+ return err;
+}
+
+/* Fetch an array of strings at address LOC in task T into
+ BUF of size BUFLEN. */
+static error_t
+get_string_array (task_t t,
+ vm_address_t loc,
+ vm_address_t *buf,
+ u_int *buflen)
+{
+ int totstringlen;
+ char *bp;
+ int *vector;
+ error_t err;
+ vm_address_t origbuf = *buf;
+
+ err = get_vector (t, loc, &vector);
+ if (err)
+ return err;
+
+ while (*vector)
+ {
+ char *string;
+ int len;
+
+ err = get_string (t, *vector, &string);
+ if (err)
+ {
+ free (vector);
+ if (*buf != origbuf)
+ vm_deallocate (mach_task_self (), *buf, *buflen);
+ return err;
+ }
+
+ len = strlen (string) + 1;
+ if (len > (bp - *(char **)buf))
+ {
+ vm_address_t newbuf;
+
+ err = vm_allocate (mach_task_self (), &newbuf, *buflen * 2, 1);
+ if (err)
+ {
+ free (string);
+ free (vector);
+ if (*buf != origbuf)
+ vm_deallocate (mach_task_self (), *buf, *buflen);
+ return err;
+ }
+ bcopy (*(char **)buf, (void *)newbuf, (vm_address_t) bp - newbuf);
+ bp = newbuf + (bp - *buf);
+ if (*buf != origbuf)
+ vm_deallocate (mach_task_self (), *buf, *buflen);
+ *buf = newbuf;
+ *buflen *= 2;
+ }
+ bcopy (string, bp, len);
+ bp += len;
+ free (string);
+ }
+ free (vector);
+ *buflen = (vm_address_t)bp - *buf;
+ return 0;
+}
+#endif /* notyet */
+
+/* Implement proc_getprocargs as described in <hurd/proc.defs>. */
+error_t
+S_proc_getprocargs (struct proc *callerp,
+ pid_t pid,
+ char **buf,
+ u_int *buflen)
+{
+ #ifdef notyet
+ struct proc *p = pid_find (pid);
+
+ if (!p)
+ return ESRCH;
+
+ return get_string_array (p->p_task, p->p_argv, buflen, buf);
+#else
+ return EOPNOTSUPP;
+#endif
+}
+
+/* Implement proc_getprocenv as described in <hurd/proc.defs>. */
+error_t
+S_proc_getprocenv (struct proc *callerp,
+ pid_t pid,
+ char **buf,
+ u_int *buflen)
+{
+#ifdef notyet
+ struct proc *p = pid_find (pid);
+
+ if (!p)
+ return ESRCH;
+
+ return get_string_array (p->p_task, p->p_envp, buflen, buf);
+#else
+ return EOPNOTSUPP;
+#endif
+}
+
+/* Implement proc_getprocinfo as described in <hurd/proc.defs>. */
+error_t
+S_proc_getprocinfo (struct proc *callerp,
+ pid_t pid,
+ int **piarray,
+ u_int *piarraylen)
+{
+ struct proc *p = pid_find (pid);
+ struct procinfo *pi;
+ int nthreads;
+ thread_t *thds;
+ error_t err;
+ size_t structsize;
+ int i;
+ int didalloc = 0;
+ u_int tkcount, thcount;
+
+ if (!p)
+ return ESRCH;
+
+ err = task_threads (p->p_task, &thds, &nthreads);
+ if (err)
+ return err;
+
+ structsize = (sizeof (struct procinfo)
+ + nthreads * sizeof (struct thread_basic_info)
+ + nthreads * sizeof (struct thread_sched_info));
+
+ if (structsize / sizeof (int) > *piarraylen)
+ {
+ vm_allocate (mach_task_self (), (u_int *)&piarray, structsize, 1);
+ didalloc = 1;
+ }
+ *piarraylen = structsize / sizeof (int);
+ pi = (struct procinfo *) *piarray;
+
+ pi->state =
+ ((p->p_stopped ? PI_STOPPED : 0)
+ | (p->p_exec ? PI_EXECED : 0)
+ | (!p->p_pgrp->pg_orphcnt ? PI_ORPHAN : 0)
+ | (p->p_pgrp->pg_session->s_sid == p->p_pid ? PI_SESSLD : 0)
+ | (!p->p_parentset ? PI_NOPARENT : 0)
+ | (p->p_msgport == MACH_PORT_NULL ? PI_NOMSG : 0));
+ pi->owner = p->p_owner;
+ pi->ppid = p->p_parent->p_pid;
+ pi->pgrp = p->p_pgrp->pg_pgid;
+ pi->session = p->p_pgrp->pg_session->s_sid;
+
+ pi->nthreads = nthreads;
+
+ tkcount = TASK_BASIC_INFO_COUNT;
+ err = task_info (p->p_task, TASK_BASIC_INFO, (int *)&pi->taskinfo,
+ &tkcount);
+
+ for (i = 0; i < nthreads; i++)
+ {
+ thcount = THREAD_BASIC_INFO_COUNT;
+ if (!err)
+ err = thread_info (thds[i], THREAD_BASIC_INFO,
+ (int *)&pi->threadinfos[i].pis_bi,
+ &thcount);
+ thcount = THREAD_SCHED_INFO_COUNT;
+ if (!err)
+ err = thread_info (thds[i], THREAD_SCHED_INFO,
+ (int *)&pi->threadinfos[i].pis_si,
+ &thcount);
+ mach_port_deallocate (mach_task_self (), thds[i]);
+ }
+
+ vm_deallocate (mach_task_self (), (u_int )thds,
+ nthreads * sizeof (thread_t));
+ if (err && didalloc)
+ vm_deallocate (mach_task_self (), (u_int) piarray, structsize);
+
+ return err;
+}
+
+/* Implement proc_setlogin as described in <hurd/proc.defs>. */
+error_t
+S_proc_setlogin (struct proc *p,
+ char *login)
+{
+ struct login *l;
+
+ if (!check_uid (p, 0))
+ return EPERM;
+
+ l = malloc (sizeof (struct login) + strlen (login) + 1);
+ l->l_refcnt = 1;
+ strcpy (l->l_name, login);
+ if (!--p->p_login->l_refcnt)
+ free (p->p_login);
+ p->p_login = l;
+ return 0;
+}
+
+/* Implement proc_getlogin as described in <hurd/proc.defs>. */
+error_t
+S_proc_getlogin (struct proc *p,
+ char *login)
+{
+ strcpy (login, p->p_login->l_name);
+ return 0;
+}
+
diff --git a/proc/main.c b/proc/main.c
new file mode 100644
index 00000000..453c50f6
--- /dev/null
+++ b/proc/main.c
@@ -0,0 +1,70 @@
+/* Initialization of the proc server
+ Copyright (C) 1993, 1994 Free Software Foundation
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell. */
+
+#include <mach.h>
+#include <hurd/hurd_types.h>
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <hurd/startup.h>
+
+#include "proc.h"
+
+
+
+int
+message_demuxer (mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+{
+ extern int process_server (mach_msg_header_t *, mach_msg_header_t *);
+ extern int notify_server (mach_msg_header_t *, mach_msg_header_t *);
+ extern int interrupt_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ return (process_server (inp, outp)
+ || notify_server (inp, outp)
+ || interrupt_server (inp, outp));
+}
+
+void
+main ()
+{
+ mach_port_t boot;
+ mach_port_t authhandle;
+
+ task_get_bootstrap_port (mach_task_self (), &boot);
+
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_PORT_SET,
+ &request_portset);
+
+ self_proc = new_proc (mach_task_self ()); /* proc 0 is the procserver */
+ startup_proc = new_proc (MACH_PORT_NULL); /* proc 1 is init */
+
+ startup_procinit (boot, startup_proc->p_reqport, &startup_proc->p_task,
+ &authhandle, &master_host_port, &master_device_port);
+
+ _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authhandle);
+ mach_port_deallocate (mach_task_self (), boot);
+
+ add_proc_to_hash (self_proc);
+ add_proc_to_hash (startup_proc);
+
+ while (1)
+ mach_msg_server (message_demuxer, 0, request_portset);
+}
diff --git a/proc/mgt.c b/proc/mgt.c
new file mode 100644
index 00000000..bbfba744
--- /dev/null
+++ b/proc/mgt.c
@@ -0,0 +1,573 @@
+/* Process management
+ Copyright (C) 1992, 1993, 1994 Free Software Foundation
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell. */
+
+#include <mach.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <hurd/hurd_types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mach/notify.h>
+#include <sys/wait.h>
+#include <mach/mig_errors.h>
+#include <sys/resource.h>
+#include <hurd/auth.h>
+#include <assert.h>
+
+#include "proc.h"
+#include "proc_S.h"
+#include "msg.h"
+
+/* Create a new id structure with the given genuine uids and gids. */
+static inline struct ids *
+make_ids (uid_t *uids, int nuids, uid_t *gids, int ngids)
+{
+ struct ids *i;
+
+ i = malloc (sizeof (struct ids));
+ i->i_nuids = nuids;
+ i->i_ngids = ngids;
+ i->i_uids = malloc (sizeof (uid_t) * nuids);
+ i->i_gids = malloc (sizeof (uid_t) * ngids);
+ i->i_refcnt = 1;
+
+ bcopy (i->i_uids, uids, sizeof (uid_t) * nuids);
+ bcopy (i->i_gids, gids, sizeof (uid_t) * ngids);
+ return i;
+}
+
+/* Free an id structure. */
+static inline void
+free_ids (struct ids *i)
+{
+ free (i->i_uids);
+ free (i->i_gids);
+ free (i);
+}
+
+/* Tell if process P has uid UID. */
+int
+check_uid (struct proc *p, uid_t uid)
+{
+ int i;
+ for (i = 0; i < p->p_id->i_nuids; i++)
+ if (p->p_id->i_uids[i] == uid)
+ return 1;
+ return 0;
+}
+
+
+/* Implement proc_reathenticate as described in <hurd/proc.defs>. */
+error_t
+S_proc_reauthenticate (struct proc *p, int id)
+{
+ error_t err;
+ uid_t gubuf[50], aubuf[50], ggbuf[50], agbuf[50];
+ uid_t *gen_uids, *aux_uids, *gen_gids, *aux_gids;
+ u_int ngen_uids, naux_uids, ngen_gids, naux_gids;
+
+ gen_uids = gubuf;
+ aux_uids = aubuf;
+ gen_gids = ggbuf;
+ aux_gids = agbuf;
+
+ ngen_uids = naux_uids = 50;
+ ngen_gids = naux_gids = 50;
+
+ err = auth_server_authenticate (authserver, p->p_reqport,
+ MACH_MSG_TYPE_COPY_SEND, id,
+ MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND,
+ &gen_uids, &ngen_uids,
+ &aux_uids, &naux_uids,
+ &gen_gids, &ngen_gids,
+ &aux_gids, &naux_gids);
+ if (err)
+ return err;
+
+ if (!--p->p_id->i_refcnt)
+ free_ids (p->p_id);
+ p->p_id = make_ids (gen_uids, ngen_uids, gen_gids, ngen_gids);
+
+ if (gen_uids != gubuf)
+ vm_deallocate (mach_task_self (), (u_int) gen_uids,
+ ngen_uids * sizeof (uid_t));
+ if (aux_uids != aubuf)
+ vm_deallocate (mach_task_self (), (u_int) aux_uids,
+ naux_uids * sizeof (uid_t));
+ if (gen_gids != ggbuf)
+ vm_deallocate (mach_task_self (), (u_int) gen_gids,
+ ngen_gids * sizeof (uid_t));
+ if (aux_gids != agbuf)
+ vm_deallocate (mach_task_self (), (u_int) aux_gids,
+ naux_gids * sizeof (uid_t));
+
+ return 0;
+}
+
+/* Implement proc_child as described in <hurd/proc.defs>. */
+error_t
+S_proc_child (struct proc *parentp,
+ task_t childt)
+{
+ struct proc *childp = task_find (childt);
+
+ if (!childp)
+ return ESRCH;
+
+ if (childp->p_parentset)
+ return EBUSY;
+
+ /* Process identification.
+ Leave p_task and p_pid alone; all the rest comes from the
+ new parent. */
+
+ if (!--childp->p_login->l_refcnt)
+ free (childp->p_login);
+ childp->p_login = parentp->p_login;
+ childp->p_login->l_refcnt++;
+
+ childp->p_owner = parentp->p_owner;
+ childp->p_noowner = parentp->p_noowner;
+
+ if (!--childp->p_id->i_refcnt)
+ free_ids (childp->p_id);
+ childp->p_id = parentp->p_id;
+ childp->p_id->i_refcnt++;
+
+ /* Process hierarchy. Remove from our current location
+ and place us under our new parent. Sanity check to make sure
+ parent is currently init. */
+ assert (childp->p_parent == startup_proc);
+ *childp->p_prevsib = childp->p_sib;
+
+ childp->p_parent = parentp;
+ childp->p_sib = parentp->p_ochild;
+ childp->p_prevsib = &parentp->p_ochild;
+ if (parentp->p_ochild)
+ parentp->p_ochild->p_prevsib = &childp->p_sib;
+ parentp->p_ochild = childp;
+
+ /* Process group structure. */
+ leave_pgrp (childp);
+ childp->p_pgrp = parentp->p_pgrp;
+ join_pgrp (childp);
+
+ inherit_process_collections (childp);
+
+ childp->p_parentset = 1;
+ if (childp->p_msgport)
+ nowait_proc_newids (childp->p_msgport, childp->p_task,
+ childp->p_parent->p_pid, childp->p_pgrp->pg_pgid,
+ !childp->p_pgrp->pg_orphcnt);
+ return 0;
+}
+
+/* Implement proc_reassign as described in <hurd/proc.defs>. */
+error_t
+S_proc_reassign (struct proc *p,
+ task_t newt)
+{
+ struct proc *stubp = task_find (newt);
+ mach_port_t foo;
+
+ if (!stubp)
+ return ESRCH;
+
+ remove_proc_from_hash (p);
+
+ task_terminate (p->p_task);
+ mach_port_deallocate (mach_task_self (), p->p_task);
+ p->p_task = newt;
+ mach_port_request_notification (mach_task_self (), p->p_task,
+ MACH_NOTIFY_DEAD_NAME, 1, p->p_reqport,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
+ if (foo)
+ mach_port_deallocate (mach_task_self (), foo);
+
+ /* For security, we need to get a new request port */
+ mach_port_mod_refs (mach_task_self (), p->p_reqport,
+ MACH_PORT_RIGHT_RECEIVE, -1);
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ &p->p_reqport);
+ mach_port_move_member (mach_task_self (), p->p_reqport,
+ request_portset);
+
+ /* Enqueued messages might refer to the old task port, so
+ destroy them. */
+ if (p->p_msgport != MACH_PORT_NULL)
+ {
+ mach_port_deallocate (mach_task_self (), p->p_msgport);
+ p->p_msgport = MACH_PORT_NULL;
+ p->p_deadmsg = 1;
+ }
+
+ /* These two are image dependent. */
+ p->p_argv = stubp->p_argv;
+ p->p_envp = stubp->p_envp;
+
+ /* Destroy stubp */
+ stubp->p_task = 0; /* block deallocation */
+ process_has_exited (stubp);
+
+ add_proc_to_hash (p);
+
+ return 0;
+}
+
+/* Implement proc_setowner as described in <hurd/proc.defs>. */
+error_t
+S_proc_setowner (struct proc *p,
+ uid_t owner)
+{
+ if (! check_uid (p, owner))
+ return EPERM;
+
+ p->p_owner = owner;
+ p->p_noowner = 0;
+ return 0;
+}
+
+/* Implement proc_getpids as described in <hurd/proc.defs>. */
+error_t
+S_proc_getpids (struct proc *p,
+ pid_t *pid,
+ pid_t *ppid,
+ int *orphaned)
+{
+ *pid = p->p_pid;
+ *ppid = p->p_parent->p_pid;
+ *orphaned = !p->p_pgrp->pg_orphcnt;
+ return 0;
+}
+
+/* Implement proc_setprocargs as described in <hurd/proc.defs>. */
+error_t
+S_proc_setprocargs (struct proc *p,
+ int argv,
+ int envp)
+{
+ p->p_argv = argv;
+ p->p_envp = envp;
+ return 0;
+}
+
+/* Implement proc_dostop as described in <hurd/proc.defs>. */
+error_t
+S_proc_dostop (struct proc *p,
+ thread_t contthread)
+{
+ thread_t *threads;
+ int i;
+ u_int nthreads;
+
+ task_suspend (p->p_task);
+ task_threads (p->p_task, &threads, &nthreads);
+ for (i = 0; i < nthreads; i++)
+ if (threads[i] != contthread)
+ {
+ thread_suspend (threads[i]);
+ mach_port_deallocate (mach_task_self (), threads[i]);
+ }
+ vm_deallocate (mach_task_self (), (u_int) threads,
+ nthreads * sizeof (thread_t));
+ task_resume (p->p_task);
+ return 0;
+}
+
+/* Implement proc_getallpids as described in <hurd/proc.defs>. */
+error_t
+S_proc_getallpids (struct proc *p,
+ pid_t **pids,
+ u_int *pidslen)
+{
+ int nprocs;
+ pid_t *loc;
+
+ void count_up (struct proc *p, void *counter)
+ {
+ ++*(int *)counter;
+ }
+ void store_pid (struct proc *p, void *loc)
+ {
+ *(*(pid_t **)loc)++ = p->p_pid;
+ }
+
+ add_tasks (0);
+
+ nprocs = 0;
+ prociterate (count_up, &nprocs);
+
+ if (nprocs > *pidslen)
+ vm_allocate (mach_task_self (), (vm_address_t *) *pids,
+ nprocs * sizeof (pid_t), 1);
+
+ loc = *pids;
+ prociterate (store_pid, &loc);
+
+ *pidslen = nprocs;
+ return 0;
+}
+
+/* Create a process for TASK, which is not otherwise known to us.
+ The task will be placed as a child of init and in init's pgrp. */
+struct proc *
+new_proc (task_t task)
+{
+ struct proc *p;
+ mach_port_t foo;
+
+ /* Because these have a reference count of one before starting,
+ they can never be freed, so we're safe. */
+ static struct login *nulllogin;
+ static struct ids nullids = {0, 0, 0, 0, 1};
+
+ if (!nulllogin)
+ {
+ nulllogin = malloc (sizeof (struct login) + 7);
+ nulllogin->l_refcnt = 1;
+ strcpy (nulllogin->l_name, "<none>");
+ }
+
+ /* Pid 0 is us; pid 1 is init. We handle those here specially;
+ all other processes inherit from init here (though proc_child
+ will move them to their actual parent usually). */
+
+ p = malloc (sizeof (struct proc));
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ &p->p_reqport);
+ mach_port_move_member (mach_task_self (), p->p_reqport,
+ request_portset);
+
+ p->p_pid = genpid ();
+ p->p_task = task;
+ mach_port_request_notification (mach_task_self (), p->p_task,
+ MACH_NOTIFY_DEAD_NAME, 1, p->p_reqport,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
+ if (foo)
+ mach_port_deallocate (mach_task_self (), foo);
+
+
+ switch (p->p_pid)
+ {
+ case 0:
+ p->p_login = malloc (sizeof (struct login) + 5);
+ p->p_login->l_refcnt = 1;
+ strcpy (p->p_login->l_name, "root");
+ break;
+
+ case 1:
+ p->p_login = self_proc->p_login;
+ p->p_login->l_refcnt++;
+ break;
+
+ default:
+ p->p_login = nulllogin;
+ p->p_login->l_refcnt++;
+ }
+
+ p->p_owner = 0;
+
+ if (p->p_pid < 2)
+ {
+ uid_t foo = 0;
+ p->p_id = make_ids (&foo, 1, &foo, 1);
+ p->p_parent = 0;
+ p->p_sib = 0;
+ }
+
+ else
+ {
+ p->p_id = &nullids;
+ p->p_id->i_refcnt++;
+
+ /* Our parent is init for now */
+ p->p_parent = startup_proc;
+
+ p->p_sib = startup_proc->p_ochild;
+ p->p_prevsib = &startup_proc->p_ochild;
+ if (p->p_sib)
+ p->p_sib->p_prevsib = &p->p_sib;
+ startup_proc->p_ochild = p;
+ }
+
+ p->p_ochild = 0;
+
+ if (p->p_pid < 2)
+ boot_setsid (p);
+ else
+ p->p_pgrp = startup_proc->p_pgrp;
+
+ p->p_colls = 0; /* should add to allcolls XXX */
+
+ p->p_msgport = MACH_PORT_NULL;
+
+ p->p_argv = p->p_envp = p->p_status = 0;
+
+ p->p_exec = 0;
+ p->p_stopped = 0;
+ p->p_waited = 0;
+ p->p_exiting = 0;
+ p->p_waiting = 0;
+ p->p_traced = 0;
+ p->p_nostopcld = 0;
+ p->p_parentset = 0;
+ p->p_deadmsg = 0;
+ p->p_checkmsghangs = 0;
+ p->p_msgportwait = 0;
+ p->p_noowner = 1;
+
+ if (p->p_pid > 1)
+ {
+ add_proc_to_hash (p);
+ join_pgrp (p);
+ }
+
+ return p;
+}
+
+/* The task associated with process P has died. Free everything, and
+ record our presence in the zombie table, then return wait if necessary. */
+void
+process_has_exited (struct proc *p)
+{
+ alert_parent (p);
+
+ leave_all_process_collections (p);
+
+ if (p->p_checkmsghangs)
+ prociterate ((void (*) (struct proc *, void *))check_message_dying, p);
+
+ mach_port_mod_refs (mach_task_self (), p->p_reqport,
+ MACH_PORT_RIGHT_RECEIVE, -1);
+
+ remove_proc_from_hash (p);
+
+ mach_port_deallocate (mach_task_self (), p->p_task);
+
+ if (!--p->p_login->l_refcnt)
+ free (p->p_login);
+
+ if (!--p->p_id->i_refcnt)
+ free_ids (p->p_id);
+
+ /* Reparent our children to init by attaching the head and tail
+ of our list onto init's. */
+ if (p->p_ochild)
+ {
+ struct proc *tp; /* will point to the last one */
+
+ /* first tell them their parent is changing */
+ for (tp = p->p_ochild; tp->p_sib; tp = tp->p_sib)
+ nowait_proc_newids (tp->p_msgport, tp->p_task, 1, tp->p_pgrp->pg_pgid,
+ !tp->p_pgrp->pg_orphcnt);
+ nowait_proc_newids (tp->p_msgport, tp->p_task, 1, tp->p_pgrp->pg_pgid,
+ !tp->p_pgrp->pg_orphcnt);
+
+ /* And now nappend the list. */
+ tp->p_sib = startup_proc->p_ochild;
+ if (tp->p_sib)
+ tp->p_sib->p_prevsib = &tp->p_sib;
+ startup_proc->p_ochild = p->p_ochild;
+ p->p_ochild->p_prevsib = &startup_proc->p_ochild;
+ }
+
+ reparent_zombies (p);
+
+ /* Remove us from our parent's list of children. */
+ *p->p_prevsib = p->p_sib;
+
+ leave_pgrp (p);
+
+ mach_port_deallocate (mach_task_self (), p->p_msgport);
+
+ if (p->p_waiting)
+ mach_port_deallocate (mach_task_self (),
+ p->p_continuation.wait_c.reply_port);
+ if (p->p_msgportwait)
+ mach_port_deallocate (mach_task_self (),
+ p->p_continuation.getmsgport_c.reply_port);
+
+ free (p);
+}
+
+
+/* Get the list of all tasks from the kernel and start adding them.
+ If we encounter TASK, then don't do any more and return its proc.
+ If TASK is null or we never find it, then return 0. */
+struct proc *
+add_tasks (task_t task)
+{
+ mach_port_t *psets;
+ u_int npsets;
+ int i;
+ struct proc *foundp = 0;
+
+ host_processor_sets (mach_host_self (), &psets, &npsets);
+ for (i = 0; i < npsets; i++)
+ {
+ mach_port_t psetpriv;
+ mach_port_t *tasks;
+ u_int ntasks;
+ int j;
+
+ if (!foundp)
+ {
+ host_processor_set_priv (master_host_port, psets[i], &psetpriv);
+ processor_set_tasks (psetpriv, &tasks, &ntasks);
+ for (j = 0; j < ntasks; j++)
+ {
+ if (!foundp)
+ {
+ struct proc *p = task_find_nocreate (tasks[j]);
+ if (!p)
+ p = new_proc (tasks[j]);
+ if (!foundp && tasks[j] == task)
+ foundp = p;
+ }
+ mach_port_deallocate (mach_task_self (), tasks[j]);
+ }
+ vm_deallocate (mach_task_self (), (vm_address_t) tasks,
+ ntasks * sizeof (task_t));
+ mach_port_deallocate (mach_task_self (), psetpriv);
+ }
+ mach_port_deallocate (mach_task_self (), psets[i]);
+ }
+ vm_deallocate (mach_host_self (), (vm_address_t) psets,
+ npsets * sizeof (mach_port_t));
+ return foundp;
+}
+
+/* Allocate a new pid. The first two times this is called it must return
+ 0 and 1 in order; after that it must simply return an unused pid.
+ (Unused means it is neither the pid nor pgrp of any relevant data.) */
+int
+genpid ()
+{
+ static int nextpid = 0;
+
+#define WRAP_AROUND 30000
+#define START_OVER 100
+
+ while (!pidfree (nextpid)
+ && ((++nextpid > WRAP_AROUND) || (nextpid = START_OVER)))
+ ;
+ return nextpid++;
+}
diff --git a/proc/msg.c b/proc/msg.c
new file mode 100644
index 00000000..379baf4f
--- /dev/null
+++ b/proc/msg.c
@@ -0,0 +1,120 @@
+/* Message port manipulations
+ Copyright (C) 1994 Free Software Foundation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <mach.h>
+#include <hurd.h>
+#include "proc.h"
+#include "process_reply.h"
+
+/* Check to see if process P is blocked trying to get the message
+ port of process AVAILP; if so, return its call. */
+void
+check_message_return (struct proc *p, struct proc *availp)
+{
+ struct getmsgport_c *c = &p->p_continuation.getmsgport_c;
+
+ if (p->p_msgportwait && c->msgp == availp)
+ {
+ proc_getmsgport_reply (c->reply_port, c->reply_port_type,
+ 0, availp->p_msgport);
+ p->p_msgportwait = 0;
+ }
+ else if (p->p_msgcollwait
+ && p->p_continuation.get_collports_c.waitp == availp)
+ check_msgcollwait_wakeup (p);
+}
+
+error_t
+S_proc_setmsgport (struct proc *p,
+ mach_port_t msgport,
+ mach_port_t *oldmsgport)
+{
+ *oldmsgport = p->p_msgport;
+ p->p_msgport = msgport;
+ p->p_deadmsg = 0;
+ if (p->p_checkmsghangs)
+ prociterate (check_message_return, p);
+ p->p_checkmsghangs = 0;
+
+ return 0;
+}
+
+
+/* Check to see if process P is blocked trying to get the message port of
+ process DYINGP; if so, return its call with ESRCH. */
+void
+check_message_dying (struct proc *p, struct proc *dyingp)
+{
+ struct getmsgport_c *c = &p->p_continuation.getmsgport_c;
+
+ if (p->p_msgportwait && c->msgp == dyingp)
+ {
+ proc_getmsgport_reply (c->reply_port, c->reply_port_type, ESRCH,
+ MACH_PORT_NULL);
+ p->p_msgportwait = 0;
+ }
+ else if (p->p_msgcollwait
+ && p->p_continuation.get_collports_c.waitp == dyingp)
+ check_msgcollwait_wakeup (p);
+}
+
+/* Cause a pending proc_getmsgport operation to immediately return */
+void
+abort_getmsgport (struct proc *p)
+{
+ struct getmsgport_c *c = &p->p_continuation.getmsgport_c;
+
+ proc_getmsgport_reply (c->reply_port, c->reply_port_type, EINTR,
+ MACH_PORT_NULL);
+ p->p_msgportwait = 0;
+}
+
+error_t
+S_proc_getmsgport (struct proc *callerp,
+ mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type,
+ int pid,
+ mach_port_t *msgport)
+{
+ struct proc *p = pid_find (pid);
+
+ if (!p)
+ return ESRCH;
+
+ if (p->p_deadmsg)
+ {
+ struct getmsgport_c *c = &callerp->p_continuation.getmsgport_c;
+ c->reply_port = reply_port;
+ c->reply_port_type = reply_port_type;
+ c->msgp = p;
+ p->p_checkmsghangs = 1;
+ callerp->p_msgportwait = 1;
+ return MIG_NO_REPLY;
+ }
+
+ *msgport = p->p_msgport;
+ return 0;
+}
+
+void
+message_port_dead (struct proc *p)
+{
+ mach_port_deallocate (mach_task_self (), p->p_msgport);
+ p->p_msgport = MACH_PORT_NULL;
+ p->p_deadmsg = 1;
+}
+
diff --git a/proc/notify.c b/proc/notify.c
new file mode 100644
index 00000000..664abe9e
--- /dev/null
+++ b/proc/notify.c
@@ -0,0 +1,58 @@
+/* Handle notifications
+ Copyright (C) 1992, 1993, 1994 Free Software Foundation
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell. */
+
+#include <mach.h>
+#include <sys/types.h>
+#include <hurd/hurd_types.h>
+#include <mach/notify.h>
+#include <stdio.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "proc.h"
+#include "notify_S.h"
+
+/* We ask for dead name notifications to detect when tasks and
+ message ports die. Both notifications get sent to the process
+ port. */
+error_t
+do_mach_notify_dead_name (mach_port_t notify,
+ mach_port_t deadport)
+{
+ struct proc *p = reqport_find (notify);
+
+ if (!p)
+ return EOPNOTSUPP;
+
+ if (p->p_reqport == deadport)
+ {
+ message_port_dead (p);
+ return 0;
+ }
+ else if (p->p_task == deadport)
+ {
+ process_has_exited (p);
+ return 0;
+ }
+ else
+ return EINVAL;
+}
diff --git a/proc/pgrp.c b/proc/pgrp.c
new file mode 100644
index 00000000..333dcbb8
--- /dev/null
+++ b/proc/pgrp.c
@@ -0,0 +1,313 @@
+/* Session and process group manipulation
+ Copyright (C) 1992, 1993, 1994 Free Software Foundation
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell. */
+
+#include <mach.h>
+#include <sys/types.h>
+#include <hurd/hurd_types.h>
+#include <sys/errno.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#include "proc.h"
+#include "proc_S.h"
+#include "msg.h"
+
+
+/* Create and return a new process group with pgid PGID in session SESS. */
+static inline struct pgrp *
+new_pgrp (pid_t pgid,
+ struct session *sess)
+{
+ struct pgrp *pg;
+
+ pg = malloc (sizeof (struct pgrp));
+ pg->pg_plist = 0;
+ pg->pg_fakecoll = MACH_PORT_NULL;
+ pg->pg_pgid = pgid;
+ pg->pg_orphcnt = 0;
+
+ pg->pg_session = sess;
+ pg->pg_next = sess->s_pgrps;
+ if (pg->pg_next)
+ pg->pg_next->pg_prevp = &pg->pg_next;
+ sess->s_pgrps = pg;
+ pg->pg_prevp = &sess->s_pgrps;
+
+ add_pgrp_to_hash (pg);
+ return pg;
+}
+
+/* Create and return a new session with session leader P. */
+static inline struct session *
+new_session (struct proc *p)
+{
+ struct session *sess;
+
+ sess = malloc (sizeof (struct session));
+ sess->s_sid = p->p_pid;
+ sess->s_pgrps = 0;
+ sess->s_fakecoll = MACH_PORT_NULL;
+ sess->s_sessionid = MACH_PORT_NULL;
+
+ add_session_to_hash (sess);
+
+ return sess;
+}
+
+/* Free an empty session */
+static inline void
+free_session (struct session *s)
+{
+ if (s->s_fakecoll)
+ mach_port_mod_refs (mach_task_self (), s->s_fakecoll,
+ MACH_PORT_RIGHT_RECEIVE, 1);
+ if (s->s_sessionid)
+ mach_port_mod_refs (mach_task_self (), s->s_sessionid,
+ MACH_PORT_RIGHT_RECEIVE, 1);
+ remove_session_from_hash (s);
+ free (s);
+}
+
+/* Free an empty process group. */
+static inline void
+free_pgrp (struct pgrp *pg)
+{
+ if (pg->pg_fakecoll)
+ mach_port_mod_refs (mach_task_self (), pg->pg_fakecoll,
+ MACH_PORT_RIGHT_RECEIVE, 1);
+ *pg->pg_prevp = pg->pg_next;
+ if (!pg->pg_session->s_pgrps)
+ free_session (pg->pg_session);
+ remove_pgrp_from_hash (pg);
+ free (pg);
+}
+
+/* Implement proc_setsid as described in <hurd/proc.defs>. */
+error_t
+S_proc_setsid (struct proc *p)
+{
+ struct session *sess;
+
+ if (p->p_pgrp->pg_pgid == p->p_pid || pgrp_find (p->p_pid))
+ return EPERM;
+
+ leave_pgrp (p);
+
+ sess = new_session (p);
+ p->p_pgrp= new_pgrp (p->p_pid, sess);
+ join_pgrp (p);
+
+ return 0;
+}
+
+/* Used in bootstrapping to set the pgrp of processes 0 and 1. */
+void
+boot_setsid (struct proc *p)
+{
+ struct session *sess;
+
+ sess = new_session (p);
+ p->p_pgrp = new_pgrp (p->p_pid, sess);
+ join_pgrp (p);
+ return;
+}
+
+/* Implement proc_getsid as described in <hurd/proc.defs>. */
+error_t
+S_proc_getsid (struct proc *callerp,
+ pid_t pid,
+ pid_t *sid)
+{
+ struct proc *p = pid_find (pid);
+ if (!p)
+ return ESRCH;
+
+ *sid = p->p_pgrp->pg_session->s_sid;
+ return 0;
+}
+
+/* Implement proc_getsessionpgids as described in <hurd/proc.defs>. */
+error_t
+S_proc_getsessionpgids (struct proc *callerp,
+ pid_t sid,
+ pid_t **pids,
+ u_int *npidsp)
+{
+ int count;
+ struct pgrp *pg;
+ struct proc *p;
+ struct session *s;
+ pid_t *pp = *pids;
+ u_int npids = *npidsp;
+
+ s = session_find (sid);
+ if (!s)
+ return ESRCH;
+
+ count = 0;
+ for (pg = s->s_pgrps; pg; pg = pg->pg_next)
+ for (p = pg->pg_plist; p; p = p->p_gnext)
+ {
+ if (++count <= npids)
+ *pp++ = p->p_pid;
+ }
+
+ if (count > npids)
+ /* They didn't all fit */
+ {
+ vm_allocate (mach_task_self (), (vm_address_t *)pids,
+ count * sizeof (pid_t), 1);
+ pp = *pids;
+ for (pg = s->s_pgrps; pg; pg = pg->pg_next)
+ for (p = pg->pg_plist; p; p = p->p_gnext)
+ *pp++ = p->p_pid;
+ /* Set dealloc XXX */
+ }
+
+ *npidsp = count;
+ return 0;
+}
+
+/* Implement proc_getsidport as described in <hurd/proc.defs>. */
+error_t
+S_proc_getsidport (struct proc *p,
+ mach_port_t *sessport)
+{
+ if (!p->p_pgrp)
+ *sessport = MACH_PORT_NULL;
+ else
+ {
+ if (!p->p_pgrp->pg_session->s_sessionid)
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
+ &p->p_pgrp->pg_session->s_sessionid);
+ *sessport = p->p_pgrp->pg_session->s_sessionid;
+ }
+ return 0;
+}
+
+/* Implement proc_setpgrp as described in <hurd/proc.defs>. */
+error_t
+S_proc_setpgrp (struct proc *callerp,
+ pid_t pid,
+ pid_t pgid)
+{
+ struct proc *p = pid_find (pid);
+ struct pgrp *pg = pgrp_find (pgid);
+
+ if (!p || (p != callerp && p->p_parent != callerp))
+ return ESRCH;
+
+ if (p->p_parent == callerp && p->p_exec)
+ return EACCES;
+
+ if (p->p_pgrp->pg_session->s_sid == p->p_pid
+ || p->p_pgrp->pg_session != callerp->p_pgrp->pg_session
+ || ((pgid != p->p_pgrp->pg_pgid
+ && (!pg || pg->pg_session != callerp->p_pgrp->pg_session))))
+ return EPERM;
+
+ leave_pgrp (p);
+ p->p_pgrp = pg ? pg : new_pgrp (pgid, p->p_pgrp->pg_session);
+ join_pgrp (p);
+
+ return 0;
+}
+
+/* Implement proc_getpgrp as described in <hurd/proc.defs>. */
+error_t
+S_proc_getpgrp (struct proc *callerp,
+ pid_t pid,
+ pid_t *pgid)
+{
+ struct proc *p = pid_find (pid);
+
+ if (!p)
+ return ESRCH;
+
+ if (p->p_pgrp)
+ *pgid = p->p_pgrp->pg_pgid;
+
+ return 0;
+}
+
+/* Implement proc_mark_exec as described in <hurd/proc.defs>. */
+error_t
+S_proc_mark_exec (struct proc *p)
+{
+ p->p_exec = 1;
+ return 0;
+}
+
+/* Make process P no longer a member of its process group.
+ Note that every process is always a member of some process group;
+ this must be followed by setting P->p_pgrp and then calling
+ join_pgrp. */
+void
+leave_pgrp (struct proc *p)
+{
+ struct pgrp *pg = p->p_pgrp;
+
+ *p->p_gprevp = p->p_gnext;
+
+ /* If we were the last member of our pgrp, free it */
+ if (!pg->pg_plist)
+ free_pgrp (pg);
+ else if (p->p_parent->p_pgrp != pg
+ && p->p_parent->p_pgrp->pg_session == pg->pg_session
+ && !--pg->pg_orphcnt)
+ {
+ /* We were the last process keeping this from being
+ an orphaned process group -- do the orphaning gook */
+ struct proc *ip;
+ int dosignal = 0;
+
+ for (ip = pg->pg_plist; ip; ip = ip->p_gnext)
+ {
+ if (ip->p_stopped)
+ dosignal = 1;
+ nowait_proc_newids (ip->p_msgport, ip->p_task, ip->p_pid,
+ ip->p_parent->p_pid, 1);
+ }
+ if (dosignal)
+ for (ip = pg->pg_plist; ip; ip = ip->p_gnext)
+ {
+ nowait_sig_post (ip->p_msgport, SIGHUP, ip->p_task);
+ nowait_sig_post (ip->p_msgport, SIGCONT, ip->p_task);
+ }
+ }
+}
+
+/* Cause process P to join its process group. */
+void
+join_pgrp (struct proc *p)
+{
+ struct pgrp *pg = p->p_pgrp;
+
+ p->p_gnext = pg->pg_plist;
+ p->p_gprevp = &pg->pg_plist;
+ if (pg->pg_plist)
+ pg->pg_plist->p_gprevp = &p->p_gnext;
+ pg->pg_plist = p;
+
+ if (p->p_parent->p_pgrp != pg
+ && p->p_parent->p_pgrp->pg_session == pg->pg_session)
+ pg->pg_orphcnt++;
+}
diff --git a/proc/proc.h b/proc/proc.h
new file mode 100644
index 00000000..782f2afd
--- /dev/null
+++ b/proc/proc.h
@@ -0,0 +1,184 @@
+/* Process server definitions
+ Copyright (C) 1992, 1993, 1994 Free Software Foundation
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell. */
+
+#ifndef PROC_H_INCLUDED
+#define PROC_H_INCLUDED
+
+
+struct proc
+{
+ mach_port_t p_reqport;
+
+ /* List of members of a process group */
+ struct proc *p_gnext, **p_gprevp; /* process group */
+
+ /* Hash table pointers that point here */
+ void **p_pidhashloc; /* by pid */
+ void **p_taskhashloc; /* by task port */
+ void **p_porthashloc; /* by request port */
+
+ /* Identification of this process */
+ task_t p_task;
+ pid_t p_pid;
+ struct login *p_login;
+ uid_t p_owner;
+ struct ids *p_id;
+
+ /* Process hierarchy */
+ /* Every process is in the process hierarchy except processes
+ 0 and 1. Processes which have not had proc_child called
+ on their behalf are parented by 1. */
+ struct proc *p_parent; /* parent process */
+ struct proc *p_ochild; /* youngest child */
+ struct proc *p_sib, **p_prevsib; /* next youngest sibling */
+
+ /* Process group structure */
+ struct pgrp *p_pgrp;
+
+ /* Communication */
+ mach_port_t p_msgport; /* send right */
+
+ /* Continuations */
+ union
+ {
+ struct wait_c
+ {
+ mach_port_t reply_port;
+ mach_msg_type_name_t reply_port_type;
+ pid_t pid;
+ int options;
+ } wait_c;
+ struct getmsgport_c
+ {
+ mach_port_t reply_port;
+ mach_msg_type_name_t reply_port_type;
+ struct proc *msgp;
+ } getmsgport_c;
+ } p_continuation;
+
+ /* Miscellaneous information */
+ int p_argv, p_envp;
+ int p_status; /* to return via wait */
+
+ int p_exec:1; /* has called proc_mark_exec */
+ int p_stopped:1; /* has called proc_mark_stop */
+ int p_waited:1; /* stop has been reported to parent */
+ int p_exiting:1; /* has called proc_mark_exit */
+ int p_waiting:1; /* blocked in wait */
+ int p_traced:1; /* has called proc_mark_traced */
+ int p_nostopcld:1; /* has called proc_mark_nostopchild */
+ int p_parentset:1; /* has had a parent set with proc_child */
+ int p_deadmsg:1; /* hang on requests for a message port */
+ int p_checkmsghangs:1; /* someone is currently hanging on us */
+ int p_msgportwait:1; /* blocked in getmsgport */
+ int p_noowner:1; /* has no owner known */
+};
+
+typedef struct proc *pstruct_t;
+
+struct pgrp
+{
+ void **pg_hashloc;
+ struct proc *pg_plist; /* member processes */
+ struct pgrp *pg_next, **pg_prevp; /* list of pgrps in session */
+ pid_t pg_pgid;
+ struct session *pg_session;
+ int pg_orphcnt; /* number of non-orphaned processes */
+};
+
+struct session
+{
+ void **s_hashloc;
+ pid_t s_sid;
+ struct pgrp *s_pgrps; /* list of member pgrps */
+ mach_port_t s_sessionid; /* receive right */
+};
+
+struct login
+{
+ int l_refcnt;
+ char l_name[0];
+};
+
+struct ids
+{
+ int i_nuids, i_ngids;
+ uid_t *i_uids;
+ gid_t *i_gids;
+ int i_refcnt;
+};
+
+mach_port_t authserver;
+struct proc *self_proc; /* process 0 (us) */
+struct proc *startup_proc; /* process 1 (init) */
+
+mach_port_t request_portset;
+
+mach_port_t master_host_port;
+mach_port_t master_device_port;
+
+mach_port_t generic_port; /* messages not related to a specific proc */
+
+
+/* Forward declarations */
+void complete_wait (struct proc *, int);
+int nextprime (int);
+int check_uid (struct proc *, uid_t);
+void addalltasks (void);
+void prociterate (void (*)(struct proc *, void *), void *);
+void count_up (void *);
+void store_pid (void *);
+void free_process (struct proc *);
+void panic (char *);
+int valid_task (task_t);
+int genpid ();
+void abort_getmsgport (struct proc *);
+int zombie_check_pid (pid_t);
+void check_message_dying (struct proc *, struct proc *);
+void message_port_dead (struct proc *);
+
+void add_proc_to_hash (struct proc *);
+void remove_proc_from_hash (struct proc *);
+void add_pgrp_to_hash (struct pgrp *);
+void add_session_to_hash (struct session *);
+void remove_session_from_hash (struct session *);
+void remove_pgrp_from_hash (struct pgrp *);
+
+struct proc *pid_find (int);
+struct proc *task_find (task_t);
+struct proc *task_find_nocreate (task_t);
+struct pgrp *pgrp_find (int);
+struct proc *reqport_find (mach_port_t);
+struct session *session_find (pid_t);
+
+struct proc *add_tasks (task_t);
+int pidfree (pid_t);
+
+struct proc *new_proc (task_t);
+
+void leave_pgrp (struct proc *);
+void join_pgrp (struct proc *);
+void boot_setsid (struct proc *);
+
+void process_has_exited (struct proc *);
+void alert_parent (struct proc *);
+void reparent_zombies (struct proc *);
+#endif
diff --git a/proc/wait.c b/proc/wait.c
new file mode 100644
index 00000000..a801c99b
--- /dev/null
+++ b/proc/wait.c
@@ -0,0 +1,314 @@
+/* Implementation of wait
+ Copyright (C) 1994 Free Software Foundation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <mach.h>
+#include <sys/types.h>
+#include <hurd/hurd_types.h>
+#include <sys/resource.h>
+
+#include "proc.h"
+
+#include <signal.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "proc_S.h"
+#include "process_reply.h"
+#include "msg.h"
+#include "interrupt_S.h"
+
+#include <mach/mig_errors.h>
+
+struct zombie
+{
+ struct zombie *next;
+ pid_t pid, pgrp;
+ struct proc *parent;
+ int exit_status;
+ struct rusage ru;
+};
+
+static struct zombie *zombie_list;
+
+/* A process is dying. Check if the parent is waiting for us to exit;
+ if so wake it up, otherwise, enter us as a zombie. */
+void
+alert_parent (struct proc *p)
+{
+ struct zombie *z;
+
+ /* Don't allow init to exit */
+ assert (p->p_parent);
+
+ if (!p->p_exiting)
+ p->p_status = W_EXITCODE (0, SIGKILL);
+
+ if (p->p_parent->p_waiting)
+ {
+ struct wait_c *w = &p->p_parent->p_continuation.wait_c;
+ if (w->pid == p->p_pid || w->pid == -p->p_pgrp->pg_pgid || w->pid == 0)
+ {
+ struct rusage ru;
+
+ bzero (&ru, sizeof (struct rusage));
+ proc_wait_reply (w->reply_port, w->reply_port_type, 0,
+ p->p_status, ru, p->p_pid);
+ p->p_parent->p_waiting = 0;
+ return;
+ }
+ }
+
+ z = malloc (sizeof (struct zombie));
+
+ z->pid = p->p_pid;
+ z->pgrp = p->p_pgrp->pg_pgid;
+ z->parent = p->p_parent;
+ z->exit_status = p->p_status;
+ bzero (&z->ru, sizeof (struct rusage));
+ z->next = zombie_list;
+ zombie_list = z;
+}
+
+/* Process P is exiting. Find all the zombies who claim P as their parent
+ and make them claim startup_proc as their parent; then wake it
+ up if appropriate. */
+void
+reparent_zombies (struct proc *p)
+{
+ struct zombie *z, *prevz;
+ struct wait_c *w = &startup_proc->p_continuation.wait_c;
+ int initwoken = 0;
+
+ for (z = zombie_list, prevz = 0; z; prevz = z, z = z->next)
+ {
+ if (z->parent != p)
+ continue;
+ z->parent = startup_proc;
+
+ if (initwoken || !startup_proc->p_waiting)
+ continue;
+
+ if (w->pid == z->pid || w->pid == -z->pgrp || w->pid == 0)
+ {
+ proc_wait_reply (w->reply_port, w->reply_port_type, 0,
+ z->exit_status, z->ru, z->pid);
+ startup_proc->p_waiting = 0;
+ (prevz ? prevz->next : zombie_list) = z->next;
+ free (z);
+ initwoken = 1;
+ }
+ }
+}
+
+/* Cause the pending wait operation of process P to immediately
+ return. */
+void
+abort_wait (struct proc *p)
+{
+ struct wait_c *w = &p->p_continuation.wait_c;
+ struct rusage ru;
+
+ proc_wait_reply (w->reply_port, w->reply_port_type, EINTR,
+ 0, ru, 0);
+ p->p_waiting = 0;
+}
+
+/* Implement proc_wait as described in <hurd/proc.defs>. */
+error_t
+S_proc_wait (struct proc *p,
+ mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type,
+ pid_t pid,
+ int options,
+ int *status,
+ struct rusage *ru,
+ pid_t *pid_status)
+{
+ struct wait_c *w;
+ struct zombie *z, *prevz;
+
+ for (z = zombie_list, prevz = 0; z; prevz = z, z = z->next)
+ {
+ if (z->parent == p
+ && (pid == z->pid || pid == -z->pgrp || pid == 0))
+ {
+ *status = z->exit_status;
+ bzero (ru, sizeof (struct rusage));
+ *pid_status = z->pid;
+ (prevz ? prevz->next : zombie_list) = z->next;
+ free (z);
+ return 0;
+ }
+ }
+
+ /* See if we can satisfy the request with a stopped
+ child; also check for invalid arguments here. */
+ if (!p->p_ochild)
+ return ESRCH;
+
+ if (pid > 0)
+ {
+ struct proc *child = pid_find (pid);
+ if (!child || child->p_parent != p)
+ return ESRCH;
+ if (child->p_stopped && !child->p_waited
+ && ((options & WUNTRACED) || child->p_traced))
+ {
+ child->p_waited = 1;
+ *status = child->p_status;
+ bzero (ru, sizeof (struct rusage));
+ *pid_status = pid;
+ return 0;
+ }
+ }
+ else
+ {
+ struct proc *child;
+ int had_a_match = !pid;
+
+ for (child = p->p_ochild; child; child = child->p_sib)
+ {
+ if (child->p_pgrp->pg_pgid == -pid)
+ had_a_match = 1;
+ if (child->p_stopped && !child->p_waited
+ && ((options & WUNTRACED) || child->p_traced))
+ {
+ child->p_waited = 1;
+ *status = child->p_status;
+ bzero (ru, sizeof (struct rusage));
+ *pid_status = child->p_pid;
+ return 0;
+ }
+ }
+ if (!had_a_match)
+ return ESRCH;
+ }
+
+ if (options & WNOHANG)
+ return EWOULDBLOCK;
+
+ p->p_waiting = 1;
+ w = &p->p_continuation.wait_c;
+ w->reply_port = reply_port;
+ w->reply_port_type = reply_port_type;
+ w->pid = pid;
+ w->options = options;
+ return MIG_NO_REPLY;
+}
+
+/* Implement proc_mark_stop as described in <hurd/prco.defs>. */
+error_t
+S_proc_mark_stop (struct proc *p,
+ int signo)
+{
+ p->p_stopped = 1;
+ p->p_status = W_STOPCODE (signo);
+ p->p_waited = 0;
+
+ /* Don't allow init to stop */
+ assert (p->p_parent);
+
+ if (p->p_parent->p_waiting)
+ {
+ struct wait_c *w = &p->p_parent->p_continuation.wait_c;
+ if (((w->options & WUNTRACED) || p->p_traced)
+ && (w->pid == p->p_pid || w->pid == p->p_pgrp->pg_pgid
+ || w->pid == 0))
+ {
+ struct rusage ru;
+ bzero (&ru, sizeof (struct rusage));
+ proc_wait_reply (w->reply_port, w->reply_port_type, 0,
+ p->p_status, ru, p->p_pid);
+ p->p_parent->p_waiting = 0;
+ p->p_waited = 1;
+ }
+ }
+
+ if (!p->p_parent->p_nostopcld)
+ nowait_sig_post (p->p_parent->p_msgport, SIGCHLD, p->p_parent->p_task);
+
+ return 0;
+}
+
+/* Implement proc_mark_exit as described in <hurd/proc.defs>. */
+error_t
+S_proc_mark_exit (struct proc *p,
+ int status)
+{
+ if (WIFSTOPPED (status))
+ return EINVAL;
+
+ p->p_exiting = 1;
+ p->p_status = status;
+ return 0;
+}
+
+/* Implement proc_mark_cont as described in <hurd/proc.defs>. */
+error_t
+S_proc_mark_cont (struct proc *p)
+{
+ p->p_stopped = 0;
+ return 0;
+}
+
+/* Implement proc_mark_traced as described in <hurd/proc.defs>. */
+error_t
+S_proc_mark_traced (struct proc *p)
+{
+ p->p_traced = 1;
+ return 0;
+}
+
+/* Implement proc_mark_nostopchild as described in <hurd/proc.defs>. */
+error_t
+S_proc_mark_nostopchild (struct proc *p,
+ int value)
+{
+ p->p_nostopcld = !! value;
+ return 0;
+}
+
+/* Return 1 if pid is in use by a zombie. */
+int
+zombie_check_pid (pid_t pid)
+{
+ struct zombie *z;
+ for (z = zombie_list; z; z = z->next)
+ if (z->pid == pid || -z->pid == pid)
+ return 1;
+ return 0;
+}
+
+/* Implement interrupt_operation as described in <hurd/interrupt.defs>. */
+error_t
+interrupt_operation (mach_port_t object)
+{
+ struct proc *p = reqport_find (object);
+
+ if (!p)
+ return EOPNOTSUPP;
+
+ if (p->p_waiting)
+ abort_wait (p);
+ else if (p->p_msgportwait)
+ abort_getmsgport (p);
+
+ return 0;
+}