summaryrefslogtreecommitdiff
path: root/devnode
diff options
context:
space:
mode:
authorSamuel Thibault <samuel.thibault@ens-lyon.org>2015-11-29 12:47:14 +0100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2015-11-29 12:47:14 +0100
commit87bc93725aea306e8bd4e4171622e4418869fc2f (patch)
treecb05ddefb862700b9f8f7b980597b0a11a3346eb /devnode
parent226a9d9c34a2d187f978a25874488e5b07986d7c (diff)
Add devnode translator
* devnode: New directory * Makefile (prog-subdirs): Add devnode.
Diffstat (limited to 'devnode')
-rw-r--r--devnode/Makefile30
-rw-r--r--devnode/README25
-rw-r--r--devnode/devnode.c359
-rw-r--r--devnode/mig-mutate.h27
-rw-r--r--devnode/util.h40
5 files changed, 481 insertions, 0 deletions
diff --git a/devnode/Makefile b/devnode/Makefile
new file mode 100644
index 00000000..9529fa7b
--- /dev/null
+++ b/devnode/Makefile
@@ -0,0 +1,30 @@
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 2008 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 the GNU Hurd; see the file COPYING. If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := devnode
+makemode := server
+
+SRCS = devnode.c
+LCLHDRS = util.h
+HURDLIBS = ports trivfs fshelp shouldbeinlibc
+target = devnode
+MIGSTUBS = deviceServer.o notifyServer.o
+MIGSFLAGS = -imacros $(srcdir)/mig-mutate.h
+device-MIGSFLAGS="-DMACH_PAYLOAD_TO_PORT=ports_payload_get_name"
+OBJS = $(SRCS:.c=.o) $(MIGSTUBS)
+
+include ../Makeconf
diff --git a/devnode/README b/devnode/README
new file mode 100644
index 00000000..90ca27cc
--- /dev/null
+++ b/devnode/README
@@ -0,0 +1,25 @@
+[Introduction]
+
+devnode is a translator that creates the device file for the kernel device. It provides another way for other programs to open the kernel device.
+The device file should be created in /dev with the device name as its file name, so clients can find the device file easily.
+Clients need to get the port to the devnode translator by calling file_name_lookup() and uses this port as a master device port to open the device by calling device_open(). The device name used in device_open() is specified by '-n' option of devnode.
+
+
+[Usage]
+
+Usage: devnode [OPTION...] device
+Hurd devnode translator.
+
+ -n, --name=DEVICENAME Accept open from clients only with DEVICENAME
+ -M, --master_device=FILE Get a pseudo master device port
+ -?, --help Give this help list
+ --usage Give a short usage message
+ -V, --version Print program version
+
+The '-n' option specifies the device name used by clients in device_open(). It can be optional. If it's specified, clients must use the name to open the device. Otherwise, every device name used by clients in device_open() is acceptable.
+The '-M' option specifies the file where devnode can get the master device port. This option can be useful to open the virtual interface created by eth-multiplexer, for example.
+
+
+[Internal]
+
+devnode is very simple. It implements the server side functions in device.defs, so it can receive the request of opening a device from clients. Only ds_device_open is actually implemented, which opens the device and returns the port to the device. Normally, devnode shouldn't get other requests.
diff --git a/devnode/devnode.c b/devnode/devnode.c
new file mode 100644
index 00000000..2802471f
--- /dev/null
+++ b/devnode/devnode.c
@@ -0,0 +1,359 @@
+/*
+ Copyright (C) 2008 Free Software Foundation, Inc.
+ Written by Zheng Da.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/*
+ * This program is a translator that sits on the top of the network
+ * interface and helps socket servers open the interface.
+ */
+
+#include <argp.h>
+#include <argz.h>
+#include <errno.h>
+#include <error.h>
+#include <stddef.h>
+#include <fcntl.h>
+
+#include <hurd.h>
+#include <mach.h>
+#include <device/device.h>
+#include <hurd/trivfs.h>
+#include <hurd/ports.h>
+#include <version.h>
+
+#include "device_S.h"
+#include "notify_S.h"
+#include "util.h"
+
+/* The name of the network interface that the translator sits on. */
+static char *device_name;
+/* The device name used by the socket servers. */
+static char *user_device_name;
+static char *master_file;
+/* The master device port for opening the interface. */
+static mach_port_t master_device;
+
+const char *argp_program_version = STANDARD_HURD_VERSION (devnode);
+
+static const char args_doc[] = "device";
+static const char doc[] = "Hurd devnode translator.";
+static const struct argp_option options[] =
+{
+ {"name", 'n', "DEVICENAME", 0,
+ "Define the device name used by clients in device_open()", 2},
+ {"master-device", 'M', "FILE", 0,
+ "Get a pseudo master device port", 3},
+ {0}
+};
+
+/* Port bucket we service requests on. */
+struct port_bucket *port_bucket;
+
+/* Trivfs hooks. */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+int trivfs_support_read = 0;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+int trivfs_allow_open = O_READ | O_WRITE;
+
+/* Our port classes. */
+struct port_class *trivfs_protid_class;
+struct port_class *trivfs_cntl_class;
+
+static int
+devnode_demuxer (mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+{
+ mig_routine_t routine;
+ if ((routine = device_server_routine (inp)) ||
+ (routine = notify_server_routine (inp)) ||
+ (routine = NULL, trivfs_demuxer (inp, outp)))
+ {
+ if (routine)
+ (*routine) (inp, outp);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+/* Implementation of notify interface */
+kern_return_t
+do_mach_notify_port_deleted (struct port_info *pi,
+ mach_port_t name)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_msg_accepted (struct port_info *pi,
+ mach_port_t name)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_port_destroyed (struct port_info *pi,
+ mach_port_t port)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_no_senders (struct port_info *pi,
+ mach_port_mscount_t mscount)
+{
+ return ports_do_mach_notify_no_senders (pi, mscount);
+}
+
+kern_return_t
+do_mach_notify_send_once (struct port_info *pi)
+{
+ return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_dead_name (struct port_info *pi,
+ mach_port_t name)
+{
+ return EOPNOTSUPP;
+}
+
+/* Implementation of device interface */
+kern_return_t
+ds_device_open (mach_port_t master_port, mach_port_t reply_port,
+ mach_msg_type_name_t reply_portPoly,
+ dev_mode_t mode, dev_name_t name, mach_port_t *device,
+ mach_msg_type_name_t *devicetype)
+{
+ error_t err;
+
+ devnode_debug ("ds_device_open is called\n");
+
+ if ((user_device_name && strcmp (user_device_name, name))
+ || device_name == NULL)
+ return D_NO_SUCH_DEVICE;
+
+ if (master_file != NULL)
+ {
+ if (master_device != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), master_device);
+
+ master_device = file_name_lookup (master_file, 0, 0);
+ if (master_device == MACH_PORT_NULL)
+ error (1, errno, "file_name_lookup");
+ }
+
+ err = device_open (master_device, mode, device_name, device);
+ *devicetype = MACH_MSG_TYPE_MOVE_SEND;
+ return err;
+}
+
+kern_return_t
+ds_device_close (device_t device)
+{
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_write (device_t device, mach_port_t reply_port,
+ mach_msg_type_name_t reply_type, dev_mode_t mode,
+ recnum_t recnum, io_buf_ptr_t data, size_t datalen,
+ int *bytes_written)
+{
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_write_inband (device_t device, mach_port_t reply_port,
+ mach_msg_type_name_t reply_type, dev_mode_t mode,
+ recnum_t recnum, io_buf_ptr_inband_t data,
+ size_t datalen, int *bytes_written)
+{
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_read (device_t device, mach_port_t reply_port,
+ mach_msg_type_name_t reply_type, dev_mode_t mode,
+ recnum_t recnum, int bytes_wanted,
+ io_buf_ptr_t *data, size_t *datalen)
+{
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_read_inband (device_t device, mach_port_t reply_port,
+ mach_msg_type_name_t reply_type, dev_mode_t mode,
+ recnum_t recnum, int bytes_wanted,
+ io_buf_ptr_inband_t data, size_t *datalen)
+{
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_map (device_t device, vm_prot_t prot, vm_offset_t offset,
+ vm_size_t size, memory_object_t *pager, int unmap)
+{
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_set_status (device_t device, dev_flavor_t flavor,
+ dev_status_t status, size_t statuslen)
+{
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_get_status (device_t device, dev_flavor_t flavor,
+ dev_status_t status, size_t *statuslen)
+{
+ return D_INVALID_OPERATION;
+}
+
+kern_return_t
+ds_device_set_filter (device_t device, mach_port_t receive_port,
+ int priority, filter_array_t filter, size_t filterlen)
+{
+ return D_INVALID_OPERATION;
+}
+
+error_t
+trivfs_append_args (struct trivfs_control *fsys, char **argz, size_t *argz_len)
+{
+ error_t err = 0;
+
+#define ADD_OPT(fmt, args...) \
+ do { char buf[100]; \
+ if (! err) { \
+ snprintf (buf, sizeof buf, fmt , ##args); \
+ err = argz_add (argz, argz_len, buf); } } while (0)
+
+ if (user_device_name)
+ ADD_OPT ("--name=%s", user_device_name);
+ if (master_file)
+ ADD_OPT ("--master-device=%s", master_file);
+
+ ADD_OPT ("%s", device_name);
+
+#undef ADD_OPT
+ return err;
+}
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, io_statbuf_t *stat)
+{
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+ int count;
+
+ /* Stop new requests. */
+ ports_inhibit_class_rpcs (trivfs_cntl_class);
+ ports_inhibit_class_rpcs (trivfs_protid_class);
+
+ count = ports_count_class (trivfs_protid_class);
+ devnode_debug ("the number of ports alive: %d\n", count);
+
+ if (count && !(flags & FSYS_GOAWAY_FORCE))
+ {
+ /* We won't go away, so start things going again... */
+ ports_enable_class (trivfs_protid_class);
+ ports_resume_class_rpcs (trivfs_cntl_class);
+ ports_resume_class_rpcs (trivfs_protid_class);
+ return EBUSY;
+ }
+
+ mach_port_deallocate (mach_task_self (), master_device);
+ devnode_debug ("the translator is gone away\n");
+ exit (0);
+}
+
+static error_t
+parse_opt (int opt, char *arg, struct argp_state *state)
+{
+ switch (opt)
+ {
+ case 'M':
+ master_file = arg;
+ master_device = file_name_lookup (arg, 0, 0);
+ if (master_device == MACH_PORT_NULL)
+ error (1, errno, "file_name_lookup");
+ break;
+ case 'n':
+ user_device_name = arg;
+ break;
+ case ARGP_KEY_ARG:
+ device_name = arg;
+ break;
+ case ARGP_KEY_ERROR:
+ case ARGP_KEY_SUCCESS:
+ case ARGP_KEY_INIT:
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ error_t err;
+ mach_port_t bootstrap;
+ struct trivfs_control *fsys;
+ const struct argp argp = { options, parse_opt, args_doc, doc };
+
+ port_bucket = ports_create_bucket ();
+ trivfs_cntl_class = ports_create_class (trivfs_clean_cntl, 0);
+ trivfs_protid_class = ports_create_class (trivfs_clean_protid, 0);
+
+ 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");
+
+ if (master_device == MACH_PORT_NULL)
+ {
+ err = get_privileged_ports (0, &master_device);
+ if (err)
+ error (1, err, "get_privileged_ports");
+ }
+
+ /* Reply to our parent. */
+ err = trivfs_startup (bootstrap, 0,
+ trivfs_cntl_class, port_bucket,
+ trivfs_protid_class, port_bucket, &fsys);
+ mach_port_deallocate (mach_task_self (), bootstrap);
+ if (err)
+ error (1, err, "Contacting parent");
+
+ /* Launch. */
+ do
+ {
+ ports_manage_port_operations_one_thread (port_bucket,
+ devnode_demuxer, 0);
+ } while (trivfs_goaway (fsys, 0));
+ return 0;
+}
diff --git a/devnode/mig-mutate.h b/devnode/mig-mutate.h
new file mode 100644
index 00000000..0656014f
--- /dev/null
+++ b/devnode/mig-mutate.h
@@ -0,0 +1,27 @@
+/*
+ Copyright (C) 2014 Free Software Foundation, Inc.
+ Written by Justus Winter.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#define NOTIFY_INTRAN \
+ port_info_t begin_using_port_info_port (mach_port_t)
+#define NOTIFY_INTRAN_PAYLOAD \
+ port_info_t begin_using_port_info_payload
+#define NOTIFY_DESTRUCTOR \
+ end_using_port_info (port_info_t)
+#define NOTIFY_IMPORTS \
+ import "libports/mig-decls.h";
diff --git a/devnode/util.h b/devnode/util.h
new file mode 100644
index 00000000..f3cc3c11
--- /dev/null
+++ b/devnode/util.h
@@ -0,0 +1,40 @@
+/*
+ Copyright (C) 2008 Free Software Foundation, Inc.
+ Written by Zheng Da.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <stdio.h>
+
+#ifdef DEBUG
+
+#define devnode_debug(format, ...) do \
+{ \
+ fprintf (stderr , "devnode: " format, ## __VA_ARGS__);\
+ fflush (stderr); \
+} while (0)
+
+#else
+
+#define devnode_debug(format, ...) do {} while (0)
+
+#endif
+
+#endif