From 206c88c0f82d1ced4780fcdabde8520ddb872951 Mon Sep 17 00:00:00 2001 From: Guillaume Cottenceau Date: Sat, 18 Oct 2003 22:34:11 +0000 Subject: use nfsmount code from util-linux-2.11z so that we're using nfsmount v3 with 2.4 kernel (not mandatory, but thought it was the origin of the cloop-over-nfs problem - which is not) --- mdk-stage1/nfs_mount4.h | 54 ++++ mdk-stage1/nfsmount.c | 797 ++++++++++++++++++++++++++++++++++++++++-------- mdk-stage1/nfsmount.h | 311 +++++++++---------- 3 files changed, 887 insertions(+), 275 deletions(-) create mode 100644 mdk-stage1/nfs_mount4.h diff --git a/mdk-stage1/nfs_mount4.h b/mdk-stage1/nfs_mount4.h new file mode 100644 index 000000000..85650773a --- /dev/null +++ b/mdk-stage1/nfs_mount4.h @@ -0,0 +1,54 @@ +/* + * We want to be able to compile mount on old kernels in such a way + * that the binary will work well on more recent kernels. + * Thus, if necessary we teach nfsmount.c the structure of new fields + * that will come later. + * + * Moreover, the new kernel includes conflict with glibc includes + * so it is easiest to ignore the kernel altogether (at compile time). + */ + +#define NFS_MOUNT_VERSION 4 + +struct nfs2_fh { + char data[32]; +}; +struct nfs3_fh { + unsigned short size; + unsigned char data[64]; +}; + +struct nfs_mount_data { + int version; /* 1 */ + int fd; /* 1 */ + struct nfs2_fh old_root; /* 1 */ + int flags; /* 1 */ + int rsize; /* 1 */ + int wsize; /* 1 */ + int timeo; /* 1 */ + int retrans; /* 1 */ + int acregmin; /* 1 */ + int acregmax; /* 1 */ + int acdirmin; /* 1 */ + int acdirmax; /* 1 */ + struct sockaddr_in addr; /* 1 */ + char hostname[256]; /* 1 */ + int namlen; /* 2 */ + unsigned int bsize; /* 3 */ + struct nfs3_fh root; /* 4 */ +}; + +/* bits in the flags field */ + +#define NFS_MOUNT_SOFT 0x0001 /* 1 */ +#define NFS_MOUNT_INTR 0x0002 /* 1 */ +#define NFS_MOUNT_SECURE 0x0004 /* 1 */ +#define NFS_MOUNT_POSIX 0x0008 /* 1 */ +#define NFS_MOUNT_NOCTO 0x0010 /* 1 */ +#define NFS_MOUNT_NOAC 0x0020 /* 1 */ +#define NFS_MOUNT_TCP 0x0040 /* 2 */ +#define NFS_MOUNT_VER3 0x0080 /* 3 */ +#define NFS_MOUNT_KERBEROS 0x0100 /* 3 */ +#define NFS_MOUNT_NONLM 0x0200 /* 3 */ +#define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */ + diff --git a/mdk-stage1/nfsmount.c b/mdk-stage1/nfsmount.c index 032fde60c..b5aa44606 100644 --- a/mdk-stage1/nfsmount.c +++ b/mdk-stage1/nfsmount.c @@ -1,27 +1,3 @@ -/* - * Guillaume Cottenceau (gc@mandrakesoft.com) - * - * Copyright 2000 MandrakeSoft - * - * This software may be freely redistributed under the terms of the GNU - * public license. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -/* this is based on work from redhat, made it lighter (gc) - */ - - -/* MODIFIED for Red Hat Linux installer - * msw@redhat.com - * o always mounts without lockd - * o uses our own host resolution - */ - /* * nfsmount.c -- Linux NFS mount * Copyright (C) 1993 Rick Sladkey @@ -44,18 +20,30 @@ * * Wed Oct 1 23:55:28 1997: Dick Streefland * Implemented the "bg", "fg" and "retry" mount options for NFS. + * + * 1999-02-22 Arkadiusz Mi¶kiewicz + * - added Native Language Support + * + * Modified by Olaf Kirch and Trond Myklebust for new NFS code, + * plus NFSv3 stuff. + * + * 2003-04-14 David Black + * - added support for multiple hostname NFS mounts */ /* * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp */ +#define HAVE_rpcsvc_nfs_prot_h +#define HAVE_inet_aton + #include #include #include #include #include -#include +#include #include #include #include @@ -63,102 +51,304 @@ #include #include #include +#include #include -#include "linux-2.2/nfs.h" -#include "linux-2.2/nfs_mount.h" //#include "mount_constants.h" +#include + +#include "nfsmount.h" + +#ifdef HAVE_rpcsvc_nfs_prot_h +#include +#else +#include +#define nfsstat nfs_stat +#endif + +#include "nfs_mount4.h" #include "log.h" #include "dns.h" -#include "nfsmount.h" +#ifndef NFS_PORT +#define NFS_PORT 2049 +#endif +#ifndef NFS_FHSIZE +#define NFS_FHSIZE 32 +#endif +static char *nfs_strerror(int stat); + +#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r)) + +#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2) + +bool_t +xdr_fhandle3 (XDR *xdrs, fhandle3 *objp) +{ + if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3)) + return FALSE; + return TRUE; +} bool_t -xdr_fhandle(XDR *xdrs, fhandle objp) +xdr_mountstat3 (XDR *xdrs, mountstat3 *objp) { - if (!xdr_opaque(xdrs, objp, FHSIZE)) { - return (FALSE); - } - return (TRUE); + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; } bool_t -xdr_fhstatus(XDR *xdrs, fhstatus *objp) +xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp) { + if (!xdr_fhandle3 (xdrs, &objp->fhandle)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->auth_flavours.auth_flavours_len, ~0, + sizeof (int), (xdrproc_t) xdr_int)) + return FALSE; + return TRUE; +} - if (!xdr_u_int(xdrs, &objp->fhs_status)) { - return (FALSE); - } +bool_t +xdr_mountres3 (XDR *xdrs, mountres3 *objp) +{ + if (!xdr_mountstat3 (xdrs, &objp->fhs_status)) + return FALSE; switch (objp->fhs_status) { - case 0: - if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle)) { - return (FALSE); - } + case MNT_OK: + if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo)) + return FALSE; break; default: break; } - return (TRUE); + return TRUE; +} + +bool_t +xdr_dirpath (XDR *xdrs, dirpath *objp) +{ + if (!xdr_string (xdrs, objp, MNTPATHLEN)) + return FALSE; + return TRUE; +} + +bool_t +xdr_fhandle (XDR *xdrs, fhandle objp) +{ + if (!xdr_opaque (xdrs, objp, FHSIZE)) + return FALSE; + return TRUE; } bool_t -xdr_dirpath(XDR *xdrs, dirpath *objp) +xdr_fhstatus (XDR *xdrs, fhstatus *objp) { + if (!xdr_u_int (xdrs, &objp->fhs_status)) + return FALSE; + switch (objp->fhs_status) { + case 0: + if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + + +static int +linux_version_code(void) { + struct utsname my_utsname; + int p, q, r; + + if (uname(&my_utsname) == 0) { + p = atoi(strtok(my_utsname.release, ".")); + q = atoi(strtok(NULL, ".")); + r = atoi(strtok(NULL, ".")); + return MAKE_VERSION(p,q,r); + } + return 0; +} - if (!xdr_string(xdrs, objp, MNTPATHLEN)) { - return (FALSE); - } - return (TRUE); +/* + * Unfortunately, the kernel prints annoying console messages + * in case of an unexpected nfs mount version (instead of + * just returning some error). Therefore we'll have to try + * and figure out what version the kernel expects. + * + * Variables: + * NFS_MOUNT_VERSION: these nfsmount sources at compile time + * nfs_mount_version: version this source and running kernel can handle + */ +static int +find_kernel_nfs_mount_version(void) { + static int kernel_version = -1; + int nfs_mount_version = NFS_MOUNT_VERSION; + + if (kernel_version == -1) + kernel_version = linux_version_code(); + + if (kernel_version) { + if (kernel_version < MAKE_VERSION(2,1,32)) + nfs_mount_version = 1; + else if (kernel_version < MAKE_VERSION(2,2,18)) + nfs_mount_version = 3; + else if (kernel_version < MAKE_VERSION(2,3,0)) + nfs_mount_version = 4; /* since 2.2.18pre9 */ + else if (kernel_version < MAKE_VERSION(2,3,99)) + nfs_mount_version = 3; + else + nfs_mount_version = 4; /* since 2.3.99pre4 */ + } + if (nfs_mount_version > NFS_MOUNT_VERSION) + nfs_mount_version = NFS_MOUNT_VERSION; + log_message("nfsmount: kernel_nfs_mount_version : %d", nfs_mount_version); + return nfs_mount_version; } +static struct pmap * +get_mountport(struct sockaddr_in *server_addr, + long unsigned prog, + long unsigned version, + long unsigned proto, + long unsigned port, + int nfs_mount_version) +{ + struct pmaplist *pmap; + static struct pmap p = {0, 0, 0, 0}; + + if (version > MAX_NFSPROT) + version = MAX_NFSPROT; + if (!prog) + prog = MOUNTPROG; + p.pm_prog = prog; + p.pm_vers = version; + p.pm_prot = proto; + p.pm_port = port; + + server_addr->sin_port = PMAPPORT; + pmap = pmap_getmaps(server_addr); + + while (pmap) { + if (pmap->pml_map.pm_prog != prog) + goto next; + if (!version && p.pm_vers > pmap->pml_map.pm_vers) + goto next; + if (version > 2 && pmap->pml_map.pm_vers != version) + goto next; + if (version && version <= 2 && pmap->pml_map.pm_vers > 2) + goto next; + if (pmap->pml_map.pm_vers > MAX_NFSPROT || + (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) || + (port && pmap->pml_map.pm_port != port)) + goto next; + memcpy(&p, &pmap->pml_map, sizeof(p)); + next: + pmap = pmap->pml_next; + } + if (!p.pm_vers) + p.pm_vers = MOUNTVERS; + if (!p.pm_prot) + p.pm_prot = IPPROTO_TCP; +#if 0 + if (!p.pm_port) { + p.pm_port = pmap_getport(server_addr, p.pm_prog, p.pm_vers, + p.pm_prot); + } +#endif +#if 0 +#define MOUNTPORT 635 + /* HJLu wants to remove all traces of the old default port. + Are there still people running a mount RPC service on this + port without having a portmapper? */ + if (!p.pm_port) + p.pm_port = MOUNTPORT; +#endif + return &p; +} -static int nfs_mount_version = 3; /* kernel >= 2.1.32 */ /* *********** TODO for kernel 2.4, nfs-mount version 4 */ -int nfsmount_prepare(const char *spec, int *flags, char **mount_opts) +int nfsmount_prepare(const char *spec, char **mount_opts) { + int running_bg = 0; char hostdir[1024]; CLIENT *mclient; - char *hostname, *dirname; - fhandle root_fhandle; + char *hostname, *dirname, *old_opts, *mounthost = NULL; + char new_opts[1024]; struct timeval total_timeout; enum clnt_stat clnt_stat; static struct nfs_mount_data data; + char *opt, *opteq; + int nfs_mount_version; + int val; struct sockaddr_in server_addr; struct sockaddr_in mount_server_addr; + struct pmap *pm_mnt; int msock, fsock; struct timeval retry_timeout; - struct fhstatus status; + union { + struct fhstatus nfsv2; + struct mountres3 nfsv3; + } status; char *s; - int port; - + int port, mountport, proto, bg, soft, intr; + int posix, nocto, noac, broken_suid, nolock; + int retry, tcp; + int mountprog, mountvers, nfsprog, nfsvers; + int retval; + time_t t; + time_t prevt; + time_t timeout; + + nfs_mount_version = find_kernel_nfs_mount_version(); + + retval = -1; msock = fsock = -1; mclient = NULL; - - strncpy(hostdir, spec, sizeof(hostdir)); - if ((s = (strchr(hostdir, ':')))) { + if (strlen(spec) >= sizeof(hostdir)) { + log_message("nfsmount: excessively long host:dir argument"); + goto fail; + } + strcpy(hostdir, spec); + if ((s = strchr(hostdir, ':'))) { hostname = hostdir; dirname = s + 1; *s = '\0'; } else { - log_message("nfsmount: format not host:dir"); + log_message("nfsmount: directory to mount not in host:dir format"); goto fail; } server_addr.sin_family = AF_INET; - - /* first, try as IP address */ - if (!inet_aton(hostname, &server_addr.sin_addr)) { - /* failure, try as machine name */ - if (mygethostbyname(hostname, &server_addr.sin_addr)) +#ifdef HAVE_inet_aton + if (!inet_aton(hostname, &server_addr.sin_addr)) +#endif + { + if (mygethostbyname(hostname, &server_addr.sin_addr)) { + log_message("nfsmount: can't get address for %s", hostname); goto fail; + } } memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr)); + /* add IP address to mtab options for use when unmounting */ + s = inet_ntoa(server_addr.sin_addr); + old_opts = ""; + if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) { + log_message("nfsmount: excessively long option argument"); + goto fail; + } + sprintf(new_opts, "%s%saddr=%s", + old_opts, *old_opts ? "," : "", s); /* Set default options. + * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to + * let the kernel decide. * timeo is filled in after we know whether it'll be TCP or UDP. */ memset(&data, 0, sizeof(data)); data.retrans = 3; @@ -166,83 +356,362 @@ int nfsmount_prepare(const char *spec, int *flags, char **mount_opts) data.acregmax = 60; data.acdirmin = 30; data.acdirmax = 60; - data.rsize = 8192; - data.wsize = 8192; - data.bsize = 8192; #if NFS_MOUNT_VERSION >= 2 data.namlen = NAME_MAX; #endif + bg = 0; + soft = 1; + intr = 0; + posix = 0; + nocto = 0; + nolock = 1; + broken_suid = 0; + noac = 0; + retry = 10000; /* 10000 minutes ~ 1 week */ + tcp = 0; + + mountprog = MOUNTPROG; + mountvers = 0; + port = 0; + mountport = 0; + nfsprog = NFS_PROGRAM; + nfsvers = 0; + + /* parse options */ + + for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) { + if ((opteq = strchr(opt, '='))) { + val = atoi(opteq + 1); + *opteq = '\0'; + if (!strcmp(opt, "rsize")) + data.rsize = val; + else if (!strcmp(opt, "wsize")) + data.wsize = val; + else if (!strcmp(opt, "timeo")) + data.timeo = val; + else if (!strcmp(opt, "retrans")) + data.retrans = val; + else if (!strcmp(opt, "acregmin")) + data.acregmin = val; + else if (!strcmp(opt, "acregmax")) + data.acregmax = val; + else if (!strcmp(opt, "acdirmin")) + data.acdirmin = val; + else if (!strcmp(opt, "acdirmax")) + data.acdirmax = val; + else if (!strcmp(opt, "actimeo")) { + data.acregmin = val; + data.acregmax = val; + data.acdirmin = val; + data.acdirmax = val; + } + else if (!strcmp(opt, "retry")) + retry = val; + else if (!strcmp(opt, "port")) + port = val; + else if (!strcmp(opt, "mountport")) + mountport = val; + else if (!strcmp(opt, "mountprog")) + mountprog = val; + else if (!strcmp(opt, "mountvers")) + mountvers = val; + else if (!strcmp(opt, "nfsprog")) + nfsprog = val; + else if (!strcmp(opt, "nfsvers") || + !strcmp(opt, "vers")) + nfsvers = val; + else if (!strcmp(opt, "proto")) { + if (!strncmp(opteq+1, "tcp", 3)) + tcp = 1; + else if (!strncmp(opteq+1, "udp", 3)) + tcp = 0; + else + log_message("Warning: Unrecognized proto= option."); + } else if (!strcmp(opt, "namlen")) { +#if NFS_MOUNT_VERSION >= 2 + if (nfs_mount_version >= 2) + data.namlen = val; + else +#endif + log_message("Warning: Option namlen is not supported."); + } else if (!strcmp(opt, "addr")) { + /* ignore */; + } else { + log_message("unknown nfs mount parameter: %s=%d", opt, val); + goto fail; + } + } else { + val = 1; + if (!strncmp(opt, "no", 2)) { + val = 0; + opt += 2; + } + if (!strcmp(opt, "bg")) + bg = val; + else if (!strcmp(opt, "fg")) + bg = !val; + else if (!strcmp(opt, "soft")) + soft = val; + else if (!strcmp(opt, "hard")) + soft = !val; + else if (!strcmp(opt, "intr")) + intr = val; + else if (!strcmp(opt, "posix")) + posix = val; + else if (!strcmp(opt, "cto")) + nocto = !val; + else if (!strcmp(opt, "ac")) + noac = !val; + else if (!strcmp(opt, "tcp")) + tcp = val; + else if (!strcmp(opt, "udp")) + tcp = !val; + else if (!strcmp(opt, "lock")) { + if (nfs_mount_version >= 3) + nolock = !val; + else + log_message("Warning: option nolock is not supported."); + } else if (!strcmp(opt, "broken_suid")) { + broken_suid = val; + } else { + log_message("unknown nfs mount option: %s%s", val ? "" : "no", opt); + goto fail; + } + } + } + +retry_mount: + proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP; + + data.flags = (soft ? NFS_MOUNT_SOFT : 0) + | (intr ? NFS_MOUNT_INTR : 0) + | (posix ? NFS_MOUNT_POSIX : 0) + | (nocto ? NFS_MOUNT_NOCTO : 0) + | (noac ? NFS_MOUNT_NOAC : 0); +#if NFS_MOUNT_VERSION >= 2 + if (nfs_mount_version >= 2) + data.flags |= (tcp ? NFS_MOUNT_TCP : 0); +#endif #if NFS_MOUNT_VERSION >= 3 if (nfs_mount_version >= 3) - data.flags |= NFS_MOUNT_NONLM; /* HACK HACK msw */ + data.flags |= (nolock ? NFS_MOUNT_NONLM : 0); +#endif +#if NFS_MOUNT_VERSION >= 4 + if (nfs_mount_version >= 4) + data.flags |= (broken_suid ? NFS_MOUNT_BROKEN_SUID : 0); #endif + if (nfsvers > MAX_NFSPROT) { + log_message("NFSv%d not supported!", nfsvers); + return 0; + } + if (mountvers > MAX_NFSPROT) { + log_message("NFSv%d not supported!", nfsvers); + return 0; + } + if (nfsvers && !mountvers) + mountvers = (nfsvers < 3) ? 1 : nfsvers; + if (nfsvers && nfsvers < mountvers) + mountvers = nfsvers; /* Adjust options if none specified */ if (!data.timeo) - data.timeo = 7; /* udp */ + data.timeo = tcp ? 70 : 7; +#ifdef NFS_MOUNT_DEBUG + log_message("rsize = %d, wsize = %d, timeo = %d, retrans = %d", + data.rsize, data.wsize, data.timeo, data.retrans); + log_message("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)", + data.acregmin, data.acregmax, data.acdirmin, data.acdirmax); + log_message("port = %d, bg = %d, retry = %d, flags = %.8x", + port, bg, retry, data.flags); + log_message("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d", + mountprog, mountvers, nfsprog, nfsvers); + log_message("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d", + (data.flags & NFS_MOUNT_SOFT) != 0, + (data.flags & NFS_MOUNT_INTR) != 0, + (data.flags & NFS_MOUNT_POSIX) != 0, + (data.flags & NFS_MOUNT_NOCTO) != 0, + (data.flags & NFS_MOUNT_NOAC) != 0); +#if NFS_MOUNT_VERSION >= 2 + log_message("tcp = %d", + (data.flags & NFS_MOUNT_TCP) != 0); +#endif +#endif data.version = nfs_mount_version; *mount_opts = (char *) &data; - if (*flags & MS_REMOUNT) - return 0; + /* create mount deamon client */ + /* See if the nfs host = mount host. */ + if (mounthost) { + if (mounthost[0] >= '0' && mounthost[0] <= '9') { + mount_server_addr.sin_family = AF_INET; + mount_server_addr.sin_addr.s_addr = inet_addr(hostname); + } else { + if (mygethostbyname(mounthost, &mount_server_addr.sin_addr)) { + log_message("nfsmount: can't get address for %s", mounthost); + goto fail; + } + } + } + /* + * The following loop implements the mount retries. On the first + * call, "running_bg" is 0. When the mount times out, and the + * "bg" option is set, the exit status EX_BG will be returned. + * For a backgrounded mount, there will be a second call by the + * child process with "running_bg" set to 1. + * + * The case where the mount point is not present and the "bg" + * option is set, is treated as a timeout. This is done to + * support nested mounts. + * + * The "retry" count specified by the user is the number of + * minutes to retry before giving up. + * + * Only the first error message will be displayed. + */ retry_timeout.tv_sec = 3; retry_timeout.tv_usec = 0; total_timeout.tv_sec = 20; total_timeout.tv_usec = 0; + timeout = time(NULL) + 60 * retry; + prevt = 0; + t = 30; + val = 1; + + + /* be careful not to use too many CPU cycles */ + if (t - prevt < 30) + sleep(30); + + pm_mnt = get_mountport(&mount_server_addr, + mountprog, + mountvers, + proto, + mountport, + nfs_mount_version); + + /* contact the mount daemon via TCP */ + mount_server_addr.sin_port = htons(pm_mnt->pm_port); + msock = RPC_ANYSOCK; + + switch (pm_mnt->pm_prot) { + case IPPROTO_UDP: + mclient = clntudp_create(&mount_server_addr, + pm_mnt->pm_prog, + pm_mnt->pm_vers, + retry_timeout, + &msock); + if (mclient) + break; + mount_server_addr.sin_port = + htons(pm_mnt->pm_port); + msock = RPC_ANYSOCK; + case IPPROTO_TCP: + mclient = clnttcp_create(&mount_server_addr, + pm_mnt->pm_prog, + pm_mnt->pm_vers, + &msock, 0, 0); + break; + default: + mclient = 0; + } - - /* contact the mount daemon via TCP */ - mount_server_addr.sin_port = htons(0); - msock = RPC_ANYSOCK; - mclient = clnttcp_create(&mount_server_addr, MOUNTPROG, MOUNTVERS, &msock, 0, 0); - - /* if this fails, contact the mount daemon via UDP */ - if (!mclient) { - mount_server_addr.sin_port = htons(0); - msock = RPC_ANYSOCK; - mclient = clntudp_create(&mount_server_addr, MOUNTPROG, MOUNTVERS, retry_timeout, &msock); - } - if (mclient) { + if (mclient) { /* try to mount hostname:dirname */ - mclient->cl_auth = authunix_create_default(); - clnt_stat = clnt_call(mclient, MOUNTPROC_MNT, - (xdrproc_t) xdr_dirpath, (caddr_t) &dirname, - (xdrproc_t) xdr_fhstatus, (caddr_t) &status, - total_timeout); - if (clnt_stat != RPC_SUCCESS) { - if (errno != ECONNREFUSED) { - log_message(clnt_sperror(mclient, "mount")); - goto fail; /* don't retry */ + mclient->cl_auth = authunix_create_default(); + + /* make pointers in xdr_mountres3 NULL so + * that xdr_array allocates memory for us + */ + memset(&status, 0, sizeof(status)); + + log_message("nfsmount: doing client call in nfs v%ld", pm_mnt->pm_vers); + if (pm_mnt->pm_vers == 3) + clnt_stat = clnt_call(mclient, + MOUNTPROC3_MNT, + (xdrproc_t) xdr_dirpath, + (caddr_t) &dirname, + (xdrproc_t) xdr_mountres3, + (caddr_t) &status, + total_timeout); + else + clnt_stat = clnt_call(mclient, + MOUNTPROC_MNT, + (xdrproc_t) xdr_dirpath, + (caddr_t) &dirname, + (xdrproc_t) xdr_fhstatus, + (caddr_t) &status, + total_timeout); + + if (clnt_stat == RPC_SUCCESS) + goto succeeded; + + if (!running_bg && prevt == 0) + clnt_perror(mclient, "mount"); + auth_destroy(mclient->cl_auth); + clnt_destroy(mclient); + mclient = 0; + close(msock); + } else { + if (!running_bg && prevt == 0) + clnt_pcreateerror("mount"); } - log_message(clnt_sperror(mclient, "mount")); - auth_destroy(mclient->cl_auth); - clnt_destroy(mclient); - mclient = 0; - close(msock); - } - } else - goto fail; + prevt = t; - if (status.fhs_status != 0) { - if (status.fhs_status == 2) - log_message("NFS server says: No such file or directory"); - else if (status.fhs_status == 13) - log_message("NFS server says: Permission denied"); - else - log_message("nfsmount prepare failed, reason given by server: %d", status.fhs_status); - goto fail; - } + goto fail; - memcpy((char *) &root_fhandle, (char *) status.fhstatus_u.fhs_fhandle, sizeof (root_fhandle)); + succeeded: + nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers; + + if (nfsvers == 2) { + if (status.nfsv2.fhs_status != 0) { + log_message("nfsmount: %s:%s failed, reason given by server: %s", + hostname, dirname, nfs_strerror(status.nfsv2.fhs_status)); + goto fail; + } + memcpy(data.root.data, + (char *) status.nfsv2.fhstatus_u.fhs_fhandle, + NFS_FHSIZE); +#if NFS_MOUNT_VERSION >= 4 + data.root.size = NFS_FHSIZE; + memcpy(data.old_root.data, + (char *) status.nfsv2.fhstatus_u.fhs_fhandle, + NFS_FHSIZE); +#endif + } else { +#if NFS_MOUNT_VERSION >= 4 + fhandle3 *fhandle; + if (status.nfsv3.fhs_status != 0) { + log_message("nfsmount: %s:%s failed, reason given by server: %s", + hostname, dirname, nfs_strerror(status.nfsv3.fhs_status)); + goto fail; + } + fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle; + memset(data.old_root.data, 0, NFS_FHSIZE); + memset(&data.root, 0, sizeof(data.root)); + data.root.size = fhandle->fhandle3_len; + memcpy(data.root.data, + (char *) fhandle->fhandle3_val, + fhandle->fhandle3_len); + + data.flags |= NFS_MOUNT_VER3; +#endif + } /* create nfs socket for kernel */ - fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (tcp) { + if (nfs_mount_version < 3) { + log_message("NFS over TCP is not supported."); + goto fail; + } + fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + } else + fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fsock < 0) { log_perror("nfs socket"); goto fail; @@ -251,21 +720,49 @@ int nfsmount_prepare(const char *spec, int *flags, char **mount_opts) log_perror("nfs bindresvport"); goto fail; } - server_addr.sin_port = PMAPPORT; - port = pmap_getport(&server_addr, NFS_PROGRAM, NFS_VERSION, IPPROTO_UDP); - if (port == 0) - port = NFS_PORT; + if (port == 0) { + server_addr.sin_port = PMAPPORT; + port = pmap_getport(&server_addr, nfsprog, nfsvers, + tcp ? IPPROTO_TCP : IPPROTO_UDP); +#if 1 + /* Here we check to see if user is mounting with the + * tcp option. If so, and if the portmap returns a + * '0' for port (service unavailable), we then notify + * the user, and retry with udp. + */ + if (port == 0 && tcp == 1) { + log_message("NFS server reported TCP not available, retrying with UDP..."); + tcp = 0; + goto retry_mount; + } +#endif + + if (port == 0) + port = NFS_PORT; +#ifdef NFS_MOUNT_DEBUG + else + log_message("used portmapper to find NFS port"); +#endif + } #ifdef NFS_MOUNT_DEBUG - else - log_message("used portmapper to find NFS port\n"); - log_message("using port %d for nfs deamon\n", port); + log_message("using port %d for nfs deamon", port); #endif server_addr.sin_port = htons(port); + /* + * connect() the socket for kernels 1.3.10 and below only, + * to avoid problems with multihomed hosts. + * --Swen + */ + if (linux_version_code() <= 66314 + && connect(fsock, (struct sockaddr *) &server_addr, + sizeof (server_addr)) < 0) { + log_perror("nfs connect"); + goto fail; + } /* prepare data structure for kernel */ data.fd = fsock; - memcpy((char *) &data.root, (char *) &root_fhandle, sizeof (root_fhandle)); memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr)); strncpy(data.hostname, hostname, sizeof(data.hostname)); @@ -288,7 +785,65 @@ int nfsmount_prepare(const char *spec, int *flags, char **mount_opts) } if (fsock != -1) close(fsock); - - return -1; + return retval; } +/* + * We need to translate between nfs status return values and + * the local errno values which may not be the same. + * + * Andreas Schwab : change errno: + * "after #include the symbol errno is reserved for any use, + * it cannot even be used as a struct tag or field name". + */ + +#ifndef EDQUOT +#define EDQUOT ENOSPC +#endif + +static struct { + enum nfsstat stat; + int errnum; +} nfs_errtbl[] = { + { NFS_OK, 0 }, + { NFSERR_PERM, EPERM }, + { NFSERR_NOENT, ENOENT }, + { NFSERR_IO, EIO }, + { NFSERR_NXIO, ENXIO }, + { NFSERR_ACCES, EACCES }, + { NFSERR_EXIST, EEXIST }, + { NFSERR_NODEV, ENODEV }, + { NFSERR_NOTDIR, ENOTDIR }, + { NFSERR_ISDIR, EISDIR }, +#ifdef NFSERR_INVAL + { NFSERR_INVAL, EINVAL }, /* that Sun forgot */ +#endif + { NFSERR_FBIG, EFBIG }, + { NFSERR_NOSPC, ENOSPC }, + { NFSERR_ROFS, EROFS }, + { NFSERR_NAMETOOLONG, ENAMETOOLONG }, + { NFSERR_NOTEMPTY, ENOTEMPTY }, + { NFSERR_DQUOT, EDQUOT }, + { NFSERR_STALE, ESTALE }, +#ifdef EWFLUSH + { NFSERR_WFLUSH, EWFLUSH }, +#endif + /* Throw in some NFSv3 values for even more fun (HP returns these) */ + { 71, EREMOTE }, + + { -1, EIO } +}; + +static char *nfs_strerror(int stat) +{ + int i; + static char buf[256]; + + for (i = 0; nfs_errtbl[i].stat != (unsigned)-1; i++) { + if (nfs_errtbl[i].stat == (unsigned)stat) + return strerror(nfs_errtbl[i].errnum); + } + sprintf(buf, "unknown nfs status return value: %d", stat); + return buf; +} + diff --git a/mdk-stage1/nfsmount.h b/mdk-stage1/nfsmount.h index 12ffa69a6..a27e8a8d7 100644 --- a/mdk-stage1/nfsmount.h +++ b/mdk-stage1/nfsmount.h @@ -8,9 +8,13 @@ #include -int nfsmount_prepare(const char *spec, int *flags, char **mount_opts); +int nfsmount_prepare(const char *spec, char **mount_opts); +#ifdef __cplusplus +extern "C" { +#endif + /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape @@ -47,19 +51,32 @@ int nfsmount_prepare(const char *spec, int *flags, char **mount_opts); /* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */ #ifndef _rpcsvc_mount_h #define _rpcsvc_mount_h +#include #define MNTPATHLEN 1024 #define MNTNAMLEN 255 #define FHSIZE 32 +#define FHSIZE3 64 typedef char fhandle[FHSIZE]; -#ifdef __cplusplus -extern "C" bool_t xdr_fhandle(XDR *, fhandle); -#elif __STDC__ -extern bool_t xdr_fhandle(XDR *, fhandle); -#else /* Old Style C */ -bool_t xdr_fhandle(); -#endif /* Old Style C */ +typedef struct { + u_int fhandle3_len; + char *fhandle3_val; +} fhandle3; + +enum mountstat3 { + MNT_OK = 0, + MNT3ERR_PERM = 1, + MNT3ERR_NOENT = 2, + MNT3ERR_IO = 5, + MNT3ERR_ACCES = 13, + MNT3ERR_NOTDIR = 20, + MNT3ERR_INVAL = 22, + MNT3ERR_NAMETOOLONG = 63, + MNT3ERR_NOTSUPP = 10004, + MNT3ERR_SERVERFAULT = 10006, +}; +typedef enum mountstat3 mountstat3; struct fhstatus { u_int fhs_status; @@ -68,44 +85,29 @@ struct fhstatus { } fhstatus_u; }; typedef struct fhstatus fhstatus; -#ifdef __cplusplus -extern "C" bool_t xdr_fhstatus(XDR *, fhstatus*); -#elif __STDC__ -extern bool_t xdr_fhstatus(XDR *, fhstatus*); -#else /* Old Style C */ -bool_t xdr_fhstatus(); -#endif /* Old Style C */ +struct mountres3_ok { + fhandle3 fhandle; + struct { + u_int auth_flavours_len; + int *auth_flavours_val; + } auth_flavours; +}; +typedef struct mountres3_ok mountres3_ok; -typedef char *dirpath; -#ifdef __cplusplus -extern "C" bool_t xdr_dirpath(XDR *, dirpath*); -#elif __STDC__ -extern bool_t xdr_dirpath(XDR *, dirpath*); -#else /* Old Style C */ -bool_t xdr_dirpath(); -#endif /* Old Style C */ +struct mountres3 { + mountstat3 fhs_status; + union { + mountres3_ok mountinfo; + } mountres3_u; +}; +typedef struct mountres3 mountres3; +typedef char *dirpath; typedef char *name; -#ifdef __cplusplus -extern "C" bool_t xdr_name(XDR *, name*); -#elif __STDC__ -extern bool_t xdr_name(XDR *, name*); -#else /* Old Style C */ -bool_t xdr_name(); -#endif /* Old Style C */ - typedef struct mountbody *mountlist; -#ifdef __cplusplus -extern "C" bool_t xdr_mountlist(XDR *, mountlist*); -#elif __STDC__ -extern bool_t xdr_mountlist(XDR *, mountlist*); -#else /* Old Style C */ -bool_t xdr_mountlist(); -#endif /* Old Style C */ - struct mountbody { name ml_hostname; @@ -113,48 +115,16 @@ struct mountbody { mountlist ml_next; }; typedef struct mountbody mountbody; -#ifdef __cplusplus -extern "C" bool_t xdr_mountbody(XDR *, mountbody*); -#elif __STDC__ -extern bool_t xdr_mountbody(XDR *, mountbody*); -#else /* Old Style C */ -bool_t xdr_mountbody(); -#endif /* Old Style C */ - typedef struct groupnode *groups; -#ifdef __cplusplus -extern "C" bool_t xdr_groups(XDR *, groups*); -#elif __STDC__ -extern bool_t xdr_groups(XDR *, groups*); -#else /* Old Style C */ -bool_t xdr_groups(); -#endif /* Old Style C */ - struct groupnode { name gr_name; groups gr_next; }; typedef struct groupnode groupnode; -#ifdef __cplusplus -extern "C" bool_t xdr_groupnode(XDR *, groupnode*); -#elif __STDC__ -extern bool_t xdr_groupnode(XDR *, groupnode*); -#else /* Old Style C */ -bool_t xdr_groupnode(); -#endif /* Old Style C */ - typedef struct exportnode *exports; -#ifdef __cplusplus -extern "C" bool_t xdr_exports(XDR *, exports*); -#elif __STDC__ -extern bool_t xdr_exports(XDR *, exports*); -#else /* Old Style C */ -bool_t xdr_exports(); -#endif /* Old Style C */ - struct exportnode { dirpath ex_dir; @@ -162,14 +132,6 @@ struct exportnode { exports ex_next; }; typedef struct exportnode exportnode; -#ifdef __cplusplus -extern "C" bool_t xdr_exportnode(XDR *, exportnode*); -#elif __STDC__ -extern bool_t xdr_exportnode(XDR *, exportnode*); -#else /* Old Style C */ -bool_t xdr_exportnode(); -#endif /* Old Style C */ - struct ppathcnf { int pc_link_max; @@ -183,110 +145,62 @@ struct ppathcnf { short pc_mask[2]; }; typedef struct ppathcnf ppathcnf; -#ifdef __cplusplus -extern "C" bool_t xdr_ppathcnf(XDR *, ppathcnf*); -#elif __STDC__ -extern bool_t xdr_ppathcnf(XDR *, ppathcnf*); -#else /* Old Style C */ -bool_t xdr_ppathcnf(); -#endif /* Old Style C */ - #endif /*!_rpcsvc_mount_h*/ -#define MOUNTPROG ((u_long)100005) -#define MOUNTVERS ((u_long)1) +#define MOUNTPROG 100005 +#define MOUNTVERS 1 -#ifdef __cplusplus -#define MOUNTPROC_NULL ((u_long)0) -extern "C" void * mountproc_null_1(void *, CLIENT *); -extern "C" void * mountproc_null_1_svc(void *, struct svc_req *); -#define MOUNTPROC_MNT ((u_long)1) -extern "C" fhstatus * mountproc_mnt_1(dirpath *, CLIENT *); -extern "C" fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *); -#define MOUNTPROC_DUMP ((u_long)2) -extern "C" mountlist * mountproc_dump_1(void *, CLIENT *); -extern "C" mountlist * mountproc_dump_1_svc(void *, struct svc_req *); -#define MOUNTPROC_UMNT ((u_long)3) -extern "C" void * mountproc_umnt_1(dirpath *, CLIENT *); -extern "C" void * mountproc_umnt_1_svc(dirpath *, struct svc_req *); -#define MOUNTPROC_UMNTALL ((u_long)4) -extern "C" void * mountproc_umntall_1(void *, CLIENT *); -extern "C" void * mountproc_umntall_1_svc(void *, struct svc_req *); -#define MOUNTPROC_EXPORT ((u_long)5) -extern "C" exports * mountproc_export_1(void *, CLIENT *); -extern "C" exports * mountproc_export_1_svc(void *, struct svc_req *); -#define MOUNTPROC_EXPORTALL ((u_long)6) -extern "C" exports * mountproc_exportall_1(void *, CLIENT *); -extern "C" exports * mountproc_exportall_1_svc(void *, struct svc_req *); - -#elif __STDC__ -#define MOUNTPROC_NULL ((u_long)0) +#if defined(__STDC__) || defined(__cplusplus) +#define MOUNTPROC_NULL 0 extern void * mountproc_null_1(void *, CLIENT *); extern void * mountproc_null_1_svc(void *, struct svc_req *); -#define MOUNTPROC_MNT ((u_long)1) +#define MOUNTPROC_MNT 1 extern fhstatus * mountproc_mnt_1(dirpath *, CLIENT *); extern fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *); -#define MOUNTPROC_DUMP ((u_long)2) +#define MOUNTPROC_DUMP 2 extern mountlist * mountproc_dump_1(void *, CLIENT *); extern mountlist * mountproc_dump_1_svc(void *, struct svc_req *); -#define MOUNTPROC_UMNT ((u_long)3) +#define MOUNTPROC_UMNT 3 extern void * mountproc_umnt_1(dirpath *, CLIENT *); extern void * mountproc_umnt_1_svc(dirpath *, struct svc_req *); -#define MOUNTPROC_UMNTALL ((u_long)4) +#define MOUNTPROC_UMNTALL 4 extern void * mountproc_umntall_1(void *, CLIENT *); extern void * mountproc_umntall_1_svc(void *, struct svc_req *); -#define MOUNTPROC_EXPORT ((u_long)5) +#define MOUNTPROC_EXPORT 5 extern exports * mountproc_export_1(void *, CLIENT *); extern exports * mountproc_export_1_svc(void *, struct svc_req *); -#define MOUNTPROC_EXPORTALL ((u_long)6) +#define MOUNTPROC_EXPORTALL 6 extern exports * mountproc_exportall_1(void *, CLIENT *); extern exports * mountproc_exportall_1_svc(void *, struct svc_req *); +extern int mountprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); -#else /* Old Style C */ -#define MOUNTPROC_NULL ((u_long)0) +#else /* K&R C */ +#define MOUNTPROC_NULL 0 extern void * mountproc_null_1(); extern void * mountproc_null_1_svc(); -#define MOUNTPROC_MNT ((u_long)1) +#define MOUNTPROC_MNT 1 extern fhstatus * mountproc_mnt_1(); extern fhstatus * mountproc_mnt_1_svc(); -#define MOUNTPROC_DUMP ((u_long)2) +#define MOUNTPROC_DUMP 2 extern mountlist * mountproc_dump_1(); extern mountlist * mountproc_dump_1_svc(); -#define MOUNTPROC_UMNT ((u_long)3) +#define MOUNTPROC_UMNT 3 extern void * mountproc_umnt_1(); extern void * mountproc_umnt_1_svc(); -#define MOUNTPROC_UMNTALL ((u_long)4) +#define MOUNTPROC_UMNTALL 4 extern void * mountproc_umntall_1(); extern void * mountproc_umntall_1_svc(); -#define MOUNTPROC_EXPORT ((u_long)5) +#define MOUNTPROC_EXPORT 5 extern exports * mountproc_export_1(); extern exports * mountproc_export_1_svc(); -#define MOUNTPROC_EXPORTALL ((u_long)6) +#define MOUNTPROC_EXPORTALL 6 extern exports * mountproc_exportall_1(); extern exports * mountproc_exportall_1_svc(); -#endif /* Old Style C */ -#define MOUNTVERS_POSIX ((u_long)2) +extern int mountprog_1_freeresult (); +#endif /* K&R C */ +#define MOUNTVERS_POSIX 2 -#ifdef __cplusplus -extern "C" void * mountproc_null_2(void *, CLIENT *); -extern "C" void * mountproc_null_2_svc(void *, struct svc_req *); -extern "C" fhstatus * mountproc_mnt_2(dirpath *, CLIENT *); -extern "C" fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *); -extern "C" mountlist * mountproc_dump_2(void *, CLIENT *); -extern "C" mountlist * mountproc_dump_2_svc(void *, struct svc_req *); -extern "C" void * mountproc_umnt_2(dirpath *, CLIENT *); -extern "C" void * mountproc_umnt_2_svc(dirpath *, struct svc_req *); -extern "C" void * mountproc_umntall_2(void *, CLIENT *); -extern "C" void * mountproc_umntall_2_svc(void *, struct svc_req *); -extern "C" exports * mountproc_export_2(void *, CLIENT *); -extern "C" exports * mountproc_export_2_svc(void *, struct svc_req *); -extern "C" exports * mountproc_exportall_2(void *, CLIENT *); -extern "C" exports * mountproc_exportall_2_svc(void *, struct svc_req *); -#define MOUNTPROC_PATHCONF ((u_long)7) -extern "C" ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *); -extern "C" ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *); - -#elif __STDC__ +#if defined(__STDC__) || defined(__cplusplus) extern void * mountproc_null_2(void *, CLIENT *); extern void * mountproc_null_2_svc(void *, struct svc_req *); extern fhstatus * mountproc_mnt_2(dirpath *, CLIENT *); @@ -301,11 +215,12 @@ extern exports * mountproc_export_2(void *, CLIENT *); extern exports * mountproc_export_2_svc(void *, struct svc_req *); extern exports * mountproc_exportall_2(void *, CLIENT *); extern exports * mountproc_exportall_2_svc(void *, struct svc_req *); -#define MOUNTPROC_PATHCONF ((u_long)7) +#define MOUNTPROC_PATHCONF 7 extern ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *); extern ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *); +extern int mountprog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t); -#else /* Old Style C */ +#else /* K&R C */ extern void * mountproc_null_2(); extern void * mountproc_null_2_svc(); extern fhstatus * mountproc_mnt_2(); @@ -320,9 +235,97 @@ extern exports * mountproc_export_2(); extern exports * mountproc_export_2_svc(); extern exports * mountproc_exportall_2(); extern exports * mountproc_exportall_2_svc(); -#define MOUNTPROC_PATHCONF ((u_long)7) +#define MOUNTPROC_PATHCONF 7 extern ppathcnf * mountproc_pathconf_2(); extern ppathcnf * mountproc_pathconf_2_svc(); -#endif /* Old Style C */ +extern int mountprog_2_freeresult (); +#endif /* K&R C */ +#define MOUNT_V3 3 + +#if defined(__STDC__) || defined(__cplusplus) +#define MOUNTPROC3_NULL 0 +extern void * mountproc3_null_3(void *, CLIENT *); +extern void * mountproc3_null_3_svc(void *, struct svc_req *); +#define MOUNTPROC3_MNT 1 +extern mountres3 * mountproc3_mnt_3(dirpath *, CLIENT *); +extern mountres3 * mountproc3_mnt_3_svc(dirpath *, struct svc_req *); +#define MOUNTPROC3_DUMP 2 +extern mountlist * mountproc3_dump_3(void *, CLIENT *); +extern mountlist * mountproc3_dump_3_svc(void *, struct svc_req *); +#define MOUNTPROC3_UMNT 3 +extern void * mountproc3_umnt_3(dirpath *, CLIENT *); +extern void * mountproc3_umnt_3_svc(dirpath *, struct svc_req *); +#define MOUNTPROC3_UMNTALL 4 +extern void * mountproc3_umntall_3(void *, CLIENT *); +extern void * mountproc3_umntall_3_svc(void *, struct svc_req *); +#define MOUNTPROC3_EXPORT 5 +extern exports * mountproc3_export_3(void *, CLIENT *); +extern exports * mountproc3_export_3_svc(void *, struct svc_req *); +extern int mountprog_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + +#else /* K&R C */ +#define MOUNTPROC3_NULL 0 +extern void * mountproc3_null_3(); +extern void * mountproc3_null_3_svc(); +#define MOUNTPROC3_MNT 1 +extern mountres3 * mountproc3_mnt_3(); +extern mountres3 * mountproc3_mnt_3_svc(); +#define MOUNTPROC3_DUMP 2 +extern mountlist * mountproc3_dump_3(); +extern mountlist * mountproc3_dump_3_svc(); +#define MOUNTPROC3_UMNT 3 +extern void * mountproc3_umnt_3(); +extern void * mountproc3_umnt_3_svc(); +#define MOUNTPROC3_UMNTALL 4 +extern void * mountproc3_umntall_3(); +extern void * mountproc3_umntall_3_svc(); +#define MOUNTPROC3_EXPORT 5 +extern exports * mountproc3_export_3(); +extern exports * mountproc3_export_3_svc(); +extern int mountprog_3_freeresult (); +#endif /* K&R C */ + +/* the xdr functions */ + +#if defined(__STDC__) || defined(__cplusplus) +extern bool_t xdr_fhandle (XDR *, fhandle); +extern bool_t xdr_fhandle3 (XDR *, fhandle3*); +extern bool_t xdr_mountstat3 (XDR *, mountstat3*); +extern bool_t xdr_fhstatus (XDR *, fhstatus*); +extern bool_t xdr_mountres3_ok (XDR *, mountres3_ok*); +extern bool_t xdr_mountres3 (XDR *, mountres3*); +extern bool_t xdr_dirpath (XDR *, dirpath*); +extern bool_t xdr_name (XDR *, name*); +extern bool_t xdr_mountlist (XDR *, mountlist*); +extern bool_t xdr_mountbody (XDR *, mountbody*); +extern bool_t xdr_groups (XDR *, groups*); +extern bool_t xdr_groupnode (XDR *, groupnode*); +extern bool_t xdr_exports (XDR *, exports*); +extern bool_t xdr_exportnode (XDR *, exportnode*); +extern bool_t xdr_ppathcnf (XDR *, ppathcnf*); + +#else /* K&R C */ +extern bool_t xdr_fhandle (); +extern bool_t xdr_fhandle3 (); +extern bool_t xdr_mountstat3 (); +extern bool_t xdr_fhstatus (); +extern bool_t xdr_mountres3_ok (); +extern bool_t xdr_mountres3 (); +extern bool_t xdr_dirpath (); +extern bool_t xdr_name (); +extern bool_t xdr_mountlist (); +extern bool_t xdr_mountbody (); +extern bool_t xdr_groups (); +extern bool_t xdr_groupnode (); +extern bool_t xdr_exports (); +extern bool_t xdr_exportnode (); +extern bool_t xdr_ppathcnf (); + +#endif /* K&R C */ + +#ifdef __cplusplus +} +#endif #endif /* !_NFSMOUNT_H_RPCGEN */ + -- cgit v1.2.1