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>
57 * NFS stats. The good thing with these values is that NFSv3 errors are
58 * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
59 * no-one uses anyway), so we can happily mix code as long as we make sure
60 * no NFSv3 errors are returned to NFSv2 clients.
61 * Error codes that have a `--' in the v2 column are not part of the
62 * standard, but seem to be widely used nevertheless.
65 NFS_OK = 0, /* v2 v3 */
66 NFSERR_PERM = 1, /* v2 v3 */
67 NFSERR_NOENT = 2, /* v2 v3 */
68 NFSERR_IO = 5, /* v2 v3 */
69 NFSERR_NXIO = 6, /* v2 v3 */
70 NFSERR_EAGAIN = 11, /* v2 v3 */
71 NFSERR_ACCES = 13, /* v2 v3 */
72 NFSERR_EXIST = 17, /* v2 v3 */
73 NFSERR_XDEV = 18, /* v3 */
74 NFSERR_NODEV = 19, /* v2 v3 */
75 NFSERR_NOTDIR = 20, /* v2 v3 */
76 NFSERR_ISDIR = 21, /* v2 v3 */
77 NFSERR_INVAL = 22, /* v2 v3 that Sun forgot */
78 NFSERR_FBIG = 27, /* v2 v3 */
79 NFSERR_NOSPC = 28, /* v2 v3 */
80 NFSERR_ROFS = 30, /* v2 v3 */
81 NFSERR_MLINK = 31, /* v3 */
82 NFSERR_OPNOTSUPP = 45, /* v2 v3 */
83 NFSERR_NAMETOOLONG = 63, /* v2 v3 */
84 NFSERR_NOTEMPTY = 66, /* v2 v3 */
85 NFSERR_DQUOT = 69, /* v2 v3 */
86 NFSERR_STALE = 70, /* v2 v3 */
87 NFSERR_REMOTE = 71, /* v2 v3 */
88 NFSERR_WFLUSH = 99, /* v2 */
89 NFSERR_BADHANDLE = 10001, /* v3 */
90 NFSERR_NOT_SYNC = 10002, /* v3 */
91 NFSERR_BAD_COOKIE = 10003, /* v3 */
92 NFSERR_NOTSUPP = 10004, /* v3 */
93 NFSERR_TOOSMALL = 10005, /* v3 */
94 NFSERR_SERVERFAULT = 10006, /* v3 */
95 NFSERR_BADTYPE = 10007, /* v3 */
96 NFSERR_JUKEBOX = 10008 /* v3 */
99 #define NFS_PROGRAM 100003
104 static const int NFS_FHSIZE = 32;
107 static const int NFS_PORT = 2049;
110 /* Disable the nls stuff */
111 # undef bindtextdomain
112 # define bindtextdomain(Domain, Directory) /* empty */
114 # define textdomain(Domain) /* empty */
115 # define _(Text) (Text)
116 # define N_(Text) (Text)
118 static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */
119 static const int MS_RDONLY = 1; /* Mount read-only */
120 static const int MS_NOSUID = 2; /* Ignore suid and sgid bits */
121 static const int MS_NODEV = 4; /* Disallow access to device special files */
122 static const int MS_NOEXEC = 8; /* Disallow program execution */
123 static const int MS_SYNCHRONOUS = 16; /* Writes are synced at once */
124 static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS */
125 static const int MS_MANDLOCK = 64; /* Allow mandatory locks on an FS */
126 static const int S_QUOTA = 128; /* Quota initialized for file/directory/symlink */
127 static const int S_APPEND = 256; /* Append-only file */
128 static const int S_IMMUTABLE = 512; /* Immutable file */
129 static const int MS_NOATIME = 1024; /* Do not update access times. */
130 static const int MS_NODIRATIME = 2048; /* Do not update directory access times */
134 * We want to be able to compile mount on old kernels in such a way
135 * that the binary will work well on more recent kernels.
136 * Thus, if necessary we teach nfsmount.c the structure of new fields
137 * that will come later.
139 * Moreover, the new kernel includes conflict with glibc includes
140 * so it is easiest to ignore the kernel altogether (at compile time).
143 /* NOTE: Do not make this into a 'static const int' because the pre-processor
144 * needs to test this value in some #if statements. */
145 #define NFS_MOUNT_VERSION 4
152 unsigned char data[64];
155 struct nfs_mount_data {
158 struct nfs2_fh old_root; /* 1 */
164 int acregmin; /* 1 */
165 int acregmax; /* 1 */
166 int acdirmin; /* 1 */
167 int acdirmax; /* 1 */
168 struct sockaddr_in addr; /* 1 */
169 char hostname[256]; /* 1 */
171 unsigned int bsize; /* 3 */
172 struct nfs3_fh root; /* 4 */
175 /* bits in the flags field */
177 static const int NFS_MOUNT_SOFT = 0x0001; /* 1 */
178 static const int NFS_MOUNT_INTR = 0x0002; /* 1 */
179 static const int NFS_MOUNT_SECURE = 0x0004; /* 1 */
180 static const int NFS_MOUNT_POSIX = 0x0008; /* 1 */
181 static const int NFS_MOUNT_NOCTO = 0x0010; /* 1 */
182 static const int NFS_MOUNT_NOAC = 0x0020; /* 1 */
183 static const int NFS_MOUNT_TCP = 0x0040; /* 2 */
184 static const int NFS_MOUNT_VER3 = 0x0080; /* 3 */
185 static const int NFS_MOUNT_KERBEROS = 0x0100; /* 3 */
186 static const int NFS_MOUNT_NONLM = 0x0200; /* 3 */
189 #define UTIL_LINUX_VERSION "2.10m"
190 #define util_linux_version "util-linux-2.10m"
192 #define HAVE_inet_aton
197 #define HAVE_locale_h
198 #define HAVE_libintl_h
200 #define HAVE_langinfo_h
201 #define HAVE_progname
203 #define HAVE_nanosleep
204 #define HAVE_personality
205 #define HAVE_tm_gmtoff
207 static char *nfs_strerror(int status);
209 #define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r))
210 #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
212 static const int EX_FAIL = 32; /* mount failure */
213 static const int EX_BG = 256; /* retry in background (internal only) */
217 * nfs_mount_version according to the sources seen at compile time.
219 static int nfs_mount_version;
222 * Unfortunately, the kernel prints annoying console messages
223 * in case of an unexpected nfs mount version (instead of
224 * just returning some error). Therefore we'll have to try
225 * and figure out what version the kernel expects.
228 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
229 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
230 * nfs_mount_version: version this source and running kernel can handle
233 find_kernel_nfs_mount_version(void)
235 static int kernel_version = 0;
240 nfs_mount_version = NFS_MOUNT_VERSION; /* default */
242 kernel_version = get_kernel_revision();
243 if (kernel_version) {
244 if (kernel_version < MAKE_VERSION(2,1,32))
245 nfs_mount_version = 1;
246 else if (kernel_version < MAKE_VERSION(2,2,18) ||
247 (kernel_version >= MAKE_VERSION(2,3,0) &&
248 kernel_version < MAKE_VERSION(2,3,99)))
249 nfs_mount_version = 3;
251 nfs_mount_version = 4; /* since 2.3.99pre4 */
253 if (nfs_mount_version > NFS_MOUNT_VERSION)
254 nfs_mount_version = NFS_MOUNT_VERSION;
258 get_mountport(struct sockaddr_in *server_addr,
260 long unsigned version,
264 struct pmaplist *pmap;
265 static struct pmap p = {0, 0, 0, 0};
267 server_addr->sin_port = PMAPPORT;
268 pmap = pmap_getmaps(server_addr);
270 if (version > MAX_NFSPROT)
271 version = MAX_NFSPROT;
280 if (pmap->pml_map.pm_prog != prog)
282 if (!version && p.pm_vers > pmap->pml_map.pm_vers)
284 if (version > 2 && pmap->pml_map.pm_vers != version)
286 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
288 if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
289 (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
290 (port && pmap->pml_map.pm_port != port))
292 memcpy(&p, &pmap->pml_map, sizeof(p));
294 pmap = pmap->pml_next;
297 p.pm_vers = MOUNTVERS;
299 p.pm_port = MOUNTPORT;
301 p.pm_prot = IPPROTO_TCP;
305 int nfsmount(const char *spec, const char *node, int *flags,
306 char **extra_opts, char **mount_opts, int running_bg)
308 static char *prev_bg_host;
314 char *mounthost=NULL;
316 struct timeval total_timeout;
317 enum clnt_stat clnt_stat;
318 static struct nfs_mount_data data;
322 struct sockaddr_in server_addr;
323 struct sockaddr_in mount_server_addr;
326 struct timeval retry_timeout;
328 struct fhstatus nfsv2;
329 struct mountres3 nfsv3;
354 find_kernel_nfs_mount_version();
359 if (strlen(spec) >= sizeof(hostdir)) {
360 bb_error_msg("excessively long host:dir argument");
363 strcpy(hostdir, spec);
364 if ((s = strchr(hostdir, ':'))) {
368 /* Ignore all but first hostname in replicated mounts
369 until they can be fully supported. (mack@sgi.com) */
370 if ((s = strchr(hostdir, ','))) {
372 bb_error_msg("warning: multiple hostnames not supported");
375 bb_error_msg("directory to mount not in host:dir format");
379 server_addr.sin_family = AF_INET;
380 #ifdef HAVE_inet_aton
381 if (!inet_aton(hostname, &server_addr.sin_addr))
384 if ((hp = gethostbyname(hostname)) == NULL) {
385 bb_herror_msg("%s", hostname);
388 if (hp->h_length > sizeof(struct in_addr)) {
389 bb_error_msg("got bad hp->h_length");
390 hp->h_length = sizeof(struct in_addr);
392 memcpy(&server_addr.sin_addr,
393 hp->h_addr, hp->h_length);
397 memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
399 /* add IP address to mtab options for use when unmounting */
401 s = inet_ntoa(server_addr.sin_addr);
402 old_opts = *extra_opts;
405 if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
406 bb_error_msg("excessively long option argument");
409 sprintf(new_opts, "%s%saddr=%s",
410 old_opts, *old_opts ? "," : "", s);
411 *extra_opts = bb_xstrdup(new_opts);
413 /* Set default options.
414 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
415 * let the kernel decide.
416 * timeo is filled in after we know whether it'll be TCP or UDP. */
417 memset(&data, 0, sizeof(data));
423 #if NFS_MOUNT_VERSION >= 2
424 data.namlen = NAME_MAX;
434 retry = 10000; /* 10000 minutes ~ 1 week */
437 mountprog = MOUNTPROG;
441 nfsprog = NFS_PROGRAM;
446 for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
447 if ((opteq = strchr(opt, '='))) {
448 val = atoi(opteq + 1);
450 if (!strcmp(opt, "rsize"))
452 else if (!strcmp(opt, "wsize"))
454 else if (!strcmp(opt, "timeo"))
456 else if (!strcmp(opt, "retrans"))
458 else if (!strcmp(opt, "acregmin"))
460 else if (!strcmp(opt, "acregmax"))
462 else if (!strcmp(opt, "acdirmin"))
464 else if (!strcmp(opt, "acdirmax"))
466 else if (!strcmp(opt, "actimeo")) {
472 else if (!strcmp(opt, "retry"))
474 else if (!strcmp(opt, "port"))
476 else if (!strcmp(opt, "mountport"))
478 else if (!strcmp(opt, "mounthost"))
479 mounthost=bb_xstrndup(opteq+1,
480 strcspn(opteq+1," \t\n\r,"));
481 else if (!strcmp(opt, "mountprog"))
483 else if (!strcmp(opt, "mountvers"))
485 else if (!strcmp(opt, "nfsprog"))
487 else if (!strcmp(opt, "nfsvers") ||
488 !strcmp(opt, "vers"))
490 else if (!strcmp(opt, "proto")) {
491 if (!strncmp(opteq+1, "tcp", 3))
493 else if (!strncmp(opteq+1, "udp", 3))
496 printf(_("Warning: Unrecognized proto= option.\n"));
497 } else if (!strcmp(opt, "namlen")) {
498 #if NFS_MOUNT_VERSION >= 2
499 if (nfs_mount_version >= 2)
503 printf(_("Warning: Option namlen is not supported.\n"));
504 } else if (!strcmp(opt, "addr"))
507 printf(_("unknown nfs mount parameter: "
508 "%s=%d\n"), opt, val);
514 if (!strncmp(opt, "no", 2)) {
518 if (!strcmp(opt, "bg"))
520 else if (!strcmp(opt, "fg"))
522 else if (!strcmp(opt, "soft"))
524 else if (!strcmp(opt, "hard"))
526 else if (!strcmp(opt, "intr"))
528 else if (!strcmp(opt, "posix"))
530 else if (!strcmp(opt, "cto"))
532 else if (!strcmp(opt, "ac"))
534 else if (!strcmp(opt, "tcp"))
536 else if (!strcmp(opt, "udp"))
538 else if (!strcmp(opt, "lock")) {
539 if (nfs_mount_version >= 3)
542 printf(_("Warning: option nolock is not supported.\n"));
544 printf(_("unknown nfs mount option: "
545 "%s%s\n"), val ? "" : "no", opt);
550 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
552 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
553 | (intr ? NFS_MOUNT_INTR : 0)
554 | (posix ? NFS_MOUNT_POSIX : 0)
555 | (nocto ? NFS_MOUNT_NOCTO : 0)
556 | (noac ? NFS_MOUNT_NOAC : 0);
557 #if NFS_MOUNT_VERSION >= 2
558 if (nfs_mount_version >= 2)
559 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
561 #if NFS_MOUNT_VERSION >= 3
562 if (nfs_mount_version >= 3)
563 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
565 if (nfsvers > MAX_NFSPROT) {
566 bb_error_msg("NFSv%d not supported!", nfsvers);
569 if (mountvers > MAX_NFSPROT) {
570 bb_error_msg("NFSv%d not supported!", nfsvers);
573 if (nfsvers && !mountvers)
574 mountvers = (nfsvers < 3) ? 1 : nfsvers;
575 if (nfsvers && nfsvers < mountvers) {
579 /* Adjust options if none specified */
581 data.timeo = tcp ? 70 : 7;
583 #ifdef NFS_MOUNT_DEBUG
584 printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
585 data.rsize, data.wsize, data.timeo, data.retrans);
586 printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
587 data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
588 printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
589 port, bg, retry, data.flags);
590 printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
591 mountprog, mountvers, nfsprog, nfsvers);
592 printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
593 (data.flags & NFS_MOUNT_SOFT) != 0,
594 (data.flags & NFS_MOUNT_INTR) != 0,
595 (data.flags & NFS_MOUNT_POSIX) != 0,
596 (data.flags & NFS_MOUNT_NOCTO) != 0,
597 (data.flags & NFS_MOUNT_NOAC) != 0);
598 #if NFS_MOUNT_VERSION >= 2
600 (data.flags & NFS_MOUNT_TCP) != 0);
604 data.version = nfs_mount_version;
605 *mount_opts = (char *) &data;
607 if (*flags & MS_REMOUNT)
611 * If the previous mount operation on the same host was
612 * backgrounded, and the "bg" for this mount is also set,
613 * give up immediately, to avoid the initial timeout.
615 if (bg && !running_bg &&
616 prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
622 /* create mount deamon client */
623 /* See if the nfs host = mount host. */
625 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
626 mount_server_addr.sin_family = AF_INET;
627 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
629 if ((hp = gethostbyname(mounthost)) == NULL) {
630 bb_herror_msg("%s", mounthost);
633 if (hp->h_length > sizeof(struct in_addr)) {
634 bb_error_msg("got bad hp->h_length?");
635 hp->h_length = sizeof(struct in_addr);
637 mount_server_addr.sin_family = AF_INET;
638 memcpy(&mount_server_addr.sin_addr,
639 hp->h_addr, hp->h_length);
645 * The following loop implements the mount retries. On the first
646 * call, "running_bg" is 0. When the mount times out, and the
647 * "bg" option is set, the exit status EX_BG will be returned.
648 * For a backgrounded mount, there will be a second call by the
649 * child process with "running_bg" set to 1.
651 * The case where the mount point is not present and the "bg"
652 * option is set, is treated as a timeout. This is done to
653 * support nested mounts.
655 * The "retry" count specified by the user is the number of
656 * minutes to retry before giving up.
658 * Only the first error message will be displayed.
660 retry_timeout.tv_sec = 3;
661 retry_timeout.tv_usec = 0;
662 total_timeout.tv_sec = 20;
663 total_timeout.tv_usec = 0;
664 timeout = time(NULL) + 60 * retry;
669 if (bg && stat(node, &statbuf) == -1) {
671 sleep(val); /* 1, 2, 4, 8, 16, 30, ... */
677 /* be careful not to use too many CPU cycles */
681 pm_mnt = get_mountport(&mount_server_addr,
687 /* contact the mount daemon via TCP */
688 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
691 switch (pm_mnt->pm_prot) {
693 mclient = clntudp_create(&mount_server_addr,
700 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
703 mclient = clnttcp_create(&mount_server_addr,
712 /* try to mount hostname:pathname */
713 mclient->cl_auth = authunix_create_default();
715 /* make pointers in xdr_mountres3 NULL so
716 * that xdr_array allocates memory for us
718 memset(&status, 0, sizeof(status));
720 if (pm_mnt->pm_vers == 3)
721 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
722 (xdrproc_t) xdr_dirpath,
724 (xdrproc_t) xdr_mountres3,
728 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
729 (xdrproc_t) xdr_dirpath,
731 (xdrproc_t) xdr_fhstatus,
735 if (clnt_stat == RPC_SUCCESS)
736 break; /* we're done */
737 if (errno != ECONNREFUSED) {
738 clnt_perror(mclient, "mount");
739 goto fail; /* don't retry */
741 if (!running_bg && prevt == 0)
742 clnt_perror(mclient, "mount");
743 auth_destroy(mclient->cl_auth);
744 clnt_destroy(mclient);
748 if (!running_bg && prevt == 0)
749 clnt_pcreateerror("mount");
756 prev_bg_host = bb_xstrdup(hostname);
765 nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
768 if (status.nfsv2.fhs_status != 0) {
769 bb_error_msg("%s:%s failed, reason given by server: %s",
771 nfs_strerror(status.nfsv2.fhs_status));
774 memcpy(data.root.data,
775 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
777 #if NFS_MOUNT_VERSION >= 4
778 data.root.size = NFS_FHSIZE;
779 memcpy(data.old_root.data,
780 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
784 #if NFS_MOUNT_VERSION >= 4
785 fhandle3 *my_fhandle;
786 if (status.nfsv3.fhs_status != 0) {
787 bb_error_msg("%s:%s failed, reason given by server: %s",
789 nfs_strerror(status.nfsv3.fhs_status));
792 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
793 memset(data.old_root.data, 0, NFS_FHSIZE);
794 memset(&data.root, 0, sizeof(data.root));
795 data.root.size = my_fhandle->fhandle3_len;
796 memcpy(data.root.data,
797 (char *) my_fhandle->fhandle3_val,
798 my_fhandle->fhandle3_len);
800 data.flags |= NFS_MOUNT_VER3;
804 /* create nfs socket for kernel */
807 if (nfs_mount_version < 3) {
808 printf(_("NFS over TCP is not supported.\n"));
811 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
813 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
815 perror(_("nfs socket"));
818 if (bindresvport(fsock, 0) < 0) {
819 perror(_("nfs bindresvport"));
823 server_addr.sin_port = PMAPPORT;
824 port = pmap_getport(&server_addr, nfsprog, nfsvers,
825 tcp ? IPPROTO_TCP : IPPROTO_UDP);
828 #ifdef NFS_MOUNT_DEBUG
830 printf(_("used portmapper to find NFS port\n"));
833 #ifdef NFS_MOUNT_DEBUG
834 printf(_("using port %d for nfs deamon\n"), port);
836 server_addr.sin_port = htons(port);
838 * connect() the socket for kernels 1.3.10 and below only,
839 * to avoid problems with multihomed hosts.
842 if (get_kernel_revision() <= 66314
843 && connect(fsock, (struct sockaddr *) &server_addr,
844 sizeof (server_addr)) < 0) {
845 perror(_("nfs connect"));
849 /* prepare data structure for kernel */
852 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
853 strncpy(data.hostname, hostname, sizeof(data.hostname));
857 auth_destroy(mclient->cl_auth);
858 clnt_destroy(mclient);
867 auth_destroy(mclient->cl_auth);
868 clnt_destroy(mclient);
878 * We need to translate between nfs status return values and
879 * the local errno values which may not be the same.
881 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
882 * "after #include <errno.h> the symbol errno is reserved for any use,
883 * it cannot even be used as a struct tag or field name".
887 #define EDQUOT ENOSPC
895 { NFSERR_PERM, EPERM },
896 { NFSERR_NOENT, ENOENT },
898 { NFSERR_NXIO, ENXIO },
899 { NFSERR_ACCES, EACCES },
900 { NFSERR_EXIST, EEXIST },
901 { NFSERR_NODEV, ENODEV },
902 { NFSERR_NOTDIR, ENOTDIR },
903 { NFSERR_ISDIR, EISDIR },
905 { NFSERR_INVAL, EINVAL }, /* that Sun forgot */
907 { NFSERR_FBIG, EFBIG },
908 { NFSERR_NOSPC, ENOSPC },
909 { NFSERR_ROFS, EROFS },
910 { NFSERR_NAMETOOLONG, ENAMETOOLONG },
911 { NFSERR_NOTEMPTY, ENOTEMPTY },
912 { NFSERR_DQUOT, EDQUOT },
913 { NFSERR_STALE, ESTALE },
915 { NFSERR_WFLUSH, EWFLUSH },
917 /* Throw in some NFSv3 values for even more fun (HP returns these) */
923 static char *nfs_strerror(int status)
926 static char buf[256];
928 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
929 if (nfs_errtbl[i].stat == status)
930 return strerror(nfs_errtbl[i].errnum);
932 sprintf(buf, _("unknown nfs status return value: %d"), status);
937 xdr_fhandle (XDR *xdrs, fhandle objp)
939 //register int32_t *buf;
941 if (!xdr_opaque (xdrs, objp, FHSIZE))
947 xdr_fhstatus (XDR *xdrs, fhstatus *objp)
949 //register int32_t *buf;
951 if (!xdr_u_int (xdrs, &objp->fhs_status))
953 switch (objp->fhs_status) {
955 if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle))
965 xdr_dirpath (XDR *xdrs, dirpath *objp)
967 //register int32_t *buf;
969 if (!xdr_string (xdrs, objp, MNTPATHLEN))
975 xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
977 //register int32_t *buf;
979 if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3))
985 xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp)
987 //register int32_t *buf;
989 if (!xdr_fhandle3 (xdrs, &objp->fhandle))
991 if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->auth_flavours.auth_flavours_len, ~0,
992 sizeof (int), (xdrproc_t) xdr_int))
998 xdr_mountstat3 (XDR *xdrs, mountstat3 *objp)
1000 //register int32_t *buf;
1002 if (!xdr_enum (xdrs, (enum_t *) objp))
1008 xdr_mountres3 (XDR *xdrs, mountres3 *objp)
1010 //register int32_t *buf;
1012 if (!xdr_mountstat3 (xdrs, &objp->fhs_status))
1014 switch (objp->fhs_status) {
1016 if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo))