diff options
Diffstat (limited to 'trans')
-rw-r--r-- | trans/ChangeLog | 561 | ||||
-rw-r--r-- | trans/Makefile | 43 | ||||
-rw-r--r-- | trans/bogus-fifo.c | 160 | ||||
-rw-r--r-- | trans/crash.c | 786 | ||||
-rw-r--r-- | trans/fifo.c | 591 | ||||
-rw-r--r-- | trans/firmlink.c | 277 | ||||
-rw-r--r-- | trans/fwd.c | 51 | ||||
-rw-r--r-- | trans/hello-mt.c | 316 | ||||
-rw-r--r-- | trans/hello.c | 279 | ||||
-rw-r--r-- | trans/ifsock.c | 134 | ||||
-rw-r--r-- | trans/magic.c | 367 | ||||
-rw-r--r-- | trans/new-fifo.c | 817 | ||||
-rw-r--r-- | trans/null.c | 318 | ||||
-rw-r--r-- | trans/password.c | 224 | ||||
-rw-r--r-- | trans/symlink.c | 197 |
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; +} |