diff options
Diffstat (limited to 'proc')
-rw-r--r-- | proc/=proc_excrepl.defs | 37 | ||||
-rw-r--r-- | proc/ChangeLog | 1082 | ||||
-rw-r--r-- | proc/Makefile | 39 | ||||
-rw-r--r-- | proc/cpu-types.c | 163 | ||||
-rw-r--r-- | proc/exc-reply.defs | 36 | ||||
-rw-r--r-- | proc/hash.c | 160 | ||||
-rw-r--r-- | proc/host.c | 408 | ||||
-rw-r--r-- | proc/info.c | 694 | ||||
-rw-r--r-- | proc/main.c | 138 | ||||
-rw-r--r-- | proc/mgt.c | 809 | ||||
-rw-r--r-- | proc/msg.c | 148 | ||||
-rw-r--r-- | proc/notify.c | 105 | ||||
-rw-r--r-- | proc/ourmsg.defs | 12 | ||||
-rw-r--r-- | proc/pgrp.c | 439 | ||||
-rw-r--r-- | proc/proc.h | 222 | ||||
-rw-r--r-- | proc/proc_exc.defs | 48 | ||||
-rw-r--r-- | proc/stubs.c | 136 | ||||
-rw-r--r-- | proc/wait.c | 235 |
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; +} + |