diff options
author | Michael I. Bushnell <mib@gnu.org> | 1994-03-22 18:36:52 +0000 |
---|---|---|
committer | Michael I. Bushnell <mib@gnu.org> | 1994-03-22 18:36:52 +0000 |
commit | a2e14dc11cdd72f366a0e0058375ab5a34bc15af (patch) | |
tree | a6e9e84032a8d25715c1981f5baa32b291939247 /proc | |
parent | e6516d3d37826282d434bfd455722c507e7cd417 (diff) |
Initial revision
Diffstat (limited to 'proc')
-rw-r--r-- | proc/Makefile | 71 | ||||
-rw-r--r-- | proc/hash.c | 292 | ||||
-rw-r--r-- | proc/host.c | 204 | ||||
-rw-r--r-- | proc/info.c | 403 | ||||
-rw-r--r-- | proc/main.c | 70 | ||||
-rw-r--r-- | proc/mgt.c | 573 | ||||
-rw-r--r-- | proc/msg.c | 120 | ||||
-rw-r--r-- | proc/notify.c | 58 | ||||
-rw-r--r-- | proc/pgrp.c | 313 | ||||
-rw-r--r-- | proc/proc.h | 184 | ||||
-rw-r--r-- | proc/wait.c | 314 |
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; +} |