aboutsummaryrefslogtreecommitdiff
path: root/trans
diff options
context:
space:
mode:
Diffstat (limited to 'trans')
-rw-r--r--trans/ChangeLog561
-rw-r--r--trans/Makefile43
-rw-r--r--trans/bogus-fifo.c160
-rw-r--r--trans/crash.c786
-rw-r--r--trans/fifo.c591
-rw-r--r--trans/firmlink.c277
-rw-r--r--trans/fwd.c51
-rw-r--r--trans/hello-mt.c316
-rw-r--r--trans/hello.c279
-rw-r--r--trans/ifsock.c134
-rw-r--r--trans/magic.c367
-rw-r--r--trans/new-fifo.c817
-rw-r--r--trans/null.c318
-rw-r--r--trans/password.c224
-rw-r--r--trans/symlink.c197
15 files changed, 5121 insertions, 0 deletions
diff --git a/trans/ChangeLog b/trans/ChangeLog
new file mode 100644
index 00000000..9bac016b
--- /dev/null
+++ b/trans/ChangeLog
@@ -0,0 +1,561 @@
+2000-01-28 Roland McGrath <roland@baalperazim.frob.com>
+
+ * crash.c (enum crash_action): New alternative crash_unspecified (0).
+ (crash_orphans_how): New variable.
+ (S_crash_dump_task): If crash_how != crash_orphans_how, ascertain if
+ the task is an orphan before deciding what to do.
+ (options): New options --action, --orphan-action.
+ Old options now compatability aliases for --action=foo.
+ (parse_opt): Parse them.
+ (doc): New variable.
+ (crash_argp): Use DOC.
+
+1999-12-03 Roland McGrath <roland@baalperazim.frob.com>
+
+ * null.c: Support --full/-f option to be /dev/full (ENOSPC writes).
+ (write_error_code): New variable.
+ (options, argp): New static const variables.
+ (parse_opt): New function.
+ (main): Move local ARGP out to static.
+ (trivfs_S_io_write): Return write_error_code instead of zero.
+
+1999-11-08 Roland McGrath <roland@baalperazim.frob.com>
+
+ * hello-mt.c: New file, modified from hello.c to be multithreaded.
+ * Makefile (targets, SRCS): Add hello-mt, hello-mt.c.
+ (hello-mt): Add appropriate deps.
+
+ * Makefile (hello): Don't depend on libthreads.
+
+ * hello.c (trivfs_modify_stat): Set st_size from contents_len, not
+ sizeof (hello) - 1.
+
+ * hello.c: New file. From Gord with some cleanups and hacks from me.
+ * Makefile (targets, SRCS): Add hello, hello.c.
+ (hello): Add appropriate deps.
+
+1999-10-11 Roland McGrath <roland@baalperazim.frob.com>
+
+ * magic.c: Rewritten using libtrivfs.
+ With new flag --directory/-d, present an empty directory that
+ has . and .. as normal and lists no other contents, but
+ looking up anything else within it does the magical retry.
+ * Makefile (magic): Update library deps accordingly.
+
+1999-09-13 Roland McGrath <roland@baalperazim.frob.com>
+
+ * fifo.c, null.c, new-fifo.c: Reverted changes related to
+ io_map_segment.
+
+1999-09-07 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * null.c (trivfs_S_io_map): Renamed to ...
+ (trivfs_S_io_map_segment): ... here, with new parameter `index'.
+ * new-fifo.c (trivfs_S_io_map): Renamed to ...
+ (trivfs_S_io_map_segment): ... here, with new parameter `index'.
+ * fifo.c (trivfs_S_io_map): Renamed to ...
+ (trivfs_S_io_map_segment): ... here, with new parameter `index'.
+
+1999-08-31 Marcus Brinkmann <Marcus.Brinkmann@ruhr-uni-bochum.de>
+
+ * crash.c (trivfs_modify_stat): Remove redundant fstype setting.
+ * password.c (trivfs_modify_stat): Likewise.
+
+ * bogus-fifo.c (main): Deallocate bootstrap port after using it.
+ * fifo.c (main): Likewise.
+ * firmlink.c (main): Likewise.
+ * ifsock.c (main): Likewise.
+ * magic.c (main): Likewise.
+ * null.c (main): Likewise.
+ * symlink.c (main): Likewise.
+
+1999-07-11 Roland McGrath <roland@baalperazim.frob.com>
+
+ * firmlink.c: Add #include <sys/mman.h>.
+
+1999-07-09 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * firmlink.c (trivfs_S_io_read): Use mmap instead of vm_allocate.
+
+1999-07-10 Roland McGrath <roland@baalperazim.frob.com>
+
+ * crash.c: Add #include <sys/mman.h> for munmap decl.
+
+1999-07-03 Thomas Bushnell, BSG <tb@mit.edu>
+
+ * crash.c (stop_pgrp): Use munmap instead of vm_deallocate.
+
+1999-06-01 Roland McGrath <roland@baalperazim.frob.com>
+
+ * crash.c (options): Add --dump-core as alias for --core-file.
+
+ * crash.c: Support three modes of operation, selected by command line
+ switches:
+ -s/--suspend suspend crashing process (old behavior)
+ -k/--kill kill crashing process, no core dump
+ -c/--core-file dump core file
+ (enum crash_action): New type.
+ (crash_how): New variable.
+ (options, crash_argp, trivfs_runtime_argp): New variables.
+ (parse_opt, trivfs_append_args): New functions.
+ (main): Call argp_parse.
+
+1999-05-19 Roland McGrath <roland@baalperazim.frob.com>
+
+ * null.c (trivfs_S_io_read): Fix return value.
+ Reported by Steinar Hamre <steinarh@fim.ntnu.no>.
+
+1999-05-01 Roland McGrath <roland@baalperazim.frob.com>
+
+ * fwd.c (main): Add missing newline in usage msg.
+ From Marcus Brinkmann.
+
+1999-02-20 Mark Kettenis <kettenis@gnu.org>
+
+ * password.c: New file.
+ * Makefile (targets): Add password.
+ (SRCS): Add password.c.
+ (OBJS): Add passwordServer.o.
+ (password-LDLIBS): New variable.
+ Use dependencies identical to those for crash.
+
+1998-10-20 Roland McGrath <roland@baalperazim.frob.com>
+
+ * fifo.c (open_hook: WAIT): Add braces to silence gcc warning.
+ (trivfs_S_io_select): Likewise.
+ * new-fifo.c (fifo_trans_open): Likewise.
+ (trivfs_S_io_select): Likewise.
+
+1998-07-20 Roland McGrath <roland@baalperazim.frob.com>
+
+ * firmlink.c (main): Fix return type to int, and use return.
+ * fwd.c (main): Likewise.
+ * new-fifo.c (main): Likewise.
+ * magic.c (main): Likewise.
+ * fifo.c (main): Likewise.
+ * null.c (main): Likewise.
+
+1997-09-04 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * null.c (main): Fix typo.
+
+Wed Aug 20 14:07:56 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * crash.c (main): New args for
+ ports_manage_port_operations_multithread.
+ * fifo.c (main): Likewise.
+ * firmlink.c (main): Likewise.
+ * new-fifo.c (main): Likewise.
+ * null.c (main): Likewise.
+
+1997-07-22 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * devport.c: File removed.
+ * Makefile (targets): Remove devport.
+ (SRCS): Remove devport.c.
+
+1997-07-15 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * magic.c (main): Actually parse the arg.
+
+1997-07-14 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * magic.c (argp_program_version, args_doc, doc): New variables.
+ (main): Use argp to parse args.
+ Add new includes <argp.h> & <version.h>.
+
+Fri Feb 28 20:00:14 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * Makefile (fwd null ifsock fifo new-fifo devport firmlink):
+ Add firmlink to targets depending on libthreads.
+
+ * null.c (main): Make multithreaded.
+
+Tue Feb 25 15:42:40 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * firmlink.c (main): Make multithreaded.
+
+Sun Feb 23 00:23:49 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * firmlink.c (argp): Use OPTIONS.
+ (getroot): If firmlink returns ENOENT, act like an unresolvable link.
+ Don't support visible mode.
+ (options, parse_opt): Remove -i.
+
+Wed Feb 19 21:34:01 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * null.c (argp_program_version): Make const.
+
+ * fifo.c (argp_program_version, argp): New variables.
+ (parse_opt): New function.
+ (options): Use argp structures instead of getopt ones.
+ (main): Use argp instead of getopt.
+ <argp.h>: New include.
+ <getopt.h>: Include removed.
+ (trivfs_protid_port_class, trivfs_cntl_portclasses,
+ trivfs_protid_nportclasses, trivfs_cntl_nportclasses):
+ Variables removed.
+ (main): Don't use them.
+ Don't create our own port classes/bucket, let trivfs_startup do it.
+
+Tue Feb 18 12:55:50 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fifo.c <version.h>: New include.
+ (parse_opt): Use KEY, not OPT.
+
+Fri Feb 14 03:05:59 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * null.c (control_class, node_class, port_bucket,
+ trivfs_protid_port_class, trivfs_cntl_portclasses,
+ trivfs_protid_nportclasses, trivfs_cntl_nportclasses):
+ Variables removed.
+ (main): Don't use them.
+
+Thu Feb 13 19:42:38 1997 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * firmlink.c: New file.
+ * Makefile (targets): Add firmlink.
+ (SRCS): Add firmlink.c.
+ (firmlink): New target.
+
+Thu Sep 26 14:27:02 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * null.c (trivfs_S_file_check_access): Function removed (trivfs
+ default is now sufficient).
+
+Tue Sep 24 15:39:36 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * null.c (provide_zeros): Variable removed.
+ (trivfs_S_io_read): Don't return zeros anymore.
+ (trivfs_S_io_readable): Always return 0.
+ (argp_program_version): New variable.
+ (main): Use argp for argument parsing.
+ (trivfs_S_file_check_access): New function.
+
+Thu Sep 12 16:39:47 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * Makefile (HURDLIBS): New variable.
+
+Fri Jul 12 23:02:36 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * crash.c (stop_pgrp): Fetch pgrp using correct call.
+
+Mon Jul 8 13:52:36 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * crash.c (stop_pgrp): Don't do anything if ORPHANED.
+
+Mon Jul 8 08:54:05 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
+
+ * crash.c (stop_pgrp): Take second arg CTTYID. Fetch each pgrp
+ member's msgpor and send msg_sig_post with that as refport instead of
+ calling POSIX.1 kill function like a bonehead.
+ (S_crash_dump_task): Pass CTTY_ID arg through to stop_pgrp.
+
+Sun Jul 7 22:43:23 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * crash.c (stop_pgrp): New function.
+ (S_crash_dump_task): Call stop_pgrp.
+
+ * Makefile (fwd): Depend on libports.
+
+Mon Jul 1 16:09:10 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * Makefile (crash): New target.
+ * Makefile (SRCS): Added crash.c.
+ * crash.c: Moved here from ../exec.
+ (S_crash_dump_task): New args EXC, CODE, SUBCODE, CTTY_ID.
+ Supply SIGCODE arg to proc_mark_stop.
+ (signal_crasher): New arg SIGCODE, supply to proc_mark_exit. All
+ callers changed.
+ (S_msg_sig_post_untraced): Supply C->sigcode to proc_mark_stop.
+ (S_crash_dump_task): Drop arg TARGET.
+ (dump_core): Likewise; all callers changed.
+ (struct crasher): Delete member `target'.
+ (S_msg_describe_ports): New function.
+
+Thu Jun 20 16:28:33 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * Makefile (null ifsock fifo new-fifo devport): Depend on
+ ../libfshelp/libfshelp.a.
+
+Wed May 29 10:31:16 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * devport.c (trivfs_S_file_get_storage_info): Implement new interface.
+
+Sat May 11 01:19:21 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * new-fifo.c (fifo_trans_parse_args): Use ARGP_ERR_UNKNOWN instead
+ of EINVAL.
+
+Tue Apr 30 09:58:47 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * Makefile (all): Delete target.
+ (include ../Makeconf): *Before* all dependences.
+ ($(targets)): Each program depends on its associated .o.
+
+Mon Apr 15 12:50:37 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu>
+
+ * new-fifo.c (fifo_trans_parse_args): Supply missing arg to
+ argp_parse.
+
+Sun Mar 31 13:26:48 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * Makefile (targets): Add devport.
+ (SRCS): Add devport.c.
+ Add devport as a target to various dependency rules.
+
+Wed Feb 7 17:51:49 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fifo.c (trivfs_S_file_set_size): Add #!$@&* reply port args.
+ * new-fifo.c (trivfs_S_file_set_size): Likewise.
+
+Mon Jan 29 09:53:01 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fifo.c (close_hook): Also disconnect ACTIVE_FIFO if the laster
+ writer is going away and there were no readers.
+ (open_hook): Unbreak a new read pipe even if not waiting for writers.
+
+ * new-fifo.c (fifo_trans_open): Typo.
+
+Sun Jan 28 21:52:00 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fifo.c (open_hook): Only bother to do anything if O_READ | O_WRITE.
+ * new-fifo.c (fifo_trans_open): Likewise.
+ When O_NONBLOCK is set, just don't block if possible, instead of
+ of returning EWOULDBLOCK.
+ (trivfs_S_io_select): The pipe is on CRED->po->hook, not CRED->hook.
+ (trivfs_modify_stat): Zero the returned size if there's no pipe.
+
+Sat Jan 27 19:30:25 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fifo.c (open_hook): When O_NONBLOCK is set, just don't block if
+ possible, instead of of returning EWOULDBLOCK.
+ Only set PO->hook if O_READ or O_WRITE is set.
+ (trivfs_S_io_select): The pipe is on CRED->po->hook, not CRED->hook.
+ (trivfs_modify_stat): Zero the returned size if there's no pipe.
+
+Thu Jan 25 18:34:26 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * fifo.c (trivfs_goaway): Handle errors from ports_inhibit_bucket_rpcs.
+ * new-fifo.c (trivfs_goaway): Likewise.
+ Call ports_interrupt_rpcs instead of ports_interrupt_rpc.
+
+Tue Jan 16 14:18:57 1996 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * new-fifo.c (trivfs_S_io_select): Request interruption if the
+ reply-port dies.
+ Don't block if there's an error immediately available.
+ * fifo.c (trivfs_S_io_select): Ditto.
+
+Mon Nov 6 12:39:32 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * magic.c (S_fsys_get_options): New function.
+ * symlink.c (S_fsys_get_options): New function.
+
+Sun Nov 5 01:56:20 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * ifsock.c (main): Add flags argument to trivfs_startup call.
+ * null.c (main): Ditto.
+ * fifo.c (main): Ditto.
+ * new-fifo.c (fifo_trans_start): Ditto.
+ * symlink.c (main): Add flags argument to fsys_startup call.
+ (S_fsys_startup): Add FLAGS arg.
+ * magic.c (main): Add flags argument to fsys_startup call.
+ (S_fsys_startup): Add FLAGS arg.
+
+Sat Oct 7 23:41:02 1995 Miles Bader <miles@gnu.ai.mit.edu>
+
+ * symlink.c (S_fsys_getpriv): Add new extra args.
+ * magic.c (S_fsys_getpriv): Ditto.
+
+Mon Sep 18 14:54:55 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * fifo.c (trivfs_S_file_set_size): Renamed from trivfs_S_file_truncate;
+ Return EINVAL if the new size isn't 0.
+ * new-fifo.c (trivfs_S_file_truncate): Ditto.
+ * null.c (trivfs_S_file_set_size): Renamed from trivfs_S_file_truncate.
+
+Fri Sep 8 12:27:35 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * fifo.c, new-fifo.c (open_hook): Block for read only when there's
+ really someone reading already, or until there's a writer.
+ (open_hook): Use the WAIT macro to block.
+ * fifo.c (wait_for_writer): New variable.
+ (main): Set WAIT_FOR_WRITER with WAIT_FOR_READER.
+ * new-fifo.c (struct fifo_trans): Added wait_for_writer field.
+ Delete standalone field. Add some comments.
+ (fifo_trans_create): Propagate and set the wait_for_writer field.
+ (fifo_trans_parse_args): Set the wait_for_writer field.
+
+ * fifo.c (trivfs_modify_stat): Only return pipe info if there's a pipe.
+ (close_hook): Don't die if there's no pipe.
+ * new-fifo.c (trivfs_modify_stat): Only return pipe info if
+ there's a pipe.
+ (fifo_trans_close): Don't die if there's no pipe.
+
+Thu Aug 31 19:16:25 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * fifo.c (trivfs_S_io_select): Use pipe_pair_select.
+ (trivfs_S_io_write): Pass in the NOBLOCK parameter to pipe_write.
+
+Wed Aug 30 12:14:58 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
+
+ * fifo.c (trivfs_goaway): Implement correctly.
+ (main): When we time out, don't exit unless there are no opens.
+ (main): Add timeouts.
+ (port_bucket): Now a local variable in main.
+ (trivfs_S_io_select): Implement correctly.
+
+Tue Aug 29 17:31:45 1995 Miles Bader <miles@geech.gnu.ai.mit.edu>
+
+ * fifo.c (open_hook): Use hurd_condition_wait to detect interrupts.
+
+Thu Aug 24 10:41:31 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * Makefile (all): New target.
+ (symlink, magic, ifsock, fifo, null): Put all dependencies in
+ these targets.
+ (null-HURDLIBS, ifsock-HURDLIBS, fifo-HURDLIBS): Removed.
+ Get rid of rules dealing with error.o
+
+Wed Aug 23 13:11:18 1995 Miles Bader <miles@duality.gnu.ai.mit.edu>
+
+ * magic.c (S_fsys_forward): New function.
+ * symlink.c (S_fsys_forward): New function.
+ * bogus-fifo.c (S_fsys_forward): New function.
+
+Tue Aug 22 10:48:47 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * Makefile (HURDLIBS): Add libshouldbeinlibc (everyone uses it).
+ (symlink, magic, fifo, null, ifsock): Remove error.o.
+ Get rid of rules dealing with error.o.
+
+ * fifo.c (trivfs_goaway, trivfs_modify_stat): Update arguments.
+ (trivfs_modify_stat): Give the size of the fifo now that we've got
+ a handle on it.
+
+Mon Aug 21 14:43:46 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * null.c (trivfs_goaway, trivfs_modify_stat): Update arguments.
+ * ifsock.c (trivfs_goaway, trivfs_modify_stat): Update arguments.
+
+ * fifo.c (open_hook): Use condition_broadcast instead of
+ condition_signal on active_fifo_changed, as all waiters need be
+ notified of changes.
+
+Tue Jul 25 13:53:30 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * fifo.c: New file.
+ (main): Don't pass in the MACH_RCV_TIMEOUT flag with a zero timeout.
+ * Makefile (SRCS): Add fifo.c.
+ (targets): Add fifo.
+ (fifo): New target.
+
+Thu Jul 6 15:42:25 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
+
+ * Makefile (OBJS): New var.
+
+ * Makefile: Removed dependencies that are now automatically
+ generated.
+
+Wed Jul 5 21:17:34 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
+
+ * Makefile (ifsock-HURDLIBS, null-HURDLIBS): New vars.
+ (null, ifsock): Fix dependencies.
+
+Wed Jun 28 15:07:25 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu>
+
+ * null.c (PT_CTL, PT_NODE): Deleted macros.
+ (trivfs_protid_porttypes, trivfs_cntl_porttypes,
+ trivfs_protid_nporttypes, trivfs_cntl_nporttypes): Deleted vars.
+ (trivfs_protid_portclasses, trivfs_cntl_portclasses,
+ trivfs_protid_nportclasses, trivfs_cntl_nportclasses): New vars.
+ (control_class, node_class, port_bucket): New vars.
+ (main): Initialize control_class, node_class, port_bucket,
+ trivfs_protid_portclasses, and trivfs_cntl_portclasses.
+ (ports_cleanroutines): Delete initialization.
+ (main): Convert to new trivfs interface.
+ (trivfs_goaway): Likewise.
+ (main): Convert to new ports interface.
+ (ports_demuxer, ports_notice_idle, ports_no_live_ports,
+ ports_no_hard_ports): Deleted functions.
+
+ * Makefile (ifsock): Add dependency on libihash.
+ (null): Likewise.
+
+ * ifsock.c (PT_CTL, PT_NODE): Deleted macros.
+ (ports_cleanroutines): Deleted var.
+ (ports_notice_idle, ports_no_live_ports, ports_no_hard_ports):
+ Deleted functions.
+ (control_class, node_class, port_bucket): New vars.
+ (trivfs_protid_porttypes, trivfs_cntl_porttypes,
+ trivfs_protid_nporttypes, trivfs_cntl_nporttypes): Deleted vars.
+ (trivfs_protid_portclasses, trivfs_cntl_portclasses,
+ trivfs_protid_nportclasses, trivfs_cntl_nportclasses): New vars.
+ (main): Initialize control_class, node_class, port_bucket,
+ trivfs-protid_portclasses, and trivfs_cntl_portclasses.
+ (main): Use new trivfs interface.
+ (trivfs_goaway): Likewise.
+ (main): Use new ports interface.
+ (S_ifsock_getsockaddr): Likewise.
+ (demuxer): Renamed from ports_demuxer.
+ (demuxer): Declare ifsock_server.
+
+Fri May 12 19:07:54 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * magic.c (S_fsys_set_options, S_fsys_mod_readonly): Change from
+ mod_readonly to set_options.
+ * symlink.c (S_fsys_set_options, S_fsys_mod_readonly): Ditto.
+
+Thu May 11 13:36:28 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * null.c (trivfs_modify_stat): Make st_blksize really large.
+
+Mon Apr 10 20:38:49 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * null.c (trivfs_S_file_truncate): Always return 0, so O_TRUNC works.
+
+Sun Apr 9 00:26:07 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * null.c (main): Use trivfs_startup() instead of doing things manually.
+ Get rid of _libports_initialize() [it gets called automatically].
+ * ifsock.c (main): Ditto; also, use error() to print error messages.
+
+Mon Apr 3 16:39:33 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * null.c (trivfs_modify_stat): Return more useful values for the
+ st_blksize and st_fstype fields.
+
+Fri Mar 31 12:20:48 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * null.c (main): Move the check for the bootstrap port after the
+ args check, so that users can run it from the shell to get a usage
+ message.
+
+ * magic.c (main): Don't deallocate our right to the underlying
+ disk node, so we don't get garbage collected prematurely. Also
+ move the check for the bootstrap port after the args check, so
+ that users can run it from the shell to get a usage message.
+
+Wed Mar 29 19:30:33 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu>
+
+ * magic.c: New file: Translator to return F_RETRY_MAGIC strings.
+ * null.c: New file: Translator for /dev/null & /dev/zero.
+ * Makefile: Add support for the magic and null servers.
+
+Wed Aug 31 11:08:10 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * symlink.c (S_fsys_mod_readonly, S_fsys_syncfs): New functions.
+
+Tue Aug 30 16:42:29 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * ifsock.c (main): Call file_name_lookup instead af path_lookup.
+
+Tue Aug 16 11:38:26 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * Makefile (symlink, symlink.o): New targets.
+ Change to be type `servers.'.
+
+Fri Jul 22 15:15:49 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu>
+
+ * Makefile: Rewritten in accord with new scheme.
diff --git a/trans/Makefile b/trans/Makefile
new file mode 100644
index 00000000..ad7a3a4a
--- /dev/null
+++ b/trans/Makefile
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 1994,95,96,97,99 Free Software Foundation, Inc.
+#
+# 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.
+
+dir := trans
+makemode := servers
+
+targets = symlink firmlink ifsock magic null fifo new-fifo fwd crash \
+ password hello hello-mt
+SRCS = ifsock.c symlink.c magic.c null.c fifo.c new-fifo.c fwd.c \
+ crash.c firmlink.c password.c hello.c hello-mt.c
+OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o
+HURDLIBS=ports trivfs threads fshelp pipe ihash shouldbeinlibc
+password-LDLIBS = $(LIBCRYPT)
+
+include ../Makeconf
+
+symlink: fsysServer.o
+ifsock: ifsockServer.o
+crash: crashServer.o crash_replyUser.o msgServer.o
+password: passwordServer.o
+
+crash password: ../libports/libports.a ../libtrivfs/libtrivfs.a ../libthreads/libthreads.a ../libfshelp/libfshelp.a
+fifo new-fifo: ../libpipe/libpipe.a
+fwd new-fifo: ../libfshelp/libfshelp.a ../libports/libports.a
+hello-mt hello magic null ifsock fifo new-fifo firmlink: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a ../libihash/libihash.a
+$(targets): ../libshouldbeinlibc/libshouldbeinlibc.a
+hello-mt magic fwd null ifsock fifo new-fifo firmlink: ../libthreads/libthreads.a
+
+$(targets): %: %.o
diff --git a/trans/bogus-fifo.c b/trans/bogus-fifo.c
new file mode 100644
index 00000000..acad6e4b
--- /dev/null
+++ b/trans/bogus-fifo.c
@@ -0,0 +1,160 @@
+/* A translator for fifos
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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 <hurd.h>
+#include <stdio.h>
+#include <error.h>
+#include <sys/socket.h>
+#include <hurd/paths.h>
+#include <hurd/socket.h>
+#include <hurd/fsys.h>
+#include "fsys_S.h"
+
+/* ---------------------------------------------------------------- */
+
+extern int fsys_server (mach_msg_header_t *, mach_msg_header_t *);
+
+/* The actual fifo, which is just a socket connected to itself. */
+static socket_t fifo;
+
+void
+main (int argc, char **argv)
+{
+ error_t err;
+ char pflocal_name[1024];
+ mach_port_t pflocal;
+ mach_port_t bootstrap, fsys, realnode;
+
+ if (argc != 1)
+ {
+ fprintf(stderr, "Usage: %s", program_invocation_name);
+ exit(-1);
+ }
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error(3, 0, "Must be started as a translator");
+
+ /* Reply to our parent */
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &fsys);
+ err = fsys_startup (bootstrap, fsys, MACH_MSG_TYPE_MAKE_SEND, &realnode);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error(1, err, "starting translator");
+
+ /* Try and connect to the pflocal server */
+ sprintf (pflocal_name, "%s/%d", _SERVERS_SOCKET, PF_LOCAL);
+ pflocal = file_name_lookup (pflocal_name, 0, 0);
+ if (pflocal == MACH_PORT_NULL)
+ error (2, errno, "%s", pflocal_name);
+
+ /* Make a local domain socket to use for our data buffering. */
+ err = socket_create (pflocal, SOCK_STREAM, 0, &fifo);
+ if (err)
+ error (3, err, "%s: socket_create", pflocal_name);
+
+ /* Connect the socket to itself, yielding a fifo! */
+ err = socket_connect2 (fifo, fifo);
+ if (err)
+ error (3, err, "%s: socket_connect2", pflocal_name);
+
+ for (;;)
+ /* We don't ever time out. The problem is, you only want to exit when
+ (1) the pipe is empty (which we can check), and (2) there are no other
+ users (which we can't). If we just drop our ref to the pipe, there
+ still could be a writer holding a ref to it. */
+ mach_msg_server_timeout (fsys_server, 0, fsys, 0, 0);
+}
+
+/* ---------------------------------------------------------------- */
+
+error_t
+S_fsys_getroot (mach_port_t fsys, mach_port_t parent,
+ uid_t *uids, unsigned num_uids, gid_t *gids, unsigned num_gids,
+ int flags,
+ retry_type *do_retry, char *retry_name,
+ mach_port_t *result, mach_msg_type_name_t *result_type)
+{
+ /* Give back a handle on our fifo. */
+ *do_retry = FS_RETRY_NORMAL;
+ *retry_name = '\0';
+ *result = fifo;
+ *result_type = MACH_MSG_TYPE_COPY_SEND;
+ return 0;
+}
+
+error_t
+S_fsys_startup (mach_port_t bootstrap, mach_port_t fsys,
+ mach_port_t *real, mach_msg_type_name_t *real_type)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_goaway (mach_port_t fsys, int flags)
+{
+ /* If there are refs to the fifo left besides ours, it will
+ stay around after we're gone. */
+ exit (0);
+}
+
+error_t
+S_fsys_syncfs (mach_port_t fsys, int wait, int recurse)
+{
+ return 0;
+}
+
+error_t
+S_fsys_set_options (mach_port_t fsys,
+ char *data, mach_msg_type_number_t data_len, int recurse)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_getfile (mach_port_t fsys,
+ uid_t *uids, unsigned num_uids, gid_t *gids, unsigned num_gids,
+ char *handle, unsigned handle_len,
+ mach_port_t *port, mach_msg_type_name_t *port_type)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_getpriv (mach_port_t fsys,
+ mach_port_t *hostpriv, mach_port_t *devmaster, task_t *fstask)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_init (mach_port_t fsys,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ mach_port_t proc, auth_t auth)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_forward (mach_port_t server, mach_port_t requestor,
+ char *argz, size_t argz_len)
+{
+ return EOPNOTSUPP;
+}
diff --git a/trans/crash.c b/trans/crash.c
new file mode 100644
index 00000000..55e7ce92
--- /dev/null
+++ b/trans/crash.c
@@ -0,0 +1,786 @@
+/* GNU Hurd standard crash dump server.
+ Copyright (C) 1995,96,97,99,2000 Free Software Foundation, Inc.
+ Written by Roland McGrath.
+
+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. */
+
+#include <hurd.h>
+#include <fcntl.h>
+#include <hurd/trivfs.h>
+#include <sys/wait.h>
+#include <error.h>
+#include <argp.h>
+#include <argz.h>
+#include <sys/mman.h>
+
+#include "crash_S.h"
+#include "crash_reply_U.h"
+#include "msg_S.h"
+
+
+process_t procserver; /* Our proc port, for easy access. */
+
+/* Port bucket we service requests on. */
+struct port_bucket *port_bucket;
+
+/* Trivfs hooks. */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+int trivfs_support_read = 0;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+int trivfs_allow_open = O_READ|O_WRITE|O_EXEC;
+
+struct port_class *trivfs_protid_portclasses[1];
+struct port_class *trivfs_cntl_portclasses[1];
+int trivfs_protid_nportclasses = 1;
+int trivfs_cntl_nportclasses = 1;
+
+struct trivfs_control *fsys;
+
+enum crash_action
+{
+ crash_unspecified,
+ crash_suspend,
+ crash_kill,
+ crash_corefile
+};
+#define CRASH_DEFAULT crash_suspend
+#define CRASH_ORPHANS_DEFAULT crash_corefile
+
+static enum crash_action crash_how, crash_orphans_how;
+
+
+error_t dump_core (task_t task, file_t core_file,
+ int signo, long int sigcode, int sigerror);
+
+
+/* This data structure describes a crashing task which we have suspended.
+ This is attached to a receive right we have set as the process's message
+ port, so we can get a msg_sig_post RPC to continue or kill the process. */
+
+struct crasher
+ {
+ struct port_info pi;
+
+ /* How to reply to the crash_dump_task RPC. The RPC remains "in
+ progress" while the process is in crash suspension. If the process
+ is resumed with SIGCONT, we will dump a core file and then reply to
+ the RPC. */
+ mach_port_t reply_port;
+ mach_msg_type_name_t reply_type;
+
+ task_t task;
+ file_t core_file;
+ int signo, sigcode, sigerror;
+
+ mach_port_t original_msgport; /* Restore on resume. */
+ mach_port_t sidport; /* Session ID port for SIGCONT auth. */
+ process_t proc; /* Proc server port. */
+ };
+
+struct port_class *crasher_portclass;
+
+/* If the process referred to by proc port USERPROC is not orphaned,
+ then send SIGTSTP to all the other members of its pgrp. */
+void
+stop_pgrp (process_t userproc, mach_port_t cttyid)
+{
+ pid_t pid, ppid, pgrp;
+ int orphaned;
+ error_t err;
+ size_t numpids = 20;
+ pid_t pids_[numpids], *pids = pids_;
+ int i;
+
+ err = proc_getpids (userproc, &pid, &ppid, &orphaned);
+ if (err || orphaned)
+ return;
+ err = proc_getpgrp (userproc, pid, &pgrp);
+ if (err)
+ return;
+
+ /* Use USERPROC so that if it's just died we get an error and don't do
+ anything. */
+ err = proc_getpgrppids (userproc, pgrp, &pids, &numpids);
+ if (err)
+ return;
+
+ for (i = 0; i < numpids; i++)
+ if (pids[i] != pid)
+ {
+ mach_port_t msgport;
+ if (proc_getmsgport (userproc, pids[i], &msgport))
+ continue;
+ msg_sig_post (msgport, SIGTSTP, 0, cttyid);
+ mach_port_deallocate (mach_task_self (), msgport);
+ }
+ if (pids != pids_)
+ munmap (pids, numpids);
+}
+
+
+kern_return_t
+S_crash_dump_task (mach_port_t port,
+ mach_port_t reply_port, mach_msg_type_name_t reply_type,
+ task_t task, file_t core_file,
+ int signo, int sigcode, int sigerror,
+ natural_t exc, natural_t code, natural_t subcode,
+ mach_port_t ctty_id)
+
+{
+ error_t err;
+ struct trivfs_protid *cred;
+ mach_port_t user_proc = MACH_PORT_NULL;
+ enum crash_action how;
+
+ cred = ports_lookup_port (port_bucket, port, trivfs_protid_portclasses[0]);
+ if (! cred)
+ return EOPNOTSUPP;
+
+ how = crash_how;
+ if (crash_how != crash_orphans_how)
+ {
+ /* We must ascertain if this is an orphan before deciding what to do. */
+ err = proc_task2proc (procserver, task, &user_proc);
+ if (!err)
+ {
+ pid_t pid, ppid;
+ int orphan;
+ err = proc_getpids (user_proc, &pid, &ppid, &orphan);
+ if (!err && orphan)
+ how = crash_orphans_how;
+ }
+ }
+
+ switch (how)
+ {
+ default: /* NOTREACHED */
+ err = EGRATUITOUS;
+ break;
+
+ case crash_suspend:
+ /* Suspend the task first thing before being twiddling it. */
+ err = task_suspend (task);
+ if (err)
+ break;
+
+ if (user_proc != MACH_PORT_NULL)
+ err = proc_task2proc (procserver, task, &user_proc);
+ if (! err)
+ {
+ struct crasher *c;
+
+ err = ports_create_port (crasher_portclass, port_bucket,
+ sizeof *c, &c);
+ if (! err)
+ {
+ mach_port_t msgport;
+
+ stop_pgrp (user_proc, ctty_id);
+
+ /* Install our port as the crasher's msgport.
+ We will wait for signals to resume (crash) it. */
+ msgport = ports_get_right (c);
+ mach_port_insert_right (mach_task_self (), msgport,
+ msgport, MACH_MSG_TYPE_MAKE_SEND);
+ err = proc_setmsgport (user_proc, msgport, &c->original_msgport);
+ mach_port_deallocate (mach_task_self (), msgport);
+
+ c->reply_port = reply_port;
+ c->reply_type = reply_type;
+ if (proc_getsidport (user_proc, &c->sidport))
+ c->sidport = MACH_PORT_NULL;
+ c->proc = user_proc;
+
+ /* Tell the proc server the crasher stopped. */
+ proc_mark_stop (user_proc, signo, sigcode);
+
+ c->task = task;
+ c->core_file = core_file;
+ c->signo = signo;
+ c->sigcode = sigcode;
+ c->sigerror = sigerror;
+
+ err = MIG_NO_REPLY;
+ ports_port_deref (c);
+ }
+ }
+ if (err != MIG_NO_REPLY)
+ task_resume (task);
+ break;
+
+ case crash_corefile:
+ err = task_suspend (task);
+ if (!err)
+ {
+ err = dump_core (task, core_file, signo, sigcode, sigerror);
+ task_resume (task);
+ }
+ break;
+
+ case crash_kill:
+ {
+ if (user_proc != MACH_PORT_NULL)
+ err = 0;
+ else
+ err = proc_task2proc (procserver, task, &user_proc);
+ if (!err)
+ err = proc_mark_exit (user_proc, W_EXITCODE (0, signo), sigcode);
+ err = task_terminate (task);
+ if (!err)
+ {
+ mach_port_deallocate (mach_task_self (), task);
+ mach_port_deallocate (mach_task_self (), core_file);
+ mach_port_deallocate (mach_task_self (), ctty_id);
+ }
+ }
+ }
+
+ if (user_proc != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), user_proc);
+
+ ports_port_deref (cred);
+ return err;
+}
+
+
+
+/* Handle an attempt to send a signal to crashing task C. */
+
+static error_t
+signal_crasher (struct crasher *c, int signo, int sigcode, mach_port_t refport)
+{
+ error_t err;
+
+ if (refport != c->task && (refport != c->sidport || signo != SIGCONT))
+ err = EPERM;
+ else
+ switch (signo)
+ {
+ case SIGTERM:
+ case SIGKILL:
+ /* Kill it as asked. */
+ proc_mark_exit (c->proc, W_EXITCODE (0, signo), sigcode);
+ err = task_terminate (c->task);
+ break;
+
+ case SIGCONT:
+ case SIGQUIT:
+ {
+ /* Resuming the process should make it dump core. */
+
+ mach_port_t old;
+
+ /* First, restore its msg port. */
+ err = proc_setmsgport (c->proc, c->original_msgport, &old);
+ mach_port_deallocate (mach_task_self (), old);
+
+ /* Tell the proc server it has resumed. */
+ proc_mark_cont (c->proc);
+
+ /* Reset the proc server port stored in C, and then destroy the
+ receive right. The null proc port tells dead_crasher to dump
+ a core file. */
+ mach_port_deallocate (mach_task_self (), c->proc);
+ c->proc = MACH_PORT_NULL;
+ ports_destroy_right (c);
+ }
+ break;
+
+ default:
+ err = EBUSY;
+ break;
+ }
+
+ ports_port_deref (c);
+ return err;
+}
+
+kern_return_t
+S_msg_sig_post (mach_port_t port,
+ mach_port_t reply_port, mach_msg_type_name_t reply_type,
+ int signo, natural_t sigcode, mach_port_t refport)
+{
+ struct crasher *c = ports_lookup_port (port_bucket, port, crasher_portclass);
+
+ if (! c)
+ return EOPNOTSUPP;
+
+ return signal_crasher (c, signo, sigcode, refport);
+}
+
+kern_return_t
+S_msg_sig_post_untraced (mach_port_t port,
+ mach_port_t reply_port,
+ mach_msg_type_name_t reply_type,
+ int signo, natural_t sigcode, mach_port_t refport)
+{
+ error_t err;
+ struct crasher *c = ports_lookup_port (port_bucket, port, crasher_portclass);
+
+ if (! c)
+ return EOPNOTSUPP;
+
+ if (signo != 0 && signo != c->signo)
+ return signal_crasher (c, signo, sigcode, refport);
+
+ if (refport != c->task)
+ err = EPERM;
+ else
+ {
+ /* Debugger attaching to the process and continuing it.
+ The debugger is welcome to this crasher, so let's
+ just restore his msgport and forget him. */
+
+ mach_port_t old;
+
+ /* First, restore its msg port. */
+ err = proc_setmsgport (c->proc, c->original_msgport, &old);
+ if (! err)
+ {
+ mach_port_deallocate (mach_task_self (), old);
+
+ /* Tell the proc server it has stopped (again)
+ with the original crash signal. */
+ proc_mark_stop (c->proc, c->signo, c->sigcode);
+
+ /* We don't need to listen on this msgport any more. */
+ ports_destroy_right (c);
+ }
+ }
+
+ ports_port_deref (c);
+ return err;
+}
+
+error_t
+dump_core (task_t task, file_t core_file,
+ int signo, long int sigcode, int sigerror)
+{
+ return ENOSYS; /* XXX */
+}
+
+/* This gets called when the receive right for a crasher message port dies. */
+
+void
+dead_crasher (void *ptr)
+{
+ struct crasher *c = ptr;
+
+ if (c->proc != MACH_PORT_NULL)
+ {
+ /* This message port just died. Clean it up. */
+ mach_port_deallocate (mach_task_self (), c->proc);
+ if (c->reply_port != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), c->reply_port);
+ }
+ else
+ {
+ /* C->proc was cleared in S_msg_sig_post as a marker that
+ this crasher should get a core dump when we clean him up. */
+ error_t err = dump_core (c->task, c->core_file,
+ c->signo, c->sigcode, c->sigerror);
+ /* Now reply to the crasher's original RPC which started this whole
+ party. He should now report his own death (with core dump iff ERR
+ reports successful dumping) to his proc server. */
+ crash_dump_task_reply (c->reply_port, c->reply_type, err);
+ /* Resume the task so it can receive our reply and die happily. */
+ task_resume (c->task);
+ }
+
+ /* Deallocate the other saved ports. */
+ mach_port_deallocate (mach_task_self (), c->original_msgport);
+ mach_port_deallocate (mach_task_self (), c->sidport);
+ mach_port_deallocate (mach_task_self (), c->task);
+ mach_port_deallocate (mach_task_self (), c->core_file);
+ mach_port_deallocate (mach_task_self (), c->sidport);
+
+ /* The port data structures are cleaned up when we return. */
+
+ /* See if we are going away and this was the last thing keeping us up. */
+ if (ports_count_class (trivfs_cntl_portclasses[0]) == 0)
+ {
+ /* We have no fsys control port, so we are detached from the
+ parent filesystem. Maybe we have no users left either. */
+ if (ports_count_class (trivfs_protid_portclasses[0]) == 0)
+ {
+ /* We have no user ports left. Maybe we have no crashers still
+ around either. */
+ if (ports_count_class (crasher_portclass) == 0)
+ /* Nobody talking. Time to die. */
+ exit (0);
+ ports_enable_class (crasher_portclass);
+ }
+ ports_enable_class (trivfs_protid_portclasses[0]);
+ }
+ ports_enable_class (trivfs_cntl_portclasses[0]);
+}
+
+
+static const struct argp_option options[] =
+{
+ {0,0,0,0,"These options specify the disposition of a crashing process:", 1},
+ {"action", 'a', "ACTION", 0, "Action taken on crashing processes", 1},
+ {"orphan-action", 'O', "ACTION", 0, "Action taken on crashing orphans", 1},
+
+ {0,0,0,0,"These options are synonyms for --action=OPTION:", 2},
+ {"suspend", 's', 0, 0, "Suspend the process", 2},
+ {"kill", 'k', 0, 0, "Kill the process", 2},
+ {"core-file", 'c', 0, 0, "Dump a core file", 2},
+ {"dump-core", 0, 0, OPTION_ALIAS },
+ {0}
+};
+static const char doc[] = "\
+Server to handle crashing tasks and dump core files or equivalent.\v\
+The ACTION values can be `suspend', `kill', or `core-file'.\n\
+If --orphan-action is not specified, the --action value is used for orphans.\
+The default is `--action=suspend --orphan-action=core-file'.";
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ error_t parse_action (enum crash_action *how)
+ {
+ if (!strcmp (arg, "suspend"))
+ *how = crash_suspend;
+ else if (!strcmp (arg, "kill"))
+ *how = crash_kill;
+ else if (!strcmp (arg, "core-file"))
+ *how = crash_corefile;
+ else
+ {
+ argp_error (state,
+ "action must be one of: suspend, kill, core-file");
+ return EINVAL;
+ }
+ return 0;
+ }
+
+ switch (opt)
+ {
+ default:
+ return ARGP_ERR_UNKNOWN;
+ case ARGP_KEY_INIT:
+ case ARGP_KEY_ERROR:
+ break;
+
+ case 'a':
+ return parse_action (&crash_how);
+ case 'O':
+ return parse_action (&crash_orphans_how);
+
+ case 's': crash_how = crash_suspend; break;
+ case 'k': crash_how = crash_kill; break;
+ case 'c': crash_how = crash_corefile; break;
+
+ case ARGP_KEY_SUCCESS:
+ if (crash_orphans_how == crash_unspecified)
+ crash_orphans_how = (crash_how == crash_unspecified
+ ? CRASH_ORPHANS_DEFAULT : crash_how);
+ if (crash_how == crash_unspecified)
+ crash_how = CRASH_DEFAULT;
+ break;
+ }
+ return 0;
+}
+
+error_t
+trivfs_append_args (struct trivfs_control *fsys,
+ char **argz, size_t *argz_len)
+{
+ const char *opt;
+
+ switch (crash_how)
+ {
+ case crash_suspend: opt = "--suspend"; break;
+ case crash_kill: opt = "--kill"; break;
+ case crash_corefile:opt = "--core-file"; break;
+ default:
+ return EGRATUITOUS;
+ }
+
+ return argz_add (argz, argz_len, opt);
+}
+
+struct argp crash_argp = { options, parse_opt, doc, 0 };
+struct argp *trivfs_runtime_argp = &crash_argp;
+
+
+static int
+crash_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+ extern int crash_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
+ extern int msg_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
+ return (crash_server (inp, outp) ||
+ msg_server (inp, outp) ||
+ trivfs_demuxer (inp, outp));
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+
+ argp_parse (&crash_argp, argc, argv, 0,0,0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (2, 0, "Must be started as a translator");
+
+ /* Fetch our proc server port for easy use. */
+ procserver = getproc ();
+
+ port_bucket = ports_create_bucket ();
+ trivfs_cntl_portclasses[0] = ports_create_class (trivfs_clean_cntl, 0);
+ trivfs_protid_portclasses[0] = ports_create_class (trivfs_clean_protid, 0);
+ crasher_portclass = ports_create_class (dead_crasher, 0);
+
+ /* Reply to our parent. */
+ err = trivfs_startup (bootstrap, 0,
+ trivfs_cntl_portclasses[0], port_bucket,
+ trivfs_protid_portclasses[0], port_bucket,
+ &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (3, err, "Contacting parent");
+
+ /* Launch. */
+ do
+ ports_manage_port_operations_multithread (port_bucket, crash_demuxer,
+ 10 * 1000, /* idle thread */
+ 10 * 60 * 1000, /* idle server */
+ 0);
+ /* That returns when 10 minutes pass without an RPC. Try shutting down
+ as if sent fsys_goaway; if we have any users who need us to stay
+ around, this returns EBUSY and we loop to service more RPCs. */
+ while (trivfs_goaway (fsys, 0));
+
+ return 0;
+}
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ int count;
+
+ /* Stop new requests. */
+ ports_inhibit_class_rpcs (trivfs_cntl_portclasses[0]);
+ ports_inhibit_class_rpcs (trivfs_protid_portclasses[0]);
+
+ /* Are there any extant user ports for the /servers/crash file? */
+ count = ports_count_class (trivfs_protid_portclasses[0]);
+ if (count == 0 || (flags & FSYS_GOAWAY_FORCE))
+ {
+ /* No users. Disconnect from the filesystem. */
+ mach_port_deallocate (mach_task_self (), fsys->underlying);
+
+ /* Are there any crasher message ports we are listening on? */
+ count = ports_count_class (crasher_portclass);
+ if (count == 0)
+ /* Nope. We got no reason to live. */
+ exit (0);
+
+ /* Continue babysitting crashing tasks we previously suspended. */
+ ports_enable_class (crasher_portclass);
+
+ /* No more communication with the parent filesystem. */
+ ports_destroy_right (fsys);
+
+ return 0;
+ }
+ else
+ {
+ /* We won't go away, so start things going again... */
+ ports_enable_class (trivfs_protid_portclasses[0]);
+ ports_resume_class_rpcs (trivfs_cntl_portclasses[0]);
+ ports_resume_class_rpcs (trivfs_protid_portclasses[0]);
+
+ return EBUSY;
+ }
+}
+
+/* Stubs for unused msgport RPCs. */
+
+kern_return_t
+S_msg_proc_newids (mach_port_t process,
+ mach_port_t task,
+ pid_t ppid,
+ pid_t pgrp,
+ int orphaned)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_add_auth (mach_port_t process,
+ auth_t auth)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_del_auth (mach_port_t process,
+ mach_port_t task,
+ intarray_t uids,
+ mach_msg_type_number_t uidsCnt,
+ intarray_t gids,
+ mach_msg_type_number_t gidsCnt)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_get_init_port (mach_port_t process,
+ mach_port_t refport,
+ int which,
+ mach_port_t *port,
+ mach_msg_type_name_t *portPoly)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_set_init_port (mach_port_t process,
+ mach_port_t refport,
+ int which,
+ mach_port_t port)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_get_init_ports (mach_port_t process,
+ mach_port_t refport,
+ portarray_t *ports,
+ mach_msg_type_name_t *portsPoly,
+ mach_msg_type_number_t *portsCnt)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_set_init_ports (mach_port_t process,
+ mach_port_t refport,
+ portarray_t ports,
+ mach_msg_type_number_t portsCnt)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_get_init_int (mach_port_t process,
+ mach_port_t refport,
+ int which,
+ int *value)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_set_init_int (mach_port_t process,
+ mach_port_t refport,
+ int which,
+ int value)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_get_init_ints (mach_port_t process,
+ mach_port_t refport,
+ intarray_t *values,
+ mach_msg_type_number_t *valuesCnt)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_set_init_ints (mach_port_t process,
+ mach_port_t refport,
+ intarray_t values,
+ mach_msg_type_number_t valuesCnt)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_get_dtable (mach_port_t process,
+ mach_port_t refport,
+ portarray_t *dtable,
+ mach_msg_type_name_t *dtablePoly,
+ mach_msg_type_number_t *dtableCnt)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_set_dtable (mach_port_t process,
+ mach_port_t refport,
+ portarray_t dtable,
+ mach_msg_type_number_t dtableCnt)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_get_fd (mach_port_t process,
+ mach_port_t refport,
+ int fd,
+ mach_port_t *port,
+ mach_msg_type_name_t *portPoly)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_set_fd (mach_port_t process,
+ mach_port_t refport,
+ int fd,
+ mach_port_t port)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_get_environment (mach_port_t process,
+ data_t *value,
+ mach_msg_type_number_t *valueCnt)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_set_environment (mach_port_t process,
+ mach_port_t refport,
+ data_t value,
+ mach_msg_type_number_t valueCnt)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_get_env_variable (mach_port_t process,
+ string_t variable,
+ data_t *value,
+ mach_msg_type_number_t *valueCnt)
+{ return EBUSY; }
+
+kern_return_t
+S_msg_set_env_variable (mach_port_t process,
+ mach_port_t refport,
+ string_t variable,
+ string_t value,
+ boolean_t replace)
+{ return EBUSY; }
+kern_return_t
+S_msg_startup_dosync (mach_port_t process)
+{ return EBUSY; }
+kern_return_t
+S_msg_get_exec_flags (mach_port_t process, mach_port_t refport, int *flags)
+{ return EBUSY; }
+kern_return_t
+S_msg_set_all_exec_flags (mach_port_t process, mach_port_t refport, int flags)
+{ return EBUSY; }
+kern_return_t
+S_msg_set_some_exec_flags (mach_port_t process, mach_port_t refport, int flags)
+{ return EBUSY; }
+kern_return_t
+S_msg_clear_some_exec_flags (mach_port_t process, mach_port_t refport,
+ int flags)
+{ return EBUSY; }
+error_t
+S_msg_report_wait (mach_port_t process, thread_t thread,
+ string_t desc, int *rpc)
+{ return EBUSY; }
+error_t
+S_msg_describe_ports (mach_port_t msgport, mach_port_t refport,
+ mach_port_t *ports, mach_msg_type_number_t nports,
+ char **desc, mach_msg_type_number_t *desclen)
+{ return EBUSY; }
diff --git a/trans/fifo.c b/trans/fifo.c
new file mode 100644
index 00000000..3b62cc21
--- /dev/null
+++ b/trans/fifo.c
@@ -0,0 +1,591 @@
+/* A translator for fifos
+
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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 <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <error.h>
+#include <string.h>
+#include <fcntl.h>
+#include <argp.h>
+
+#include <cthreads.h>
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <hurd/trivfs.h>
+#include <hurd/fsys.h>
+#include <hurd/pipe.h>
+
+#include <version.h>
+
+/* Global options. These defaults are the standard ones, I think... */
+int wait_for_reader = 1, wait_for_writer = 1;
+int one_reader = 1;
+
+/* What kinds of pipes we use. */
+struct pipe_class *fifo_pipe_class;
+
+/* The current fifo that new opens will see, or NULL if there is none. */
+struct pipe *active_fifo = NULL;
+
+/* Lock this when changing ACTIVE_FIFO. */
+struct mutex active_fifo_lock;
+/* Signal this when ACTIVE_FIFO may have changed. */
+struct condition active_fifo_changed;
+
+const char *argp_program_version = STANDARD_HURD_VERSION (null);
+
+static struct argp_option options[] =
+{
+ { "multiple-readers", 'm', 0, 0, "Allow multiple simultaneous readers" },
+ { "noblock", 'n', 0, 0, "Don't block on open" },
+ { "dgram", 'd', 0, 0, "Reads reflect write record boundaries" },
+ { 0 }
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 'm': one_reader = 0; break;
+ case 'n': wait_for_reader = wait_for_writer = 0; break;
+ case 'd': fifo_pipe_class = seqpack_pipe_class; break;
+ default: return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static const struct argp argp = {
+ options, parse_opt, 0, "Translator for fifos"
+};
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+
+ fifo_pipe_class = stream_pipe_class;
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "must be started as a translator");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (3, err, "Contacting parent");
+
+ /* Launch. */
+ do
+ {
+ ports_enable_class (fsys->protid_class);
+ ports_manage_port_operations_multithread (fsys->pi.bucket,
+ trivfs_demuxer,
+ 30*1000, 5*60*1000, 0);
+ }
+ while (ports_count_class (fsys->protid_class) > 0);
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------- */
+
+static error_t
+open_hook (struct trivfs_peropen *po)
+{
+ error_t err = 0;
+ int flags = po->openmodes;
+
+ if (flags & (O_READ | O_WRITE))
+ {
+ mutex_lock (&active_fifo_lock);
+
+/* Wait until the active fifo has changed so that CONDITION is true. */
+#define WAIT(condition, noblock_err) \
+ while (!err && !(condition)) \
+ { \
+ if (flags & O_NONBLOCK) \
+ { \
+ err = noblock_err; \
+ break; \
+ } \
+ else if (hurd_condition_wait (&active_fifo_changed, &active_fifo_lock)) \
+ err = EINTR; \
+ }
+
+ if (flags & O_READ)
+ /* When opening for read, what we do depends on what mode this server
+ is running in. The default (if ONE_READER is set) is to only
+ allow one reader at a time, with additional opens for read
+ blocking here until the old reader goes away; otherwise, we allow
+ multiple readers. If WAIT_FOR_WRITER is true, then once we've
+ created a fifo, we also block until someone opens it for writing;
+ otherwise, the first read will block until someone writes
+ something. */
+ {
+ if (one_reader)
+ /* Wait until there isn't any active fifo, so we can make one. */
+ WAIT (!active_fifo || !active_fifo->readers, EWOULDBLOCK);
+
+ if (!err && active_fifo == NULL)
+ /* No other readers, and indeed, no fifo; make one. */
+ {
+ err = pipe_create (fifo_pipe_class, &active_fifo);
+ if (! err)
+ active_fifo->flags &= ~PIPE_BROKEN; /* Avoid immediate EOF. */
+ }
+ if (!err)
+ {
+ pipe_add_reader (active_fifo);
+ condition_broadcast (&active_fifo_changed);
+ /* We'll unlock ACTIVE_FIFO_LOCK below; the writer code won't
+ make us block because we've ensured that there's a reader
+ for it. */
+
+ if (wait_for_writer)
+ /* Wait until there's a writer. */
+ {
+ WAIT (active_fifo->writers, 0);
+ if (err)
+ /* Back out the new pipe creation. */
+ {
+ pipe_remove_reader (active_fifo);
+ active_fifo = NULL;
+ condition_broadcast (&active_fifo_changed);
+ }
+ }
+ }
+ }
+
+ if (!err && (flags & O_WRITE))
+ /* Open the active_fifo for writing. If WAIT_FOR_READER is true,
+ then we block until there's someone to read what we wrote,
+ otherwise, if there's no fifo, we create one, which we just write
+ into and leave it for someone to read later. */
+ {
+ if (wait_for_reader)
+ /* Wait until there's a fifo to write to. */
+ WAIT (active_fifo && active_fifo->readers, ENXIO);
+ if (!err && active_fifo == NULL)
+ /* No other readers, and indeed, no fifo; make one. */
+ {
+ err = pipe_create (fifo_pipe_class, &active_fifo);
+ if (!err)
+ active_fifo->flags &= ~PIPE_BROKEN;
+ }
+ if (!err)
+ {
+ pipe_add_writer (active_fifo);
+ condition_broadcast (&active_fifo_changed);
+ }
+ }
+
+ po->hook = active_fifo;
+
+ mutex_unlock (&active_fifo_lock);
+ }
+
+ return err;
+}
+
+static void
+close_hook (struct trivfs_peropen *po)
+{
+ int was_active, detach = 0;
+ int flags = po->openmodes;
+ struct pipe *pipe = po->hook;
+
+ if (!pipe)
+ return;
+
+ mutex_lock (&active_fifo_lock);
+ was_active = (active_fifo == pipe);
+
+ if (was_active)
+ /* See if PIPE should cease to be the user-visible face of this fifo. */
+ detach =
+ ((flags & O_READ) && pipe->readers == 1)
+ || ((flags & O_WRITE) && pipe->writers == 1);
+ else
+ /* Let others have their fun. */
+ mutex_unlock (&active_fifo_lock);
+
+ if (flags & O_READ)
+ pipe_remove_reader (pipe);
+ if (flags & O_WRITE)
+ pipe_remove_writer (pipe);
+ /* At this point, PIPE may be gone, so we can't look at it again. */
+
+ if (was_active)
+ {
+ if (detach)
+ active_fifo = NULL;
+ condition_broadcast (&active_fifo_changed);
+ mutex_unlock (&active_fifo_lock);
+ }
+}
+
+/* Trivfs hooks */
+
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 1;
+int trivfs_support_exec = 0;
+
+int trivfs_allow_open = O_READ | O_WRITE;
+
+error_t (*trivfs_peropen_create_hook) (struct trivfs_peropen *) = open_hook;
+void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) = close_hook;
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ struct pipe *pipe = cred->po->hook;
+
+ st->st_mode &= ~S_IFMT;
+ st->st_mode |= S_IFIFO;
+
+ if (pipe)
+ {
+ mutex_lock (&pipe->lock);
+ st->st_size = pipe_readable (pipe, 1);
+ st->st_blocks = st->st_size >> 9;
+ mutex_unlock (&pipe->lock);
+ }
+ else
+ st->st_size = st->st_blocks = 0;
+
+ /* As we try to be clever with large transfers, ask for them. */
+ st->st_blksize = vm_page_size * 16;
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+ error_t err;
+ int force = (flags & FSYS_GOAWAY_FORCE);
+ struct port_bucket *bucket = ((struct port_info *)cntl)->bucket;
+
+ err = ports_inhibit_bucket_rpcs (bucket);
+ if (err == EINTR || (err && !force))
+ return err;
+
+ if (ports_count_class (cntl->protid_class) > 0 && !force)
+ /* Still some opens, and we're not being forced to go away, so don't. */
+ {
+ ports_enable_class (cntl->protid_class);
+ ports_resume_bucket_rpcs (bucket);
+ return EBUSY;
+ }
+
+ exit (0);
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Return objects mapping the data underlying this memory object. If
+ the object can be read then memobjrd will be provided; if the
+ object can be written then memobjwr will be provided. For objects
+ where read data and write data are the same, these objects will be
+ equal, otherwise they will be disjoint. Servers are permitted to
+ implement io_map but not io_map_cntl. Some objects do not provide
+ mapping; they will set none of the ports and return an error. Such
+ objects can still be accessed by io_read and io_write. */
+error_t
+trivfs_S_io_map(struct trivfs_protid *cred,
+ memory_object_t *rdobj,
+ mach_msg_type_name_t *rdtype,
+ memory_object_t *wrobj,
+ mach_msg_type_name_t *wrtype)
+{
+ return EINVAL;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Read data from an IO object. If offset if -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char **data, size_t *data_len,
+ off_t offs, size_t amount)
+{
+ error_t err;
+
+ if (!cred)
+ err = EOPNOTSUPP;
+ else if (!(cred->po->openmodes & O_READ))
+ err = EBADF;
+ else
+ {
+ struct pipe *pipe = cred->po->hook;
+ mutex_lock (&pipe->lock);
+ err = pipe_read (pipe, cred->po->openmodes & O_NONBLOCK, NULL,
+ data, data_len, amount);
+ mutex_unlock (&pipe->lock);
+ }
+
+ return err;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Tell how much data can be read from the object without blocking for
+ a "long time" (this should be the same meaning of "long time" used
+ by the nonblocking flag. */
+error_t
+trivfs_S_io_readable (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ size_t *amount)
+{
+ error_t err;
+
+ if (!cred)
+ err = EOPNOTSUPP;
+ else if (!(cred->po->openmodes & O_READ))
+ err = EBADF;
+ else
+ {
+ struct pipe *pipe = cred->po->hook;
+ mutex_lock (&pipe->lock);
+ *amount = pipe_readable (pipe, 1);
+ mutex_unlock (&pipe->lock);
+ err = 0;
+ }
+
+ return err;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t offset, int whence, off_t *new_offset)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return ESPIPE;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
+ Block until one of the indicated types of i/o can be done "quickly", and
+ return the types that are then available. ID_TAG is returned as passed; it
+ is just for the convenience of the user in matching up reply messages with
+ specific requests sent. */
+error_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ int *select_type, int *tag)
+{
+ struct pipe *pipe;
+ error_t err = 0;
+ int ready = 0;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ pipe = cred->po->hook;
+
+ if (*select_type & SELECT_READ)
+ {
+ if (cred->po->openmodes & O_READ)
+ {
+ mutex_lock (&pipe->lock);
+ if (pipe_wait_readable (pipe, 1, 1) != EWOULDBLOCK)
+ ready |= SELECT_READ; /* Data immediately readable (or error). */
+ mutex_unlock (&pipe->lock);
+ }
+ else
+ ready |= SELECT_READ; /* Error immediately available... */
+ }
+
+ if (*select_type & SELECT_WRITE)
+ {
+ if (cred->po->openmodes & O_WRITE)
+ {
+ mutex_lock (&pipe->lock);
+ if (pipe_wait_writable (pipe, 1) != EWOULDBLOCK)
+ ready |= SELECT_WRITE; /* Data immediately writable (or error). */
+ mutex_unlock (&pipe->lock);
+ }
+ else
+ ready |= SELECT_WRITE; /* Error immediately available... */
+ }
+
+ if (ready)
+ *select_type = ready;
+ else
+ /* Wait for something to change. */
+ {
+ ports_interrupt_self_on_port_death (cred, reply);
+ err = pipe_pair_select (pipe, pipe, select_type, 1);
+ }
+
+ return err;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Write data to an IO object. If offset is -1, write at the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount successfully written is returned in amount. A
+ given user should not have more than one outstanding io_write on an
+ object at a time; servers implement congestion control by delaying
+ responses to io_write. Servers may drop data (returning ENOBUFS)
+ if they recevie more than one write when not prepared for it. */
+error_t
+trivfs_S_io_write (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char *data, size_t data_len,
+ off_t offs, size_t *amount)
+{
+ error_t err;
+
+ if (!cred)
+ err = EOPNOTSUPP;
+ else
+ {
+ int flags = cred->po->openmodes;
+ struct pipe *pipe = cred->po->hook;
+
+ if (!(flags & O_WRITE))
+ err = EBADF;
+ else
+ {
+ mutex_lock (&pipe->lock);
+ err = pipe_write (pipe, flags & O_NONBLOCK, NULL,
+ data, data_len, amount);
+ mutex_unlock (&pipe->lock);
+ }
+ }
+
+ return err;
+}
+
+/* ---------------------------------------------------------------- */
+
+error_t
+trivfs_S_file_set_size (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t size)
+{
+ return size == 0 ? 0 : EINVAL;
+}
+
+/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
+ O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
+ will tell you which of O_READ, O_WRITE, and O_EXEC the object can
+ be used for. The O_ASYNC bit affects icky async I/O; good async
+ I/O is done through io_async which is orthogonal to these calls. */
+
+error_t
+trivfs_S_io_get_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ int *bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ {
+ *bits = cred->po->openmodes;
+ return 0;
+ }
+}
+
+error_t
+trivfs_S_io_set_all_openmodes(struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int mode)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return 0;
+}
+
+error_t
+trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return 0;
+}
+
+error_t
+trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return 0;
+}
+
+/* ---------------------------------------------------------------- */
+/* Get/set the owner of the IO object. For terminals, this affects
+ controlling terminal behavior (see term_become_ctty). For all
+ objects this affects old-style async IO. Negative values represent
+ pgrps. This has nothing to do with the owner of a file (as
+ returned by io_stat, and as used for various permission checks by
+ filesystems). An owner of 0 indicates that there is no owner. */
+
+error_t
+trivfs_S_io_get_owner (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ pid_t *owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ *owner = 0;
+ return 0;
+}
+
+error_t
+trivfs_S_io_mod_owner (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ pid_t owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return EINVAL;
+}
diff --git a/trans/firmlink.c b/trans/firmlink.c
new file mode 100644
index 00000000..de9cd19b
--- /dev/null
+++ b/trans/firmlink.c
@@ -0,0 +1,277 @@
+/* A translator for `firmlinks'
+
+ Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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 <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <argp.h>
+#include <error.h>
+#include <sys/mman.h>
+
+#include <hurd/trivfs.h>
+
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (firmlink);
+
+static const struct argp_option options[] =
+{
+ { 0 }
+};
+
+static const char args_doc[] = "TARGET";
+static const char doc[] = "A translator for firmlinks"
+"\vA firmlink is sort of half-way between a symbolic link and a hard link;"
+"\n"
+"\nLike a symbolic link, it is `by name', and contains no actual reference to"
+" the target. However, the lookup returns a node which will redirect parent"
+" lookups so that attempts to find the cwd that go through the link will"
+" reflect the link name, not the target name. The target referenced by the"
+" firmlink is looked up in the namespace of the translator, not the client.";
+
+/* Link parameters. */
+static char *target = 0; /* What we translate too. */
+
+/* Parse a single option/argument. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ if (key == ARGP_KEY_ARG && state->arg_num == 0)
+ target = arg;
+ else if (key == ARGP_KEY_ARG || key == ARGP_KEY_NO_ARGS)
+ argp_usage (state);
+ else
+ return ARGP_ERR_UNKNOWN;
+ return 0;
+}
+
+static struct argp argp = { options, parse_opt, args_doc, doc };
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+
+ /* Parse our options... */
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "Must be started as a translator");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (2, err, "Contacting parent");
+
+ /* Launch. */
+ ports_manage_port_operations_multithread (fsys->pi.bucket, trivfs_demuxer,
+ 2 * 60 * 1000, 0, 0);
+
+ return 0;
+}
+
+/* Return in LINK the node that TARGET_NAME resolves to, with its parent
+ replaced by PARENT. FLAGS are the flags to open TARGET_NAME with. */
+static error_t
+firmlink (mach_port_t parent, const char *target_name, int flags,
+ mach_port_t *link)
+{
+ error_t err;
+ file_t authed_link;
+ file_t target = file_name_lookup (target_name, flags & ~O_CREAT, 0);
+
+ if (target == MACH_PORT_NULL)
+ return errno;
+
+ err = file_reparent (target, parent, &authed_link);
+ mach_port_deallocate (mach_task_self (), target);
+ mach_port_deallocate (mach_task_self (), parent);
+
+ if (! err)
+ {
+ err = io_restrict_auth (authed_link, link, 0, 0, 0, 0);
+ mach_port_deallocate (mach_task_self (), authed_link);
+ }
+
+ return err;
+}
+
+/* Trivfs hooks */
+
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+
+int trivfs_allow_open = O_READ;
+
+/* Return the root node of our file system: A firmlink to TARGET, unless
+ TARGET doesn't exist, in which case we return a symlink-like node. */
+static error_t
+getroot (struct trivfs_control *cntl,
+ mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
+ mach_port_t dotdot,
+ uid_t *uids, u_int nuids, uid_t *gids, u_int ngids,
+ int flags,
+ retry_type *do_retry, char *retry_name,
+ mach_port_t *node, mach_msg_type_name_t *node_type)
+{
+ error_t err = firmlink (dotdot, target, flags, node);
+
+ if (err == ENOENT)
+ /* No target? Act like a link. */
+ return EAGAIN;
+
+ if (! err)
+ {
+ *node_type = MACH_MSG_TYPE_MOVE_SEND;
+ *do_retry = FS_RETRY_REAUTH;
+ retry_name[0] = '\0';
+ }
+
+ return err;
+}
+
+/* Called by trivfs_S_fsys_getroot before any other processing takes place;
+ if the return value is EAGAIN, normal trivfs getroot processing continues,
+ otherwise the rpc returns with that return value. */
+error_t (*trivfs_getroot_hook) () = getroot;
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ st->st_size = strlen (target);
+ st->st_blocks = 0;
+ st->st_mode &= ~S_IFMT;
+ st->st_mode |= S_IFLNK;
+}
+
+/* Shutdown the filesystem. */
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+ error_t err;
+ int force = (flags & FSYS_GOAWAY_FORCE);
+ struct port_bucket *bucket = ((struct port_info *)cntl)->bucket;
+
+ err = ports_inhibit_bucket_rpcs (bucket);
+ if (err == EINTR || (err && !force))
+ return err;
+
+ if (ports_count_class (cntl->protid_class) > 0 && !force)
+ /* Still some opens, and we're not being forced to go away, so don't. */
+ {
+ ports_enable_class (cntl->protid_class);
+ ports_resume_bucket_rpcs (bucket);
+ return EBUSY;
+ }
+
+ exit (0);
+}
+
+/* We store the file offset in po->hook (ick!) */
+
+/* Read data from an IO object. If offset if -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ vm_address_t *data, mach_msg_type_number_t *data_len,
+ off_t offs, mach_msg_type_number_t amount)
+{
+ error_t err = 0;
+
+ if (! cred)
+ err = EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_READ))
+ err = EBADF;
+ else
+ {
+ off_t max = strlen (target);
+ off_t start = offs >= 0 ? offs : (off_t)cred->po->hook;
+ if (start < 0)
+ return EINVAL;
+ if (start + amount > max)
+ amount = max - start;
+ if (amount > *data_len)
+ *data = (vm_address_t) mmap (0, amount, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ err = (*data == -1) ? errno : 0;
+ if (!err && amount > 0)
+ {
+ memcpy ((char *)(*data + start), target, amount);
+ if (offs < 0)
+ cred->po->hook = (void *)(start + amount); /* Update PO offset. */
+ }
+ *data_len = amount;
+ }
+
+ return err;
+}
+
+/* Tell how much data can be read from the object without blocking for
+ a "long time" (this should be the same meaning of "long time" used
+ by the nonblocking flag. */
+error_t
+trivfs_S_io_readable (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ mach_msg_type_number_t *amount)
+{
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_READ))
+ return EBADF;
+ else if ((off_t)cred->po->hook < 0)
+ return EINVAL;
+ else
+ *amount = strlen (target) - (off_t)cred->po->hook;
+ return 0;
+}
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t offset, int whence, off_t *new_offset)
+{
+ return EOPNOTSUPP;
+}
+
+/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
+ Block until one of the indicated types of i/o can be done "quickly", and
+ return the types that are then available. ID_TAG is returned as passed; it
+ is just for the convenience of the user in matching up reply messages with
+ specific requests sent. */
+error_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ int *type, int *tag)
+{
+ return EOPNOTSUPP;
+}
diff --git a/trans/fwd.c b/trans/fwd.c
new file mode 100644
index 00000000..f30aad1a
--- /dev/null
+++ b/trans/fwd.c
@@ -0,0 +1,51 @@
+/* A translator to start up a central translation server
+
+ Note: most translators that use a central server will look for the server
+ and forward the request to the server if they find one, otherwise doing
+ the translation themselves.
+
+ Copyright (C) 1995, 1998, 1999 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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 <error.h>
+#include <stdio.h>
+#include <hurd/fshelp.h>
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+
+ if (argc < 2 || *argv[1] == '-')
+ {
+ fprintf (stderr, "Usage: %s SERVER [TRANS_NAME [TRANS_ARG...]]\n",
+ program_invocation_name);
+ return 1;
+ }
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (2, 0, "must be started as a translator");
+
+ err = fshelp_delegate_translation (argv[1], bootstrap, argv + 2);
+ if (err)
+ error (3, err, "%s", argv[1]);
+
+ return 0;
+}
diff --git a/trans/hello-mt.c b/trans/hello-mt.c
new file mode 100644
index 00000000..2aebbba0
--- /dev/null
+++ b/trans/hello-mt.c
@@ -0,0 +1,316 @@
+/* hello-mt.c - A trivial single-file translator, multithreaded version
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#define _GNU_SOURCE 1
+
+#include <hurd/trivfs.h>
+#include <stdio.h>
+#include <argp.h>
+#include <argz.h>
+#include <error.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <cthreads.h>
+#include <rwlock.h>
+
+/* The message we return when we are read. */
+static const char hello[] = "Hello, world!\n";
+static char *contents = (char *) hello;
+static size_t contents_len = sizeof hello - 1;
+
+/* This lock protects access to contents and contents_len. */
+static struct rwlock contents_lock;
+
+/* Trivfs hooks. */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+
+int trivfs_allow_open = O_READ;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+
+/* NOTE: This example is not robust: it is possible to trigger some
+ assertion failures because we don't implement the following:
+
+ $ cd /src/hurd/libtrivfs
+ $ grep -l 'assert.*!trivfs_support_read' *.c |
+ xargs grep '^trivfs_S_' | sed 's/^[^:]*:\([^ ]*\).*$/\1/'
+ trivfs_S_io_get_openmodes
+ trivfs_S_io_clear_some_openmodes
+ trivfs_S_io_set_some_openmodes
+ trivfs_S_io_set_all_openmodes
+ trivfs_S_io_readable
+ trivfs_S_io_select
+ $
+
+ For that reason, you should run this as an active translator
+ `settrans -ac testnode /path/to/thello' so that you can see the
+ error messages when they appear. */
+
+/* A hook for us to keep track of the file descriptor state. */
+struct open
+{
+ struct mutex lock;
+ off_t offs;
+};
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ /* Mark the node as a read-only plain file. */
+ st->st_mode &= ~(S_IFMT | ALLPERMS);
+ st->st_mode |= (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH);
+ st->st_size = contents_len; /* No need to lock for reading one word. */
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+ exit (0);
+}
+
+
+static error_t
+open_hook (struct trivfs_peropen *peropen)
+{
+ struct open *op = malloc (sizeof (struct open));
+ if (op == NULL)
+ return ENOMEM;
+
+ /* Initialize the offset. */
+ op->offs = 0;
+ mutex_init (&op->lock);
+ peropen->hook = op;
+ return 0;
+}
+
+
+static void
+close_hook (struct trivfs_peropen *peropen)
+{
+ struct open *op = peropen->hook;
+
+ mutex_clear (&op->lock);
+ free (op);
+}
+
+
+/* Read data from an IO object. If offset is -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMOUNT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ vm_address_t *data, mach_msg_type_number_t *data_len,
+ off_t offs, mach_msg_type_number_t amount)
+{
+ struct open *op;
+
+ /* Deny access if they have bad credentials. */
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_READ))
+ return EBADF;
+
+ op = cred->po->hook;
+
+ mutex_lock (&op->lock);
+
+ /* Get the offset. */
+ if (offs == -1)
+ offs = op->offs;
+
+ rwlock_reader_lock (&contents_lock);
+
+ /* Prune the amount they want to read. */
+ if (offs > contents_len)
+ offs = contents_len;
+ if (offs + amount > contents_len)
+ amount = contents_len - offs;
+
+ if (amount > 0)
+ {
+ /* Possibly allocate a new buffer. */
+ if (*data_len < amount)
+ *data = (vm_address_t) mmap (0, amount, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+
+ /* Copy the constant data into the buffer. */
+ memcpy ((char *) *data, contents + offs, amount);
+
+ /* Update the saved offset. */
+ op->offs += amount;
+ }
+
+ mutex_unlock (&op->lock);
+
+ rwlock_reader_unlock (&contents_lock);
+
+ *data_len = amount;
+ return 0;
+}
+
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t offs, int whence, off_t *new_offs)
+{
+ struct open *op;
+ error_t err = 0;
+ if (! cred)
+ return EOPNOTSUPP;
+
+ op = cred->po->hook;
+
+ mutex_lock (&op->lock);
+
+ switch (whence)
+ {
+ case SEEK_SET:
+ op->offs = offs; break;
+ case SEEK_CUR:
+ op->offs += offs; break;
+ case SEEK_END:
+ op->offs = contents_len - offs; break;
+ default:
+ err = EINVAL;
+ }
+
+ if (! err)
+ *new_offs = op->offs;
+
+ mutex_unlock (&op->lock);
+
+ return err;
+}
+
+
+/* If this variable is set, it is called every time a new peropen
+ structure is created and initialized. */
+error_t (*trivfs_peropen_create_hook)(struct trivfs_peropen *) = open_hook;
+
+/* If this variable is set, it is called every time a peropen structure
+ is about to be destroyed. */
+void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) = close_hook;
+
+
+/* Options processing. We accept the same options on the command line
+ and from fsys_set_options. */
+
+static const struct argp_option options[] =
+{
+ {"contents", 'c', "STRING", 0, "Specify the contents of the virtual file"},
+ {0}
+};
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ switch (opt)
+ {
+ default:
+ return ARGP_ERR_UNKNOWN;
+ case ARGP_KEY_INIT:
+ case ARGP_KEY_SUCCESS:
+ case ARGP_KEY_ERROR:
+ break;
+
+ case 'c':
+ {
+ char *new = strdup (arg);
+ if (new == NULL)
+ return ENOMEM;
+ rwlock_writer_lock (&contents_lock);
+ if (contents != hello)
+ free (contents);
+ contents = new;
+ contents_len = strlen (new);
+ rwlock_writer_unlock (&contents_lock);
+ break;
+ }
+ }
+ return 0;
+}
+
+/* This will be called from libtrivfs to help construct the answer
+ to an fsys_get_options RPC. */
+error_t
+trivfs_append_args (struct trivfs_control *fsys,
+ char **argz, size_t *argz_len)
+{
+ error_t err;
+ char *opt;
+
+ rwlock_reader_lock (&contents_lock);
+ err = asprintf (&opt, "--contents=%s", contents) < 0 ? ENOMEM : 0;
+ rwlock_reader_unlock (&contents_lock);
+
+ if (!err)
+ {
+ err = argz_add (argz, argz_len, opt);
+ free (opt);
+ }
+
+ return err;
+}
+
+static struct argp hello_argp = { options, parse_opt, 0, 0 };
+
+/* Setting this variable makes libtrivfs use our argp to
+ parse options passed in an fsys_set_options RPC. */
+struct argp *trivfs_runtime_argp = &hello_argp;
+
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+
+ /* Initialize the lock that will protect CONTENTS and CONTENTS_LEN.
+ We must do this before argp_parse, because parse_opt (above) will
+ use the lock. */
+ rwlock_init (&contents_lock);
+
+ /* We use the same argp for options available at startup
+ as for options we'll accept in an fsys_set_options RPC. */
+ argp_parse (&hello_argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "Must be started as a translator");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (3, err, "trivfs_startup");
+
+ /* Launch. */
+ ports_manage_port_operations_multithread (fsys->pi.bucket, trivfs_demuxer,
+ 10 * 1000, /* idle thread */
+ 10 * 60 * 1000, /* idle server */
+ 0);
+
+ return 0;
+}
diff --git a/trans/hello.c b/trans/hello.c
new file mode 100644
index 00000000..d1657dda
--- /dev/null
+++ b/trans/hello.c
@@ -0,0 +1,279 @@
+/* hello.c - A trivial single-file translator
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ Gordon Matzigkeit <gord@fig.org>, 1999
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#define _GNU_SOURCE 1
+
+#include <hurd/trivfs.h>
+#include <stdio.h>
+#include <argp.h>
+#include <argz.h>
+#include <error.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+/* The message we return when we are read. */
+static const char hello[] = "Hello, world!\n";
+static char *contents = (char *) hello;
+static size_t contents_len = sizeof hello - 1;
+
+/* Trivfs hooks. */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+
+int trivfs_allow_open = O_READ;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+
+/* NOTE: This example is not robust: it is possible to trigger some
+ assertion failures because we don't implement the following:
+
+ $ cd /src/hurd/libtrivfs
+ $ grep -l 'assert.*!trivfs_support_read' *.c |
+ xargs grep '^trivfs_S_' | sed 's/^[^:]*:\([^ ]*\).*$/\1/'
+ trivfs_S_io_get_openmodes
+ trivfs_S_io_clear_some_openmodes
+ trivfs_S_io_set_some_openmodes
+ trivfs_S_io_set_all_openmodes
+ trivfs_S_io_readable
+ trivfs_S_io_select
+ $
+
+ For that reason, you should run this as an active translator
+ `settrans -ac testnode /path/to/thello' so that you can see the
+ error messages when they appear. */
+
+/* A hook for us to keep track of the file descriptor state. */
+struct open
+{
+ off_t offs;
+};
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ /* Mark the node as a read-only plain file. */
+ st->st_mode &= ~(S_IFMT | ALLPERMS);
+ st->st_mode |= (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH);
+ st->st_size = contents_len;
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+ exit (0);
+}
+
+
+static error_t
+open_hook (struct trivfs_peropen *peropen)
+{
+ struct open *op = malloc (sizeof (struct open));
+ if (op == NULL)
+ return ENOMEM;
+
+ /* Initialize the offset. */
+ op->offs = 0;
+ peropen->hook = op;
+ return 0;
+}
+
+
+static void
+close_hook (struct trivfs_peropen *peropen)
+{
+ free (peropen->hook);
+}
+
+
+/* Read data from an IO object. If offset is -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMOUNT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ vm_address_t *data, mach_msg_type_number_t *data_len,
+ off_t offs, mach_msg_type_number_t amount)
+{
+ struct open *op;
+
+ /* Deny access if they have bad credentials. */
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_READ))
+ return EBADF;
+
+ /* Get the offset. */
+ op = cred->po->hook;
+ if (offs == -1)
+ offs = op->offs;
+
+ /* Prune the amount they want to read. */
+ if (offs > contents_len)
+ offs = contents_len;
+ if (offs + amount > contents_len)
+ amount = contents_len - offs;
+
+ if (amount > 0)
+ {
+ /* Possibly allocate a new buffer. */
+ if (*data_len < amount)
+ *data = (vm_address_t) mmap (0, amount, PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+
+ /* Copy the constant data into the buffer. */
+ memcpy ((char *) *data, contents + offs, amount);
+
+ /* Update the saved offset. */
+ op->offs += amount;
+ }
+
+ *data_len = amount;
+ return 0;
+}
+
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t offs, int whence, off_t *new_offs)
+{
+ struct open *op;
+ error_t err = 0;
+ if (! cred)
+ return EOPNOTSUPP;
+
+ op = cred->po->hook;
+ switch (whence)
+ {
+ case SEEK_SET:
+ op->offs = offs; break;
+ case SEEK_CUR:
+ op->offs += offs; break;
+ case SEEK_END:
+ op->offs = contents_len - offs; break;
+ default:
+ err = EINVAL;
+ }
+
+ if (! err)
+ *new_offs = op->offs;
+
+ return err;
+}
+
+
+/* If this variable is set, it is called every time a new peropen
+ structure is created and initialized. */
+error_t (*trivfs_peropen_create_hook)(struct trivfs_peropen *) = open_hook;
+
+/* If this variable is set, it is called every time a peropen structure
+ is about to be destroyed. */
+void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) = close_hook;
+
+
+/* Options processing. We accept the same options on the command line
+ and from fsys_set_options. */
+
+static const struct argp_option options[] =
+{
+ {"contents", 'c', "STRING", 0, "Specify the contents of the virtual file"},
+ {0}
+};
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ switch (opt)
+ {
+ default:
+ return ARGP_ERR_UNKNOWN;
+ case ARGP_KEY_INIT:
+ case ARGP_KEY_SUCCESS:
+ case ARGP_KEY_ERROR:
+ break;
+
+ case 'c':
+ {
+ char *new = strdup (arg);
+ if (new == NULL)
+ return ENOMEM;
+ if (contents != hello)
+ free (contents);
+ contents = new;
+ contents_len = strlen (new);
+ break;
+ }
+ }
+ return 0;
+}
+
+/* This will be called from libtrivfs to help construct the answer
+ to an fsys_get_options RPC. */
+error_t
+trivfs_append_args (struct trivfs_control *fsys,
+ char **argz, size_t *argz_len)
+{
+ error_t err;
+ char *opt;
+
+ if (asprintf (&opt, "--contents=%s", contents) < 0)
+ return ENOMEM;
+
+ err = argz_add (argz, argz_len, opt);
+
+ free (opt);
+
+ return err;
+}
+
+static struct argp hello_argp = { options, parse_opt, 0, 0 };
+
+/* Setting this variable makes libtrivfs use our argp to
+ parse options passed in an fsys_set_options RPC. */
+struct argp *trivfs_runtime_argp = &hello_argp;
+
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+
+ /* We use the same argp for options available at startup
+ as for options we'll accept in an fsys_set_options RPC. */
+ argp_parse (&hello_argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "Must be started as a translator");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (3, err, "trivfs_startup");
+
+ /* Launch. */
+ ports_manage_port_operations_one_thread (fsys->pi.bucket, trivfs_demuxer, 0);
+
+ return 0;
+}
diff --git a/trans/ifsock.c b/trans/ifsock.c
new file mode 100644
index 00000000..15fb7df3
--- /dev/null
+++ b/trans/ifsock.c
@@ -0,0 +1,134 @@
+/* Server for S_IFSOCK nodes
+ Copyright (C) 1994, 1995 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 <hurd.h>
+#include <hurd/ports.h>
+#include <hurd/trivfs.h>
+#include <hurd/paths.h>
+#include <sys/socket.h>
+#include <hurd/socket.h>
+#include <hurd/fsys.h>
+#include <stdio.h>
+#include <error.h>
+#include <fcntl.h>
+
+#include "ifsock_S.h"
+
+mach_port_t address_port;
+
+struct port_class *control_class;
+struct port_class *node_class;
+struct port_bucket *port_bucket;
+
+int trivfs_fstype = FSTYPE_IFSOCK;
+int trivfs_fsid = 0; /* ??? */
+
+int trivfs_support_read = 0;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+
+int trivfs_allow_open = 0;
+
+struct port_class *trivfs_protid_portclasses[1];
+struct port_class *trivfs_cntl_portclasses[1];
+int trivfs_protid_nportclasses = 1;
+int trivfs_cntl_nportclasses = 1;
+
+int
+demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+ extern int ifsock_server (mach_msg_header_t *, mach_msg_header_t *);
+ return trivfs_demuxer (inp, outp) || ifsock_server (inp, outp);
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t pflocal;
+ mach_port_t bootstrap;
+ char buf[512];
+
+ control_class = ports_create_class (trivfs_clean_cntl, 0);
+ node_class = ports_create_class (trivfs_clean_protid, 0);
+ port_bucket = ports_create_bucket ();
+ trivfs_protid_portclasses[0] = node_class;
+ trivfs_cntl_portclasses[0] = control_class;
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error(1, 0, "Must be started as a translator");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, control_class, port_bucket,
+ node_class, port_bucket, NULL);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error(2, err, "Contacting parent");
+
+ /* Try and connect to the pflocal server */
+ sprintf (buf, "%s/%d", _SERVERS_SOCKET, PF_LOCAL);
+ pflocal = file_name_lookup (buf, 0, 0);
+
+ if (pflocal == MACH_PORT_NULL)
+ address_port = MACH_PORT_NULL;
+ else
+ {
+ errno = socket_fabricate_address (pflocal, AF_LOCAL, &address_port);
+ if (errno)
+ address_port = MACH_PORT_NULL;
+ mach_port_deallocate (mach_task_self (), pflocal);
+ }
+
+ /* Launch. */
+ ports_manage_port_operations_one_thread (port_bucket, demuxer, 0);
+ return 0;
+}
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ st->st_mode = (st->st_mode & ~S_IFMT) | S_IFSOCK;
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ exit (0);
+}
+
+error_t
+S_ifsock_getsockaddr (file_t sockfile,
+ mach_port_t *address)
+{
+ struct trivfs_protid *cred = ports_lookup_port (port_bucket, sockfile,
+ node_class);
+ int perms;
+ error_t err;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ err = file_check_access (cred->realnode, &perms);
+ if (!err && !(perms & O_READ))
+ err = EACCES;
+
+ if (!err)
+ *address = address_port;
+ ports_port_deref (cred);
+ return err;
+}
diff --git a/trans/magic.c b/trans/magic.c
new file mode 100644
index 00000000..680e88e1
--- /dev/null
+++ b/trans/magic.c
@@ -0,0 +1,367 @@
+/* A translator for returning FS_RETRY_MAGIC strings.
+
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+ 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 <hurd.h>
+#include <hurd/ports.h>
+#include <hurd/trivfs.h>
+#include <hurd/fsys.h>
+#include <version.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <error.h>
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <argp.h>
+#include <argz.h>
+#include <assert.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (magic);
+static char args_doc[] = "MAGIC";
+static char doc[] = "A translator that returns the magic retry result MAGIC";
+static const struct argp_option options[] =
+{
+ {"directory", 'd', 0, 0, "Provide virtual (empty) directory node"},
+ {0}
+};
+
+/* The magic string we return for lookups. */
+static char *magic;
+
+static int directory; /* --directory flag */
+
+/* Pre-fab contents of dummy directory for dir_readdir.
+ Set up only under --directory. */
+static void *dirbuf;
+static size_t dirbufsize;
+
+/* Trivfs hooks */
+
+int trivfs_fstype = FSTYPE_DEV;
+int trivfs_fsid = 0;
+
+int trivfs_support_read = 0;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+
+int trivfs_allow_open = O_READ;
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ st->st_size = dirbufsize;
+ st->st_blocks = getpagesize () / S_BLKSIZE;
+
+ st->st_mode = ((st->st_mode & ~S_IFMT & ~ALLPERMS)
+ | S_IFDIR | S_IXUSR|S_IXGRP|S_IXOTH
+ | (st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH)));
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ exit (0);
+}
+
+
+/* This hook is used when running without --directory;
+ it circumvents basically all the trivfs machinery. */
+
+static error_t
+magic_getroot (struct trivfs_control *cntl,
+ mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type,
+ mach_port_t dotdot,
+ uid_t *uids, u_int nuids, uid_t *gids, u_int ngids,
+ int flags,
+ retry_type *do_retry, char *retry_name,
+ mach_port_t *node, mach_msg_type_name_t *node_type)
+{
+ strcpy (retry_name, magic);
+ *do_retry = FS_RETRY_MAGICAL;
+ *node = MACH_PORT_NULL;
+ *node_type = MACH_MSG_TYPE_COPY_SEND;
+ return 0;
+}
+
+/* This hook is used when running with --directory, when
+ we do use all the normal trivfs machinery. We just use
+ the normal trivfs open, but then stash the DOTDOT port
+ in the trivfs_peropen. */
+
+static error_t
+magic_open (struct trivfs_control *cntl,
+ struct iouser *user,
+ mach_port_t dotdot,
+ int flags,
+ mach_port_t realnode,
+ struct trivfs_protid **cred)
+{
+ error_t err = trivfs_open (cntl, user, flags, realnode, cred);
+ if (!err)
+ {
+ (*cred)->po->hook = (void *) dotdot;
+ err = mach_port_mod_refs (mach_task_self (), dotdot,
+ MACH_PORT_RIGHT_SEND, +1);
+ assert_perror (err);
+ err = mach_port_deallocate (mach_task_self (), dotdot);
+ assert_perror (err);
+ }
+ return err;
+}
+
+
+/* Do a directory lookup. */
+
+error_t
+trivfs_S_dir_lookup (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char *name,
+ int flags,
+ mode_t mode,
+ retry_type *retry_type,
+ char *retry_name,
+ mach_port_t *retrypt,
+ mach_msg_type_name_t *retrypt_type)
+{
+ int perms;
+ error_t err;
+ struct trivfs_protid *newcred;
+ mach_port_t dotdot;
+ struct iouser *user;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (name[0] != '\0')
+ {
+ if (!directory)
+ return ENOTDIR;
+ else
+ {
+ /* We have a real lookup in the dummy directory.
+ Handle `.' and `..' specially, and anything else
+ gets redirected to the magical retry. */
+
+ while (*name == '/')
+ ++name;
+ while (!strncmp (name, "./", 2))
+ {
+ name += 2;
+ while (*name == '/')
+ ++name;
+ }
+
+ if (!strcmp (name, "..") || !strncmp (name, "../", 3))
+ {
+ name += 2;
+ while (*name == '/')
+ ++name;
+ strcpy (retry_name, name);
+ *retry_type = FS_RETRY_REAUTH;
+ *retrypt = (mach_port_t) cred->po->hook;
+ *retrypt_type = MACH_MSG_TYPE_COPY_SEND;
+ return 0;
+ }
+ else if (name[0] != '\0' && strcmp (name, "."))
+ {
+ char *p = stpcpy (retry_name, magic);
+ *p++ = '/';
+ strcpy (p, name);
+ *retry_type = FS_RETRY_MAGICAL;
+ *retrypt = MACH_PORT_NULL;
+ *retrypt_type = MACH_MSG_TYPE_COPY_SEND;
+ return 0;
+ }
+ }
+ }
+
+ /* This is a null-pathname "reopen" call; do the right thing. */
+
+ /* Burn off flags we don't actually implement */
+ flags &= O_HURD;
+ flags &= ~(O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS);
+
+ /* Validate permissions */
+ if (! trivfs_check_access_hook)
+ file_check_access (cred->realnode, &perms);
+ else
+ (*trivfs_check_access_hook) (cred->po->cntl, cred->user,
+ cred->realnode, &perms);
+ if ((flags & (O_READ|O_WRITE|O_EXEC) & perms)
+ != (flags & (O_READ|O_WRITE|O_EXEC)))
+ return EACCES;
+
+ /* Execute the open */
+
+ dotdot = (mach_port_t) cred->po->hook;
+ user = iohelp_dup_iouser (cred->user);
+ err = magic_open (cred->po->cntl, user, dotdot, flags,
+ cred->realnode, &newcred);
+ if (err)
+ {
+ iohelp_free_iouser (user);
+ return err;
+ }
+ err = mach_port_mod_refs (mach_task_self (), dotdot,
+ MACH_PORT_RIGHT_SEND, +1);
+ assert_perror (err);
+ err = mach_port_mod_refs (mach_task_self (), cred->realnode,
+ MACH_PORT_RIGHT_SEND, +1);
+ assert_perror (err);
+
+ *retry_type = FS_RETRY_NORMAL;
+ *retry_name = '\0';
+ *retrypt = ports_get_right (newcred);
+ *retrypt_type = MACH_MSG_TYPE_MAKE_SEND;
+ ports_port_deref (newcred);
+ return 0;
+}
+
+error_t
+trivfs_S_dir_readdir (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char **data,
+ u_int *datalen,
+ boolean_t *data_dealloc,
+ int entry,
+ int nentries,
+ vm_size_t bufsiz,
+ int *amount)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+
+ if (entry > 0)
+ {
+ void *p;
+ int i;
+ i = 0;
+ for (p = dirbuf; p < dirbuf + dirbufsize;
+ p += ((struct dirent *) p)->d_reclen)
+ if (++i == entry)
+ break;
+ *data = p;
+ *datalen = dirbuf + dirbufsize - p;
+ *amount = 2 - entry;
+ }
+ else
+ {
+ *data = dirbuf;
+ *datalen = dirbufsize;
+ *amount = 2;
+ }
+
+ *data_dealloc = 0;
+ return 0;
+}
+
+
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ switch (opt)
+ {
+ case 'd':
+ directory = 1;
+ return 0;
+
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+ return EINVAL;
+
+ case ARGP_KEY_ARGS:
+ if (state->next != state->argc - 1)
+ {
+ argp_usage (state);
+ return EINVAL;
+ }
+ else
+ {
+ magic = state->argv[state->next];
+ return 0;
+ }
+ break;
+ }
+
+ return ARGP_ERR_UNKNOWN;
+}
+
+error_t
+trivfs_append_args (struct trivfs_control *fsys,
+ char **argz, size_t *argz_len)
+{
+ return ((directory ? argz_add (argz, argz_len, "--directory") : 0)
+ ?: argz_add (argz, argz_len, magic));
+}
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+ struct argp argp = { options, parse_opt, args_doc, doc };
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "Must be started as a translator");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (3, err, "Contacting parent");
+
+ if (directory)
+ {
+ inline struct dirent *add (struct dirent *d, const char *name)
+ {
+ d->d_fileno = 2; /* random */
+ d->d_type = DT_DIR;
+ d->d_namlen = strlen (name);
+ strcpy (d->d_name, name);
+ d->d_name[d->d_namlen] = '\0';
+ d->d_reclen = &d->d_name[d->d_namlen + 1] - (char *) d;
+ d->d_reclen = ((d->d_reclen + __alignof (struct dirent) - 1)
+ & ~(__alignof (struct dirent) - 1));
+ return (struct dirent *) ((char *) d + d->d_reclen);
+ }
+ struct dirent *d;
+ dirbuf = mmap (0, getpagesize (), PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ d = add (dirbuf, ".");
+ d = add (d, "..");
+ dirbufsize = (char *) d - (char *) dirbuf;
+
+ trivfs_open_hook = &magic_open;
+ }
+ else
+ trivfs_getroot_hook = &magic_getroot;
+
+ /* Launch. */
+ ports_manage_port_operations_one_thread (fsys->pi.bucket, trivfs_demuxer,
+ 2 * 60 * 1000);
+
+ return 0;
+}
diff --git a/trans/new-fifo.c b/trans/new-fifo.c
new file mode 100644
index 00000000..203a7d4d
--- /dev/null
+++ b/trans/new-fifo.c
@@ -0,0 +1,817 @@
+/* A translator for fifos
+
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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 <stdio.h>
+#include <errno.h>
+#include <argp.h>
+#include <unistd.h>
+#include <error.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#include <cthreads.h>
+#include <hurd.h>
+#include <argz.h>
+#include <hurd/fshelp.h>
+#include <hurd/ports.h>
+#include <hurd/trivfs.h>
+#include <hurd/fsys.h>
+#include <hurd/pipe.h>
+#include <hurd/paths.h>
+
+#define DEFAULT_SERVER _SERVERS "fifo";
+
+struct port_bucket *port_bucket;
+struct port_class *fifo_port_class, *server_port_class, *fsys_port_class;
+
+/* ---------------------------------------------------------------- */
+
+static const struct argp_option options[] =
+{
+ {"multiple-readers", 'r', 0, 0, "Allow multiple simultaneous readers"},
+ {"noblock", 'n', 0, 0, "Don't block on open"},
+ {"dgram", 'd', 0, 0, "Reflect write record boundaries"},
+ {"server", 's', 0, 0, "Operate in server mode"},
+ {"standalone", 'S', 0, 0, "Don't attempt to use a fifo server"},
+ {"use-server", 'U', "NAME",0, "Attempt use server NAME"},
+ {0,0}
+};
+
+/* Per translator variables. */
+struct fifo_trans
+{
+ /* True if this not a real translator, but instead a translator server,
+ which responds to requests to create translators. */
+ int server;
+
+ /* True if opens for writing should hang until there's a reader. */
+ int wait_for_reader;
+ /* True if opens for reading should hang until there's a writer. */
+ int wait_for_writer;
+ /* True if opens for read should hang until there are no other readers. */
+ int one_reader;
+
+ /* If non-null, the name of a fifo server to do the translation in our
+ stead. */
+ char *use_server;
+
+ /* The translator from which this was initialized. */
+ struct fifo_trans *parent;
+
+ /* What kinds of pipes we use. */
+ struct pipe_class *fifo_pipe_class;
+
+ /* The current fifo that new opens will see, or NULL if there is none. */
+ struct pipe *active_fifo;
+ /* Lock this when changing ACTIVE_FIFO. */
+ struct mutex active_fifo_lock;
+ /* Signal this when ACTIVE_FIFO may have changed. */
+ struct condition active_fifo_changed;
+};
+
+/* Return a new FIFO_TRANS in TRANS, initializing it from FROM if it's
+ non-null, where possible. */
+static void
+fifo_trans_create (struct fifo_trans *from, struct fifo_trans **trans)
+{
+ struct fifo_trans *new = malloc (sizeof (struct fifo_trans));
+
+ new->server = 0;
+ mutex_init (&new->active_fifo_lock);
+ condition_init (&new->active_fifo_changed);
+
+ new->parent = from;
+
+ if (from)
+ /* Inherit things that can be inherited. */
+ {
+ new->wait_for_reader = from->wait_for_reader;
+ new->wait_for_writer = from->wait_for_writer;
+ new->one_reader = from->one_reader;
+ new->use_server = from->use_server;
+ new->fifo_pipe_class = from->fifo_pipe_class;
+ }
+ else
+ /* Otherwise just use default values. */
+ {
+ new->wait_for_reader = 1;
+ new->wait_for_writer = 1;
+ new->one_reader = 1;
+ new->use_server = DEFAULT_SERVER;
+ new->fifo_pipe_class = stream_pipe_class;
+ }
+
+ *trans = new;
+}
+
+static void
+fifo_trans_free (struct fifo_trans *trans)
+{
+ free (trans);
+}
+
+static error_t
+fifo_trans_start (struct fifo_trans *trans, mach_port_t requestor)
+{
+ struct trivfs_control *control;
+ struct port_class *class =
+ (trans->server ? server_port_class : fifo_port_class);
+ error_t
+ err = trivfs_startup (requestor, 0,
+ fsys_port_class, port_bucket, class, port_bucket,
+ &control);
+ if (!err)
+ control->hook = trans;
+ return err;
+}
+
+/* Parse our options. SERVER is true if we are a fifo server providing
+ service for others (in which case we don't print error messages). The
+ results of the parse are put into TRANS. */
+static error_t
+fifo_trans_parse_args (struct fifo_trans *trans, int argc, char **argv,
+ int print_errs)
+{
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
+ switch (key)
+ {
+ case 'r': trans->one_reader = 0; break;
+ case 'n': trans->wait_for_reader = trans->wait_for_writer = 0; break;
+ case 'd': trans->fifo_pipe_class = seqpack_pipe_class;
+ case 's': trans->server = 1; break;
+ case 'U': trans->use_server = arg; break;
+ case 'S': trans->use_server = 0; break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+ struct argp argp = {options, parse_opt};
+ return argp_parse (&argp, argc, argv, print_errs ? 0 : ARGP_SILENT, 0, 0);
+}
+
+/* ---------------------------------------------------------------- */
+
+struct port_class *trivfs_protid_portclasses[1];
+struct port_class *trivfs_cntl_portclasses[1];
+int trivfs_protid_nportclasses = 1;
+int trivfs_cntl_nportclasses = 1;
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct fifo_trans *trans;
+ /* Clean up a fsys control node. */
+ void clean_fsys (void *vfsys)
+ {
+ struct trivfs_control *fsys = vfsys;
+ if (fsys->hook)
+ fifo_trans_free (fsys->hook);
+ trivfs_clean_cntl (fsys);
+ }
+
+ fifo_trans_create (0, &trans);
+
+ if (fifo_trans_parse_args (trans, argc, argv, 1) != 0)
+ exit (1);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error(1, 0, "must be started as a translator");
+
+ if (!trans->server && trans->use_server)
+ /* Attempt to contact a fifo server to do our work for us. */
+ {
+ err = fshelp_delegate_translation (trans->use_server, bootstrap, argv);
+ if (!err)
+ exit (0);
+ }
+
+ port_bucket = ports_create_bucket ();
+ fifo_port_class = ports_create_class (trivfs_clean_protid, 0);
+ server_port_class = ports_create_class (trivfs_clean_protid, 0);
+ fsys_port_class = ports_create_class (clean_fsys, 0);
+
+ trivfs_protid_portclasses[0] = fifo_port_class;
+ trivfs_protid_portclasses[1] = server_port_class;
+ trivfs_cntl_portclasses[0] = fsys_port_class;
+
+ /* Reply to our parent */
+ fifo_trans_start (trans, bootstrap);
+
+ /* Launch. */
+ do
+ {
+ ports_enable_class (fifo_port_class);
+ ports_manage_port_operations_multithread (port_bucket,
+ trivfs_demuxer,
+ 30*1000, 5*60*1000, 0);
+ }
+ while (ports_count_class (fifo_port_class) > 0);
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------- */
+
+static error_t
+fifo_trans_open (struct fifo_trans *trans, int flags, void **hook)
+{
+ error_t err = 0;
+
+ if (flags & (O_READ | O_WRITE))
+ {
+ mutex_lock (&trans->active_fifo_lock);
+
+/* Wait until the active fifo has changed so that CONDITION is true. */
+#define WAIT(condition, noblock_err) \
+ while (!err && !(condition)) \
+ { \
+ if (flags & O_NONBLOCK) \
+ { \
+ err = noblock_err; \
+ break; \
+ } \
+ else if (hurd_condition_wait (&trans->active_fifo_changed, \
+ &trans->active_fifo_lock)) \
+ err = EINTR; \
+ }
+
+ if (flags & O_READ)
+ /* When opening for read, what we do depends on what mode this server
+ is running in. The default (if ONE_READER is set) is to only
+ allow one reader at a time, with additional opens for read
+ blocking here until the old reader goes away; otherwise, we allow
+ multiple readers. If WAIT_FOR_WRITER is true, then once we've
+ created a fifo, we also block until someone opens it for writing;
+ otherwise, the first read will block until someone writes
+ something. */
+ {
+ if (trans->one_reader)
+ /* Wait until there isn't any active fifo, so we can make one. */
+ WAIT (!trans->active_fifo || !trans->active_fifo->readers,
+ EWOULDBLOCK);
+ if (!err && trans->active_fifo == NULL)
+ /* No other readers, and indeed, no fifo; make one. */
+ err = pipe_create (trans->fifo_pipe_class, &trans->active_fifo);
+ if (!err)
+ {
+ pipe_add_reader (trans->active_fifo);
+ condition_broadcast (&trans->active_fifo_changed);
+ /* We'll unlock ACTIVE_FIFO_LOCK below; the writer code won't
+ make us block because we've ensured that there's a reader
+ for it. */
+
+ if (trans->wait_for_writer)
+ /* Wait until there's a writer. */
+ {
+ WAIT (trans->active_fifo->writers, 0);
+ if (err)
+ /* Back out the new pipe creation. */
+ {
+ pipe_remove_reader (trans->active_fifo);
+ trans->active_fifo = NULL;
+ condition_broadcast (&trans->active_fifo_changed);
+ }
+ }
+ else
+ /* Otherwise prevent an immediate eof. */
+ trans->active_fifo->flags &= ~PIPE_BROKEN;
+ }
+ }
+
+ if (!err && (flags & O_WRITE))
+ /* Open the trans->active_fifo for writing. If WAIT_FOR_READER is
+ true, then we block until there's someone to read what we wrote,
+ otherwise, if there's no fifo, we create one, which we just write
+ into and leave it for someone to read later. */
+ {
+ if (trans->wait_for_reader)
+ /* Wait until there's a fifo to write to. */
+ WAIT (trans->active_fifo && trans->active_fifo->readers, 0);
+ if (!err && trans->active_fifo == NULL)
+ /* No other readers, and indeed, no fifo; make one. */
+ {
+ err = pipe_create (trans->fifo_pipe_class, &trans->active_fifo);
+ if (!err)
+ trans->active_fifo->flags &= ~PIPE_BROKEN;
+ }
+ if (!err)
+ {
+ pipe_add_writer (trans->active_fifo);
+ condition_broadcast (&trans->active_fifo_changed);
+ }
+ }
+
+ *hook = trans->active_fifo;
+ }
+
+ mutex_unlock (&trans->active_fifo_lock);
+
+ return err;
+}
+
+static void
+fifo_trans_close (struct fifo_trans *trans, struct trivfs_peropen *po)
+{
+ int was_active, going_away = 0;
+ int flags = po->openmodes;
+ struct pipe *pipe = po->hook;
+
+ if (!pipe)
+ return;
+
+ mutex_lock (&trans->active_fifo_lock);
+ was_active = (trans->active_fifo == pipe);
+
+ if (was_active)
+ /* We're the last reader; when we're gone there is no more joy. */
+ going_away = ((flags & O_READ) && pipe->readers == 1);
+ else
+ /* Let others have their fun. */
+ mutex_unlock (&trans->active_fifo_lock);
+
+ if (flags & O_READ)
+ pipe_remove_reader (pipe);
+ if (flags & O_WRITE)
+ pipe_remove_writer (pipe);
+ /* At this point, PIPE may be gone, so we can't look at it again. */
+
+ if (was_active)
+ {
+ if (going_away)
+ trans->active_fifo = NULL;
+ condition_broadcast (&trans->active_fifo_changed);
+ mutex_unlock (&trans->active_fifo_lock);
+ }
+}
+
+static error_t
+open_hook (struct trivfs_peropen *po)
+{
+ struct fifo_trans *trans = po->cntl->hook;
+
+ if (! trans->server)
+ /* We're opening a normal fifo node. */
+ return fifo_trans_open (trans, po->openmodes, &po->hook);
+ else if (po->openmodes & (O_READ|O_WRITE|O_APPEND))
+ return EPERM;
+ else
+ /* We're a fifo server serving a new fifo. */
+ return 0;
+}
+
+static void
+close_hook (struct trivfs_peropen *po)
+{
+ struct fifo_trans *trans = po->cntl->hook;
+
+ if (! trans->server)
+ /* We're closing a normal fifo node. */
+ fifo_trans_close (trans, po);
+}
+
+/* Trivfs hooks */
+
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 1;
+int trivfs_support_exec = 0;
+
+int trivfs_allow_open = O_READ | O_WRITE;
+
+error_t (*trivfs_peropen_create_hook) (struct trivfs_peropen *) = open_hook;
+void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) = close_hook;
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ struct fifo_trans *trans = cred->po->cntl->hook;
+ if (! trans->server)
+ /* A fifo node */
+ {
+ struct pipe *pipe = cred->po->hook;
+
+ st->st_mode &= ~S_IFMT;
+ st->st_mode |= S_IFIFO;
+
+ if (pipe)
+ {
+ mutex_lock (&pipe->lock);
+ st->st_size = pipe_readable (pipe, 1);
+ st->st_blocks = st->st_size >> 9;
+ mutex_unlock (&pipe->lock);
+ }
+ else
+ st->st_size = st->st_blocks = 0;
+
+ /* As we try to be clever with large transfers, ask for them. */
+ st->st_blksize = vm_page_size * 16;
+ }
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ error_t err;
+ int num_opens;
+ int force = flags & FSYS_GOAWAY_FORCE;
+ int unlink = flags & FSYS_GOAWAY_UNLINK;
+ struct fifo_trans *trans = fsys->hook;
+
+ err = ports_inhibit_port_rpcs (fsys);
+ if (err == EINTR || (err && !force))
+ return err;
+
+ num_opens = ports_count_class (fsys->protid_class);
+ if (num_opens > 0 && !force && !unlink)
+ /* Still some opens, and we're not being forced to go away, so don't.*/
+ {
+ ports_enable_class (fsys->protid_class);
+ ports_resume_port_rpcs (fsys);
+ return EBUSY;
+ }
+
+ /* Kill the control connection. */
+ mach_port_deallocate (mach_task_self (), fsys->underlying);
+ fsys->underlying = MACH_PORT_NULL;
+ ports_destroy_right (fsys);
+
+ if (force)
+ /* Kill opens. */
+ {
+ error_t maybe_trash_protid (void *vcred)
+ {
+ struct trivfs_protid *cred = vcred;
+ if (cred->po->cntl == fsys)
+ {
+ ports_destroy_right (cred);
+ ports_interrupt_rpcs (cred);
+ }
+ return 0;
+ }
+ ports_bucket_iterate (((struct port_info *)fsys)->bucket,
+ maybe_trash_protid);
+ }
+
+ if (! trans->parent)
+ /* The root translator, go away, bye bye. */
+ exit (0);
+
+ /* Let things continue; what should die will. */
+ ports_enable_class (fsys->protid_class);
+ ports_resume_port_rpcs (fsys);
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Return objects mapping the data underlying this memory object. If
+ the object can be read then memobjrd will be provided; if the
+ object can be written then memobjwr will be provided. For objects
+ where read data and write data are the same, these objects will be
+ equal, otherwise they will be disjoint. Servers are permitted to
+ implement io_map but not io_map_cntl. Some objects do not provide
+ mapping; they will set none of the ports and return an error. Such
+ objects can still be accessed by io_read and io_write. */
+error_t
+trivfs_S_io_map(struct trivfs_protid *cred,
+ memory_object_t *rdobj,
+ mach_msg_type_name_t *rdtype,
+ memory_object_t *wrobj,
+ mach_msg_type_name_t *wrtype)
+{
+ return EINVAL;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Read data from an IO object. If offset if -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char **data, size_t *data_len,
+ off_t offs, size_t amount)
+{
+ error_t err;
+
+ if (!cred)
+ err = EOPNOTSUPP;
+ else if (!(cred->po->openmodes & O_READ))
+ err = EBADF;
+ else
+ {
+ struct pipe *pipe = cred->po->hook;
+ assert (pipe);
+ mutex_lock (&pipe->lock);
+ err = pipe_read (pipe, cred->po->openmodes & O_NONBLOCK, NULL,
+ data, data_len, amount);
+ mutex_unlock (&pipe->lock);
+ }
+
+ return err;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Tell how much data can be read from the object without blocking for
+ a "long time" (this should be the same meaning of "long time" used
+ by the nonblocking flag. */
+error_t
+trivfs_S_io_readable (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ size_t *amount)
+{
+ error_t err;
+
+ if (!cred)
+ err = EOPNOTSUPP;
+ else if (!(cred->po->openmodes & O_READ))
+ err = EBADF;
+ else
+ {
+ struct pipe *pipe = cred->po->hook;
+ assert (pipe);
+ mutex_lock (&pipe->lock);
+ *amount = pipe_readable (pipe, 1);
+ mutex_unlock (&pipe->lock);
+ err = 0;
+ }
+
+ return err;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t offset, int whence, off_t *new_offset)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ return ESPIPE;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
+ Block until one of the indicated types of i/o can be done "quickly", and
+ return the types that are then available. ID_TAG is returned as passed; it
+ is just for the convenience of the user in matching up reply messages with
+ specific requests sent. */
+error_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ int *select_type, int *tag)
+{
+ struct pipe *pipe;
+ error_t err = 0;
+ int ready = 0;
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ pipe = cred->po->hook;
+
+ if (*select_type & SELECT_READ)
+ {
+ if (cred->po->openmodes & O_READ)
+ {
+ mutex_lock (&pipe->lock);
+ if (pipe_wait_readable (pipe, 1, 1) != EWOULDBLOCK)
+ ready |= SELECT_READ; /* Data immediately readable (or error). */
+ mutex_unlock (&pipe->lock);
+ }
+ else
+ ready |= SELECT_READ; /* Error immediately available... */
+ }
+
+ if (*select_type & SELECT_WRITE)
+ {
+ if (cred->po->openmodes & O_WRITE)
+ {
+ mutex_lock (&pipe->lock);
+ if (pipe_wait_writable (pipe, 1) != EWOULDBLOCK)
+ ready |= SELECT_WRITE; /* Data immediately writable (or error). */
+ mutex_unlock (&pipe->lock);
+ }
+ else
+ ready |= SELECT_WRITE; /* Error immediately available... */
+ }
+
+ if (ready)
+ *select_type = ready;
+ else
+ /* Wait for something to change. */
+ {
+ ports_interrupt_self_on_port_death (cred, reply);
+ err = pipe_pair_select (pipe, pipe, select_type, 1);
+ }
+
+ return err;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Write data to an IO object. If offset is -1, write at the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount successfully written is returned in amount. A
+ given user should not have more than one outstanding io_write on an
+ object at a time; servers implement congestion control by delaying
+ responses to io_write. Servers may drop data (returning ENOBUFS)
+ if they recevie more than one write when not prepared for it. */
+error_t
+trivfs_S_io_write (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ char *data, size_t data_len,
+ off_t offs, size_t *amount)
+{
+ error_t err;
+
+ if (!cred)
+ err = EOPNOTSUPP;
+ else if (!(cred->po->openmodes & O_WRITE))
+ err = EBADF;
+ else
+ {
+ struct pipe *pipe = cred->po->hook;
+ mutex_lock (&pipe->lock);
+ err = pipe_write (pipe, cred->po->openmodes & O_NONBLOCK, NULL,
+ data, data_len, amount);
+ mutex_unlock (&pipe->lock);
+ }
+
+ return err;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Truncate file. */
+error_t
+trivfs_S_file_set_size (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t size)
+{
+ return size == 0 ? 0 : EINVAL;
+}
+
+/* ---------------------------------------------------------------- */
+/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
+ O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
+ will tell you which of O_READ, O_WRITE, and O_EXEC the object can
+ be used for. The O_ASYNC bit affects icky async I/O; good async
+ I/O is done through io_async which is orthogonal to these calls. */
+
+error_t
+trivfs_S_io_get_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ int *bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ {
+ *bits = cred->po->openmodes;
+ return 0;
+ }
+}
+
+error_t
+trivfs_S_io_set_all_openmodes(struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int mode)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return 0;
+}
+
+error_t
+trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return 0;
+}
+
+error_t
+trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return 0;
+}
+
+/* ---------------------------------------------------------------- */
+/* Get/set the owner of the IO object. For terminals, this affects
+ controlling terminal behavior (see term_become_ctty). For all
+ objects this affects old-style async IO. Negative values represent
+ pgrps. This has nothing to do with the owner of a file (as
+ returned by io_stat, and as used for various permission checks by
+ filesystems). An owner of 0 indicates that there is no owner. */
+
+error_t
+trivfs_S_io_get_owner (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t reply_type,
+ pid_t *owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ *owner = 0;
+ return 0;
+}
+
+error_t
+trivfs_S_io_mod_owner (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ pid_t owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return EINVAL;
+}
+
+/* ---------------------------------------------------------------- */
+
+/* Ask SERVER to provide fsys translation service for us. REQUESTOR is
+ the bootstrap port supplied to the original translator, and ARGV are
+ the command line arguments. If the recipient accepts the request, he
+ (or some delegate) should send fsys_startup to REQUESTOR to start the
+ filesystem up. */
+error_t
+trivfs_S_fsys_forward (mach_port_t server,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ mach_port_t requestor,
+ char *argz, size_t argz_len)
+{
+ error_t err;
+ struct fifo_trans *server_trans, *trans;
+ int argc = argz_count (argz, argz_len);
+ char **argv = alloca (sizeof (char *) * (argc + 1));
+ /* SERVER should be our root node. */
+ struct trivfs_protid *cred =
+ ports_lookup_port (port_bucket, server, server_port_class);
+
+ if (!cred)
+ return EOPNOTSUPP;
+
+ server_trans = cred->po->cntl->hook;
+ assert (server_trans->server);
+
+ argz_extract (argz, argz_len, argv);
+
+ /* Make a new translator, inheriting from its server. */
+ fifo_trans_create (server_trans, &trans);
+
+ /* Parse the new arguments to change the defaults. */
+ err = fifo_trans_parse_args (trans, argc, argv, 0);
+
+ if (!err)
+ /* Set our new translator along it's merry way... */
+ fifo_trans_start (trans, requestor);
+
+ ports_port_deref (cred);
+
+ return err;
+}
diff --git a/trans/null.c b/trans/null.c
new file mode 100644
index 00000000..ecec5c94
--- /dev/null
+++ b/trans/null.c
@@ -0,0 +1,318 @@
+/* A translator for providing endless empty space and immediate eof.
+
+ Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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 <hurd.h>
+#include <hurd/ports.h>
+#include <hurd/trivfs.h>
+#include <hurd/fsys.h>
+#include <version.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <error.h>
+#include <string.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <argp.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (null);
+
+/* Error code to return for write attempts.
+ If zero, they succeed in writing to the bitbucket. */
+static error_t write_error_code;
+
+static const struct argp_option options[] =
+{
+ {"full", 'f', 0, 0, "Cause writes to fail as if to a full disk"},
+ {0}
+};
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ switch (opt)
+ {
+ case 'f':
+ write_error_code = ENOSPC;
+ return 0;
+ }
+ return ARGP_ERR_UNKNOWN;
+}
+
+static const struct argp argp =
+{ options, parse_opt, 0, "Endless sink and null source" };
+
+int
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error(1, 0, "Must be started as a translator");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error(3, err, "Contacting parent");
+
+ /* Launch. */
+ ports_manage_port_operations_multithread (fsys->pi.bucket, trivfs_demuxer,
+ 2 * 60 * 1000, 0, 0);
+
+ return 0;
+}
+
+/* Trivfs hooks */
+
+int trivfs_fstype = FSTYPE_DEV;
+int trivfs_fsid = 0;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 1;
+int trivfs_support_exec = 0;
+
+int trivfs_allow_open = O_READ | O_WRITE;
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ st->st_blksize = vm_page_size * 256; /* Make transfers LARRRRRGE */
+
+ st->st_size = 0;
+ st->st_blocks = 0;
+
+ st->st_mode &= ~S_IFMT;
+ st->st_mode |= S_IFCHR;
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ exit (0);
+}
+
+/* Return objects mapping the data underlying this memory object. If
+ the object can be read then memobjrd will be provided; if the
+ object can be written then memobjwr will be provided. For objects
+ where read data and write data are the same, these objects will be
+ equal, otherwise they will be disjoint. Servers are permitted to
+ implement io_map but not io_map_cntl. Some objects do not provide
+ mapping; they will set none of the ports and return an error. Such
+ objects can still be accessed by io_read and io_write. */
+kern_return_t
+trivfs_S_io_map(struct trivfs_protid *cred,
+ memory_object_t *rdobj,
+ mach_msg_type_name_t *rdtype,
+ memory_object_t *wrobj,
+ mach_msg_type_name_t *wrtype)
+{
+ return EINVAL; /* XXX should work! */
+}
+
+/* Read data from an IO object. If offset if -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMT. */
+kern_return_t
+trivfs_S_io_read(struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ vm_address_t *data,
+ mach_msg_type_number_t *datalen,
+ off_t offs,
+ mach_msg_type_number_t amt)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else if (!(cred->po->openmodes & O_READ))
+ return EBADF;
+ else
+ {
+ *datalen = 0;
+ return 0;
+ }
+}
+
+/* Tell how much data can be read from the object without blocking for
+ a "long time" (this should be the same meaning of "long time" used
+ by the nonblocking flag. */
+kern_return_t
+trivfs_S_io_readable (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ mach_msg_type_number_t *amount)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else if (!(cred->po->openmodes & O_READ))
+ return EINVAL;
+ else
+ *amount = 0;
+ return 0;
+}
+
+/* Change current read/write offset */
+kern_return_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ off_t offset, int whence, off_t *new_offset)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ *new_offset = 0;
+ return 0;
+}
+
+/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
+ Block until one of the indicated types of i/o can be done "quickly", and
+ return the types that are then available. ID_TAG is returned as passed; it
+ is just for the convenience of the user in matching up reply messages with
+ specific requests sent. */
+kern_return_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ int *type, int *tag)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else if (((*type & SELECT_READ) && !(cred->po->openmodes & O_READ))
+ || ((*type & SELECT_WRITE) && !(cred->po->openmodes & O_WRITE)))
+ return EBADF;
+ else
+ *type &= ~SELECT_URG;
+ return 0;
+}
+
+/* Write data to an IO object. If offset is -1, write at the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount successfully written is returned in amount. A
+ given user should not have more than one outstanding io_write on an
+ object at a time; servers implement congestion control by delaying
+ responses to io_write. Servers may drop data (returning ENOBUFS)
+ if they recevie more than one write when not prepared for it. */
+kern_return_t
+trivfs_S_io_write (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ vm_address_t data, mach_msg_type_number_t datalen,
+ off_t offs, mach_msg_type_number_t *amt)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else if (!(cred->po->openmodes & O_WRITE))
+ return EBADF;
+ *amt = datalen;
+ return write_error_code;
+}
+
+/* Truncate file. */
+kern_return_t
+trivfs_S_file_set_size (struct trivfs_protid *cred, off_t size)
+{
+ return 0;
+}
+
+/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
+ O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
+ will tell you which of O_READ, O_WRITE, and O_EXEC the object can
+ be used for. The O_ASYNC bit affects icky async I/O; good async
+ I/O is done through io_async which is orthogonal to these calls. */
+
+kern_return_t
+trivfs_S_io_get_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ int *bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ {
+ *bits = cred->po->openmodes;
+ return 0;
+ }
+}
+
+error_t
+trivfs_S_io_set_all_openmodes(struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ int mode)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return 0;
+}
+
+kern_return_t
+trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return 0;
+}
+
+kern_return_t
+trivfs_S_io_clear_some_openmodes (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ int bits)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return 0;
+}
+
+/* Get/set the owner of the IO object. For terminals, this affects
+ controlling terminal behavior (see term_become_ctty). For all
+ objects this affects old-style async IO. Negative values represent
+ pgrps. This has nothing to do with the owner of a file (as
+ returned by io_stat, and as used for various permission checks by
+ filesystems). An owner of 0 indicates that there is no owner. */
+
+kern_return_t
+trivfs_S_io_get_owner (struct trivfs_protid *cred,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ pid_t *owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ *owner = 0;
+ return 0;
+}
+
+kern_return_t
+trivfs_S_io_mod_owner (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ pid_t owner)
+{
+ if (!cred)
+ return EOPNOTSUPP;
+ else
+ return EINVAL;
+}
diff --git a/trans/password.c b/trans/password.c
new file mode 100644
index 00000000..5f87a10f
--- /dev/null
+++ b/trans/password.c
@@ -0,0 +1,224 @@
+/* Hurd standard password server.
+ Copyright (C) 1999 Free Software Foundation
+ Written by Mark Kettenis.
+
+ 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 this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <argp.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hurd.h>
+#include <hurd/auth.h>
+#include <hurd/ports.h>
+#include <hurd/trivfs.h>
+
+#include <ugids.h>
+#include <version.h>
+
+#include "password_S.h"
+
+
+const char *argp_program_version = STANDARD_HURD_VERSION (password);
+
+/* Port bucket we service requests on. */
+struct port_bucket *port_bucket;
+
+/* Trivfs hooks. */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+int trivfs_support_read = 0;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+int trivfs_allow_open = 0;
+
+struct port_class *trivfs_protid_portclasses[1];
+struct port_class *trivfs_cntl_portclasses[1];
+int trivfs_protid_nportclasses = 1;
+int trivfs_cntl_nportclasses = 1;
+
+
+static int
+password_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+ extern int password_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
+ return password_server (inp, outp) || trivfs_demuxer (inp, outp);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+ const struct argp argp = { 0, 0, 0, "Hurd standard password server" };
+
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "must be started as a translator");
+
+ port_bucket = ports_create_bucket ();
+ trivfs_cntl_portclasses[0] = ports_create_class (trivfs_clean_cntl, 0);
+ trivfs_protid_portclasses[0] = ports_create_class (trivfs_clean_protid, 0);
+
+ /* Reply to our parent. */
+ err = trivfs_startup (bootstrap, 0,
+ trivfs_cntl_portclasses[0], port_bucket,
+ trivfs_protid_portclasses[0], port_bucket,
+ &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (3, err, "Contacting parent");
+
+ /* Launch. */
+ do
+ ports_manage_port_operations_multithread (port_bucket, password_demuxer,
+ 2 * 60 * 1000,
+ 10 * 60 * 1000,
+ 0);
+ /* That returns when 10 minutes pass without an RPC. Try shutting down
+ as if sent fsys_goaway; if we have any users who need us to stay
+ around, this returns EBUSY and we loop to service more RPCs. */
+ while (trivfs_goaway (fsys, 0));
+
+ return 0;
+}
+
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ int count;
+
+ /* Stop new requests. */
+ ports_inhibit_class_rpcs (trivfs_cntl_portclasses[0]);
+ ports_inhibit_class_rpcs (trivfs_protid_portclasses[0]);
+
+ /* Are there any extant user ports for the /servers/password file? */
+ count = ports_count_class (trivfs_protid_portclasses[0]);
+ if (count > 0 && !(flags & FSYS_GOAWAY_FORCE))
+ {
+ /* We won't go away, so start things going again... */
+ ports_enable_class (trivfs_protid_portclasses[0]);
+ ports_resume_class_rpcs (trivfs_cntl_portclasses[0]);
+ ports_resume_class_rpcs (trivfs_protid_portclasses[0]);
+
+ return EBUSY;
+ }
+
+ exit (0);
+}
+
+
+/* Implement password_check_user as described in <hurd/password.defs>. */
+kern_return_t
+S_password_check_user (io_t server, uid_t user, char *pw,
+ mach_port_t *port, mach_msg_type_name_t *port_type)
+{
+ struct trivfs_protid *cred;
+ struct ugids ugids = UGIDS_INIT;
+ auth_t auth;
+ error_t err;
+
+ char *getpass (const char *prompt, uid_t id, int is_group,
+ void *pwd_or_group, void *hook)
+ {
+ assert (! is_group && id == user);
+ return strdup (pw);
+ }
+
+ cred = ports_lookup_port (port_bucket, server, trivfs_protid_portclasses[0]);
+ if (! cred)
+ return EOPNOTSUPP;
+
+ /* Verify password. */
+ err = ugids_add_user (&ugids, user, 1);
+ if (!err)
+ err = ugids_verify (&ugids, 0, 0, getpass, 0, 0, 0);
+
+ if (!err)
+ {
+ auth = getauth ();
+ err = auth_makeauth (auth, 0, MACH_MSG_TYPE_COPY_SEND, 0,
+ ugids.eff_uids.ids, ugids.eff_uids.num,
+ ugids.avail_uids.ids, ugids.avail_uids.num,
+ ugids.eff_gids.ids, ugids.eff_gids.num,
+ ugids.avail_gids.ids, ugids.avail_gids.num,
+ port);
+ mach_port_deallocate (mach_task_self (), auth);
+ *port_type = MACH_MSG_TYPE_MOVE_SEND;
+ }
+
+ ugids_fini (&ugids);
+
+ ports_port_deref (cred);
+ return err;
+}
+
+/* Implement password_check_group as described in <hurd/password.defs>. */
+kern_return_t
+S_password_check_group (io_t server, uid_t group, char *pw,
+ mach_port_t *port, mach_msg_type_name_t *port_type)
+{
+ struct trivfs_protid *cred;
+ struct ugids ugids = UGIDS_INIT;
+ auth_t auth;
+ error_t err;
+
+ char *getpass (const char *prompt, uid_t id, int is_group,
+ void *pwd_or_group, void *hook)
+ {
+ assert (is_group && id == group);
+ return strdup (pw);
+ }
+
+ cred = ports_lookup_port (port_bucket, server, trivfs_protid_portclasses[0]);
+ if (! cred)
+ return EOPNOTSUPP;
+
+ /* Verify password. */
+ err = ugids_add_gid (&ugids, group, 1);
+ if (!err)
+ err = ugids_verify (&ugids, 0, 0, getpass, 0, 0, 0);
+
+ if (!err)
+ {
+ auth = getauth ();
+ err = auth_makeauth (auth, 0, MACH_MSG_TYPE_COPY_SEND, 0,
+ ugids.eff_uids.ids, ugids.eff_uids.num,
+ ugids.avail_uids.ids, ugids.avail_uids.num,
+ ugids.eff_gids.ids, ugids.eff_gids.num,
+ ugids.avail_gids.ids, ugids.avail_gids.num,
+ port);
+ mach_port_deallocate (mach_task_self (), auth);
+ *port_type = MACH_MSG_TYPE_MOVE_SEND;
+ }
+
+ ugids_fini (&ugids);
+
+ ports_port_deref (cred);
+ return err;
+}
diff --git a/trans/symlink.c b/trans/symlink.c
new file mode 100644
index 00000000..24a1a30f
--- /dev/null
+++ b/trans/symlink.c
@@ -0,0 +1,197 @@
+/* Translator for S_IFLNK nodes
+ Copyright (C) 1994 Free Software Foundation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <hurd.h>
+#include <stdio.h>
+#include <hurd/fsys.h>
+#include <fcntl.h>
+#include "fsys_S.h"
+
+mach_port_t realnode;
+
+/* We return this for O_NOLINK lookups */
+mach_port_t realnodenoauth;
+
+/* We return this for non O_NOLINK lookups */
+char *linktarget;
+
+extern int fsys_server (mach_msg_header_t *, mach_msg_header_t *);
+
+int
+main (int argc, char **argv)
+{
+ mach_port_t bootstrap;
+ mach_port_t control;
+ error_t error;
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ {
+ fprintf (stderr, "%s must be started as a translator\n", argv[0]);
+ exit (1);
+ }
+
+ if (argc != 2)
+ {
+ fprintf (stderr, "Usage: %s link-target\n", argv[0]);
+ exit (1);
+ }
+
+ linktarget = argv[1];
+
+ /* Reply to our parent */
+ mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &control);
+ error =
+ fsys_startup (bootstrap, 0, control, MACH_MSG_TYPE_MAKE_SEND, &realnode);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (error)
+ {
+ perror ("Starting up translator");
+ exit (1);
+ }
+ io_restrict_auth (realnode, &realnodenoauth, 0, 0, 0, 0);
+ mach_port_deallocate (mach_task_self (), realnode);
+
+ /* Launch */
+ while (1)
+ {
+ /* The timeout here is 10 minutes */
+ error = mach_msg_server_timeout (fsys_server, 0, control,
+ MACH_RCV_TIMEOUT, 1000 * 60 * 10);
+ if (error == MACH_RCV_TIMED_OUT)
+ exit (0);
+ }
+}
+
+error_t
+S_fsys_getroot (mach_port_t fsys_t,
+ mach_port_t dotdotnode,
+ uid_t *uids,
+ u_int nuids,
+ uid_t *gids,
+ u_int ngids,
+ int flags,
+ retry_type *do_retry,
+ char *retry_name,
+ mach_port_t *ret,
+ mach_msg_type_name_t *rettype)
+{
+ if (flags & O_NOLINK)
+ {
+ /* Return our underlying node. */
+ *ret = realnodenoauth;
+ *rettype = MACH_MSG_TYPE_COPY_SEND;
+ *do_retry = FS_RETRY_REAUTH;
+ retry_name[0] = '\0';
+ return 0;
+ }
+ else
+ {
+ /* Return telling the user to follow the link */
+ strcpy (retry_name, linktarget);
+ if (linktarget[0] == '/')
+ {
+ *do_retry = FS_RETRY_MAGICAL;
+ *ret = MACH_PORT_NULL;
+ *rettype = MACH_MSG_TYPE_COPY_SEND;
+ }
+ else
+ {
+ *do_retry = FS_RETRY_REAUTH;
+ *ret = dotdotnode;
+ *rettype = MACH_MSG_TYPE_MOVE_SEND;
+ }
+ }
+ return 0;
+}
+
+error_t
+S_fsys_startup (mach_port_t bootstrap, int flags, mach_port_t control,
+ mach_port_t *real, mach_msg_type_name_t *realtype)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_goaway (mach_port_t control,
+ int flags)
+{
+ exit (0);
+}
+
+error_t
+S_fsys_syncfs (mach_port_t control,
+ int wait,
+ int recurse)
+{
+ return 0;
+}
+
+error_t
+S_fsys_set_options (mach_port_t control,
+ char *data, mach_msg_type_number_t len,
+ int do_children)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_get_options (mach_port_t control,
+ char **data, mach_msg_type_number_t *len)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_getfile (mach_port_t control,
+ uid_t *uids,
+ u_int nuids,
+ uid_t *gids,
+ u_int ngids,
+ char *handle,
+ u_int handllen,
+ mach_port_t *pt,
+ mach_msg_type_name_t *pttype)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_getpriv (mach_port_t control,
+ mach_port_t *host_priv, mach_msg_type_name_t *host_priv_type,
+ mach_port_t *dev_master, mach_msg_type_name_t *dev_master_type,
+ task_t *fs_task, mach_msg_type_name_t *fs_task_type)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_init (mach_port_t control,
+ mach_port_t reply,
+ mach_msg_type_name_t replytype,
+ mach_port_t proc,
+ auth_t auth)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+S_fsys_forward (mach_port_t server, mach_port_t requestor,
+ char *argz, size_t argz_len)
+{
+ return EOPNOTSUPP;
+}