summaryrefslogtreecommitdiff
path: root/trans
diff options
context:
space:
mode:
Diffstat (limited to 'trans')
-rw-r--r--trans/ChangeLog396
-rw-r--r--trans/Makefile40
-rw-r--r--trans/bogus-fifo.c1
-rw-r--r--trans/crash.c230
-rw-r--r--trans/devport.c185
-rw-r--r--trans/fakeroot.c925
-rw-r--r--trans/fifo.c97
-rw-r--r--trans/firmlink.c38
-rw-r--r--trans/fwd.c14
-rw-r--r--trans/hello-mt.c331
-rw-r--r--trans/hello.c291
-rw-r--r--trans/ifsock.c38
-rw-r--r--trans/magic.c589
-rw-r--r--trans/new-fifo.c100
-rw-r--r--trans/null.c83
-rw-r--r--trans/password.c224
-rw-r--r--trans/proxy-defpager.c278
-rw-r--r--trans/streamio.c1161
-rw-r--r--trans/symlink.c97
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)
{