blob: 92b10a2326dca4b3ab03a25a7e54c897835e4fbb [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersen1c43d0c1999-11-18 07:58:07 +00002/*
3 * nfsmount.c -- Linux NFS mount
4 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
5 *
Rob Landley7a260f02006-06-19 03:20:03 +00006 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Eric Andersen1c43d0c1999-11-18 07:58:07 +00007 *
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.
10 *
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.
13 *
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.
16 *
17 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
18 * - added Native Language Support
Eric Andersenc7bda1c2004-03-15 08:29:22 +000019 *
Eric Andersenda1d1e72000-07-10 23:39:44 +000020 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
21 * plus NFSv3 stuff.
Eric Andersen1c43d0c1999-11-18 07:58:07 +000022 */
23
24/*
25 * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
26 */
27
Rob Landley22d26fc2006-06-15 15:49:36 +000028#include "busybox.h"
Eric Andersen1c43d0c1999-11-18 07:58:07 +000029#include <sys/utsname.h>
Eric Andersencbe31da2001-02-20 06:14:08 +000030#undef TRUE
31#undef FALSE
32#include <rpc/rpc.h>
33#include <rpc/pmap_prot.h>
34#include <rpc/pmap_clnt.h>
Eric Andersencbe31da2001-02-20 06:14:08 +000035#include "nfsmount.h"
Eric Andersen1c43d0c1999-11-18 07:58:07 +000036
Rob Landley7b363fd2005-12-20 17:18:01 +000037/* This is just a warning of a common mistake. Possibly this should be a
Bernhard Reutner-Fischered7bb622006-02-23 14:25:15 +000038 * uclibc faq entry rather than in busybox... */
Rob Landley7b363fd2005-12-20 17:18:01 +000039#if ENABLE_FEATURE_MOUNT_NFS && defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
40#error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
41#endif
42
Eric Andersen80ff9442002-12-11 04:04:26 +000043
Eric Andersen80ff9442002-12-11 04:04:26 +000044
45
Rob Landleybc68cd12006-03-10 19:22:06 +000046enum {
Glenn L McGrathc52a97d2000-12-09 23:59:04 +000047#ifndef NFS_FHSIZE
Rob Landleybc68cd12006-03-10 19:22:06 +000048 NFS_FHSIZE = 32,
Glenn L McGrathc52a97d2000-12-09 23:59:04 +000049#endif
50#ifndef NFS_PORT
Rob Landleybc68cd12006-03-10 19:22:06 +000051 NFS_PORT = 2049
Glenn L McGrathc52a97d2000-12-09 23:59:04 +000052#endif
Rob Landleybc68cd12006-03-10 19:22:06 +000053};
Eric Andersen1c43d0c1999-11-18 07:58:07 +000054
Eric Andersenda1d1e72000-07-10 23:39:44 +000055/* Disable the nls stuff */
Rob Landleyc27f4f52006-09-08 00:41:48 +000056//# undef bindtextdomain
57//# define bindtextdomain(Domain, Directory) /* empty */
58//# undef textdomain
59//# define textdomain(Domain) /* empty */
Eric Andersenda1d1e72000-07-10 23:39:44 +000060
Rob Landleyc27f4f52006-09-08 00:41:48 +000061//enum {
62// S_QUOTA = 128, /* Quota initialized for file/directory/symlink */
63//};
Eric Andersenda1d1e72000-07-10 23:39:44 +000064
65
66/*
67 * We want to be able to compile mount on old kernels in such a way
68 * that the binary will work well on more recent kernels.
69 * Thus, if necessary we teach nfsmount.c the structure of new fields
70 * that will come later.
71 *
72 * Moreover, the new kernel includes conflict with glibc includes
73 * so it is easiest to ignore the kernel altogether (at compile time).
74 */
75
Eric Andersenda1d1e72000-07-10 23:39:44 +000076struct nfs2_fh {
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000077 char data[32];
Eric Andersenda1d1e72000-07-10 23:39:44 +000078};
79struct nfs3_fh {
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000080 unsigned short size;
81 unsigned char data[64];
Eric Andersenda1d1e72000-07-10 23:39:44 +000082};
83
84struct nfs_mount_data {
85 int version; /* 1 */
86 int fd; /* 1 */
87 struct nfs2_fh old_root; /* 1 */
88 int flags; /* 1 */
89 int rsize; /* 1 */
90 int wsize; /* 1 */
91 int timeo; /* 1 */
92 int retrans; /* 1 */
93 int acregmin; /* 1 */
94 int acregmax; /* 1 */
95 int acdirmin; /* 1 */
96 int acdirmax; /* 1 */
97 struct sockaddr_in addr; /* 1 */
98 char hostname[256]; /* 1 */
99 int namlen; /* 2 */
100 unsigned int bsize; /* 3 */
101 struct nfs3_fh root; /* 4 */
102};
103
104/* bits in the flags field */
Rob Landleybc68cd12006-03-10 19:22:06 +0000105enum {
106 NFS_MOUNT_SOFT = 0x0001, /* 1 */
107 NFS_MOUNT_INTR = 0x0002, /* 1 */
108 NFS_MOUNT_SECURE = 0x0004, /* 1 */
109 NFS_MOUNT_POSIX = 0x0008, /* 1 */
110 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
111 NFS_MOUNT_NOAC = 0x0020, /* 1 */
112 NFS_MOUNT_TCP = 0x0040, /* 2 */
113 NFS_MOUNT_VER3 = 0x0080, /* 3 */
114 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
115 NFS_MOUNT_NONLM = 0x0200 /* 3 */
116};
Eric Andersenda1d1e72000-07-10 23:39:44 +0000117
118
119#define UTIL_LINUX_VERSION "2.10m"
120#define util_linux_version "util-linux-2.10m"
121
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000122#define HAVE_inet_aton
Eric Andersenda1d1e72000-07-10 23:39:44 +0000123#define HAVE_scsi_h
124#define HAVE_blkpg_h
125#define HAVE_kd_h
126#define HAVE_termcap
127#define HAVE_locale_h
128#define HAVE_libintl_h
129#define ENABLE_NLS
130#define HAVE_langinfo_h
131#define HAVE_progname
132#define HAVE_openpty
133#define HAVE_nanosleep
134#define HAVE_personality
135#define HAVE_tm_gmtoff
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000136
Eric Andersen1ca20a72001-03-21 07:34:27 +0000137static char *nfs_strerror(int status);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000138
Eric Andersenda1d1e72000-07-10 23:39:44 +0000139#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000140
Rob Landleybc68cd12006-03-10 19:22:06 +0000141enum {
142 EX_FAIL = 32, /* mount failure */
143 EX_BG = 256 /* retry in background (internal only) */
144};
Eric Andersenda1d1e72000-07-10 23:39:44 +0000145
146
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000147/*
Eric Andersenda1d1e72000-07-10 23:39:44 +0000148 * nfs_mount_version according to the sources seen at compile time.
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000149 */
Mark Whitley59ab0252001-01-23 22:30:04 +0000150static int nfs_mount_version;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000151
152/*
153 * Unfortunately, the kernel prints annoying console messages
154 * in case of an unexpected nfs mount version (instead of
155 * just returning some error). Therefore we'll have to try
156 * and figure out what version the kernel expects.
157 *
158 * Variables:
159 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
160 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
161 * nfs_mount_version: version this source and running kernel can handle
162 */
Eric Andersenda1d1e72000-07-10 23:39:44 +0000163static void
Mark Whitley065c7e72001-02-01 19:51:13 +0000164find_kernel_nfs_mount_version(void)
165{
Eric Andersenda1d1e72000-07-10 23:39:44 +0000166 static int kernel_version = 0;
167
168 if (kernel_version)
169 return;
170
Rob Landleyc27f4f52006-09-08 00:41:48 +0000171 nfs_mount_version = 4; /* default */
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000172
Bernhard Reutner-Fischere2e56c72006-05-19 11:54:02 +0000173 kernel_version = get_linux_version_code();
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000174 if (kernel_version) {
Bernhard Reutner-Fischere2e56c72006-05-19 11:54:02 +0000175 if (kernel_version < KERNEL_VERSION(2,1,32))
Mark Whitley065c7e72001-02-01 19:51:13 +0000176 nfs_mount_version = 1;
Bernhard Reutner-Fischere2e56c72006-05-19 11:54:02 +0000177 else if (kernel_version < KERNEL_VERSION(2,2,18) ||
178 (kernel_version >= KERNEL_VERSION(2,3,0) &&
179 kernel_version < KERNEL_VERSION(2,3,99)))
Mark Whitley065c7e72001-02-01 19:51:13 +0000180 nfs_mount_version = 3;
181 else
182 nfs_mount_version = 4; /* since 2.3.99pre4 */
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000183 }
Rob Landleyc27f4f52006-09-08 00:41:48 +0000184 if (nfs_mount_version > 4)
185 nfs_mount_version = 4;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000186}
187
Eric Andersenda1d1e72000-07-10 23:39:44 +0000188static struct pmap *
189get_mountport(struct sockaddr_in *server_addr,
190 long unsigned prog,
191 long unsigned version,
192 long unsigned proto,
193 long unsigned port)
194{
Denis Vlasenko2244a212006-09-10 18:28:23 +0000195 struct pmaplist *pmap;
196 static struct pmap p = {0, 0, 0, 0};
Eric Andersenda1d1e72000-07-10 23:39:44 +0000197
Denis Vlasenko2244a212006-09-10 18:28:23 +0000198 server_addr->sin_port = PMAPPORT;
199 pmap = pmap_getmaps(server_addr);
Eric Andersenda1d1e72000-07-10 23:39:44 +0000200
Denis Vlasenko2244a212006-09-10 18:28:23 +0000201 if (version > MAX_NFSPROT)
202 version = MAX_NFSPROT;
203 if (!prog)
204 prog = MOUNTPROG;
205 p.pm_prog = prog;
206 p.pm_vers = version;
207 p.pm_prot = proto;
208 p.pm_port = port;
209
210 while (pmap) {
211 if (pmap->pml_map.pm_prog != prog)
212 goto next;
213 if (!version && p.pm_vers > pmap->pml_map.pm_vers)
214 goto next;
215 if (version > 2 && pmap->pml_map.pm_vers != version)
216 goto next;
217 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
218 goto next;
219 if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
220 (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
221 (port && pmap->pml_map.pm_port != port))
222 goto next;
223 memcpy(&p, &pmap->pml_map, sizeof(p));
Eric Andersenda1d1e72000-07-10 23:39:44 +0000224next:
Denis Vlasenko2244a212006-09-10 18:28:23 +0000225 pmap = pmap->pml_next;
226 }
227 if (!p.pm_vers)
228 p.pm_vers = MOUNTVERS;
229 if (!p.pm_port)
230 p.pm_port = MOUNTPORT;
231 if (!p.pm_prot)
232 p.pm_prot = IPPROTO_TCP;
233 return &p;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000234}
235
236int nfsmount(const char *spec, const char *node, int *flags,
Rob Landley6a6798b2005-08-10 20:35:54 +0000237 char **mount_opts, int running_bg)
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000238{
239 static char *prev_bg_host;
240 char hostdir[1024];
241 CLIENT *mclient;
242 char *hostname;
Matt Kraaif9d6aa02001-07-26 14:26:53 +0000243 char *pathname;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000244 char *old_opts;
Denis Vlasenko2244a212006-09-10 18:28:23 +0000245 char *mounthost = NULL;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000246 char new_opts[1024];
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000247 struct timeval total_timeout;
248 enum clnt_stat clnt_stat;
Eric Andersen882cec32004-07-26 12:05:12 +0000249 struct nfs_mount_data data;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000250 char *opt, *opteq;
251 int val;
252 struct hostent *hp;
253 struct sockaddr_in server_addr;
254 struct sockaddr_in mount_server_addr;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000255 struct pmap* pm_mnt;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000256 int msock, fsock;
257 struct timeval retry_timeout;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000258 union {
259 struct fhstatus nfsv2;
260 struct mountres3 nfsv3;
261 } status;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000262 struct stat statbuf;
263 char *s;
264 int port;
265 int mountport;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000266 int proto;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000267 int bg;
268 int soft;
269 int intr;
270 int posix;
271 int nocto;
272 int noac;
273 int nolock;
274 int retry;
275 int tcp;
276 int mountprog;
277 int mountvers;
278 int nfsprog;
279 int nfsvers;
280 int retval;
281 time_t t;
282 time_t prevt;
283 time_t timeout;
284
285 find_kernel_nfs_mount_version();
286
287 retval = EX_FAIL;
288 msock = fsock = -1;
289 mclient = NULL;
290 if (strlen(spec) >= sizeof(hostdir)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000291 bb_error_msg("excessively long host:dir argument");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000292 goto fail;
293 }
294 strcpy(hostdir, spec);
295 if ((s = strchr(hostdir, ':'))) {
296 hostname = hostdir;
Matt Kraaif9d6aa02001-07-26 14:26:53 +0000297 pathname = s + 1;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000298 *s = '\0';
299 /* Ignore all but first hostname in replicated mounts
300 until they can be fully supported. (mack@sgi.com) */
301 if ((s = strchr(hostdir, ','))) {
302 *s = '\0';
Manuel Novoa III cad53642003-03-19 09:13:01 +0000303 bb_error_msg("warning: multiple hostnames not supported");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000304 }
305 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000306 bb_error_msg("directory to mount not in host:dir format");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000307 goto fail;
308 }
309
310 server_addr.sin_family = AF_INET;
311#ifdef HAVE_inet_aton
312 if (!inet_aton(hostname, &server_addr.sin_addr))
313#endif
314 {
315 if ((hp = gethostbyname(hostname)) == NULL) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000316 bb_herror_msg("%s", hostname);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000317 goto fail;
318 } else {
319 if (hp->h_length > sizeof(struct in_addr)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000320 bb_error_msg("got bad hp->h_length");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000321 hp->h_length = sizeof(struct in_addr);
322 }
Eric Andersenda1d1e72000-07-10 23:39:44 +0000323 memcpy(&server_addr.sin_addr,
Denis Vlasenko2244a212006-09-10 18:28:23 +0000324 hp->h_addr, hp->h_length);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000325 }
326 }
327
Denis Vlasenko2244a212006-09-10 18:28:23 +0000328 memcpy(&mount_server_addr, &server_addr, sizeof (mount_server_addr));
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000329
330 /* add IP address to mtab options for use when unmounting */
331
332 s = inet_ntoa(server_addr.sin_addr);
Rob Landley6a6798b2005-08-10 20:35:54 +0000333 old_opts = *mount_opts;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000334 if (!old_opts)
335 old_opts = "";
336 if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000337 bb_error_msg("excessively long option argument");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000338 goto fail;
339 }
Eric Andersenda1d1e72000-07-10 23:39:44 +0000340 sprintf(new_opts, "%s%saddr=%s",
341 old_opts, *old_opts ? "," : "", s);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000342 *mount_opts = xstrdup(new_opts);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000343
344 /* Set default options.
345 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
346 * let the kernel decide.
347 * timeo is filled in after we know whether it'll be TCP or UDP. */
348 memset(&data, 0, sizeof(data));
Eric Andersenda1d1e72000-07-10 23:39:44 +0000349 data.retrans = 3;
350 data.acregmin = 3;
351 data.acregmax = 60;
352 data.acdirmin = 30;
353 data.acdirmax = 60;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000354 data.namlen = NAME_MAX;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000355
356 bg = 0;
357 soft = 0;
358 intr = 0;
359 posix = 0;
360 nocto = 0;
361 nolock = 0;
362 noac = 0;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000363 retry = 10000; /* 10000 minutes ~ 1 week */
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000364 tcp = 0;
365
366 mountprog = MOUNTPROG;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000367 mountvers = 0;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000368 port = 0;
369 mountport = 0;
Rob Landleyc27f4f52006-09-08 00:41:48 +0000370 nfsprog = 100003;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000371 nfsvers = 0;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000372
373 /* parse options */
374
375 for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
376 if ((opteq = strchr(opt, '='))) {
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000377 val = atoi(opteq + 1);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000378 *opteq = '\0';
379 if (!strcmp(opt, "rsize"))
380 data.rsize = val;
381 else if (!strcmp(opt, "wsize"))
382 data.wsize = val;
383 else if (!strcmp(opt, "timeo"))
384 data.timeo = val;
385 else if (!strcmp(opt, "retrans"))
386 data.retrans = val;
387 else if (!strcmp(opt, "acregmin"))
388 data.acregmin = val;
389 else if (!strcmp(opt, "acregmax"))
390 data.acregmax = val;
391 else if (!strcmp(opt, "acdirmin"))
392 data.acdirmin = val;
393 else if (!strcmp(opt, "acdirmax"))
394 data.acdirmax = val;
395 else if (!strcmp(opt, "actimeo")) {
396 data.acregmin = val;
397 data.acregmax = val;
398 data.acdirmin = val;
399 data.acdirmax = val;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000400 }
401 else if (!strcmp(opt, "retry"))
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000402 retry = val;
403 else if (!strcmp(opt, "port"))
404 port = val;
405 else if (!strcmp(opt, "mountport"))
Denis Vlasenko2244a212006-09-10 18:28:23 +0000406 mountport = val;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000407 else if (!strcmp(opt, "mounthost"))
Denis Vlasenko2244a212006-09-10 18:28:23 +0000408 mounthost = xstrndup(opteq+1,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000409 strcspn(opteq+1," \t\n\r,"));
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000410 else if (!strcmp(opt, "mountprog"))
411 mountprog = val;
412 else if (!strcmp(opt, "mountvers"))
413 mountvers = val;
414 else if (!strcmp(opt, "nfsprog"))
415 nfsprog = val;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000416 else if (!strcmp(opt, "nfsvers") ||
417 !strcmp(opt, "vers"))
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000418 nfsvers = val;
419 else if (!strcmp(opt, "proto")) {
Eric Andersenda1d1e72000-07-10 23:39:44 +0000420 if (!strncmp(opteq+1, "tcp", 3))
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000421 tcp = 1;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000422 else if (!strncmp(opteq+1, "udp", 3))
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000423 tcp = 0;
424 else
Rob Landley83947292006-05-29 04:49:55 +0000425 printf("Warning: Unrecognized proto= option.\n");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000426 } else if (!strcmp(opt, "namlen")) {
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000427 if (nfs_mount_version >= 2)
428 data.namlen = val;
429 else
Rob Landley83947292006-05-29 04:49:55 +0000430 printf("Warning: Option namlen is not supported.\n");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000431 } else if (!strcmp(opt, "addr"))
Eric Andersenda1d1e72000-07-10 23:39:44 +0000432 /* ignore */;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000433 else {
Rob Landley83947292006-05-29 04:49:55 +0000434 printf("unknown nfs mount parameter: %s=%d\n", opt, val);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000435 goto fail;
436 }
Eric Andersenda1d1e72000-07-10 23:39:44 +0000437 }
438 else {
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000439 val = 1;
440 if (!strncmp(opt, "no", 2)) {
441 val = 0;
442 opt += 2;
443 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000444 if (!strcmp(opt, "bg"))
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000445 bg = val;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000446 else if (!strcmp(opt, "fg"))
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000447 bg = !val;
448 else if (!strcmp(opt, "soft"))
449 soft = val;
450 else if (!strcmp(opt, "hard"))
451 soft = !val;
452 else if (!strcmp(opt, "intr"))
453 intr = val;
454 else if (!strcmp(opt, "posix"))
455 posix = val;
456 else if (!strcmp(opt, "cto"))
457 nocto = !val;
458 else if (!strcmp(opt, "ac"))
459 noac = !val;
460 else if (!strcmp(opt, "tcp"))
461 tcp = val;
462 else if (!strcmp(opt, "udp"))
463 tcp = !val;
464 else if (!strcmp(opt, "lock")) {
465 if (nfs_mount_version >= 3)
466 nolock = !val;
467 else
Rob Landley83947292006-05-29 04:49:55 +0000468 printf("Warning: option nolock is not supported.\n");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000469 } else {
Rob Landley83947292006-05-29 04:49:55 +0000470 printf("unknown nfs mount option: %s%s\n", val ? "" : "no", opt);
Eric Andersenda1d1e72000-07-10 23:39:44 +0000471 goto fail;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000472 }
473 }
474 }
Eric Andersenda1d1e72000-07-10 23:39:44 +0000475 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
476
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000477 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
478 | (intr ? NFS_MOUNT_INTR : 0)
479 | (posix ? NFS_MOUNT_POSIX : 0)
480 | (nocto ? NFS_MOUNT_NOCTO : 0)
481 | (noac ? NFS_MOUNT_NOAC : 0);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000482 if (nfs_mount_version >= 2)
483 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000484 if (nfs_mount_version >= 3)
485 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
Rob Landley29ba9792006-04-17 23:02:57 +0000486 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000487 bb_error_msg("NFSv%d not supported!", nfsvers);
Rob Landley29ba9792006-04-17 23:02:57 +0000488 return 1;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000489 }
490 if (nfsvers && !mountvers)
491 mountvers = (nfsvers < 3) ? 1 : nfsvers;
492 if (nfsvers && nfsvers < mountvers) {
493 mountvers = nfsvers;
494 }
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000495
496 /* Adjust options if none specified */
497 if (!data.timeo)
498 data.timeo = tcp ? 70 : 7;
499
500#ifdef NFS_MOUNT_DEBUG
501 printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
Eric Andersenda1d1e72000-07-10 23:39:44 +0000502 data.rsize, data.wsize, data.timeo, data.retrans);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000503 printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
Eric Andersenda1d1e72000-07-10 23:39:44 +0000504 data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000505 printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
Eric Andersenda1d1e72000-07-10 23:39:44 +0000506 port, bg, retry, data.flags);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000507 printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
Eric Andersenda1d1e72000-07-10 23:39:44 +0000508 mountprog, mountvers, nfsprog, nfsvers);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000509 printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
Eric Andersenda1d1e72000-07-10 23:39:44 +0000510 (data.flags & NFS_MOUNT_SOFT) != 0,
511 (data.flags & NFS_MOUNT_INTR) != 0,
512 (data.flags & NFS_MOUNT_POSIX) != 0,
513 (data.flags & NFS_MOUNT_NOCTO) != 0,
514 (data.flags & NFS_MOUNT_NOAC) != 0);
Eric Andersenda1d1e72000-07-10 23:39:44 +0000515 printf("tcp = %d\n",
516 (data.flags & NFS_MOUNT_TCP) != 0);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000517#endif
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000518
519 data.version = nfs_mount_version;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000520
521 if (*flags & MS_REMOUNT)
Eric Andersen882cec32004-07-26 12:05:12 +0000522 goto copy_data_and_return;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000523
524 /*
525 * If the previous mount operation on the same host was
526 * backgrounded, and the "bg" for this mount is also set,
527 * give up immediately, to avoid the initial timeout.
528 */
529 if (bg && !running_bg &&
Eric Andersenda1d1e72000-07-10 23:39:44 +0000530 prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000531 if (retry > 0)
532 retval = EX_BG;
533 return retval;
534 }
535
Mike Frysingerfa6c4842006-05-26 01:48:17 +0000536 /* create mount daemon client */
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000537 /* See if the nfs host = mount host. */
538 if (mounthost) {
Denis Vlasenko2244a212006-09-10 18:28:23 +0000539 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
540 mount_server_addr.sin_family = AF_INET;
541 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
542 } else {
543 if ((hp = gethostbyname(mounthost)) == NULL) {
544 bb_herror_msg("%s", mounthost);
545 goto fail;
546 } else {
547 if (hp->h_length > sizeof(struct in_addr)) {
548 bb_error_msg("got bad hp->h_length?");
549 hp->h_length = sizeof(struct in_addr);
550 }
551 mount_server_addr.sin_family = AF_INET;
552 memcpy(&mount_server_addr.sin_addr,
553 hp->h_addr, hp->h_length);
554 }
555 }
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000556 }
557
558 /*
559 * The following loop implements the mount retries. On the first
560 * call, "running_bg" is 0. When the mount times out, and the
561 * "bg" option is set, the exit status EX_BG will be returned.
562 * For a backgrounded mount, there will be a second call by the
563 * child process with "running_bg" set to 1.
564 *
565 * The case where the mount point is not present and the "bg"
566 * option is set, is treated as a timeout. This is done to
567 * support nested mounts.
568 *
569 * The "retry" count specified by the user is the number of
570 * minutes to retry before giving up.
571 *
572 * Only the first error message will be displayed.
573 */
574 retry_timeout.tv_sec = 3;
575 retry_timeout.tv_usec = 0;
576 total_timeout.tv_sec = 20;
577 total_timeout.tv_usec = 0;
578 timeout = time(NULL) + 60 * retry;
579 prevt = 0;
580 t = 30;
581 val = 1;
582 for (;;) {
583 if (bg && stat(node, &statbuf) == -1) {
584 if (running_bg) {
Eric Andersenda1d1e72000-07-10 23:39:44 +0000585 sleep(val); /* 1, 2, 4, 8, 16, 30, ... */
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000586 val *= 2;
587 if (val > 30)
588 val = 30;
589 }
590 } else {
591 /* be careful not to use too many CPU cycles */
592 if (t - prevt < 30)
593 sleep(30);
594
Eric Andersenda1d1e72000-07-10 23:39:44 +0000595 pm_mnt = get_mountport(&mount_server_addr,
Denis Vlasenko2244a212006-09-10 18:28:23 +0000596 mountprog,
597 mountvers,
598 proto,
599 mountport);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000600
Eric Andersenda1d1e72000-07-10 23:39:44 +0000601 /* contact the mount daemon via TCP */
602 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
603 msock = RPC_ANYSOCK;
604
605 switch (pm_mnt->pm_prot) {
606 case IPPROTO_UDP:
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000607 mclient = clntudp_create(&mount_server_addr,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000608 pm_mnt->pm_prog,
609 pm_mnt->pm_vers,
610 retry_timeout,
611 &msock);
Denis Vlasenko2244a212006-09-10 18:28:23 +0000612 if (mclient)
613 break;
614 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
615 msock = RPC_ANYSOCK;
616 case IPPROTO_TCP:
617 mclient = clnttcp_create(&mount_server_addr,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000618 pm_mnt->pm_prog,
619 pm_mnt->pm_vers,
620 &msock, 0, 0);
Denis Vlasenko2244a212006-09-10 18:28:23 +0000621 break;
622 default:
623 mclient = 0;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000624 }
625 if (mclient) {
Matt Kraaif9d6aa02001-07-26 14:26:53 +0000626 /* try to mount hostname:pathname */
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000627 mclient->cl_auth = authunix_create_default();
Eric Andersenda1d1e72000-07-10 23:39:44 +0000628
629 /* make pointers in xdr_mountres3 NULL so
630 * that xdr_array allocates memory for us
631 */
632 memset(&status, 0, sizeof(status));
633
634 if (pm_mnt->pm_vers == 3)
635 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
636 (xdrproc_t) xdr_dirpath,
Matt Kraaif9d6aa02001-07-26 14:26:53 +0000637 (caddr_t) &pathname,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000638 (xdrproc_t) xdr_mountres3,
639 (caddr_t) &status,
Denis Vlasenko2244a212006-09-10 18:28:23 +0000640 total_timeout);
Eric Andersenda1d1e72000-07-10 23:39:44 +0000641 else
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000642 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000643 (xdrproc_t) xdr_dirpath,
Matt Kraaif9d6aa02001-07-26 14:26:53 +0000644 (caddr_t) &pathname,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000645 (xdrproc_t) xdr_fhstatus,
646 (caddr_t) &status,
647 total_timeout);
648
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000649 if (clnt_stat == RPC_SUCCESS)
650 break; /* we're done */
651 if (errno != ECONNREFUSED) {
652 clnt_perror(mclient, "mount");
653 goto fail; /* don't retry */
654 }
655 if (!running_bg && prevt == 0)
656 clnt_perror(mclient, "mount");
657 auth_destroy(mclient->cl_auth);
658 clnt_destroy(mclient);
659 mclient = 0;
660 close(msock);
661 } else {
662 if (!running_bg && prevt == 0)
663 clnt_pcreateerror("mount");
664 }
665 prevt = t;
666 }
667 if (!bg)
Denis Vlasenko2244a212006-09-10 18:28:23 +0000668 goto fail;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000669 if (!running_bg) {
Rob Landleyd921b2e2006-08-03 15:41:12 +0000670 prev_bg_host = xstrdup(hostname);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000671 if (retry > 0)
672 retval = EX_BG;
673 goto fail;
674 }
675 t = time(NULL);
676 if (t >= timeout)
677 goto fail;
678 }
Eric Andersenda1d1e72000-07-10 23:39:44 +0000679 nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000680
Eric Andersenda1d1e72000-07-10 23:39:44 +0000681 if (nfsvers == 2) {
682 if (status.nfsv2.fhs_status != 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000683 bb_error_msg("%s:%s failed, reason given by server: %s",
Matt Kraaif9d6aa02001-07-26 14:26:53 +0000684 hostname, pathname,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000685 nfs_strerror(status.nfsv2.fhs_status));
686 goto fail;
687 }
688 memcpy(data.root.data,
Denis Vlasenko2244a212006-09-10 18:28:23 +0000689 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
690 NFS_FHSIZE);
Eric Andersenda1d1e72000-07-10 23:39:44 +0000691 data.root.size = NFS_FHSIZE;
692 memcpy(data.old_root.data,
Denis Vlasenko2244a212006-09-10 18:28:23 +0000693 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
694 NFS_FHSIZE);
Eric Andersenda1d1e72000-07-10 23:39:44 +0000695 } else {
Eric Andersen851895a2001-03-21 21:52:25 +0000696 fhandle3 *my_fhandle;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000697 if (status.nfsv3.fhs_status != 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000698 bb_error_msg("%s:%s failed, reason given by server: %s",
Matt Kraaif9d6aa02001-07-26 14:26:53 +0000699 hostname, pathname,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000700 nfs_strerror(status.nfsv3.fhs_status));
701 goto fail;
702 }
Eric Andersen851895a2001-03-21 21:52:25 +0000703 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000704 memset(data.old_root.data, 0, NFS_FHSIZE);
705 memset(&data.root, 0, sizeof(data.root));
Eric Andersen851895a2001-03-21 21:52:25 +0000706 data.root.size = my_fhandle->fhandle3_len;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000707 memcpy(data.root.data,
Denis Vlasenko2244a212006-09-10 18:28:23 +0000708 (char *) my_fhandle->fhandle3_val,
709 my_fhandle->fhandle3_len);
Eric Andersenda1d1e72000-07-10 23:39:44 +0000710
711 data.flags |= NFS_MOUNT_VER3;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000712 }
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000713
714 /* create nfs socket for kernel */
715
716 if (tcp) {
717 if (nfs_mount_version < 3) {
Rob Landley83947292006-05-29 04:49:55 +0000718 printf("NFS over TCP is not supported.\n");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000719 goto fail;
720 }
721 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
722 } else
723 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
724 if (fsock < 0) {
Rob Landley83947292006-05-29 04:49:55 +0000725 perror("nfs socket");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000726 goto fail;
727 }
728 if (bindresvport(fsock, 0) < 0) {
Rob Landley83947292006-05-29 04:49:55 +0000729 perror("nfs bindresvport");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000730 goto fail;
731 }
732 if (port == 0) {
733 server_addr.sin_port = PMAPPORT;
734 port = pmap_getport(&server_addr, nfsprog, nfsvers,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000735 tcp ? IPPROTO_TCP : IPPROTO_UDP);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000736 if (port == 0)
737 port = NFS_PORT;
738#ifdef NFS_MOUNT_DEBUG
739 else
Rob Landley83947292006-05-29 04:49:55 +0000740 printf("used portmapper to find NFS port\n");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000741#endif
742 }
743#ifdef NFS_MOUNT_DEBUG
Rob Landley83947292006-05-29 04:49:55 +0000744 printf("using port %d for nfs daemon\n", port);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000745#endif
746 server_addr.sin_port = htons(port);
Eric Andersenda1d1e72000-07-10 23:39:44 +0000747 /*
748 * connect() the socket for kernels 1.3.10 and below only,
749 * to avoid problems with multihomed hosts.
750 * --Swen
751 */
Bernhard Reutner-Fischere2e56c72006-05-19 11:54:02 +0000752 if (get_linux_version_code() <= KERNEL_VERSION(2,3,10)
Eric Andersenda1d1e72000-07-10 23:39:44 +0000753 && connect(fsock, (struct sockaddr *) &server_addr,
Denis Vlasenko2244a212006-09-10 18:28:23 +0000754 sizeof (server_addr)) < 0) {
Rob Landley83947292006-05-29 04:49:55 +0000755 perror("nfs connect");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000756 goto fail;
757 }
758
759 /* prepare data structure for kernel */
760
761 data.fd = fsock;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000762 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
763 strncpy(data.hostname, hostname, sizeof(data.hostname));
764
765 /* clean up */
766
767 auth_destroy(mclient->cl_auth);
768 clnt_destroy(mclient);
769 close(msock);
Eric Andersen882cec32004-07-26 12:05:12 +0000770copy_data_and_return:
771 *mount_opts = xrealloc(*mount_opts, sizeof(data));
772 memcpy(*mount_opts, &data, sizeof(data));
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000773 return 0;
774
775 /* abort */
776
Eric Andersenda1d1e72000-07-10 23:39:44 +0000777fail:
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000778 if (msock != -1) {
779 if (mclient) {
780 auth_destroy(mclient->cl_auth);
781 clnt_destroy(mclient);
782 }
783 close(msock);
784 }
785 if (fsock != -1)
786 close(fsock);
787 return retval;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000788}
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000789
790/*
791 * We need to translate between nfs status return values and
792 * the local errno values which may not be the same.
793 *
794 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
795 * "after #include <errno.h> the symbol errno is reserved for any use,
796 * it cannot even be used as a struct tag or field name".
797 */
798
799#ifndef EDQUOT
800#define EDQUOT ENOSPC
801#endif
802
Rob Landleyc27f4f52006-09-08 00:41:48 +0000803// Convert each NFSERR_BLAH into EBLAH
804
"Vladimir N. Oleynik"1f0262b2005-10-20 11:17:48 +0000805static const struct {
Rob Landleyc27f4f52006-09-08 00:41:48 +0000806 int stat;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000807 int errnum;
808} nfs_errtbl[] = {
Rob Landleyc27f4f52006-09-08 00:41:48 +0000809 {0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST},
810 {19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG},
811 {28,ENOSPC}, {30,EROFS}, {63,ENAMETOOLONG}, {66,ENOTEMPTY}, {69,EDQUOT},
812 {70,ESTALE}, {71,EREMOTE}, {-1,EIO}
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000813};
814
Rob Landleyc27f4f52006-09-08 00:41:48 +0000815
Eric Andersen1ca20a72001-03-21 07:34:27 +0000816static char *nfs_strerror(int status)
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000817{
818 int i;
819 static char buf[256];
820
821 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
Eric Andersen1ca20a72001-03-21 07:34:27 +0000822 if (nfs_errtbl[i].stat == status)
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000823 return strerror(nfs_errtbl[i].errnum);
824 }
Rob Landley83947292006-05-29 04:49:55 +0000825 sprintf(buf, "unknown nfs status return value: %d", status);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000826 return buf;
827}
828
Denis Vlasenko2244a212006-09-10 18:28:23 +0000829static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000830{
Denis Vlasenko2244a212006-09-10 18:28:23 +0000831 if (!xdr_opaque(xdrs, objp, FHSIZE))
Eric Andersenda1d1e72000-07-10 23:39:44 +0000832 return FALSE;
833 return TRUE;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000834}
835
Denis Vlasenko2244a212006-09-10 18:28:23 +0000836bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000837{
Denis Vlasenko2244a212006-09-10 18:28:23 +0000838 if (!xdr_u_int(xdrs, &objp->fhs_status))
Eric Andersenda1d1e72000-07-10 23:39:44 +0000839 return FALSE;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000840 switch (objp->fhs_status) {
841 case 0:
Denis Vlasenko2244a212006-09-10 18:28:23 +0000842 if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle))
Eric Andersenda1d1e72000-07-10 23:39:44 +0000843 return FALSE;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000844 break;
845 default:
846 break;
847 }
Eric Andersenda1d1e72000-07-10 23:39:44 +0000848 return TRUE;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000849}
850
Denis Vlasenko2244a212006-09-10 18:28:23 +0000851bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000852{
Denis Vlasenko2244a212006-09-10 18:28:23 +0000853 if (!xdr_string(xdrs, objp, MNTPATHLEN))
Eric Andersenda1d1e72000-07-10 23:39:44 +0000854 return FALSE;
855 return TRUE;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000856}
857
Denis Vlasenko2244a212006-09-10 18:28:23 +0000858bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000859{
Denis Vlasenko2244a212006-09-10 18:28:23 +0000860 if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
Eric Andersenda1d1e72000-07-10 23:39:44 +0000861 return FALSE;
862 return TRUE;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000863}
864
Denis Vlasenko2244a212006-09-10 18:28:23 +0000865bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000866{
Denis Vlasenko2244a212006-09-10 18:28:23 +0000867 if (!xdr_fhandle3(xdrs, &objp->fhandle))
868 return FALSE;
869 if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), &(objp->auth_flavours.auth_flavours_len), ~0,
870 sizeof (int), (xdrproc_t) xdr_int))
871 return FALSE;
872 return TRUE;
873}
874
875bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
876{
877 if (!xdr_enum(xdrs, (enum_t *) objp))
Eric Andersenda1d1e72000-07-10 23:39:44 +0000878 return FALSE;
879 return TRUE;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000880}
881
Denis Vlasenko2244a212006-09-10 18:28:23 +0000882bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000883{
Denis Vlasenko2244a212006-09-10 18:28:23 +0000884 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
885 return FALSE;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000886 switch (objp->fhs_status) {
887 case MNT_OK:
Denis Vlasenko2244a212006-09-10 18:28:23 +0000888 if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
Eric Andersenda1d1e72000-07-10 23:39:44 +0000889 return FALSE;
890 break;
891 default:
892 break;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000893 }
Eric Andersenda1d1e72000-07-10 23:39:44 +0000894 return TRUE;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000895}