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
110 static const int NFS_FHSIZE = 32;
113 static const int NFS_PORT = 2049;
116 /* Disable the nls stuff */
117 # undef bindtextdomain
118 # define bindtextdomain(Domain, Directory) /* empty */
120 # define textdomain(Domain) /* empty */
121 # define _(Text) (Text)
122 # define N_(Text) (Text)
124 static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */
125 static const int MS_RDONLY = 1; /* Mount read-only */
126 static const int MS_NOSUID = 2; /* Ignore suid and sgid bits */
127 static const int MS_NODEV = 4; /* Disallow access to device special files */
128 static const int MS_NOEXEC = 8; /* Disallow program execution */
129 static const int MS_SYNCHRONOUS = 16; /* Writes are synced at once */
130 static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS */
131 static const int MS_MANDLOCK = 64; /* Allow mandatory locks on an FS */
132 static const int S_QUOTA = 128; /* Quota initialized for file/directory/symlink */
133 static const int S_APPEND = 256; /* Append-only file */
134 static const int S_IMMUTABLE = 512; /* Immutable file */
135 static const int MS_NOATIME = 1024; /* Do not update access times. */
136 static const int MS_NODIRATIME = 2048; /* Do not update directory access times */
140 * We want to be able to compile mount on old kernels in such a way
141 * that the binary will work well on more recent kernels.
142 * Thus, if necessary we teach nfsmount.c the structure of new fields
143 * that will come later.
145 * Moreover, the new kernel includes conflict with glibc includes
146 * so it is easiest to ignore the kernel altogether (at compile time).
149 /* NOTE: Do not make this into a 'static const int' because the pre-processor
150 * needs to test this value in some #if statements. */
151 #define NFS_MOUNT_VERSION 4
158 unsigned char data[64];
161 struct nfs_mount_data {
164 struct nfs2_fh old_root; /* 1 */
170 int acregmin; /* 1 */
171 int acregmax; /* 1 */
172 int acdirmin; /* 1 */
173 int acdirmax; /* 1 */
174 struct sockaddr_in addr; /* 1 */
175 char hostname[256]; /* 1 */
177 unsigned int bsize; /* 3 */
178 struct nfs3_fh root; /* 4 */
181 /* bits in the flags field */
183 static const int NFS_MOUNT_SOFT = 0x0001; /* 1 */
184 static const int NFS_MOUNT_INTR = 0x0002; /* 1 */
185 static const int NFS_MOUNT_SECURE = 0x0004; /* 1 */
186 static const int NFS_MOUNT_POSIX = 0x0008; /* 1 */
187 static const int NFS_MOUNT_NOCTO = 0x0010; /* 1 */
188 static const int NFS_MOUNT_NOAC = 0x0020; /* 1 */
189 static const int NFS_MOUNT_TCP = 0x0040; /* 2 */
190 static const int NFS_MOUNT_VER3 = 0x0080; /* 3 */
191 static const int NFS_MOUNT_KERBEROS = 0x0100; /* 3 */
192 static const int NFS_MOUNT_NONLM = 0x0200; /* 3 */
195 #define UTIL_LINUX_VERSION "2.10m"
196 #define util_linux_version "util-linux-2.10m"
198 #define HAVE_inet_aton
203 #define HAVE_locale_h
204 #define HAVE_libintl_h
206 #define HAVE_langinfo_h
207 #define HAVE_progname
209 #define HAVE_nanosleep
210 #define HAVE_personality
211 #define HAVE_tm_gmtoff
213 static char *nfs_strerror(int status);
215 #define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
216 #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
218 static const int EX_FAIL = 32; /* mount failure */
219 static const int EX_BG = 256; /* retry in background (internal only) */
223 * nfs_mount_version according to the sources seen at compile time.
225 static int nfs_mount_version;
228 * Unfortunately, the kernel prints annoying console messages
229 * in case of an unexpected nfs mount version (instead of
230 * just returning some error). Therefore we'll have to try
231 * and figure out what version the kernel expects.
234 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
235 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
236 * nfs_mount_version: version this source and running kernel can handle
239 find_kernel_nfs_mount_version(void)
241 static int kernel_version = 0;
246 nfs_mount_version = NFS_MOUNT_VERSION; /* default */
248 kernel_version = get_kernel_revision();
249 if (kernel_version) {
250 if (kernel_version < MAKE_VERSION(2,1,32))
251 nfs_mount_version = 1;
252 else if (kernel_version < MAKE_VERSION(2,2,18) ||
253 (kernel_version >= MAKE_VERSION(2,3,0) &&
254 kernel_version < MAKE_VERSION(2,3,99)))
255 nfs_mount_version = 3;
257 nfs_mount_version = 4; /* since 2.3.99pre4 */
259 if (nfs_mount_version > NFS_MOUNT_VERSION)
260 nfs_mount_version = NFS_MOUNT_VERSION;
264 get_mountport(struct sockaddr_in *server_addr,
266 long unsigned version,
270 struct pmaplist *pmap;
271 static struct pmap p = {0, 0, 0, 0};
273 server_addr->sin_port = PMAPPORT;
274 pmap = pmap_getmaps(server_addr);
276 if (version > MAX_NFSPROT)
277 version = MAX_NFSPROT;
286 if (pmap->pml_map.pm_prog != prog)
288 if (!version && p.pm_vers > pmap->pml_map.pm_vers)
290 if (version > 2 && pmap->pml_map.pm_vers != version)
292 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
294 if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
295 (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
296 (port && pmap->pml_map.pm_port != port))
298 memcpy(&p, &pmap->pml_map, sizeof(p));
300 pmap = pmap->pml_next;
303 p.pm_vers = MOUNTVERS;
305 p.pm_port = MOUNTPORT;
307 p.pm_prot = IPPROTO_TCP;
311 int nfsmount(const char *spec, const char *node, int *flags,
312 char **mount_opts, int running_bg)
314 static char *prev_bg_host;
320 char *mounthost=NULL;
322 struct timeval total_timeout;
323 enum clnt_stat clnt_stat;
324 struct nfs_mount_data data;
328 struct sockaddr_in server_addr;
329 struct sockaddr_in mount_server_addr;
332 struct timeval retry_timeout;
334 struct fhstatus nfsv2;
335 struct mountres3 nfsv3;
360 find_kernel_nfs_mount_version();
365 if (strlen(spec) >= sizeof(hostdir)) {
366 bb_error_msg("excessively long host:dir argument");
369 strcpy(hostdir, spec);
370 if ((s = strchr(hostdir, ':'))) {
374 /* Ignore all but first hostname in replicated mounts
375 until they can be fully supported. (mack@sgi.com) */
376 if ((s = strchr(hostdir, ','))) {
378 bb_error_msg("warning: multiple hostnames not supported");
381 bb_error_msg("directory to mount not in host:dir format");
385 server_addr.sin_family = AF_INET;
386 #ifdef HAVE_inet_aton
387 if (!inet_aton(hostname, &server_addr.sin_addr))
390 if ((hp = gethostbyname(hostname)) == NULL) {
391 bb_herror_msg("%s", hostname);
394 if (hp->h_length > sizeof(struct in_addr)) {
395 bb_error_msg("got bad hp->h_length");
396 hp->h_length = sizeof(struct in_addr);
398 memcpy(&server_addr.sin_addr,
399 hp->h_addr, hp->h_length);
403 memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
405 /* add IP address to mtab options for use when unmounting */
407 s = inet_ntoa(server_addr.sin_addr);
408 old_opts = *mount_opts;
411 if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
412 bb_error_msg("excessively long option argument");
415 sprintf(new_opts, "%s%saddr=%s",
416 old_opts, *old_opts ? "," : "", s);
417 *mount_opts = bb_xstrdup(new_opts);
419 /* Set default options.
420 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
421 * let the kernel decide.
422 * timeo is filled in after we know whether it'll be TCP or UDP. */
423 memset(&data, 0, sizeof(data));
429 #if NFS_MOUNT_VERSION >= 2
430 data.namlen = NAME_MAX;
440 retry = 10000; /* 10000 minutes ~ 1 week */
443 mountprog = MOUNTPROG;
447 nfsprog = NFS_PROGRAM;
452 for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
453 if ((opteq = strchr(opt, '='))) {
454 val = atoi(opteq + 1);
456 if (!strcmp(opt, "rsize"))
458 else if (!strcmp(opt, "wsize"))
460 else if (!strcmp(opt, "timeo"))
462 else if (!strcmp(opt, "retrans"))
464 else if (!strcmp(opt, "acregmin"))
466 else if (!strcmp(opt, "acregmax"))
468 else if (!strcmp(opt, "acdirmin"))
470 else if (!strcmp(opt, "acdirmax"))
472 else if (!strcmp(opt, "actimeo")) {
478 else if (!strcmp(opt, "retry"))
480 else if (!strcmp(opt, "port"))
482 else if (!strcmp(opt, "mountport"))
484 else if (!strcmp(opt, "mounthost"))
485 mounthost=bb_xstrndup(opteq+1,
486 strcspn(opteq+1," \t\n\r,"));
487 else if (!strcmp(opt, "mountprog"))
489 else if (!strcmp(opt, "mountvers"))
491 else if (!strcmp(opt, "nfsprog"))
493 else if (!strcmp(opt, "nfsvers") ||
494 !strcmp(opt, "vers"))
496 else if (!strcmp(opt, "proto")) {
497 if (!strncmp(opteq+1, "tcp", 3))
499 else if (!strncmp(opteq+1, "udp", 3))
502 printf(_("Warning: Unrecognized proto= option.\n"));
503 } else if (!strcmp(opt, "namlen")) {
504 #if NFS_MOUNT_VERSION >= 2
505 if (nfs_mount_version >= 2)
509 printf(_("Warning: Option namlen is not supported.\n"));
510 } else if (!strcmp(opt, "addr"))
513 printf(_("unknown nfs mount parameter: "
514 "%s=%d\n"), opt, val);
520 if (!strncmp(opt, "no", 2)) {
524 if (!strcmp(opt, "bg"))
526 else if (!strcmp(opt, "fg"))
528 else if (!strcmp(opt, "soft"))
530 else if (!strcmp(opt, "hard"))
532 else if (!strcmp(opt, "intr"))
534 else if (!strcmp(opt, "posix"))
536 else if (!strcmp(opt, "cto"))
538 else if (!strcmp(opt, "ac"))
540 else if (!strcmp(opt, "tcp"))
542 else if (!strcmp(opt, "udp"))
544 else if (!strcmp(opt, "lock")) {
545 if (nfs_mount_version >= 3)
548 printf(_("Warning: option nolock is not supported.\n"));
550 printf(_("unknown nfs mount option: "
551 "%s%s\n"), val ? "" : "no", opt);
556 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
558 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
559 | (intr ? NFS_MOUNT_INTR : 0)
560 | (posix ? NFS_MOUNT_POSIX : 0)
561 | (nocto ? NFS_MOUNT_NOCTO : 0)
562 | (noac ? NFS_MOUNT_NOAC : 0);
563 #if NFS_MOUNT_VERSION >= 2
564 if (nfs_mount_version >= 2)
565 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
567 #if NFS_MOUNT_VERSION >= 3
568 if (nfs_mount_version >= 3)
569 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
571 if (nfsvers > MAX_NFSPROT) {
572 bb_error_msg("NFSv%d not supported!", nfsvers);
575 if (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 //register int32_t *buf;
949 if (!xdr_opaque (xdrs, objp, FHSIZE))
955 xdr_fhstatus (XDR *xdrs, fhstatus *objp)
957 //register int32_t *buf;
959 if (!xdr_u_int (xdrs, &objp->fhs_status))
961 switch (objp->fhs_status) {
963 if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle))
973 xdr_dirpath (XDR *xdrs, dirpath *objp)
975 //register int32_t *buf;
977 if (!xdr_string (xdrs, objp, MNTPATHLEN))
983 xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
985 //register int32_t *buf;
987 if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
993 xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp)
995 //register int32_t *buf;
997 if (!xdr_fhandle3 (xdrs, &objp->fhandle))
999 if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (unsigned int *) &objp->auth_flavours.auth_flavours_len, ~0,
1000 sizeof (int), (xdrproc_t) xdr_int))
1006 xdr_mountstat3 (XDR *xdrs, mountstat3 *objp)
1008 //register int32_t *buf;
1010 if (!xdr_enum (xdrs, (enum_t *) objp))
1016 xdr_mountres3 (XDR *xdrs, mountres3 *objp)
1018 //register int32_t *buf;
1020 if (!xdr_mountstat3 (xdrs, &objp->fhs_status))
1022 switch (objp->fhs_status) {
1024 if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo))