summaryrefslogtreecommitdiff
path: root/trans
diff options
context:
space:
mode:
authorMiles Bader <miles@gnu.org>1997-02-21 21:55:41 +0000
committerMiles Bader <miles@gnu.org>1997-02-21 21:55:41 +0000
commita6d04a211c6f48bc23aea892c8b9544a22401714 (patch)
treeb671d487e4359ba8eacbe6f625bc0f27fa2e67d2 /trans
parent37e138a0b010037798144653c56c7e151bd40554 (diff)
Initial checkin.
Diffstat (limited to 'trans')
-rw-r--r--trans/firmlink.c271
1 files changed, 271 insertions, 0 deletions
diff --git a/trans/firmlink.c b/trans/firmlink.c
new file mode 100644
index 00000000..effae3d4
--- /dev/null
+++ b/trans/firmlink.c
@@ -0,0 +1,271 @@
+/* A translator for `firmlinks'
+
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <argp.h>
+#include <error.h>
+
+#include <hurd/trivfs.h>
+
+#include <version.h>
+
+const char *argp_program_version = STANDARD_HURD_VERSION (firmlink);
+
+static const struct argp_option options[] =
+{
+ { "invisible", 'i', 0, 0, "Don't resemble a symlink" },
+ { 0 }
+};
+
+static const char args_doc[] = "TARGET";
+static const char doc[] = "A translator for firmlinks"
+"\vA firmlink is sort of half-way between a symbolic link and a hard link;"
+"\n"
+"\nLike a symbolic link, it is `by name', and contains no actual reference to"
+" the target. However, the lookup returns a node which will redirect parent"
+" lookups so that attempts to find the cwd that go through the link will"
+" reflect the link name, not the target name. The target referenced by the"
+" firmlink is looked up in the namespace of the translator, not the client.";
+
+/* Link parameters. */
+static char *target = 0; /* What we translate too. */
+static int invisible = 0; /* Return a link node to O_NOLINK opens? */
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ if (key == 'i')
+ invisible = 1;
+ else if (key == ARGP_KEY_ARG && state->arg_num == 0)
+ target = arg;
+ else if (key == ARGP_KEY_ARG || key == ARGP_KEY_NO_ARGS)
+ argp_usage (state);
+ else
+ return ARGP_ERR_UNKNOWN;
+ return 0;
+}
+
+static struct argp argp = { 0, parse_opt, args_doc, doc };
+
+void
+main (int argc, char **argv)
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+
+ /* Parse our options... */
+ argp_parse (&argp, argc, argv, 0, 0, 0);
+
+ task_get_bootstrap_port (mach_task_self (), &bootstrap);
+ if (bootstrap == MACH_PORT_NULL)
+ error (1, 0, "Must be started as a translator");
+
+ /* Reply to our parent */
+ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+ if (err)
+ error (2, err, "Contacting parent");
+
+ /* Launch. */
+ ports_manage_port_operations_one_thread (fsys->pi.bucket, trivfs_demuxer, 0);
+
+ exit (0);
+}
+
+static error_t
+firmlink (mach_port_t parent, const char *target_name, int flags,
+ mach_port_t *link)
+{
+ error_t err;
+ file_t authed_link;
+ file_t target = file_name_lookup (target_name, flags & ~O_CREAT, 0);
+
+ if (target == MACH_PORT_NULL)
+ return errno;
+
+ err = file_reparent (target, parent, &authed_link);
+ mach_port_deallocate (mach_task_self (), target);
+ mach_port_deallocate (mach_task_self (), parent);
+
+ if (! err)
+ {
+ err = io_restrict_auth (authed_link, link, 0, 0, 0, 0);
+ mach_port_deallocate (mach_task_self (), authed_link);
+ }
+
+ return err;
+}
+
+/* Trivfs hooks */
+
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+
+int trivfs_support_read = 1;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+
+int trivfs_allow_open = O_READ;
+
+static error_t
+getroot (struct trivfs_control *cntl,
+ mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
+ mach_port_t dotdot,
+ uid_t *uids, u_int nuids, uid_t *gids, u_int ngids,
+ int flags,
+ retry_type *do_retry, char *retry_name,
+ mach_port_t *node, mach_msg_type_name_t *node_type)
+{
+ error_t err;
+
+ if ((flags & O_NOLINK) && !invisible)
+ /* Cons up our own node. */
+ return EAGAIN;
+
+ err = firmlink (dotdot, target, flags, node);
+ if (!err)
+ {
+ *node_type = MACH_MSG_TYPE_MOVE_SEND;
+ *do_retry = FS_RETRY_REAUTH;
+ retry_name[0] = '\0';
+ }
+
+ return err;
+}
+
+/* Called by trivfs_S_fsys_getroot before any other processing takes place;
+ if the return value is EAGAIN, normal trivfs getroot processing continues,
+ otherwise the rpc returns with that return value. */
+error_t (*trivfs_getroot_hook) () = getroot;
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+{
+ st->st_size = strlen (target);
+ st->st_blocks = 0;
+ st->st_mode &= ~S_IFMT;
+ st->st_mode |= S_IFLNK;
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *cntl, int flags)
+{
+ error_t err;
+ int force = (flags & FSYS_GOAWAY_FORCE);
+ struct port_bucket *bucket = ((struct port_info *)cntl)->bucket;
+
+ err = ports_inhibit_bucket_rpcs (bucket);
+ if (err == EINTR || (err && !force))
+ return err;
+
+ if (ports_count_class (cntl->protid_class) > 0 && !force)
+ /* Still some opens, and we're not being forced to go away, so don't. */
+ {
+ ports_enable_class (cntl->protid_class);
+ ports_resume_bucket_rpcs (bucket);
+ return EBUSY;
+ }
+
+ exit (0);
+}
+
+/* We store the file offset in po->hook (ick!) */
+
+/* Read data from an IO object. If offset if -1, read from the object
+ maintained file pointer. If the object is not seekable, offset is
+ ignored. The amount desired to be read is in AMT. */
+error_t
+trivfs_S_io_read (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ vm_address_t *data, mach_msg_type_number_t *data_len,
+ off_t offs, mach_msg_type_number_t amount)
+{
+ error_t err = 0;
+
+ if (! cred)
+ err = EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_READ))
+ err = EBADF;
+ else
+ {
+ off_t max = strlen (target);
+ off_t start = offs >= 0 ? offs : (off_t)cred->po->hook;
+ if (start < 0)
+ return EINVAL;
+ if (start + amount > max)
+ amount = max - start;
+ if (amount > *data_len)
+ err = vm_allocate (mach_task_self (), data, amount, 1);
+ if (!err && amount > 0)
+ {
+ memcpy ((char *)(*data + start), target, amount);
+ if (offs < 0)
+ cred->po->hook = (void *)(start + amount); /* Update PO offset. */
+ }
+ *data_len = amount;
+ }
+
+ return err;
+}
+
+/* Tell how much data can be read from the object without blocking for
+ a "long time" (this should be the same meaning of "long time" used
+ by the nonblocking flag. */
+error_t
+trivfs_S_io_readable (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ mach_msg_type_number_t *amount)
+{
+ if (! cred)
+ return EOPNOTSUPP;
+ else if (! (cred->po->openmodes & O_READ))
+ return EBADF;
+ else if ((off_t)cred->po->hook < 0)
+ return EINVAL;
+ else
+ *amount = strlen (target) - (off_t)cred->po->hook;
+ return 0;
+}
+
+/* Change current read/write offset */
+error_t
+trivfs_S_io_seek (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ off_t offset, int whence, off_t *new_offset)
+{
+ return EOPNOTSUPP;
+}
+
+/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
+ Block until one of the indicated types of i/o can be done "quickly", and
+ return the types that are then available. ID_TAG is returned as passed; it
+ is just for the convenience of the user in matching up reply messages with
+ specific requests sent. */
+error_t
+trivfs_S_io_select (struct trivfs_protid *cred,
+ mach_port_t reply, mach_msg_type_name_t reply_type,
+ int *type, int *tag)
+{
+ return EOPNOTSUPP;
+}