diff options
Diffstat (limited to 'nfsd')
-rw-r--r-- | nfsd/Makefile | 34 | ||||
-rw-r--r-- | nfsd/cache.c | 496 | ||||
-rw-r--r-- | nfsd/fsys.c | 192 | ||||
-rw-r--r-- | nfsd/loop.c | 233 | ||||
-rw-r--r-- | nfsd/main.c | 78 | ||||
-rw-r--r-- | nfsd/nfsd.h | 128 | ||||
-rw-r--r-- | nfsd/ops.c | 652 | ||||
-rw-r--r-- | nfsd/proctables.c | 57 | ||||
-rw-r--r-- | nfsd/xdr.c | 204 |
9 files changed, 2074 insertions, 0 deletions
diff --git a/nfsd/Makefile b/nfsd/Makefile new file mode 100644 index 00000000..4460b4ba --- /dev/null +++ b/nfsd/Makefile @@ -0,0 +1,34 @@ +# +# Copyright (C) 1996 Free Software Foundation, Inc. +# Written by Michael I. Bushnell, p/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. + +dir := nfsd +makemode := utility + +SRCS = cache.c loop.c main.c ops.c fsys.c xdr.c +OBJS = $(subst .c,.o,$(SRCS)) +LCLHDRS = nfsd.h +target = nfsd +installationdir = $(sbindir) + +include ../Makeconf + +CPPFLAGS += -DLOCALSTATEDIR=$(localstatedir) + +nfsd: ../libthreads/libthreads.a ../libshouldbeinlibc/libshouldbeinlibc.a
\ No newline at end of file diff --git a/nfsd/cache.c b/nfsd/cache.c new file mode 100644 index 00000000..745a7c8e --- /dev/null +++ b/nfsd/cache.c @@ -0,0 +1,496 @@ +/* + Copyright (C) 1996 Free Software Foundation, Inc. + Written by Michael I. Bushnell, p/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. */ + + +#include <string.h> +#include <hurd/fsys.h> +#include <assert.h> +#include <string.h> +#include "nfsd.h" + + +#undef TRUE +#undef FALSE +#define malloc spoogie_woogie /* ugh^2. */ +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/auth_unix.h> +#undef malloc + +#define IDHASH_TABLE_SIZE 1024 +#define FHHASH_TABLE_SIZE 1024 +#define REPLYHASH_TABLE_SIZE 1024 + + +static struct idspec *idhashtable[IDHASH_TABLE_SIZE]; +spin_lock_t idhashlock = SPIN_LOCK_INITIALIZER; +static int nfreeids; +static int leastidlastuse; + +/* Compare I against the specified set of users/groups. */ +/* Use of int in decl of UIDS and GIDS is correct here; that's + the NFS type because they come in in known 32 bit slots. */ +static int +idspec_compare (struct idspec *i, int nuids, int ngids, + int *uids, int *gids) +{ + if (i->nuids != nuids + || i->ngids != ngids) + return 0; + + assert (sizeof (int) == sizeof (uid_t)); + + if (bcmp (i->uids, uids, nuids * sizeof (uid_t)) + || bcmp (i->gids, gids, ngids * sizeof (gid_t))) + return 0; + + return 1; +} + +/* Compute a hash value for a given user spec */ +static int +idspec_hash (int nuids, int ngids, int *uids, int *gids) +{ + int hash, n; + + hash = nuids + ngids; + for (n = 0; n < ngids; n++) + hash += gids[n]; + for (n = 0; n < nuids; n++) + hash += uids[n]; + hash %= IDHASH_TABLE_SIZE; + return hash; +} + +/* Lookup a user spec in the hash table and allocate a reference */ +static struct idspec * +idspec_lookup (int nuids, int ngids, int *uids, int *gids) +{ + int hash; + struct idspec *i; + + hash = idspec_hash (nuids, ngids, uids, gids); + + spin_lock (&idhashlock); + for (i = idhashtable[hash]; i; i = i->next) + if (idspec_compare (i, nuids, ngids, uids, gids)) + { + i->references++; + if (i->references == 1) + nfreeids--; + spin_unlock (&idhashlock); + return i; + } + + assert (sizeof (uid_t) == sizeof (int)); + i = malloc (sizeof (struct idspec)); + i->nuids = nuids; + i->ngids = ngids; + i->uids = malloc (nuids * sizeof (uid_t)); + i->gids = malloc (ngids * sizeof (gid_t)); + bcopy (uids, i->uids, nuids * sizeof (uid_t)); + bcopy (gids, i->gids, ngids * sizeof (gid_t)); + i->references = 1; + + i->next = idhashtable[hash]; + if (idhashtable[hash]) + idhashtable[hash]->prevp = &i->next; + i->prevp = &idhashtable[hash]; + idhashtable[hash] = i; + + spin_unlock (&idhashlock); + return i; +} + +int * +process_cred (int *p, struct idspec **credp) +{ + int type; + int len; + int *uid; + int *gids; + int ngids; + int firstgid; + int i; + + type = ntohl (*p++); + + if (type != AUTH_UNIX) + { + int size = ntohl (*p++); + *credp = idspec_lookup (0, 0, 0, 0); + return p + INTSIZE (size); + } + + p++; /* skip size */ + p++; /* skip seconds */ + len = ntohl (*p++); + p += INTSIZE (len); /* skip hostname */ + + uid = p++; /* remember loc of uid */ + *uid = ntohl (*uid); + + firstgid = *p++; /* remember first gid */ + gids = p; /* here's where the array will start */ + ngids = ntohl (*p++); + + /* Now swap the first gid to be the first element of the array */ + *gids = firstgid; + ngids++; /* and count it */ + + /* And byteswap the gids */ + for (i = 1; i < ngids; i++) + gids[i] = ntohl (gids[i]); + + /* Next is the verf field; skip it entirely */ + p++; /* skip id */ + len = htonl (*p++); + p += INTSIZE (len); + + *credp = idspec_lookup (1, ngids, uid, gids); + return p; +} + +void +cred_rele (struct idspec *i) +{ + spin_lock (&idhashlock); + i->references--; + if (i->references == 0) + { + i->lastuse = mapped_time->seconds; + if (i->lastuse < leastidlastuse || nfreeids == 0) + leastidlastuse = i->lastuse; + nfreeids++; + } + spin_unlock (&idhashlock); +} + +void +cred_ref (struct idspec *i) +{ + spin_lock (&idhashlock); + assert (i->references); + i->references++; + spin_unlock (&idhashlock); +} + +void +scan_creds () +{ + struct idspec *i; + int n; + int newleast = mapped_time->seconds; + + spin_lock (&idhashlock); + if (mapped_time->seconds - leastidlastuse > ID_KEEP_TIMEOUT) + for (n = 0; n < IDHASH_TABLE_SIZE && nfreeids; n++) + for (i = idhashtable[n]; i && nfreeids; i = i->next) + if (!i->references + && mapped_time->seconds - i->lastuse > ID_KEEP_TIMEOUT) + { + nfreeids--; + *i->prevp = i->next; + if (i->next) + i->next->prevp = i->prevp; + free (i->uids); + free (i->gids); + free (i); + } + else + if (!i->references && newleast > i->lastuse) + newleast = i->lastuse; + + /* If we didn't bail early, then this is valid */ + if (nfreeids) + leastidlastuse = newleast; + spin_unlock (&idhashlock); +} + + + +static struct cache_handle *fhhashtable[FHHASH_TABLE_SIZE]; +struct mutex fhhashlock = MUTEX_INITIALIZER; +static int nfreefh; +static int leastfhlastuse; + +static int +fh_hash (char *fhandle, struct idspec *i) +{ + int hash = 0, n; + + for (n = 0; n < NFS_FHSIZE; n++) + hash += fhandle[n]; + hash += (int) i >> 6; + return hash; +} + +int * +lookup_cache_handle (int *p, struct cache_handle **cp, struct idspec *i) +{ + int hash; + struct cache_handle *c; + fsys_t fsys; + file_t port; + + hash = fh_hash ((char *)p, i); + mutex_lock (&fhhashlock); + for (c = fhhashtable[hash]; c; c = c->next) + if (c->ids == i && ! bcmp (c->handle, p, NFS_FHSIZE)) + { + if (c->references == 0) + nfreefh--; + c->references++; + mutex_unlock (&fhhashlock); + *cp = c; + return p + NFS_FHSIZE / sizeof (int); + } + + /* Not found */ + + /* First four bytes are our internal table of filesystems */ + fsys = lookup_filesystem (*p); + if (fsys == MACH_PORT_NULL + || fsys_getfile (fsys, i->uids, i->nuids, i->gids, i->ngids, + (char *)(p + 1), NFS_FHSIZE - sizeof (int), &port)) + { + mutex_unlock (&fhhashlock); + *cp = 0; + return p + NFS_FHSIZE / sizeof (int); + } + + c = malloc (sizeof (struct cache_handle)); + bcopy (p, c->handle, NFS_FHSIZE); + cred_ref (i); + c->ids = i; + c->port = port; + c->references = 1; + + c->next = fhhashtable[hash]; + if (c->next) + c->next->prevp = &c->next; + c->prevp = &fhhashtable[hash]; + fhhashtable[hash] = c; + + mutex_unlock (&fhhashlock); + *cp = c; + return p + NFS_FHSIZE / sizeof (int); +} + +void +cache_handle_rele (struct cache_handle *c) +{ + mutex_lock (&fhhashlock); + c->references--; + if (c->references == 0) + { + c->lastuse = mapped_time->seconds; + if (c->lastuse < leastfhlastuse || nfreefh == 0) + leastfhlastuse = c->lastuse; + nfreefh++; + } + mutex_unlock (&fhhashlock); +} + +void +scan_fhs () +{ + struct cache_handle *c; + int n; + int newleast = mapped_time->seconds; + + mutex_lock (&fhhashlock); + if (mapped_time->seconds - leastfhlastuse > FH_KEEP_TIMEOUT) + for (n = 0; n < FHHASH_TABLE_SIZE && nfreefh; n++) + for (c = fhhashtable[n]; c && nfreefh; c = c->next) + if (!c->references + && mapped_time->seconds - c->lastuse > FH_KEEP_TIMEOUT) + { + nfreefh--; + *c->prevp = c->next; + if (c->next) + c->next->prevp = c->prevp; + cred_rele (c->ids); + mach_port_deallocate (mach_task_self (), c->port); + free (c); + } + else + if (!c->references && newleast > c->lastuse) + newleast = c->lastuse; + + /* If we didn't bail early, then this is valid. */ + if (nfreefh) + leastfhlastuse = newleast; + mutex_unlock (&fhhashlock); +} + +struct cache_handle * +create_cached_handle (int fs, struct cache_handle *credc, file_t newport) +{ + char fhandle[NFS_FHSIZE]; + error_t err; + struct cache_handle *c; + int hash; + char *bp = fhandle + sizeof (int); + size_t handlelen = NFS_FHSIZE - sizeof (int); + + *(int *)fhandle = fs; + err = file_getfh (newport, &bp, &handlelen); + if (err || handlelen != NFS_FHSIZE - sizeof (int)) + { + mach_port_deallocate (mach_task_self (), newport); + return 0; + } + if (bp != fhandle + sizeof (int)) + { + bcopy (bp, fhandle + sizeof (int), NFS_FHSIZE - sizeof (int)); + vm_deallocate (mach_task_self (), (vm_address_t) bp, handlelen); + } + + hash = fh_hash (fhandle, credc->ids); + mutex_lock (&fhhashlock); + for (c = fhhashtable[hash]; c; c = c->next) + if (c->ids == credc->ids && ! bcmp (fhandle, c->handle, NFS_FHSIZE)) + { + /* Return this one */ + if (c->references == 0) + nfreefh--; + c->references++; + mutex_unlock (&fhhashlock); + mach_port_deallocate (mach_task_self (), newport); + return c; + } + + /* Create it anew */ + c = malloc (sizeof (struct cache_handle)); + bcopy (fhandle, c->handle, NFS_FHSIZE); + cred_ref (credc->ids); + c->ids = credc->ids; + c->port = newport; + c->references = 1; + + /* And add it to the hash table */ + c->next = fhhashtable[hash]; + if (c->next) + c->next->prevp = &c->next; + c->prevp = &fhhashtable[hash]; + fhhashtable[hash] = c; + mutex_unlock (&fhhashlock); + + return c; +} + + + +static struct cached_reply *replyhashtable [REPLYHASH_TABLE_SIZE]; +static spin_lock_t replycachelock = SPIN_LOCK_INITIALIZER; +static int nfreereplies; +static int leastreplylastuse; + +/* Check the list of cached replies to see if this is a replay of a + previous transaction; if so, return the cache record. Otherwise, + create a new cache record. */ +struct cached_reply * +check_cached_replies (int xid, + struct sockaddr_in *sender) +{ + struct cached_reply *cr; + int hash; + + hash = xid % REPLYHASH_TABLE_SIZE; + + spin_lock (&replycachelock); + for (cr = replyhashtable[hash]; cr; cr = cr->next) + if (cr->xid == xid + && !bcmp (sender, &cr->source, sizeof (struct sockaddr_in))) + { + cr->references++; + if (cr->references == 1) + nfreereplies--; + spin_unlock (&replycachelock); + mutex_lock (&cr->lock); + return cr; + } + + cr = malloc (sizeof (struct cached_reply)); + mutex_init (&cr->lock); + mutex_lock (&cr->lock); + bcopy (sender, &cr->source, sizeof (struct sockaddr_in)); + cr->xid = xid; + cr->data = 0; + + cr->next = replyhashtable[hash]; + if (replyhashtable[hash]) + replyhashtable[hash]->prevp = &cr->next; + cr->prevp = &replyhashtable[hash]; + replyhashtable[hash] = cr; + + spin_unlock (&replycachelock); + return cr; +} + +/* A cached reply returned by check_cached_replies is now no longer + needed by its caller. */ +void +release_cached_reply (struct cached_reply *cr) +{ + mutex_unlock (&cr->lock); + spin_lock (&replycachelock); + cr->references--; + if (cr->references == 0) + { + cr->lastuse = mapped_time->seconds; + if (cr->lastuse < leastreplylastuse || nfreereplies == 0) + leastreplylastuse = cr->lastuse; + nfreereplies++; + } + spin_unlock (&replycachelock); +} + +void +scan_replies () +{ + struct cached_reply *cr; + int n; + int newleast = mapped_time->seconds; + + spin_lock (&replycachelock); + if (mapped_time->seconds - leastreplylastuse > REPLY_KEEP_TIMEOUT) + for (n = 0; n < REPLYHASH_TABLE_SIZE && nfreereplies; n++) + for (cr = replyhashtable[n]; cr && nfreereplies; cr = cr->next) + if (!cr->references + && mapped_time->seconds - cr->lastuse > REPLY_KEEP_TIMEOUT) + { + nfreereplies--; + *cr->prevp = cr->next; + if (cr->next) + cr->next->prevp = cr->prevp; + if (cr->data) + free (cr->data); + } + else + if (!cr->references && newleast > cr->lastuse) + newleast = cr->lastuse; + + /* If we didn't bail early, then this is valid */ + if (nfreereplies) + leastreplylastuse = newleast; + spin_unlock (&replycachelock); +} diff --git a/nfsd/fsys.c b/nfsd/fsys.c new file mode 100644 index 00000000..d3c50220 --- /dev/null +++ b/nfsd/fsys.c @@ -0,0 +1,192 @@ +/* Filesystem management for NFS server + Copyright (C) 1996 Free Software Foundation, Inc. + Written by Michael I. Bushnell, p/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. */ + +#include <stdio.h> +#include <errno.h> +#include <hurd.h> +#include <fcntl.h> +#include <string.h> + +#include "nfsd.h" + +struct fsys_spec +{ + fsys_t fsys; + char *name; +}; + +static struct fsys_spec *fsystable; +static int nfsys = 0; +static int fsystablesize = 0; + +file_t index_file_dir; +char *index_file_compname; + +/* Read the filesystem table in from disk */ +void +init_filesystems (void) +{ + int nitems; + char *name; + int index; + int line; + file_t root; + static FILE *index_file; + + fsystable = (struct fsys_spec *) malloc ((fsystablesize = 10) + * sizeof (struct fsys_spec)); + + if (!index_file_name) + return; + + index_file = fopen (index_file_name, "r"); + if (!index_file) + { + fprintf (stderr, "%s: Cannot open `%s': %s\n", + program_invocation_name, index_file_name, strerror (errno)); + return; + } + + for (line = 1; ; line++) + { + nitems = fscanf (index_file, "%d %as\n", &index, &name); + if (nitems == EOF) + { + fclose (index_file); + return; + } + + if (nitems != 2) + { + fprintf (stderr, "%s:%s:%d Bad syntax\n", + program_invocation_name, index_file_name, line); + continue; + } + + root = file_name_lookup (name, 0, 0); + if (!root) + { + fprintf (stderr, "%s:%s:%d Filesystem `%s': %s\n", + program_invocation_name, index_file_name, line, + name, strerror (errno)); + free (name); + continue; + } + + if (index >= fsystablesize) + fsystable = (struct fsys_spec *) realloc (fsystable, + (fsystablesize = index * 2) + * sizeof (struct fsys_spec)); + if (index > nfsys) + nfsys = index; + + fsystable[index].name = name; + file_getcontrol (root, &fsystable[nfsys].fsys); + mach_port_deallocate (mach_task_self (), root); + } +} + +/* Write the current filesystem table to disk synchronously. */ +static void +write_filesystems (void) +{ + file_t newindex; + FILE *f; + int i; + + if (!index_file_name) + return; + + if (index_file_dir == MACH_PORT_NULL) + { + index_file_dir = file_name_split (index_file_name, &index_file_compname); + if (index_file_dir == MACH_PORT_NULL) + { + fprintf (stderr, "%s: `%s': %s\n", + program_invocation_name, index_file_name, strerror (errno)); + index_file_name = 0; + return; + } + } + + /* Create an anonymous file in the same directory */ + errno = dir_mkfile (index_file_dir, O_WRONLY, 0666, &newindex); + if (errno) + { + fprintf (stderr, "%s: `%s': %s\n", + program_invocation_name, index_file_name, strerror (errno)); + index_file_name = 0; + mach_port_deallocate (mach_task_self (), index_file_dir); + index_file_dir = MACH_PORT_NULL; + return; + } + + f = fopenport (newindex, "w"); + + for (i = 0; i < nfsys; i++) + if (fsystable[i].name) + fprintf (f, "%d %s\n", i, fsystable[i].name); + + /* Link it in */ + errno = dir_link (index_file_dir, newindex, index_file_compname, 0); + if (errno) + fprintf (stderr, "%s: `%s': %s\n", + program_invocation_name, index_file_name, strerror (errno)); + fflush (f); + file_sync (newindex, 1, 0); + fclose (f); +} + +/* From a filesystem ID number, return the fsys_t for talking to that + filesystem; MACH_PORT_NULL if it isn't in our list. */ +fsys_t +lookup_filesystem (int id) +{ + if (id >= nfsys) + return MACH_PORT_NULL; + return fsystable[id].fsys; +} + +/* Enter a name in the table of filesystems; return its ID number. + ROOT refers to the root of this filesystem. */ +int +enter_filesystem (char *name, file_t root) +{ + int i; + + for (i = 0; i < nfsys; i++) + if (fsystable[i].name && !strcmp (fsystable[i].name, name)) + return i; + + if (nfsys == fsystablesize) + fsystable = (struct fsys_spec *) realloc (fsystable, + (fsystablesize *= 2) + * sizeof (struct fsys_spec)); + + fsystable[nfsys].name = malloc (strlen (name) + 1); + strcpy (fsystable[nfsys].name, name); + file_getcontrol (root, &fsystable[nfsys].fsys); + nfsys++; + + write_filesystems (); + + return nfsys - 1; +} + diff --git a/nfsd/loop.c b/nfsd/loop.c new file mode 100644 index 00000000..3520e1da --- /dev/null +++ b/nfsd/loop.c @@ -0,0 +1,233 @@ +/* + Copyright (C) 1996 Free Software Foundation, Inc. + Written by Michael I. Bushnell, p/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. */ + +#include <string.h> +#include <fcntl.h> + +#include "nfsd.h" + +#include <rpc/pmap_prot.h> +#include "../nfs/rpcsvc/mount.h" + +#undef TRUE +#undef FALSE +#define malloc spoogie_woogie /* barf */ +#include <rpc/xdr.h> +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/rpc_msg.h> +#undef malloc + +void +server_loop () +{ + char buf[MAXIOSIZE]; + int xid; + int *p, *r; + char *rbuf; + struct cached_reply *cr; + int program; + struct sockaddr_in sender; + int version; + int procedure; + struct proctable *table = 0; + struct procedure *proc; + struct idspec *cred; + struct cache_handle *c, fakec; + error_t err; + size_t addrlen; + fd_set readfds; + int maxfd; + int i; + int *errloc; + + bzero (&fakec, sizeof (struct cache_handle)); + + if (main_udp_socket > pmap_udp_socket) + maxfd = main_udp_socket; + else + maxfd = pmap_udp_socket; + + for (;;) + { + FD_ZERO (&readfds); + FD_SET (main_udp_socket, &readfds); + FD_SET (pmap_udp_socket, &readfds); + select (maxfd, &readfds, 0, 0, 0); + + for (i = main_udp_socket; + i != -1; + i = (i == main_udp_socket ? pmap_udp_socket : -1)) + { + if (!FD_ISSET (i, &readfds)) + continue; + + p = (int *) buf; + proc = 0; + addrlen = sizeof (struct sockaddr_in); + recvfrom (i, buf, MAXIOSIZE, 0, &sender, &addrlen); + xid = *p++; + + /* Ignore things that aren't proper RPCs. */ + if (ntohl (*p++) != CALL) + continue; + + cr = check_cached_replies (xid, &sender); + if (cr->data) + /* This transacation has already completed */ + goto repost_reply; + + r = (int *) rbuf = malloc (MAXIOSIZE); + + if (ntohl (*p++) != RPC_MSG_VERSION) + { + /* Reject RPC */ + *r++ = xid; + *r++ = htonl (REPLY); + *r++ = htonl (MSG_DENIED); + *r++ = htonl (RPC_MISMATCH); + *r++ = htonl (RPC_MSG_VERSION); + *r++ = htonl (RPC_MSG_VERSION); + goto send_reply; + } + + program = ntohl (*p++); + switch (program) + { + case MOUNTPROG: + version = MOUNTVERS; + table = &mounttable; + break; + + case NFS_PROGRAM: + version = NFS_VERSION; + table = &nfstable; + break; + + case PMAPPROG: + version = PMAPVERS; + table = &pmaptable; + break; + + default: + /* Program unavailable */ + *r++ = xid; + *r++ = htonl (REPLY); + *r++ = htonl (MSG_ACCEPTED); + *r++ = htonl (AUTH_NULL); + *r++ = htonl (0); + *r++ = htonl (PROG_UNAVAIL); + goto send_reply; + } + + if (ntohl (*p++) != version) + { + /* Program mismatch */ + *r++ = xid; + *r++ = htonl (REPLY); + *r++ = htonl (MSG_ACCEPTED); + *r++ = htonl (AUTH_NULL); + *r++ = htonl (0); + *r++ = htonl (PROG_MISMATCH); + *r++ = htonl (version); + *r++ = htonl (version); + goto send_reply; + } + + procedure = htonl (*p++); + if (procedure < table->min + || procedure > table->max + || table->procs[procedure - table->min].func == 0) + { + /* Procedure unavailable */ + *r++ = xid; + *r++ = htonl (REPLY); + *r++ = htonl (MSG_ACCEPTED); + *r++ = htonl (AUTH_NULL); + *r++ = htonl (0); + *r++ = htonl (PROC_UNAVAIL); + *r++ = htonl (table->min); + *r++ = htonl (table->max); + goto send_reply; + } + proc = &table->procs[procedure - table->min]; + + p = process_cred (p, &cred); /* auth */ + p = skip_cred (p); /* verf */ + + if (proc->need_handle) + p = lookup_cache_handle (p, &c, cred); + else + { + fakec.ids = cred; + c = &fakec; + } + + if (proc->alloc_reply) + { + size_t amt; + amt = (*proc->alloc_reply) (p) + 256; + if (amt > MAXIOSIZE) + { + free (rbuf); + r = (int *) rbuf = malloc (amt); + } + } + + /* Fill in beginning of reply */ + *r++ = xid; + *r++ = htonl (REPLY); + *r++ = htonl (MSG_ACCEPTED); + *r++ = htonl (AUTH_NULL); + *r++ = htonl (0); + *r++ = htonl (SUCCESS); + if (proc->process_error) + { + /* Assume success for now and patch it later if necessary */ + errloc = r; + *r++ = htonl (0); + } + + if (c) + err = (*proc->func) (c, p, &r); + else + err = ESTALE; + + if (proc->process_error && err) + { + r = errloc; + *r++ = htonl (nfs_error_trans (err)); + } + + cred_rele (cred); + if (c != &fakec) + cache_handle_rele (c); + + send_reply: + cr->data = rbuf; + cr->len = (char *)r - rbuf; + + repost_reply: + sendto (i, cr->data, cr->len, 0, + (struct sockaddr *)&sender, addrlen); + release_cached_reply (cr); + } + } +} diff --git a/nfsd/main.c b/nfsd/main.c new file mode 100644 index 00000000..69099361 --- /dev/null +++ b/nfsd/main.c @@ -0,0 +1,78 @@ +/* Main NFS server program + Copyright (C) 1996 Free Software Foundation, Inc. + Written by Michael I. Bushnell, p/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. */ + +#include "nfsd.h" +#include <stdio.h> +#include <unistd.h> +#include <rpc/pmap_prot.h> +#include <maptime.h> + +int main_udp_socket, pmap_udp_socket; +struct sockaddr_in main_address, pmap_address; +char *index_file_name; + +int +main (int argc, char **argv) +{ + int nthreads; + + if (argc > 2) + { + fprintf (stderr, "%s [num-threads]\n", argv[0]); + exit (1); + } + if (argc == 1) + nthreads = 4; + else + nthreads = atoi (argv[1]); + if (!nthreads) + nthreads = 4; + + index_file_name = asprintf ("%s/state/misc/nfsd.index", LOCALSTATEDIR); + + maptime_map (0, 0, &mapped_time); + + main_address.sin_family = AF_INET; + main_address.sin_port = htons (NFS_PORT); + main_address.sin_addr.s_addr = INADDR_ANY; + pmap_address.sin_family = AF_INET; + pmap_address.sin_port = htons (PMAPPORT); + pmap_address.sin_addr.s_addr = INADDR_ANY; + + main_udp_socket = socket (PF_INET, SOCK_DGRAM, 0); + pmap_udp_socket = socket (PF_INET, SOCK_DGRAM, 0); + bind (main_udp_socket, (struct sockaddr *)&main_address, + sizeof (struct sockaddr_in)); + bind (pmap_udp_socket, (struct sockaddr *)&pmap_address, + sizeof (struct sockaddr_in)); + + init_filesystems (); + + while (nthreads--) + cthread_detach (cthread_fork ((cthread_fn_t) server_loop, 0)); + + for (;;) + { + sleep (1); + scan_fhs (); + scan_creds (); + scan_replies (); + } +} diff --git a/nfsd/nfsd.h b/nfsd/nfsd.h new file mode 100644 index 00000000..7b6f530d --- /dev/null +++ b/nfsd/nfsd.h @@ -0,0 +1,128 @@ +/* + Copyright (C) 1996 Free Software Foundation, Inc. + Written by Michael I. Bushnell, p/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. */ + +typedef int bool_t; + +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> +#include <netinet/in.h> +#include <cthreads.h> +#include "../nfs/rpcsvc/nfs_prot.h" /* XXX */ +#include <hurd/fs.h> + +/* These should be configuration options */ +#define ID_KEEP_TIMEOUT 3600 /* one hour */ +#define FH_KEEP_TIMEOUT 600 /* ten minutes */ +#define REPLY_KEEP_TIMEOUT 120 /* two minutes */ +#define MAXIOSIZE 10240 + +struct idspec +{ + struct idspec *next, **prevp; + int nuids, ngids; + uid_t *uids, *gids; + time_t lastuse; + int references; +}; + +struct cache_handle +{ + struct cache_handle *next, **prevp; + char handle[NFS_FHSIZE]; + struct idspec *ids; + file_t port; + time_t lastuse; + int references; +}; + +struct cached_reply +{ + struct cached_reply *next, **prevp; + struct mutex lock; + struct sockaddr_in source; + int xid; + time_t lastuse; + int references; + size_t len; + char *data; +}; + +struct procedure +{ + error_t (*func) (struct cache_handle *, int *, int **); + size_t (*alloc_reply) (int *); + int need_handle; + int process_error; +}; + +struct proctable +{ + int min; + int max; + struct procedure procs[0]; +}; + +volatile struct mapped_time_value *mapped_time; + +#define INTSIZE(n) (((n) + 3) >> 2) + +/* We don't actually distinguish between these two sockets, but + we have to listen on two different ports, so that's why they're here. */ +extern int main_udp_socket, pmap_udp_socket; +extern struct sockaddr_in main_address, pmap_address; + +/* Name of the file on disk containing the filesystem index table */ +extern char *index_file_name; + + +/* cache.c */ +int *process_cred (int *, struct idspec **); +void cred_rele (struct idspec *); +void cred_ref (struct idspec *); +void scan_creds (void); +int *lookup_cache_handle (int *, struct cache_handle **, struct idspec *); +void cache_handle_rele (struct cache_handle *); +void scan_fhs (void); +struct cache_handle *create_cached_handle (int, struct cache_handle *, file_t); +struct cached_reply *check_cached_replies (int, struct sockaddr_in *); +void release_cached_reply (struct cached_reply *cr); +void scan_replies (void); + +/* loop.c */ +void server_loop (void); + +/* ops.c */ +extern struct proctable nfstable, mounttable, pmaptable; + +/* xdr.c */ +int *skip_cred (int *); +int nfs_error_trans (error_t); +int *encode_fattr (int *, struct stat *); +int *decode_name (int *, char **); +int *encode_fhandle (int *, char *); +int *encode_string (int *, char *); +int *encode_data (int *, char *, size_t); +int *encode_statfs (int *, struct statfs *); + +/* fsys.c */ +fsys_t lookup_filesystem (int); +int enter_filesystem (char *, file_t); +void init_filesystems (void); diff --git a/nfsd/ops.c b/nfsd/ops.c new file mode 100644 index 00000000..93c8373c --- /dev/null +++ b/nfsd/ops.c @@ -0,0 +1,652 @@ +/* NFS daemon protocol operations + Copyright (C) 1996 Free Software Foundation, Inc. + Written by Michael I. Bushnell, p/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. */ + +#include <hurd/io.h> +#include <hurd/fs.h> +#include <fcntl.h> +#include <hurd/paths.h> +#include <hurd.h> +#include <dirent.h> + +#include "nfsd.h" +#include "../nfs/rpcsvc/mount.h" /* XXX */ +#include <rpc/pmap_prot.h> + +static error_t +op_null (struct cache_handle *c, + int *p, + int **reply) +{ + return 0; +} + +static error_t +op_getattr (struct cache_handle *c, + int *p, + int **reply) +{ + struct stat st; + error_t err; + + err = io_stat (c->port, &st); + if (!err) + *reply = encode_fattr (*reply, &st); + return err; +} + +static error_t +complete_setattr (mach_port_t port, + int *p) +{ + uid_t uid, gid; + off_t size; + time_value_t atime, mtime; + struct stat st; + error_t err; + + err = io_stat (port, &st); + if (err) + return err; + + uid = ntohl (*p++); + gid = ntohl (*p++); + if ((uid != -1 && uid != st.st_uid) + || (gid != -1 && gid != st.st_gid)) + { + if (uid == -1) + uid = st.st_uid; + if (gid == -1) + gid = st.st_gid; + err = file_chown (port, uid, gid); + if (err) + return err; + } + + size = ntohl (*p++); + if (size != -1 && size != st.st_size) + err = file_set_size (port, size); + if (err) + return err; + + atime.seconds = ntohl (*p++); + atime.microseconds = ntohl (*p++); + mtime.seconds = ntohl (*p++); + mtime.microseconds = ntohl (*p++); + if (atime.seconds != -1 && atime.microseconds == -1) + atime.microseconds = 0; + if (mtime.seconds != -1 && mtime.microseconds == -1) + mtime.microseconds = 0; + if (atime.seconds != -1 || mtime.seconds != -1 + || atime.microseconds != -1 || mtime.microseconds != -1) + { + if (atime.seconds == -1) + atime.seconds = st.st_atime; + if (atime.microseconds == -1) + atime.microseconds = st.st_atime_usec; + if (mtime.seconds == -1) + mtime.seconds = st.st_mtime; + if (mtime.microseconds == -1) + mtime.microseconds = st.st_mtime_usec; + err = file_utimes (port, atime, mtime); + if (err) + return err; + } + + return 0; +} + +static error_t +op_setattr (struct cache_handle *c, + int *p, + int **reply) +{ + error_t err = 0; + mode_t mode; + + mode = ntohl (*p++); + if (mode != -1) + err = file_chmod (c->port, mode); + if (err) + return err; + + return complete_setattr (c->port, p); +} + +static error_t +op_lookup (struct cache_handle *c, + int *p, + int **reply) +{ + error_t err; + char *name; + retry_type do_retry; + char retry_name [1024]; + mach_port_t newport; + struct cache_handle *newc; + struct stat st; + + decode_name (p, &name); + + err = dir_lookup (c->port, name, O_NOTRANS, 0, &do_retry, retry_name, + &newport); + free (name); + + /* Block attempts to bounce out of this filesystem by any technique */ + if (!err + && (do_retry != FS_RETRY_NORMAL + || retry_name[0] != '\0')) + err = EACCES; + + if (!err) + err = io_stat (newport, &st); + + if (err) + return err; + + newc = create_cached_handle (*(int *)c->handle, c, newport); + if (!newc) + return ESTALE; + *reply = encode_fhandle (*reply, newc->handle); + *reply = encode_fattr (*reply, &st); + return 0; +} + +static error_t +op_readlink (struct cache_handle *c, + int *p, + int **reply) +{ + char buf[2048], *transp = buf; + mach_msg_type_number_t len = sizeof (buf); + error_t err; + + /* Shamelessly copied from the libc readlink */ + err = file_get_translator (c->port, &transp, &len); + if (err) + return err; + + if (len < sizeof (_HURD_SYMLINK) + || memcmp (transp, _HURD_SYMLINK, sizeof (_HURD_SYMLINK))) + return EINVAL; + + transp += sizeof (_HURD_SYMLINK); + + *reply = encode_string (*reply, transp); + return 0; +} + +static size_t +count_read_buffersize (int *p) +{ + return ntohl (*++p); /* skip OFFSET, return COUNT */ +} + +static error_t +op_read (struct cache_handle *c, + int *p, + int **reply) +{ + off_t offset; + size_t count; + char buf[2048], *bp = buf; + mach_msg_type_number_t buflen = sizeof (buf); + struct stat st; + error_t err; + + offset = ntohl (*p++); + count = ntohl (*p++); + + err = io_read (c->port, &bp, &buflen, offset, count); + if (err) + return err; + + err = io_stat (c->port, &st); + if (err) + return err; + + *reply = encode_fattr (*reply, &st); + *reply = encode_data (*reply, bp, buflen); + return 0; +} + +static error_t +op_write (struct cache_handle *c, + int *p, + int **reply) +{ + off_t offset; + size_t count; + error_t err; + mach_msg_type_number_t amt; + char *bp; + struct stat st; + + p++; + offset = ntohl (*p++); + p++; + count = ntohl (*p++); + bp = (char *) *reply; + + while (count) + { + err = io_write (c->port, bp, count, offset, &amt); + if (err) + return err; + if (amt == 0) + return EIO; + count -= amt; + bp += amt; + offset += amt; + } + + file_sync (c->port, 1, 0); + + err = io_stat (c->port, &st); + if (err) + return err; + *reply = encode_fattr (*reply, &st); + return 0; +} + +static error_t +op_create (struct cache_handle *c, + int *p, + int **reply) +{ + error_t err; + char *name; + retry_type do_retry; + char retry_name [1024]; + mach_port_t newport; + struct cache_handle *newc; + struct stat st; + mode_t mode; + + p = decode_name (p, &name); + mode = ntohl (*p++); + + err = dir_lookup (c->port, name, O_NOTRANS | O_CREAT | O_EXCL, mode, + &do_retry, retry_name, &newport); + if (!err + && (do_retry != FS_RETRY_NORMAL + || retry_name[0] != '\0')) + err = EACCES; + + if (err) + return err; + + err = complete_setattr (newport, p); + if (!err) + err = io_stat (newport, &st); + + if (err) + { + dir_unlink (c->port, name); + free (name); + return err; + } + free (name); + + newc = create_cached_handle (*(int *)c->handle, c, newport); + if (!newc) + return ESTALE; + + *reply = encode_fhandle (*reply, newc->handle); + *reply = encode_fattr (*reply, &st); + return 0; +} + +static error_t +op_remove (struct cache_handle *c, + int *p, + int **reply) +{ + error_t err; + char *name; + + decode_name (p, &name); + + err = dir_unlink (c->port, name); + free (name); + + return 0; +} + +static error_t +op_rename (struct cache_handle *fromc, + int *p, + int **reply) +{ + struct cache_handle *toc; + char *fromname, *toname; + error_t err = 0; + + p = decode_name (p, &fromname); + p = lookup_cache_handle (p, &toc, fromc->ids); + decode_name (p, &toname); + + if (!toc) + err = ESTALE; + if (!err) + err = dir_rename (fromc->port, fromname, toc->port, toname, 0); + free (fromname); + free (toname); + return err; +} + +static error_t +op_link (struct cache_handle *filec, + int *p, + int **reply) +{ + struct cache_handle *dirc; + char *name; + error_t err = 0; + + p = lookup_cache_handle (p, &dirc, filec->ids); + decode_name (p, &name); + + if (!dirc) + err = ESTALE; + if (!err) + err = dir_link (dirc->port, filec->port, name, 1); + + free (name); + return err; +} + +static error_t +op_symlink (struct cache_handle *c, + int *p, + int **reply) +{ + char *name, *target; + error_t err; + mode_t mode; + file_t newport = MACH_PORT_NULL; + size_t len; + char *buf; + + p = decode_name (p, &name); + p = decode_name (p, &target); + mode = ntohl (*p++); + if (mode == -1) + mode = 0777; + + len = strlen (target) + 1; + buf = alloca (sizeof (_HURD_SYMLINK) + len); + memcpy (buf, _HURD_SYMLINK, sizeof (_HURD_SYMLINK)); + memcpy (buf + sizeof (_HURD_SYMLINK), target, len); + + err = dir_mkfile (c->port, O_WRITE, mode, &newport); + if (!err) + err = file_set_translator (newport, + FS_TRANS_EXCL|FS_TRANS_SET, + FS_TRANS_EXCL|FS_TRANS_SET, 0, + buf, sizeof (_HURD_SYMLINK) + len, + MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND); + if (!err) + err = dir_link (c->port, newport, name, 1); + + free (name); + free (target); + + if (newport != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), newport); + return err; +} + +static error_t +op_mkdir (struct cache_handle *c, + int *p, + int **reply) +{ + char *name; + mode_t mode; + retry_type do_retry; + char retry_name [1024]; + mach_port_t newport; + struct stat st; + struct cache_handle *newc; + error_t err; + + p = decode_name (p, &name); + mode = ntohl (*p++); + + err = dir_mkdir (c->port, name, mode); + + if (err) + { + free (name); + return err; + } + + err = dir_lookup (c->port, name, O_NOTRANS, 0, &do_retry, + retry_name, &newport); + free (name); + if (!err + && (do_retry != FS_RETRY_NORMAL + || retry_name[0] != '\0')) + err = EACCES; + if (err) + return err; + + err = complete_setattr (newport, p); + if (!err) + err = io_stat (newport, &st); + if (err) + return err; + + newc = create_cached_handle (*(int *)c->handle, c, newport); + if (!newc) + return ESTALE; + *reply = encode_fhandle (*reply, newc->handle); + *reply = encode_fattr (*reply, &st); + return 0; +} + +static error_t +op_rmdir (struct cache_handle *c, + int *p, + int **reply) +{ + char *name; + error_t err; + + decode_name (p, &name); + + err = dir_rmdir (c->port, name); + free (name); + return err; +} + +static error_t +op_readdir (struct cache_handle *c, + int *p, + int **reply) +{ + int cookie; + unsigned count; + error_t err; + char *buf; + struct dirent *dp; + size_t bufsize; + int nentries; + int i; + int *replystart; + + cookie = ntohl (*p++); + count = ntohl (*p++); + + buf = alloca (count); + bufsize = count; + err = dir_readdir (c->port, &buf, &bufsize, cookie, -1, count, &nentries); + if (err) + return err; + + if (nentries == 0) + { + *(*reply)++ = htonl (0); /* no entry */ + *(*reply)++ = htonl (1); /* EOF */ + } + else + { + for (i = 0, dp = (struct dirent *) buf, replystart = *reply; + ((char *)dp < buf + bufsize + && i < nentries + && (char *)reply < (char *)replystart + count); + i++, dp = (struct dirent *) ((char *)dp + dp->d_reclen)) + { + *(*reply)++ = htonl (1); /* entry present */ + *(*reply)++ = htonl (dp->d_ino); + *reply = encode_string (*reply, dp->d_name); + *(*reply)++ = htonl (i + cookie + 1); /* next entry */ + } + *(*reply)++ = htonl (0); /* not EOF */ + } + + return 0; +} + +static size_t +count_readdir_buffersize (int *p) +{ + return ntohl (*++p); /* skip COOKIE; return COUNT */ +} + +static error_t +op_statfs (struct cache_handle *c, + int *p, + int **reply) +{ + struct statfs st; + error_t err; + + err = file_statfs (c->port, &st); + if (!err) + *reply = encode_statfs (*reply, &st); + return err; +} + +static error_t +op_mnt (struct cache_handle *c, + int *p, + int **reply) +{ + file_t root; + struct cache_handle *newc; + char *name; + + decode_name (p, &name); + + root = file_name_lookup (name, 0, 0); + if (!root) + { + free (name); + return errno; + } + + newc = create_cached_handle (enter_filesystem (name, root), c, root); + free (name); + if (!newc) + return ESTALE; + *reply = encode_fhandle (*reply, newc->handle); + return 0; +} + +static error_t +op_getport (struct cache_handle *c, + int *p, + int **reply) +{ + int prog, vers, prot; + + prog = ntohl (*p++); + vers = ntohl (*p++); + prot = ntohl (*p++); + + if (prot != IPPROTO_UDP) + *(*reply)++ = htonl (0); + else if ((prog == MOUNTPROG && vers == MOUNTVERS) + || (prog == NFS_PROGRAM && vers == NFS_VERSION)) + *(*reply)++ = htonl (NFS_PORT); + else if (prog == PMAPPROG && vers == PMAPVERS) + *(*reply)++ = htonl (PMAPPORT); + else + *(*reply)++ = 0; + + return 0; +} + + +struct proctable nfstable = +{ + NFSPROC_NULL, /* first proc */ + NFSPROC_STATFS, /* last proc */ + { + { op_null, 0, 0, 0}, + { op_getattr, 0, 1, 1}, + { op_setattr, 0, 1, 1}, + { 0, 0, 0, 0 }, /* deprecated NFSPROC_ROOT */ + { op_lookup, 0, 1, 1}, + { op_readlink, 0, 1, 1}, + { op_read, count_read_buffersize, 1, 1}, + { 0, 0, 0, 0 }, /* nonexistent NFSPROC_WRITECACHE */ + { op_write, 0, 1, 1}, + { op_create, 0, 1, 1}, + { op_remove, 0, 1, 1}, + { op_rename, 0, 1, 1}, + { op_link, 0, 1, 1}, + { op_symlink, 0, 1, 1}, + { op_mkdir, 0, 1, 1}, + { op_rmdir, 0, 1, 1}, + { op_readdir, count_readdir_buffersize, 1, 1}, + { op_statfs, 0, 1, 1}, + } +}; + + +struct proctable mounttable = +{ + MOUNTPROC_NULL, /* first proc */ + MOUNTPROC_EXPORT, /* last proc */ + { + { op_null, 0, 0, 0}, + { op_mnt, 0, 0, 1}, + { 0, 0, 0, 0}, /* MOUNTPROC_DUMP */ + { 0, 0, 0, 0}, /* MOUNTPROC_UMNT */ + { 0, 0, 0, 0}, /* MOUNTPROC_UMNTALL */ + { 0, 0, 0, 0}, /* MOUNTPROC_EXPORT */ + } +}; + +struct proctable pmaptable = +{ + PMAPPROC_NULL, /* first proc */ + PMAPPROC_CALLIT, /* last proc */ + { + { op_null, 0, 0, 0}, + { 0, 0, 0, 0}, /* PMAPPROC_SET */ + { 0, 0, 0, 0}, /* PMAPPROC_UNSET */ + { op_getport, 0, 0, 0}, + { 0, 0, 0, 0}, /* PMAPPROC_DUMP */ + { 0, 0, 0, 0}, /* PMAPPROC_CALLIT */ + } +}; diff --git a/nfsd/proctables.c b/nfsd/proctables.c new file mode 100644 index 00000000..1bc76a38 --- /dev/null +++ b/nfsd/proctables.c @@ -0,0 +1,57 @@ +/* + Copyright (C) 1996 Free Software Foundation, Inc. + Written by Michael I. Bushnell, p/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. */ + + +struct proctable nfstable = +{ + NFSPROC_NULL, /* first proc */ + NFSPROC_STATFS, /* last proc */ + { op_null, 0, 0}, + { op_getattr, 0, 1}, + { op_setattr, 0, 1}, + { 0, 0, 0 }, /* deprecated NFSPROC_ROOT */ + { op_lookup, 0, 1}, + { op_readlink, 0, 1}, + { op_read, count_read_buffersize, 1}, + { 0, 0, 0 }, /* nonexistent NFSPROC_WRITECACHE */ + { op_write, 0, 1}, + { op_create, 0, 1}, + { op_remove, 0, 1}, + { op_rename, 0, 1}, + { op_link, 0, 1}, + { op_symlink, 0, 1}, + { op_mkdir, 0, 1}, + { op_rmdir, 0, 1}, + { op_readdir, count_readdir_buffersize, 1}, + { op_statfs, 0, 1}, +}; + + +struct proctable mounttable = +{ + MOUNTPROC_NULL, /* first proc */ + MOUNTPROC_EXPORT, /* last proc */ + { op_null, 0, 0}, + { op_mnt, 0, 0}, + { 0, 0, 0}, /* MOUNTPROC_DUMP */ + { 0, 0, 0}, /* MOUNTPROC_UMNT */ + { 0, 0, 0}, /* MOUNTPROC_UMNTALL */ + { 0, 0, 0}, /* MOUNTPROC_EXPORT */ +}; diff --git a/nfsd/xdr.c b/nfsd/xdr.c new file mode 100644 index 00000000..d5bea0bd --- /dev/null +++ b/nfsd/xdr.c @@ -0,0 +1,204 @@ +/* XDR packing and unpacking in nfsd + Copyright (C) 1996 Free Software Foundation, Inc. + Written by Michael I. Bushnell, p/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. */ + +#include <sys/stat.h> +#include <sys/statfs.h> +#include <string.h> +#include "nfsd.h" + +/* Return the address of the next thing after the credential at P. */ +int * +skip_cred (int *p) +{ + int size; + + p++; /* TYPE */ + size = ntohl (*p++); + return p + INTSIZE (size); +} + +/* Any better ideas? */ +static int +hurd_mode_to_nfs_mode (mode_t m) +{ + return m & 0x177777; +} + +static int +hurd_mode_to_nfs_type (mode_t m) +{ + switch (m & S_IFMT) + { + case S_IFDIR: + return NFDIR; + + case S_IFCHR: + return NFCHR; + + case S_IFBLK: + return NFBLK; + + case S_IFREG: + return NFREG; + + case S_IFLNK: + return NFLNK; + + case S_IFSOCK: + return NFSOCK; + + case S_IFIFO: + return NFFIFO; + + default: + return NFNON; + } +} + +/* Encode ST into P and return the next thing to come after it. */ +int * +encode_fattr (int *p, struct stat *st) +{ + *p++ = htonl (hurd_mode_to_nfs_type (st->st_mode)); + *p++ = htonl (hurd_mode_to_nfs_mode (st->st_mode)); + *p++ = htonl (st->st_nlink); + *p++ = htonl (st->st_uid); + *p++ = htonl (st->st_gid); + *p++ = htonl (st->st_size); + *p++ = htonl (st->st_blksize); + *p++ = htonl (st->st_rdev); + *p++ = htonl (st->st_blocks); + return p; +} + +/* Decode P into NAME and return the next thing to come after it. */ +int * +decode_name (int *p, char **name) +{ + int len; + + len = ntohl (*p++); + *name = malloc (len + 1); + bcopy (p, *name, len); + (*name)[len] = '\0'; + return p + INTSIZE (len); +} + +/* Encode HANDLE into P and return the next thing to come after it. */ +int * +encode_fhandle (int *p, char *handle) +{ + bcopy (handle, p, NFS_FHSIZE); + return p + INTSIZE (NFS_FHSIZE); +} + +/* Encode STRING into P and return the next thing to come after it. */ +int * +encode_string (int *p, char *string) +{ + return encode_data (p, string, strlen (string)); +} + +/* Encode DATA into P and return the next thing to come after it. */ +int * +encode_data (int *p, char *data, size_t len) +{ + int nints = INTSIZE (len); + + p[nints] = 0; + *p++ = htonl (len); + bcopy (data, p, len); + return p + nints; +} + +/* Encode ST into P and return the next thing to come after it. */ +int * +encode_statfs (int *p, struct statfs *st) +{ + *p++ = st->f_bsize; + *p++ = st->f_bsize; + *p++ = st->f_blocks; + *p++ = st->f_bfree; + *p++ = st->f_bavail; + return p; +} + +/* Return an NFS error corresponding to Hurd error ERR. */ +int +nfs_error_trans (error_t err) +{ + switch (err) + { + case 0: + return NFS_OK; + + case EPERM: + return NFSERR_PERM; + + case ENOENT: + return NFSERR_NOENT; + + case EIO: + default: + return NFSERR_IO; + + case ENXIO: + return NFSERR_NXIO; + + case EACCES: + return NFSERR_ACCES; + + case EEXIST: + return NFSERR_EXIST; + + case ENODEV: + return NFSERR_NODEV; + + case ENOTDIR: + return NFSERR_NOTDIR; + + case EISDIR: + return NFSERR_ISDIR; + + case E2BIG: + return NFSERR_FBIG; + + case ENOSPC: + return NFSERR_NOSPC; + + case EROFS: + return NFSERR_ROFS; + + case ENAMETOOLONG: + return NFSERR_NAMETOOLONG; + + case ENOTEMPTY: + return NFSERR_NOTEMPTY; + + case EDQUOT: + return NFSERR_DQUOT; + + case ESTALE: + return NFSERR_STALE; + } +} + + + |