diff options
Diffstat (limited to 'trans')
-rw-r--r-- | trans/ChangeLog | 396 | ||||
-rw-r--r-- | trans/Makefile | 40 | ||||
-rw-r--r-- | trans/bogus-fifo.c | 1 | ||||
-rw-r--r-- | trans/crash.c | 230 | ||||
-rw-r--r-- | trans/devport.c | 185 | ||||
-rw-r--r-- | trans/fakeroot.c | 925 | ||||
-rw-r--r-- | trans/fifo.c | 97 | ||||
-rw-r--r-- | trans/firmlink.c | 38 | ||||
-rw-r--r-- | trans/fwd.c | 14 | ||||
-rw-r--r-- | trans/hello-mt.c | 331 | ||||
-rw-r--r-- | trans/hello.c | 291 | ||||
-rw-r--r-- | trans/ifsock.c | 38 | ||||
-rw-r--r-- | trans/magic.c | 589 | ||||
-rw-r--r-- | trans/new-fifo.c | 100 | ||||
-rw-r--r-- | trans/null.c | 83 | ||||
-rw-r--r-- | trans/password.c | 224 | ||||
-rw-r--r-- | trans/proxy-defpager.c | 278 | ||||
-rw-r--r-- | trans/streamio.c | 1161 | ||||
-rw-r--r-- | trans/symlink.c | 97 |
19 files changed, 4222 insertions, 896 deletions
diff --git a/trans/ChangeLog b/trans/ChangeLog deleted file mode 100644 index f2fa2ab7..00000000 --- a/trans/ChangeLog +++ /dev/null @@ -1,396 +0,0 @@ -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 index 1e81c5a5..4e6a22dd 100644 --- a/trans/Makefile +++ b/trans/Makefile @@ -1,5 +1,6 @@ -# -# Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation +# +# Copyright (C) 1994, 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2006, 2007, +# 2008 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 @@ -18,23 +19,36 @@ dir := trans makemode := servers -targets = symlink firmlink ifsock magic null fifo new-fifo fwd devport crash -SRCS = ifsock.c symlink.c magic.c null.c fifo.c new-fifo.c fwd.c devport.c \ - crash.c firmlink.c -OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o -HURDLIBS=ports trivfs threads fshelp pipe ihash shouldbeinlibc +targets = symlink firmlink ifsock magic null fifo new-fifo fwd crash \ + password hello hello-mt streamio fakeroot proxy-defpager +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 streamio.c \ + fakeroot.c proxy-defpager.c +OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o \ + crashServer.o crash_replyUser.o msgServer.o \ + default_pagerServer.o default_pagerUser.o \ + device_replyServer.o elfcore.o +HURDLIBS = threads ports netfs trivfs iohelp fshelp pipe ihash shouldbeinlibc +password-LDLIBS = $(LIBCRYPT) include ../Makeconf -symlink magic: fsysServer.o +vpath elfcore.c $(top_srcdir)/exec + +symlink: fsysServer.o ifsock: ifsockServer.o -crash: crashServer.o crash_replyUser.o msgServer.o +crash: crashServer.o crash_replyUser.o msgServer.o elfcore.o +password: passwordServer.o +streamio: device_replyServer.o +proxy-defpager: default_pagerServer.o default_pagerUser.o -crash: ../libports/libports.a ../libtrivfs/libtrivfs.a ../libthreads/libthreads.a ../libfshelp/libfshelp.a +proxy-defpager crash password streamio: ../libthreads/libthreads.a ../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 -null ifsock fifo new-fifo devport firmlink: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a ../libihash/libihash.a +fwd: ../libfshelp/libfshelp.a ../libports/libports.a +hello-mt magic null ifsock fifo new-fifo firmlink: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libthreads/libthreads.a ../libports/libports.a ../libihash/libihash.a +magic: ../libiohelp/libiohelp.a +hello: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a ../libihash/libihash.a +fakeroot: ../libnetfs/libnetfs.a ../libfshelp/libfshelp.a ../libiohelp/libiohelp.a ../libthreads/libthreads.a ../libports/libports.a ../libihash/libihash.a $(targets): ../libshouldbeinlibc/libshouldbeinlibc.a -fwd null ifsock fifo new-fifo devport firmlink: ../libthreads/libthreads.a $(targets): %: %.o diff --git a/trans/bogus-fifo.c b/trans/bogus-fifo.c index 3151dcc8..acad6e4b 100644 --- a/trans/bogus-fifo.c +++ b/trans/bogus-fifo.c @@ -55,6 +55,7 @@ main (int argc, char **argv) /* 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"); diff --git a/trans/crash.c b/trans/crash.c index 5947cb26..4a59d450 100644 --- a/trans/crash.c +++ b/trans/crash.c @@ -1,5 +1,8 @@ /* GNU Hurd standard crash dump server. - Copyright (C) 1995, 1996 Free Software Foundation, Inc. + + Copyright (C) 1995, 1996, 1997, 1999, 2000, 2001, 2002, 2006, 2007 + Free Software Foundation, Inc. + Written by Roland McGrath. This file is part of the GNU Hurd. @@ -23,12 +26,19 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <hurd/trivfs.h> #include <sys/wait.h> #include <error.h> +#include <argp.h> +#include <argz.h> +#include <sys/mman.h> + +#include <version.h> #include "crash_S.h" #include "crash_reply_U.h" #include "msg_S.h" +const char *argp_program_version = STANDARD_HURD_VERSION (crash); + process_t procserver; /* Our proc port, for easy access. */ /* Port bucket we service requests on. */ @@ -49,6 +59,23 @@ 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; + + +/* This is defined in ../exec/elfcore.c, or we could have + different implementations for other formats. */ +extern error_t dump_core (task_t task, file_t file, off_t corelimit, + 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 @@ -67,6 +94,7 @@ struct crasher task_t task; file_t core_file; + off_t core_limit; int signo, sigcode, sigerror; mach_port_t original_msgport; /* Restore on resume. */ @@ -100,7 +128,7 @@ stop_pgrp (process_t userproc, mach_port_t cttyid) err = proc_getpgrppids (userproc, pgrp, &pids, &numpids); if (err) return; - + for (i = 0; i < numpids; i++) if (pids[i] != pid) { @@ -111,7 +139,7 @@ stop_pgrp (process_t userproc, mach_port_t cttyid) mach_port_deallocate (mach_task_self (), msgport); } if (pids != pids_) - vm_deallocate (mach_task_self (), (vm_address_t) pids, numpids); + munmap (pids, numpids); } @@ -119,25 +147,48 @@ 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, + int signo, integer_t 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_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; - /* Suspend the task first thing before being twiddling it. */ - err = task_suspend (task); - - if (! err) + 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; @@ -152,9 +203,7 @@ S_crash_dump_task (mach_port_t port, /* 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); + msgport = ports_get_send_right (c); err = proc_setmsgport (user_proc, msgport, &c->original_msgport); mach_port_deallocate (mach_task_self (), msgport); @@ -169,6 +218,7 @@ S_crash_dump_task (mach_port_t port, c->task = task; c->core_file = core_file; + c->core_limit = (off_t) -1; /* XXX should core limit in RPC */ c->signo = signo; c->sigcode = sigcode; c->sigerror = sigerror; @@ -179,7 +229,40 @@ S_crash_dump_task (mach_port_t port, } if (err != MIG_NO_REPLY) task_resume (task); + break; + + case crash_corefile: + err = task_suspend (task); + if (!err) + { + err = dump_core (task, core_file, + (off_t) -1, /* XXX should get core limit in RPC */ + 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; } @@ -294,13 +377,6 @@ S_msg_sig_post_untraced (mach_port_t port, 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 @@ -319,7 +395,7 @@ dead_crasher (void *ptr) { /* 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, + error_t err = dump_core (c->task, c->core_file, c->core_limit, 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 @@ -358,6 +434,109 @@ dead_crasher (void *ptr) } +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\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) +{ + error_t err; + const char *opt; + + switch (crash_how) + { + case crash_suspend: opt = "--action=suspend"; break; + case crash_kill: opt = "--action=kill"; break; + case crash_corefile: opt = "--action=core-file"; break; + default: + return EGRATUITOUS; + } + err = argz_add (argz, argz_len, opt); + + if (!err) + { + switch (crash_orphans_how) + { + case crash_suspend: opt = "--orphan-action=suspend"; break; + case crash_kill: opt = "--orphan-action=kill"; break; + case crash_corefile: opt = "--orphan-action=core-file"; break; + default: + return EGRATUITOUS; + } + err = argz_add (argz, argz_len, opt); + } + + return err; +} + +struct argp crash_argp = { options, parse_opt, 0, doc }; +struct argp *trivfs_runtime_argp = &crash_argp; + static int crash_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp) @@ -375,6 +554,7 @@ 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) @@ -402,7 +582,7 @@ main (int argc, char **argv) ports_manage_port_operations_multithread (port_bucket, crash_demuxer, 10 * 1000, /* idle thread */ 10 * 60 * 1000, /* idle server */ - 0, MACH_PORT_NULL); + 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. */ @@ -414,7 +594,6 @@ main (int argc, char **argv) void trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st) { - st->st_fstype = FSTYPE_MISC; } error_t @@ -598,9 +777,6 @@ S_msg_set_env_variable (mach_port_t process, 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 @@ -615,7 +791,7 @@ S_msg_clear_some_exec_flags (mach_port_t process, mach_port_t refport, { return EBUSY; } error_t S_msg_report_wait (mach_port_t process, thread_t thread, - string_t desc, int *rpc) + string_t desc, mach_msg_id_t *rpc) { return EBUSY; } error_t S_msg_describe_ports (mach_port_t msgport, mach_port_t refport, diff --git a/trans/devport.c b/trans/devport.c deleted file mode 100644 index a6dfe7f8..00000000 --- a/trans/devport.c +++ /dev/null @@ -1,185 +0,0 @@ -/* A really stupid translator allowing a user to get a device port - - Copyright (C) 1996 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 <error.h> -#include <string.h> - -#include <hurd.h> -#include <hurd/ports.h> -#include <hurd/trivfs.h> -#include <hurd/fsys.h> - -#include <device/device.h> - -static mach_port_t device_master = MACH_PORT_NULL; -static char *device_name = 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; - -void -main (int argc, char **argv) -{ - error_t err; - mach_port_t bootstrap; - struct port_class *control_class; - struct port_class *node_class; - struct port_bucket *port_bucket; - - 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; - - if (argc != 2) - { - fprintf (stderr, "Usage: %s DEVICE-NAME", program_invocation_name); - exit(1); - } - - device_name = argv[1]; - - task_get_bootstrap_port (mach_task_self (), &bootstrap); - if (bootstrap == MACH_PORT_NULL) - error (1, 0, "must be started as a translator"); - - err = get_privileged_ports (0, &device_master); - if (err) - error (2, err, "Can't get device master port"); - - /* Reply to our parent */ - err = trivfs_startup (bootstrap, 0, control_class, port_bucket, - node_class, port_bucket, NULL); - if (err) - error (3, err, "Contacting parent"); - - /* Launch. */ - ports_manage_port_operations_one_thread (port_bucket, trivfs_demuxer, 0); - - exit(0); -} - -/* 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 = 0; - -void -trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st) -{ - 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); -} - -error_t -trivfs_S_file_get_storage_info (struct trivfs_protid *cred, - mach_port_t reply, - mach_msg_type_name_t reply_type, - mach_port_t **ports, - mach_msg_type_name_t *ports_type, - mach_msg_type_number_t *num_ports, - int **ints, mach_msg_type_number_t *num_ints, - off_t **offsets, - mach_msg_type_number_t *num_offsets, - char **data, mach_msg_type_number_t *data_len) -{ - error_t err = 0; - - if (!cred) - err = EOPNOTSUPP; - else - { - /* True when we've allocated memory for the corresponding vector. */ - int al_ports = 0, al_ints = 0, al_offsets = 0, al_data = 0; - size_t name_len = strlen (device_name) + 1; - -#define ENSURE_MEM(v, vl, alp, num) \ - if (!err && *vl < num) \ - { \ - err = vm_allocate (mach_task_self (), \ - (vm_address_t *)v, num * sizeof (**v), 1); \ - if (! err) \ - { \ - *vl = num; \ - alp = 1; \ - } \ - } - - ENSURE_MEM (ports, num_ports, al_ports, 1); - ENSURE_MEM (ints, num_ints, al_ints, 6); - ENSURE_MEM (offsets, num_offsets, al_offsets, 0); - ENSURE_MEM (data, data_len, al_data, name_len); - - if (! err) - err = device_open (device_master, 0, device_name, *ports); - - if (! err) - { - (*ints)[0] = STORAGE_DEVICE; /* type */ - (*ints)[1] = 0; /* flags */ - (*ints)[2] = 0; /* block_size */ - (*ints)[3] = 0; /* num_runs */ - (*ints)[4] = name_len; /* name_len */ - (*ints)[5] = 0; /* misc_len */ - *num_ints = 6; - - strcpy (*data, device_name); - *data_len = name_len; - - *num_ports = 1; - *ports_type = MACH_MSG_TYPE_MOVE_SEND; - - *num_offsets = 0; - } - else - /* Some memory allocation failed (not bloody likely). */ - { -#define DISCARD_MEM(v, vl, alp) \ - if (alp) \ - vm_deallocate (mach_task_self (), (vm_address_t)*v, *vl * sizeof (**v)); - - DISCARD_MEM (ports, num_ports, al_ports); - DISCARD_MEM (ints, num_ints, al_ints); - DISCARD_MEM (offsets, num_offsets, al_offsets); - DISCARD_MEM (data, data_len, al_data); - } - } - - return err; -} diff --git a/trans/fakeroot.c b/trans/fakeroot.c new file mode 100644 index 00000000..c1102343 --- /dev/null +++ b/trans/fakeroot.c @@ -0,0 +1,925 @@ +/* fakeroot -- a translator for faking actions that aren't really permitted + Copyright (C) 2002, 2003, 2008 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 */ + +#include <hurd/netfs.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <argp.h> +#include <error.h> +#include <string.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <cthreads.h> +#include <hurd/ihash.h> +#include <hurd/paths.h> + +#include <version.h> + +const char *argp_program_version = STANDARD_HURD_VERSION (fakeroot); + +char *netfs_server_name = "fakeroot"; +char *netfs_server_version = HURD_VERSION; +int netfs_maxsymlinks = 16; /* arbitrary */ + +static auth_t fakeroot_auth_port; + +struct netnode +{ + hurd_ihash_locp_t idport_locp;/* easy removal pointer in idport ihash */ + mach_port_t idport; /* port from io_identity */ + int openmodes; /* O_READ | O_WRITE | O_EXEC */ + file_t file; /* port on real file */ + + unsigned int faked; +}; + +#define FAKE_UID (1 << 0) +#define FAKE_GID (1 << 1) +#define FAKE_AUTHOR (1 << 2) +#define FAKE_MODE (1 << 3) +#define FAKE_REFERENCE (1 << 4) /* got node_norefs with st_nlink > 0 */ + +struct mutex idport_ihash_lock = MUTEX_INITIALIZER; +struct hurd_ihash idport_ihash + = HURD_IHASH_INITIALIZER (offsetof (struct netnode, idport_locp)); + + +/* Make a new virtual node. Always consumes the ports. */ +static error_t +new_node (file_t file, mach_port_t idport, int locked, int openmodes, + struct node **np) +{ + error_t err; + struct netnode *nn = calloc (1, sizeof *nn); + if (nn == 0) + { + mach_port_deallocate (mach_task_self (), file); + if (idport != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), idport); + if (locked) + mutex_unlock (&idport_ihash_lock); + return ENOMEM; + } + nn->file = file; + nn->openmodes = openmodes; + if (idport != MACH_PORT_NULL) + nn->idport = idport; + else + { + ino_t fileno; + mach_port_t fsidport; + assert (!locked); + err = io_identity (file, &nn->idport, &fsidport, &fileno); + if (err) + { + mach_port_deallocate (mach_task_self (), file); + free (nn); + return err; + } + } + *np = netfs_make_node (nn); + if (*np == 0) + { + if (locked) + mutex_unlock (&idport_ihash_lock); + err = ENOMEM; + } + else + { + if (!locked) + mutex_lock (&idport_ihash_lock); + err = hurd_ihash_add (&idport_ihash, nn->idport, *np); + if (!err) + netfs_nref (*np); /* Return a reference to the caller. */ + mutex_unlock (&idport_ihash_lock); + } + if (err) + { + mach_port_deallocate (mach_task_self (), nn->idport); + mach_port_deallocate (mach_task_self (), file); + free (nn); + } + return err; +} + +/* Node NP has no more references; free all its associated storage. */ +void +netfs_node_norefs (struct node *np) +{ + if (np->nn->faked != 0 + && netfs_validate_stat (np, 0) == 0 && np->nn_stat.st_nlink > 0) + { + /* The real node still exists and we have faked some attributes. + We must keep our node alive in core to retain those values. + XXX + For now, we will leak the node if it gets deleted later. + That will keep the underlying file alive with st_nlink=0 + until this fakeroot filesystem dies. One easy solution + would be to scan nodes with references=1 for st_nlink=0 + at some convenient time, periodically or in syncfs. */ + if ((np->nn->faked & FAKE_REFERENCE) == 0) + { + np->nn->faked |= FAKE_REFERENCE; + ++np->references; + } + mutex_unlock (&np->lock); + return; + } + + spin_unlock (&netfs_node_refcnt_lock); /* Avoid deadlock. */ + mutex_lock (&idport_ihash_lock); + spin_lock (&netfs_node_refcnt_lock); + /* Previous holder of this lock might have just got a reference. */ + if (np->references > 0) + { + mutex_unlock (&idport_ihash_lock); + return; + } + hurd_ihash_locp_remove (&idport_ihash, np->nn->idport_locp); + mutex_unlock (&idport_ihash_lock); + mach_port_deallocate (mach_task_self (), np->nn->file); + mach_port_deallocate (mach_task_self (), np->nn->idport); + free (np->nn); + free (np); +} + +/* Given an existing node, make sure it has NEWMODES in its openmodes. + If not null, FILE is a port with those openmodes. */ +static error_t +check_openmodes (struct netnode *nn, int newmodes, file_t file) +{ + error_t err = 0; + + if (newmodes &~ nn->openmodes) + { + /* The user wants openmodes we haven't tried before. */ + + if (file != MACH_PORT_NULL && (nn->openmodes & ~newmodes)) + { + /* Intersecting sets. + We need yet another new peropen on this node. */ + mach_port_deallocate (mach_task_self (), file); + file = MACH_PORT_NULL; + } + if (file == MACH_PORT_NULL); + { + enum retry_type bad_retry; + char bad_retryname[1024]; /* XXX */ + err = dir_lookup (nn->file, "", nn->openmodes | newmodes, 0, + &bad_retry, bad_retryname, &file); + if (!err && (bad_retry != FS_RETRY_NORMAL + || bad_retryname[0] != '\0')) + { + mach_port_deallocate (mach_task_self (), file); + err = EGRATUITOUS; + } + } + if (! err) + { + /* The new port has more openmodes than + the old one. We can just use it now. */ + mach_port_deallocate (mach_task_self (), nn->file); + nn->file = file; + nn->openmodes = newmodes; + } + } + else if (file != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), file); + + return err; +} + +/* This is called by netfs_S_fsys_getroot. */ +error_t +netfs_check_open_permissions (struct iouser *user, struct node *np, + int flags, int newnode) +{ + return check_openmodes (np->nn, flags & (O_RDWR|O_EXEC), MACH_PORT_NULL); +} + +error_t +netfs_S_dir_lookup (struct protid *diruser, + char *filename, + int flags, + mode_t mode, + retry_type *do_retry, + char *retry_name, + mach_port_t *retry_port, + mach_msg_type_name_t *retry_port_type) +{ + struct node *dnp, *np; + error_t err; + struct protid *newpi; + struct iouser *user; + mach_port_t file; + mach_port_t idport, fsidport; + ino_t fileno; + + if (!diruser) + return EOPNOTSUPP; + + dnp = diruser->po->np; + err = dir_lookup (dnp->nn->file, filename, + flags & (O_NOLINK|O_RDWR|O_EXEC|O_CREAT|O_EXCL|O_NONBLOCK), + mode, do_retry, retry_name, &file); + if (err) + return err; + + switch (*do_retry) + { + case FS_RETRY_REAUTH: + { + mach_port_t ref = mach_reply_port (); + err = io_reauthenticate (file, ref, MACH_MSG_TYPE_MAKE_SEND); + if (! err) + { + mach_port_deallocate (mach_task_self (), file); + err = auth_user_authenticate (fakeroot_auth_port, ref, + MACH_MSG_TYPE_MAKE_SEND, + retry_port); + } + mach_port_destroy (mach_task_self (), ref); + if (err) + return err; + } + *do_retry = FS_RETRY_NORMAL; + /*FALLTHROUGH*/ + + case FS_RETRY_NORMAL: + case FS_RETRY_MAGICAL: + default: + if (file == MACH_PORT_NULL) + { + *retry_port = MACH_PORT_NULL; + *retry_port_type = MACH_MSG_TYPE_COPY_SEND; + return 0; + } + break; + } + + /* We have a new port to an underlying node. + Find or make our corresponding virtual node. */ + + np = 0; + err = io_identity (file, &idport, &fsidport, &fileno); + if (err) + mach_port_deallocate (mach_task_self (), file); + else + { + mach_port_deallocate (mach_task_self (), fsidport); + if (fsidport == netfs_fsys_identity) + { + /* Talking to ourselves! We just looked up one of our + own nodes. Find the node and return it. */ + struct protid *cred + = ports_lookup_port (netfs_port_bucket, file, + netfs_protid_class); + mach_port_deallocate (mach_task_self (), idport); + mach_port_deallocate (mach_task_self (), file); + if (cred == 0) + return EGRATUITOUS; + np = cred->po->np; + netfs_nref (np); + ports_port_deref (cred); + } + else + { + mutex_lock (&idport_ihash_lock); + np = hurd_ihash_find (&idport_ihash, idport); + if (np != 0) + { + /* We already know about this node. */ + mach_port_deallocate (mach_task_self (), idport); + mutex_lock (&np->lock); + err = check_openmodes (np->nn, (flags & (O_RDWR|O_EXEC)), file); + if (!err) + netfs_nref (np); + mutex_unlock (&np->lock); + mutex_unlock (&idport_ihash_lock); + } + else + err = new_node (file, idport, 1, flags, &np); + } + } + if (err) + return err; + + if (retry_name[0] == '\0' && *do_retry == FS_RETRY_NORMAL) + flags &= ~(O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS|O_NONBLOCK); + else + flags = 0; + + err = iohelp_dup_iouser (&user, diruser->user); + if (!err) + { + newpi = netfs_make_protid (netfs_make_peropen (np, flags, diruser->po), + user); + if (! newpi) + { + iohelp_free_iouser (user); + err = errno; + } + else + { + *retry_port = ports_get_right (newpi); + *retry_port_type = MACH_MSG_TYPE_MAKE_SEND; + ports_port_deref (newpi); + } + } + + netfs_nrele (np); + return err; +} + +/* These callbacks are used only by the standard netfs_S_dir_lookup, + which we do not use. But the shared library requires us to define them. */ +error_t +netfs_attempt_lookup (struct iouser *user, struct node *dir, + char *name, struct node **np) +{ + assert (! "should not be here"); + return EIEIO; +} + +error_t +netfs_attempt_create_file (struct iouser *user, struct node *dir, + char *name, mode_t mode, struct node **np) +{ + assert (! "should not be here"); + return EIEIO; +} + +/* Make sure that NP->nn_stat is filled with the most current information. + CRED identifies the user responsible for the operation. NP is locked. */ +error_t +netfs_validate_stat (struct node *np, struct iouser *cred) +{ + struct stat st; + error_t err = io_stat (np->nn->file, &st); + if (err) + return err; + + if (np->nn->faked & FAKE_UID) + st.st_uid = np->nn_stat.st_uid; + if (np->nn->faked & FAKE_GID) + st.st_gid = np->nn_stat.st_gid; + if (np->nn->faked & FAKE_AUTHOR) + st.st_author = np->nn_stat.st_author; + if (np->nn->faked & FAKE_MODE) + st.st_mode = np->nn_stat.st_mode; + + np->nn_stat = st; + np->nn_translated = S_ISLNK (st.st_mode) ? S_IFLNK : 0; + + return 0; +} + +error_t +netfs_attempt_chown (struct iouser *cred, struct node *np, + uid_t uid, uid_t gid) +{ + if (uid != -1) + { + np->nn->faked |= FAKE_UID; + np->nn_stat.st_uid = uid; + } + if (gid != -1) + { + np->nn->faked |= FAKE_GID; + np->nn_stat.st_gid = gid; + } + return 0; +} + +error_t +netfs_attempt_chauthor (struct iouser *cred, struct node *np, uid_t author) +{ + np->nn->faked |= FAKE_AUTHOR; + np->nn_stat.st_author = author; + return 0; +} + +/* Return the mode that the real underlying file should have if the + fake mode is being set to MODE. We always give ourselves read and + write permission so that we can open the file as root would be able + to. We give ourselves execute permission iff any execute bit is + set in the fake mode. */ +static inline mode_t +real_from_fake_mode (mode_t mode) +{ + return mode | S_IREAD | S_IWRITE | (((mode << 3) | (mode << 6)) & S_IEXEC); +} + +/* This should attempt a chmod call for the user specified by CRED on + locked node NODE, to change the mode to MODE. Unlike the normal Unix + and Hurd meaning of chmod, this function is also used to attempt to + change files into other types. If such a transition is attempted which + is impossible, then return EOPNOTSUPP. */ +error_t +netfs_attempt_chmod (struct iouser *cred, struct node *np, mode_t mode) +{ + if ((mode & S_IFMT) == 0) + mode |= np->nn_stat.st_mode & S_IFMT; + if ((mode & S_IFMT) != (np->nn_stat.st_mode & S_IFMT)) + return EOPNOTSUPP; + if (((mode | (mode << 3) | (mode << 6)) + ^ (np->nn_stat.st_mode | (np->nn_stat.st_mode << 3) + | (np->nn_stat.st_mode << 6))) + & S_IEXEC) + { + /* We are changing the executable bit, so this is not all fake. We + don't bother with error checking since the fake mode change should + always succeed--worst case a later open will get EACCES. */ + (void) file_chmod (np->nn->file, real_from_fake_mode (mode)); + } + np->nn->faked |= FAKE_MODE; + np->nn_stat.st_mode = mode; + return 0; +} + +/* The user must define this function. Attempt to turn locked node NP + (user CRED) into a symlink with target NAME. */ +error_t +netfs_attempt_mksymlink (struct iouser *cred, struct node *np, char *name) +{ + int namelen = strlen (name) + 1; + char trans[sizeof _HURD_SYMLINK + namelen]; + memcpy (trans, _HURD_SYMLINK, sizeof _HURD_SYMLINK); + memcpy (&trans[sizeof _HURD_SYMLINK], name, namelen); + return file_set_translator (np->nn->file, + FS_TRANS_EXCL|FS_TRANS_SET, + FS_TRANS_EXCL|FS_TRANS_SET, 0, + trans, sizeof trans, + MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND); +} + +error_t +netfs_attempt_mkdev (struct iouser *cred, struct node *np, + mode_t type, dev_t indexes) +{ + char *trans = 0; + int translen = asprintf (&trans, "%s%c%d%c%d", + S_ISCHR (type) ? _HURD_CHRDEV : _HURD_BLKDEV, + '\0', major (indexes), '\0', minor (indexes)); + if (trans == 0) + return ENOMEM; + else + { + error_t err = file_set_translator (np->nn->file, + FS_TRANS_EXCL|FS_TRANS_SET, + FS_TRANS_EXCL|FS_TRANS_SET, 0, + trans, translen + 1, + MACH_PORT_NULL, + MACH_MSG_TYPE_COPY_SEND); + free (trans); + return err; + } +} + +error_t +netfs_attempt_chflags (struct iouser *cred, struct node *np, int flags) +{ + return file_chflags (np->nn->file, flags); +} + +error_t +netfs_attempt_utimes (struct iouser *cred, struct node *np, + struct timespec *atime, struct timespec *mtime) +{ + union tv + { + struct timeval tv; + time_value_t tvt; + }; + union tv a, m; + if (atime) + { + TIMESPEC_TO_TIMEVAL (&a.tv, atime); + } + else + a.tv.tv_sec = a.tv.tv_usec = -1; + if (mtime) + { + TIMESPEC_TO_TIMEVAL (&m.tv, mtime); + } + else + m.tv.tv_sec = m.tv.tv_usec = -1; + + return file_utimes (np->nn->file, a.tvt, m.tvt); +} + +error_t +netfs_attempt_set_size (struct iouser *cred, struct node *np, off_t size) +{ + return file_set_size (np->nn->file, size); +} + +error_t +netfs_attempt_statfs (struct iouser *cred, struct node *np, struct statfs *st) +{ + return file_statfs (np->nn->file, st); +} + +error_t +netfs_attempt_sync (struct iouser *cred, struct node *np, int wait) +{ + return file_sync (np->nn->file, wait, 0); +} + +error_t +netfs_attempt_syncfs (struct iouser *cred, int wait) +{ + return 0; +} + +error_t +netfs_attempt_mkdir (struct iouser *user, struct node *dir, + char *name, mode_t mode) +{ + return dir_mkdir (dir->nn->file, name, mode | S_IRWXU); +} + + +/* XXX + Removing a node should mark the netnode so that it is GC'd when + it has no hard refs. + */ + +error_t +netfs_attempt_unlink (struct iouser *user, struct node *dir, char *name) +{ + return dir_unlink (dir->nn->file, name); +} + +error_t +netfs_attempt_rename (struct iouser *user, struct node *fromdir, + char *fromname, struct node *todir, + char *toname, int excl) +{ + return dir_rename (fromdir->nn->file, fromname, + todir->nn->file, toname, excl); +} + +error_t +netfs_attempt_rmdir (struct iouser *user, + struct node *dir, char *name) +{ + return dir_rmdir (dir->nn->file, name); +} + +error_t +netfs_attempt_link (struct iouser *user, struct node *dir, + struct node *file, char *name, int excl) +{ + return dir_link (dir->nn->file, file->nn->file, name, excl); +} + +error_t +netfs_attempt_mkfile (struct iouser *user, struct node *dir, + mode_t mode, struct node **np) +{ + file_t newfile; + error_t err = dir_mkfile (dir->nn->file, O_RDWR|O_EXEC, + real_from_fake_mode (mode), &newfile); + mutex_unlock (&dir->lock); + if (err == 0) + err = new_node (newfile, MACH_PORT_NULL, 0, O_RDWR|O_EXEC, np); + return err; +} + +error_t +netfs_attempt_readlink (struct iouser *user, struct node *np, char *buf) +{ + char transbuf[sizeof _HURD_SYMLINK + np->nn_stat.st_size + 1]; + char *trans = transbuf; + size_t translen = sizeof transbuf; + error_t err = file_get_translator (np->nn->file, &trans, &translen); + if (err == 0) + { + if (translen < sizeof _HURD_SYMLINK + || memcmp (trans, _HURD_SYMLINK, sizeof _HURD_SYMLINK) != 0) + err = EINVAL; + else + { + assert (translen <= sizeof _HURD_SYMLINK + np->nn_stat.st_size + 1); + memcpy (buf, &trans[sizeof _HURD_SYMLINK], + translen - sizeof _HURD_SYMLINK); + } + if (trans != transbuf) + munmap (trans, translen); + } + return err; +} + +error_t +netfs_attempt_read (struct iouser *cred, struct node *np, + off_t offset, size_t *len, void *data) +{ + char *buf = data; + error_t err = io_read (np->nn->file, &buf, len, offset, *len); + if (err == 0 && buf != data) + { + memcpy (data, buf, *len); + munmap (buf, *len); + } + return err; +} + +error_t +netfs_attempt_write (struct iouser *cred, struct node *np, + off_t offset, size_t *len, void *data) +{ + return io_write (np->nn->file, data, *len, offset, len); +} + +error_t +netfs_report_access (struct iouser *cred, struct node *np, int *types) +{ + *types = O_RDWR|O_EXEC; + return 0; +} + +error_t +netfs_get_dirents (struct iouser *cred, struct node *dir, + int entry, int nentries, char **data, + mach_msg_type_number_t *datacnt, + vm_size_t bufsize, int *amt) +{ + return dir_readdir (dir->nn->file, data, datacnt, + entry, nentries, bufsize, amt); +} + +error_t +netfs_file_get_storage_info (struct iouser *cred, + struct node *np, + mach_port_t **ports, + mach_msg_type_name_t *ports_type, + mach_msg_type_number_t *num_ports, + int **ints, + mach_msg_type_number_t *num_ints, + off_t **offsets, + mach_msg_type_number_t *num_offsets, + char **data, + mach_msg_type_number_t *data_len) +{ + *ports_type = MACH_MSG_TYPE_MOVE_SEND; + return file_get_storage_info (np->nn->file, + ports, num_ports, + ints, num_ints, + offsets, num_offsets, + data, data_len); +} + +kern_return_t +netfs_S_file_exec (struct protid *user, + task_t task, + int flags, + char *argv, + size_t argvlen, + char *envp, + size_t envplen, + mach_port_t *fds, + size_t fdslen, + mach_port_t *portarray, + size_t portarraylen, + int *intarray, + size_t intarraylen, + mach_port_t *deallocnames, + size_t deallocnameslen, + mach_port_t *destroynames, + size_t destroynameslen) +{ + error_t err; + file_t file; + + if (!user) + return EOPNOTSUPP; + + mutex_lock (&user->po->np->lock); + err = check_openmodes (user->po->np->nn, O_EXEC, MACH_PORT_NULL); + file = user->po->np->nn->file; + if (!err) + err = mach_port_mod_refs (mach_task_self (), + file, MACH_PORT_RIGHT_SEND, 1); + mutex_unlock (&user->po->np->lock); + + if (!err) + { + /* We cannot use MACH_MSG_TYPE_MOVE_SEND because we might need to + retry an interrupted call that would have consumed the rights. */ + err = file_exec (user->po->np->nn->file, task, flags, argv, argvlen, + envp, envplen, fds, MACH_MSG_TYPE_COPY_SEND, fdslen, + portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen, + intarray, intarraylen, deallocnames, deallocnameslen, + destroynames, destroynameslen); + mach_port_deallocate (mach_task_self (), file); + } + + if (err == 0) + { + size_t i; + mach_port_deallocate (mach_task_self (), task); + for (i = 0; i < fdslen; ++i) + mach_port_deallocate (mach_task_self (), fds[i]); + for (i = 0; i < portarraylen; ++i) + mach_port_deallocate (mach_task_self (), portarray[i]); + } + return err; +} + +error_t +netfs_S_io_map (struct protid *user, + mach_port_t *rdobj, mach_msg_type_name_t *rdobjtype, + mach_port_t *wrobj, mach_msg_type_name_t *wrobjtype) +{ + error_t err; + + if (!user) + return EOPNOTSUPP; + *rdobjtype = *wrobjtype = MACH_MSG_TYPE_MOVE_SEND; + + mutex_lock (&user->po->np->lock); + err = io_map (user->po->np->nn->file, rdobj, wrobj); + mutex_unlock (&user->po->np->lock); + return err; +} + +error_t +netfs_S_io_map_cntl (struct protid *user, + mach_port_t *obj, + mach_msg_type_name_t *objtype) +{ + error_t err; + + if (!user) + return EOPNOTSUPP; + *objtype = MACH_MSG_TYPE_MOVE_SEND; + + mutex_lock (&user->po->np->lock); + err = io_map_cntl (user->po->np->nn->file, obj); + mutex_unlock (&user->po->np->lock); + return err; +} + +#define NETFS_S_SIMPLE(name) \ +error_t \ +netfs_S_##name (struct protid *user) \ +{ \ + error_t err; \ + \ + if (!user) \ + return EOPNOTSUPP; \ + \ + mutex_lock (&user->po->np->lock); \ + err = name (user->po->np->nn->file); \ + mutex_unlock (&user->po->np->lock); \ + return err; \ +} + +NETFS_S_SIMPLE (io_get_conch) +NETFS_S_SIMPLE (io_release_conch) +NETFS_S_SIMPLE (io_eofnotify) +NETFS_S_SIMPLE (io_readnotify) +NETFS_S_SIMPLE (io_readsleep) +NETFS_S_SIMPLE (io_sigio) + +error_t +netfs_S_io_prenotify (struct protid *user, + vm_offset_t start, vm_offset_t stop) +{ + error_t err; + + if (!user) + return EOPNOTSUPP; + + mutex_lock (&user->po->np->lock); + err = io_prenotify (user->po->np->nn->file, start, stop); + mutex_unlock (&user->po->np->lock); + return err; +} + +error_t +netfs_S_io_postnotify (struct protid *user, + vm_offset_t start, vm_offset_t stop) +{ + error_t err; + + if (!user) + return EOPNOTSUPP; + + mutex_lock (&user->po->np->lock); + err = io_postnotify (user->po->np->nn->file, start, stop); + mutex_unlock (&user->po->np->lock); + return err; +} + +/* This overrides the library's definition. */ +int +netfs_demuxer (mach_msg_header_t *inp, + mach_msg_header_t *outp) +{ + int netfs_fs_server (mach_msg_header_t *, mach_msg_header_t *); + int netfs_io_server (mach_msg_header_t *, mach_msg_header_t *); + int netfs_fsys_server (mach_msg_header_t *, mach_msg_header_t *); + int netfs_ifsock_server (mach_msg_header_t *, mach_msg_header_t *); + + if (netfs_io_server (inp, outp) + || netfs_fs_server (inp, outp) + || ports_notify_server (inp, outp) + || netfs_fsys_server (inp, outp) + /* XXX we should intercept interrupt_operation and do + the ports_S_interrupt_operation work as well as + sending an interrupt_operation to the underlying file. + */ + || ports_interrupt_server (inp, outp)) + return 1; + else + { + /* We didn't recognize the message ID, so pass the message through + unchanged to the underlying file. */ + struct protid *cred = ports_lookup_port (netfs_port_bucket, + inp->msgh_local_port, + netfs_protid_class); + if (cred == 0) + /* This must be an unknown message on our fsys control port. */ + return 0; + else + { + error_t err; + assert (MACH_MSGH_BITS_LOCAL (inp->msgh_bits) + == MACH_MSG_TYPE_MOVE_SEND); + inp->msgh_bits = (inp->msgh_bits & MACH_MSGH_BITS_COMPLEX) + | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, + MACH_MSGH_BITS_REMOTE (inp->msgh_bits)); + inp->msgh_local_port = inp->msgh_remote_port; /* reply port */ + inp->msgh_remote_port = cred->po->np->nn->file; + err = mach_msg (inp, MACH_SEND_MSG, inp->msgh_size, 0, + MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL); + assert_perror (err); /* XXX should synthesize reply */ + ports_port_deref (cred); + return 1; + } + } +} + + +int +main (int argc, char **argv) +{ + error_t err; + mach_port_t bootstrap; + + struct argp argp = { NULL, NULL, NULL, "\ +A translator for faking privileged access to an underlying filesystem.\v\ +This translator appears to give transparent access to the underlying \ +directory node. However, all accesses are made using the credentials \ +of the translator regardless of the client and the translator fakes \ +success for chown and chmod operations that only root could actually do, \ +reporting the faked IDs and modes in later stat calls, and allows \ +any user to open nodes regardless of permissions as is done for root." }; + + /* Parse our command line arguments (all none of them). */ + argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0); + + fakeroot_auth_port = getauth (); + + task_get_bootstrap_port (mach_task_self (), &bootstrap); + netfs_init (); + + /* Get our underlying node (we presume it's a directory) and use + that to make the root node of the filesystem. */ + err = new_node (netfs_startup (bootstrap, O_READ), MACH_PORT_NULL, 0, O_READ, + &netfs_root_node); + if (err) + error (5, err, "Cannot create root node"); + + err = netfs_validate_stat (netfs_root_node, 0); + if (err) + error (6, err, "Cannot stat underlying node"); + + netfs_root_node->nn_stat.st_mode &= ~(S_IPTRANS | S_IATRANS); + netfs_root_node->nn_stat.st_mode |= S_IROOT; + netfs_root_node->nn->faked |= FAKE_MODE; + + netfs_server_loop (); /* Never returns. */ + + /*NOTREACHED*/ + return 0; +} diff --git a/trans/fifo.c b/trans/fifo.c index 6ef40e62..39043acd 100644 --- a/trans/fifo.c +++ b/trans/fifo.c @@ -1,8 +1,7 @@ /* A translator for fifos - Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. - - Written by Miles Bader <miles@gnu.ai.mit.edu> + Copyright (C) 1995,96,97,98,2001,02 Free Software Foundation, Inc. + Written by Miles Bader <miles@gnu.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -19,6 +18,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdio.h> +#include <stdlib.h> #include <errno.h> #include <unistd.h> #include <error.h> @@ -50,7 +50,7 @@ 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); +const char *argp_program_version = STANDARD_HURD_VERSION (fifo); static struct argp_option options[] = { @@ -74,10 +74,10 @@ parse_opt (int key, char *arg, struct argp_state *state) } static const struct argp argp = { - options, parse_opt, 0, "Translator for fifos" + options, parse_opt, 0, "Translator for fifos." }; -void +int main (int argc, char **argv) { error_t err; @@ -94,6 +94,7 @@ main (int argc, char **argv) /* 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"); @@ -101,12 +102,13 @@ main (int argc, char **argv) do { ports_enable_class (fsys->protid_class); - ports_manage_port_operations_multithread (fsys->pi.bucket, trivfs_demuxer, - 30*1000, 5*60*1000, 0, 0); + ports_manage_port_operations_multithread (fsys->pi.bucket, + trivfs_demuxer, + 30*1000, 5*60*1000, 0); } while (ports_count_class (fsys->protid_class) > 0); - exit(0); + return 0; } /* ---------------------------------------------------------------- */ @@ -122,15 +124,17 @@ open_hook (struct trivfs_peropen *po) 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; +#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 @@ -313,13 +317,14 @@ trivfs_goaway (struct trivfs_control *cntl, int flags) 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) +trivfs_S_io_map (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t replytype, + memory_object_t *rdobj, + mach_msg_type_name_t *rdtype, + memory_object_t *wrobj, + mach_msg_type_name_t *wrtype) { - return EINVAL; + return EOPNOTSUPP; } /* ---------------------------------------------------------------- */ @@ -402,7 +407,7 @@ trivfs_S_io_seek (struct trivfs_protid *cred, 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) + int *select_type) { struct pipe *pipe; error_t err = 0; @@ -414,26 +419,30 @@ trivfs_S_io_select (struct trivfs_protid *cred, 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 (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 (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; @@ -498,7 +507,7 @@ trivfs_S_file_set_size (struct trivfs_protid *cred, /* 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 + 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 diff --git a/trans/firmlink.c b/trans/firmlink.c index 48211308..087e19d0 100644 --- a/trans/firmlink.c +++ b/trans/firmlink.c @@ -1,8 +1,7 @@ /* A translator for `firmlinks' - Copyright (C) 1997 Free Software Foundation, Inc. - - Written by Miles Bader <miles@gnu.ai.mit.edu> + Copyright (C) 1997,98,99,2001,02 Free Software Foundation, Inc. + Written by Miles Bader <miles@gnu.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -18,13 +17,16 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <stdint.h> #include <stdio.h> +#include <stdlib.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> @@ -38,8 +40,8 @@ static const struct argp_option options[] = }; 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;" +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" @@ -65,7 +67,7 @@ parse_opt (int key, char *arg, struct argp_state *state) static struct argp argp = { options, parse_opt, args_doc, doc }; -void +int main (int argc, char **argv) { error_t err; @@ -81,14 +83,15 @@ main (int argc, char **argv) /* 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, 0); + 2 * 60 * 1000, 0, 0); - exit (0); + return 0; } /* Return in LINK the node that TARGET_NAME resolves to, with its parent @@ -200,8 +203,8 @@ trivfs_goaway (struct trivfs_control *cntl, int flags) 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) + char **data, mach_msg_type_number_t *data_len, + loff_t offs, mach_msg_type_number_t amount) { error_t err = 0; @@ -211,17 +214,18 @@ trivfs_S_io_read (struct trivfs_protid *cred, err = EBADF; else { - off_t max = strlen (target); - off_t start = offs >= 0 ? offs : (off_t)cred->po->hook; + size_t max = strlen (target); + intptr_t start = offs >= 0 ? offs : (intptr_t)cred->po->hook; if (start < 0) return EINVAL; if (start + amount > max) amount = max - start; if (amount > *data_len) - err = vm_allocate (mach_task_self (), data, amount, 1); + *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + err = (*data == MAP_FAILED) ? errno : 0; if (!err && amount > 0) { - memcpy ((char *)(*data + start), target, amount); + memcpy (*data, target + start, amount); if (offs < 0) cred->po->hook = (void *)(start + amount); /* Update PO offset. */ } @@ -243,10 +247,10 @@ trivfs_S_io_readable (struct trivfs_protid *cred, return EOPNOTSUPP; else if (! (cred->po->openmodes & O_READ)) return EBADF; - else if ((off_t)cred->po->hook < 0) + else if ((intptr_t)cred->po->hook < 0) return EINVAL; else - *amount = strlen (target) - (off_t)cred->po->hook; + *amount = strlen (target) - (intptr_t)cred->po->hook; return 0; } @@ -267,7 +271,7 @@ trivfs_S_io_seek (struct trivfs_protid *cred, 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) + int *type) { return EOPNOTSUPP; } diff --git a/trans/fwd.c b/trans/fwd.c index 6b90d333..f30aad1a 100644 --- a/trans/fwd.c +++ b/trans/fwd.c @@ -4,7 +4,7 @@ and forward the request to the server if they find one, otherwise doing the translation themselves. - Copyright (C) 1995 Free Software Foundation, Inc. + Copyright (C) 1995, 1998, 1999 Free Software Foundation, Inc. Written by Miles Bader <miles@gnu.ai.mit.edu> @@ -26,7 +26,7 @@ #include <stdio.h> #include <hurd/fshelp.h> -void +int main (int argc, char **argv) { error_t err; @@ -34,18 +34,18 @@ main (int argc, char **argv) if (argc < 2 || *argv[1] == '-') { - fprintf(stderr, "Usage: %s SERVER [TRANS_NAME [TRANS_ARG...]]", - program_invocation_name); - exit(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"); + 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]); - exit (0); + return 0; } diff --git a/trans/hello-mt.c b/trans/hello-mt.c new file mode 100644 index 00000000..b933cfde --- /dev/null +++ b/trans/hello-mt.c @@ -0,0 +1,331 @@ +/* hello-mt.c - A trivial single-file translator, multithreaded version + Copyright (C) 1998,99,2001,02,2006 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 <stdlib.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> + +#include <version.h> + +const char *argp_program_version = STANDARD_HURD_VERSION (hello-mt); + +/* 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, + char **data, mach_msg_type_number_t *data_len, + loff_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 = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + if (*data == MAP_FAILED) + { + mutex_unlock (&op->lock); + rwlock_reader_unlock (&contents_lock); + return ENOMEM; + } + + /* 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_CUR: + offs += op->offs; + goto check; + case SEEK_END: + offs += contents_len; + case SEEK_SET: + check: + if (offs >= 0) + { + *new_offs = op->offs = offs; + break; + } + default: + err = EINVAL; + } + + 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, + "A multi-threaded translator providing a warm greeting." }; + +/* 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..c49feeb2 --- /dev/null +++ b/trans/hello.c @@ -0,0 +1,291 @@ +/* hello.c - A trivial single-file translator + Copyright (C) 1998,1999,2001,02,2006 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 <stdlib.h> +#include <argp.h> +#include <argz.h> +#include <error.h> +#include <string.h> +#include <fcntl.h> +#include <sys/mman.h> + +#include <version.h> + +const char *argp_program_version = STANDARD_HURD_VERSION (hello); + +/* 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, + char **data, mach_msg_type_number_t *data_len, + loff_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 = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + if (*data == MAP_FAILED) + return ENOMEM; + } + + /* 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_CUR: + offs += op->offs; + goto check; + case SEEK_END: + offs += contents_len; + case SEEK_SET: + check: + if (offs >= 0) + { + *new_offs = op->offs = offs; + break; + } + default: + err = EINVAL; + } + + 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, "A translator providing a warm greeting." }; + +/* 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 index 2e53ea96..092bb40d 100644 --- a/trans/ifsock.c +++ b/trans/ifsock.c @@ -1,5 +1,5 @@ /* Server for S_IFSOCK nodes - Copyright (C) 1994, 1995 Free Software Foundation + Copyright (C) 1994, 1995, 2001, 02, 2006 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 @@ -23,11 +23,27 @@ #include <hurd/socket.h> #include <hurd/fsys.h> #include <stdio.h> +#include <stdlib.h> #include <error.h> #include <fcntl.h> +#include <argp.h> + +#include <sys/cdefs.h> +#ifndef __XSTRING /* Could / should (?) be provided by glibc. */ +#define __XSTRING(x) __STRING(x) /* Expand x, then stringify. */ +#endif + +#include <version.h> #include "ifsock_S.h" +const char *argp_program_version = STANDARD_HURD_VERSION (ifsock); + +static const char doc[] = "A translator to provide Unix domain sockets." +"\vThis translator acts as a hook for Unix domain sockets." +" The pflocal translator on " _SERVERS_SOCKET "/" __XSTRING(PF_LOCAL) +" implements the sockets."; + mach_port_t address_port; struct port_class *control_class; @@ -62,6 +78,9 @@ main (int argc, char **argv) mach_port_t pflocal; mach_port_t bootstrap; char buf[512]; + const struct argp argp = { 0, 0, 0, doc }; + + argp_parse (&argp, argc, argv, 0, 0, 0); control_class = ports_create_class (trivfs_clean_cntl, 0); node_class = ports_create_class (trivfs_clean_protid, 0); @@ -72,10 +91,11 @@ main (int argc, char **argv) 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"); @@ -87,8 +107,8 @@ main (int argc, char **argv) address_port = MACH_PORT_NULL; else { - errno = socket_fabricate_address (pflocal, AF_LOCAL, &address_port); - if (errno) + err = socket_fabricate_address (pflocal, AF_LOCAL, &address_port); + if (err) address_port = MACH_PORT_NULL; mach_port_deallocate (mach_task_self (), pflocal); } @@ -97,7 +117,7 @@ main (int argc, char **argv) ports_manage_port_operations_one_thread (port_bucket, demuxer, 0); return 0; } - + void trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st) { @@ -114,18 +134,18 @@ error_t S_ifsock_getsockaddr (file_t sockfile, mach_port_t *address) { - struct trivfs_protid *cred = ports_lookup_port (port_bucket, sockfile, + 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); diff --git a/trans/magic.c b/trans/magic.c index 952a5c28..1a8427ce 100644 --- a/trans/magic.c +++ b/trans/magic.c @@ -1,8 +1,6 @@ /* A translator for returning FS_RETRY_MAGIC strings. - Copyright (C) 1995 Free Software Foundation, Inc. - - Written by Miles Bader <miles@gnu.ai.mit.edu> + Copyright (C) 1999,2001,02, 03 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 @@ -19,138 +17,549 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <hurd.h> +#include <hurd/ports.h> +#include <hurd/trivfs.h> +#include <hurd/fshelp.h> +#include <hurd/fsys.h> +#include <version.h> + #include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/mman.h> #include <error.h> -#include <hurd/fsys.h> -#include "fsys_S.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); + +/* This structure has all the state about one filesystem. + It hangs off trivfs_control->hook. */ +struct magic +{ + /* We chain all filesystems together so we can tell easily when they are + all unused. */ + struct trivfs_control *next; + + /* The magic string we return for lookups. */ + char *magic; + + int directory; /* --directory flag */ + + /* Pre-fab contents of dummy directory for dir_readdir. + Set up only under --directory. */ + void *dirbuf; + size_t dirbufsize; + + unsigned int nusers; /* Count of users, only with --directory. */ +}; + +static inline void +free_magic (struct magic *m) +{ + free (m->magic); + if (m->dirbuf) + munmap (m->dirbuf, m->dirbufsize); + free (m); +} + +static struct trivfs_control *all_fsys; -/* ---------------------------------------------------------------- */ +/* Trivfs hooks */ + +int trivfs_fstype = FSTYPE_DEV; +int trivfs_fsid = 0; -extern int fsys_server (mach_msg_header_t *, mach_msg_header_t *); +int trivfs_support_read = 0; +int trivfs_support_write = 0; +int trivfs_support_exec = 0; -/* The magic string we return for lookups. */ -static char *magic = NULL; +int trivfs_allow_open = O_READ; void -main (int argc, char **argv) +trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st) { - error_t err; - mach_port_t bootstrap, control, realnode; - - if (argc != 2 || *argv[1] == '-') - { - fprintf(stderr, "Usage: %s MAGIC", program_invocation_name); - exit(-1); - } + struct magic *const m = cred->po->cntl->hook; - magic = argv[1]; - - task_get_bootstrap_port (mach_task_self (), &bootstrap); - if (bootstrap == MACH_PORT_NULL) - error(3, 0, "Must be started as a translator"); + st->st_size = m->dirbufsize; + st->st_blocks = getpagesize () / S_BLKSIZE; - /* Reply to our parent */ - mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &control); - err = - fsys_startup (bootstrap, 0, control, MACH_MSG_TYPE_MAKE_SEND, &realnode); - if (err) - error(1, err, "starting translator"); + 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))); +} - /* Launch */ - while (1) - { - /* The timeout here is 10 minutes */ - err = mach_msg_server_timeout (fsys_server, 0, control, - MACH_RCV_TIMEOUT, 1000 * 60 * 10); - if (err == MACH_RCV_TIMED_OUT) - exit (0); - } +error_t +trivfs_goaway (struct trivfs_control *fsys, int flags) +{ + struct magic *const m = fsys->hook; + + /* We are single-threaded, so no fancy stuff is needed here. */ + + if (m->nusers > 0 && !(flags & FSYS_GOAWAY_FORCE)) + return EBUSY; + + /* No more communication with the parent filesystem. + This running RPC should now be the only ref keeping FSYS alive. */ + ports_destroy_right (fsys); + return 0; +} + + +/* Clean pointers in a struct trivfs_control when its last reference + vanishes before it's freed. This overrides the libtrivfs version + so we can clean up our hook data. */ +void +trivfs_clean_cntl (void *arg) +{ + struct trivfs_control *cntl = arg; + struct magic *const m = cntl->hook; + + /* Remove us from the list of all filesystems. */ + struct trivfs_control **lastp = &all_fsys; + while (*lastp != cntl) + lastp = &((struct magic *) (*lastp)->hook)->next; + *lastp = m->next; + + if (all_fsys == 0) + /* Nothing more to do in this life. */ + exit (0); + + mach_port_destroy (mach_task_self (), cntl->filesys_id); + mach_port_destroy (mach_task_self (), cntl->file_id); + mach_port_deallocate (mach_task_self (), cntl->underlying); + + free_magic (m); } -/* ---------------------------------------------------------------- */ +/* This hook is used when running without --directory; + it circumvents basically all the trivfs machinery. */ -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) -{ - strcpy(retry_name, magic); +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) +{ + error_t err; + struct magic *const m = cntl->hook; + + if (m->directory) + return EAGAIN; /* Do normal trivfs getroot processing. */ + + strcpy (retry_name, m->magic); *do_retry = FS_RETRY_MAGICAL; - *ret = MACH_PORT_NULL; - *rettype = MACH_MSG_TYPE_COPY_SEND; + *node = MACH_PORT_NULL; + *node_type = MACH_MSG_TYPE_COPY_SEND; + + err = mach_port_deallocate (mach_task_self (), dotdot); + assert_perror (err); + 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 *real_type) +/* 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) { - return EOPNOTSUPP; + error_t err = trivfs_open (cntl, user, flags, realnode, cred); + if (!err) + { + /* We consume the reference for DOTDOT. */ + (*cred)->po->hook = (void *) dotdot; + struct magic *const m = cntl->hook; + m->nusers++; + } + return err; } -error_t -S_fsys_goaway (mach_port_t control, - int flags) +static void +magic_peropen_destroy (struct trivfs_peropen *po) { - exit (0); + mach_port_deallocate (mach_task_self (), (mach_port_t) po->hook); } -error_t -S_fsys_syncfs (mach_port_t control, - int wait, - int recurse) + +/* We have this hook only for simple tracking of the live user ports. */ +static void +magic_protid_destroy (struct trivfs_protid *cred) { - return 0; + struct magic *const m = cred->po->cntl->hook; + m->nusers--; } + +/* Do a directory lookup. */ + error_t -S_fsys_set_options (mach_port_t control, - char *data, mach_msg_type_number_t len, - int do_children) +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) { - return EOPNOTSUPP; + int perms; + error_t err; + struct trivfs_protid *newcred; + mach_port_t dotdot; + struct iouser *user; + + if (!cred) + return EOPNOTSUPP; + + if (name[0] != '\0') + { + struct magic *const m = cred->po->cntl->hook; + + if (!m->directory) + return ENOTDIR; + + /* 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, ".")) + { + if (m->magic == 0) + strcpy (retry_name, name); + else + { + char *p = stpcpy (retry_name, m->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; + err = iohelp_dup_iouser (&user, cred->user); + if (err) + return err; + 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 -S_fsys_get_options (mach_port_t control, - char **data, mach_msg_type_number_t *len) +trivfs_S_dir_readdir (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t reply_type, + char **data, + size_t *datalen, + boolean_t *data_dealloc, + int entry, + int nentries, + vm_size_t bufsiz, + int *amount) { - return EOPNOTSUPP; + if (!cred) + return EOPNOTSUPP; + + struct magic *const m = cred->po->cntl->hook; + + if (entry > 0) + { + void *p; + int i; + i = 0; + for (p = m->dirbuf; p < m->dirbuf + m->dirbufsize; + p += ((struct dirent *) p)->d_reclen) + if (i++ == entry) + break; + *data = p; + *datalen = m->dirbuf + m->dirbufsize - p; + *amount = 2 - entry; + } + else + { + *data = m->dirbuf; + *datalen = m->dirbufsize; + *amount = 2; + } + + *data_dealloc = 0; + return 0; } -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) + +#include <hurd/paths.h> +#define _SERVERS_MAGIC _SERVERS "magic" + +/* To whom should we try to delegate on startup? */ +static const char *delegate = _SERVERS_MAGIC; + +static const struct argp_option options[] = { - return EOPNOTSUPP; + {"directory", 'd', 0, 0, "Provide virtual (empty) directory node"}, + {"use-server", 'U', "NAME", 0, + "Delegate to server NAME instead of " _SERVERS_MAGIC}, + {0} +}; + +static error_t +parse_opt (int opt, char *arg, struct argp_state *state) +{ + struct magic *const m = state->input; + + switch (opt) + { + case 'U': + /* This is only valid for the startup options, not delegates. */ + if (all_fsys != 0) + return EINVAL; + delegate = arg; + return 0; + + case 'd': + case ARGP_KEY_NO_ARGS: + m->directory = 1; + return 0; + + case ARGP_KEY_ARG: + if (m->magic != 0) + { + argp_usage (state); + return EINVAL; + } + m->magic = strdup (arg); + return m->magic == 0 ? ENOMEM : 0; + + case ARGP_KEY_SUCCESS: + if (m->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; + m->dirbuf = mmap (0, getpagesize (), PROT_READ|PROT_WRITE, + MAP_ANON, 0, 0); + d = add (m->dirbuf, "."); + d = add (d, ".."); + m->dirbufsize = (char *) d - (char *) m->dirbuf; + } + return 0; + } + + return ARGP_ERR_UNKNOWN; } 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) +trivfs_append_args (struct trivfs_control *fsys, + char **argz, size_t *argz_len) { - return EOPNOTSUPP; + struct magic *const m = fsys->hook; + return ((m->directory ? argz_add (argz, argz_len, "--directory") : 0) + ?: (m->magic ? argz_add (argz, argz_len, m->magic) : 0)); } -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) +static struct argp argp = + { + options, parse_opt, "MAGIC", + "A translator that returns the magic retry result MAGIC." + }; + +int +main (int argc, char **argv) { - return EOPNOTSUPP; + error_t err; + mach_port_t bootstrap; + struct trivfs_control *fsys; + struct magic *m = calloc (1, sizeof *m); + + argp_parse (&argp, argc, argv, 0, 0, m); + + task_get_bootstrap_port (mach_task_self (), &bootstrap); + if (bootstrap == MACH_PORT_NULL) + error (1, 0, "Must be started as a translator"); + + if (delegate != 0) + { + /* First, try to have the canonical server sitting on /servers/magic + take over for us. */ + err = fshelp_delegate_translation (delegate, bootstrap, argv); + if (err == 0) + return 0; + } + + /* Nope, we are doing it ourselves. */ + + trivfs_getroot_hook = &magic_getroot; + trivfs_open_hook = &magic_open; + trivfs_protid_destroy_hook = &magic_protid_destroy; + if (m->directory) + trivfs_peropen_destroy_hook = &magic_peropen_destroy; + + /* 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"); + fsys->hook = m; + all_fsys = fsys; + + /* Launch. */ + while (1) + { + ports_manage_port_operations_one_thread (fsys->pi.bucket, trivfs_demuxer, + 10 * 60 * 1000); + + /* 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. */ + + struct trivfs_control *fs = all_fsys; + do + { + struct magic *const m = fs->hook; + struct trivfs_control *const next = m->next; + trivfs_goaway (fs, 0); + fs = next; + } while (fs != 0); + } + + return 0; } + +/* Handle delegated filesystems. */ error_t -S_fsys_forward (mach_port_t server, mach_port_t requestor, - char *argz, size_t argz_len) +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) { - return EOPNOTSUPP; + struct trivfs_protid *cred + = ports_lookup_port (all_fsys->pi.bucket, server, + trivfs_protid_portclasses[0]); + if (!cred) + return EOPNOTSUPP; + ports_port_deref (cred); + + /* Allocate a new structure for parameters, and parse the arguments + to fill it in. */ + struct magic *m = calloc (1, sizeof *m); + if (!m) + return ENOMEM; + + int argc = argz_count (argz, argz_len); + char *argv[argc + 1]; + argz_extract (argz, argz_len, argv); + error_t err = argp_parse (&argp, argc, argv, + ARGP_NO_ERRS | ARGP_NO_HELP, 0, m); + if (err) + { + free_magic (m); + return err; + } + + /* Now we are ready to start up the filesystem. Contact the parent. */ + struct trivfs_control *fsys; + err = trivfs_startup (requestor, 0, + trivfs_cntl_portclasses[0], all_fsys->pi.bucket, + trivfs_protid_portclasses[0], all_fsys->pi.bucket, + &fsys); + if (err) + { + free_magic (m); + return err; + } + mach_port_deallocate (mach_task_self (), requestor); + + /* The new filesystem is all hooked up. + Put it on the list of all filesystems we are serving. */ + m->next = all_fsys; + fsys->hook = m; + all_fsys = fsys; + + return 0; } diff --git a/trans/new-fifo.c b/trans/new-fifo.c index 150121f6..5306deed 100644 --- a/trans/new-fifo.c +++ b/trans/new-fifo.c @@ -1,8 +1,7 @@ /* A translator for fifos - Copyright (C) 1995, 1996 Free Software Foundation, Inc. - - Written by Miles Bader <miles@gnu.ai.mit.edu> + Copyright (C) 1995,96,97,98,2000,02 Free Software Foundation, Inc. + Written by Miles Bader <miles@gnu.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -37,8 +36,12 @@ #include <hurd/pipe.h> #include <hurd/paths.h> +#include <version.h> + #define DEFAULT_SERVER _SERVERS "fifo"; +const char *argp_program_version = STANDARD_HURD_VERSION (new-fifo); + struct port_bucket *port_bucket; struct port_class *fifo_port_class, *server_port_class, *fsys_port_class; @@ -165,18 +168,18 @@ fifo_trans_parse_args (struct fifo_trans *trans, int argc, char **argv, } return 0; } - struct argp argp = {options, parse_opt}; + struct argp argp = {options, parse_opt, 0, "A translator for fifos." }; return argp_parse (&argp, argc, argv, print_errs ? 0 : ARGP_SILENT, 0, 0); } /* ---------------------------------------------------------------- */ -struct port_class *trivfs_protid_portclasses[1]; +struct port_class *trivfs_protid_portclasses[2]; struct port_class *trivfs_cntl_portclasses[1]; -int trivfs_protid_nportclasses = 1; +int trivfs_protid_nportclasses = 2; int trivfs_cntl_nportclasses = 1; -void +int main (int argc, char **argv) { error_t err; @@ -226,11 +229,11 @@ main (int argc, char **argv) ports_enable_class (fifo_port_class); ports_manage_port_operations_multithread (port_bucket, trivfs_demuxer, - 30*1000, 5*60*1000, 0, 0); + 30*1000, 5*60*1000, 0); } while (ports_count_class (fifo_port_class) > 0); - exit (0); + return 0; } /* ---------------------------------------------------------------- */ @@ -245,16 +248,18 @@ fifo_trans_open (struct fifo_trans *trans, int flags, void **hook) 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; +#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 @@ -497,13 +502,14 @@ trivfs_goaway (struct trivfs_control *fsys, int flags) 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) +trivfs_S_io_map (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t replytype, + memory_object_t *rdobj, + mach_msg_type_name_t *rdtype, + memory_object_t *wrobj, + mach_msg_type_name_t *wrtype) { - return EINVAL; + return EOPNOTSUPP; } /* ---------------------------------------------------------------- */ @@ -588,7 +594,7 @@ trivfs_S_io_seek (struct trivfs_protid *cred, 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) + int *select_type) { struct pipe *pipe; error_t err = 0; @@ -600,26 +606,30 @@ trivfs_S_io_select (struct trivfs_protid *cred, 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 (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 (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; @@ -681,7 +691,7 @@ trivfs_S_file_set_size (struct trivfs_protid *cred, /* 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 + 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 diff --git a/trans/null.c b/trans/null.c index fadb1dee..9673a758 100644 --- a/trans/null.c +++ b/trans/null.c @@ -1,8 +1,7 @@ /* A translator for providing endless empty space and immediate eof. - Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. - - Written by Miles Bader <miles@gnu.ai.mit.edu> + Copyright (C) 1995,96,97,98,99,2001,02,03 Free Software Foundation, Inc. + Written by Miles Bader <miles@gnu.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -25,6 +24,7 @@ #include <version.h> #include <stdio.h> +#include <stdlib.h> #include <unistd.h> #include <error.h> #include <string.h> @@ -34,13 +34,37 @@ const char *argp_program_version = STANDARD_HURD_VERSION (null); -void +/* 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; - const struct argp argp = { 0, 0, 0, "Endless sink and null source" }; argp_parse (&argp, argc, argv, 0, 0, 0); @@ -50,14 +74,15 @@ main (int argc, char **argv) /* 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, 0); + 2 * 60 * 1000, 0, 0); - exit(0); + return 0; } /* Trivfs hooks */ @@ -98,13 +123,14 @@ trivfs_goaway (struct trivfs_control *fsys, int flags) 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) +trivfs_S_io_map (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t replytype, + 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! */ + return EOPNOTSUPP; /* XXX should work! */ } /* Read data from an IO object. If offset if -1, read from the object @@ -113,21 +139,20 @@ trivfs_S_io_map(struct trivfs_protid *cred, 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, + char **data, mach_msg_type_number_t *datalen, - off_t offs, + loff_t offs, mach_msg_type_number_t amt) { - error_t err = 0; - if (!cred) - err = EOPNOTSUPP; + return EOPNOTSUPP; else if (!(cred->po->openmodes & O_READ)) - err = EBADF; + return EBADF; else - *datalen = 0; - - return 0; + { + *datalen = 0; + return 0; + } } /* Tell how much data can be read from the object without blocking for @@ -167,7 +192,7 @@ trivfs_S_io_seek (struct trivfs_protid *cred, 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) + int *type) { if (!cred) return EOPNOTSUPP; @@ -189,20 +214,22 @@ trivfs_S_io_select (struct trivfs_protid *cred, 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) + char *data, mach_msg_type_number_t datalen, + loff_t offs, mach_msg_type_number_t *amt) { if (!cred) return EOPNOTSUPP; else if (!(cred->po->openmodes & O_WRITE)) return EBADF; *amt = datalen; - return 0; + return write_error_code; } /* Truncate file. */ kern_return_t -trivfs_S_file_set_size (struct trivfs_protid *cred, off_t size) +trivfs_S_file_set_size (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t replytype, + loff_t size) { return 0; } @@ -210,7 +237,7 @@ trivfs_S_file_set_size (struct trivfs_protid *cred, off_t size) /* 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 + 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 diff --git a/trans/password.c b/trans/password.c new file mode 100644 index 00000000..6f15a9e8 --- /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/proxy-defpager.c b/trans/proxy-defpager.c new file mode 100644 index 00000000..0a5ab65e --- /dev/null +++ b/trans/proxy-defpager.c @@ -0,0 +1,278 @@ +/* A translator for providing access to Mach default_pager.defs control calls + + Copyright (C) 2002, 2007 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/trivfs.h> +#include <unistd.h> +#include <fcntl.h> +#include <argp.h> +#include <error.h> +#include <version.h> +#include <hurd/paths.h> + +#include "default_pager_S.h" +#include "default_pager_U.h" + +static mach_port_t real_defpager, dev_master; + +static error_t +allowed (mach_port_t port, int mode) +{ + struct trivfs_protid *cred = ports_lookup_port + (0, port, trivfs_protid_portclasses[0]); + if (!cred) + return MIG_BAD_ID; + error_t result = (cred->po->openmodes & mode) ? 0 : EACCES; + ports_port_deref (cred); + return result; +} + +kern_return_t +S_default_pager_object_create (mach_port_t default_pager, + memory_object_t *memory_object, + vm_size_t object_size) +{ + return allowed (default_pager, O_EXEC) + ?: default_pager_object_create (real_defpager, memory_object, object_size); +} + +kern_return_t +S_default_pager_info (mach_port_t default_pager, default_pager_info_t *info) +{ + return allowed (default_pager, O_READ) + ?: default_pager_info (real_defpager, info); +} + +kern_return_t +S_default_pager_objects (mach_port_t default_pager, + default_pager_object_array_t *objects, + mach_msg_type_number_t *objectsCnt, + mach_port_array_t *ports, + mach_msg_type_number_t *portsCnt) +{ + return allowed (default_pager, O_WRITE) + ?: default_pager_objects (real_defpager, + objects, objectsCnt, ports, portsCnt); +} + +kern_return_t +S_default_pager_object_pages (mach_port_t default_pager, + mach_port_t memory_object, + default_pager_page_array_t *pages, + mach_msg_type_number_t *pagesCnt) +{ + return allowed (default_pager, O_WRITE) + ?: default_pager_object_pages (real_defpager, memory_object, + pages, pagesCnt); +} + + +kern_return_t +S_default_pager_paging_file (mach_port_t default_pager, + mach_port_t master_device_port, + default_pager_filename_t filename, + boolean_t add) +{ + return allowed (default_pager, O_WRITE) + ?: default_pager_paging_file (real_defpager, dev_master, filename, add) + ?: mach_port_deallocate (mach_task_self (), master_device_port); +} + +kern_return_t +S_default_pager_paging_storage (mach_port_t default_pager, + mach_port_t device, + recnum_t *runs, mach_msg_type_number_t nruns, + default_pager_filename_t name, + boolean_t add) +{ + return allowed (default_pager, O_WRITE) + ?: default_pager_paging_storage (real_defpager, dev_master, + runs, nruns, name, add) + ?: mach_port_deallocate (mach_task_self (), device); +} + +kern_return_t +S_default_pager_object_set_size (mach_port_t memory_object, + mach_port_seqno_t seqno, + vm_size_t object_size_limit) +{ + /* This is sent to an object, not the control port. */ + return MIG_BAD_ID; +} + + +/* Trivfs hooks */ + +int trivfs_fstype = FSTYPE_MISC; +int trivfs_fsid; + +int trivfs_support_read = 1; +int trivfs_support_write = 1; +int trivfs_support_exec = 1; + +int trivfs_allow_open = O_READ | O_WRITE | O_EXEC; + +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); +} + +kern_return_t +trivfs_S_io_read (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t replytype, + char **data, + mach_msg_type_number_t *datalen, + loff_t offs, + mach_msg_type_number_t amt) +{ + if (!cred) + return EOPNOTSUPP; + return EIO; +} + +kern_return_t +trivfs_S_io_write (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t replytype, + char *data, mach_msg_type_number_t datalen, + loff_t offs, mach_msg_type_number_t *amt) +{ + if (!cred) + return EOPNOTSUPP; + return EIO; +} + +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; +} + +const char *argp_program_version = STANDARD_HURD_VERSION (proxy-defpager); + +static const struct argp argp = +{doc: "\ +Access to control interfaces of Mach default pager.\n\ +This translator should normally be set on " _SERVERS_DEFPAGER "."}; + +int +proxy_defpager_demuxer (mach_msg_header_t *inp, + mach_msg_header_t *outp) +{ + extern int default_pager_server (mach_msg_header_t *, mach_msg_header_t *); + + return default_pager_server (inp, outp) + || trivfs_demuxer (inp, outp); +} + +int +main (int argc, char **argv) +{ + error_t err; + mach_port_t bootstrap; + struct trivfs_control *fsys; + mach_port_t host_priv; + + argp_parse (&argp, argc, argv, 0, 0, 0); + + err = get_privileged_ports (&host_priv, &dev_master); + if (err) + error (2, err, "cannot get privileged ports"); + real_defpager = MACH_PORT_NULL; + err = vm_set_default_memory_manager (host_priv, &real_defpager); + mach_port_deallocate (mach_task_self (), host_priv); + if (err) + error (3, err, "vm_set_default_memory_manager"); + if (real_defpager == MACH_PORT_NULL) + error (1, 0, "no default memory manager set!"); + + task_get_bootstrap_port (mach_task_self (), &bootstrap); + if (bootstrap == MACH_PORT_NULL) + error (1, 0, "Must be started as a translator"); + + trivfs_fsid = getpid (); + + /* Reply to our parent. */ + err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys); + mach_port_deallocate (mach_task_self (), bootstrap); + if (err) + error (4, err, "Contacting parent"); + + /* Launch. */ + ports_manage_port_operations_multithread (fsys->pi.bucket, + proxy_defpager_demuxer, + 2 * 60 * 1000, 0, 0); + + return 0; +} diff --git a/trans/streamio.c b/trans/streamio.c new file mode 100644 index 00000000..c563c03c --- /dev/null +++ b/trans/streamio.c @@ -0,0 +1,1161 @@ +/* A translator for handling stream devices. + + Copyright (C) 2001,02 Free Software Foundation, Inc. + + Written by OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp> + + 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 <string.h> +#include <assert.h> +#include <stdio.h> +#include <fcntl.h> +#include <argp.h> +#include <error.h> + +#include <mach.h> +#include <device/device.h> +#include <device/device_request.h> + +#include <hurd.h> +#include <hurd/ports.h> +#include <hurd/trivfs.h> +#include <version.h> + +/* The global lock */ +struct mutex global_lock; + +/* Wakeup when device_open is finished */ +struct condition open_alert; + +/* Wakeup for select */ +struct condition select_alert; + +/* Bucket for all out ports */ +struct port_bucket *streamdev_bucket; + +/* The buffers we use */ +struct buffer *input_buffer, *output_buffer; + + +/* Information about a buffer. */ +struct buffer +{ + /* Point to the head of the buffer. */ + char *head; + /* Point to the tail of the buffer. */ + char *tail; + /* The buffer array size. */ + size_t size; + /* Wakeup when the buffer is not empty or not full. */ + struct condition *wait; + /* The buffer. */ + char buf[0]; +}; + +/* Create a new buffer structure with SIZE, returning the pointer. */ +static inline struct buffer * +create_buffer (size_t size) +{ + struct buffer *new = malloc (sizeof (struct buffer) + size); + assert (new); + new->head = new->tail = new->buf; + new->size = size; + new->wait = malloc (sizeof (struct condition)); + assert (new->wait); + condition_init (new->wait); + return new; +} + +/* Return the size of B. */ +static inline size_t +buffer_size (struct buffer *b) +{ + return b->tail - b->head; +} + +/* Return how much characters can be read from B. */ +static inline size_t +buffer_readable (struct buffer *b) +{ + return buffer_size (b); +} + +/* Return how much characters can be written to B. */ +static inline size_t +buffer_writable (struct buffer *b) +{ + return b->size - buffer_size (b); +} + +/* Flush B. */ +static inline void +clear_buffer (struct buffer *b) +{ + if (b == 0) + return; + b->head = b->tail = b->buf; + condition_broadcast (b->wait); +} + +/* Read up to LEN bytes from B to DATA, returning the amount actually read. */ +static inline size_t +buffer_read (struct buffer *b, void *data, size_t len) +{ + size_t max = buffer_size (b); + + if (len > max) + len = max; + + memcpy (data, b->head, len); + b->head += len; + + if (b->head > b->buf + b->size / 2) + { + size_t size = buffer_size (b); + + memmove (b->buf, b->head, size); + b->head = b->buf; + b->tail = b->buf + size; + } + + condition_broadcast (b->wait); + return len; +} + +/* Write LEN bytes from DATA to B, returning the amount actually written. */ +static inline size_t +buffer_write (struct buffer *b, void *data, size_t len) +{ + size_t size = buffer_writable (b); + + if (len > size) + len = size; + + memcpy (b->tail, data, len); + b->tail += len; + + condition_broadcast (b->wait); + return len; +} + + +/* Open a new device structure for the device NAME with MODE. If an error + occurs, the error code is returned, otherwise 0. */ +error_t dev_open (const char *name, dev_mode_t mode); + +/* Check if the device is already opened. */ +int dev_already_opened (void); + +/* Close the device. */ +void dev_close (void); + +/* Read up to AMOUNT bytes, returned in BUF and LEN. If NOWAIT is non-zero + and the buffer is empty, then returns EWOULDBLOCK. If an error occurs, + the error code is returned, otherwise 0. */ +error_t dev_read (size_t amount, void **buf, size_t *len, int nowait); + +/* Return current readable size in AMOUNT. If an error occurs, the error + code is returned, otherwise 0. */ +error_t dev_readable (size_t *amount); + +/* Write LEN bytes from BUF, returning the amount actually written + in AMOUNT. If NOWAIT is non-zero and the buffer is full, then returns + EWOULDBLOCK. If an error occurs, the error code is returned, + otherwise 0. */ +error_t dev_write (void *buf, size_t len, size_t *amount, int nowait); + +/* Try and write out any pending writes to the device. If WAIT is non-zero, + will wait for any activity to cease. */ +error_t dev_sync (int wait); + + + +static struct argp_option options[] = +{ + {"rdev", 'n', "ID", 0, + "The stat rdev number for this node; may be either a" + " single integer, or of the form MAJOR,MINOR"}, + {"readonly", 'r', 0, 0, "Disallow writing"}, + {"rdonly", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, + {"ro", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, + {"writable", 'w', 0, 0, "Allow writing"}, + {"rdwr", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, + {"rw", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, + {"writeonly", 'W',0, 0, "Disallow reading"}, + {"wronly", 0, 0, OPTION_ALIAS | OPTION_HIDDEN}, + {0} +}; + +static const char args_doc[] = "DEVICE"; +static const char doc[] = "Translator for stream devices."; + +const char *argp_program_version = STANDARD_HURD_VERSION (streamio); + + +static char *stream_name; +static int rdev; +static int nperopens; + +/* Parse a single option. */ +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case 'r': + trivfs_allow_open = O_READ; + break; + case 'w': + trivfs_allow_open = O_RDWR; + break; + case 'W': + trivfs_allow_open = O_WRITE; + break; + + case 'n': + { + char *start = arg; + char *end; + + rdev = strtoul (start, &end, 0); + if (*end == ',') + /* MAJOR,MINOR form */ + { + start = end + 1; + rdev = (rdev << 8) + strtoul (start, &end, 0); + } + + if (end == start || *end != '\0') + { + argp_error (state, "%s: Invalid argument to --rdev", arg); + return EINVAL; + } + } + break; + + case ARGP_KEY_ARG: + stream_name = arg; + break; + + case ARGP_KEY_END: + if (stream_name == 0) + argp_usage (state); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static const struct argp argp = { options, parse_opt, args_doc, doc }; + + +int +demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp) +{ + extern int device_reply_server (mach_msg_header_t *, mach_msg_header_t *); + + return (trivfs_demuxer (inp, outp) + || device_reply_server (inp, outp)); +} + +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 (2, 0, "Must be started as a translator"); + + streamdev_bucket = ports_create_bucket (); + + err = trivfs_startup (bootstrap, 0, + 0, streamdev_bucket, 0, streamdev_bucket, + &fsys); + if (err) + error (3, err, "trivfs_startup"); + + mutex_init (&global_lock); + + condition_init (&open_alert); + condition_init (&select_alert); + + if (trivfs_allow_open & O_READ) + { + input_buffer = create_buffer (256); + condition_implies (input_buffer->wait, &select_alert); + } + if (trivfs_allow_open & O_WRITE) + { + output_buffer = create_buffer (256); + condition_implies (output_buffer->wait, &select_alert); + } + + /* Launch */ + ports_manage_port_operations_multithread (streamdev_bucket, demuxer, + 0, 0, 0); + + return 0; +} + + +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; + +static error_t +open_hook (struct trivfs_control *cntl, struct iouser *user, int flags) +{ + error_t err; + dev_mode_t mode; + + if (flags & O_WRITE & ~trivfs_allow_open) + return EROFS; + if (flags & O_READ & ~trivfs_allow_open) + return EIO; + + if ((flags & (O_READ|O_WRITE)) == 0) + return 0; + + /* XXX */ + if (flags & O_ASYNC) + return EOPNOTSUPP; + + mutex_lock (&global_lock); + + mode = 0; + if (flags & O_READ) + mode |= D_READ; + if (flags & O_WRITE) + mode |= D_WRITE; + + if (!dev_already_opened ()) + { + err = dev_open (stream_name, mode); + if (err) + { + mutex_unlock (&global_lock); + return err; + } + + if (!(flags & O_NONBLOCK)) + { + if (hurd_condition_wait (&open_alert, &global_lock)) + { + mutex_unlock (&global_lock); + return EINTR; + } + + if (!dev_already_opened ()) + { + mutex_unlock (&global_lock); + return ENODEV; + } + } + } + + mutex_unlock (&global_lock); + return 0; +} + +error_t (*trivfs_check_open_hook) (struct trivfs_control *, + struct iouser *, int) + = open_hook; + +static error_t +po_create_hook (struct trivfs_peropen *po) +{ + mutex_lock (&global_lock); + nperopens++; + mutex_unlock (&global_lock); + return 0; +} + +error_t (*trivfs_peropen_create_hook) (struct trivfs_peropen *) = + po_create_hook; + +static void +po_destroy_hook (struct trivfs_peropen *po) +{ + mutex_lock (&global_lock); + nperopens--; + if (!nperopens) + { + if (dev_already_opened ()) + { + clear_buffer (input_buffer); + dev_close (); + } + } + mutex_unlock (&global_lock); +} + +void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *) + = po_destroy_hook; + +void +trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st) +{ + st->st_blksize = vm_page_size; + st->st_size = 0; + + st->st_rdev = rdev; + st->st_mode &= ~S_IFMT; + st->st_mode |= S_IFCHR; + if ((trivfs_allow_open & O_READ) == 0) + st->st_mode &= ~(S_IRUSR | S_IRGRP | S_IROTH); + if ((trivfs_allow_open & O_WRITE) == 0) + st->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); +} + +error_t +trivfs_goaway (struct trivfs_control *fsys, int flags) +{ + error_t err; + int force = (flags & FSYS_GOAWAY_FORCE); + int nosync = (flags & FSYS_GOAWAY_NOSYNC); + struct port_class *root_port_class = fsys->protid_class; + + mutex_lock (&global_lock); + + if (!dev_already_opened ()) + exit (0); + + err = ports_inhibit_class_rpcs (root_port_class); + if (err == EINTR || (err && !force)) + { + mutex_unlock (&global_lock); + return err; + } + + if (force && nosync) + exit (0); + + if (!force && ports_count_class (root_port_class) > 0) + goto busy; + + if (!nosync) + dev_close (); + exit (0); + + busy: + ports_enable_class (root_port_class); + ports_resume_class_rpcs (root_port_class); + mutex_unlock (&global_lock); + + return EBUSY; +} + + +error_t +trivfs_S_io_read (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t reply_type, + char **data, mach_msg_type_number_t *data_len, + loff_t offs, mach_msg_type_number_t amount) +{ + error_t err; + + if (!cred) + return EOPNOTSUPP; + + if (!(cred->po->openmodes & O_READ)) + return EBADF; + + mutex_lock (&global_lock); + err = dev_read (amount, (void **)data, data_len, cred->po->openmodes & O_NONBLOCK); + mutex_unlock (&global_lock); + return err; +} + +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) +{ + error_t err; + + if (!cred) + return EOPNOTSUPP; + + if (!(cred->po->openmodes & O_READ)) + return EBADF; + + mutex_lock (&global_lock); + err = dev_readable (amount); + mutex_unlock (&global_lock); + return err; +} + +error_t +trivfs_S_io_write (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t reply_type, + char *data, mach_msg_type_number_t data_len, + loff_t offs, mach_msg_type_number_t *amount) +{ + error_t err; + + if (!cred) + return EOPNOTSUPP; + + if (!(cred->po->openmodes & O_WRITE)) + return EBADF; + + mutex_lock (&global_lock); + err = dev_write ((void *)data, data_len, amount, cred->po->openmodes & O_NONBLOCK); + mutex_unlock (&global_lock); + return err; +} + +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) +{ + if (!cred) + return EOPNOTSUPP; + else + return ESPIPE; +} + +error_t +trivfs_S_io_select (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t reply_type, + int *type) +{ + int available; + + if (!cred) + return EOPNOTSUPP; + + if (!(cred->po->openmodes & O_WRITE) && (*type & SELECT_WRITE)) + return EBADF; + + *type &= SELECT_READ | SELECT_WRITE; + + if (*type == 0) + return 0; + + available = 0; + + while (1) + { + mutex_lock (&global_lock); + if ((*type & SELECT_READ) && buffer_readable (input_buffer)) + available |= SELECT_READ; + if (output_buffer) + { + if ((*type & SELECT_WRITE) && buffer_writable (output_buffer)) + available |= SELECT_WRITE; + } + + if (available) + { + *type = available; + mutex_unlock (&global_lock); + return 0; + } + + if (cred->po->openmodes & O_NONBLOCK) + { + mutex_unlock (&global_lock); + return EWOULDBLOCK; + } + + ports_interrupt_self_on_port_death (cred, reply); + if (hurd_condition_wait (&select_alert, &global_lock)) + { + *type = 0; + mutex_unlock (&global_lock); + return EINTR; + } + } +} + +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) +{ + if (!cred) + return EOPNOTSUPP; + else if (!(cred->po->openmodes & O_WRITE)) + return EBADF; + else + return 0; +} + +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; +} + +error_t +trivfs_S_file_sync (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t reply_type, + int wait, int omit_metadata) +{ + error_t err; + + if (!cred) + return EOPNOTSUPP; + + mutex_lock (&global_lock); + err = dev_sync (wait); + mutex_unlock (&global_lock); + return err; +} + +error_t +trivfs_S_file_syncfs (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t reply_type, + int wait, int dochildren) +{ + error_t err; + + if (!cred) + return EOPNOTSUPP; + + mutex_lock (&global_lock); + err = dev_sync (wait); + mutex_unlock (&global_lock); + return err; +} + + +/* This flag is set if there is an outstanding device_write. */ +static int output_pending; + +/* This flag is set if there is an outstanding device_read. */ +static int input_pending; + +/* This flag is set if there is an outstanding device_open. */ +static int open_pending; + +static char pending_output[IO_INBAND_MAX]; +static int npending_output; + +/* This flag is set if EOF is returned. */ +static int eof; + +/* The error number. */ +static error_t err; + +static struct port_class *phys_reply_class; + +/* The Mach device_t representing the stream. */ +static device_t phys_device = MACH_PORT_NULL; + +/* The ports we get replies on for device calls. */ +static mach_port_t phys_reply_writes = MACH_PORT_NULL; +static mach_port_t phys_reply = MACH_PORT_NULL; + +/* The port-info structures. */ +static struct port_info *phys_reply_writes_pi; +static struct port_info *phys_reply_pi; + +static device_t device_master; + +/* The block size and whole size of the device. */ +static size_t dev_blksize; +static size_t dev_size; + + +/* Open a new device structure for the device NAME with MODE. If an error + occurs, the error code is returned, otherwise 0. */ +/* Be careful that the global lock is already locked. */ +error_t +dev_open (const char *name, dev_mode_t mode) +{ + if (open_pending || (phys_device != MACH_PORT_NULL)) + return 0; + + err = get_privileged_ports (0, &device_master); + if (err) + return err; + + phys_reply_class = ports_create_class (0, 0); + err = ports_create_port (phys_reply_class, streamdev_bucket, + sizeof (struct port_info), &phys_reply_pi); + if (err) + { + mach_port_deallocate (mach_task_self (), device_master); + return err; + } + + phys_reply = ports_get_right (phys_reply_pi); + mach_port_insert_right (mach_task_self (), phys_reply, phys_reply, + MACH_MSG_TYPE_MAKE_SEND); + + if (output_buffer) + { + err = ports_create_port (phys_reply_class, streamdev_bucket, + sizeof (struct port_info), + &phys_reply_writes_pi); + if (err) + { + mach_port_deallocate (mach_task_self (), phys_reply); + phys_reply = MACH_PORT_NULL; + ports_port_deref (phys_reply_pi); + phys_reply_pi = 0; + mach_port_deallocate (mach_task_self (), device_master); + return err; + } + + phys_reply_writes = ports_get_right (phys_reply_writes_pi); + mach_port_insert_right (mach_task_self (), phys_reply_writes, + phys_reply_writes, MACH_MSG_TYPE_MAKE_SEND); + } + + err = device_open_request (device_master, phys_reply, mode, name); + if (err) + { + mach_port_deallocate (mach_task_self (), phys_reply); + phys_reply = MACH_PORT_NULL; + ports_port_deref (phys_reply_pi); + phys_reply_pi = 0; + if (output_buffer) + { + mach_port_deallocate (mach_task_self (), phys_reply_writes); + phys_reply_writes = MACH_PORT_NULL; + ports_port_deref (phys_reply_writes_pi); + phys_reply_writes_pi = 0; + } + mach_port_deallocate (mach_task_self (), device_master); + return err; + } + + open_pending = 1; + return 0; +} + +kern_return_t +device_open_reply (mach_port_t reply, int returncode, mach_port_t device) +{ + int sizes[DEV_GET_SIZE_COUNT]; + size_t sizes_len = DEV_GET_SIZE_COUNT; + int amount; + + if (reply != phys_reply) + return EOPNOTSUPP; + + mutex_lock (&global_lock); + + open_pending = 0; + condition_broadcast (&open_alert); + + if (returncode != 0) + { + dev_close (); + mutex_unlock (&global_lock); + return 0; + } + + phys_device = device; + eof = 0; + + /* Get the block size and the whole size. */ + err = device_get_status (device, DEV_GET_SIZE, sizes, &sizes_len); + if (err == D_INVALID_OPERATION) + { + /* XXX Assume that the block size is 1 and the whole size is 0. */ + dev_blksize = 1; + dev_size = 0; + err = 0; + } + else if (err == 0) + { + assert (sizes_len == DEV_GET_SIZE_COUNT); + + dev_blksize = sizes[DEV_GET_SIZE_RECORD_SIZE]; + dev_size = sizes[DEV_GET_SIZE_DEVICE_SIZE]; + + assert (dev_blksize && dev_blksize <= IO_INBAND_MAX); + } + else + { + dev_close (); + mutex_unlock (&global_lock); + return 0; + } + + amount = vm_page_size; + if (dev_blksize != 1) + amount = amount / dev_blksize * dev_blksize; + + mutex_unlock (&global_lock); + return 0; +} + +/* Check if the device is already opened. */ +/* Be careful that the global lock is already locked. */ +int +dev_already_opened (void) +{ + return (phys_device != MACH_PORT_NULL); +} + +/* Close the device. */ +/* Be careful that the global lock is already locked. */ +void +dev_close (void) +{ + /* Sync all pending writes. */ + dev_sync (1); + + device_close (phys_device); + mach_port_deallocate (mach_task_self (), phys_device); + phys_device = MACH_PORT_NULL; + + mach_port_deallocate (mach_task_self (), phys_reply); + phys_reply = MACH_PORT_NULL; + ports_port_deref (phys_reply_pi); + phys_reply_pi = 0; + clear_buffer (input_buffer); + input_pending = 0; + + if (output_buffer) + { + mach_port_deallocate (mach_task_self (), phys_reply_writes); + phys_reply_writes = MACH_PORT_NULL; + ports_port_deref (phys_reply_writes_pi); + phys_reply_writes_pi = 0; + clear_buffer (output_buffer); + npending_output = 0; + output_pending = 0; + } +} + +/* Be careful that the global lock is already locked. */ +static error_t +start_input (int nowait) +{ + int size; + error_t err; + size_t amount; + + size = buffer_writable (input_buffer); + + if (size < dev_blksize || input_pending) + return 0; + + amount = vm_page_size; + if (dev_blksize != 1) + amount = amount / dev_blksize * dev_blksize; + + err = device_read_request_inband (phys_device, phys_reply, + nowait? D_NOWAIT : 0, + 0, amount); + if (err == D_WOULD_BLOCK) + err = 0; + if (err) + dev_close (); + else + input_pending = 1; + + return err; +} + +/* Read up to AMOUNT bytes, returned in BUF and LEN. If NOWAIT is non-zero + and the buffer is empty, then returns EWOULDBLOCK. If an error occurs, + the error code is returned, otherwise 0. */ +/* Be careful that the global lock is already locked. */ +error_t +dev_read (size_t amount, void **buf, size_t *len, int nowait) +{ + size_t max, avail; + + if (err) + return err; + + while (!buffer_readable (input_buffer)) + { + err = start_input (nowait); + if (err) + return err; + + if (eof) + { + *len = 0; + return 0; + } + + if (nowait) + return EWOULDBLOCK; + + if (hurd_condition_wait (input_buffer->wait, &global_lock)) + return EINTR; + } + + avail = buffer_size (input_buffer); + max = (amount < avail) ? amount : avail; + if (max > *len) + vm_allocate (mach_task_self (), (vm_address_t *)buf, max, 1); + + *len = buffer_read (input_buffer, *buf, max); + assert (*len == max); + + err = start_input (nowait); + return err; +} + +error_t +device_read_reply_inband (mach_port_t reply, error_t errorcode, + char *data, u_int datalen) +{ + if (reply != phys_reply) + return EOPNOTSUPP; + + mutex_lock (&global_lock); + + input_pending = 0; + err = errorcode; + if (!err) + { + if (datalen == 0) + { + eof = 1; + dev_close (); + mutex_unlock (&global_lock); + return 0; + } + + while (datalen) + { + size_t nwritten; + + while (!buffer_writable (input_buffer)) + condition_wait (input_buffer->wait, &global_lock); + + nwritten = buffer_write (input_buffer, data, datalen); + data += nwritten; + datalen -= nwritten; + condition_broadcast (input_buffer->wait); + } + } + else + { + dev_close (); + mutex_unlock (&global_lock); + return 0; + } + mutex_unlock (&global_lock); + return 0; +} + +/* Return current readable size in AMOUNT. If an error occurs, the error + code is returned, otherwise 0. */ +/* Be careful that the global lock is already locked. */ +error_t +dev_readable (size_t *amount) +{ + *amount = buffer_size (input_buffer); + return 0; +} + +/* Be careful that the global lock is already locked. */ +static error_t +start_output (int nowait) +{ + int size; + + assert (output_buffer); + + size = buffer_size (output_buffer); + + if (size < dev_blksize || output_pending) + return 0; + + if (size + npending_output > IO_INBAND_MAX) + size = IO_INBAND_MAX - npending_output; + + if (dev_blksize != 1) + size = size / dev_blksize * dev_blksize; + + buffer_read (output_buffer, pending_output + npending_output, size); + npending_output += size; + + err = device_write_request_inband (phys_device, phys_reply_writes, + nowait? D_NOWAIT : 0, + 0, pending_output, npending_output); + if (err == D_WOULD_BLOCK) + err = 0; + if (err) + dev_close (); + else + output_pending = 1; + + return err; +} + +/* Write LEN bytes from BUF, returning the amount actually written + in AMOUNT. If NOWAIT is non-zero and the buffer is full, then returns + EWOULDBLOCK. If an error occurs, the error code is returned, + otherwise 0. */ +/* Be careful that the global lock is already locked. */ +error_t +dev_write (void *buf, size_t len, size_t *amount, int nowait) +{ + if (err) + return err; + + while (!buffer_writable (output_buffer)) + { + err = start_output (nowait); + if (err) + return err; + + if (nowait) + return EWOULDBLOCK; + + if (hurd_condition_wait (output_buffer->wait, &global_lock)) + return EINTR; + } + + *amount = buffer_write (output_buffer, buf, len); + err = start_output (nowait); + + return err; +} + +error_t +device_write_reply_inband (mach_port_t reply, error_t returncode, int amount) +{ + if (reply != phys_reply_writes) + return EOPNOTSUPP; + + mutex_lock (&global_lock); + + output_pending = 0; + + if (!returncode) + { + if (amount >= npending_output) + { + npending_output = 0; + condition_broadcast (output_buffer->wait); + } + else + { + npending_output -= amount; + memmove (pending_output, pending_output + amount, npending_output); + } + } + else + dev_close (); + + mutex_unlock (&global_lock); + return 0; +} + +/* Try and write out any pending writes to the device. If WAIT is non-zero, + will wait for any activity to cease. */ +/* Be careful that the global lock is already locked. */ +error_t +dev_sync (int wait) +{ + if (err) + return err; + + if (!output_buffer || phys_device == MACH_PORT_NULL) + return 0; + + while (buffer_readable (output_buffer) >= dev_blksize) + { + err = start_output (! wait); + if (err) + return err; + + if (!wait) + return 0; + + if (hurd_condition_wait (output_buffer->wait, &global_lock)) + return EINTR; + } + + /* XXX: When the size of output_buffer is non-zero and less than + DEV_BLKSIZE, the rest will be ignored or discarded. */ + return 0; +} + +/* Unused stubs. */ +kern_return_t +device_read_reply (mach_port_t reply, kern_return_t returncode, + io_buf_ptr_t data, mach_msg_type_number_t amount) +{ + return EOPNOTSUPP; +} + +kern_return_t +device_write_reply (mach_port_t reply, kern_return_t returncode, int amount) +{ + return EOPNOTSUPP; +} diff --git a/trans/symlink.c b/trans/symlink.c index d8495f8b..03b51003 100644 --- a/trans/symlink.c +++ b/trans/symlink.c @@ -1,5 +1,5 @@ /* Translator for S_IFLNK nodes - Copyright (C) 1994 Free Software Foundation + Copyright (C) 1994, 2000, 2001, 2002 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 @@ -17,8 +17,14 @@ #include <hurd.h> #include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <argp.h> #include <hurd/fsys.h> #include <fcntl.h> +#include <errno.h> +#include <error.h> +#include <version.h> #include "fsys_S.h" mach_port_t realnode; @@ -31,37 +37,64 @@ char *linktarget; extern int fsys_server (mach_msg_header_t *, mach_msg_header_t *); +const char *argp_program_version = STANDARD_HURD_VERSION (symlink); + +static const struct argp_option options[] = + { + { 0 } + }; + +static const char args_doc[] = "TARGET"; +static const char doc[] = "A translator for symlinks." +"\vA symlink is an alias for another node in the filesystem." +"\n" +"\nA symbolic link refers to its target `by name', and contains no actual" +" reference to the target. The target referenced by the symlink is" +" looked up in the namespace of the client."; + +/* 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) + linktarget = 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) { mach_port_t bootstrap; mach_port_t control; - error_t error; - + error_t err; + + /* Parse our options... */ + argp_parse (&argp, argc, argv, 0, 0, 0); + 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); - } + error (1, 0, "Must be started as a translator"); 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); - if (error) - { - perror ("Starting up translator"); - exit (1); - } + mach_port_insert_right (mach_task_self (), control, control, + MACH_MSG_TYPE_MAKE_SEND); + err = + fsys_startup (bootstrap, 0, control, MACH_MSG_TYPE_COPY_SEND, &realnode); + mach_port_deallocate (mach_task_self (), control); + mach_port_deallocate (mach_task_self (), bootstrap); + if (err) + error (1, err, "Starting up translator"); + io_restrict_auth (realnode, &realnodenoauth, 0, 0, 0, 0); mach_port_deallocate (mach_task_self (), realnode); @@ -69,9 +102,9 @@ main (int argc, char **argv) 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) + err = mach_msg_server_timeout (fsys_server, 0, control, + MACH_RCV_TIMEOUT, 1000 * 60 * 10); + if (err == MACH_RCV_TIMED_OUT) exit (0); } } @@ -79,10 +112,8 @@ main (int argc, char **argv) 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, + uid_t *uids, size_t nuids, + uid_t *gids, size_t ngids, int flags, retry_type *do_retry, char *retry_name, @@ -126,8 +157,7 @@ S_fsys_startup (mach_port_t bootstrap, int flags, mach_port_t control, } error_t -S_fsys_goaway (mach_port_t control, - int flags) +S_fsys_goaway (mach_port_t control, int flags) { exit (0); } @@ -157,12 +187,9 @@ S_fsys_get_options (mach_port_t control, 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, + uid_t *uids, size_t nuids, + uid_t *gids, size_t ngids, + char *handle, size_t handllen, mach_port_t *pt, mach_msg_type_name_t *pttype) { |