summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMoritz Schulte <moritz@duesseldorf.ccc.de>2002-04-15 23:11:59 +0000
committerMoritz Schulte <moritz@duesseldorf.ccc.de>2002-04-15 23:11:59 +0000
commit6fa433dc3d76ce6cd0a90fa744bce4f89132d830 (patch)
tree8b0d76eb82eea350078098aa9e4c79efac87d679
Initial import, second try.
-rw-r--r--Makefile44
-rw-r--r--lib.c63
-rw-r--r--lib.h26
-rw-r--r--main.c129
-rw-r--r--netfs.c660
-rw-r--r--netio.h56
-rw-r--r--node.c222
-rw-r--r--node.h33
-rw-r--r--protocol.c152
-rw-r--r--protocol.h23
-rw-r--r--version.h30
11 files changed, 1438 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000..6e5259276
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,44 @@
+# netio - creates socket ports via the filesystem
+# Copyright (C) 2001, 02 Moritz Schulte <moritz@duesseldorf.ccc.de>
+#
+# 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 of the License, 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
+
+CFLAGS = -g -Wall -D_GNU_SOURCE
+
+netio: main.o netfs.o node.o lib.o protocol.o
+ gcc $(CFLAGS) -lnetfs -lfshelp -liohelp -lthreads -lports \
+ -lihash -lshouldbeinlibc \
+ -o netio main.o netfs.o node.o lib.o protocol.o
+
+main.o: main.c netio.h lib.h node.h protocol.h
+ gcc $(CFLAGS) -c main.c
+
+netfs.o: netfs.c netio.h lib.h node.h protocol.h
+ gcc $(CFLAGS) -c netfs.c
+
+lib.o: lib.c lib.h
+ gcc $(CFLAGS) -c lib.c
+
+node.o: node.c netio.h lib.h protocol.h
+ gcc $(CFLAGS) -c node.c
+
+protocol.o: protocol.c netio.h lib.h node.h
+ gcc $(CFLAGS) -c protocol.c
+
+clean:
+ rm -rf *.o netio
+
+.PHONY: clean
diff --git a/lib.c b/lib.c
new file mode 100644
index 000000000..295ad5e8d
--- /dev/null
+++ b/lib.c
@@ -0,0 +1,63 @@
+/* netio - creates socket ports via the filesystem
+ Copyright (C) 2001, 02 Moritz Schulte <moritz@duesseldorf.ccc.de>
+
+ 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 of the
+ License, 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <hurd.h>
+#include <hurd/socket.h>
+#include <hurd/paths.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <errno.h>
+#include <error.h>
+
+#include "lib.h"
+
+/* Try to alloc SIZE bytes into *MEM. Return ENOMEM if malloc()
+ failed. */
+error_t
+my_malloc (size_t size, void **mem)
+{
+ *mem = malloc (size);
+ if (! *mem)
+ return ENOMEM;
+ return 0;
+}
+
+/* Open a port to the socket server for the protocol family number NO
+ and store it in *SOCK. Return 0 on success or an error code. */
+error_t
+open_socket_server (int no, pf_t *sock)
+{
+ char *path;
+ error_t err;
+ pf_t port;
+ err = asprintf (&path, "%s/%i", _SERVERS_SOCKET, no);
+ if (err < 0)
+ return ENOMEM;
+ err = 0;
+ port = file_name_lookup (path, 0, 0);
+ free (path);
+ if (port == MACH_PORT_NULL)
+ err = errno;
+ else
+ *sock = port;
+ return err;
+}
diff --git a/lib.h b/lib.h
new file mode 100644
index 000000000..b5744cb59
--- /dev/null
+++ b/lib.h
@@ -0,0 +1,26 @@
+/* netio - creates socket ports via the filesystem
+ Copyright (C) 2001, 02 Moritz Schulte <moritz@duesseldorf.ccc.de>
+
+ 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 of the
+ License, 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 <errno.h>
+#include <stdint.h>
+#include <hurd/socket.h>
+
+#define STRING_EQUAL(s1, s2) (! strcmp (s1, s2))
+
+error_t my_malloc (size_t size, void **mem);
+error_t open_socket_server (int no, pf_t *sock);
diff --git a/main.c b/main.c
new file mode 100644
index 000000000..82060bb70
--- /dev/null
+++ b/main.c
@@ -0,0 +1,129 @@
+/* netio - creates socket ports via the filesystem
+ Copyright (C) 2001, 02 Moritz Schulte <moritz@duesseldorf.ccc.de>
+
+ 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 of the
+ License, 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.h>
+#include <hurd/netfs.h>
+#include <hurd/paths.h>
+#include <argp.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "netio.h"
+#include "lib.h"
+#include "node.h"
+#include "protocol.h"
+
+#include "version.h"
+
+const char *argp_program_version = STANDARD_HURD_VERSION (netio);
+const char *argp_program_bug_address =
+"Moritz Schulte <moritz@duesseldorf.ccc.de>";
+const char *doc = "Hurd netio translator v" NETIO_VERSION;
+
+/* The underlying node. */
+mach_port_t ul_node;
+
+/* The socket server, PF_INET for us. */
+pf_t socket_server;
+
+/* Has to be defined for libnetfs... */
+int netfs_maxsymlinks = 0;
+
+/* Used for updating node information. */
+volatile struct mapped_time_value *netio_maptime;
+
+/* argp options. */
+static const struct argp_option netio_options[] =
+{
+ { 0 }
+};
+
+/* argp option parser. */
+static error_t
+parse_opts (int key, char *arg, struct argp_state *sate)
+{
+ return 0;
+}
+
+/* Main. */
+int
+main (int argc, char **argv)
+{
+ struct argp netio_argp = { netio_options, parse_opts,
+ NULL, doc, NULL };
+ mach_port_t bootstrap_port;
+ error_t err;
+
+ argp_parse (&netio_argp, argc, argv, 0, 0, 0);
+ task_get_bootstrap_port (mach_task_self (), &bootstrap_port);
+ netfs_init ();
+ ul_node = netfs_startup (bootstrap_port, 0);
+
+ err = node_make_root_node (&netfs_root_node);
+ if (err)
+ error (EXIT_FAILURE, err, "cannot create root node");
+
+ {
+ /* Here we adjust the root node permissions. */
+ struct stat ul_node_stat;
+ err = io_stat (ul_node, &ul_node_stat);
+ if (err)
+ error (EXIT_FAILURE, err, "cannot stat underlying node");
+ netfs_root_node->nn_stat.st_fsid = getpid ();
+ netfs_root_node->nn_stat = ul_node_stat;
+ netfs_root_node->nn_stat.st_mode = S_IFDIR | (ul_node_stat.st_mode
+ & ~S_IFMT & ~S_ITRANS);
+
+ /* If the underlying node isn't a directory, enhance the stat
+ information, if needed. */
+ if (! S_ISDIR (ul_node_stat.st_mode))
+ {
+ if (ul_node_stat.st_mode & S_IRUSR)
+ netfs_root_node->nn_stat.st_mode |= S_IXUSR;
+ if (ul_node_stat.st_mode & S_IRGRP)
+ netfs_root_node->nn_stat.st_mode |= S_IXGRP;
+ if (ul_node_stat.st_mode & S_IROTH)
+ netfs_root_node->nn_stat.st_mode |= S_IXOTH;
+ }
+ }
+
+ err = maptime_map (0, 0, &netio_maptime);
+ if (err)
+ error (EXIT_FAILURE, err, "cannot map time");
+
+ fshelp_touch (&netfs_root_node->nn_stat,
+ TOUCH_ATIME|TOUCH_MTIME|TOUCH_CTIME,
+ netio_maptime);
+
+ err = open_socket_server (PF_INET, &socket_server);
+ if (err)
+ error (EXIT_FAILURE, err, "open_socket_server");
+
+ err = protocol_register_protocols ();
+ if (err)
+ error (EXIT_FAILURE, err, "protocol_register_protocols");
+
+ for (;;)
+ netfs_server_loop ();
+
+ /* Never reached. */
+ exit (0);
+}
diff --git a/netfs.c b/netfs.c
new file mode 100644
index 000000000..149732b8a
--- /dev/null
+++ b/netfs.c
@@ -0,0 +1,660 @@
+/* netio - creates socket ports via the filesystem
+ Copyright (C) 2001, 02 Moritz Schulte <moritz@duesseldorf.ccc.de>
+
+ 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 of the
+ License, 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 <hurd/socket.h>
+#include <argz.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <dirent.h>
+#include <sys/mman.h>
+
+#include "netio.h"
+#include "lib.h"
+#include "node.h"
+#include "protocol.h"
+
+/* Returned directory entries are aligned to blocks this many bytes
+ long. Must be a power of two. For netfs_get_dirents. Taken from
+ hostmux. */
+#define DIRENT_ALIGN 4
+#define DIRENT_NAME_OFFS offsetof (struct dirent, d_name)
+/* Length is structure before the name + the name + '\0', all
+ padded to a four-byte alignment. */
+#define DIRENT_LEN(name_len) \
+ ((DIRENT_NAME_OFFS + (name_len) + 1 + (DIRENT_ALIGN - 1)) \
+ & ~(DIRENT_ALIGN - 1))
+
+/* The user must define this function. Lookup NAME in DIR (which is
+ locked) for USER; set *NP to the found name upon return. If the
+ name was not found, then return ENOENT. On any error, clear *NP.
+ (*NP, if found, should be locked and a reference to it generated.
+ This call should unlock DIR no matter what.) */
+error_t
+netfs_attempt_lookup (struct iouser *user, struct node *dir,
+ char *name, struct node **node)
+{
+ error_t err;
+ err = fshelp_access (&dir->nn_stat, S_IEXEC, user);
+ if (err)
+ goto out;
+ if (STRING_EQUAL (name, "."))
+ {
+ *node = dir;
+ netfs_nref (*node);
+ }
+ else if (STRING_EQUAL (name, ".."))
+ {
+ *node = dir->nn->dir;
+ netfs_nref (*node);
+ }
+ else
+ {
+ if (dir->nn->flags & PROTOCOL_NODE)
+ err = node_make_host_node (user, dir, name, node);
+ else if (dir->nn->flags & HOST_NODE)
+ err = node_make_port_node (user, dir, name, node);
+ else if (dir->nn->flags & ROOT_NODE)
+ {
+ err = protocol_find_node (name, node);
+ if (! err)
+ netfs_nref (*node);
+ }
+ else
+ err = EOPNOTSUPP; /* FIXME? */
+ }
+
+ out:
+ fshelp_touch (&dir->nn_stat, TOUCH_ATIME, netio_maptime);
+ mutex_unlock (&dir->lock);
+ if (err)
+ *node = 0;
+ else
+ mutex_lock (&(*node)->lock);
+ return err;
+}
+
+/* Return an argz string describing the current options. Fill *ARGZ
+ with a pointer to newly malloced storage holding the list and *LEN
+ to the length of that storage. */
+error_t
+netfs_append_args (char **argz, size_t *argz_len)
+{
+ return 0;
+}
+
+/* Make sure that NP->nn_stat is filled with current information.
+ CRED identifies the user responsible for the operation. */
+error_t
+netfs_validate_stat (struct node *np, struct iouser *cred)
+{
+ return 0;
+}
+
+/* This should attempt a chmod call for the user specified by CRED on
+ locked node NP, to change the owner to UID and the group to GID. */
+error_t
+netfs_attempt_chown (struct iouser *cred, struct node *np,
+ uid_t uid, uid_t gid)
+{
+ return EOPNOTSUPP;
+}
+
+/* This should attempt a chauthor call for the user specified by CRED
+ on locked node NP, thereby changing the author to AUTHOR. */
+error_t
+netfs_attempt_chauthor (struct iouser *cred, struct node *np,
+ uid_t author)
+{
+ return EOPNOTSUPP;
+}
+
+/* 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)
+{
+ error_t err;
+
+ /* We only support permission chmod's on the root node. */
+ if (np->nn->dir ||
+ ((mode & S_IFMT) | (np->nn_stat.st_mode & S_IFMT))
+ != (np->nn_stat.st_mode & S_IFMT))
+ err = EOPNOTSUPP;
+ else
+ {
+ if (! (err = fshelp_isowner (&np->nn_stat, cred)))
+ {
+ np->nn_stat.st_mode = mode | (np->nn_stat.st_mode & S_IFMT);
+ fshelp_touch (&np->nn_stat, TOUCH_CTIME, netio_maptime);
+ }
+ }
+ return err;
+}
+
+/* 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)
+{
+ return EOPNOTSUPP;
+}
+
+/* Attempt to turn NODE (user CRED) into a device. TYPE is either
+ S_IFBLK or S_IFCHR. NP is locked. */
+error_t
+netfs_attempt_mkdev (struct iouser *cred, struct node *np,
+ mode_t type, dev_t indexes)
+{
+ return EOPNOTSUPP;
+}
+
+/* Attempt to set the passive translator record for FILE to ARGZ (of
+ length ARGZLEN) for user CRED. NP is locked. */
+error_t
+netfs_set_translator (struct iouser *cred, struct node *np,
+ char *argz, size_t argzlen)
+{
+ return EOPNOTSUPP;
+}
+
+/* For locked node NODE with S_IPTRANS set in its mode, look up the
+ name of its translator. Store the name into newly malloced
+ storage, and return it in *ARGZ; set *ARGZ_LEN to the total length. */
+error_t
+netfs_get_translator (struct node *node, char **argz,
+ size_t *argz_len)
+{
+ return EOPNOTSUPP;
+}
+
+/* This should attempt a chflags call for the user specified by CRED
+ on locked node NP, to change the flags to FLAGS. */
+error_t
+netfs_attempt_chflags (struct iouser *cred, struct node *np,
+ int flags)
+{
+ return EOPNOTSUPP;
+}
+
+/* This should attempt a utimes call for the user specified by CRED on
+ locked node NP, to change the atime to ATIME and the mtime to
+ MTIME. If ATIME or MTIME is null, then set to the current time. */
+error_t
+netfs_attempt_utimes (struct iouser *cred, struct node *np,
+ struct timespec *atime, struct timespec *mtime)
+{
+ return 0;
+}
+
+/* This should attempt to set the size of the locked file NP (for user
+ CRED) to SIZE bytes long. */
+error_t
+netfs_attempt_set_size (struct iouser *cred, struct node *np,
+ off_t size)
+{
+ return 0;
+}
+
+/* This should attempt to fetch filesystem status information for the
+ remote filesystem, for the user CRED. NP is locked. */
+error_t
+netfs_attempt_statfs (struct iouser *cred, struct node *np,
+ struct statfs *st)
+{
+ return EOPNOTSUPP;
+}
+
+/* This should sync the locked file NP completely to disk, for the
+ user CRED. If WAIT is set, return only after the sync is
+ completely finished. */
+error_t
+netfs_attempt_sync (struct iouser *cred, struct node *np,
+ int wait)
+{
+ return EOPNOTSUPP;
+}
+
+/* This should sync the entire remote filesystem. If WAIT is set,
+ return only after the sync is completely finished. */
+error_t
+netfs_attempt_syncfs (struct iouser *cred, int wait)
+{
+ return 0;
+}
+
+/* Delete NAME in DIR (which is locked) for USER. */
+error_t
+netfs_attempt_unlink (struct iouser *user, struct node *dir,
+ char *name)
+{
+ return EOPNOTSUPP;
+}
+
+/* Attempt to rename the directory FROMDIR to TODIR. Note that neither
+ of the specific nodes are locked. */
+error_t
+netfs_attempt_rename (struct iouser *user, struct node *fromdir,
+ char *fromname, struct node *todir,
+ char *toname, int excl)
+{
+ return EOPNOTSUPP;
+}
+
+/* Attempt to create a new directory named NAME in DIR (which is
+ locked) for USER with mode MODE. */
+error_t
+netfs_attempt_mkdir (struct iouser *user, struct node *dir,
+ char *name, mode_t mode)
+{
+ return EOPNOTSUPP;
+}
+
+/* Attempt to remove directory named NAME in DIR (which is locked) for
+ USER. */
+error_t
+netfs_attempt_rmdir (struct iouser *user,
+ struct node *dir, char *name)
+{
+ /* Let's allow unlinking of protocol directories. */
+ if (dir->nn->dir)
+ return EOPNOTSUPP;
+ return protocol_unregister (name);
+}
+
+/* Create a link in DIR with name NAME to FILE for USER. Note that
+ neither DIR nor FILE are locked. If EXCL is set, do not delete the
+ target. Return EEXIST if NAME is already found in DIR. */
+error_t
+netfs_attempt_link (struct iouser *user, struct node *dir,
+ struct node *file, char *name, int excl)
+{
+ return EOPNOTSUPP;
+}
+
+/* Attempt to create an anonymous file related to DIR (which is
+ locked) for USER with MODE. Set *NP to the returned file upon
+ success. No matter what, unlock DIR. */
+error_t
+netfs_attempt_mkfile (struct iouser *user, struct node *dir,
+ mode_t mode, struct node **np)
+{
+ return EOPNOTSUPP;
+}
+
+/* (We don't use this function!) Attempt to create a file named NAME
+ in DIR (which is locked) for USER with MODE. Set *NP to the new
+ node upon return. On any error, clear *NP. *NP should be locked
+ on success; no matter what, unlock DIR before returning. */
+error_t
+netfs_attempt_create_file (struct iouser *user, struct node *dir,
+ char *name, mode_t mode, struct node **np)
+{
+ return EOPNOTSUPP;
+}
+
+/* Read the contents of locked node NP (a symlink), for USER, into
+ BUF. */
+error_t
+netfs_attempt_readlink (struct iouser *user, struct node *np,
+ char *buf)
+{
+ return EOPNOTSUPP;
+}
+
+/* libnetfs uses this functions once. */
+error_t
+netfs_check_open_permissions (struct iouser *user, struct node *np,
+ int flags, int newnode)
+{
+ error_t err = 0;
+ if (! err && (flags & O_READ))
+ err = fshelp_access (&np->nn_stat, S_IREAD, user);
+ if (! err && (flags & O_WRITE))
+ err = fshelp_access (&np->nn_stat, S_IWRITE, user);
+ if (! err && (flags & O_EXEC))
+ err = fshelp_access (&np->nn_stat, S_IEXEC, user);
+ return err;
+}
+
+/* Read from the locked file NP for user CRED starting at OFFSET and
+ continuing for up to *LEN bytes. Put the data at DATA. Set *LEN
+ to the amount successfully read upon return. */
+error_t
+netfs_attempt_read (struct iouser *cred, struct node *np,
+ off_t offset, size_t *len, void *data)
+{
+ error_t err = 0;
+ if (! (np->nn->flags & PORT_NODE))
+ *len = 0;
+ {
+ addr_port_t addrport;
+ char *bufp = (char *) data;
+ mach_msg_type_number_t nread = *len;
+ mach_port_t *ports;
+ mach_msg_type_number_t nports;
+ char *cdata = NULL;
+ mach_msg_type_number_t clen = 0;
+ int flags = 0;
+
+ if (err)
+ goto out;
+ err = socket_recv (np->nn->sock, &addrport, flags, &bufp, &nread,
+ &ports, &nports, &cdata, &clen, &flags,
+ nread);
+ if (err)
+ goto out;
+
+ mach_port_deallocate (mach_task_self (), addrport);
+ vm_deallocate (mach_task_self (), (vm_address_t) cdata, clen);
+ if (bufp != (char *) data)
+ {
+ memcpy ((char *) data, bufp, nread);
+ vm_deallocate (mach_task_self (), (vm_address_t) bufp, nread);
+ }
+ }
+ out:
+ return err;
+}
+
+/* Write to the locked file NP for user CRED starting at OFSET and
+ continuing for up to *LEN bytes from DATA. Set *LEN to the amount
+ successfully written upon return. */
+error_t
+netfs_attempt_write (struct iouser *cred, struct node *np,
+ off_t offset, size_t *len, void *data)
+{
+ error_t err = 0;
+ if (! np->nn->connected)
+ err = node_connect_socket (np);
+ if (err)
+ goto out;
+ err = socket_send (np->nn->sock, MACH_PORT_NULL, 0, (char *) data,
+ *len, NULL, MACH_MSG_TYPE_COPY_SEND, 0, NULL, 0,
+ (int *) len);
+ out:
+ return err;
+}
+
+/* Return the valid access types (bitwise OR of O_READ, O_WRITE, and
+ O_EXEC) in *TYPES for locked file NP and user CRED. */
+error_t
+netfs_report_access (struct iouser *cred, struct node *np,
+ int *types)
+{
+ *types = 0;
+ if (fshelp_access (&np->nn_stat, S_IREAD, cred) == 0)
+ *types |= O_READ;
+ if (fshelp_access (&np->nn_stat, S_IWRITE, cred) == 0)
+ *types |= O_WRITE;
+ if (fshelp_access (&np->nn_stat, S_IEXEC, cred) == 0)
+ *types |= O_EXEC;
+ return 0;
+}
+
+/* Create a new user from the specified UID and GID arrays. */
+struct iouser *
+netfs_make_user (uid_t *uids, int nuids, uid_t *gids, int ngids)
+{
+ return NULL;
+}
+
+/* Node NP has no more references; free all its associated storage. */
+void
+netfs_node_norefs (struct node *np)
+{
+ node_destroy (np);
+}
+
+/* Fill the array *DATA of size BUFSIZE with up to NENTRIES dirents
+ from DIR (which is locked) starting with entry ENTRY for user CRED.
+ The number of entries in the array is stored in *AMT and the number
+ of bytes in *DATACNT. If the supplied buffer is not large enough
+ to hold the data, it should be grown. Taken from hostmux. */
+error_t
+netfs_get_dirents (struct iouser *cred, struct node *dir,
+ int first_entry, int num_entries, char **data,
+ mach_msg_type_number_t *data_len,
+ vm_size_t max_data_len, int *data_entries)
+{
+ error_t err;
+ int count;
+ size_t size = 0; /* Total size of our return block. */
+ struct node *first_name, *nm;
+
+ /* Add the length of a directory entry for NAME to SIZE and return true,
+ unless it would overflow MAX_DATA_LEN or NUM_ENTRIES, in which case
+ return false. */
+ int bump_size (const char *name)
+ {
+ if (num_entries == -1 || count < num_entries)
+ {
+ size_t new_size = size + DIRENT_LEN (strlen (name));
+ if (max_data_len > 0 && new_size > max_data_len)
+ return 0;
+ size = new_size;
+ count++;
+ return 1;
+ }
+ else
+ return 0;
+ }
+
+ if (dir->nn->flags & PORT_NODE)
+ return ENOTDIR;
+
+ /* Find the first entry. */
+ for (first_name = dir->nn->entries, count = 0;
+ first_name && first_entry > count;
+ first_name = first_name->next)
+ count++;
+
+ count = 0;
+
+ /* Make space for the `.' and `..' entries. */
+ if (first_entry == 0)
+ bump_size (".");
+ if (first_entry <= 1)
+ bump_size ("..");
+
+ /* See how much space we need for the result. */
+ for (nm = first_name; nm; nm = nm->next)
+ if (!bump_size (nm->nn->protocol->name))
+ break;
+
+ /* Allocate it. */
+ *data = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ err = ((void *) *data == (void *) -1) ? errno : 0;
+
+ if (! err)
+ /* Copy out the result. */
+ {
+ char *p = *data;
+
+ int add_dir_entry (const char *name, ino_t fileno, int type)
+ {
+ if (num_entries == -1 || count < num_entries)
+ {
+ struct dirent hdr;
+ size_t name_len = strlen (name);
+ size_t sz = DIRENT_LEN (name_len);
+
+ if (sz > size)
+ return 0;
+ else
+ size -= sz;
+
+ hdr.d_fileno = fileno;
+ hdr.d_reclen = sz;
+ hdr.d_type = type;
+ hdr.d_namlen = name_len;
+
+ memcpy (p, &hdr, DIRENT_NAME_OFFS);
+ strcpy (p + DIRENT_NAME_OFFS, name);
+ p += sz;
+
+ count++;
+
+ return 1;
+ }
+ else
+ return 0;
+ }
+
+ *data_len = size;
+ *data_entries = count;
+
+ count = 0;
+
+ /* Add `.' and `..' entries. */
+ if (first_entry == 0)
+ add_dir_entry (".", 2, DT_DIR);
+ if (first_entry <= 1)
+ add_dir_entry ("..", 2, DT_DIR);
+
+ /* Fill in the real directory entries. */
+ for (nm = first_name; nm; nm = nm->next)
+ if (!add_dir_entry (nm->nn->protocol->name, nm->nn->protocol->id,
+ DT_DIR))
+ break;
+ }
+
+ fshelp_touch (&dir->nn_stat, TOUCH_ATIME, netio_maptime);
+ return err;
+}
+
+/* We need our special version of netfs_S_io_read. */
+
+error_t
+block_for_reading (socket_t sock)
+{
+ mach_port_t reply_port;
+ int type = SELECT_READ;
+ error_t err;
+ do
+ {
+ reply_port = mach_reply_port ();
+ if (reply_port == MACH_PORT_NULL)
+ return EIEIO; /* FIXME? */
+ err = io_select (sock, reply_port, 1000, &type);
+ }
+ while (err == EMACH_RCV_TIMED_OUT);
+ return err;
+}
+
+/* Implement the io_read interface. This is the original
+ implementation from libnetfs with one special hack at the
+ beginning. */
+error_t
+netfs_S_io_read (struct protid *user,
+ char **data,
+ mach_msg_type_number_t *datalen,
+ off_t offset,
+ mach_msg_type_number_t amount)
+{
+ error_t err;
+ off_t start;
+ struct node *node;
+ int alloced = 0;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ node = user->po->np;
+
+ /* This is our special hack. */
+ if (! node->nn->connected)
+ err = node_connect_socket (node);
+ if (err || node->nn->flags & PORT_NODE)
+ err = block_for_reading (node->nn->sock);
+ if (err)
+ return err;
+
+ mutex_lock (&user->po->np->lock);
+
+ if ((user->po->openstat & O_READ) == 0)
+ {
+ mutex_unlock (&node->lock);
+ return EBADF;
+ }
+
+ if (amount > *datalen)
+ {
+ alloced = 1;
+ *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
+ }
+ *datalen = amount;
+
+ start = (offset == -1 ? user->po->filepointer : offset);
+
+ if (start < 0)
+ err = EINVAL;
+ else if (S_ISLNK (node->nn_stat.st_mode))
+ /* Read from a symlink. */
+ {
+ off_t size = node->nn_stat.st_size;
+
+ if (start + amount > size)
+ amount = size - start;
+
+ if (start >= size)
+ {
+ *datalen = 0;
+ err = 0;
+ }
+ else if (amount < size || start > 0)
+ {
+ char *whole_link = alloca (size);
+ err = netfs_attempt_readlink (user->user, node, *data);
+ if (! err)
+ {
+ memcpy (*data, whole_link + start, amount);
+ *datalen = amount;
+ }
+ }
+ else
+ err = netfs_attempt_readlink (user->user, node, *data);
+ }
+ else
+ /* Read from a normal file. */
+ err = netfs_attempt_read (user->user, node, start, datalen, *data);
+
+ if (offset == -1 && !err)
+ user->po->filepointer += *datalen;
+
+ mutex_unlock (&node->lock);
+
+ if (err && alloced)
+ munmap (*data, amount);
+
+ if (!err && alloced && (round_page (*datalen) < round_page (amount)))
+ munmap (*data + round_page (*datalen),
+ round_page (amount) - round_page (*datalen));
+
+ return err;
+}
diff --git a/netio.h b/netio.h
new file mode 100644
index 000000000..f0fd7fdfd
--- /dev/null
+++ b/netio.h
@@ -0,0 +1,56 @@
+/* netio - creates socket ports via the filesystem
+ Copyright (C) 2001, 02 Moritz Schulte <moritz@duesseldorf.ccc.de>
+
+ 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 of the
+ License, 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/socket.h>
+#include <stdint.h>
+#include <maptime.h>
+
+#define NETIO_VERSION "0.1"
+
+#define OPENONLY_STATE_MODES (O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS|O_NONBLOCK)
+
+#define PROTOCOL_ID_TCP 0x00000001
+#define PROTOCOL_ID_UDP 0x00000002
+
+struct protocol
+{
+ char *name;
+ int id;
+ error_t (*socket_open) (struct node *np);
+};
+
+#define ROOT_NODE 0x00000001
+#define PROTOCOL_NODE 0x00000002
+#define HOST_NODE 0x00000004
+#define PORT_NODE 0x00000008
+
+struct netnode
+{
+ unsigned short int flags; /* Either ROOT_NODE, PROTOCOL_NODE,
+ HOST_NODE or PORT_NODE. */
+ char *host;
+ uint16_t port;
+ struct protocol *protocol;
+ socket_t sock;
+ addr_port_t addr;
+ unsigned short int connected;
+ struct node *entries;
+ struct node *dir;
+};
+
+extern volatile struct mapped_time_value *netio_maptime;
diff --git a/node.c b/node.c
new file mode 100644
index 000000000..29529103a
--- /dev/null
+++ b/node.c
@@ -0,0 +1,222 @@
+/* netio - creates socket ports via the filesystem
+ Copyright (C) 2001, 02 Moritz Schulte <moritz@duesseldorf.ccc.de>
+
+ 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 of the
+ License, 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 <errno.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+
+#include "netio.h"
+#include "lib.h"
+
+/* Create a new node in the directory *DIR (if DIR is nonzero) and
+ store it in *NODE. If CONNECT is true (in which case *DIR has to
+ be a valid directory node), attach the new node to the list of
+ directory entries of *DIR. Return 0 on success or an error code. */
+error_t
+node_make_new (struct node *dir, int connect, struct node **node)
+{
+ struct netnode *netnode;
+ error_t err;
+
+ err = my_malloc (sizeof (struct netnode), (void **) &netnode);
+ if (err)
+ return err;
+ *node = netfs_make_node (netnode);
+ if (! *node)
+ {
+ free (netnode);
+ return ENOMEM;
+ }
+ (*node)->nn->flags = 0;
+ (*node)->nn->host = 0;
+ (*node)->nn->port = 0;
+ (*node)->nn->protocol = 0;
+ (*node)->nn->sock = MACH_PORT_NULL;
+ (*node)->nn->addr = MACH_PORT_NULL;
+ (*node)->nn->connected = 0;
+ (*node)->nn->entries = 0;
+ (*node)->nn->dir = dir;
+ if (dir)
+ netfs_nref (dir);
+
+ if (connect)
+ {
+ (*node)->next = dir->nn->entries;
+ (*node)->prevp = &dir->nn->entries;
+ if ((*node)->next)
+ (*node)->next->prevp = &(*node)->next;
+ dir->nn->entries = (*node);
+ }
+ else
+ {
+ (*node)->next = 0;
+ (*node)->prevp = 0;
+ }
+ return err;
+}
+
+/* Destroy the node and release a reference to the parent directory. */
+error_t
+node_destroy (struct node *np)
+{
+ if (np->nn->flags & PORT_NODE)
+ {
+ if (np->nn->connected)
+ socket_shutdown (np->nn->sock, 2);
+ }
+ else if (np->nn->flags & HOST_NODE)
+ free (np->nn->host);
+ else if (np->nn->flags & PROTOCOL_NODE)
+ {
+ free (np->nn->protocol);
+ *np->prevp = np->next;
+ if (np->next)
+ np->next->prevp = np->prevp;
+ }
+ assert (np->nn->dir);
+ spin_unlock (&netfs_node_refcnt_lock); /* FIXME? Is this locking
+ okay? */
+ netfs_nput (np->nn->dir);
+ spin_lock (&netfs_node_refcnt_lock);
+ free (np->nn);
+ free (np);
+ return 0;
+}
+
+/* Create a new protocol node for *PROTOCOL in the directory *DIR.
+ Return 0 on success or an error code. */
+error_t
+node_make_protocol_node (struct node *dir, struct protocol *protocol)
+{
+ struct node *node;
+ error_t err;
+ err = node_make_new (dir, 1, &node);
+ if (err)
+ return err;
+ node->nn->flags |= PROTOCOL_NODE;
+ node->nn->protocol = protocol;
+ node->nn_stat.st_mode = S_IFDIR
+ | S_IRUSR | S_IXUSR
+ | S_IRGRP | S_IXGRP
+ | S_IROTH | S_IXOTH;
+ node->nn_stat.st_ino = protocol->id;
+ node->nn_stat.st_dev = netfs_root_node->nn_stat.st_dev;
+ node->nn_stat.st_uid = netfs_root_node->nn_stat.st_uid;
+ node->nn_stat.st_gid = netfs_root_node->nn_stat.st_gid;
+ node->nn_stat.st_size = 0; /* ? */
+ node->nn_stat.st_blocks = 0;
+ node->nn_stat.st_blksize = 0;
+ fshelp_touch (&node->nn_stat, TOUCH_ATIME | TOUCH_CTIME | TOUCH_MTIME,
+ netio_maptime);
+ return err;
+}
+
+/* Create a new host node for HOST in the directory *DIR and store it
+ in *NODE. Return 0 on success or an error code. */
+error_t
+node_make_host_node (struct iouser *user, struct node *dir, char *host,
+ struct node **node)
+{
+ struct node *np;
+ error_t err;
+ err = node_make_new (dir, 0, &np);
+ if (err)
+ return err;
+ np->nn->host = strdup (host);
+ if (! np->nn->host)
+ {
+ netfs_nrele (np);
+ err = ENOMEM;
+ goto out;
+ }
+ np->nn->flags |= HOST_NODE;
+ np->nn->protocol = dir->nn->protocol;
+ np->nn_stat.st_mode = S_IFDIR | S_IRUSR | S_IXUSR ;
+ np->nn_stat.st_ino = 1; /* ? */
+ np->nn_stat.st_dev = netfs_root_node->nn_stat.st_dev;
+ np->nn_stat.st_uid = *user->uids->ids;
+ np->nn_stat.st_gid = *user->gids->ids;
+ np->nn_stat.st_size = 0; /* ? */
+ np->nn_stat.st_blocks = 0;
+ np->nn_stat.st_blksize = 0;
+ fshelp_touch (&np->nn_stat, TOUCH_ATIME | TOUCH_CTIME | TOUCH_MTIME,
+ netio_maptime);
+ *node = np;
+
+ out:
+ return err;
+}
+
+/* Create a new port node for PORT in the directory *DIR and store it
+ in *NODE. Return 0 on success or an error code. */
+error_t
+node_make_port_node (struct iouser *user, struct node *dir,
+ char *port, struct node **node)
+{
+ struct node *np;
+ error_t err;
+ err = node_make_new (dir, 0, &np);
+ if (err)
+ return err;
+ np->nn->flags |= PORT_NODE;
+ np->nn->host = dir->nn->host;
+ np->nn->protocol = dir->nn->protocol;
+ np->nn->port = (uint16_t) strtol (port, 0, 10);
+ np->nn->flags |= HOST_NODE;
+ np->nn->protocol = dir->nn->protocol;
+ np->nn_stat.st_mode = S_IFSOCK | S_IRUSR | S_IWUSR ;
+ np->nn_stat.st_ino = 1; /* ? */
+ np->nn_stat.st_dev = netfs_root_node->nn_stat.st_dev;
+ np->nn_stat.st_uid = *user->uids->ids;
+ np->nn_stat.st_gid = *user->gids->ids;
+ np->nn_stat.st_size = 0; /* ? */
+ np->nn_stat.st_blocks = 0;
+ np->nn_stat.st_blksize = 0;
+ fshelp_touch (&np->nn_stat, TOUCH_ATIME | TOUCH_CTIME | TOUCH_MTIME,
+ netio_maptime);
+ *node = np;
+ return err;
+}
+
+/* Create the root node. Return 0 on success or an error code. */
+error_t
+node_make_root_node (struct node **node)
+{
+ struct node *np;
+ error_t err;
+ err = node_make_new (0, 0, &np);
+ if (err)
+ goto out;
+ np->nn->flags |= ROOT_NODE;
+ *node = np;
+ out:
+ return err;
+}
+
+/* Connect the socket of the node *NP. Return 0 on success or an
+ error code. */
+error_t
+node_connect_socket (struct node *np)
+{
+ error_t err;
+ err = (*np->nn->protocol->socket_open) (np);
+ if (! err)
+ np->nn->connected = 1;
+ return err;
+}
diff --git a/node.h b/node.h
new file mode 100644
index 000000000..3169beef9
--- /dev/null
+++ b/node.h
@@ -0,0 +1,33 @@
+/* netio - creates socket ports via the filesystem
+ Copyright (C) 2001, 02 Moritz Schulte <moritz@duesseldorf.ccc.de>
+
+ 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 of the
+ License, 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 <errno.h>
+#include <hurd/netfs.h>
+#include <hurd/iohelp.h>
+
+error_t node_make_new (struct node *dir, int connect, struct node **node);
+error_t node_make_protocol_node (struct node *dir,
+ struct protocol *protocol);
+error_t node_make_host_node (struct iouser *user, struct node *dir,
+ char *host, struct node **node);
+error_t node_make_port_node (struct iouser *user, struct node *dir,
+ char *port, struct node **node);
+error_t node_make_root_node (struct node **the_node);
+error_t node_connect_socket (struct node *np);
+error_t node_destroy (struct node *np);
+
diff --git a/protocol.c b/protocol.c
new file mode 100644
index 000000000..88dcb5901
--- /dev/null
+++ b/protocol.c
@@ -0,0 +1,152 @@
+/* netio - creates socket ports via the filesystem
+ Copyright (C) 2002 Moritz Schulte <moritz@duesseldorf.ccc.de>
+
+ 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 of the
+ License, 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 <hurd/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "netio.h"
+#include "lib.h"
+#include "node.h"
+
+/* Connect the node *NODE with style STYLE (SOCK_STREAM or
+ SOCK_DGRAM). Used by protocol_socket_open_{tcp,udp}. Return 0 on
+ success or an error code. */
+error_t
+protocol_socket_open_std (struct node *node, int style)
+{
+ extern pf_t socket_server;
+ socket_t sock;
+ addr_port_t aport;
+ error_t err;
+ struct sockaddr_in addr;
+ struct hostent *hostinfo;
+
+ hostinfo = gethostbyname (node->nn->host);
+ if (hostinfo == NULL)
+ {
+ err = h_errno;
+ goto out;
+ }
+
+ if ((err = socket_create (socket_server, style, 0, &sock)))
+ goto out;
+ addr.sin_family = AF_INET;
+ addr.sin_addr = *(struct in_addr *) hostinfo->h_addr;
+ addr.sin_port = htons (node->nn->port);
+ if ((err = socket_create_address (sock, addr.sin_family,
+ (char *) &addr, sizeof (addr), &aport)))
+ goto out;
+ if ((err = socket_connect (sock, aport)))
+ goto out;
+
+ node->nn->sock = sock;
+ node->nn->addr = aport;
+
+ /* FIXME: cleanup missing? */
+
+ out:
+ return err;
+}
+
+/* Open a TCP socket for *NODE. Return 0 on success or an error code. */
+error_t
+protocol_socket_open_tcp (struct node *node)
+{
+ return protocol_socket_open_std (node, SOCK_STREAM);
+}
+
+/* Open a UDP socket for *NODE. Return 0 on success or an error code. */
+error_t
+protocol_socket_open_udp (struct node *node)
+{
+ return protocol_socket_open_std (node, SOCK_DGRAM);
+}
+
+/* Store the protocol node for the protocol specified by NAME in
+ *NODE. Return 0 on success or ENOENT if the node could not be
+ found. */
+error_t
+protocol_find_node (char *name, struct node **node)
+{
+ struct node *np;
+ for (np = netfs_root_node->nn->entries;
+ np && strcmp (np->nn->protocol->name, name);
+ np = np->next);
+ if (! np)
+ return ENOENT;
+ *node = np;
+ return 0;
+}
+
+/* Register a protocol specified by ID and NAME, creating an according
+ node. Sockets for that protocol get opened by SOCKET_OPEN_FUNC.
+ Return 0 on success or an error code. */
+error_t
+protocol_register (int id, char *name,
+ error_t (*socket_open_func) (struct node *node))
+{
+ error_t err;
+ struct protocol *protocol;
+ err = my_malloc (sizeof (struct protocol), (void **) &protocol);
+ if (err)
+ return err;
+ protocol->name = strdup (name);
+ if (! protocol->name)
+ {
+ free (protocol);
+ return ENOMEM;
+ }
+ err = node_make_protocol_node (netfs_root_node, protocol);
+ if (err)
+ {
+ free (protocol->name);
+ free (protocol);
+ return err;
+ }
+ protocol->id = id;
+ protocol->socket_open = socket_open_func;
+ return 0;
+}
+
+/* Unregister the protocol specified by NAME, drop the reference to
+ the protocol node. Return 0 on success or ENOENT if that protocol
+ could not be found. */
+error_t
+protocol_unregister (char *name)
+{
+ struct node *np;
+ error_t err;
+ err = protocol_find_node (name, &np);
+ if (err)
+ return err;
+ netfs_nrele (np);
+ return 0;
+}
+
+/* Register the protocols - create according nodes. Return 0 on
+ success or an error code. */
+error_t
+protocol_register_protocols (void)
+{
+ return (protocol_register (PROTOCOL_ID_TCP, "tcp",
+ protocol_socket_open_tcp)
+ || protocol_register (PROTOCOL_ID_UDP, "udp",
+ protocol_socket_open_udp));
+}
diff --git a/protocol.h b/protocol.h
new file mode 100644
index 000000000..2afae90f9
--- /dev/null
+++ b/protocol.h
@@ -0,0 +1,23 @@
+/* netio - creates socket ports via the filesystem
+ Copyright (C) 2002 Moritz Schulte <moritz@duesseldorf.ccc.de>
+
+ 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 of the
+ License, 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 */
+
+error_t protocol_register_protocols (void);
+error_t protocol_register (int id, char *name,
+ error_t (*socket_open_func) (struct node *node));
+error_t protocol_unregister (char *name);;
+error_t protocol_find_node (char *name, struct node **node);
diff --git a/version.h b/version.h
new file mode 100644
index 000000000..54108e57a
--- /dev/null
+++ b/version.h
@@ -0,0 +1,30 @@
+/* Hurd version
+ Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG.
+
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef HURD_VERSION
+#define HURD_VERSION "0.2"
+#endif
+
+/* The standard way to print versions for --version. */
+#define _SHV_SEP "; "
+#define STANDARD_HURD_VERSION(s, extra...) \
+ #s " (GNU Hurd" _SHV_SEP ##extra ") " HURD_VERSION
+
+