From 4fe21e255e483a711f898227b90b130afd969b33 Mon Sep 17 00:00:00 2001 From: Manolis Ragkousis Date: Thu, 12 May 2016 15:08:36 +0300 Subject: [PATCH] libhurdutil: New library containing utils to be used by Guix. * libhurdutil/hurdutil.h: New file. * libhurdutil/settrans.c: New file. * libhurdutil/Makefile: New file. * utils/Makefile (HURDLIBS, settrans): Use the new library. * utils/settrans.c: Update to use the new library. * Makefile: (lib-subdirs): Add library. --- Makefile | 2 +- libhurdutil/Makefile | 28 +++ libhurdutil/hurdutil.h | 78 +++++++ libhurdutil/settrans.c | 377 ++++++++++++++++++++++++++++++++++ utils/Makefile | 4 +- utils/settrans.c | 536 ++++++++++++++----------------------------------- 6 files changed, 633 insertions(+), 392 deletions(-) create mode 100644 libhurdutil/Makefile create mode 100644 libhurdutil/hurdutil.h create mode 100644 libhurdutil/settrans.c diff --git a/Makefile b/Makefile index d48baaa..e712767 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ include ./Makeconf lib-subdirs = libshouldbeinlibc libihash libiohelp libports libthreads \ libpager libfshelp libdiskfs libtrivfs libps \ libnetfs libpipe libstore libhurdbugaddr libftpconn libcons \ - libhurd-slab + libhurd-slab libhurdutil # Hurd programs prog-subdirs = auth proc exec term \ diff --git a/libhurdutil/Makefile b/libhurdutil/Makefile new file mode 100644 index 0000000..2e0e642 --- /dev/null +++ b/libhurdutil/Makefile @@ -0,0 +1,28 @@ +# Copyright (C) 2016 Free Software Foundation, Inc. +# +# This file is part of the GNU Hurd. +# +# The GNU Hurd is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2, or (at +# your option) any later version. +# +# The GNU Hurd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +dir := libhurdutil +makemode := library + +libname := libhurdutil +SRCS = settrans.c +installhdrs = hurdutil.h + +OBJS = $(SRCS:.c=.o) + +include ../Makeconf diff --git a/libhurdutil/hurdutil.h b/libhurdutil/hurdutil.h new file mode 100644 index 0000000..5786cff --- /dev/null +++ b/libhurdutil/hurdutil.h @@ -0,0 +1,78 @@ +/* hurdutil.h - Hurd utils interface. + Copyright (C) 2016 Free Software Foundation, Inc. + Written by Manolis Fragkiskos Ragkousis . + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _HURD_UTIL_H +#define _HURD_UTIL_H + +#include +#include +#include +#include +#include + +#include + +struct settrans_flags +{ + /* The name of the node we're putting the translator on. */ + char *node_name; + + /* Flags to pass to file_set_translator. */ + int lookup_flags; + int goaway_flags; + + /* Various option flags. */ + int passive; + int active; + int keep_active; + int pause; + int kill_active; + int orphan; + int start; + int stack; + int excl; + int timeout; + char *pid_file; + char *underlying_node_name; + int underlying_lookup_flags; + char **chroot_command; + char *chroot_chdir; + + /* The translator's arg vector, in '\0' separated format. */ + char *argz; + size_t argz_len; +}; +typedef struct settrans_flags *settrans_flags_t; + +/* Initialize the flags to be used. */ +void settrans_flags_init (settrans_flags_t flags); + +/* Release the memory allocated. */ +void settrans_flags_cleanup (settrans_flags_t flags); + +/* Create the struct containing the flags and initialize them. + If a memory allocation error occurs, ENOMEM is returned, + otherwise 0.*/ +error_t settrans_flags_create (settrans_flags_t *flags); + +/* Set a translator according to the flags passed. On success return 0. */ +error_t settrans(settrans_flags_t flags); + +#endif /* _HURD_UTIL_H */ diff --git a/libhurdutil/settrans.c b/libhurdutil/settrans.c new file mode 100644 index 0000000..eeaa964 --- /dev/null +++ b/libhurdutil/settrans.c @@ -0,0 +1,377 @@ +/* settrans.c - Set a file's translator. + + Copyright (C) 1995,96,97,98,2001,02,13,14,16 + Free Software Foundation, Inc. + Written by Miles Bader + Written by Manolis Fragkiskos Ragkousis . + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include "hurdutil.h" + +#define DEFAULT_TIMEOUT 60 + +/* Authentication of the current process. */ +uid_t *uids; +gid_t *gids; +size_t uids_len, gids_len; + +/* Initialize and populate the uids and gids vectors. */ +error_t +get_credentials (void) +{ + /* Fetch uids... */ + uids_len = geteuids (0, 0); + if (uids_len < 0) + return errno; + + uids = malloc (uids_len * sizeof (uid_t)); + if (! uids) + return ENOMEM; + + uids_len = geteuids (uids_len, uids); + if (uids_len < 0) + return errno; + + /* ... and gids. */ + gids_len = getgroups (0, 0); + if (gids_len < 0) + return errno; + + gids = malloc (gids_len * sizeof (gid_t)); + if (! uids) + return ENOMEM; + + gids_len = getgroups (gids_len, gids); + if (gids_len < 0) + return errno; + + return 0; +} + +/* ---------------------------------------------------------------- */ + +void +settrans_flags_init (settrans_flags_t flags) +{ + flags->node_name = 0; + + flags->lookup_flags = O_NOTRANS; + flags->goaway_flags = 0; + + flags->passive = 0; + flags->active = 0; + flags->keep_active = 0; + flags->pause = 0; + flags->kill_active = 0; + flags->orphan = 0; + flags->start = 0; + flags->stack = 0; + flags->excl = 0; + flags->timeout = DEFAULT_TIMEOUT * 1000; /* ms */ + flags->pid_file = 0; + flags->underlying_node_name = NULL; + flags->chroot_command = 0; + flags->chroot_chdir = "/"; + + flags->argz; + flags->argz_len; +} + +void +settrans_flags_cleanup (settrans_flags_t flags) +{ + free(flags); +} + +error_t +settrans_flags_create (settrans_flags_t *flags) +{ + *flags = malloc (sizeof (struct settrans_flags)); + if (*flags == NULL) + return ENOMEM; + + settrans_flags_init(*flags); + + return 0; +} + +error_t settrans(settrans_flags_t flags) +{ + error_t err; + + /* The filesystem node we're putting a translator on. */ + char *node_name = flags->node_name; + file_t node; + + /* The translator's arg vector, in '\0' separated format. */ + char *argz = flags->argz; + size_t argz_len = flags->argz_len; + + /* The control port for any active translator we start up. */ + fsys_t active_control = MACH_PORT_NULL; + + /* Flags to pass to file_set_translator. */ + int active_flags = 0; + int passive_flags = 0; + int lookup_flags = flags->lookup_flags; + int goaway_flags = flags->goaway_flags; + + /* Various option flags. */ + int passive = flags->passive; + int active = flags->active; + int keep_active = flags->keep_active; + int pause = flags->pause; + int kill_active = flags->kill_active; + int orphan = flags->orphan; + int start = flags->start; + int stack = flags->stack; + char *pid_file = flags->pid_file; + int excl = flags->excl; + int timeout = flags->timeout; /* ms */ + char *underlying_node_name = flags->underlying_node_name; + int underlying_lookup_flags = flags->underlying_lookup_flags; + char **chroot_command = flags->chroot_command; + char *chroot_chdir = flags->chroot_chdir; + + if (stack) + { + underlying_node_name = node_name; + underlying_lookup_flags = lookup_flags && ~O_NOTRANS; + } + else + underlying_lookup_flags = lookup_flags; + + + if (!active && !passive && !chroot_command) + passive = 1; /* By default, set the passive translator. */ + + if (passive) + passive_flags = FS_TRANS_SET | (excl ? FS_TRANS_EXCL : 0); + if (active) + active_flags = FS_TRANS_SET | (excl ? FS_TRANS_EXCL : 0) + | (orphan ? FS_TRANS_ORPHAN : 0); + + if (passive && !active) + { + /* When setting just the passive, decide what to do with any active. */ + if (kill_active) + /* Make it go away. */ + active_flags = FS_TRANS_SET; + else if (! keep_active) + /* Ensure that there isn't one. */ + active_flags = FS_TRANS_SET | FS_TRANS_EXCL; + } + + if (start) + { + /* Retrieve the passive translator record in argz. */ + mach_port_t node = file_name_lookup (node_name, lookup_flags, 0); + if (node == MACH_PORT_NULL) + error (4, errno, "%s", node_name); + + char buf[1024]; + argz = buf; + argz_len = sizeof (buf); + + err = file_get_translator (node, &argz, &argz_len); + if (err == EINVAL) + error (4, 0, "%s: no passive translator record found", node_name); + if (err) + error (4, err, "%s", node_name); + + mach_port_deallocate (mach_task_self (), node); + } + + if ((active || chroot_command) && argz_len > 0) + { + /* Error during file lookup; we use this to avoid duplicating error + messages. */ + error_t open_err = 0; + + /* The callback to start_translator opens NODE as a side effect. */ + error_t open_node (int flags, + mach_port_t *underlying, + mach_msg_type_name_t *underlying_type, + task_t task, void *cookie) + { + if (pause) + { + fprintf (stderr, "Translator pid: %d\nPausing...", + task2pid (task)); + getchar (); + } + + if (pid_file != NULL) + { + FILE *h; + h = fopen (pid_file, "w"); + if (h == NULL) + error (4, errno, "Failed to open pid file"); + + fprintf (h, "%i\n", task2pid (task)); + fclose (h); + } + + node = file_name_lookup (node_name, flags | lookup_flags, 0666); + if (node == MACH_PORT_NULL) + { + open_err = errno; + return open_err; + } + + if (underlying_node_name) + { + *underlying = file_name_lookup (underlying_node_name, + flags | underlying_lookup_flags, + 0666); + if (! MACH_PORT_VALID (*underlying)) + { + /* For the error message. */ + node_name = underlying_node_name; + open_err = errno; + return open_err; + } + } + else + *underlying = node; + *underlying_type = MACH_MSG_TYPE_COPY_SEND; + + return 0; + } + err = fshelp_start_translator (open_node, NULL, argz, argz, argz_len, + timeout, &active_control); + if (err) + /* If ERR is due to a problem opening the translated node, we print + that name, otherwise, the name of the translator. */ + error(4, err, "%s", (err == open_err) ? node_name : argz); + } + else + { + node = file_name_lookup(node_name, lookup_flags, 0666); + if (node == MACH_PORT_NULL) + error(1, errno, "%s", node_name); + } + + if (active || passive) + { + err = file_set_translator (node, + passive_flags, active_flags, goaway_flags, + argz, argz_len, + active_control, MACH_MSG_TYPE_COPY_SEND); + if (err) + { + error (5, err, "%s", node_name); + } + + } + + if (chroot_command) + { + pid_t child; + int status; + switch ((child = fork ())) + { + case -1: + error (6, errno, "fork"); + + case 0:; /* Child. */ + /* We will act as the parent filesystem would for a lookup + of the active translator's root node, then use this port + as our root directory while we exec the command. */ + + char retry_name[1024]; /* XXX */ + retry_type do_retry; + mach_port_t root; + file_t executable; + char *prefixed_name; + + err = get_credentials (); + if (err) + error (6, err, "getting credentials"); + + err = fsys_getroot (active_control, + MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND, + uids, uids_len, gids, gids_len, 0, + &do_retry, retry_name, &root); + mach_port_deallocate (mach_task_self (), active_control); + if (err) + error (6, err, "fsys_getroot"); + err = hurd_file_name_lookup_retry (&_hurd_ports_use, &getdport, 0, + do_retry, retry_name, 0, 0, + &root); + if (err) + error (6, err, "cannot resolve root port"); + + if (setcrdir (root)) + error (7, errno, "cannot install root port"); + mach_port_deallocate (mach_task_self (), root); + if (chdir (chroot_chdir)) + error (8, errno, "%s", chroot_chdir); + + /* Lookup executable in PATH. */ + executable = file_name_path_lookup (chroot_command[0], + getenv ("PATH"), + O_EXEC, 0, + &prefixed_name); + if (MACH_PORT_VALID (executable)) + { + err = mach_port_deallocate (mach_task_self (), executable); + assert_perror (err); + if (prefixed_name) + chroot_command[0] = prefixed_name; + } + + execvp (chroot_command[0], chroot_command); + error (8, errno, "cannot execute %s", chroot_command[0]); + break; + + default: /* Parent. */ + if (waitpid (child, &status, 0) != child) + error (8, errno, "waitpid on %d", child); + + err = fsys_goaway (active_control, goaway_flags); + if (err && err != EBUSY) + error (9, err, "fsys_goaway"); + + if (WIFSIGNALED (status)) + error (WTERMSIG (status) + 128, 0, + "%s for child %d", strsignal (WTERMSIG (status)), child); + if (WEXITSTATUS (status) != 0) + error (WEXITSTATUS (status), 0, + "Error %d for child %d", WEXITSTATUS (status), child); + } + } + return 0; +} diff --git a/utils/Makefile b/utils/Makefile index d2ef9e8..be10cf6 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -34,7 +34,7 @@ SRCS = shd.c ps.c settrans.c syncfs.c showtrans.c addauth.c rmauth.c \ nullauth.c match-options.c msgids.c rpcscan.c OBJS = $(filter-out %.sh,$(SRCS:.c=.o)) -HURDLIBS = ps ihash store fshelp ports ftpconn shouldbeinlibc +HURDLIBS = ps ihash store fshelp ports ftpconn shouldbeinlibc hurdutil LDLIBS += -lpthread login-LDLIBS = -lutil -lcrypt addauth-LDLIBS = -lcrypt @@ -60,7 +60,7 @@ storeinfo storecat storeread: ../libstore/libstore.a ftpcp ftpdir: ../libftpconn/libftpconn.a mount umount: ../libihash/libihash.a settrans: ../libfshelp/libfshelp.a ../libihash/libihash.a \ - ../libports/libports.a + ../libports/libports.a ../libhurdutil/libhurdutil.a ps w ids settrans syncfs showtrans fsysopts storeinfo login vmstat portinfo \ devprobe vminfo addauth rmauth setauth unsu ftpcp ftpdir storeread \ storecat msgport mount umount nullauth rpctrace: \ diff --git a/utils/settrans.c b/utils/settrans.c index e01906b..9c6eba1 100644 --- a/utils/settrans.c +++ b/utils/settrans.c @@ -1,8 +1,9 @@ /* Set a file's translator. Copyright (C) 1995,96,97,98,2001,02,13,14 - Free Software Foundation, Inc. + Free Software Foundation, Inc. Written by Miles Bader + Revised by Manolis Fragkiskos Ragkousis . This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -38,424 +39,181 @@ #include #include - -const char *argp_program_version = STANDARD_HURD_VERSION (settrans); - -#define DEFAULT_TIMEOUT 60 +#include #define _STRINGIFY(arg) #arg #define STRINGIFY(arg) _STRINGIFY (arg) #define OPT_CHROOT_CHDIR -1 +#define OPT_STACK -2 static struct argp_option options[] = -{ - {"active", 'a', 0, 0, "Start TRANSLATOR and set it as NODE's active translator" }, - {"start", 's', 0, 0, "Start the translator specified by the NODE's passive translator record and set it as NODE's active translator" }, - {"passive", 'p', 0, 0, "Change NODE's passive translator record (default)" }, - {"create", 'c', 0, 0, "Create NODE if it doesn't exist" }, - {"dereference", 'L', 0, 0, "If a translator exists, put the new one on top"}, - {"pid-file", 'F', "FILENAME", 0, "When starting an active translator," + { + {"active", 'a', 0, 0, "Start TRANSLATOR and set it as NODE's active translator" }, + {"start", 's', 0, 0, "Start the translator specified by the NODE's passive translator record and set it as NODE's active translator" }, + {"passive", 'p', 0, 0, "Change NODE's passive translator record (default)" }, + {"create", 'c', 0, 0, "Create NODE if it doesn't exist" }, + {"dereference", 'L', 0, 0, "If a translator exists, put the new one on top"}, + {"pid-file", 'F', "FILENAME", 0, "When starting an active translator," " write its pid to this file"}, - {"pause", 'P', 0, 0, "When starting an active translator, prompt and" + {"pause", 'P', 0, 0, "When starting an active translator, prompt and" " wait for a newline on stdin before completing the startup handshake"}, - {"timeout", 't',"SEC",0, "Timeout for translator startup, in seconds" + {"timeout", 't',"SEC",0, "Timeout for translator startup, in seconds" " (default " STRINGIFY (DEFAULT_TIMEOUT) "); 0 means no timeout"}, - {"exclusive", 'x', 0, 0, "Only set the translator if there is not one already"}, - {"orphan", 'o', 0, 0, "Disconnect old translator from the filesystem " - "(do not ask it to go away)"}, - {"underlying", 'U', "NODE", 0, "Open NODE and hand it to the translator " - "as the underlying node"}, - - {"chroot", 'C', 0, 0, - "Instead of setting the node's translator, take following arguments up to" - " `--' and run that command chroot'd to the translated node."}, - {"chroot-chdir", OPT_CHROOT_CHDIR, "DIR", 0, - "Change to DIR before running the chrooted command. " - "DIR must be an absolute path."}, - - {0,0,0,0, "When setting the passive translator, if there's an active translator:"}, - {"goaway", 'g', 0, 0, "Ask the active translator to go away"}, - {"keep-active", 'k', 0, 0, "Leave any existing active translator running"}, - - {0,0,0,0, "When an active translator is told to go away:"}, - {"recursive", 'R', 0, 0, "Shutdown its children too"}, - {"force", 'f', 0, 0, "Ask it to ignore current users and shutdown " - "anyway." }, - {"nosync", 'S', 0, 0, "Don't sync it before killing it"}, - - {0, 0} -}; + {"exclusive", 'x', 0, 0, "Only set the translator if there is not one already"}, + {"orphan", 'o', 0, 0, "Disconnect old translator from the filesystem " + "(do not ask it to go away)"}, + {"underlying", 'U', "NODE", 0, "Open NODE and hand it to the translator " + "as the underlying node"}, + {"stack", OPT_STACK, 0, 0, "Replace an existing translator, but keep it " + "running, and put the new one on top"}, + + {"chroot", 'C', 0, 0, + "Instead of setting the node's translator, take following arguments up to" + " `--' and run that command chroot'd to the translated node."}, + {"chroot-chdir", OPT_CHROOT_CHDIR, "DIR", 0, + "Change to DIR before running the chrooted command. " + "DIR must be an absolute path."}, + + {0,0,0,0, "When setting the passive translator, if there's an active translator:"}, + {"goaway", 'g', 0, 0, "Ask the active translator to go away"}, + {"keep-active", 'k', 0, 0, "Leave any existing active translator running"}, + + {0,0,0,0, "When an active translator is told to go away:"}, + {"recursive", 'R', 0, 0, "Shutdown its children too"}, + {"force", 'f', 0, 0, "Ask it to ignore current users and shutdown " + "anyway." }, + {"nosync", 'S', 0, 0, "Don't sync it before killing it"}, + + {0, 0} + }; static char *args_doc = "NODE [TRANSLATOR ARG...]"; static char *doc = "Set the passive/active translator on NODE." -"\vBy default the passive translator is set."; + "\vBy default the passive translator is set."; -/* Authentication of the current process. */ -uid_t *uids; -gid_t *gids; -size_t uids_len, gids_len; - -/* Initialize and populate the uids and gids vectors. */ -error_t -get_credentials (void) -{ - /* Fetch uids... */ - uids_len = geteuids (0, 0); - if (uids_len < 0) - return errno; - - uids = malloc (uids_len * sizeof (uid_t)); - if (! uids) - return ENOMEM; - - uids_len = geteuids (uids_len, uids); - if (uids_len < 0) - return errno; - - /* ... and gids. */ - gids_len = getgroups (0, 0); - if (gids_len < 0) - return errno; - - gids = malloc (gids_len * sizeof (gid_t)); - if (! uids) - return ENOMEM; - gids_len = getgroups (gids_len, gids); - if (gids_len < 0) - return errno; - - return 0; -} - -/* ---------------------------------------------------------------- */ int main(int argc, char *argv[]) { error_t err; - /* The filesystem node we're putting a translator on. */ - char *node_name = 0; - file_t node; - - /* The translator's arg vector, in '\0' separated format. */ - char *argz = 0; - size_t argz_len = 0; - - /* The control port for any active translator we start up. */ - fsys_t active_control = MACH_PORT_NULL; - - /* Flags to pass to file_set_translator. */ - int active_flags = 0; - int passive_flags = 0; - int lookup_flags = O_NOTRANS; - int goaway_flags = 0; - - /* Various option flags. */ - int passive = 0, active = 0, keep_active = 0, pause = 0, kill_active = 0, - orphan = 0; - int start = 0; - char *pid_file = NULL; - int excl = 0; - int timeout = DEFAULT_TIMEOUT * 1000; /* ms */ - char *underlying_node_name = NULL; - char **chroot_command = 0; - char *chroot_chdir = "/"; + /* The flags to be used to create the translator. */ + settrans_flags_t flags; + + settrans_flags_create(&flags); /* Parse our options... */ error_t parse_opt (int key, char *arg, struct argp_state *state) - { - switch (key) - { - case ARGP_KEY_ARG: - if (state->arg_num == 0) - node_name = arg; - else /* command */ - { - if (start) - argp_error (state, "both --start and TRANSLATOR given"); - - error_t err = - argz_create (state->argv + state->next - 1, &argz, &argz_len); - if (err) - error(3, err, "Can't create options vector"); - state->next = state->argc; /* stop parsing */ - } - break; - - case ARGP_KEY_NO_ARGS: - argp_usage (state); - return EINVAL; - - case 'a': active = 1; break; - case 's': - start = 1; - active = 1; /* start implies active */ - break; - case 'p': passive = 1; break; - case 'k': keep_active = 1; break; - case 'g': kill_active = 1; break; - case 'x': excl = 1; break; - case 'P': pause = 1; break; - case 'F': - pid_file = strdup (arg); - if (pid_file == NULL) - error(3, ENOMEM, "Failed to duplicate argument"); - break; - - case 'o': orphan = 1; break; - case 'U': - underlying_node_name = strdup (arg); - if (underlying_node_name == NULL) - error(3, ENOMEM, "Failed to duplicate argument"); - break; - - case 'C': - if (chroot_command) - { - argp_error (state, "--chroot given twice"); - return EINVAL; - } - chroot_command = &state->argv[state->next]; - while (state->next < state->argc) - { - if (!strcmp (state->argv[state->next], "--")) - { - state->argv[state->next++] = 0; - if (chroot_command[0] == 0) - { - argp_error (state, - "--chroot must be followed by a command"); - return EINVAL; - } - return 0; - } - ++state->next; - } - argp_error (state, "--chroot command must be terminated with `--'"); - return EINVAL; - - case OPT_CHROOT_CHDIR: - if (arg[0] != '/') - argp_error (state, "--chroot-chdir must be absolute"); - chroot_chdir = arg; - break; - - case 'c': lookup_flags |= O_CREAT; break; - case 'L': lookup_flags &= ~O_NOTRANS; break; - - case 'R': goaway_flags |= FSYS_GOAWAY_RECURSE; break; - case 'S': goaway_flags |= FSYS_GOAWAY_NOSYNC; break; - case 'f': goaway_flags |= FSYS_GOAWAY_FORCE; break; - - /* Use atof so the user can specifiy fractional timeouts. */ - case 't': timeout = atof (arg) * 1000.0; break; - - default: - return ARGP_ERR_UNKNOWN; - } - return 0; - } + { + switch (key) + { + case ARGP_KEY_ARG: + if (state->arg_num == 0) + flags->node_name = arg; + else /* command */ + { + if (flags->start) + argp_error (state, "both --start and TRANSLATOR given"); + + error_t err = + argz_create (state->argv + state->next - 1, &flags->argz, &flags->argz_len); + if (err) + error(3, err, "Can't create options vector"); + state->next = state->argc; /* stop parsing */ + } + break; + + case ARGP_KEY_NO_ARGS: + argp_usage (state); + return EINVAL; + + case 'a': flags->active = 1; break; + case 's': + flags->start = 1; + flags->active = 1; /* start implies active */ + break; + case OPT_STACK: + flags->stack = 1; + flags->active = 1; /* stack implies active */ + flags->orphan = 1; /* stack implies orphan */ + break; + case 'p': flags->passive = 1; break; + case 'k': flags->keep_active = 1; break; + case 'g': flags->kill_active = 1; break; + case 'x': flags->excl = 1; break; + case 'P': flags->pause = 1; break; + case 'F': + flags->pid_file = strdup (arg); + if (flags->pid_file == NULL) + error(3, ENOMEM, "Failed to duplicate argument"); + break; + + case 'o': flags->orphan = 1; break; + case 'U': + flags->underlying_node_name = strdup (arg); + if (flags->underlying_node_name == NULL) + error(3, ENOMEM, "Failed to duplicate argument"); + break; + + case 'C': + if (flags->chroot_command) + { + argp_error (state, "--chroot given twice"); + return EINVAL; + } + flags->chroot_command = &state->argv[state->next]; + while (state->next < state->argc) + { + if (!strcmp (state->argv[state->next], "--")) + { + state->argv[state->next++] = 0; + if (flags->chroot_command[0] == 0) + { + argp_error (state, + "--chroot must be followed by a command"); + return EINVAL; + } + return 0; + } + ++state->next; + } + argp_error (state, "--chroot command must be terminated with `--'"); + return EINVAL; + + case OPT_CHROOT_CHDIR: + if (arg[0] != '/') + argp_error (state, "--chroot-chdir must be absolute"); + flags->chroot_chdir = arg; + break; + + case 'c': flags->lookup_flags |= O_CREAT; break; + case 'L': flags->lookup_flags &= ~O_NOTRANS; break; + + case 'R': flags->goaway_flags |= FSYS_GOAWAY_RECURSE; break; + case 'S': flags->goaway_flags |= FSYS_GOAWAY_NOSYNC; break; + case 'f': flags->goaway_flags |= FSYS_GOAWAY_FORCE; break; + + /* Use atof so the user can specifiy fractional timeouts. */ + case 't': flags->timeout = atof (arg) * 1000.0; break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; + } struct argp argp = {options, parse_opt, args_doc, doc}; argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0); - if (!active && !passive && !chroot_command) - passive = 1; /* By default, set the passive translator. */ - - if (passive) - passive_flags = FS_TRANS_SET | (excl ? FS_TRANS_EXCL : 0); - if (active) - active_flags = FS_TRANS_SET | (excl ? FS_TRANS_EXCL : 0) - | (orphan ? FS_TRANS_ORPHAN : 0); - - if (passive && !active) - { - /* When setting just the passive, decide what to do with any active. */ - if (kill_active) - /* Make it go away. */ - active_flags = FS_TRANS_SET; - else if (! keep_active) - /* Ensure that there isn't one. */ - active_flags = FS_TRANS_SET | FS_TRANS_EXCL; - } - - if (start) + err = settrans(flags); + if (err) { - /* Retrieve the passive translator record in argz. */ - mach_port_t node = file_name_lookup (node_name, lookup_flags, 0); - if (node == MACH_PORT_NULL) - error (4, errno, "%s", node_name); - - char buf[1024]; - argz = buf; - argz_len = sizeof (buf); - - err = file_get_translator (node, &argz, &argz_len); - if (err == EINVAL) - error (4, 0, "%s: no passive translator record found", node_name); - if (err) - error (4, err, "%s", node_name); - - mach_port_deallocate (mach_task_self (), node); + settrans_flags_cleanup(flags); + error(1, err, "Could not set translator"); } - if ((active || chroot_command) && argz_len > 0) - { - /* Error during file lookup; we use this to avoid duplicating error - messages. */ - error_t open_err = 0; - - /* The callback to start_translator opens NODE as a side effect. */ - error_t open_node (int flags, - mach_port_t *underlying, - mach_msg_type_name_t *underlying_type, - task_t task, void *cookie) - { - if (pause) - { - fprintf (stderr, "Translator pid: %d\nPausing...", - task2pid (task)); - getchar (); - } - - if (pid_file != NULL) - { - FILE *h; - h = fopen (pid_file, "w"); - if (h == NULL) - error (4, errno, "Failed to open pid file"); - - fprintf (h, "%i\n", task2pid (task)); - fclose (h); - } - - node = file_name_lookup (node_name, flags | lookup_flags, 0666); - if (node == MACH_PORT_NULL) - { - open_err = errno; - return open_err; - } - - if (underlying_node_name) - { - *underlying = file_name_lookup (underlying_node_name, - flags | lookup_flags, 0666); - if (! MACH_PORT_VALID (*underlying)) - { - /* For the error message. */ - node_name = underlying_node_name; - open_err = errno; - return open_err; - } - } - else - *underlying = node; - *underlying_type = MACH_MSG_TYPE_COPY_SEND; - - return 0; - } - err = fshelp_start_translator (open_node, NULL, argz, argz, argz_len, - timeout, &active_control); - if (err) - /* If ERR is due to a problem opening the translated node, we print - that name, otherwise, the name of the translator. */ - error(4, err, "%s", (err == open_err) ? node_name : argz); - } - else - { - node = file_name_lookup(node_name, lookup_flags, 0666); - if (node == MACH_PORT_NULL) - error(1, errno, "%s", node_name); - } - - if (active || passive) - { - err = file_set_translator (node, - passive_flags, active_flags, goaway_flags, - argz, argz_len, - active_control, MACH_MSG_TYPE_COPY_SEND); - if (err) - error (5, err, "%s", node_name); - } - - if (chroot_command) - { - pid_t child; - int status; - switch ((child = fork ())) - { - case -1: - error (6, errno, "fork"); - - case 0:; /* Child. */ - /* We will act as the parent filesystem would for a lookup - of the active translator's root node, then use this port - as our root directory while we exec the command. */ - - char retry_name[1024]; /* XXX */ - retry_type do_retry; - mach_port_t root; - file_t executable; - char *prefixed_name; - - err = get_credentials (); - if (err) - error (6, err, "getting credentials"); - - err = fsys_getroot (active_control, - MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND, - uids, uids_len, gids, gids_len, 0, - &do_retry, retry_name, &root); - mach_port_deallocate (mach_task_self (), active_control); - if (err) - error (6, err, "fsys_getroot"); - err = hurd_file_name_lookup_retry (&_hurd_ports_use, &getdport, 0, - do_retry, retry_name, 0, 0, - &root); - if (err) - error (6, err, "cannot resolve root port"); - - if (setcrdir (root)) - error (7, errno, "cannot install root port"); - mach_port_deallocate (mach_task_self (), root); - if (chdir (chroot_chdir)) - error (8, errno, "%s", chroot_chdir); - - /* Lookup executable in PATH. */ - executable = file_name_path_lookup (chroot_command[0], - getenv ("PATH"), - O_EXEC, 0, - &prefixed_name); - if (MACH_PORT_VALID (executable)) - { - err = mach_port_deallocate (mach_task_self (), executable); - assert_perror (err); - if (prefixed_name) - chroot_command[0] = prefixed_name; - } - - execvp (chroot_command[0], chroot_command); - error (8, errno, "cannot execute %s", chroot_command[0]); - break; - - default: /* Parent. */ - if (waitpid (child, &status, 0) != child) - error (8, errno, "waitpid on %d", child); - - err = fsys_goaway (active_control, goaway_flags); - if (err && err != EBUSY) - error (9, err, "fsys_goaway"); - - if (WIFSIGNALED (status)) - error (WTERMSIG (status) + 128, 0, - "%s for child %d", strsignal (WTERMSIG (status)), child); - if (WEXITSTATUS (status) != 0) - error (WEXITSTATUS (status), 0, - "Error %d for child %d", WEXITSTATUS (status), child); - } - } + settrans_flags_cleanup(flags); return 0; } -- 2.8.2