1 /* vi: set sw=4 ts=4: */
3 * nfsmount.c -- Linux NFS mount
4 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
17 * numbers to be specified on the command line.
19 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
20 * Omit the call to connect() for Linux version 1.3.11 or later.
22 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
23 * Implemented the "bg", "fg" and "retry" mount options for NFS.
25 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
26 * - added Native Language Support
28 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
33 * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
41 #include <sys/socket.h>
43 #include <sys/utsname.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
51 #include <rpc/pmap_prot.h>
52 #include <rpc/pmap_clnt.h>
55 /* This is just a warning of a common mistake. Possibly this should be a
56 * uclibc faq entry rather than in busybox... */
57 #if ENABLE_FEATURE_MOUNT_NFS && defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
58 #error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
63 * NFS stats. The good thing with these values is that NFSv3 errors are
64 * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
65 * no-one uses anyway), so we can happily mix code as long as we make sure
66 * no NFSv3 errors are returned to NFSv2 clients.
67 * Error codes that have a `--' in the v2 column are not part of the
68 * standard, but seem to be widely used nevertheless.
71 NFS_OK = 0, /* v2 v3 */
72 NFSERR_PERM = 1, /* v2 v3 */
73 NFSERR_NOENT = 2, /* v2 v3 */
74 NFSERR_IO = 5, /* v2 v3 */
75 NFSERR_NXIO = 6, /* v2 v3 */
76 NFSERR_EAGAIN = 11, /* v2 v3 */
77 NFSERR_ACCES = 13, /* v2 v3 */
78 NFSERR_EXIST = 17, /* v2 v3 */
79 NFSERR_XDEV = 18, /* v3 */
80 NFSERR_NODEV = 19, /* v2 v3 */
81 NFSERR_NOTDIR = 20, /* v2 v3 */
82 NFSERR_ISDIR = 21, /* v2 v3 */
83 NFSERR_INVAL = 22, /* v2 v3 that Sun forgot */
84 NFSERR_FBIG = 27, /* v2 v3 */
85 NFSERR_NOSPC = 28, /* v2 v3 */
86 NFSERR_ROFS = 30, /* v2 v3 */
87 NFSERR_MLINK = 31, /* v3 */
88 NFSERR_OPNOTSUPP = 45, /* v2 v3 */
89 NFSERR_NAMETOOLONG = 63, /* v2 v3 */
90 NFSERR_NOTEMPTY = 66, /* v2 v3 */
91 NFSERR_DQUOT = 69, /* v2 v3 */
92 NFSERR_STALE = 70, /* v2 v3 */
93 NFSERR_REMOTE = 71, /* v2 v3 */
94 NFSERR_WFLUSH = 99, /* v2 */
95 NFSERR_BADHANDLE = 10001, /* v3 */
96 NFSERR_NOT_SYNC = 10002, /* v3 */
97 NFSERR_BAD_COOKIE = 10003, /* v3 */
98 NFSERR_NOTSUPP = 10004, /* v3 */
99 NFSERR_TOOSMALL = 10005, /* v3 */
100 NFSERR_SERVERFAULT = 10006, /* v3 */
101 NFSERR_BADTYPE = 10007, /* v3 */
102 NFSERR_JUKEBOX = 10008 /* v3 */
105 #define NFS_PROGRAM 100003
117 /* Disable the nls stuff */
118 # undef bindtextdomain
119 # define bindtextdomain(Domain, Directory) /* empty */
121 # define textdomain(Domain) /* empty */
124 MS_MGC_VAL = 0xc0ed0000, /* Magic number indicatng "new" flags */
125 MS_RDONLY = 1, /* Mount read-only */
126 MS_NOSUID = 2, /* Ignore suid and sgid bits */
127 MS_NODEV = 4, /* Disallow access to device special files */
128 MS_NOEXEC = 8, /* Disallow program execution */
129 MS_SYNCHRONOUS = 16, /* Writes are synced at once */
130 MS_REMOUNT = 32, /* Alter flags of a mounted FS */
131 MS_MANDLOCK = 64, /* Allow mandatory locks on an FS */
132 S_QUOTA = 128, /* Quota initialized for file/directory/symlink */
133 S_APPEND = 256, /* Append-only file */
134 S_IMMUTABLE = 512, /* Immutable file */
135 MS_NOATIME = 1024, /* Do not update access times. */
136 MS_NODIRATIME = 2048 /* Do not update directory access times */
141 * We want to be able to compile mount on old kernels in such a way
142 * that the binary will work well on more recent kernels.
143 * Thus, if necessary we teach nfsmount.c the structure of new fields
144 * that will come later.
146 * Moreover, the new kernel includes conflict with glibc includes
147 * so it is easiest to ignore the kernel altogether (at compile time).
150 /* NOTE: Do not make this into a 'static const int' because the pre-processor
151 * needs to test this value in some #if statements. */
152 #define NFS_MOUNT_VERSION 4
159 unsigned char data[64];
162 struct nfs_mount_data {
165 struct nfs2_fh old_root; /* 1 */
171 int acregmin; /* 1 */
172 int acregmax; /* 1 */
173 int acdirmin; /* 1 */
174 int acdirmax; /* 1 */
175 struct sockaddr_in addr; /* 1 */
176 char hostname[256]; /* 1 */
178 unsigned int bsize; /* 3 */
179 struct nfs3_fh root; /* 4 */
182 /* bits in the flags field */
184 NFS_MOUNT_SOFT = 0x0001, /* 1 */
185 NFS_MOUNT_INTR = 0x0002, /* 1 */
186 NFS_MOUNT_SECURE = 0x0004, /* 1 */
187 NFS_MOUNT_POSIX = 0x0008, /* 1 */
188 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
189 NFS_MOUNT_NOAC = 0x0020, /* 1 */
190 NFS_MOUNT_TCP = 0x0040, /* 2 */
191 NFS_MOUNT_VER3 = 0x0080, /* 3 */
192 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
193 NFS_MOUNT_NONLM = 0x0200 /* 3 */
197 #define UTIL_LINUX_VERSION "2.10m"
198 #define util_linux_version "util-linux-2.10m"
200 #define HAVE_inet_aton
205 #define HAVE_locale_h
206 #define HAVE_libintl_h
208 #define HAVE_langinfo_h
209 #define HAVE_progname
211 #define HAVE_nanosleep
212 #define HAVE_personality
213 #define HAVE_tm_gmtoff
215 static char *nfs_strerror(int status);
217 #define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
218 #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
221 EX_FAIL = 32, /* mount failure */
222 EX_BG = 256 /* retry in background (internal only) */
227 * nfs_mount_version according to the sources seen at compile time.
229 static int nfs_mount_version;
232 * Unfortunately, the kernel prints annoying console messages
233 * in case of an unexpected nfs mount version (instead of
234 * just returning some error). Therefore we'll have to try
235 * and figure out what version the kernel expects.
238 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
239 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
240 * nfs_mount_version: version this source and running kernel can handle
243 find_kernel_nfs_mount_version(void)
245 static int kernel_version = 0;
250 nfs_mount_version = NFS_MOUNT_VERSION; /* default */
252 kernel_version = get_kernel_revision();
253 if (kernel_version) {
254 if (kernel_version < MAKE_VERSION(2,1,32))
255 nfs_mount_version = 1;
256 else if (kernel_version < MAKE_VERSION(2,2,18) ||
257 (kernel_version >= MAKE_VERSION(2,3,0) &&
258 kernel_version < MAKE_VERSION(2,3,99)))
259 nfs_mount_version = 3;
261 nfs_mount_version = 4; /* since 2.3.99pre4 */
263 if (nfs_mount_version > NFS_MOUNT_VERSION)
264 nfs_mount_version = NFS_MOUNT_VERSION;
268 get_mountport(struct sockaddr_in *server_addr,
270 long unsigned version,
274 struct pmaplist *pmap;
275 static struct pmap p = {0, 0, 0, 0};
277 server_addr->sin_port = PMAPPORT;
278 pmap = pmap_getmaps(server_addr);
280 if (version > MAX_NFSPROT)
281 version = MAX_NFSPROT;
290 if (pmap->pml_map.pm_prog != prog)
292 if (!version && p.pm_vers > pmap->pml_map.pm_vers)
294 if (version > 2 && pmap->pml_map.pm_vers != version)
296 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
298 if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
299 (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
300 (port && pmap->pml_map.pm_port != port))
302 memcpy(&p, &pmap->pml_map, sizeof(p));
304 pmap = pmap->pml_next;
307 p.pm_vers = MOUNTVERS;
309 p.pm_port = MOUNTPORT;
311 p.pm_prot = IPPROTO_TCP;
315 int nfsmount(const char *spec, const char *node, int *flags,
316 char **mount_opts, int running_bg)
318 static char *prev_bg_host;
324 char *mounthost=NULL;
326 struct timeval total_timeout;
327 enum clnt_stat clnt_stat;
328 struct nfs_mount_data data;
332 struct sockaddr_in server_addr;
333 struct sockaddr_in mount_server_addr;
336 struct timeval retry_timeout;
338 struct fhstatus nfsv2;
339 struct mountres3 nfsv3;
364 find_kernel_nfs_mount_version();
369 if (strlen(spec) >= sizeof(hostdir)) {
370 bb_error_msg("excessively long host:dir argument");
373 strcpy(hostdir, spec);
374 if ((s = strchr(hostdir, ':'))) {
378 /* Ignore all but first hostname in replicated mounts
379 until they can be fully supported. (mack@sgi.com) */
380 if ((s = strchr(hostdir, ','))) {
382 bb_error_msg("warning: multiple hostnames not supported");
385 bb_error_msg("directory to mount not in host:dir format");
389 server_addr.sin_family = AF_INET;
390 #ifdef HAVE_inet_aton
391 if (!inet_aton(hostname, &server_addr.sin_addr))
394 if ((hp = gethostbyname(hostname)) == NULL) {
395 bb_herror_msg("%s", hostname);
398 if (hp->h_length > sizeof(struct in_addr)) {
399 bb_error_msg("got bad hp->h_length");
400 hp->h_length = sizeof(struct in_addr);
402 memcpy(&server_addr.sin_addr,
403 hp->h_addr, hp->h_length);
407 memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
409 /* add IP address to mtab options for use when unmounting */
411 s = inet_ntoa(server_addr.sin_addr);
412 old_opts = *mount_opts;
415 if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
416 bb_error_msg("excessively long option argument");
419 sprintf(new_opts, "%s%saddr=%s",
420 old_opts, *old_opts ? "," : "", s);
421 *mount_opts = bb_xstrdup(new_opts);
423 /* Set default options.
424 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
425 * let the kernel decide.
426 * timeo is filled in after we know whether it'll be TCP or UDP. */
427 memset(&data, 0, sizeof(data));
433 #if NFS_MOUNT_VERSION >= 2
434 data.namlen = NAME_MAX;
444 retry = 10000; /* 10000 minutes ~ 1 week */
447 mountprog = MOUNTPROG;
451 nfsprog = NFS_PROGRAM;
456 for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
457 if ((opteq = strchr(opt, '='))) {
458 val = atoi(opteq + 1);
460 if (!strcmp(opt, "rsize"))
462 else if (!strcmp(opt, "wsize"))
464 else if (!strcmp(opt, "timeo"))
466 else if (!strcmp(opt, "retrans"))
468 else if (!strcmp(opt, "acregmin"))
470 else if (!strcmp(opt, "acregmax"))
472 else if (!strcmp(opt, "acdirmin"))
474 else if (!strcmp(opt, "acdirmax"))
476 else if (!strcmp(opt, "actimeo")) {
482 else if (!strcmp(opt, "retry"))
484 else if (!strcmp(opt, "port"))
486 else if (!strcmp(opt, "mountport"))
488 else if (!strcmp(opt, "mounthost"))
489 mounthost=bb_xstrndup(opteq+1,
490 strcspn(opteq+1," \t\n\r,"));
491 else if (!strcmp(opt, "mountprog"))
493 else if (!strcmp(opt, "mountvers"))
495 else if (!strcmp(opt, "nfsprog"))
497 else if (!strcmp(opt, "nfsvers") ||
498 !strcmp(opt, "vers"))
500 else if (!strcmp(opt, "proto")) {
501 if (!strncmp(opteq+1, "tcp", 3))
503 else if (!strncmp(opteq+1, "udp", 3))
506 printf(_("Warning: Unrecognized proto= option.\n"));
507 } else if (!strcmp(opt, "namlen")) {
508 #if NFS_MOUNT_VERSION >= 2
509 if (nfs_mount_version >= 2)
513 printf(_("Warning: Option namlen is not supported.\n"));
514 } else if (!strcmp(opt, "addr"))
517 printf(_("unknown nfs mount parameter: "
518 "%s=%d\n"), opt, val);
524 if (!strncmp(opt, "no", 2)) {
528 if (!strcmp(opt, "bg"))
530 else if (!strcmp(opt, "fg"))
532 else if (!strcmp(opt, "soft"))
534 else if (!strcmp(opt, "hard"))
536 else if (!strcmp(opt, "intr"))
538 else if (!strcmp(opt, "posix"))
540 else if (!strcmp(opt, "cto"))
542 else if (!strcmp(opt, "ac"))
544 else if (!strcmp(opt, "tcp"))
546 else if (!strcmp(opt, "udp"))
548 else if (!strcmp(opt, "lock")) {
549 if (nfs_mount_version >= 3)
552 printf(_("Warning: option nolock is not supported.\n"));
554 printf(_("unknown nfs mount option: "
555 "%s%s\n"), val ? "" : "no", opt);
560 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
562 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
563 | (intr ? NFS_MOUNT_INTR : 0)
564 | (posix ? NFS_MOUNT_POSIX : 0)
565 | (nocto ? NFS_MOUNT_NOCTO : 0)
566 | (noac ? NFS_MOUNT_NOAC : 0);
567 #if NFS_MOUNT_VERSION >= 2
568 if (nfs_mount_version >= 2)
569 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
571 #if NFS_MOUNT_VERSION >= 3
572 if (nfs_mount_version >= 3)
573 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
575 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
576 bb_error_msg("NFSv%d not supported!", nfsvers);
579 if (nfsvers && !mountvers)
580 mountvers = (nfsvers < 3) ? 1 : nfsvers;
581 if (nfsvers && nfsvers < mountvers) {
585 /* Adjust options if none specified */
587 data.timeo = tcp ? 70 : 7;
589 #ifdef NFS_MOUNT_DEBUG
590 printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
591 data.rsize, data.wsize, data.timeo, data.retrans);
592 printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
593 data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
594 printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
595 port, bg, retry, data.flags);
596 printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
597 mountprog, mountvers, nfsprog, nfsvers);
598 printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
599 (data.flags & NFS_MOUNT_SOFT) != 0,
600 (data.flags & NFS_MOUNT_INTR) != 0,
601 (data.flags & NFS_MOUNT_POSIX) != 0,
602 (data.flags & NFS_MOUNT_NOCTO) != 0,
603 (data.flags & NFS_MOUNT_NOAC) != 0);
604 #if NFS_MOUNT_VERSION >= 2
606 (data.flags & NFS_MOUNT_TCP) != 0);
610 data.version = nfs_mount_version;
612 if (*flags & MS_REMOUNT)
613 goto copy_data_and_return;
616 * If the previous mount operation on the same host was
617 * backgrounded, and the "bg" for this mount is also set,
618 * give up immediately, to avoid the initial timeout.
620 if (bg && !running_bg &&
621 prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
627 /* create mount deamon client */
628 /* See if the nfs host = mount host. */
630 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
631 mount_server_addr.sin_family = AF_INET;
632 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
634 if ((hp = gethostbyname(mounthost)) == NULL) {
635 bb_herror_msg("%s", mounthost);
638 if (hp->h_length > sizeof(struct in_addr)) {
639 bb_error_msg("got bad hp->h_length?");
640 hp->h_length = sizeof(struct in_addr);
642 mount_server_addr.sin_family = AF_INET;
643 memcpy(&mount_server_addr.sin_addr,
644 hp->h_addr, hp->h_length);
650 * The following loop implements the mount retries. On the first
651 * call, "running_bg" is 0. When the mount times out, and the
652 * "bg" option is set, the exit status EX_BG will be returned.
653 * For a backgrounded mount, there will be a second call by the
654 * child process with "running_bg" set to 1.
656 * The case where the mount point is not present and the "bg"
657 * option is set, is treated as a timeout. This is done to
658 * support nested mounts.
660 * The "retry" count specified by the user is the number of
661 * minutes to retry before giving up.
663 * Only the first error message will be displayed.
665 retry_timeout.tv_sec = 3;
666 retry_timeout.tv_usec = 0;
667 total_timeout.tv_sec = 20;
668 total_timeout.tv_usec = 0;
669 timeout = time(NULL) + 60 * retry;
674 if (bg && stat(node, &statbuf) == -1) {
676 sleep(val); /* 1, 2, 4, 8, 16, 30, ... */
682 /* be careful not to use too many CPU cycles */
686 pm_mnt = get_mountport(&mount_server_addr,
692 /* contact the mount daemon via TCP */
693 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
696 switch (pm_mnt->pm_prot) {
698 mclient = clntudp_create(&mount_server_addr,
705 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
708 mclient = clnttcp_create(&mount_server_addr,
717 /* try to mount hostname:pathname */
718 mclient->cl_auth = authunix_create_default();
720 /* make pointers in xdr_mountres3 NULL so
721 * that xdr_array allocates memory for us
723 memset(&status, 0, sizeof(status));
725 if (pm_mnt->pm_vers == 3)
726 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
727 (xdrproc_t) xdr_dirpath,
729 (xdrproc_t) xdr_mountres3,
733 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
734 (xdrproc_t) xdr_dirpath,
736 (xdrproc_t) xdr_fhstatus,
740 if (clnt_stat == RPC_SUCCESS)
741 break; /* we're done */
742 if (errno != ECONNREFUSED) {
743 clnt_perror(mclient, "mount");
744 goto fail; /* don't retry */
746 if (!running_bg && prevt == 0)
747 clnt_perror(mclient, "mount");
748 auth_destroy(mclient->cl_auth);
749 clnt_destroy(mclient);
753 if (!running_bg && prevt == 0)
754 clnt_pcreateerror("mount");
761 prev_bg_host = bb_xstrdup(hostname);
770 nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
773 if (status.nfsv2.fhs_status != 0) {
774 bb_error_msg("%s:%s failed, reason given by server: %s",
776 nfs_strerror(status.nfsv2.fhs_status));
779 memcpy(data.root.data,
780 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
782 #if NFS_MOUNT_VERSION >= 4
783 data.root.size = NFS_FHSIZE;
784 memcpy(data.old_root.data,
785 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
789 #if NFS_MOUNT_VERSION >= 4
790 fhandle3 *my_fhandle;
791 if (status.nfsv3.fhs_status != 0) {
792 bb_error_msg("%s:%s failed, reason given by server: %s",
794 nfs_strerror(status.nfsv3.fhs_status));
797 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
798 memset(data.old_root.data, 0, NFS_FHSIZE);
799 memset(&data.root, 0, sizeof(data.root));
800 data.root.size = my_fhandle->fhandle3_len;
801 memcpy(data.root.data,
802 (char *) my_fhandle->fhandle3_val,
803 my_fhandle->fhandle3_len);
805 data.flags |= NFS_MOUNT_VER3;
809 /* create nfs socket for kernel */
812 if (nfs_mount_version < 3) {
813 printf(_("NFS over TCP is not supported.\n"));
816 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
818 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
820 perror(_("nfs socket"));
823 if (bindresvport(fsock, 0) < 0) {
824 perror(_("nfs bindresvport"));
828 server_addr.sin_port = PMAPPORT;
829 port = pmap_getport(&server_addr, nfsprog, nfsvers,
830 tcp ? IPPROTO_TCP : IPPROTO_UDP);
833 #ifdef NFS_MOUNT_DEBUG
835 printf(_("used portmapper to find NFS port\n"));
838 #ifdef NFS_MOUNT_DEBUG
839 printf(_("using port %d for nfs deamon\n"), port);
841 server_addr.sin_port = htons(port);
843 * connect() the socket for kernels 1.3.10 and below only,
844 * to avoid problems with multihomed hosts.
847 if (get_kernel_revision() <= 66314
848 && connect(fsock, (struct sockaddr *) &server_addr,
849 sizeof (server_addr)) < 0) {
850 perror(_("nfs connect"));
854 /* prepare data structure for kernel */
857 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
858 strncpy(data.hostname, hostname, sizeof(data.hostname));
862 auth_destroy(mclient->cl_auth);
863 clnt_destroy(mclient);
865 copy_data_and_return:
866 *mount_opts = xrealloc(*mount_opts, sizeof(data));
867 memcpy(*mount_opts, &data, sizeof(data));
875 auth_destroy(mclient->cl_auth);
876 clnt_destroy(mclient);
886 * We need to translate between nfs status return values and
887 * the local errno values which may not be the same.
889 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
890 * "after #include <errno.h> the symbol errno is reserved for any use,
891 * it cannot even be used as a struct tag or field name".
895 #define EDQUOT ENOSPC
898 static const struct {
903 { NFSERR_PERM, EPERM },
904 { NFSERR_NOENT, ENOENT },
906 { NFSERR_NXIO, ENXIO },
907 { NFSERR_ACCES, EACCES },
908 { NFSERR_EXIST, EEXIST },
909 { NFSERR_NODEV, ENODEV },
910 { NFSERR_NOTDIR, ENOTDIR },
911 { NFSERR_ISDIR, EISDIR },
913 { NFSERR_INVAL, EINVAL }, /* that Sun forgot */
915 { NFSERR_FBIG, EFBIG },
916 { NFSERR_NOSPC, ENOSPC },
917 { NFSERR_ROFS, EROFS },
918 { NFSERR_NAMETOOLONG, ENAMETOOLONG },
919 { NFSERR_NOTEMPTY, ENOTEMPTY },
920 { NFSERR_DQUOT, EDQUOT },
921 { NFSERR_STALE, ESTALE },
923 { NFSERR_WFLUSH, EWFLUSH },
925 /* Throw in some NFSv3 values for even more fun (HP returns these) */
931 static char *nfs_strerror(int status)
934 static char buf[256];
936 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
937 if (nfs_errtbl[i].stat == status)
938 return strerror(nfs_errtbl[i].errnum);
940 sprintf(buf, _("unknown nfs status return value: %d"), status);
945 xdr_fhandle (XDR *xdrs, fhandle objp)
947 if (!xdr_opaque (xdrs, objp, FHSIZE))
953 xdr_fhstatus (XDR *xdrs, fhstatus *objp)
955 if (!xdr_u_int (xdrs, &objp->fhs_status))
957 switch (objp->fhs_status) {
959 if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle))
969 xdr_dirpath (XDR *xdrs, dirpath *objp)
971 if (!xdr_string (xdrs, objp, MNTPATHLEN))
977 xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
979 if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
985 xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp)
987 if (!xdr_fhandle3 (xdrs, &objp->fhandle))
989 if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (unsigned int *) &objp->auth_flavours.auth_flavours_len, ~0,
990 sizeof (int), (xdrproc_t) xdr_int))
996 xdr_mountstat3 (XDR *xdrs, mountstat3 *objp)
998 if (!xdr_enum (xdrs, (enum_t *) objp))
1004 xdr_mountres3 (XDR *xdrs, mountres3 *objp)
1006 if (!xdr_mountstat3 (xdrs, &objp->fhs_status))
1008 switch (objp->fhs_status) {
1010 if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo))