1 /* vi: set sw=4 ts=4: */
3 * nfsmount.c -- Linux NFS mount
4 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
6 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
9 * numbers to be specified on the command line.
11 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
12 * Omit the call to connect() for Linux version 1.3.11 or later.
14 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
15 * Implemented the "bg", "fg" and "retry" mount options for NFS.
17 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
18 * - added Native Language Support
20 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
25 * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
33 #include <sys/utsname.h>
37 #include <rpc/pmap_prot.h>
38 #include <rpc/pmap_clnt.h>
41 /* This is just a warning of a common mistake. Possibly this should be a
42 * uclibc faq entry rather than in busybox... */
43 #if ENABLE_FEATURE_MOUNT_NFS && defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
44 #error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
49 * NFS stats. The good thing with these values is that NFSv3 errors are
50 * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
51 * no-one uses anyway), so we can happily mix code as long as we make sure
52 * no NFSv3 errors are returned to NFSv2 clients.
53 * Error codes that have a `--' in the v2 column are not part of the
54 * standard, but seem to be widely used nevertheless.
57 NFS_OK = 0, /* v2 v3 */
58 NFSERR_PERM = 1, /* v2 v3 */
59 NFSERR_NOENT = 2, /* v2 v3 */
60 NFSERR_IO = 5, /* v2 v3 */
61 NFSERR_NXIO = 6, /* v2 v3 */
62 NFSERR_EAGAIN = 11, /* v2 v3 */
63 NFSERR_ACCES = 13, /* v2 v3 */
64 NFSERR_EXIST = 17, /* v2 v3 */
65 NFSERR_XDEV = 18, /* v3 */
66 NFSERR_NODEV = 19, /* v2 v3 */
67 NFSERR_NOTDIR = 20, /* v2 v3 */
68 NFSERR_ISDIR = 21, /* v2 v3 */
69 NFSERR_INVAL = 22, /* v2 v3 that Sun forgot */
70 NFSERR_FBIG = 27, /* v2 v3 */
71 NFSERR_NOSPC = 28, /* v2 v3 */
72 NFSERR_ROFS = 30, /* v2 v3 */
73 NFSERR_MLINK = 31, /* v3 */
74 NFSERR_OPNOTSUPP = 45, /* v2 v3 */
75 NFSERR_NAMETOOLONG = 63, /* v2 v3 */
76 NFSERR_NOTEMPTY = 66, /* v2 v3 */
77 NFSERR_DQUOT = 69, /* v2 v3 */
78 NFSERR_STALE = 70, /* v2 v3 */
79 NFSERR_REMOTE = 71, /* v2 v3 */
80 NFSERR_WFLUSH = 99, /* v2 */
81 NFSERR_BADHANDLE = 10001, /* v3 */
82 NFSERR_NOT_SYNC = 10002, /* v3 */
83 NFSERR_BAD_COOKIE = 10003, /* v3 */
84 NFSERR_NOTSUPP = 10004, /* v3 */
85 NFSERR_TOOSMALL = 10005, /* v3 */
86 NFSERR_SERVERFAULT = 10006, /* v3 */
87 NFSERR_BADTYPE = 10007, /* v3 */
88 NFSERR_JUKEBOX = 10008 /* v3 */
91 #define NFS_PROGRAM 100003
103 /* Disable the nls stuff */
104 # undef bindtextdomain
105 # define bindtextdomain(Domain, Directory) /* empty */
107 # define textdomain(Domain) /* empty */
110 S_QUOTA = 128, /* Quota initialized for file/directory/symlink */
115 * We want to be able to compile mount on old kernels in such a way
116 * that the binary will work well on more recent kernels.
117 * Thus, if necessary we teach nfsmount.c the structure of new fields
118 * that will come later.
120 * Moreover, the new kernel includes conflict with glibc includes
121 * so it is easiest to ignore the kernel altogether (at compile time).
124 /* NOTE: Do not make this into a 'static const int' because the pre-processor
125 * needs to test this value in some #if statements. */
126 #define NFS_MOUNT_VERSION 4
133 unsigned char data[64];
136 struct nfs_mount_data {
139 struct nfs2_fh old_root; /* 1 */
145 int acregmin; /* 1 */
146 int acregmax; /* 1 */
147 int acdirmin; /* 1 */
148 int acdirmax; /* 1 */
149 struct sockaddr_in addr; /* 1 */
150 char hostname[256]; /* 1 */
152 unsigned int bsize; /* 3 */
153 struct nfs3_fh root; /* 4 */
156 /* bits in the flags field */
158 NFS_MOUNT_SOFT = 0x0001, /* 1 */
159 NFS_MOUNT_INTR = 0x0002, /* 1 */
160 NFS_MOUNT_SECURE = 0x0004, /* 1 */
161 NFS_MOUNT_POSIX = 0x0008, /* 1 */
162 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
163 NFS_MOUNT_NOAC = 0x0020, /* 1 */
164 NFS_MOUNT_TCP = 0x0040, /* 2 */
165 NFS_MOUNT_VER3 = 0x0080, /* 3 */
166 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
167 NFS_MOUNT_NONLM = 0x0200 /* 3 */
171 #define UTIL_LINUX_VERSION "2.10m"
172 #define util_linux_version "util-linux-2.10m"
174 #define HAVE_inet_aton
179 #define HAVE_locale_h
180 #define HAVE_libintl_h
182 #define HAVE_langinfo_h
183 #define HAVE_progname
185 #define HAVE_nanosleep
186 #define HAVE_personality
187 #define HAVE_tm_gmtoff
189 static char *nfs_strerror(int status);
191 #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
194 EX_FAIL = 32, /* mount failure */
195 EX_BG = 256 /* retry in background (internal only) */
200 * nfs_mount_version according to the sources seen at compile time.
202 static int nfs_mount_version;
205 * Unfortunately, the kernel prints annoying console messages
206 * in case of an unexpected nfs mount version (instead of
207 * just returning some error). Therefore we'll have to try
208 * and figure out what version the kernel expects.
211 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
212 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
213 * nfs_mount_version: version this source and running kernel can handle
216 find_kernel_nfs_mount_version(void)
218 static int kernel_version = 0;
223 nfs_mount_version = NFS_MOUNT_VERSION; /* default */
225 kernel_version = get_linux_version_code();
226 if (kernel_version) {
227 if (kernel_version < KERNEL_VERSION(2,1,32))
228 nfs_mount_version = 1;
229 else if (kernel_version < KERNEL_VERSION(2,2,18) ||
230 (kernel_version >= KERNEL_VERSION(2,3,0) &&
231 kernel_version < KERNEL_VERSION(2,3,99)))
232 nfs_mount_version = 3;
234 nfs_mount_version = 4; /* since 2.3.99pre4 */
236 if (nfs_mount_version > NFS_MOUNT_VERSION)
237 nfs_mount_version = NFS_MOUNT_VERSION;
241 get_mountport(struct sockaddr_in *server_addr,
243 long unsigned version,
247 struct pmaplist *pmap;
248 static struct pmap p = {0, 0, 0, 0};
250 server_addr->sin_port = PMAPPORT;
251 pmap = pmap_getmaps(server_addr);
253 if (version > MAX_NFSPROT)
254 version = MAX_NFSPROT;
263 if (pmap->pml_map.pm_prog != prog)
265 if (!version && p.pm_vers > pmap->pml_map.pm_vers)
267 if (version > 2 && pmap->pml_map.pm_vers != version)
269 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
271 if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
272 (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
273 (port && pmap->pml_map.pm_port != port))
275 memcpy(&p, &pmap->pml_map, sizeof(p));
277 pmap = pmap->pml_next;
280 p.pm_vers = MOUNTVERS;
282 p.pm_port = MOUNTPORT;
284 p.pm_prot = IPPROTO_TCP;
288 int nfsmount(const char *spec, const char *node, int *flags,
289 char **mount_opts, int running_bg)
291 static char *prev_bg_host;
297 char *mounthost=NULL;
299 struct timeval total_timeout;
300 enum clnt_stat clnt_stat;
301 struct nfs_mount_data data;
305 struct sockaddr_in server_addr;
306 struct sockaddr_in mount_server_addr;
309 struct timeval retry_timeout;
311 struct fhstatus nfsv2;
312 struct mountres3 nfsv3;
337 find_kernel_nfs_mount_version();
342 if (strlen(spec) >= sizeof(hostdir)) {
343 bb_error_msg("excessively long host:dir argument");
346 strcpy(hostdir, spec);
347 if ((s = strchr(hostdir, ':'))) {
351 /* Ignore all but first hostname in replicated mounts
352 until they can be fully supported. (mack@sgi.com) */
353 if ((s = strchr(hostdir, ','))) {
355 bb_error_msg("warning: multiple hostnames not supported");
358 bb_error_msg("directory to mount not in host:dir format");
362 server_addr.sin_family = AF_INET;
363 #ifdef HAVE_inet_aton
364 if (!inet_aton(hostname, &server_addr.sin_addr))
367 if ((hp = gethostbyname(hostname)) == NULL) {
368 bb_herror_msg("%s", hostname);
371 if (hp->h_length > sizeof(struct in_addr)) {
372 bb_error_msg("got bad hp->h_length");
373 hp->h_length = sizeof(struct in_addr);
375 memcpy(&server_addr.sin_addr,
376 hp->h_addr, hp->h_length);
380 memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
382 /* add IP address to mtab options for use when unmounting */
384 s = inet_ntoa(server_addr.sin_addr);
385 old_opts = *mount_opts;
388 if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
389 bb_error_msg("excessively long option argument");
392 sprintf(new_opts, "%s%saddr=%s",
393 old_opts, *old_opts ? "," : "", s);
394 *mount_opts = bb_xstrdup(new_opts);
396 /* Set default options.
397 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
398 * let the kernel decide.
399 * timeo is filled in after we know whether it'll be TCP or UDP. */
400 memset(&data, 0, sizeof(data));
406 #if NFS_MOUNT_VERSION >= 2
407 data.namlen = NAME_MAX;
417 retry = 10000; /* 10000 minutes ~ 1 week */
420 mountprog = MOUNTPROG;
424 nfsprog = NFS_PROGRAM;
429 for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
430 if ((opteq = strchr(opt, '='))) {
431 val = atoi(opteq + 1);
433 if (!strcmp(opt, "rsize"))
435 else if (!strcmp(opt, "wsize"))
437 else if (!strcmp(opt, "timeo"))
439 else if (!strcmp(opt, "retrans"))
441 else if (!strcmp(opt, "acregmin"))
443 else if (!strcmp(opt, "acregmax"))
445 else if (!strcmp(opt, "acdirmin"))
447 else if (!strcmp(opt, "acdirmax"))
449 else if (!strcmp(opt, "actimeo")) {
455 else if (!strcmp(opt, "retry"))
457 else if (!strcmp(opt, "port"))
459 else if (!strcmp(opt, "mountport"))
461 else if (!strcmp(opt, "mounthost"))
462 mounthost=bb_xstrndup(opteq+1,
463 strcspn(opteq+1," \t\n\r,"));
464 else if (!strcmp(opt, "mountprog"))
466 else if (!strcmp(opt, "mountvers"))
468 else if (!strcmp(opt, "nfsprog"))
470 else if (!strcmp(opt, "nfsvers") ||
471 !strcmp(opt, "vers"))
473 else if (!strcmp(opt, "proto")) {
474 if (!strncmp(opteq+1, "tcp", 3))
476 else if (!strncmp(opteq+1, "udp", 3))
479 printf("Warning: Unrecognized proto= option.\n");
480 } else if (!strcmp(opt, "namlen")) {
481 #if NFS_MOUNT_VERSION >= 2
482 if (nfs_mount_version >= 2)
486 printf("Warning: Option namlen is not supported.\n");
487 } else if (!strcmp(opt, "addr"))
490 printf("unknown nfs mount parameter: %s=%d\n", opt, val);
496 if (!strncmp(opt, "no", 2)) {
500 if (!strcmp(opt, "bg"))
502 else if (!strcmp(opt, "fg"))
504 else if (!strcmp(opt, "soft"))
506 else if (!strcmp(opt, "hard"))
508 else if (!strcmp(opt, "intr"))
510 else if (!strcmp(opt, "posix"))
512 else if (!strcmp(opt, "cto"))
514 else if (!strcmp(opt, "ac"))
516 else if (!strcmp(opt, "tcp"))
518 else if (!strcmp(opt, "udp"))
520 else if (!strcmp(opt, "lock")) {
521 if (nfs_mount_version >= 3)
524 printf("Warning: option nolock is not supported.\n");
526 printf("unknown nfs mount option: %s%s\n", val ? "" : "no", opt);
531 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
533 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
534 | (intr ? NFS_MOUNT_INTR : 0)
535 | (posix ? NFS_MOUNT_POSIX : 0)
536 | (nocto ? NFS_MOUNT_NOCTO : 0)
537 | (noac ? NFS_MOUNT_NOAC : 0);
538 #if NFS_MOUNT_VERSION >= 2
539 if (nfs_mount_version >= 2)
540 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
542 #if NFS_MOUNT_VERSION >= 3
543 if (nfs_mount_version >= 3)
544 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
546 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
547 bb_error_msg("NFSv%d not supported!", nfsvers);
550 if (nfsvers && !mountvers)
551 mountvers = (nfsvers < 3) ? 1 : nfsvers;
552 if (nfsvers && nfsvers < mountvers) {
556 /* Adjust options if none specified */
558 data.timeo = tcp ? 70 : 7;
560 #ifdef NFS_MOUNT_DEBUG
561 printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
562 data.rsize, data.wsize, data.timeo, data.retrans);
563 printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
564 data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
565 printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
566 port, bg, retry, data.flags);
567 printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
568 mountprog, mountvers, nfsprog, nfsvers);
569 printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
570 (data.flags & NFS_MOUNT_SOFT) != 0,
571 (data.flags & NFS_MOUNT_INTR) != 0,
572 (data.flags & NFS_MOUNT_POSIX) != 0,
573 (data.flags & NFS_MOUNT_NOCTO) != 0,
574 (data.flags & NFS_MOUNT_NOAC) != 0);
575 #if NFS_MOUNT_VERSION >= 2
577 (data.flags & NFS_MOUNT_TCP) != 0);
581 data.version = nfs_mount_version;
583 if (*flags & MS_REMOUNT)
584 goto copy_data_and_return;
587 * If the previous mount operation on the same host was
588 * backgrounded, and the "bg" for this mount is also set,
589 * give up immediately, to avoid the initial timeout.
591 if (bg && !running_bg &&
592 prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
598 /* create mount daemon client */
599 /* See if the nfs host = mount host. */
601 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
602 mount_server_addr.sin_family = AF_INET;
603 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
605 if ((hp = gethostbyname(mounthost)) == NULL) {
606 bb_herror_msg("%s", mounthost);
609 if (hp->h_length > sizeof(struct in_addr)) {
610 bb_error_msg("got bad hp->h_length?");
611 hp->h_length = sizeof(struct in_addr);
613 mount_server_addr.sin_family = AF_INET;
614 memcpy(&mount_server_addr.sin_addr,
615 hp->h_addr, hp->h_length);
621 * The following loop implements the mount retries. On the first
622 * call, "running_bg" is 0. When the mount times out, and the
623 * "bg" option is set, the exit status EX_BG will be returned.
624 * For a backgrounded mount, there will be a second call by the
625 * child process with "running_bg" set to 1.
627 * The case where the mount point is not present and the "bg"
628 * option is set, is treated as a timeout. This is done to
629 * support nested mounts.
631 * The "retry" count specified by the user is the number of
632 * minutes to retry before giving up.
634 * Only the first error message will be displayed.
636 retry_timeout.tv_sec = 3;
637 retry_timeout.tv_usec = 0;
638 total_timeout.tv_sec = 20;
639 total_timeout.tv_usec = 0;
640 timeout = time(NULL) + 60 * retry;
645 if (bg && stat(node, &statbuf) == -1) {
647 sleep(val); /* 1, 2, 4, 8, 16, 30, ... */
653 /* be careful not to use too many CPU cycles */
657 pm_mnt = get_mountport(&mount_server_addr,
663 /* contact the mount daemon via TCP */
664 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
667 switch (pm_mnt->pm_prot) {
669 mclient = clntudp_create(&mount_server_addr,
676 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
679 mclient = clnttcp_create(&mount_server_addr,
688 /* try to mount hostname:pathname */
689 mclient->cl_auth = authunix_create_default();
691 /* make pointers in xdr_mountres3 NULL so
692 * that xdr_array allocates memory for us
694 memset(&status, 0, sizeof(status));
696 if (pm_mnt->pm_vers == 3)
697 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
698 (xdrproc_t) xdr_dirpath,
700 (xdrproc_t) xdr_mountres3,
704 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
705 (xdrproc_t) xdr_dirpath,
707 (xdrproc_t) xdr_fhstatus,
711 if (clnt_stat == RPC_SUCCESS)
712 break; /* we're done */
713 if (errno != ECONNREFUSED) {
714 clnt_perror(mclient, "mount");
715 goto fail; /* don't retry */
717 if (!running_bg && prevt == 0)
718 clnt_perror(mclient, "mount");
719 auth_destroy(mclient->cl_auth);
720 clnt_destroy(mclient);
724 if (!running_bg && prevt == 0)
725 clnt_pcreateerror("mount");
732 prev_bg_host = bb_xstrdup(hostname);
741 nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
744 if (status.nfsv2.fhs_status != 0) {
745 bb_error_msg("%s:%s failed, reason given by server: %s",
747 nfs_strerror(status.nfsv2.fhs_status));
750 memcpy(data.root.data,
751 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
753 #if NFS_MOUNT_VERSION >= 4
754 data.root.size = NFS_FHSIZE;
755 memcpy(data.old_root.data,
756 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
760 #if NFS_MOUNT_VERSION >= 4
761 fhandle3 *my_fhandle;
762 if (status.nfsv3.fhs_status != 0) {
763 bb_error_msg("%s:%s failed, reason given by server: %s",
765 nfs_strerror(status.nfsv3.fhs_status));
768 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
769 memset(data.old_root.data, 0, NFS_FHSIZE);
770 memset(&data.root, 0, sizeof(data.root));
771 data.root.size = my_fhandle->fhandle3_len;
772 memcpy(data.root.data,
773 (char *) my_fhandle->fhandle3_val,
774 my_fhandle->fhandle3_len);
776 data.flags |= NFS_MOUNT_VER3;
780 /* create nfs socket for kernel */
783 if (nfs_mount_version < 3) {
784 printf("NFS over TCP is not supported.\n");
787 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
789 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
791 perror("nfs socket");
794 if (bindresvport(fsock, 0) < 0) {
795 perror("nfs bindresvport");
799 server_addr.sin_port = PMAPPORT;
800 port = pmap_getport(&server_addr, nfsprog, nfsvers,
801 tcp ? IPPROTO_TCP : IPPROTO_UDP);
804 #ifdef NFS_MOUNT_DEBUG
806 printf("used portmapper to find NFS port\n");
809 #ifdef NFS_MOUNT_DEBUG
810 printf("using port %d for nfs daemon\n", port);
812 server_addr.sin_port = htons(port);
814 * connect() the socket for kernels 1.3.10 and below only,
815 * to avoid problems with multihomed hosts.
818 if (get_linux_version_code() <= KERNEL_VERSION(2,3,10)
819 && connect(fsock, (struct sockaddr *) &server_addr,
820 sizeof (server_addr)) < 0) {
821 perror("nfs connect");
825 /* prepare data structure for kernel */
828 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
829 strncpy(data.hostname, hostname, sizeof(data.hostname));
833 auth_destroy(mclient->cl_auth);
834 clnt_destroy(mclient);
836 copy_data_and_return:
837 *mount_opts = xrealloc(*mount_opts, sizeof(data));
838 memcpy(*mount_opts, &data, sizeof(data));
846 auth_destroy(mclient->cl_auth);
847 clnt_destroy(mclient);
857 * We need to translate between nfs status return values and
858 * the local errno values which may not be the same.
860 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
861 * "after #include <errno.h> the symbol errno is reserved for any use,
862 * it cannot even be used as a struct tag or field name".
866 #define EDQUOT ENOSPC
869 static const struct {
874 { NFSERR_PERM, EPERM },
875 { NFSERR_NOENT, ENOENT },
877 { NFSERR_NXIO, ENXIO },
878 { NFSERR_ACCES, EACCES },
879 { NFSERR_EXIST, EEXIST },
880 { NFSERR_NODEV, ENODEV },
881 { NFSERR_NOTDIR, ENOTDIR },
882 { NFSERR_ISDIR, EISDIR },
884 { NFSERR_INVAL, EINVAL }, /* that Sun forgot */
886 { NFSERR_FBIG, EFBIG },
887 { NFSERR_NOSPC, ENOSPC },
888 { NFSERR_ROFS, EROFS },
889 { NFSERR_NAMETOOLONG, ENAMETOOLONG },
890 { NFSERR_NOTEMPTY, ENOTEMPTY },
891 { NFSERR_DQUOT, EDQUOT },
892 { NFSERR_STALE, ESTALE },
894 { NFSERR_WFLUSH, EWFLUSH },
896 /* Throw in some NFSv3 values for even more fun (HP returns these) */
902 static char *nfs_strerror(int status)
905 static char buf[256];
907 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
908 if (nfs_errtbl[i].stat == status)
909 return strerror(nfs_errtbl[i].errnum);
911 sprintf(buf, "unknown nfs status return value: %d", status);
916 xdr_fhandle (XDR *xdrs, fhandle objp)
918 if (!xdr_opaque (xdrs, objp, FHSIZE))
924 xdr_fhstatus (XDR *xdrs, fhstatus *objp)
926 if (!xdr_u_int (xdrs, &objp->fhs_status))
928 switch (objp->fhs_status) {
930 if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle))
940 xdr_dirpath (XDR *xdrs, dirpath *objp)
942 if (!xdr_string (xdrs, objp, MNTPATHLEN))
948 xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
950 if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
956 xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp)
958 if (!xdr_fhandle3 (xdrs, &objp->fhandle))
960 if (!xdr_array (xdrs, &(objp->auth_flavours.auth_flavours_val), &(objp->auth_flavours.auth_flavours_len), ~0,
961 sizeof (int), (xdrproc_t) xdr_int))
967 xdr_mountstat3 (XDR *xdrs, mountstat3 *objp)
969 if (!xdr_enum (xdrs, (enum_t *) objp))
975 xdr_mountres3 (XDR *xdrs, mountres3 *objp)
977 if (!xdr_mountstat3 (xdrs, &objp->fhs_status))
979 switch (objp->fhs_status) {
981 if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo))