aboutsummaryrefslogtreecommitdiff
path: root/proc
diff options
context:
space:
mode:
Diffstat (limited to 'proc')
-rw-r--r--proc/=proc_excrepl.defs37
-rw-r--r--proc/ChangeLog1082
-rw-r--r--proc/Makefile39
-rw-r--r--proc/cpu-types.c163
-rw-r--r--proc/exc-reply.defs36
-rw-r--r--proc/hash.c160
-rw-r--r--proc/host.c408
-rw-r--r--proc/info.c694
-rw-r--r--proc/main.c138
-rw-r--r--proc/mgt.c809
-rw-r--r--proc/msg.c148
-rw-r--r--proc/notify.c105
-rw-r--r--proc/ourmsg.defs12
-rw-r--r--proc/pgrp.c439
-rw-r--r--proc/proc.h222
-rw-r--r--proc/proc_exc.defs48
-rw-r--r--proc/stubs.c136
-rw-r--r--proc/wait.c235
18 files changed, 4911 insertions, 0 deletions
diff --git a/proc/=proc_excrepl.defs b/proc/=proc_excrepl.defs
new file mode 100644
index 00000000..ce78230b
--- /dev/null
+++ b/proc/=proc_excrepl.defs
@@ -0,0 +1,37 @@
+/* Reply side of proc-exc.defs. */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+subsystem proc_excrepl 2500;
+
+#include <mach/std_types.defs>
+
+ServerPrefix S_;
+
+simpleroutine proc_exception_raise_reply (
+ reply: mach_port_send_t;
+ reply_code: int);
diff --git a/proc/ChangeLog b/proc/ChangeLog
new file mode 100644
index 00000000..06db51dd
--- /dev/null
+++ b/proc/ChangeLog
@@ -0,0 +1,1082 @@
+2000-01-23 Roland McGrath <roland@baalperazim.frob.com>
+
+ * info.c (get_string): New arg, pass back length of string.
+ (get_string_array): Use it, rather than repeating strlen.
+ When increasing NEWSIZE to fit, round it to page size.
+ Diddle a few casts to be prettier.
+
+2000-01-06 Roland McGrath <roland@baalperazim.frob.com>
+
+ * primes.c: File removed (long obsolete).
+ * proc.h: Don't declare nextprime.
+
+1999-07-11 Roland McGrath <roland@baalperazim.frob.com>
+
+ * proc.h: Add #include <sys/mman.h>.
+
+1999-07-10 Roland McGrath <roland@baalperazim.frob.com>
+
+ * info.c: Add #include <sys/mman.h> for munmap decl.
+ * mgt.c: Likewise.
+
+1999-07-09 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * info.c (get_string_array): Use mmap instead of vm_allocate.
+ (S_proc_getprocinfo): Likewise.
+ (S_proc_getloginpids): Likewise.
+ * mgt.c (S_proc_getallpids): Likewise.
+ * pgrp.c (S_proc_getsessionpids): Likewise.
+ (S_proc_getsessionpgids): Likewise.
+ (S_proc_getpgrppids): Likewise.
+
+1999-07-03 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * info.c (get_string): Use munmap instead of vm_deallocate.
+ (get_vector): Likewise.
+ (get_string_array): Likewise.
+ (S_proc_getprocinfo): Likewise.
+ * mgt.c (S_proc_reauthenticate): Likewise.
+ (S_proc_dostop): Likewise.
+ (add_tasks): Likewise.
+
+1999-06-19 Roland McGrath <roland@baalperazim.frob.com>
+
+ * main.c (main): Remove commented-out wire_task_self call, #include.
+
+1999-06-05 Roland McGrath <roland@baalperazim.frob.com>
+
+ * mgt.c (create_startup_proc): Don't call add_proc_to_hash here.
+ * main.c (main): Do it here instead, after we have the task port.
+
+1999-06-04 Roland McGrath <roland@baalperazim.frob.com>
+
+ * proc.h (struct proc): Use unsigned int for flag bitfields.
+
+ * mgt.c (allocate_proc, complete_proc): New functions, broken
+ out of new_proc. Remove magic handling of PIDs 0 and 1.
+ (new_proc): Now just call those two. Made static.
+ (create_startup_proc): New function, also broken out of old new_proc.
+ Do special setup for PID 1 (init) proc structure here.
+ * proc.h: Update decls.
+ * main.c (main): Use create_startup_proc for startup_proc, and
+ allocate_proc + complete_proc (with PID 0) for self_proc.
+
+ * mgt.c (make_ids): Add const to arguments.
+
+1999-05-29 Roland McGrath <roland@baalperazim.frob.com>
+
+ * mgt.c (add_tasks): Skip invalid (null) rights in tasks array.
+ * info.c (S_proc_pid2task): Add assert for p_task right validity.
+
+ * main.c: Include <device/device.h>.
+
+1999-05-23 Roland McGrath <roland@baalperazim.frob.com>
+
+ * main.c (main): Set up console on stderr.
+
+1999-05-01 Mark Kettenis <kettenis@gnu.org>
+
+ * msg.c (check_msgport_death): New function.
+ (S_proc_getmsgport): Use it.
+ * proc.h (check_msgport_death): Provide prototype.
+ * info.c (S_proc_getprocinfo): Call check_msgport_death to make
+ sure that our knowledge about P's message port is up to date.
+
+1999-05-02 Roland McGrath <roland@baalperazim.frob.com>
+
+ * main.c: Include <error.h>.
+
+1999-05-01 Roland McGrath <roland@baalperazim.frob.com>
+
+ * main.c (main): Use assert_perror. Give diagnostic for lack of
+ bootstrap port.
+
+1999-03-14 Roland McGrath <roland@baalperazim.frob.com>
+
+ * mgt.c (S_proc_reassign): Remove unused variable FOO.
+
+1999-03-11 Mark Kettenis <kettenis@gnu.org>
+
+ * notify.c (do_mach_notify_dead_name): Remove unnecessary braces.
+
+ * msg.c (S_proc_setmsgport): Remove unused variable FOO.
+ (S_proc_getmsgport): Only check if the message port is still alive
+ if it is not MACH_PORT_NULL. Use mach_port_type instead of
+ mach_port_get_refs to check if the port is dead.
+
+ * mgt.c (S_proc_reassign): Use mach_port_destroy to release the
+ old task port.
+
+Tue Mar 9 13:11:43 1999 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * notify.c (do_mach_notify_dead_name): Don't check against
+ P->p_msgport anymore.
+ * msg.c (message_port_dead): Delete function.
+ (S_proc_setmsgport): Don't request a dead-name notification
+ anymore.
+ (S_proc_getmsgport): Check to see if P->p_msgport is dead before
+ returning it.
+ * mgt.c (S_proc_reassign): Only use mach_port_deallocate to
+ release P->msgport.
+ (process_has_exited): Likewise.
+ * proc.h (message_port_dead): Delete prototype.
+
+ * mgt.c (S_proc_reassign): It's not necessary to re-request the
+ task-death notification; we've moved both the task right and the
+ proc port that gets the notification, so delete that.
+
+ * mgt.c (S_proc_reassign): Use mach_port_destroy instead of
+ mach_port_deallocate to release P->p_msgport, for the same reasons
+ as the changes below.
+
+Sun Mar 7 18:19:07 1999 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * mgt.c (process_has_exited): Use mach_port_destroy instead of
+ mach_port_deallocate to release P->p_msgport.
+ (complete_exit): Likewise for P->p_task.
+ These changes eliminate a race; we are destroying the receiver of
+ the dead-name notifications on these ports, but if that means we
+ lose a notification, then the ref-count on the name will get
+ incremented and we can't re-decrement it since we never hear the
+ notification.
+
+1999-03-06 Mark Kettenis <kettenis@gnu.org>
+
+ * notify.c (do_mach_notify_dead_name): Deallocate reference to
+ DEADPORT.
+
+Sat Feb 20 06:26:17 1999 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * stubs.c (send_signal): Typo in comment.
+
+1998-07-20 Roland McGrath <roland@baalperazim.frob.com>
+
+ * cpu-types.c: Test with #ifdef for CPU_TYPE_I486, CPU_TYPE_PENTIUM,
+ CPU_TYPE_PENTIUMPRO, CPU_TYPE_POWERPC, since not all <mach/machine.h>
+ versions have them.
+
+Tue Sep 16 15:26:04 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * host.c (hostid, hostname, hostnamelen): Delete variables.
+ (S_proc_sethostid, S_proc_gethostid, S_proc_sethostname,
+ S_proc_gethostname): Delete functions.
+
+Wed Aug 20 14:06:46 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * main.c (main): New args for
+ ports_manage_port_operations_multithread.
+
+1997-06-30 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * main.c (main): Arg parsing added. HOLD variable removed.
+ (argp_program_version): New variable.
+ Include <argp.h> and <version.h>.
+
+Thu Jun 26 14:03:16 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * cpu-types.c (mach_cpu_types): Add entries for 486, 586, 686,
+ and powerpc.
+ (mach_cpu_subtypes): Add subtypes for new x86 subtypes. (None
+ added for powerpc yet.)
+
+Mon Feb 3 16:52:14 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * hash.c (pid_find, task_find, task_find_nocreate, reqport_find):
+ Don't dereference P if it's 0.
+
+Fri Oct 25 20:30:22 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * host.c: Include <version.h>.
+
+Thu Oct 24 16:13:40 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * host.c (initialize_version_info): Construct UNAME_INFO.machine
+ with a dash instead of a slash so that it can be used as a file
+ name component.
+
+ * host.c (initialize_version_info): Copy our version into element
+ 0 of server_versions, not element 1. Use HURD_VERSION instead of
+ OUR_VERSION. Use literal "proc" instead of OUR_SERVER_NAME.
+ * proc.h (OUR_SERVER_NAME, OUR_VERSION): Delete macro.
+
+Thu Sep 12 16:33:49 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * Makefile (HURDLIBS): New variable.
+ (proc): Delete special dependency.
+
+Thu Sep 5 10:43:39 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * host.c (struct server_version): Delete member `release'.
+ (kernel_name, kernel_version): New variables.
+ (rebuild_uname): Do the voting on versions, not releases.
+ (initialize_version_info): Store kernel information in kernel_name
+ and kernel_version, not as an entry in the server_versions array.
+ Don't fill in a release for ourselves.
+ (S_proc_register_version): Ignore RELEASE arg.
+
+Sun Jul 28 22:57:03 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * info.c (get_string_array): Correctly adjust NEWSIZE when
+ reallocating to add very long strings.
+
+Sat Jul 20 10:08:05 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * msg.c (S_proc_getmsgport): Deal with PID dying while we're waiting.
+
+Fri Jul 19 18:22:46 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * msg.c (S_proc_setmsgport): Bother to request DEAD_NAME
+ notification on new message port being installed.
+
+Thu Jul 18 13:23:51 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * msg.c (S_proc_setmsgport): Use MOVE_SEND, not COPY_SEND, to
+ return the old message port to the caller.
+
+ * mgt.c (S_proc_handle_exceptions): Release newly created reference
+ on E when we are done with it.
+ (S_proc_child): Deallocate our ref on childt once we know we will
+ return success.
+ (S_proc_reassign): Likewise for NEWT.
+
+ * main.c (main): Don't wire proc anymore. It's not necessary or
+ useful.
+
+Thu Jul 18 04:15:49 1996 Roland McGrath <roland@baalperazim.frob.com>
+
+ * mgt.c (add_tasks): Fix vm_deallocate call to use mach_task_self ()
+ instead of mach_host_self ().
+
+Tue Jul 16 11:34:34 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * wait.c (EWOULDBLOCK): Define to work around new libc bug.
+
+Sun Jul 7 21:04:03 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * mgt.c (S_proc_reauthenticate): Don't use unsafe MOVE_SEND in
+ user-side interruptible RPC.
+
+Wed Jul 3 14:44:00 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * mgt.c (process_has_exited): When reparenting children to init,
+ if one of them is dead, alert init.
+
+Fri Jun 28 11:54:21 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * proc.h (check_owner): Return true any time PROC1 has root.
+
+Thu May 30 19:11:31 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * pgrp.c (S_proc_getsidport): MAKE_SEND_ONCE -> MAKE_SEND.
+
+Wed May 29 11:35:37 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * info.c (S_proc_getprocinfo): Get rid of temp hack for strnlen.
+
+Fri May 24 15:50:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * info.c (S_proc_getprocinfo): Set PI->exitstatus and PI->sigcode.
+
+ * mgt.c (process_has_exited): Don't call alert_parent if P->p_task
+ is null (which happens only if this is the stub process in
+ proc_reassign). This because the parent is uninvolved in the
+ death of stubp.
+
+Wed May 22 17:47:15 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * stubs.c (send_signal): Send sigcode in message.
+
+ * msg.c (S_proc_setmsgport): Add OLDMSGPORT_TYPE param.
+
+Tue May 14 22:50:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * proc.h (check_owner): New inline function.
+ * info.c (S_proc_pid2task, S_proc_pid2proc): Use check_owner.
+
+Sun May 12 13:22:04 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * info.c (PI_FETCH_THREAD_DETAILS): New macro.
+ (S_proc_getprocinfo): Only allocate thread detail storage if we're
+ actually returning thread details (a lone PI_FETCH_THREADS simply
+ means "number of threads"). React to errors somewhat more gracefully.
+
+ * info.c (S_proc_getprocinfo): Add comment.
+
+Fri May 10 16:32:17 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * info.c (S_proc_get_tty): New function.
+
+Fri May 10 09:26:53 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * mgt.c (S_proc_exception_raise): Fetch sigcode from correctly
+ named member of HSD.
+
+Thu May 9 19:13:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * mgt.c (S_proc_reauthenticate): Use new authentication
+ interface.
+
+ * mgt.c (S_proc_setowner): Expect and interpret new CLEAR parm.
+
+ * info.c (S_proc_getprocinfo): FLAGS is now an in-out parameter.
+
+ * proc.h (struct proc): Add p_sigcode.
+ * wait.c (S_proc_wait): New parm SIGCODE; return p_sigcode in it.
+ (S_proc_mark_stop): New parm SIGCODE; record it.
+ (S_proc_mark_exit): Likewise.
+ (alert_parent): Set P->p_sigcode if process is dying irregularly.
+ * mgt.c (S_proc_exception_raise): Set P->p_sigcode; use new
+ _hurd_exception2signal args.
+
+Mon May 6 14:23:11 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * proc.h (OUR_VERSION): Upgrade to 0.0.
+
+Tue Apr 30 16:48:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * info.c (S_proc_getprocinfo): Release GLOBAL_LOCK around time
+ consuming bits, and more importantly, potential calls to P's
+ msgport, which can block.
+ Fix test when appending to WAITS.
+
+Mon Apr 29 16:58:24 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * info.c (S_proc_getprocinfo): Install temporary hack so things at
+ least compile. Turned on thread_waits code.
+
+Mon Apr 15 13:51:41 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * mgt.c (process_has_exited): Clear p->p_waited.
+
+Fri Mar 29 09:38:28 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * wait.c (S_proc_wait): When looking for a specific pid, use
+ pid_find_allow_zombie, not ordinary pid_find.
+
+ * mgt.c (S_proc_reassign): Use new ports_transfer_right call
+ instead of claim/install sequence; the latter has leaves the port
+ out of any hash table for a time, which produces a race with
+ incoming messages.
+
+Thu Mar 28 09:21:16 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * mgt.c (S_proc_reassign): Make send once right directly from
+ value in P->p_pi, don't use ports_get_right.
+
+ * mgt.c (process_has_exited): Inhibit this call from happening
+ twice.
+
+ * info.c (S_proc_pid2task): Return MACH_PORT_NULL for a zombie.
+ (S_proc_pid2proc): Likewise.
+
+ * Makefile (mutated_ourmsg_U.h): New target.
+ * mgt.c: Include mutated_ourmsg_U.h instead of ourmsg_U.h.
+ * pgrp.c: Likewise.
+
+ * wait.c: Don't include ourmsg_U.h or process_reply_U.h.
+ * msg.c: Don't include process_reply_U.h.
+
+ * msg.c (S_proc_getmsgport): Allow call to be made for dead
+ processes; they'll return null. Thank you, Mr. Posix.
+ * mgt.c (process_has_exited): Null out P->p_msgport and drop
+ reference.
+
+ * wait.c (S_proc_wait): Return EOPNOTSUPP if RPC destination is
+ not a valid process.
+ (S_proc_mark_stop): Likewise.
+ (S_proc_mark_exit): Likewise.
+ (S_proc_mark_cont): Likewise.
+ (S_proc_mark_traced): Likewise.
+ (S_proc_mod_stopchild): Likewise.
+ * msg.c (S_proc_setmsgport): Likewise.
+ (S_proc_getmsgport): Likewise.
+ * pgrp.c (S_proc_setsid): Likewise.
+ (S_proc_getsidport): Likewise.
+ (S_proc_setpgrp): Likewise.
+ (S_proc_mark_exec): Likewise.
+ * mgt.c (S_proc_reauthenticate): Likewise.
+ (S_proc_child): Likewise.
+ (S_proc_reassign): Likewise.
+ (S_proc_setowner): Likewise.
+ (S_proc_getpids): Likewise.
+ (S_proc_set_arg_locations): Likewise.
+ (S_proc_dostop): Likewise.
+ * info.c (S_proc_pid2task): Likewise.
+ (S_proc_proc2task): Likewise.
+ (S_proc_pid2proc): Likewise.
+ (S_proc_make_login_coll): Likewise.
+ (S_proc_setlogin): Likewise.
+ (S_proc_getlogin): Likewise.
+ * host.c (S_proc_sethostid): Likewise.
+ (S_proc_sethostname): Likewise.
+ (S_proc_getprivports): Likewise.
+ (S_proc_setexecdata): Likewise.
+
+ * proc.h (process_drop): New (inline) function.
+ * hash.c (reqport_find): Only deallocate newly found reference
+ if process is dead.
+ * Makefile (MIGSTUBS): Delete process_replyUser.c.
+ (MIGSFLAGS): Provide new definition.
+ * msg.c (S_proc_setmsgport): Spawn thread to tickle init instead
+ of sending reply here.
+ (tickle_init): New function.
+
+Mon Mar 25 17:02:04 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * Makefile (proc): Add libshouldbeinlibc.a.
+ * main.c: Include <wire.h>.
+ (main): Use wire_task_self instead of doing it ourselves.
+
+Thu Mar 21 11:59:29 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * wait.c (S_proc_wait) [child_ready]: Flip test of waited flag.
+ * mgt.c (new_proc): Oops, reinstall code to request dead name
+ notification on the task port.
+
+Wed Mar 20 10:41:01 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * pgrp.c (S_proc_setpgrp): Delete bletcherous hack from July 22,
+ 1995.
+
+ -- All these changes get rid of zombies and integrate them
+ into the regular process tables. --
+ * proc.h (struct zombie): Delete type.
+ (zombie_list): Delete variable.
+ * hash.c (pid_find): Return 0 if process is dead.
+ (task_find): Likewise.
+ (task_find_nocreate): Likewise.
+ (pidfree): Don't call zombie_check_pid. Call
+ pid_find_allow_zombie instead of pid_find.
+ (pid_find_allow_zombie): New function.
+ (prociterate): Don't call FUN for dead processes.
+ * mgt.c (new_proc): Initialize P->p_dead.
+ (process_has_exited): Don't call reparent_zombies. Set P->p_dead.
+ Don't remove from hash tables here, delete ref to task port or
+ remove from parent's list of children (now in
+ complete_exit). Don't remove from pgrp here.
+ (complete_exit): New function.
+ * wait.c (alert_parent): Don't create zombie.
+ (reparent_zombies): Delete function.
+ (S_proc_wait): Don't scan zombie list; check dead children at the
+ same time as stopped children. When completing wait on a dead
+ child, call complete_exit after we've finished work.
+ (zombie_check_pid): Delete function.
+ * proc.h (complete_exit): Provide prototype.
+
+ -- All these changes make proc multithreaded
+ and use the ports library in the usual fashion
+ (well, almost the usual fashion) --
+ * Makefile (proc): Mention ../libports/libports.a.
+ * hash.c (porthash, exchash): Delete variables.
+ (reqport_find): Use ports library instead of porthash.
+ (add_proc_to_hash): Don't add to porthash.
+ (remove_proc_from_hash): Don't remove from porthash.
+ (exc_find, remove_exc_from_hash): Delete functions.
+ * mgt.c (new_proc): Allocate new proc structure with
+ ports_create_port. Don't frob P->p_reqport.
+ (process_has_exited): Don't frob P->p_reqport, cal
+ ports_destry_right instead.
+ * proc.h (proc_bucket, proc_class): New variables.
+ (request_portset): Delete variable.
+ * proc.h (struct proc): Delete members `p_reqport' and
+ p_porthashloc. Add member `p_pi'.
+ * Makefile (MIGSFLAGS): Delete variable.
+ * proc.h (global_lock): New variable.
+ * main.c (global_lock): Provide definition.
+ (message_demuxer): Lock global_lock around work.
+ (main): Initialize proc_bucket and proc_class instead of
+ request_portset. Initialize generic_port through ports
+ library calls. Fetch startup procserver port through ports
+ library instead of reading p_reqport. Initialize exc_class.
+ * mgt.c (S_proc_reauthenticate) Likewise.
+
+ * proc.h: Include <hurd/ports.h> and <cthreads.h>.
+ * info.c (S_proc_task2proc): Use ports_get_right instead
+ of p_reqport.
+ (S_proc_pid2proc): Likewise.
+ * proc.h (exc_port_class): New variable.
+ (struct exc): Add member `pi'. Remove member `excport'.
+ * mgt.c (S_proc_handle_exceptions): Allocate using
+ ports library.
+ (S_proc_exception_raise): Use ports library to manage
+ structure.
+ (exc_clean): New function.
+
+
+***
+
+ -- All these changes switch to using condition variables
+ for wakeup instead of explicit block code --
+ * mgt.c (new_proc): Initialize P->p_wakeup.
+ * wait.c (waiting_parent_cares): Delete function.
+ * Makefile (MIGSTUBS): Delete interruptServer.o.
+ * main.c (message_demuxer): Remove call to interrupt_server.
+ Add call to ports_interrupt_server.
+ * wait.c: Don't include "interrupt_S.h".
+ (alent_parent): Unconditionally enqueue zombie.
+ (S_interrupt_operation): Delete function.
+ (abort_wait): Delete function.
+ * msg.c (abort_getmsgport): Delete function.
+ * wait.c (alert_parent): Use condition_broadcast instead of
+ continuation stuff.
+ (reparent_zombies): Likewise.
+ (S_proc_mark_stop): Likewise.
+ * msg.c (check_message_return): Likewise.
+ (check_message_dying): Likewise.
+ * wait.c (S_proc_wait): Use condition_wait instead of continuation
+ stuff; never return EBUSY.
+ * msg.c (S_proc_getmsgport): Likewise.
+ * proc.h (struct proc): New member `p_wakeup'. Delete member
+ `p_continuation'.
+
+
+
+Mon Feb 12 14:13:55 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * info.c (S_proc_getprocinfo): Fail reasonably for #ifdef'd-out
+ thread waits code.
+
+Fri Feb 9 15:45:07 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * info.c (S_proc_getprocinfo): Support returning wait strings.
+
+Fri Feb 9 15:19:14 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * mgt.c (S_proc_exception_raise): Rewritten.
+ (S_proc_handle_exceptions): Don't set E->replyport.
+ (S_proc_exception_raise_reply): Function removed.
+ * main.c (message_demuxer): Don't call proc_excrepl_server.
+ * proc_excrepl.defs: File removed.
+ * Makefile (DIST_FILES): Remove proc_excrepl.defs.
+ (MIGSTUBS): Remove its objects.
+ * proc_exc.defs: Add msgoption arg.
+ Use integer_t where appropriate.
+ * notify.c (do_mach_notify_no_senders): Don't use E->replyport.
+ * proc.h (struct exc): Removed useless members `replyport',
+ `replyporttype'.
+
+Wed Dec 20 17:29:13 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * mgt.c (S_proc_reassign): Have notifications sent to the correct
+ request port.
+ Once we've given STUBP's request port to P, don't leave it in
+ STUBP, so process_has_exited() doesn't dealloc it.
+
+ * pgrp.c (S_proc_getsidport): Add and use new arg sessport_type.
+
+Wed Dec 20 13:31:01 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * mgt.c (new_proc): Don't set P->p_noowner for processes 0 and 1.
+
+Wed Dec 20 13:09:04 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * info.c (get_vector): Rewritten without arbitrary limits.
+
+Tue Dec 19 18:14:30 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * pgrp.c (free_session): Correctly get rid of the receive right
+ we're holding.
+ (S_proc_getsidport): Return errors.
+
+Tue Dec 19 13:58:59 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * info.c (get_string_array): Fix stupid bug in copying to newly
+ allocated space.
+
+Tue Dec 19 13:17:46 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * mgt.c (S_proc_reauthenticate): Reverse miles' last change.
+
+Mon Dec 18 19:56:03 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * mgt.c (S_proc_reauthenticate): Don't return 0 for the new port.
+
+Tue Nov 21 13:50:30 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * wait.c (S_interrupt_operation): Include new seqno parameter.
+
+Tue Nov 14 13:15:55 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * wait.c (S_proc_wait): `p->msgportwait' ==> `p->p_msgportwait'
+ typo fix.
+
+Thu Nov 9 13:01:28 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * msg.c (S_proc_setmsgport): Only do the RPC reply by hand for
+ init. Also, return the correct port in that by-hand reply.
+
+ * msg.c (S_proc_getmsgport): Also return EBUSY if P->waiting,
+ because both share the same memory in the proc structure.
+ * wait.c (S_proc_wait): Likewise, mutatis mutandis.
+
+Wed Nov 8 13:10:27 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * info.c (S_proc_getprocinfo): Don't attempt msg_report_wait if
+ P->p_msgport is not valid.
+
+ * info.c (S_proc_getprocinfo): Inhibit PI_FETCH_THREAD_WAITS for
+ now.
+
+Tue Nov 7 19:49:32 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * info.c (S_proc_getprocinfo): Calculate the size of the returned
+ structure correctly.
+
+Sun Nov 5 02:05:10 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * proc.h: Include <sys/resource.h>.
+
+ * info.c (S_proc_getprocinfo): Add NOISE and NOISE_LEN args.
+ Fix various typos. Initialize ERR.
+
+Tue Oct 31 14:19:04 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * wait.c (struct zombie): Deleted; now in proc.h.
+ (zombie_list): Likewise.
+ * proc.h (struct zombie): New type.
+ (zombie_list): New variable.
+
+ * info.c (S_proc_getprocinfo): Implement all the rest of the PI
+ flags except PI_ZOMBIE.
+
+Mon Oct 30 16:22:49 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * info.c (S_proc_getprocinfo): Support new FETCH flags; support
+ new msg_report_wait call; improve organization.
+
+ * info.c (S_proc_getprocenv): Removed #ifdef notyet; fixed args to
+ get_string_array.
+
+Sat Sep 16 12:57:31 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * ourmsg.defs: New file.
+ * Makefile (DIST_FILES): Added ourmsg.defs.
+ (ourmsg_U.h ourmsgUser.c, ourmsg.defs): Targets removed.
+
+Thu Aug 24 10:38:58 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * Makefile (MIGSTUBS): New variable.
+ (OBJS): Get the mig stubs from $(MIGSTUBS).
+
+Wed Aug 23 14:25:30 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * Makefile (proc): Put all dependencies here.
+ (HURDLIBS, REMHDRS): Removed.
+ (OBJS): Calculate the appropiate bits from $(SRCS).
+
+Sat Jul 22 15:04:52 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * wait.c (zombie_check_pid): Examine Z->pgrp too.
+
+ * pgrp.c (S_proc_setpgrp): Install bletcherous hack.
+
+Thu Jul 6 15:41:22 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
+
+ * hash.c: "ihash.h" -> <hurd/ihash.h>.
+
+ * Makefile (ourmsg_U.h ourmsgUser.c): Use local ourmsg.defs
+ instead of include file directly.
+ (ourmsg.defs): New target.
+
+ * Makefile: Removed dependencies that are now automatically
+ generated.
+
+Tue Jun 27 12:02:47 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
+
+ * mgt.c (S_proc_dostop): Remove assigments from inside if tests.
+
+Tue Jun 6 13:24:51 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
+
+ * Makefile (OBJS): Removed ihash.o and primes.o.
+ (CPPFLAGS): Deleted addition of -I../lib.
+ (vpath): Deleted spec.
+ (REMHDRS): Added ../libihash/ihash.h.
+ (HURDLIBS): Added libihash.
+
+Wed Apr 26 14:32:19 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
+
+ * wait.c (S_proc_wait): Use `waiter_cares', not
+ `waiting_parent_cares' in zombie check.
+
+Tue Apr 18 09:30:13 1995 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
+
+ * wait.c (reparent_zombies): Send SIGCHLD signal to init.
+
+ * wait.c (S_proc_wait): Don't return ESRCH; return ECHILD.
+
+Wed Apr 12 14:36:30 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
+
+ * Makefile (SRCS): Omit primes.c (it's moved to the lib dir).
+
+Thu Apr 6 14:29:06 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * info.c (S_proc_getprocinfo): New var `tp'. Bother to set
+ PI->logincollection.
+
+Wed Apr 5 20:32:02 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * wait.c (waiter_cares, waiting_parent_cares): New functions.
+ (alert_parent, reparent_zombies, S_proc_wait, S_proc_mark_stop):
+ Use them.
+
+Tue Apr 4 14:36:36 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * main.c (main): Wire text and data segment on startup to avoid
+ failure mode during non-standalone pseudo-crash.
+
+Tue Mar 14 11:55:00 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
+
+ * hash.c (addhash, findhash): Moved to ihash.c (which is has a more
+ generic interface) and renamed ihash_add & ihash_find; all callers
+ changed. Other changes: struct htable becomes struct ihash, and
+ all routines that previously deleted things explicitly use
+ ihash_locp_remove instead.
+
+Thu Jan 19 02:01:14 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * pgrp.c (S_proc_setpgrp): Use nowait_msg_proc_newids instead of
+ nowait_proc_newids.
+ * mgt.c (S_proc_child): Likewise.
+
+Tue Jan 17 17:48:32 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * mgt.c (check_uid): Return true if P has root.
+
+ * proc.h (struct proc): Make `argv' and `envp' members
+ `vm_address_t'.
+
+Thu Nov 3 12:13:49 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * mgt.c (S_proc_getallpids): Don't dereference PIDS in call
+ to vm_allocate.
+
+ * info.c (S_proc_getprocinfo): Don't take address of PIARRAY
+ in call to vm_allocate. Dereference PIARRAY in call to
+ vm_deallocate.
+
+Fri Oct 14 04:54:46 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * mgt.c (new_proc): Don't assume MACH_PORT_NULL is zero.
+ (genpid): Deal with all pids between STAR_OVER and WRAP_AROUND
+ being used.
+
+Mon Oct 10 14:23:00 1994 Jim Blandy <jimb@geech.gnu.ai.mit.edu>
+
+ * primes.c (nextprime): Doc fix.
+
+Mon Oct 10 02:18:02 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * host.c (rebuild_uname): If all the server versions after [0]
+ (the microkernel) match, merge them all into one "Hurd-VERSION"
+ element in the uname version string.
+
+Sun Oct 2 20:36:57 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * host.c (S_proc_sethostname): Don't write off end of
+ uname_info.nodename.
+ (rebuild_uname): Rewritten.
+ (initialize_version_info): Write Mach version info as first
+ element of server_versions.
+ (machversion): Variable removed.
+
+Sat Sep 10 11:37:32 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * mgt.c (make_ids): Copy from UIDS and GIDS into newly allocated
+ space, not vice versa.
+
+Wed Aug 31 11:03:13 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * mgt.c (S_proc_reassign): Rather than getting a new request port,
+ preserve STUBP's request port. This is more convenient for
+ users (and equally good security), and it's what the protocol spec
+ says anyway.
+
+Tue Aug 30 12:44:37 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * primes.c: Replaced file with new version from Jim Blandy
+ (jimb@gnu.ai.mit.edu), David Carlton (carlton@math.mit.edu).
+
+ * proc.h (check_dead_execdata_notify): Add prototype.
+
+Mon Aug 29 12:53:27 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * mgt.c (S_proc_reauthenticate): Use new authentication protocol.
+
+Tue Aug 23 11:41:26 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * pgrp.c (S_proc_setpgrp): If we don't actually change the pgrp,
+ still send proc_newids; the library depends on always getting it.
+
+Mon Aug 22 17:09:21 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * wait.c (S_proc_mark_stop): Removed now meaningless assert.
+
+ * info.c (S_proc_getloginpids): Compute size in realloc correctly.
+
+Mon Aug 22 13:29:21 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * wait.c (S_proc_mod_stopchild): Negate VALUE; sense of
+ p_nostopcld flag is opposite of flag value described in process.defs.
+
+Fri Aug 19 10:21:57 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * pgrp.c (S_proc_getpgrppids): Understand PGID of zero as meaning
+ caller's pgrp.
+
+ * mgt.c (S_proc_child): Check CHILDP->p_msgport against
+ MACH_PORT_NULL explicitly.
+
+ * pgrp.c (join_pgrp): If pg->pg_orphcnt has significantly changed,
+ then notify all the processes in the pgrp.
+ (leave_pgrp): Only send newids message if ip->p_msgport is set.
+ * mgt.c (S_proc_child): Becase join_pgrp now always sends
+ newids; don't do it here if we called join_pgrp.
+
+Fri Aug 19 04:53:04 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+
+ * pgrp.c (leave_pgrp): Fix swapped args to nowait_proc_newids.
+ (join_pgrp): Call nowait_proc_newids to notify the process.
+
+Thu Aug 18 10:40:13 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * mgt.c (S_proc_reauthenticate): Use MACH_MSG_TYPE_MAKE_SEND
+ to create a send right from P->p_reqport.
+
+ * main.c (main): Removed var `authhandle'. Use global
+ `authserver' instead.
+
+Wed Aug 17 14:02:31 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * host.c (init_stdarrays): Removed function.
+ (S_proc_execdata_notify): Never call init_stdarrays.
+ Only call exec_setexecdata if std_port_array is set.
+ (S_proc_getexecdata): Return error if there is no std_port_array.
+
+Mon Aug 15 16:12:22 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * host.c (check_dead_execdata_notify): New function.
+ * notify.c (do_mach_notify_dead_name): For notifications sent
+ to GENERIC_PORT, call check_dead_execdata_notify.
+ * main.c (main): Create GENERIC_PORT and put it in
+ REQUEST_PORTSET.
+
+ * host.c (init_stdarrays): New function.
+ (S_proc_execdata_notify): Call init_stdarrays the first time.
+ (S_proc_getexecdata): Likewise.
+
+ * host.c: Include <hurd.h> for various frobs. Include
+ <unistd.h> for getpid.
+
+Fri Jul 22 11:01:53 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * Makefile: Rewritten in accord with new scheme.
+ * wait.c: Include "ourmsg_U.h" instead of "msg.h".
+ Include "process_reply_U.h" instead of "process_reply.h".
+ Include "process_S.h" instead of "proc_S.h".
+ * mgt.c: Include "proc_exc_U.h" instead of "proc_exc.h".
+ Include "proc_excrepl_U.h" insted of "proc_excrepl.h".
+ Include "ourmsg_U.h" instead of "msg.h".
+ Include "process_S.h" instead of "proc_S.h".
+ * pgrp.c: Include "process_S.h" instead of "proc_S.h".
+ Include "ourmsg_U.h" instead of "msg.h".
+ * msg.c: Include "process_reply_U.h" instead of "process_reply.h".
+ * host.c: Include "process_S.h" instead of "proc_S.h".
+ * info.c: Likewise.
+
+Wed Jul 20 16:18:31 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * wait.c (alert_parent): Delete unused variable `err'.
+
+Tue Jul 19 12:45:43 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
+
+ * Makefile (proc): Don't use variable $(link) anymore.
+
+Mon Jul 11 14:32:17 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
+
+ * pgrp.c (leave_pgrp): When pulling process off of pgrp list,
+ mutate *both* links.
+ (free_pgrp): When pulling pgrp off of session list, mutate
+ *both* links.
+
+Tue Jul 5 14:23:21 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
+
+ * Makefile (TAGSLIBS, TAGSHDRS): New variables.
+
+Fri Jul 1 10:57:07 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
+
+ * stubs.c (send_signal): Rewrote to be machine independent
+ and cleaner.
+
+Thu Jun 30 14:05:21 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
+
+ * stubs.c: New file.
+ * wait.c (alert_parent): Call send_signal instead of nowait_sig_post.
+ (S_proc_mark_stop): Likewise.
+ * pgrp.c (leave_pgrp): Likewise.
+ * proc.h (send_signal): New prototype.
+ * Makefile (OBJS): Added stubs.o.
+ (SRCS): Added stubs.c.
+ (LIBS): New var to get cthreads library.
+
+ * wait.c (alert_parent): Eliminate pointless assert with confusingly
+ incorrect comment.
+
+ * hash.c (findhash): If we find a slot with ID matching the
+ one we're looking for, but it has been deleted, then return
+ 0 rather than HASH_DEL.
+
+ * wait.c (S_proc_wait, reparent_zombies, alert_parent): Use
+ macros WAIT_ANY and WAIT_MYPGRP instead of magic values -1
+ and 0.
+
+ * wait.c (S_proc_wait): Implement correct interpretation of PID
+ argument: -1 means any child; 0 means child in the same pgrp.
+ [Incorrect semantics were in loop to search zombies, and loop
+ looking for stopped children]
+ (reparent_zombies): Likewise. [Incorrect semantics were in
+ PID check before returning startup_proc's wait.]
+ (alert_parent): Likewise. [Incorrect semantics were in
+ PID check before returning P->p_parent's wait.]
+
+ * wait.c (S_proc_wait): Only return wait on stopped child if
+ it passes the PID test.
+
+ * pgrp.c (S_proc_setpgrp): Don't do process group change if we are
+ changing into our own process group.
+ * mgt.c (S_proc_child): Likewise.
+
+ * pgrp.c (S_proc_setpgrp): When PID is zero, act on calling
+ process; when PGID is zero, use pid of affected process.
+ (S_proc_setpgrp): EPERM check should succeed if pgid is the
+ affected process's *pid*, not pgrp.
+
+Thu Jun 30 08:40:35 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
+
+ * mgt.c (S_proc_dostop): Use the proper allocation for task_threads.
+ Check for errors. Deallocate the send right from CONTTHREAD too.
+
+ * wait.c (alert_parent): Send SIGCHLD to the parent.
+
+Tue Jun 28 18:12:43 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
+
+ * primes.c: Include <assert.h>.
+ (nextprime): Use calloc instead of alloca, bzero. P might be
+ bigger than will fit on the stack. Assert non-null return
+ from calloc and realloc.
+
+Tue Jun 28 13:57:08 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
+
+ * main.c (main): Set priority of proc server to 2 so that we
+ get more CPU than ordinary programs.
+
+Fri Jun 24 17:29:55 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
+
+ * hash.c (struct htable): New member `locps'.
+ (addhash): Store LOCP into hash table for use during rehash.
+ During rehash, then provide correct LOCP parm for old elements.
+ Allocate and free HT->locps as appropriate.
+
+Fri Jun 24 04:15:16 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
+
+ * mgt.c (S_proc_setprocargs): Renamed to S_proc_set_arg_locations.
+ (S_proc_get_arg_locations): New function.
+
+Mon Jun 20 15:07:00 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
+
+ * Makefile (install): Use $(INSTALL_BIN) instead of cp.
+
+Fri Jun 17 13:00:27 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
+
+ * mgt.c (S_proc_child): Reverse Roland's change of June 11.
+
+Sat Jun 11 11:20:16 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu)
+
+ * mgt.c (S_proc_child): Inherit the argv and envp values from the
+ parent.
+
+Fri May 27 16:03:53 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
+
+ * primes.c: Doc fix, with appreciation to Jim Blandy.
+
+Fri May 13 16:58:13 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu)
+
+ * info.c (S_proc_getprocinfo): Only scan through the threads
+ if task_info succeeds.
+
+ * info.c (S_proc_getprocinfo): Behave properly if one of the
+ threads has died in between the call to task_threads and the
+ calls to thread_info (just pretend it never existed).
+
+ * info.c (get_string, get_vector, S_proc_getprocinfo): If the task
+ has died (there's a race between pending requests and processing
+ of dead-name notifications) then convert MACH_SEND_INVALID_DEST to
+ ESRCH.
+
+Thu May 12 00:59:03 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
+
+ * main.c (main): Take three args. Store ARGV and ENVP in SELF_PROC.
+
+ * info.c (S_proc_getprocargs): Remove `#ifdef notyet's.
+ (get_string, get_vector, get_string_array): Functions exposed.
+ (get_string_array): Set BP before the loop. Use a for loop that
+ iterates over elts in VECTOR. Fix check of LEN to reallocate buffer.
+ (S_proc_getprocargs): Cast BUF to vm_address_t * for get_string_array.
+ (get_vector): Fix pointer arithmetic; break out of loop when done.
+ Check for error from malloc.
+ (get_string): Use memchr for scanning. Check for error from
+ malloc. Pass READLEN correctly to vm_deallocate.
+
+ * msg.c (S_proc_setmsgport): Take new reply port args.
+ Send reply before trying startup_essential_task.
+ Include <hurd/startup.h> to declare startup_essential_task.
+
+ * cpu-types.c: New file.
+ * Makefile (SRCS, OBJS): Add it.
+ * host.c: Include <stdio.h> for sprintf.
+ (rebuild_uname): Removed unused variable J.
+ (S_proc_register_version): Fix arg types.
+ Use master_host_port, not host_priv.
+ Remove unused variable J.
+ (server_versions): Fix syntax errors in struct definition.
+ (S_proc_uname): Fixed type of first arg.
+ (rebuild_uname): Fix typo.
+ (initialize_version_info): Cast args to host_info.
+ (initialize_version_info): Allocate space for machversion.
+
+Mon May 9 14:32:37 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
+
+ * mgt.c (new_proc): Regard init as having a dead message
+ port initially.
+
+ * msg.c (S_proc_setmsgport): When init chimes in, tell it
+ we are essential.
+
+ * proc.h (OUR_VERSION, OUR_SERVER_NAME): New macros.
+ * host.c (uname_info, machversion, server_versions,
+ nserver_versions, server_version_nalloc): New variables.
+ (S_proc_register_version, rebuild_uname, initialize_version_info,
+ S_proc_uname): New functions.
+ (S_proc_sethostname): Also set uname_info.nodename.
+ * main.c (main): Call initialize_version_info.
+
+Fri May 6 13:00:36 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu)
+
+ * host.c (S_proc_gethostname): If HOSTNAME is null, return
+ an empty hostname instead of crashing.
+ (S_proc_gethostname): Test buffer length properly; allocate
+ space for the null too.
+
+ * mgt.c (process_has_exited): delete unused variable LAST.
+ * msg.c (check_message_return): delete unused variables I,
+ MSGPORTS, and CP. Changed type of second arg to `void *'
+ so that the function type is appropriate for the first arg
+ to prociterate.
+ (check_message_dying): delete unused variable I.
+
+ * wait.c, host.c, info.c, mgt.c, notify.c, pgrp.c: Changed MiG
+ server stubs' return types from error_t to kern_return_t; the
+ types are incompatible right now.
+
+Thu May 5 07:50:24 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu)
+
+ * Makefile: Change uses of $(headers) to $(includedir).
diff --git a/proc/Makefile b/proc/Makefile
new file mode 100644
index 00000000..a1159700
--- /dev/null
+++ b/proc/Makefile
@@ -0,0 +1,39 @@
+# Copyright (C) 1992, 1993, 1994, 1995, 1996 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
+makemode := server
+
+target = proc
+SRCS = wait.c hash.c host.c info.c main.c mgt.c notify.c pgrp.c msg.c \
+ cpu-types.c stubs.c
+LCLHDRS = proc.h
+DIST_FILES = proc_exc.defs ourmsg.defs
+
+MIGSFLAGS="-DPROCESS_INTRAN=pstruct_t reqport_find (process_t)" \
+ "-DPROCESS_DESTRUCTOR=process_drop (pstruct_t)" \
+ "-DPROCESS_IMPORTS=import \"proc.h\";"
+
+MIGSTUBS = processServer.o notifyServer.o \
+ ourmsgUser.o proc_excUser.o proc_excServer.o
+OBJS = $(SRCS:.c=.o) $(MIGSTUBS)
+HURDLIBS=threads ihash ports shouldbeinlibc
+
+include ../Makeconf
+
+mutated_ourmsg_U.h: ourmsg_U.h
+ sed -e 's/_msg_user_/_ourmsg_user_/' < $< > $@
diff --git a/proc/cpu-types.c b/proc/cpu-types.c
new file mode 100644
index 00000000..7bcaa928
--- /dev/null
+++ b/proc/cpu-types.c
@@ -0,0 +1,163 @@
+/* Printable names for Mach CPU types and subtypes.
+ Information culled from <mach/machine.h>. */
+
+#include <mach/machine.h>
+
+const char *const mach_cpu_types[] =
+ {
+ [CPU_TYPE_VAX] = "vax",
+ [CPU_TYPE_ROMP] = "romp",
+ [CPU_TYPE_MC68020] = "mc68020",
+ [CPU_TYPE_NS32032] = "ns32032",
+ [CPU_TYPE_NS32332] = "ns32332",
+ [CPU_TYPE_NS32532] = "ns32532",
+ [CPU_TYPE_I386] = "i386",
+ [CPU_TYPE_MIPS] = "mips",
+ [CPU_TYPE_MC68030] = "mc68030",
+ [CPU_TYPE_MC68040] = "mc68040",
+ [CPU_TYPE_HPPA] = "hppa",
+ [CPU_TYPE_ARM] = "arm",
+ [CPU_TYPE_MC88000] = "mc88000",
+ [CPU_TYPE_SPARC] = "sparc",
+ [CPU_TYPE_I860] = "i860",
+ [CPU_TYPE_ALPHA] = "alpha",
+#ifdef CPU_TYPE_I486
+ [CPU_TYPE_I486] = "i486",
+#endif
+#ifdef CPU_TYPE_PENTIUM
+ [CPU_TYPE_PENTIUM] = "i586",
+#endif
+#ifdef CPU_TYPE_PENTIUMPRO
+ [CPU_TYPE_PENTIUMPRO] = "i686",
+#endif
+#ifdef CPU_TYPE_POWERPC
+ [CPU_TYPE_POWERPC] = "powerpc",
+#endif
+ };
+
+const char *const mach_cpu_subtypes[][32] =
+ {
+ [CPU_TYPE_VAX] =
+ {
+ [CPU_SUBTYPE_VAX780] = "VAX780",
+ [CPU_SUBTYPE_VAX785] = "VAX785",
+ [CPU_SUBTYPE_VAX750] = "VAX750",
+ [CPU_SUBTYPE_VAX730] = "VAX730",
+ [CPU_SUBTYPE_UVAXI] = "UVAXI",
+ [CPU_SUBTYPE_UVAXII] = "UVAXII",
+ [CPU_SUBTYPE_VAX8200] = "VAX8200",
+ [CPU_SUBTYPE_VAX8500] = "VAX8500",
+ [CPU_SUBTYPE_VAX8600] = "VAX8600",
+ [CPU_SUBTYPE_VAX8650] = "VAX8650",
+ [CPU_SUBTYPE_VAX8800] = "VAX8800",
+ [CPU_SUBTYPE_UVAXIII] = "UVAXIII",
+ },
+ [CPU_TYPE_ROMP] =
+ {
+ [CPU_SUBTYPE_RT_PC] = "RT_PC",
+ [CPU_SUBTYPE_RT_APC] = "RT_APC",
+ [CPU_SUBTYPE_RT_135] = "RT_135",
+ },
+ [CPU_TYPE_MC68020] =
+ {
+ [CPU_SUBTYPE_SUN3_50] = "SUN3_50",
+ [CPU_SUBTYPE_SUN3_160] = "SUN3_160",
+ [CPU_SUBTYPE_SUN3_260] = "SUN3_260",
+ [CPU_SUBTYPE_SUN3_110] = "SUN3_110",
+ [CPU_SUBTYPE_SUN3_60] = "SUN3_60",
+
+ [CPU_SUBTYPE_HP_320] = "HP_320",
+ [CPU_SUBTYPE_HP_330] = "HP_330",
+ [CPU_SUBTYPE_HP_350] = "HP_350",
+ },
+ [CPU_TYPE_NS32032] =
+ {
+ [CPU_SUBTYPE_MMAX_DPC] = "MMAX_DPC",
+ [CPU_SUBTYPE_SQT] = "SQT",
+ [CPU_SUBTYPE_MMAX_APC_FPU] = "MMAX_APC_FPU",
+ [CPU_SUBTYPE_MMAX_APC_FPA] = "MMAX_APC_FPA",
+ [CPU_SUBTYPE_MMAX_XPC] = "MMAX_XPC",
+ [CPU_SUBTYPE_PC532] = "PC532",
+ },
+#define Ix86_SUBTYPES \
+ { \
+ [CPU_SUBTYPE_AT386] = "AT386", \
+ [CPU_SUBTYPE_EXL] = "EXL", \
+ [CPU_SUBTYPE_iPSC386] = "iPSC386", \
+ [CPU_SUBTYPE_SYMMETRY] = "SYMMETRY", \
+ [CPU_SUBTYPE_PS2] = "PS2", \
+ }
+ [CPU_TYPE_I386] = Ix86_SUBTYPES,
+#ifdef CPU_TYPE_I486
+ [CPU_TYPE_I486] = Ix86_SUBTYPES,
+#endif
+#ifdef CPU_TYPE_PENTIUM
+ [CPU_TYPE_PENTIUM] = Ix86_SUBTYPES,
+#endif
+#ifdef CPU_TYPE_PENTIUMPRO
+ [CPU_TYPE_PENTIUMPRO] = Ix86_SUBTYPES,
+#endif
+ [CPU_TYPE_MIPS] =
+ {
+ [CPU_SUBTYPE_MIPS_R2300] = "R2300",
+ [CPU_SUBTYPE_MIPS_R2600] = "R2600",
+ [CPU_SUBTYPE_MIPS_R2800] = "R2800",
+ [CPU_SUBTYPE_MIPS_R2000a] = "R2000a",
+ [CPU_SUBTYPE_MIPS_R2000] = "R2000",
+ [CPU_SUBTYPE_MIPS_R3000a] = "R3000a",
+ [CPU_SUBTYPE_MIPS_R3000] = "R3000",
+ },
+ [CPU_TYPE_MC68030] =
+ {
+ [CPU_SUBTYPE_NeXT] = "NeXT",
+ [CPU_SUBTYPE_HP_340] = "HP_340",
+ [CPU_SUBTYPE_HP_360] = "HP_360",
+ [CPU_SUBTYPE_HP_370] = "HP_370",
+ },
+ [CPU_TYPE_HPPA] =
+ {
+ [CPU_SUBTYPE_HPPA_825] = "825",
+ [CPU_SUBTYPE_HPPA_835] = "835",
+ [CPU_SUBTYPE_HPPA_840] = "840",
+ [CPU_SUBTYPE_HPPA_850] = "850",
+ [CPU_SUBTYPE_HPPA_855] = "855",
+ },
+ [CPU_TYPE_ARM] =
+ {
+ [CPU_SUBTYPE_ARM_A500_ARCH] = "A500_ARCH",
+ [CPU_SUBTYPE_ARM_A500] = "A500",
+ [CPU_SUBTYPE_ARM_A440] = "A440",
+ [CPU_SUBTYPE_ARM_M4] = "M4",
+ [CPU_SUBTYPE_ARM_A680] = "A680",
+ },
+ [CPU_TYPE_MC88000] =
+ {
+ [CPU_SUBTYPE_MMAX_JPC] = "MMAX_JPC",
+ [CPU_SUBTYPE_LUNA88K] = "LUNA88K",
+ },
+ [CPU_TYPE_SPARC] =
+ {
+ [CPU_SUBTYPE_SUN4_260] = "SUN4_260",
+ [CPU_SUBTYPE_SUN4_110] = "SUN4_110",
+ [CPU_SUBTYPE_SUN4_330] = "SUN4_330",
+ [CPU_SUBTYPE_SUN4C_60] = "SUN4C_60",
+ [CPU_SUBTYPE_SUN4C_65] = "SUN4C_65",
+ [CPU_SUBTYPE_SUN4C_20] = "SUN4C_20",
+ [CPU_SUBTYPE_SUN4C_30] = "SUN4C_30",
+ [CPU_SUBTYPE_SUN4C_40] = "SUN4C_40",
+ [CPU_SUBTYPE_SUN4C_50] = "SUN4C_50",
+ [CPU_SUBTYPE_SUN4C_75] = "SUN4C_75",
+ },
+ [CPU_TYPE_I860] =
+ {
+ [CPU_SUBTYPE_iPSC860] = "iPSC860",
+ [CPU_SUBTYPE_OKI860] = "OKI860",
+ },
+ [CPU_TYPE_ALPHA] =
+ {
+ [CPU_SUBTYPE_ALPHA_EV3] = "ALPHA_EV3",
+ [CPU_SUBTYPE_ALPHA_EV4] = "ALPHA_EV4",
+ [CPU_SUBTYPE_ALPHA_ISP] = "ALPHA_ISP",
+ [CPU_SUBTYPE_ALPHA_21064] = "ALPHA_21064",
+ },
+ };
diff --git a/proc/exc-reply.defs b/proc/exc-reply.defs
new file mode 100644
index 00000000..8a047233
--- /dev/null
+++ b/proc/exc-reply.defs
@@ -0,0 +1,36 @@
+/* This special version of exc.defs exists because the proc server
+ has to be able to do both halves of the exc interface separately.
+ Its interface is identical to <mach/exc.defs>. */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+subsystem exc 2400;
+
+#include <mach/std_types.defs>
+
+simpleroutine exception_raise (exception_port: mach_port_t;
+ \ No newline at end of file
diff --git a/proc/hash.c b/proc/hash.c
new file mode 100644
index 00000000..76c2369c
--- /dev/null
+++ b/proc/hash.c
@@ -0,0 +1,160 @@
+/* Hash table functions
+ Copyright (C) 1993, 1994, 1995, 1996, 1997 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"
+#include <hurd/ihash.h>
+
+static struct ihash pghash, pidhash, taskhash, sidhash;
+
+/* Find the process corresponding to a given pid. */
+struct proc *
+pid_find (pid_t pid)
+{
+ struct proc *p;
+ p = ihash_find (&pidhash, pid);
+ return (!p || p->p_dead) ? 0 : p;
+}
+
+/* Find the process corresponding to a given pid. Return it even if
+ it's dead. */
+struct proc *
+pid_find_allow_zombie (pid_t pid)
+{
+ return ihash_find (&pidhash, pid);
+}
+
+/* Find the process corresponding to a given task. */
+struct proc *
+task_find (task_t task)
+{
+ struct proc *p;
+ p = ihash_find (&taskhash, task) ? : add_tasks (task);
+ return (!p || p->p_dead) ? 0 : p;
+}
+
+/* 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)
+{
+ struct proc *p;
+ p = ihash_find (&taskhash, task);
+ return (!p || p->p_dead) ? 0 : p;
+}
+
+/* Find the process corresponding to a given request port. */
+struct proc *
+reqport_find (mach_port_t reqport)
+{
+ struct proc *p;
+ p = ports_lookup_port (proc_bucket, reqport, proc_class);
+ if (p && p->p_dead)
+ ports_port_deref (p);
+ return (!p || p->p_dead) ? 0 : p;
+}
+
+/* Find the process group corresponding to a given pgid. */
+struct pgrp *
+pgrp_find (pid_t pgid)
+{
+ return ihash_find (&pghash, pgid);
+}
+
+/* Find the session corresponding to a given sid. */
+struct session *
+session_find (pid_t sid)
+{
+ return ihash_find (&sidhash, sid);
+}
+
+/* Add a new process to the various hash tables. */
+void
+add_proc_to_hash (struct proc *p)
+{
+ ihash_add (&pidhash, p->p_pid, p, &p->p_pidhashloc);
+ ihash_add (&taskhash, p->p_task, p, &p->p_taskhashloc);
+}
+
+/* Add a new process group to the various hash tables. */
+void
+add_pgrp_to_hash (struct pgrp *pg)
+{
+ ihash_add (&pghash, pg->pg_pgid, pg, &pg->pg_hashloc);
+}
+
+/* Add a new session to the various hash tables. */
+void
+add_session_to_hash (struct session *s)
+{
+ ihash_add (&sidhash, s->s_sid, s, &s->s_hashloc);
+}
+
+/* Remove a process group from the various hash tables. */
+void
+remove_pgrp_from_hash (struct pgrp *pg)
+{
+ ihash_locp_remove(0, pg->pg_hashloc);
+}
+
+/* Remove a process from the various hash tables. */
+void
+remove_proc_from_hash (struct proc *p)
+{
+ ihash_locp_remove(0, p->p_pidhashloc);
+ ihash_locp_remove(0, p->p_taskhashloc);
+}
+
+/* Remove a session from the various hash tables. */
+void
+remove_session_from_hash (struct session *s)
+{
+ ihash_locp_remove(0, s->s_hashloc);
+}
+
+/* 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)
+{
+ error_t thunk(void *value)
+ {
+ struct proc *p = value;
+ if (!p->p_dead)
+ (*fun)(p, arg);
+ return 0;
+ }
+ ihash_iterate(&pidhash, thunk);
+}
+
+/* Tell if a pid is available for use */
+int
+pidfree (pid_t pid)
+{
+ return (!pid_find_allow_zombie (pid)
+ && !pgrp_find (pid) && !session_find (pid));
+}
diff --git a/proc/host.c b/proc/host.c
new file mode 100644
index 00000000..8f9460cb
--- /dev/null
+++ b/proc/host.c
@@ -0,0 +1,408 @@
+/* Proc server host management calls
+ Copyright (C) 1992, 1993, 1994, 1996, 1997 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.h>
+#include <sys/types.h>
+#include <hurd/hurd_types.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <mach/notify.h>
+#include <string.h>
+#include <stdio.h>
+#include <hurd/exec.h>
+#include <unistd.h>
+#include <assert.h>
+#include <version.h>
+
+#include "proc.h"
+#include "process_S.h"
+
+static mach_port_t *std_port_array;
+static int *std_int_array;
+static int n_std_ports, n_std_ints;
+static struct utsname uname_info;
+
+struct server_version
+{
+ char *name;
+ char *version;
+} *server_versions;
+int nserver_versions, server_versions_nalloc;
+
+struct execdata_notify
+{
+ mach_port_t notify_port;
+ struct execdata_notify *next;
+} *execdata_notifys;
+
+
+/* Implement proc_getprivports as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_getprivports (struct proc *p,
+ mach_port_t *hostpriv,
+ mach_port_t *devpriv)
+{
+ if (!p)
+ return EOPNOTSUPP;
+
+ 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>. */
+kern_return_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 (!p)
+ return EOPNOTSUPP;
+
+ 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>. */
+kern_return_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)
+{
+ /* No need to check P here; we don't use it. */
+
+ /* XXX memory leak here */
+
+ if (!std_port_array)
+ return ENOENT;
+
+ 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>. */
+kern_return_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;
+
+ /* No need to check P here; we don't use it. */
+
+ 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);
+
+ if (std_port_array)
+ exec_setexecdata (n->notify_port, std_port_array, MACH_MSG_TYPE_COPY_SEND,
+ n_std_ports, std_int_array, n_std_ints);
+ return 0;
+}
+
+/* Check all the execdata notify ports and see if one of them is
+ PORT; if it is, then free it. */
+void
+check_dead_execdata_notify (mach_port_t port)
+{
+ struct execdata_notify *en, **prevp;
+
+ for (en = execdata_notifys, prevp = &execdata_notifys; en; en = *prevp)
+ {
+ if (en->notify_port == port)
+ {
+ mach_port_deallocate (mach_task_self (), port);
+ *prevp = en->next;
+ free (en);
+ }
+ else
+ prevp = &en->next;
+ }
+}
+
+/* Version information handling.
+
+ A server registers its name and version with
+ startup_register_version.
+
+ The uname release is the most popular version number.
+
+ The uname version string is composed of all the server names and
+ versions, omitting special mention of those which match the uname
+ release, plus the kernel version string. */
+
+char *kernel_name, *kernel_version;
+
+
+/* Rebuild the uname version string. */
+static void
+rebuild_uname (void)
+{
+ unsigned int i, j;
+ char *p, *end;
+
+ /* Set up for addstr to write into STRING. */
+ inline void initstr (char *string)
+ {
+ p = string;
+ end = p + _UTSNAME_LENGTH;
+ }
+ /* If NAME is not null, write "name-version/", else "version/". */
+ inline void addstr (const char *name, const char *version)
+ {
+ size_t len;
+ if (name)
+ {
+ len = strlen (name);
+ if (p + len + 1 < end)
+ memcpy (p, name, len);
+ p += len;
+ if (p < end)
+ *p++ = '-';
+ }
+ len = strlen (version);
+ if (p + len + 1 < end)
+ memcpy (p, version, len);
+ p += len;
+ if (p < end)
+ *p++ = '/';
+ }
+
+ /* Collect all the differing version strings and count how many
+ servers use each. */
+ struct version
+ {
+ const char *version;
+ unsigned int count;
+ } versions[nserver_versions];
+ int compare_versions (const void *a, const void *b)
+ {
+ return (((const struct version *) b)->count -
+ ((const struct version *) a)->count);
+ }
+ unsigned int nversions = 0;
+
+ for (i = 0; i < nserver_versions; ++i)
+ {
+ for (j = 0; j < nversions; ++j)
+ if (! strcmp (versions[j].version, server_versions[i].version))
+ {
+ ++versions[j].count;
+ break;
+ }
+ if (j == nversions)
+ {
+ versions[nversions].version = server_versions[i].version;
+ versions[nversions].count = 1;
+ ++nversions;
+ }
+ }
+
+ /* Sort the versions in order of decreasing popularity. */
+ qsort (versions, nversions, sizeof (struct version), compare_versions);
+
+ /* Now build the uname strings. */
+
+ /* release is the most popular version */
+ strcpy (uname_info.release, versions[0].version);
+
+ initstr (uname_info.version);
+
+ addstr (kernel_name, kernel_version);
+
+ if (versions[0].count > 1)
+ addstr ("Hurd", versions[0].version);
+
+ /* Now, for any which differ (if there might be any), write it out
+ separately. */
+ if (versions[0].count != nserver_versions)
+ for (i = 0; i < nserver_versions; i++)
+ if (versions[0].count == 1
+ || strcmp (server_versions[i].version, versions[0].version))
+ addstr (server_versions[i].name, server_versions[i].version);
+
+ if (p > end)
+#ifdef notyet
+ syslog (LOG_EMERG,
+ "_UTSNAME_LENGTH %u too short; inform bug-glibc@prep.ai.mit.edu\n",
+ p - end)
+#endif
+ ;
+ else
+ p[-1] = '\0';
+ end[-1] = '\0';
+}
+
+void
+initialize_version_info (void)
+{
+ extern const char *const mach_cpu_types[];
+ extern const char *const mach_cpu_subtypes[][32];
+ kernel_version_t kv;
+ char *p;
+ struct host_basic_info info;
+ unsigned int n = sizeof info;
+ error_t err;
+
+ /* Fill in fixed slots sysname and machine. */
+ strcpy (uname_info.sysname, "GNU");
+
+ err = host_info (mach_host_self (), HOST_BASIC_INFO, (int *) &info, &n);
+ assert (! err);
+ snprintf (uname_info.machine, sizeof uname_info.machine, "%s-%s",
+ mach_cpu_types[info.cpu_type],
+ mach_cpu_subtypes[info.cpu_type][info.cpu_subtype]);
+
+ /* Notice Mach's and our own version and initialize server version
+ varables. */
+ server_versions = malloc (sizeof (struct server_version) * 10);
+ server_versions_nalloc = 10;
+
+ err = host_kernel_version (mach_host_self (), kv);
+ assert (! err);
+ p = index (kv, ':');
+ if (p)
+ *p = '\0';
+ p = index (kv, ' ');
+ if (p)
+ *p = '\0';
+ kernel_name = strdup (p ? kv : "mach");
+ kernel_version = strdup (p ? p + 1 : kv);
+
+ server_versions[0].name = strdup ("proc");
+ server_versions[0].version = strdup (HURD_VERSION);
+
+ nserver_versions = 1;
+
+ rebuild_uname ();
+
+ uname_info.nodename[0] = '\0';
+}
+
+kern_return_t
+S_proc_uname (pstruct_t process,
+ struct utsname *uname)
+{
+ /* No need to check PROCESS here, we don't use it. */
+ *uname = uname_info;
+ return 0;
+}
+
+kern_return_t
+S_proc_register_version (pstruct_t server,
+ mach_port_t credential,
+ char *name,
+ char *release,
+ char *version)
+{
+ int i;
+
+ /* No need to check SERVER here; we don't use it. */
+
+ if (credential != master_host_port)
+ /* Must be privileged to register for uname. */
+ return EPERM;
+
+ for (i = 0; i < nserver_versions; i++)
+ if (!strcmp (name, server_versions[i].name))
+ {
+ /* Change this entry. */
+ free (server_versions[i].version);
+ server_versions[i].version = malloc (strlen (version) + 1);
+ strcpy (server_versions[i].version, version);
+ break;
+ }
+ if (i == nserver_versions)
+ {
+ /* Didn't find it; extend. */
+ if (nserver_versions == server_versions_nalloc)
+ {
+ server_versions_nalloc *= 2;
+ server_versions = realloc (server_versions,
+ sizeof (struct server_version) *
+ server_versions_nalloc);
+ }
+ server_versions[nserver_versions].name = malloc (strlen (name) + 1);
+ server_versions[nserver_versions].version = malloc (strlen (version)
+ + 1);
+ strcpy (server_versions[nserver_versions].name, name);
+ strcpy (server_versions[nserver_versions].version, version);
+ nserver_versions++;
+ }
+
+ rebuild_uname ();
+ mach_port_deallocate (mach_task_self (), credential);
+ return 0;
+}
+
diff --git a/proc/info.c b/proc/info.c
new file mode 100644
index 00000000..2855adef
--- /dev/null
+++ b/proc/info.c
@@ -0,0 +1,694 @@
+/* Process information queries
+ Copyright (C) 1992,93,94,95,96,99,2000 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. */
+
+/* Written by Michael I. Bushnell. */
+
+#include <mach.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <hurd/hurd_types.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <assert.h>
+#include <hurd/msg.h>
+
+#include "proc.h"
+#include "process_S.h"
+
+/* Implement S_proc_pid2task as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_pid2task (struct proc *callerp,
+ pid_t pid,
+ task_t *t)
+{
+ struct proc *p = pid_find_allow_zombie (pid);
+
+ if (!callerp)
+ return EOPNOTSUPP;
+
+ if (!p)
+ return ESRCH;
+
+ if (p->p_dead)
+ {
+ *t = MACH_PORT_NULL;
+ return 0;
+ }
+
+ if (! check_owner (callerp, p))
+ return EPERM;
+
+ assert (MACH_PORT_VALID (p->p_task));
+ *t = p->p_task;
+
+ return 0;
+}
+
+/* Implement proc_task2pid as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_task2pid (struct proc *callerp,
+ task_t t,
+ pid_t *pid)
+{
+ struct proc *p = task_find (t);
+
+ /* No need to check CALLERP here; we don't use it. */
+
+ 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>. */
+kern_return_t
+S_proc_task2proc (struct proc *callerp,
+ task_t t,
+ mach_port_t *outproc)
+{
+ struct proc *p = task_find (t);
+
+ /* No need to check CALLERP here; we don't use it. */
+
+ if (!p)
+ return ESRCH;
+
+ *outproc = ports_get_right (p);
+ mach_port_deallocate (mach_task_self (), t);
+ return 0;
+}
+
+/* Implement proc_proc2task as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_proc2task (struct proc *p,
+ task_t *t)
+{
+ if (!p)
+ return EOPNOTSUPP;
+ *t = p->p_task;
+ return 0;
+}
+
+/* Implement proc_pid2proc as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_pid2proc (struct proc *callerp,
+ pid_t pid,
+ mach_port_t *outproc)
+{
+ struct proc *p = pid_find_allow_zombie (pid);
+
+ if (!callerp)
+ return EOPNOTSUPP;
+
+ if (!p)
+ return ESRCH;
+
+ if (p->p_dead)
+ {
+ *outproc = MACH_PORT_NULL;
+ return 0;
+ }
+
+ if (! check_owner (callerp, p))
+ return EPERM;
+
+ *outproc = ports_get_right (p);
+ return 0;
+}
+
+
+/* Read a string starting at address ADDR in task T; set *STR to point at
+ newly malloced storage holding it, and *LEN to its length with null. */
+static error_t
+get_string (task_t t,
+ vm_address_t addr,
+ char **str, size_t *len)
+{
+ /* 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 == MACH_SEND_INVALID_DEST)
+ err = ESRCH;
+ if (err)
+ return err;
+
+ /* Scan for a null. */
+ c = memchr ((char *) (data + (addr - readaddr)), '\0',
+ readlen - (addr - readaddr));
+ if (c == NULL)
+ err = KERN_INVALID_ADDRESS;
+ else
+ {
+ c++; /* Include the null. */
+ *len = c - (char *) (data + (addr - readaddr));
+ *str = malloc (*len);
+ if (*str == NULL)
+ err = ENOMEM;
+ else
+ memcpy (*str, (char *) data + (addr - readaddr), *len);
+ }
+
+ munmap ((caddr_t) data, readlen);
+ return err;
+}
+
+/* Read a vector of addresses (stored as are argv and envp) from task 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_size_t readsize;
+ vm_address_t scanned;
+ error_t err;
+
+ *vec = NULL;
+ readaddr = trunc_page (addr);
+ readsize = 0;
+ scanned = addr;
+ do
+ {
+ vm_address_t data;
+ mach_msg_type_number_t readlen = 0;
+ vm_address_t *t;
+
+ readsize += vm_page_size;
+ err = vm_read (task, readaddr, readsize, &data, &readlen);
+ if (err == MACH_SEND_INVALID_DEST)
+ err = ESRCH;
+ if (err)
+ return err;
+
+ /* XXX fault bad here */
+
+ /* Scan for a null. */
+ for (t = (vm_address_t *) (data + (scanned - readaddr));
+ t < (vm_address_t *) (data + readlen);
+ ++t)
+ if (*t == 0)
+ {
+ ++t; /* Include the null. */
+ *vec = malloc ((char *)t - (char *)(data + (addr - readaddr)));
+ if (*vec == NULL)
+ err = ENOMEM;
+ else
+ bcopy ((char *)(data + (addr - readaddr)), *vec,
+ (char *)t - (char *)(data + (addr - readaddr)));
+ break;
+ }
+
+ /* If we didn't find the null terminator, then we will loop
+ to read an additional page. */
+ scanned = data + readlen;
+ munmap ((caddr_t) data, readlen);
+ } while (!err && *vec == NULL);
+
+ 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)
+{
+ char *bp;
+ int *vector, *vp;
+ error_t err;
+ vm_address_t origbuf = *buf;
+
+ err = get_vector (t, loc, &vector);
+ if (err)
+ return err;
+
+ bp = (char *) *buf;
+ for (vp = vector; *vp; ++vp)
+ {
+ char *string;
+ size_t len;
+
+ err = get_string (t, *vp, &string, &len);
+ if (err)
+ {
+ free (vector);
+ if (*buf != origbuf)
+ munmap ((caddr_t) *buf, *buflen);
+ return err;
+ }
+
+ if (len > (char *) *buf + *buflen - bp)
+ {
+ char *newbuf;
+ vm_size_t prev_len = bp - (char *) *buf;
+ vm_size_t newsize = *buflen * 2;
+
+ if (newsize < prev_len + len)
+ /* Since we will mmap whole pages anyway,
+ notice how much space we really have. */
+ newsize = round_page (prev_len + len);
+
+ newbuf = mmap (0, newsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ if (newbuf == MAP_FAILED)
+ {
+ err = errno;
+ free (string);
+ free (vector);
+ if (*buf != origbuf)
+ munmap ((caddr_t) *buf, *buflen);
+ return err;
+ }
+
+ memcpy (newbuf, (char *) *buf, prev_len);
+ bp = newbuf + prev_len;
+ if (*buf != origbuf)
+ munmap ((caddr_t) *buf, *buflen);
+
+ *buf = (vm_address_t) newbuf;
+ *buflen = newsize;
+ }
+
+ memcpy (bp, string, len);
+ bp += len;
+ free (string);
+ }
+
+ free (vector);
+ *buflen = bp - (char *) *buf;
+ return 0;
+}
+
+
+/* Implement proc_getprocargs as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_getprocargs (struct proc *callerp,
+ pid_t pid,
+ char **buf,
+ u_int *buflen)
+{
+ struct proc *p = pid_find (pid);
+
+ /* No need to check CALLERP here; we don't use it. */
+
+ if (!p)
+ return ESRCH;
+
+ return get_string_array (p->p_task, p->p_argv, (vm_address_t *) buf, buflen);
+}
+
+/* Implement proc_getprocenv as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_getprocenv (struct proc *callerp,
+ pid_t pid,
+ char **buf,
+ u_int *buflen)
+{
+ struct proc *p = pid_find (pid);
+
+ /* No need to check CALLERP here; we don't use it. */
+
+ if (!p)
+ return ESRCH;
+
+ return get_string_array (p->p_task, p->p_envp, (vm_address_t *)buf, buflen);
+}
+
+/* Handy abbreviation for all the various thread details. */
+#define PI_FETCH_THREAD_DETAILS \
+ (PI_FETCH_THREAD_SCHED | PI_FETCH_THREAD_BASIC | PI_FETCH_THREAD_WAITS)
+
+/* Implement proc_getprocinfo as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_getprocinfo (struct proc *callerp,
+ pid_t pid,
+ int *flags,
+ int **piarray,
+ u_int *piarraylen,
+ char **waits, mach_msg_type_number_t *waits_len)
+{
+ struct proc *p = pid_find (pid);
+ struct procinfo *pi;
+ int nthreads;
+ thread_t *thds;
+ error_t err = 0;
+ size_t structsize;
+ int i;
+ int pi_alloced = 0, waits_alloced = 0;
+ /* The amount of WAITS we've filled in so far. */
+ mach_msg_type_number_t waits_used = 0;
+ u_int tkcount, thcount;
+ struct proc *tp;
+ task_t task; /* P's task port. */
+ mach_port_t msgport; /* P's msgport, or MACH_PORT_NULL if none. */
+
+ /* No need to check CALLERP here; we don't use it. */
+
+ if (!p)
+ return ESRCH;
+
+ task = p->p_task;
+
+ check_msgport_death (p);
+ msgport = p->p_msgport;
+
+ if (*flags & PI_FETCH_THREAD_DETAILS)
+ *flags |= PI_FETCH_THREADS;
+
+ if (*flags & PI_FETCH_THREADS)
+ {
+ err = task_threads (p->p_task, &thds, &nthreads);
+ if (err == MACH_SEND_INVALID_DEST)
+ err = ESRCH;
+ if (err)
+ return err;
+ }
+ else
+ nthreads = 0;
+
+ structsize = sizeof (struct procinfo);
+ if (*flags & PI_FETCH_THREAD_DETAILS)
+ structsize += nthreads * sizeof (pi->threadinfos[0]);
+
+ if (structsize / sizeof (int) > *piarraylen)
+ {
+ *piarray = mmap (0, structsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ pi_alloced = 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_waiting ? PI_WAITING : 0)
+ | (!p->p_pgrp->pg_orphcnt ? PI_ORPHAN : 0)
+ | (p->p_msgport == MACH_PORT_NULL ? PI_NOMSG : 0)
+ | (p->p_pgrp->pg_session->s_sid == p->p_pid ? PI_SESSLD : 0)
+ | (p->p_noowner ? PI_NOTOWNED : 0)
+ | (!p->p_parentset ? PI_NOPARENT : 0)
+ | (p->p_traced ? PI_TRACED : 0)
+ | (p->p_msgportwait ? PI_GETMSG : 0)
+ | (p->p_loginleader ? PI_LOGINLD : 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;
+ for (tp = p; !tp->p_loginleader; tp = tp->p_parent)
+ assert (tp);
+ pi->logincollection = tp->p_pid;
+ if (p->p_dead || p->p_stopped)
+ {
+ pi->exitstatus = p->p_status;
+ pi->sigcode = p->p_sigcode;
+ }
+ else
+ pi->exitstatus = pi->sigcode = 0;
+
+ pi->nthreads = nthreads;
+
+ /* Release GLOBAL_LOCK around time consuming bits, and more importatantly,
+ potential calls to P's msgport, which can block. */
+ mutex_unlock (&global_lock);
+
+ if (*flags & PI_FETCH_TASKINFO)
+ {
+ tkcount = TASK_BASIC_INFO_COUNT;
+ err = task_info (task, TASK_BASIC_INFO, (int *)&pi->taskinfo, &tkcount);
+ if (err == MACH_SEND_INVALID_DEST)
+ err = ESRCH;
+ }
+
+ for (i = 0; i < nthreads; i++)
+ {
+ if (*flags & PI_FETCH_THREAD_DETAILS)
+ pi->threadinfos[i].died = 0;
+ if (*flags & PI_FETCH_THREAD_BASIC)
+ {
+ thcount = THREAD_BASIC_INFO_COUNT;
+ err = thread_info (thds[i], THREAD_BASIC_INFO,
+ (int *)&pi->threadinfos[i].pis_bi,
+ &thcount);
+ if (err == MACH_SEND_INVALID_DEST)
+ {
+ pi->threadinfos[i].died = 1;
+ err = 0;
+ continue;
+ }
+ else if (err)
+ /* Something screwy, give up on this bit of info. */
+ {
+ *flags &= ~PI_FETCH_THREAD_BASIC;
+ err = 0;
+ }
+ }
+
+ if (*flags & PI_FETCH_THREAD_SCHED)
+ {
+ thcount = THREAD_SCHED_INFO_COUNT;
+ err = thread_info (thds[i], THREAD_SCHED_INFO,
+ (int *)&pi->threadinfos[i].pis_si,
+ &thcount);
+ if (err == MACH_SEND_INVALID_DEST)
+ {
+ pi->threadinfos[i].died = 1;
+ err = 0;
+ continue;
+ }
+ if (err)
+ /* Something screwy, give up o nthis bit of info. */
+ {
+ *flags &= ~PI_FETCH_THREAD_SCHED;
+ err = 0;
+ }
+ }
+
+ /* Note that there are thread wait entries only for threads not marked
+ dead. */
+
+ if (*flags & PI_FETCH_THREAD_WAITS)
+ {
+ /* See what thread I is waiting on. */
+ if (msgport == MACH_PORT_NULL)
+ *flags &= ~PI_FETCH_THREAD_WAITS; /* Can't return much... */
+ else
+ {
+ string_t desc;
+ size_t desc_len;
+
+ if (msg_report_wait (msgport, thds[i],
+ desc, &pi->threadinfos[i].rpc_block))
+ desc[0] = '\0'; /* Don't know. */
+
+ /* See how long DESC is, being sure not to barf if it's
+ unterminated (string_t's are fixed length). */
+ desc_len = strnlen (desc, sizeof desc);
+
+ if (waits_used + desc_len + 1 > *waits_len)
+ /* Not enough room in WAITS, we must allocate more. */
+ {
+ char *new_waits = 0;
+ mach_msg_type_number_t new_len =
+ round_page (waits_used + desc_len + 1);
+
+ new_waits = mmap (0, new_len, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ err = (new_waits == (char *) -1) ? errno : 0;
+ if (err)
+ /* Just don't return any more waits information. */
+ *flags &= ~PI_FETCH_THREAD_WAITS;
+ else
+ {
+ if (waits_used > 0)
+ bcopy (*waits, new_waits, waits_used);
+ if (*waits_len > 0 && waits_alloced)
+ munmap (*waits, *waits_len);
+ *waits = new_waits;
+ *waits_len = new_len;
+ waits_alloced = 1;
+ }
+ }
+
+ if (waits_used + desc_len + 1 <= *waits_len)
+ /* Append DESC to WAITS. */
+ {
+ bcopy (desc, *waits + waits_used, desc_len);
+ waits_used += desc_len;
+ (*waits)[waits_used++] = '\0';
+ }
+ }
+ }
+
+ mach_port_deallocate (mach_task_self (), thds[i]);
+ }
+
+ if (*flags & PI_FETCH_THREADS)
+ munmap (thds, nthreads * sizeof (thread_t));
+ if (err && pi_alloced)
+ munmap (*piarray, structsize);
+ if (err && waits_alloced)
+ munmap (*waits, *waits_len);
+ else
+ *waits_len = waits_used;
+
+ /* Reacquire GLOBAL_LOCK to make the central locking code happy. */
+ mutex_lock (&global_lock);
+
+ return err;
+}
+
+/* Implement proc_make_login_coll as described in <hurd/process.defs>. */
+kern_return_t
+S_proc_make_login_coll (struct proc *p)
+{
+ if (!p)
+ return EOPNOTSUPP;
+ p->p_loginleader = 1;
+ return 0;
+}
+
+/* Implement proc_getloginid as described in <hurd/process.defs>. */
+kern_return_t
+S_proc_getloginid (struct proc *callerp,
+ pid_t pid,
+ pid_t *leader)
+{
+ struct proc *proc = pid_find (pid);
+ struct proc *p;
+
+ /* No need to check CALLERP here; we don't use it. */
+
+ if (!proc)
+ return ESRCH;
+
+ for (p = proc; !p->p_loginleader; p = p->p_parent)
+ assert (p);
+
+ *leader = p->p_pid;
+ return 0;
+}
+
+/* Implement proc_getloginpids as described in <hurd/process.defs>. */
+kern_return_t
+S_proc_getloginpids (struct proc *callerp,
+ pid_t id,
+ pid_t **pids,
+ u_int *npids)
+{
+ struct proc *l = pid_find (id);
+ struct proc *p;
+ struct proc **tail, **new, **parray;
+ int parraysize;
+ int i;
+
+ /* No need to check CALLERP here; we don't use it. */
+
+ if (!l || !l->p_loginleader)
+ return ESRCH;
+
+ /* Simple breadth first search of the children of L. */
+ parraysize = 50;
+ parray = malloc (sizeof (struct proc *) * parraysize);
+ parray[0] = l;
+ for (tail = parray, new = &parray[1]; tail != new; tail++)
+ {
+ for (p = (*tail)->p_ochild; p; p = p->p_sib)
+ if (!p->p_loginleader)
+ {
+ /* Add P to the list at NEW */
+ if (new - parray > parraysize)
+ {
+ struct proc **newparray;
+ newparray = realloc (parray, ((parraysize *= 2)
+ * sizeof (struct proc *)));
+ tail = newparray + (tail - parray);
+ new = newparray + (new - parray);
+ parray = newparray;
+ }
+ *new++ = p;
+ }
+ }
+
+ if (*npids < new - parray)
+ *pids = mmap (0, (new - parray) * sizeof (pid_t), PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ *npids = new - parray;
+ for (i = 0; i < *npids; i++)
+ (*pids)[i] = parray[i]->p_pid;
+ free (parray);
+ return 0;
+}
+
+/* Implement proc_setlogin as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_setlogin (struct proc *p,
+ char *login)
+{
+ struct login *l;
+
+ if (!p)
+ return EOPNOTSUPP;
+
+ 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>. */
+kern_return_t
+S_proc_getlogin (struct proc *p,
+ char *login)
+{
+ if (!p)
+ return EOPNOTSUPP;
+ strcpy (login, p->p_login->l_name);
+ return 0;
+}
+
+/* Implement proc_get_tty as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_get_tty (struct proc *p, pid_t pid,
+ mach_port_t *tty, mach_msg_type_name_t *tty_type)
+{
+ return EOPNOTSUPP; /* XXX */
+}
diff --git a/proc/main.c b/proc/main.c
new file mode 100644
index 00000000..ced0e5a7
--- /dev/null
+++ b/proc/main.c
@@ -0,0 +1,138 @@
+/* Initialization of the proc server
+ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1999 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/startup.h>
+#include <device/device.h>
+#include <assert.h>
+#include <argp.h>
+#include <error.h>
+#include <version.h>
+
+#include "proc.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (proc);
+
+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 proc_exc_server (mach_msg_header_t *, mach_msg_header_t *);
+ int status;
+
+ mutex_lock (&global_lock);
+ status = (process_server (inp, outp)
+ || notify_server (inp, outp)
+ || ports_interrupt_server (inp, outp)
+ || proc_exc_server (inp, outp));
+ mutex_unlock (&global_lock);
+ return status;
+}
+
+struct mutex global_lock = MUTEX_INITIALIZER;
+
+int
+main (int argc, char **argv, char **envp)
+{
+ mach_port_t boot;
+ error_t err;
+ mach_port_t pset, psetcntl;
+ void *genport;
+ process_t startup_port;
+ struct argp argp = { 0, 0, 0, "Hurd process server" };
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ initialize_version_info ();
+
+ err = task_get_bootstrap_port (mach_task_self (), &boot);
+ assert_perror (err);
+ if (boot == MACH_PORT_NULL)
+ error (2, 0, "proc server can only be run by init during boot");
+
+ proc_bucket = ports_create_bucket ();
+ proc_class = ports_create_class (0, 0);
+ generic_port_class = ports_create_class (0, 0);
+ exc_class = ports_create_class (exc_clean, 0);
+ ports_create_port (generic_port_class, proc_bucket,
+ sizeof (struct port_info), &genport);
+ generic_port = ports_get_right (genport);
+
+ /* Create the initial proc object for init (PID 1). */
+ startup_proc = create_startup_proc ();
+
+ /* Create our own proc object (we are PID 0). */
+ self_proc = allocate_proc (mach_task_self ());
+ complete_proc (self_proc, 0);
+
+ startup_port = ports_get_right (startup_proc);
+ mach_port_insert_right (mach_task_self (), startup_port,
+ startup_port, MACH_MSG_TYPE_MAKE_SEND);
+ err = startup_procinit (boot, startup_port, &startup_proc->p_task,
+ &authserver, &master_host_port, &master_device_port);
+ assert_perror (err);
+ mach_port_deallocate (mach_task_self (), startup_port);
+
+ mach_port_mod_refs (mach_task_self (), authserver, MACH_PORT_RIGHT_SEND, 1);
+ _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authserver);
+ mach_port_deallocate (mach_task_self (), boot);
+
+ add_proc_to_hash (startup_proc); /* Now that we have the task port. */
+
+ /* Set our own argv and envp locations. */
+ self_proc->p_argv = (int) argv;
+ self_proc->p_envp = (int) envp;
+
+ /* Give ourselves good scheduling performance, because we are so
+ important. */
+ err = thread_get_assignment (mach_thread_self (), &pset);
+ assert_perror (err);
+ err = host_processor_set_priv (master_host_port, pset, &psetcntl);
+ assert_perror (err);
+ thread_max_priority (mach_thread_self (), psetcntl, 0);
+ assert_perror (err);
+ err = task_priority (mach_task_self (), 2, 1);
+ assert_perror (err);
+
+ mach_port_deallocate (mach_task_self (), pset);
+ mach_port_deallocate (mach_task_self (), psetcntl);
+
+ {
+ /* Get our stderr set up to print on the console, in case we have
+ to panic or something. */
+ mach_port_t cons;
+ error_t err;
+ err = device_open (master_device_port, D_READ|D_WRITE, "console", &cons);
+ assert_perror (err);
+ stdin = mach_open_devstream (cons, "r");
+ stdout = stderr = mach_open_devstream (cons, "w");
+ mach_port_deallocate (mach_task_self (), cons);
+ }
+
+ while (1)
+ ports_manage_port_operations_multithread (proc_bucket,
+ message_demuxer,
+ 0, 0, 0);
+}
diff --git a/proc/mgt.c b/proc/mgt.c
new file mode 100644
index 00000000..551885de
--- /dev/null
+++ b/proc/mgt.c
@@ -0,0 +1,809 @@
+/* Process management
+ Copyright (C) 1992,93,94,95,96,99 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. */
+
+/* Written by Michael I. Bushnell. */
+
+#include <mach.h>
+#include <sys/types.h>
+#include <sys/mman.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 "process_S.h"
+#include "mutated_ourmsg_U.h"
+#include "proc_exc_S.h"
+#include "proc_exc_U.h"
+#include <hurd/signal.h>
+
+/* Create a new id structure with the given genuine uids and gids. */
+static inline struct ids *
+make_ids (const uid_t *uids, size_t nuids, const uid_t *gids, size_t 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;
+
+ memcpy (i->i_uids, uids, sizeof (uid_t) * nuids);
+ memcpy (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, or has root. */
+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 || p->p_id->i_uids[i] == 0)
+ return 1;
+ return 0;
+}
+
+
+/* Implement proc_reathenticate as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_reauthenticate (struct proc *p, mach_port_t rendport)
+{
+ 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;
+
+ if (!p)
+ return EOPNOTSUPP;
+
+ 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,
+ rendport, MACH_MSG_TYPE_COPY_SEND,
+ 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;
+ mach_port_deallocate (mach_task_self (), rendport);
+
+ 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)
+ munmap (gen_uids, ngen_uids * sizeof (uid_t));
+ if (aux_uids != aubuf)
+ munmap (aux_uids, naux_uids * sizeof (uid_t));
+ if (gen_gids != ggbuf)
+ munmap (gen_gids, ngen_gids * sizeof (uid_t));
+ if (aux_gids != agbuf)
+ munmap (aux_gids, naux_gids * sizeof (uid_t));
+
+ return 0;
+}
+
+/* Implement proc_child as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_child (struct proc *parentp,
+ task_t childt)
+{
+ struct proc *childp = task_find (childt);
+
+ if (!parentp)
+ return EOPNOTSUPP;
+
+ if (!childp)
+ return ESRCH;
+
+ if (childp->p_parentset)
+ return EBUSY;
+
+ mach_port_deallocate (mach_task_self (), childt);
+
+ /* 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);
+ if (childp->p_sib)
+ childp->p_sib->p_prevsib = childp->p_prevsib;
+ *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. */
+ if (childp->p_pgrp != parentp->p_pgrp)
+ {
+ leave_pgrp (childp);
+ childp->p_pgrp = parentp->p_pgrp;
+ join_pgrp (childp);
+ /* Not necessary to call newids ourself because join_pgrp does
+ it for us. */
+ }
+ else if (childp->p_msgport != MACH_PORT_NULL)
+ nowait_msg_proc_newids (childp->p_msgport, childp->p_task,
+ childp->p_parent->p_pid, childp->p_pgrp->pg_pgid,
+ !childp->p_pgrp->pg_orphcnt);
+ childp->p_parentset = 1;
+ return 0;
+}
+
+/* Implement proc_reassign as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_reassign (struct proc *p,
+ task_t newt)
+{
+ struct proc *stubp = task_find (newt);
+
+ if (!p)
+ return EOPNOTSUPP;
+
+ if (!stubp)
+ return ESRCH;
+
+ if (stubp == p)
+ return EINVAL;
+
+ mach_port_deallocate (mach_task_self (), newt);
+
+ remove_proc_from_hash (p);
+
+ task_terminate (p->p_task);
+ mach_port_destroy (mach_task_self (), p->p_task);
+ p->p_task = stubp->p_task;
+
+ /* For security, we need use the request port from STUBP */
+ ports_transfer_right (p, stubp);
+
+ /* 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 = MACH_PORT_NULL;/* block deallocation */
+ process_has_exited (stubp);
+ stubp->p_waited = 1; /* fake out complete_exit */
+ complete_exit (stubp);
+
+ add_proc_to_hash (p);
+
+ return 0;
+}
+
+/* Implement proc_setowner as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_setowner (struct proc *p,
+ uid_t owner,
+ int clear)
+{
+ if (!p)
+ return EOPNOTSUPP;
+
+ if (clear)
+ p->p_noowner = 1;
+ else
+ {
+ 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>. */
+kern_return_t
+S_proc_getpids (struct proc *p,
+ pid_t *pid,
+ pid_t *ppid,
+ int *orphaned)
+{
+ if (!p)
+ return EOPNOTSUPP;
+ *pid = p->p_pid;
+ *ppid = p->p_parent->p_pid;
+ *orphaned = !p->p_pgrp->pg_orphcnt;
+ return 0;
+}
+
+/* Implement proc_set_arg_locations as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_set_arg_locations (struct proc *p,
+ vm_address_t argv,
+ vm_address_t envp)
+{
+ if (!p)
+ return EOPNOTSUPP;
+ p->p_argv = argv;
+ p->p_envp = envp;
+ return 0;
+}
+
+/* Implement proc_get_arg_locations as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_get_arg_locations (struct proc *p,
+ vm_address_t *argv,
+ vm_address_t *envp)
+{
+ *argv = p->p_argv;
+ *envp = p->p_envp;
+ return 0;
+}
+
+/* Implement proc_dostop as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_dostop (struct proc *p,
+ thread_t contthread)
+{
+ thread_t threadbuf[2], *threads = threadbuf;
+ unsigned int nthreads = 2, i;
+ error_t err;
+
+ if (!p)
+ return EOPNOTSUPP;
+
+ err = task_suspend (p->p_task);
+ if (err)
+ return err;
+ err = task_threads (p->p_task, &threads, &nthreads);
+ if (err)
+ return err;
+ for (i = 0; i < nthreads; i++)
+ {
+ if (threads[i] != contthread)
+ err = thread_suspend (threads[i]);
+ mach_port_deallocate (mach_task_self (), threads[i]);
+ }
+ if (threads != threadbuf)
+ munmap (threads, nthreads * sizeof (thread_t));
+ err = task_resume (p->p_task);
+ if (err)
+ return err;
+
+ mach_port_deallocate (mach_task_self (), contthread);
+ return 0;
+}
+
+/* Clean state of E before it is deallocated */
+void
+exc_clean (void *arg)
+{
+ struct exc *e = arg;
+ mach_port_deallocate (mach_task_self (), e->forwardport);
+}
+
+/* Implement proc_handle_exceptions as described in <hurd/process.defs>. */
+kern_return_t
+S_proc_handle_exceptions (struct proc *p,
+ mach_port_t msgport,
+ mach_port_t forwardport,
+ int flavor,
+ thread_state_t new_state,
+ mach_msg_type_number_t statecnt)
+{
+ struct exc *e;
+ error_t err;
+
+ /* No need to check P here; we don't use it. */
+
+ err = ports_import_port (exc_class, proc_bucket, msgport,
+ (sizeof (struct exc)
+ + (statecnt * sizeof (natural_t))), &e);
+ if (err)
+ return err;
+
+ e->forwardport = forwardport;
+ e->flavor = flavor;
+ e->statecnt = statecnt;
+ bcopy (new_state, e->thread_state, statecnt * sizeof (natural_t));
+ ports_port_deref (e);
+ return 0;
+}
+
+/* Called on exception ports provided to proc_handle_exceptions. Do
+ the thread_set_state requested by proc_handle_exceptions and then
+ send an exception_raise message as requested. */
+kern_return_t
+S_proc_exception_raise (mach_port_t excport,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ mach_port_t thread,
+ mach_port_t task,
+ int exception,
+ int code,
+ int subcode)
+{
+ error_t err;
+ struct proc *p;
+ struct exc *e = ports_lookup_port (proc_bucket, excport, exc_class);
+ if (!e)
+ return EOPNOTSUPP;
+
+ p = task_find (task);
+ if (! p)
+ {
+ /* Bogus RPC. */
+ ports_port_deref (e);
+ return EINVAL;
+ }
+
+ /* Try to forward the message. */
+ err = proc_exception_raise (e->forwardport,
+ reply, reply_type, MACH_SEND_NOTIFY,
+ thread, task, exception, code, subcode);
+ mach_port_deallocate (mach_task_self (), thread);
+ mach_port_deallocate (mach_task_self (), task);
+
+ switch (err)
+ {
+ struct hurd_signal_detail hsd;
+ int signo;
+
+ case 0:
+ /* We have successfully forwarded the exception message. Now reset
+ the faulting thread's state to run its recovery code, which should
+ dequeue that message. */
+ err = thread_set_state (thread, e->flavor, e->thread_state, e->statecnt);
+ ports_port_deref (e);
+ return MIG_NO_REPLY;
+
+ default:
+ /* Some unexpected error in forwarding the message. */
+ /* FALLTHROUGH */
+
+ case MACH_SEND_INVALID_NOTIFY:
+ /* The port's queue is full, meaning the thread didn't receive
+ the exception message we forwarded last time it faulted.
+ Declare that signal thread hopeless and the task crashed. */
+
+ /* Translate the exception code into a signal number
+ and mark the process has dying that way. */
+ hsd.exc = exception;
+ hsd.exc_code = code;
+ hsd.exc_subcode = subcode;
+ _hurd_exception2signal (&hsd, &signo);
+ p->p_exiting = 1;
+ p->p_status = W_EXITCODE (0, signo);
+ p->p_sigcode = hsd.code;
+
+ /* Nuke the task; we will get a notification message and report it
+ died with SIGNO. */
+ task_terminate (task);
+ ports_port_deref (e);
+ return 0;
+ }
+
+}
+
+/* Implement proc_getallpids as described in <hurd/proc.defs>. */
+kern_return_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;
+ }
+
+ /* No need to check P here; we don't use it. */
+
+ add_tasks (0);
+
+ nprocs = 0;
+ prociterate (count_up, &nprocs);
+
+ if (nprocs > *pidslen)
+ *pids = mmap (0, nprocs * sizeof (pid_t), PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+
+ loc = *pids;
+ prociterate (store_pid, &loc);
+
+ *pidslen = nprocs;
+ return 0;
+}
+
+/* Create a process for TASK, which is not otherwise known to us.
+ The PID/parentage/job-control fields are not yet filled in,
+ and the proc is not entered into any hash table. */
+struct proc *
+allocate_proc (task_t task)
+{
+ struct proc *p;
+ mach_port_t foo;
+
+ /* 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). */
+
+ ports_create_port (proc_class, proc_bucket, sizeof (struct proc), &p);
+
+ p->p_task = task;
+
+ mach_port_request_notification (mach_task_self (), p->p_task,
+ MACH_NOTIFY_DEAD_NAME, 1, p->p_pi.port_right,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
+ if (foo != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), foo);
+
+ p->p_msgport = MACH_PORT_NULL;
+
+ condition_init (&p->p_wakeup);
+
+ p->p_argv = p->p_envp = p->p_status = 0;
+
+ p->p_owner = 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_deadmsg = 0;
+ p->p_checkmsghangs = 0;
+ p->p_msgportwait = 0;
+ p->p_dead = 0;
+
+ return p;
+}
+
+/* Allocate and initialize the proc structure for init (PID 1),
+ the original parent of all other procs. */
+struct proc *
+create_startup_proc (void)
+{
+ static const uid_t zero;
+ struct proc *p;
+
+ p = allocate_proc (MACH_PORT_NULL);
+
+ p->p_pid = 1;
+
+ p->p_parent = p;
+ p->p_sib = 0;
+ p->p_prevsib = &p->p_ochild;
+ p->p_ochild = p;
+ p->p_parentset = 1;
+
+ p->p_deadmsg = 1; /* Force initial "re-"fetch of msgport. */
+
+ p->p_noowner = 0;
+ p->p_id = make_ids (&zero, 1, &zero, 1);
+
+ p->p_loginleader = 1;
+ p->p_login = malloc (sizeof (struct login) + 5);
+ p->p_login->l_refcnt = 1;
+ strcpy (p->p_login->l_name, "root");
+
+ boot_setsid (p);
+
+ return p;
+}
+
+/* Complete a new process that has been allocated but not entirely initialized.
+ This gets called for every process except startup_proc (PID 1). */
+void
+complete_proc (struct proc *p, pid_t pid)
+{
+ /* 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>");
+ }
+
+ p->p_pid = pid;
+
+ p->p_id = &nullids;
+ p->p_id->i_refcnt++;
+
+ p->p_login = nulllogin;
+ p->p_login->l_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_loginleader = 0;
+ p->p_ochild = 0;
+ p->p_parentset = 0;
+
+ p->p_noowner = 1;
+
+ p->p_pgrp = startup_proc->p_pgrp;
+
+ add_proc_to_hash (p);
+ join_pgrp (p);
+}
+
+
+/* Create a process for TASK, which is not otherwise known to us
+ and initialize it in the usual ways. */
+static struct proc *
+new_proc (task_t task)
+{
+ struct proc *p = allocate_proc (task);
+ complete_proc (p, genpid ());
+ return p;
+}
+
+/* The task associated with process P has died. Drop most state,
+ and then record us as dead. Our parent will eventually complete the
+ deallocation. */
+void
+process_has_exited (struct proc *p)
+{
+ /* We have already died; this can happen since both proc_reassign
+ and dead-name notifications could result in two calls to this
+ routine for the same process. */
+ if (p->p_dead)
+ return;
+
+ p->p_waited = 0;
+ if (p->p_task != MACH_PORT_NULL)
+ alert_parent (p);
+
+ if (p->p_msgport)
+ mach_port_deallocate (mach_task_self (), p->p_msgport);
+ p->p_msgport = MACH_PORT_NULL;
+
+ prociterate ((void (*) (struct proc *, void *))check_message_dying, p);
+
+ /* Nuke external send rights and the (possible) associated reference */
+ ports_destroy_right (p);
+
+ 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 */
+ int isdead = 0;
+
+ /* first tell them their parent is changing */
+ for (tp = p->p_ochild; tp->p_sib; tp = tp->p_sib)
+ {
+ if (tp->p_msgport != MACH_PORT_NULL)
+ nowait_msg_proc_newids (tp->p_msgport, tp->p_task,
+ 1, tp->p_pgrp->pg_pgid,
+ !tp->p_pgrp->pg_orphcnt);
+ tp->p_parent = startup_proc;
+ if (tp->p_dead)
+ isdead = 1;
+ }
+ if (tp->p_msgport != MACH_PORT_NULL)
+ nowait_msg_proc_newids (tp->p_msgport, tp->p_task,
+ 1, tp->p_pgrp->pg_pgid,
+ !tp->p_pgrp->pg_orphcnt);
+ tp->p_parent = startup_proc;
+
+ /* And now nappend the lists. */
+ 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;
+
+ if (isdead)
+ alert_parent (startup_proc);
+ }
+
+ /* If an operation is in progress for this process, cause it
+ to wakeup and return now. */
+ if (p->p_waiting || p->p_msgportwait)
+ condition_broadcast (&p->p_wakeup);
+
+ p->p_dead = 1;
+}
+
+void
+complete_exit (struct proc *p)
+{
+ assert (p->p_dead);
+ assert (p->p_waited);
+
+ remove_proc_from_hash (p);
+ if (p->p_task != MACH_PORT_NULL)
+ mach_port_destroy (mach_task_self (), p->p_task);
+
+ /* Remove us from our parent's list of children. */
+ if (p->p_sib)
+ p->p_sib->p_prevsib = p->p_prevsib;
+ *p->p_prevsib = p->p_sib;
+
+ leave_pgrp (p);
+
+ /* Drop the reference we created long ago in new_proc. The only
+ other references that ever show up are those for RPC args, which
+ will shortly vanish (because we are p_dead, those routines do
+ nothing). */
+ ports_port_deref (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++)
+ {
+ int set = 0;
+
+ /* The kernel can deliver us an array with null slots in the
+ middle, e.g. if a task died during the call. */
+ if (! MACH_PORT_VALID (tasks[j]))
+ continue;
+
+ if (!foundp)
+ {
+ struct proc *p = task_find_nocreate (tasks[j]);
+ if (!p)
+ {
+ p = new_proc (tasks[j]);
+ set = 1;
+ }
+ if (!foundp && tasks[j] == task)
+ foundp = p;
+ }
+ if (!set)
+ mach_port_deallocate (mach_task_self (), tasks[j]);
+ }
+ munmap (tasks, ntasks * sizeof (task_t));
+ mach_port_deallocate (mach_task_self (), psetpriv);
+ }
+ mach_port_deallocate (mach_task_self (), psets[i]);
+ }
+ munmap (psets, npsets * sizeof (mach_port_t));
+ return foundp;
+}
+
+/* Allocate a new unused PID.
+ (Unused means it is neither the pid nor pgrp of any relevant data.) */
+int
+genpid ()
+{
+#define WRAP_AROUND 30000
+#define START_OVER 100
+ static int nextpid = 0;
+ static int wrap = WRAP_AROUND;
+
+ int wrapped = 0;
+
+ while (!pidfree (nextpid))
+ {
+ ++nextpid;
+ if (nextpid > wrap)
+ {
+ if (wrapped)
+ {
+ wrap *= 2;
+ wrapped = 0;
+ }
+ else
+ {
+ nextpid = START_OVER;
+ wrapped = 1;
+ }
+ }
+ }
+
+ return nextpid++;
+}
diff --git a/proc/msg.c b/proc/msg.c
new file mode 100644
index 00000000..b8413e3b
--- /dev/null
+++ b/proc/msg.c
@@ -0,0 +1,148 @@
+/* Message port manipulations
+ Copyright (C) 1994, 1995, 1996, 1999 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 <hurd/startup.h>
+#include <assert.h>
+#include <stdlib.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, void *availpaddr)
+{
+ if (p->p_msgportwait)
+ {
+ condition_broadcast (&p->p_wakeup);
+ p->p_msgportwait = 0;
+ }
+}
+
+/* Register ourselves with init. */
+static any_t
+tickle_init (any_t initport)
+{
+ startup_essential_task ((mach_port_t) initport, mach_task_self (),
+ MACH_PORT_NULL, "proc", master_host_port);
+ return 0;
+}
+
+error_t
+S_proc_setmsgport (struct proc *p,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ mach_port_t msgport,
+ mach_port_t *oldmsgport,
+ mach_msg_type_name_t *oldmsgport_type)
+{
+ if (!p)
+ return EOPNOTSUPP;
+
+ *oldmsgport = p->p_msgport;
+ *oldmsgport_type = MACH_MSG_TYPE_MOVE_SEND;
+
+ p->p_msgport = msgport;
+ p->p_deadmsg = 0;
+ if (p->p_checkmsghangs)
+ prociterate (check_message_return, p);
+ p->p_checkmsghangs = 0;
+
+ if (p == startup_proc)
+ /* Init is single threaded, so we can't delay our reply for
+ the essential task RPC; spawn a thread to do it. */
+ cthread_detach (cthread_fork (tickle_init, (any_t) msgport));
+
+ return 0;
+}
+
+/* Check to see if process P is blocked trying to get the message port of
+ process DYINGP; if so, wake it up. */
+void
+check_message_dying (struct proc *p, struct proc *dyingp)
+{
+ if (p->p_msgportwait)
+ {
+ condition_broadcast (&p->p_wakeup);
+ p->p_msgportwait = 0;
+ }
+}
+
+/* Check if the message port of process P has died. Return nonzero if
+ this has indeed happened. */
+int
+check_msgport_death (struct proc *p)
+{
+ /* Only check if the message port passed away, if we know that it
+ was ever alive. */
+ if (p->p_msgport != MACH_PORT_NULL)
+ {
+ mach_port_type_t type;
+ error_t err;
+
+ err = mach_port_type (mach_task_self (), p->p_msgport, &type);
+ if (err || (type & MACH_PORT_TYPE_DEAD_NAME))
+ {
+ /* The port appears to be dead; throw it away. */
+ mach_port_deallocate (mach_task_self (), p->p_msgport);
+ p->p_msgport = MACH_PORT_NULL;
+ p->p_deadmsg = 1;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+error_t
+S_proc_getmsgport (struct proc *callerp,
+ mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type,
+ pid_t pid,
+ mach_port_t *msgport)
+{
+ int cancel;
+ struct proc *p = pid_find_allow_zombie (pid);
+
+ if (!callerp)
+ return EOPNOTSUPP;
+
+restart:
+ while (p && p->p_deadmsg && !p->p_dead)
+ {
+ callerp->p_msgportwait = 1;
+ p->p_checkmsghangs = 1;
+ cancel = hurd_condition_wait (&callerp->p_wakeup, &global_lock);
+ if (callerp->p_dead)
+ return EOPNOTSUPP;
+ if (cancel)
+ return EINTR;
+
+ /* Refetch P in case it went away while we were waiting. */
+ p = pid_find_allow_zombie (pid);
+ }
+
+ if (!p)
+ return ESRCH;
+
+ if (check_msgport_death (p))
+ goto restart;
+
+ *msgport = p->p_msgport;
+
+ return 0;
+}
diff --git a/proc/notify.c b/proc/notify.c
new file mode 100644
index 00000000..07fc376d
--- /dev/null
+++ b/proc/notify.c
@@ -0,0 +1,105 @@
+/* Handle notifications
+ Copyright (C) 1992, 1993, 1994, 1996, 1999 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. */
+
+/* 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 <stdlib.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. */
+kern_return_t
+do_mach_notify_dead_name (mach_port_t notify,
+ mach_port_t deadport)
+{
+ struct proc *p;
+
+ /* Drop gratuitous extra reference that the notification creates. */
+ mach_port_deallocate (mach_task_self (), deadport);
+
+ if (notify == generic_port)
+ {
+ check_dead_execdata_notify (deadport);
+ return 0;
+ }
+
+ p = ports_lookup_port (proc_bucket, notify, proc_class);
+
+ if (!p)
+ return EOPNOTSUPP;
+
+ if (p->p_task == deadport)
+ {
+ process_has_exited (p);
+ ports_port_deref (p);
+ return 0;
+ }
+ else
+ {
+ ports_port_deref (p);
+ return EINVAL;
+ }
+}
+
+/* We get no-senders notifications on exception ports that we
+ handle through proc_handle_exceptions. */
+kern_return_t
+do_mach_notify_no_senders (mach_port_t notify,
+ mach_port_mscount_t mscount)
+{
+ return ports_do_mach_notify_no_senders (notify, mscount);
+}
+
+kern_return_t
+do_mach_notify_port_deleted (mach_port_t notify,
+ mach_port_t name)
+{
+ return 0;
+}
+
+kern_return_t
+do_mach_notify_msg_accepted (mach_port_t notify,
+ mach_port_t name)
+{
+ return 0;
+}
+
+kern_return_t
+do_mach_notify_port_destroyed (mach_port_t notify,
+ mach_port_t name)
+{
+ return 0;
+}
+
+kern_return_t
+do_mach_notify_send_once (mach_port_t notify)
+{
+ return 0;
+}
diff --git a/proc/ourmsg.defs b/proc/ourmsg.defs
new file mode 100644
index 00000000..ca3fdcd6
--- /dev/null
+++ b/proc/ourmsg.defs
@@ -0,0 +1,12 @@
+/* Private specialized presentation of msg.defs for proc server. */
+
+#define routine simpleroutine
+
+/* The reason for this= 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. */
+#define out /* empty */
+
+#define USERPREFIX nowait_
+
+#include <hurd/msg.defs>
diff --git a/proc/pgrp.c b/proc/pgrp.c
new file mode 100644
index 00000000..ecd4b6e3
--- /dev/null
+++ b/proc/pgrp.c
@@ -0,0 +1,439 @@
+/* Session and process group manipulation
+ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1999 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. */
+
+/* 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 "process_S.h"
+#include "mutated_ourmsg_U.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_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_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_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)
+{
+ *pg->pg_prevp = pg->pg_next;
+ if (pg->pg_next)
+ pg->pg_next->pg_prevp = pg->pg_prevp;
+ 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>. */
+kern_return_t
+S_proc_setsid (struct proc *p)
+{
+ struct session *sess;
+
+ if (!p)
+ return EOPNOTSUPP;
+
+ 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>. */
+kern_return_t
+S_proc_getsid (struct proc *callerp,
+ pid_t pid,
+ pid_t *sid)
+{
+ struct proc *p = pid_find (pid);
+ if (!p)
+ return ESRCH;
+
+ /* No need to check CALLERP; we don't use it. */
+
+ *sid = p->p_pgrp->pg_session->s_sid;
+ return 0;
+}
+
+/* Implement proc_getsessionpids as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_getsessionpids (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;
+
+ /* No need to check CALLERP; we don't use it. */
+
+ 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 */
+ {
+ *pids = mmap (0, count * sizeof (pid_t), PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ 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_getsessionpgids as described in <hurd/process.defs>. */
+kern_return_t
+S_proc_getsessionpgids (struct proc *callerp,
+ pid_t sid,
+ pid_t **pgids,
+ u_int *npgidsp)
+{
+ int count;
+ struct pgrp *pg;
+ struct session *s;
+ pid_t *pp = *pgids;
+ int npgids = *npgidsp;
+
+ /* No need to check CALLERP; we don't use it. */
+
+ s = session_find (sid);
+ if (!s)
+ return ESRCH;
+ count = 0;
+
+ for (pg = s->s_pgrps; pg; pg = pg->pg_next)
+ if (++count <= npgids)
+ *pp++ = pg->pg_pgid;
+
+ if (count > npgids)
+ /* They didn't all fit. */
+ {
+ *pgids = mmap (0, count * sizeof (pid_t), PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ pp = *pgids;
+ for (pg = s->s_pgrps; pg; pg = pg->pg_next)
+ *pp++ = pg->pg_pgid;
+ /* Dealloc ? XXX */
+ }
+ *npgidsp = count;
+ return 0;
+}
+
+/* Implement proc_getpgrppids as described in <hurd/process.defs>. */
+kern_return_t
+S_proc_getpgrppids (struct proc *callerp,
+ pid_t pgid,
+ pid_t **pids,
+ u_int *npidsp)
+{
+
+ struct proc *p;
+ struct pgrp *pg;
+ pid_t *pp = *pids;
+ unsigned int npids = *npidsp, count;
+
+ /* No need to check CALLERP; we don't use it. */
+
+ if (pgid == 0)
+ pg = callerp->p_pgrp;
+ else
+ {
+ pg = pgrp_find (pgid);
+ if (!pg)
+ return ESRCH;
+ }
+
+ count = 0;
+ 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. */
+ {
+ *pids = mmap (0, count * sizeof (pid_t), PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ pp = *pids;
+ for (p = pg->pg_plist; p; p = p->p_gnext)
+ *pp++ = p->p_pid;
+ /* Dealloc ? XXX */
+ }
+ *npidsp = count;
+ return 0;
+}
+
+/* Implement proc_getsidport as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_getsidport (struct proc *p,
+ mach_port_t *sessport, mach_msg_type_name_t *sessport_type)
+{
+ error_t err = 0;
+
+ if (!p)
+ return EOPNOTSUPP;
+
+ if (!p->p_pgrp)
+ *sessport = MACH_PORT_NULL;
+ else
+ {
+ if (p->p_pgrp->pg_session->s_sessionid == MACH_PORT_NULL)
+ err = 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;
+ }
+ *sessport_type = MACH_MSG_TYPE_MAKE_SEND;
+ return err;
+}
+
+/* Implement proc_setpgrp as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_setpgrp (struct proc *callerp,
+ pid_t pid,
+ pid_t pgid)
+{
+ struct proc *p;
+ struct pgrp *pg;
+
+ if (!callerp)
+ return EOPNOTSUPP;
+
+ p = pid ? pid_find (pid) : callerp;
+
+ if (!p || (p != callerp && p->p_parent != callerp))
+ return ESRCH;
+
+ if (p->p_parent == callerp && p->p_exec)
+ return EACCES;
+
+ if (!pgid)
+ pgid = p->p_pid;
+ pg = pgrp_find (pgid);
+
+ if (p->p_pgrp->pg_session->s_sid == p->p_pid
+ || p->p_pgrp->pg_session != callerp->p_pgrp->pg_session
+ || ((pgid != p->p_pid
+ && (!pg || pg->pg_session != callerp->p_pgrp->pg_session))))
+ return EPERM;
+
+ if (p->p_pgrp != pg)
+ {
+ leave_pgrp (p);
+ p->p_pgrp = pg ? pg : new_pgrp (pgid, p->p_pgrp->pg_session);
+ join_pgrp (p);
+ }
+ else
+ nowait_msg_proc_newids (p->p_msgport, p->p_task, p->p_parent->p_pid,
+ pg->pg_pgid, !pg->pg_orphcnt);
+
+ return 0;
+}
+
+/* Implement proc_getpgrp as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_getpgrp (struct proc *callerp,
+ pid_t pid,
+ pid_t *pgid)
+{
+ struct proc *p = pid_find (pid);
+
+ /* No need to check CALLERP; we don't use it. */
+
+ 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>. */
+kern_return_t
+S_proc_mark_exec (struct proc *p)
+{
+ if (!p)
+ return EOPNOTSUPP;
+ 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 (p->p_gnext)
+ p->p_gnext->p_gprevp = p->p_gprevp;
+
+ /* 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;
+ if (ip->p_msgport != MACH_PORT_NULL)
+ nowait_msg_proc_newids (ip->p_msgport, ip->p_task, ip->p_parent->p_pid,
+ ip->p_pid, 1);
+ }
+ if (dosignal)
+ for (ip = pg->pg_plist; ip; ip = ip->p_gnext)
+ {
+ send_signal (ip->p_msgport, SIGHUP, ip->p_task);
+ send_signal (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;
+ struct proc *tp;
+ int origorphcnt;
+
+ 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;
+
+ origorphcnt = !!pg->pg_orphcnt;
+ if (p->p_parent->p_pgrp != pg
+ && p->p_parent->p_pgrp->pg_session == pg->pg_session)
+ pg->pg_orphcnt++;
+ if (origorphcnt != !!pg->pg_orphcnt)
+ {
+ /* Tell all the processes that their status has changed */
+ for (tp = pg->pg_plist; tp; tp = tp->p_gnext)
+ if (tp->p_msgport != MACH_PORT_NULL)
+ nowait_msg_proc_newids (tp->p_msgport, tp->p_task,
+ tp->p_parent->p_pid, pg->pg_pgid,
+ !pg->pg_orphcnt);
+ }
+ else if (p->p_msgport != MACH_PORT_NULL)
+ /* Always notify process P, because its pgrp has changed. */
+ nowait_msg_proc_newids (p->p_msgport, p->p_task,
+ p->p_parent->p_pid, pg->pg_pgid, !pg->pg_orphcnt);
+}
diff --git a/proc/proc.h b/proc/proc.h
new file mode 100644
index 00000000..0022b132
--- /dev/null
+++ b/proc/proc.h
@@ -0,0 +1,222 @@
+/* Process server definitions
+ Copyright (C) 1992,93,94,95,96,99,2000 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. */
+
+/* Written by Michael I. Bushnell. */
+
+#ifndef PROC_H_INCLUDED
+#define PROC_H_INCLUDED
+
+#include <sys/resource.h>
+#include <sys/mman.h>
+#include <hurd/ports.h>
+#include <cthreads.h>
+
+struct proc
+{
+ struct port_info p_pi;
+
+ /* 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 */
+
+ /* 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 */
+
+ struct condition p_wakeup;
+
+ /* Miscellaneous information */
+ vm_address_t p_argv, p_envp;
+ int p_status; /* to return via wait */
+ int p_sigcode;
+
+ unsigned int p_exec:1; /* has called proc_mark_exec */
+ unsigned int p_stopped:1; /* has called proc_mark_stop */
+ unsigned int p_waited:1; /* stop has been reported to parent */
+ unsigned int p_exiting:1; /* has called proc_mark_exit */
+ unsigned int p_waiting:1; /* blocked in wait */
+ unsigned int p_traced:1; /* has called proc_mark_traced */
+ unsigned int p_nostopcld:1; /* has called proc_mark_nostopchild */
+ unsigned int p_parentset:1; /* has had a parent set with proc_child */
+ unsigned int p_deadmsg:1; /* hang on requests for a message port */
+ unsigned int p_checkmsghangs:1; /* someone is currently hanging on us */
+ unsigned int p_msgportwait:1; /* blocked in getmsgport */
+ unsigned int p_noowner:1; /* has no owner known */
+ unsigned int p_loginleader:1; /* leader of login collection */
+ unsigned int p_dead:1; /* process is dead */
+};
+
+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;
+};
+
+/* Structure for an exception port we are listening on. */
+struct exc
+{
+ struct port_info pi;
+ mach_port_t forwardport; /* Send right to forward msg to. */
+ int flavor; /* State to restore faulting thread to. */
+ mach_msg_type_number_t statecnt;
+ natural_t thread_state[0];
+};
+
+struct zombie *zombie_list;
+
+mach_port_t authserver;
+struct proc *self_proc; /* process 0 (us) */
+struct proc *startup_proc; /* process 1 (init) */
+
+struct port_bucket *proc_bucket;
+struct port_class *proc_class;
+struct port_class *generic_port_class;
+struct port_class *exc_class;
+
+mach_port_t master_host_port;
+mach_port_t master_device_port;
+
+mach_port_t generic_port; /* messages not related to a specific proc */
+
+struct mutex global_lock;
+
+extern inline void
+process_drop (struct proc *p)
+{
+ if (p)
+ ports_port_deref (p);
+}
+
+/* Forward declarations */
+void complete_wait (struct proc *, 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 *);
+int check_msgport_death (struct proc *);
+void check_dead_execdata_notify (mach_port_t);
+
+void add_proc_to_hash (struct proc *);
+void add_exc_to_hash (struct exc *);
+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 *);
+void remove_exc_from_hash (struct exc *);
+struct exc *exc_find (mach_port_t);
+struct proc *pid_find (int);
+struct proc *pid_find_allow_zombie (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);
+
+void exc_clean (void *);
+
+struct proc *add_tasks (task_t);
+int pidfree (pid_t);
+
+struct proc *create_startup_proc (void);
+struct proc *allocate_proc (task_t);
+void complete_proc (struct proc *, pid_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 *);
+void complete_exit (struct proc *);
+
+void initialize_version_info (void);
+
+void send_signal (mach_port_t, int, mach_port_t);
+
+/* Returns true if PROC1 has `owner' privileges over PROC2 (and can thus get
+ its task port &c). If PROC2 has an owner, then PROC1 must have that uid;
+ otherwise, both must be in the same login collection. */
+extern inline int
+check_owner (struct proc *proc1, struct proc *proc2)
+{
+ return
+ proc2->p_noowner
+ ? check_uid (proc1, 0) || proc1->p_login == proc2->p_login
+ : check_uid (proc1, proc2->p_owner);
+}
+
+#endif
diff --git a/proc/proc_exc.defs b/proc/proc_exc.defs
new file mode 100644
index 00000000..283de477
--- /dev/null
+++ b/proc/proc_exc.defs
@@ -0,0 +1,48 @@
+/* This special version of exc.defs exists because the proc server
+ needs to do the call with special options.
+ Its RPC interface is identical to <mach/exc.defs>. */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+subsystem proc_exc 2400;
+
+#include <mach/std_types.defs>
+
+ServerPrefix S_;
+
+routine proc_exception_raise (
+ exception_port: mach_port_t;
+ replyport reply: mach_port_poly_t;
+ msgoption flags: integer_t;
+ thread: mach_port_t;
+ task: mach_port_t;
+ exception: integer_t;
+ code: integer_t;
+ subcode: integer_t);
+
+
+
diff --git a/proc/stubs.c b/proc/stubs.c
new file mode 100644
index 00000000..f95bdfa5
--- /dev/null
+++ b/proc/stubs.c
@@ -0,0 +1,136 @@
+/* By-hand stubs for some RPC calls
+ Copyright (C) 1994, 1996, 1999 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 <cthreads.h>
+#include <stdlib.h>
+#include <hurd/hurd_types.h>
+#include <mach/message.h>
+#include <string.h>
+
+#include "proc.h"
+
+/* From hurd/msg.defs: */
+#define RPCID_SIG_POST 23000
+
+struct msg_spec
+{
+ int len;
+ void *contents;
+};
+
+/* Send the Mach message indicated by msg_spec; call cthread_exit
+ when it has been delivered. */
+static void
+blocking_message_send (struct msg_spec *message)
+{
+ cthread_wire ();
+ mach_msg ((mach_msg_header_t *)message->contents, MACH_SEND_MSG,
+ message->len, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ cthread_exit (0);
+}
+
+/* Send signal SIGNO to MSGPORT with REFPORT as reference. Don't
+ block in any fashion. */
+void
+send_signal (mach_port_t msgport,
+ int signal,
+ mach_port_t refport)
+{
+ error_t err;
+
+ static struct
+ {
+ mach_msg_header_t head;
+ mach_msg_type_t signaltype;
+ int signal;
+ mach_msg_type_t sigcode_type;
+ natural_t sigcode;
+ mach_msg_type_t refporttype;
+ mach_port_t refport;
+ }
+ message =
+ {
+ {
+ /* Message header: */
+ (MACH_MSGH_BITS_COMPLEX
+ | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE)), /* msgh_bits */
+ sizeof message, /* msgh_size */
+ 0, /* msgh_remote_port */
+ MACH_PORT_NULL, /* msgh_local_port */
+ 0, /* msgh_seqno */
+ RPCID_SIG_POST, /* msgh_id */
+ },
+ {
+ /* Type descriptor for signo */
+ MACH_MSG_TYPE_INTEGER_32, /* msgt_name */
+ 32, /* msgt_size */
+ 1, /* msgt_number */
+ 1, /* msgt_inline */
+ 0, /* msgt_longform */
+ 0, /* msgt_deallocate */
+ 0, /* msgt_unused */
+ },
+ /* Signal number */
+ 0,
+ /* Type descriptor for sigcode */
+ {
+ MACH_MSG_TYPE_INTEGER_32, /* msgt_name */
+ 32, /* msgt_size */
+ 1, /* msgt_number */
+ 1, /* msgt_inline */
+ 0, /* msgt_longform */
+ 0, /* msgt_deallocate */
+ 0, /* msgt_unused */
+ },
+ /* Sigcode */
+ 0,
+ {
+ /* Type descriptor for refport */
+ MACH_MSG_TYPE_COPY_SEND, /* msgt_name */
+ 32, /* msgt_size */
+ 1, /* msgt_number */
+ 1, /* msgt_inline */
+ 0, /* msgt_longform */
+ 0, /* msgt_deallocate */
+ 0, /* msgt_unused */
+ },
+ /* Reference port */
+ MACH_PORT_NULL,
+ };
+
+ message.head.msgh_remote_port = msgport;
+ message.signal = signal;
+ message.refport = refport;
+
+ err = mach_msg((mach_msg_header_t *)&message,
+ MACH_SEND_MSG|MACH_SEND_TIMEOUT, sizeof message, 0,
+ MACH_PORT_NULL, 0, MACH_PORT_NULL);
+
+ if (err == MACH_SEND_TIMEOUT)
+ {
+ struct msg_spec *msg_spec = malloc (sizeof (struct msg_spec));
+
+ msg_spec->len = sizeof message;
+ msg_spec->contents = malloc (sizeof message);
+ bcopy (&message, msg_spec->contents, sizeof message);
+
+ cthread_detach (cthread_fork ((cthread_fn_t) blocking_message_send,
+ msg_spec));
+ }
+}
diff --git a/proc/wait.c b/proc/wait.c
new file mode 100644
index 00000000..60ec58ff
--- /dev/null
+++ b/proc/wait.c
@@ -0,0 +1,235 @@
+/* Implementation of wait
+ Copyright (C) 1994, 1995, 1996 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 "process_S.h"
+#include <mach/mig_errors.h>
+
+#define EWOULDBLOCK EAGAIN /* XXX */
+
+/* Return nonzero if a `waitpid' on WAIT_PID by a process
+ in MYPGRP cares about the death of PID/PGRP. */
+static inline int
+waiter_cares (pid_t wait_pid, pid_t mypgrp,
+ pid_t pid, pid_t pgrp)
+{
+ return (wait_pid == pid ||
+ wait_pid == -pgrp ||
+ wait_pid == WAIT_ANY ||
+ (wait_pid == WAIT_MYPGRP && pgrp == mypgrp));
+}
+
+/* A process is dying. Send SIGCHLD to the parent. Wake the parent
+if it is waiting for us to exit. */
+void
+alert_parent (struct proc *p)
+{
+ send_signal (p->p_parent->p_msgport, SIGCHLD, p->p_parent->p_task);
+
+ if (!p->p_exiting)
+ {
+ p->p_status = W_EXITCODE (0, SIGKILL);
+ p->p_sigcode = -1;
+ }
+
+ if (p->p_parent->p_waiting)
+ {
+ condition_broadcast (&p->p_parent->p_wakeup);
+ p->p_parent->p_waiting = 0;
+ }
+}
+
+kern_return_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,
+ int *sigcode,
+ struct rusage *ru,
+ pid_t *pid_status)
+{
+ int cancel;
+
+ int child_ready (struct proc *child)
+ {
+ if (child->p_waited)
+ return 0;
+ if (child->p_dead)
+ return 1;
+ if (!child->p_stopped)
+ return 0;
+ if (child->p_traced || (options & WUNTRACED))
+ return 1;
+ return 0;
+ }
+
+ if (!p)
+ return EOPNOTSUPP;
+
+ start_over:
+ /* See if we can satisfy the request with a stopped
+ child; also check for invalid arguments here. */
+ if (!p->p_ochild)
+ return ECHILD;
+
+ if (pid > 0)
+ {
+ struct proc *child = pid_find_allow_zombie (pid);
+ if (!child || child->p_parent != p)
+ return ECHILD;
+ if (child_ready (child))
+ {
+ child->p_waited = 1;
+ *status = child->p_status;
+ *sigcode = child->p_sigcode;
+ if (child->p_dead)
+ complete_exit (child);
+ bzero (ru, sizeof (struct rusage));
+ *pid_status = pid;
+ return 0;
+ }
+ }
+ else
+ {
+ struct proc *child;
+ int had_a_match = pid == 0;
+
+ for (child = p->p_ochild; child; child = child->p_sib)
+ if (waiter_cares (pid, p->p_pgrp->pg_pgid,
+ child->p_pid, child->p_pgrp->pg_pgid))
+ {
+ had_a_match = 1;
+ if (child_ready (child))
+ {
+ child->p_waited = 1;
+ *status = child->p_status;
+ *sigcode = child->p_sigcode;
+ *pid_status = child->p_pid;
+ if (child->p_dead)
+ complete_exit (child);
+ bzero (ru, sizeof (struct rusage));
+ return 0;
+ }
+ }
+
+ if (!had_a_match)
+ return ECHILD;
+ }
+
+ if (options & WNOHANG)
+ return EWOULDBLOCK;
+
+ p->p_waiting = 1;
+ cancel = hurd_condition_wait (&p->p_wakeup, &global_lock);
+ if (p->p_dead)
+ return EOPNOTSUPP;
+ if (cancel)
+ return EINTR;
+ goto start_over;
+}
+
+/* Implement proc_mark_stop as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_mark_stop (struct proc *p,
+ int signo,
+ int sigcode)
+{
+ if (!p)
+ return EOPNOTSUPP;
+
+ p->p_stopped = 1;
+ p->p_status = W_STOPCODE (signo);
+ p->p_sigcode = sigcode;
+ p->p_waited = 0;
+
+ if (p->p_parent->p_waiting)
+ {
+ condition_broadcast (&p->p_parent->p_wakeup);
+ p->p_parent->p_waiting = 0;
+ }
+
+ if (!p->p_parent->p_nostopcld)
+ send_signal (p->p_parent->p_msgport, SIGCHLD, p->p_parent->p_task);
+
+ return 0;
+}
+
+/* Implement proc_mark_exit as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_mark_exit (struct proc *p,
+ int status,
+ int sigcode)
+{
+ if (!p)
+ return EOPNOTSUPP;
+
+ if (WIFSTOPPED (status))
+ return EINVAL;
+
+ p->p_exiting = 1;
+ p->p_status = status;
+ p->p_sigcode = sigcode;
+ return 0;
+}
+
+/* Implement proc_mark_cont as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_mark_cont (struct proc *p)
+{
+ if (!p)
+ return EOPNOTSUPP;
+ p->p_stopped = 0;
+ return 0;
+}
+
+/* Implement proc_mark_traced as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_mark_traced (struct proc *p)
+{
+ if (!p)
+ return EOPNOTSUPP;
+ p->p_traced = 1;
+ return 0;
+}
+
+/* Implement proc_mark_nostopchild as described in <hurd/proc.defs>. */
+kern_return_t
+S_proc_mod_stopchild (struct proc *p,
+ int value)
+{
+ if (!p)
+ return EOPNOTSUPP;
+ /* VALUE is nonzero if we should send SIGCHLD. */
+ p->p_nostopcld = ! value;
+ return 0;
+}
+