blob: 43c3b663d6b20d9cf696093cd4570209d0c5cc58 [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
Rob Landley22d26fc2006-06-15 15:49:36 +000024#include "busybox.h"
Eric Andersen1c43d0c1999-11-18 07:58:07 +000025#include <sys/utsname.h>
Eric Andersencbe31da2001-02-20 06:14:08 +000026#undef TRUE
27#undef FALSE
28#include <rpc/rpc.h>
29#include <rpc/pmap_prot.h>
30#include <rpc/pmap_clnt.h>
Eric Andersen1c43d0c1999-11-18 07:58:07 +000031
Rob Landley7b363fd2005-12-20 17:18:01 +000032/* This is just a warning of a common mistake. Possibly this should be a
Bernhard Reutner-Fischered7bb622006-02-23 14:25:15 +000033 * uclibc faq entry rather than in busybox... */
Rob Landley7b363fd2005-12-20 17:18:01 +000034#if ENABLE_FEATURE_MOUNT_NFS && defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
35#error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
36#endif
37
Denis Vlasenko39e93cc2006-09-10 18:38:17 +000038/* former nfsmount.h */
Eric Andersen80ff9442002-12-11 04:04:26 +000039
Denis Vlasenko39e93cc2006-09-10 18:38:17 +000040#define MOUNTPORT 635
41#define MNTPATHLEN 1024
42#define MNTNAMLEN 255
43#define FHSIZE 32
44#define FHSIZE3 64
Eric Andersen80ff9442002-12-11 04:04:26 +000045
Denis Vlasenko39e93cc2006-09-10 18:38:17 +000046typedef char fhandle[FHSIZE];
47
48typedef struct {
49 unsigned int fhandle3_len;
50 char *fhandle3_val;
51} fhandle3;
52
53enum mountstat3 {
54 MNT_OK = 0,
55 MNT3ERR_PERM = 1,
56 MNT3ERR_NOENT = 2,
57 MNT3ERR_IO = 5,
58 MNT3ERR_ACCES = 13,
59 MNT3ERR_NOTDIR = 20,
60 MNT3ERR_INVAL = 22,
61 MNT3ERR_NAMETOOLONG = 63,
62 MNT3ERR_NOTSUPP = 10004,
63 MNT3ERR_SERVERFAULT = 10006,
64};
65typedef enum mountstat3 mountstat3;
66
67struct fhstatus {
68 unsigned int fhs_status;
69 union {
70 fhandle fhs_fhandle;
71 } fhstatus_u;
72};
73typedef struct fhstatus fhstatus;
74
75struct mountres3_ok {
76 fhandle3 fhandle;
77 struct {
78 unsigned int auth_flavours_len;
79 char *auth_flavours_val;
80 } auth_flavours;
81};
82typedef struct mountres3_ok mountres3_ok;
83
84struct mountres3 {
85 mountstat3 fhs_status;
86 union {
87 mountres3_ok mountinfo;
88 } mountres3_u;
89};
90typedef struct mountres3 mountres3;
91
92typedef char *dirpath;
93
94typedef char *name;
95
96typedef struct mountbody *mountlist;
97
98struct mountbody {
99 name ml_hostname;
100 dirpath ml_directory;
101 mountlist ml_next;
102};
103typedef struct mountbody mountbody;
104
105typedef struct groupnode *groups;
106
107struct groupnode {
108 name gr_name;
109 groups gr_next;
110};
111typedef struct groupnode groupnode;
112
113typedef struct exportnode *exports;
114
115struct exportnode {
116 dirpath ex_dir;
117 groups ex_groups;
118 exports ex_next;
119};
120typedef struct exportnode exportnode;
121
122struct ppathcnf {
123 int pc_link_max;
124 short pc_max_canon;
125 short pc_max_input;
126 short pc_name_max;
127 short pc_path_max;
128 short pc_pipe_buf;
129 u_char pc_vdisable;
130 char pc_xxx;
131 short pc_mask[2];
132};
133typedef struct ppathcnf ppathcnf;
134
135#define MOUNTPROG 100005
136#define MOUNTVERS 1
137
138#define MOUNTPROC_NULL 0
139#define MOUNTPROC_MNT 1
140#define MOUNTPROC_DUMP 2
141#define MOUNTPROC_UMNT 3
142#define MOUNTPROC_UMNTALL 4
143#define MOUNTPROC_EXPORT 5
144#define MOUNTPROC_EXPORTALL 6
145
146#define MOUNTVERS_POSIX 2
147
148#define MOUNTPROC_PATHCONF 7
149
150#define MOUNT_V3 3
151
152#define MOUNTPROC3_NULL 0
153#define MOUNTPROC3_MNT 1
154#define MOUNTPROC3_DUMP 2
155#define MOUNTPROC3_UMNT 3
156#define MOUNTPROC3_UMNTALL 4
157#define MOUNTPROC3_EXPORT 5
158
159/* former nfsmount.h ends */
Eric Andersen80ff9442002-12-11 04:04:26 +0000160
Rob Landleybc68cd12006-03-10 19:22:06 +0000161enum {
Glenn L McGrathc52a97d2000-12-09 23:59:04 +0000162#ifndef NFS_FHSIZE
Rob Landleybc68cd12006-03-10 19:22:06 +0000163 NFS_FHSIZE = 32,
Glenn L McGrathc52a97d2000-12-09 23:59:04 +0000164#endif
165#ifndef NFS_PORT
Rob Landleybc68cd12006-03-10 19:22:06 +0000166 NFS_PORT = 2049
Glenn L McGrathc52a97d2000-12-09 23:59:04 +0000167#endif
Rob Landleybc68cd12006-03-10 19:22:06 +0000168};
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000169
Rob Landleyc27f4f52006-09-08 00:41:48 +0000170//enum {
171// S_QUOTA = 128, /* Quota initialized for file/directory/symlink */
172//};
Eric Andersenda1d1e72000-07-10 23:39:44 +0000173
174
175/*
176 * We want to be able to compile mount on old kernels in such a way
177 * that the binary will work well on more recent kernels.
178 * Thus, if necessary we teach nfsmount.c the structure of new fields
179 * that will come later.
180 *
181 * Moreover, the new kernel includes conflict with glibc includes
182 * so it is easiest to ignore the kernel altogether (at compile time).
183 */
184
Eric Andersenda1d1e72000-07-10 23:39:44 +0000185struct nfs2_fh {
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000186 char data[32];
Eric Andersenda1d1e72000-07-10 23:39:44 +0000187};
188struct nfs3_fh {
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000189 unsigned short size;
190 unsigned char data[64];
Eric Andersenda1d1e72000-07-10 23:39:44 +0000191};
192
193struct nfs_mount_data {
194 int version; /* 1 */
195 int fd; /* 1 */
196 struct nfs2_fh old_root; /* 1 */
197 int flags; /* 1 */
198 int rsize; /* 1 */
199 int wsize; /* 1 */
200 int timeo; /* 1 */
201 int retrans; /* 1 */
202 int acregmin; /* 1 */
203 int acregmax; /* 1 */
204 int acdirmin; /* 1 */
205 int acdirmax; /* 1 */
206 struct sockaddr_in addr; /* 1 */
207 char hostname[256]; /* 1 */
208 int namlen; /* 2 */
209 unsigned int bsize; /* 3 */
210 struct nfs3_fh root; /* 4 */
211};
212
213/* bits in the flags field */
Rob Landleybc68cd12006-03-10 19:22:06 +0000214enum {
215 NFS_MOUNT_SOFT = 0x0001, /* 1 */
216 NFS_MOUNT_INTR = 0x0002, /* 1 */
217 NFS_MOUNT_SECURE = 0x0004, /* 1 */
218 NFS_MOUNT_POSIX = 0x0008, /* 1 */
219 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
220 NFS_MOUNT_NOAC = 0x0020, /* 1 */
221 NFS_MOUNT_TCP = 0x0040, /* 2 */
222 NFS_MOUNT_VER3 = 0x0080, /* 3 */
223 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
224 NFS_MOUNT_NONLM = 0x0200 /* 3 */
225};
Eric Andersenda1d1e72000-07-10 23:39:44 +0000226
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000227#define HAVE_inet_aton
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000228
Denis Vlasenko39e93cc2006-09-10 18:38:17 +0000229/*
230 * We need to translate between nfs status return values and
231 * the local errno values which may not be the same.
232 *
233 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
234 * "after #include <errno.h> the symbol errno is reserved for any use,
235 * it cannot even be used as a struct tag or field name".
236 */
237
238#ifndef EDQUOT
239#define EDQUOT ENOSPC
240#endif
241
242// Convert each NFSERR_BLAH into EBLAH
243
244static const struct {
245 int stat;
246 int errnum;
247} nfs_errtbl[] = {
248 {0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST},
249 {19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG},
250 {28,ENOSPC}, {30,EROFS}, {63,ENAMETOOLONG}, {66,ENOTEMPTY}, {69,EDQUOT},
251 {70,ESTALE}, {71,EREMOTE}, {-1,EIO}
252};
253
254static char *nfs_strerror(int status)
255{
256 int i;
257 static char buf[256];
258
259 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
260 if (nfs_errtbl[i].stat == status)
261 return strerror(nfs_errtbl[i].errnum);
262 }
263 sprintf(buf, "unknown nfs status return value: %d", status);
264 return buf;
265}
266
267static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
268{
269 if (!xdr_opaque(xdrs, objp, FHSIZE))
270 return FALSE;
271 return TRUE;
272}
273
274static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
275{
276 if (!xdr_u_int(xdrs, &objp->fhs_status))
277 return FALSE;
278 switch (objp->fhs_status) {
279 case 0:
280 if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle))
281 return FALSE;
282 break;
283 default:
284 break;
285 }
286 return TRUE;
287}
288
289static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
290{
291 if (!xdr_string(xdrs, objp, MNTPATHLEN))
292 return FALSE;
293 return TRUE;
294}
295
296static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
297{
298 if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
299 return FALSE;
300 return TRUE;
301}
302
303static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
304{
305 if (!xdr_fhandle3(xdrs, &objp->fhandle))
306 return FALSE;
307 if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), &(objp->auth_flavours.auth_flavours_len), ~0,
308 sizeof (int), (xdrproc_t) xdr_int))
309 return FALSE;
310 return TRUE;
311}
312
313static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
314{
315 if (!xdr_enum(xdrs, (enum_t *) objp))
316 return FALSE;
317 return TRUE;
318}
319
320static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
321{
322 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
323 return FALSE;
324 switch (objp->fhs_status) {
325 case MNT_OK:
326 if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
327 return FALSE;
328 break;
329 default:
330 break;
331 }
332 return TRUE;
333}
334
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000335
Eric Andersenda1d1e72000-07-10 23:39:44 +0000336#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000337
Rob Landleybc68cd12006-03-10 19:22:06 +0000338enum {
339 EX_FAIL = 32, /* mount failure */
340 EX_BG = 256 /* retry in background (internal only) */
341};
Eric Andersenda1d1e72000-07-10 23:39:44 +0000342
343
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000344/*
Eric Andersenda1d1e72000-07-10 23:39:44 +0000345 * nfs_mount_version according to the sources seen at compile time.
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000346 */
Mark Whitley59ab0252001-01-23 22:30:04 +0000347static int nfs_mount_version;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000348
349/*
350 * Unfortunately, the kernel prints annoying console messages
351 * in case of an unexpected nfs mount version (instead of
352 * just returning some error). Therefore we'll have to try
353 * and figure out what version the kernel expects.
354 *
355 * Variables:
356 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
357 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
358 * nfs_mount_version: version this source and running kernel can handle
359 */
Eric Andersenda1d1e72000-07-10 23:39:44 +0000360static void
Mark Whitley065c7e72001-02-01 19:51:13 +0000361find_kernel_nfs_mount_version(void)
362{
Eric Andersenda1d1e72000-07-10 23:39:44 +0000363 static int kernel_version = 0;
364
365 if (kernel_version)
366 return;
367
Rob Landleyc27f4f52006-09-08 00:41:48 +0000368 nfs_mount_version = 4; /* default */
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000369
Bernhard Reutner-Fischere2e56c72006-05-19 11:54:02 +0000370 kernel_version = get_linux_version_code();
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000371 if (kernel_version) {
Bernhard Reutner-Fischere2e56c72006-05-19 11:54:02 +0000372 if (kernel_version < KERNEL_VERSION(2,1,32))
Mark Whitley065c7e72001-02-01 19:51:13 +0000373 nfs_mount_version = 1;
Bernhard Reutner-Fischere2e56c72006-05-19 11:54:02 +0000374 else if (kernel_version < KERNEL_VERSION(2,2,18) ||
375 (kernel_version >= KERNEL_VERSION(2,3,0) &&
376 kernel_version < KERNEL_VERSION(2,3,99)))
Mark Whitley065c7e72001-02-01 19:51:13 +0000377 nfs_mount_version = 3;
378 else
379 nfs_mount_version = 4; /* since 2.3.99pre4 */
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000380 }
Rob Landleyc27f4f52006-09-08 00:41:48 +0000381 if (nfs_mount_version > 4)
382 nfs_mount_version = 4;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000383}
384
Eric Andersenda1d1e72000-07-10 23:39:44 +0000385static struct pmap *
386get_mountport(struct sockaddr_in *server_addr,
Denis Vlasenko39e93cc2006-09-10 18:38:17 +0000387 long unsigned prog,
388 long unsigned version,
389 long unsigned proto,
390 long unsigned port)
Eric Andersenda1d1e72000-07-10 23:39:44 +0000391{
Denis Vlasenko2244a212006-09-10 18:28:23 +0000392 struct pmaplist *pmap;
393 static struct pmap p = {0, 0, 0, 0};
Eric Andersenda1d1e72000-07-10 23:39:44 +0000394
Denis Vlasenko2244a212006-09-10 18:28:23 +0000395 server_addr->sin_port = PMAPPORT;
396 pmap = pmap_getmaps(server_addr);
Eric Andersenda1d1e72000-07-10 23:39:44 +0000397
Denis Vlasenko2244a212006-09-10 18:28:23 +0000398 if (version > MAX_NFSPROT)
399 version = MAX_NFSPROT;
400 if (!prog)
401 prog = MOUNTPROG;
402 p.pm_prog = prog;
403 p.pm_vers = version;
404 p.pm_prot = proto;
405 p.pm_port = port;
406
407 while (pmap) {
408 if (pmap->pml_map.pm_prog != prog)
409 goto next;
410 if (!version && p.pm_vers > pmap->pml_map.pm_vers)
411 goto next;
412 if (version > 2 && pmap->pml_map.pm_vers != version)
413 goto next;
414 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
415 goto next;
416 if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
417 (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
418 (port && pmap->pml_map.pm_port != port))
419 goto next;
420 memcpy(&p, &pmap->pml_map, sizeof(p));
Eric Andersenda1d1e72000-07-10 23:39:44 +0000421next:
Denis Vlasenko2244a212006-09-10 18:28:23 +0000422 pmap = pmap->pml_next;
423 }
424 if (!p.pm_vers)
425 p.pm_vers = MOUNTVERS;
426 if (!p.pm_port)
427 p.pm_port = MOUNTPORT;
428 if (!p.pm_prot)
429 p.pm_prot = IPPROTO_TCP;
430 return &p;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000431}
432
433int nfsmount(const char *spec, const char *node, int *flags,
Rob Landley6a6798b2005-08-10 20:35:54 +0000434 char **mount_opts, int running_bg)
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000435{
436 static char *prev_bg_host;
437 char hostdir[1024];
438 CLIENT *mclient;
439 char *hostname;
Matt Kraaif9d6aa02001-07-26 14:26:53 +0000440 char *pathname;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000441 char *old_opts;
Denis Vlasenko2244a212006-09-10 18:28:23 +0000442 char *mounthost = NULL;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000443 char new_opts[1024];
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000444 struct timeval total_timeout;
445 enum clnt_stat clnt_stat;
Eric Andersen882cec32004-07-26 12:05:12 +0000446 struct nfs_mount_data data;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000447 char *opt, *opteq;
448 int val;
449 struct hostent *hp;
450 struct sockaddr_in server_addr;
451 struct sockaddr_in mount_server_addr;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000452 struct pmap* pm_mnt;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000453 int msock, fsock;
454 struct timeval retry_timeout;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000455 union {
456 struct fhstatus nfsv2;
457 struct mountres3 nfsv3;
458 } status;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000459 struct stat statbuf;
460 char *s;
461 int port;
462 int mountport;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000463 int proto;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000464 int bg;
465 int soft;
466 int intr;
467 int posix;
468 int nocto;
469 int noac;
470 int nolock;
471 int retry;
472 int tcp;
473 int mountprog;
474 int mountvers;
475 int nfsprog;
476 int nfsvers;
477 int retval;
478 time_t t;
479 time_t prevt;
480 time_t timeout;
481
482 find_kernel_nfs_mount_version();
483
484 retval = EX_FAIL;
485 msock = fsock = -1;
486 mclient = NULL;
487 if (strlen(spec) >= sizeof(hostdir)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000488 bb_error_msg("excessively long host:dir argument");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000489 goto fail;
490 }
491 strcpy(hostdir, spec);
492 if ((s = strchr(hostdir, ':'))) {
493 hostname = hostdir;
Matt Kraaif9d6aa02001-07-26 14:26:53 +0000494 pathname = s + 1;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000495 *s = '\0';
496 /* Ignore all but first hostname in replicated mounts
497 until they can be fully supported. (mack@sgi.com) */
498 if ((s = strchr(hostdir, ','))) {
499 *s = '\0';
Manuel Novoa III cad53642003-03-19 09:13:01 +0000500 bb_error_msg("warning: multiple hostnames not supported");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000501 }
502 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000503 bb_error_msg("directory to mount not in host:dir format");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000504 goto fail;
505 }
506
507 server_addr.sin_family = AF_INET;
508#ifdef HAVE_inet_aton
509 if (!inet_aton(hostname, &server_addr.sin_addr))
510#endif
511 {
512 if ((hp = gethostbyname(hostname)) == NULL) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000513 bb_herror_msg("%s", hostname);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000514 goto fail;
515 } else {
516 if (hp->h_length > sizeof(struct in_addr)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000517 bb_error_msg("got bad hp->h_length");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000518 hp->h_length = sizeof(struct in_addr);
519 }
Eric Andersenda1d1e72000-07-10 23:39:44 +0000520 memcpy(&server_addr.sin_addr,
Denis Vlasenko2244a212006-09-10 18:28:23 +0000521 hp->h_addr, hp->h_length);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000522 }
523 }
524
Denis Vlasenko2244a212006-09-10 18:28:23 +0000525 memcpy(&mount_server_addr, &server_addr, sizeof (mount_server_addr));
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000526
527 /* add IP address to mtab options for use when unmounting */
528
529 s = inet_ntoa(server_addr.sin_addr);
Rob Landley6a6798b2005-08-10 20:35:54 +0000530 old_opts = *mount_opts;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000531 if (!old_opts)
532 old_opts = "";
533 if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000534 bb_error_msg("excessively long option argument");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000535 goto fail;
536 }
Eric Andersenda1d1e72000-07-10 23:39:44 +0000537 sprintf(new_opts, "%s%saddr=%s",
538 old_opts, *old_opts ? "," : "", s);
Rob Landleyd921b2e2006-08-03 15:41:12 +0000539 *mount_opts = xstrdup(new_opts);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000540
541 /* Set default options.
542 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
543 * let the kernel decide.
544 * timeo is filled in after we know whether it'll be TCP or UDP. */
545 memset(&data, 0, sizeof(data));
Eric Andersenda1d1e72000-07-10 23:39:44 +0000546 data.retrans = 3;
547 data.acregmin = 3;
548 data.acregmax = 60;
549 data.acdirmin = 30;
550 data.acdirmax = 60;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000551 data.namlen = NAME_MAX;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000552
553 bg = 0;
554 soft = 0;
555 intr = 0;
556 posix = 0;
557 nocto = 0;
558 nolock = 0;
559 noac = 0;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000560 retry = 10000; /* 10000 minutes ~ 1 week */
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000561 tcp = 0;
562
563 mountprog = MOUNTPROG;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000564 mountvers = 0;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000565 port = 0;
566 mountport = 0;
Rob Landleyc27f4f52006-09-08 00:41:48 +0000567 nfsprog = 100003;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000568 nfsvers = 0;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000569
570 /* parse options */
571
572 for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
573 if ((opteq = strchr(opt, '='))) {
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000574 val = atoi(opteq + 1);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000575 *opteq = '\0';
576 if (!strcmp(opt, "rsize"))
577 data.rsize = val;
578 else if (!strcmp(opt, "wsize"))
579 data.wsize = val;
580 else if (!strcmp(opt, "timeo"))
581 data.timeo = val;
582 else if (!strcmp(opt, "retrans"))
583 data.retrans = val;
584 else if (!strcmp(opt, "acregmin"))
585 data.acregmin = val;
586 else if (!strcmp(opt, "acregmax"))
587 data.acregmax = val;
588 else if (!strcmp(opt, "acdirmin"))
589 data.acdirmin = val;
590 else if (!strcmp(opt, "acdirmax"))
591 data.acdirmax = val;
592 else if (!strcmp(opt, "actimeo")) {
593 data.acregmin = val;
594 data.acregmax = val;
595 data.acdirmin = val;
596 data.acdirmax = val;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000597 }
598 else if (!strcmp(opt, "retry"))
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000599 retry = val;
600 else if (!strcmp(opt, "port"))
601 port = val;
602 else if (!strcmp(opt, "mountport"))
Denis Vlasenko2244a212006-09-10 18:28:23 +0000603 mountport = val;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000604 else if (!strcmp(opt, "mounthost"))
Denis Vlasenko2244a212006-09-10 18:28:23 +0000605 mounthost = xstrndup(opteq+1,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000606 strcspn(opteq+1," \t\n\r,"));
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000607 else if (!strcmp(opt, "mountprog"))
608 mountprog = val;
609 else if (!strcmp(opt, "mountvers"))
610 mountvers = val;
611 else if (!strcmp(opt, "nfsprog"))
612 nfsprog = val;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000613 else if (!strcmp(opt, "nfsvers") ||
614 !strcmp(opt, "vers"))
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000615 nfsvers = val;
616 else if (!strcmp(opt, "proto")) {
Eric Andersenda1d1e72000-07-10 23:39:44 +0000617 if (!strncmp(opteq+1, "tcp", 3))
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000618 tcp = 1;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000619 else if (!strncmp(opteq+1, "udp", 3))
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000620 tcp = 0;
621 else
Denis Vlasenko39e93cc2006-09-10 18:38:17 +0000622 bb_error_msg("warning: unrecognized proto= option");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000623 } else if (!strcmp(opt, "namlen")) {
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000624 if (nfs_mount_version >= 2)
625 data.namlen = val;
626 else
Denis Vlasenko39e93cc2006-09-10 18:38:17 +0000627 bb_error_msg("warning: option namlen is not supported\n");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000628 } else if (!strcmp(opt, "addr"))
Eric Andersenda1d1e72000-07-10 23:39:44 +0000629 /* ignore */;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000630 else {
Denis Vlasenko39e93cc2006-09-10 18:38:17 +0000631 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000632 goto fail;
633 }
Eric Andersenda1d1e72000-07-10 23:39:44 +0000634 }
635 else {
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000636 val = 1;
637 if (!strncmp(opt, "no", 2)) {
638 val = 0;
639 opt += 2;
640 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000641 if (!strcmp(opt, "bg"))
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000642 bg = val;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000643 else if (!strcmp(opt, "fg"))
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000644 bg = !val;
645 else if (!strcmp(opt, "soft"))
646 soft = val;
647 else if (!strcmp(opt, "hard"))
648 soft = !val;
649 else if (!strcmp(opt, "intr"))
650 intr = val;
651 else if (!strcmp(opt, "posix"))
652 posix = val;
653 else if (!strcmp(opt, "cto"))
654 nocto = !val;
655 else if (!strcmp(opt, "ac"))
656 noac = !val;
657 else if (!strcmp(opt, "tcp"))
658 tcp = val;
659 else if (!strcmp(opt, "udp"))
660 tcp = !val;
661 else if (!strcmp(opt, "lock")) {
662 if (nfs_mount_version >= 3)
663 nolock = !val;
664 else
Denis Vlasenko39e93cc2006-09-10 18:38:17 +0000665 bb_error_msg("warning: option nolock is not supported");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000666 } else {
Denis Vlasenko39e93cc2006-09-10 18:38:17 +0000667 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
Eric Andersenda1d1e72000-07-10 23:39:44 +0000668 goto fail;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000669 }
670 }
671 }
Eric Andersenda1d1e72000-07-10 23:39:44 +0000672 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
673
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000674 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
675 | (intr ? NFS_MOUNT_INTR : 0)
676 | (posix ? NFS_MOUNT_POSIX : 0)
677 | (nocto ? NFS_MOUNT_NOCTO : 0)
678 | (noac ? NFS_MOUNT_NOAC : 0);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000679 if (nfs_mount_version >= 2)
680 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000681 if (nfs_mount_version >= 3)
682 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
Rob Landley29ba9792006-04-17 23:02:57 +0000683 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000684 bb_error_msg("NFSv%d not supported!", nfsvers);
Rob Landley29ba9792006-04-17 23:02:57 +0000685 return 1;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000686 }
687 if (nfsvers && !mountvers)
688 mountvers = (nfsvers < 3) ? 1 : nfsvers;
689 if (nfsvers && nfsvers < mountvers) {
690 mountvers = nfsvers;
691 }
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000692
693 /* Adjust options if none specified */
694 if (!data.timeo)
695 data.timeo = tcp ? 70 : 7;
696
697#ifdef NFS_MOUNT_DEBUG
698 printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
Eric Andersenda1d1e72000-07-10 23:39:44 +0000699 data.rsize, data.wsize, data.timeo, data.retrans);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000700 printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
Eric Andersenda1d1e72000-07-10 23:39:44 +0000701 data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000702 printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
Eric Andersenda1d1e72000-07-10 23:39:44 +0000703 port, bg, retry, data.flags);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000704 printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
Eric Andersenda1d1e72000-07-10 23:39:44 +0000705 mountprog, mountvers, nfsprog, nfsvers);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000706 printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
Eric Andersenda1d1e72000-07-10 23:39:44 +0000707 (data.flags & NFS_MOUNT_SOFT) != 0,
708 (data.flags & NFS_MOUNT_INTR) != 0,
709 (data.flags & NFS_MOUNT_POSIX) != 0,
710 (data.flags & NFS_MOUNT_NOCTO) != 0,
711 (data.flags & NFS_MOUNT_NOAC) != 0);
Eric Andersenda1d1e72000-07-10 23:39:44 +0000712 printf("tcp = %d\n",
713 (data.flags & NFS_MOUNT_TCP) != 0);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000714#endif
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000715
716 data.version = nfs_mount_version;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000717
718 if (*flags & MS_REMOUNT)
Eric Andersen882cec32004-07-26 12:05:12 +0000719 goto copy_data_and_return;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000720
721 /*
722 * If the previous mount operation on the same host was
723 * backgrounded, and the "bg" for this mount is also set,
724 * give up immediately, to avoid the initial timeout.
725 */
726 if (bg && !running_bg &&
Eric Andersenda1d1e72000-07-10 23:39:44 +0000727 prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000728 if (retry > 0)
729 retval = EX_BG;
730 return retval;
731 }
732
Mike Frysingerfa6c4842006-05-26 01:48:17 +0000733 /* create mount daemon client */
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000734 /* See if the nfs host = mount host. */
735 if (mounthost) {
Denis Vlasenko2244a212006-09-10 18:28:23 +0000736 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
737 mount_server_addr.sin_family = AF_INET;
738 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
739 } else {
740 if ((hp = gethostbyname(mounthost)) == NULL) {
741 bb_herror_msg("%s", mounthost);
742 goto fail;
743 } else {
744 if (hp->h_length > sizeof(struct in_addr)) {
745 bb_error_msg("got bad hp->h_length?");
746 hp->h_length = sizeof(struct in_addr);
747 }
748 mount_server_addr.sin_family = AF_INET;
749 memcpy(&mount_server_addr.sin_addr,
750 hp->h_addr, hp->h_length);
751 }
752 }
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000753 }
754
755 /*
756 * The following loop implements the mount retries. On the first
757 * call, "running_bg" is 0. When the mount times out, and the
758 * "bg" option is set, the exit status EX_BG will be returned.
759 * For a backgrounded mount, there will be a second call by the
760 * child process with "running_bg" set to 1.
761 *
762 * The case where the mount point is not present and the "bg"
763 * option is set, is treated as a timeout. This is done to
764 * support nested mounts.
765 *
766 * The "retry" count specified by the user is the number of
767 * minutes to retry before giving up.
768 *
769 * Only the first error message will be displayed.
770 */
771 retry_timeout.tv_sec = 3;
772 retry_timeout.tv_usec = 0;
773 total_timeout.tv_sec = 20;
774 total_timeout.tv_usec = 0;
775 timeout = time(NULL) + 60 * retry;
776 prevt = 0;
777 t = 30;
778 val = 1;
779 for (;;) {
780 if (bg && stat(node, &statbuf) == -1) {
781 if (running_bg) {
Eric Andersenda1d1e72000-07-10 23:39:44 +0000782 sleep(val); /* 1, 2, 4, 8, 16, 30, ... */
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000783 val *= 2;
784 if (val > 30)
785 val = 30;
786 }
787 } else {
788 /* be careful not to use too many CPU cycles */
789 if (t - prevt < 30)
790 sleep(30);
791
Eric Andersenda1d1e72000-07-10 23:39:44 +0000792 pm_mnt = get_mountport(&mount_server_addr,
Denis Vlasenko2244a212006-09-10 18:28:23 +0000793 mountprog,
794 mountvers,
795 proto,
796 mountport);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000797
Eric Andersenda1d1e72000-07-10 23:39:44 +0000798 /* contact the mount daemon via TCP */
799 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
800 msock = RPC_ANYSOCK;
801
802 switch (pm_mnt->pm_prot) {
803 case IPPROTO_UDP:
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000804 mclient = clntudp_create(&mount_server_addr,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000805 pm_mnt->pm_prog,
806 pm_mnt->pm_vers,
807 retry_timeout,
808 &msock);
Denis Vlasenko2244a212006-09-10 18:28:23 +0000809 if (mclient)
810 break;
811 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
812 msock = RPC_ANYSOCK;
813 case IPPROTO_TCP:
814 mclient = clnttcp_create(&mount_server_addr,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000815 pm_mnt->pm_prog,
816 pm_mnt->pm_vers,
817 &msock, 0, 0);
Denis Vlasenko2244a212006-09-10 18:28:23 +0000818 break;
819 default:
820 mclient = 0;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000821 }
822 if (mclient) {
Matt Kraaif9d6aa02001-07-26 14:26:53 +0000823 /* try to mount hostname:pathname */
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000824 mclient->cl_auth = authunix_create_default();
Eric Andersenda1d1e72000-07-10 23:39:44 +0000825
Denis Vlasenko39e93cc2006-09-10 18:38:17 +0000826 /* make pointers in xdr_mountres3 NULL so
827 * that xdr_array allocates memory for us
828 */
829 memset(&status, 0, sizeof(status));
Eric Andersenda1d1e72000-07-10 23:39:44 +0000830
Denis Vlasenko39e93cc2006-09-10 18:38:17 +0000831 if (pm_mnt->pm_vers == 3)
832 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000833 (xdrproc_t) xdr_dirpath,
Matt Kraaif9d6aa02001-07-26 14:26:53 +0000834 (caddr_t) &pathname,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000835 (xdrproc_t) xdr_mountres3,
836 (caddr_t) &status,
Denis Vlasenko2244a212006-09-10 18:28:23 +0000837 total_timeout);
Denis Vlasenko39e93cc2006-09-10 18:38:17 +0000838 else
839 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000840 (xdrproc_t) xdr_dirpath,
Matt Kraaif9d6aa02001-07-26 14:26:53 +0000841 (caddr_t) &pathname,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000842 (xdrproc_t) xdr_fhstatus,
843 (caddr_t) &status,
844 total_timeout);
845
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000846 if (clnt_stat == RPC_SUCCESS)
847 break; /* we're done */
848 if (errno != ECONNREFUSED) {
849 clnt_perror(mclient, "mount");
850 goto fail; /* don't retry */
851 }
852 if (!running_bg && prevt == 0)
853 clnt_perror(mclient, "mount");
854 auth_destroy(mclient->cl_auth);
855 clnt_destroy(mclient);
856 mclient = 0;
857 close(msock);
858 } else {
859 if (!running_bg && prevt == 0)
860 clnt_pcreateerror("mount");
861 }
862 prevt = t;
863 }
864 if (!bg)
Denis Vlasenko2244a212006-09-10 18:28:23 +0000865 goto fail;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000866 if (!running_bg) {
Rob Landleyd921b2e2006-08-03 15:41:12 +0000867 prev_bg_host = xstrdup(hostname);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000868 if (retry > 0)
869 retval = EX_BG;
870 goto fail;
871 }
872 t = time(NULL);
873 if (t >= timeout)
874 goto fail;
875 }
Eric Andersenda1d1e72000-07-10 23:39:44 +0000876 nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000877
Eric Andersenda1d1e72000-07-10 23:39:44 +0000878 if (nfsvers == 2) {
879 if (status.nfsv2.fhs_status != 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000880 bb_error_msg("%s:%s failed, reason given by server: %s",
Matt Kraaif9d6aa02001-07-26 14:26:53 +0000881 hostname, pathname,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000882 nfs_strerror(status.nfsv2.fhs_status));
883 goto fail;
884 }
885 memcpy(data.root.data,
Denis Vlasenko2244a212006-09-10 18:28:23 +0000886 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
887 NFS_FHSIZE);
Eric Andersenda1d1e72000-07-10 23:39:44 +0000888 data.root.size = NFS_FHSIZE;
889 memcpy(data.old_root.data,
Denis Vlasenko2244a212006-09-10 18:28:23 +0000890 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
891 NFS_FHSIZE);
Eric Andersenda1d1e72000-07-10 23:39:44 +0000892 } else {
Eric Andersen851895a2001-03-21 21:52:25 +0000893 fhandle3 *my_fhandle;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000894 if (status.nfsv3.fhs_status != 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000895 bb_error_msg("%s:%s failed, reason given by server: %s",
Matt Kraaif9d6aa02001-07-26 14:26:53 +0000896 hostname, pathname,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000897 nfs_strerror(status.nfsv3.fhs_status));
898 goto fail;
899 }
Eric Andersen851895a2001-03-21 21:52:25 +0000900 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000901 memset(data.old_root.data, 0, NFS_FHSIZE);
902 memset(&data.root, 0, sizeof(data.root));
Eric Andersen851895a2001-03-21 21:52:25 +0000903 data.root.size = my_fhandle->fhandle3_len;
Eric Andersenda1d1e72000-07-10 23:39:44 +0000904 memcpy(data.root.data,
Denis Vlasenko2244a212006-09-10 18:28:23 +0000905 (char *) my_fhandle->fhandle3_val,
906 my_fhandle->fhandle3_len);
Eric Andersenda1d1e72000-07-10 23:39:44 +0000907
908 data.flags |= NFS_MOUNT_VER3;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000909 }
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000910
911 /* create nfs socket for kernel */
912
913 if (tcp) {
914 if (nfs_mount_version < 3) {
Denis Vlasenko39e93cc2006-09-10 18:38:17 +0000915 bb_error_msg("NFS over TCP is not supported");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000916 goto fail;
917 }
918 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
919 } else
920 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
921 if (fsock < 0) {
Rob Landley83947292006-05-29 04:49:55 +0000922 perror("nfs socket");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000923 goto fail;
924 }
925 if (bindresvport(fsock, 0) < 0) {
Rob Landley83947292006-05-29 04:49:55 +0000926 perror("nfs bindresvport");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000927 goto fail;
928 }
929 if (port == 0) {
930 server_addr.sin_port = PMAPPORT;
931 port = pmap_getport(&server_addr, nfsprog, nfsvers,
Eric Andersenda1d1e72000-07-10 23:39:44 +0000932 tcp ? IPPROTO_TCP : IPPROTO_UDP);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000933 if (port == 0)
934 port = NFS_PORT;
935#ifdef NFS_MOUNT_DEBUG
936 else
Rob Landley83947292006-05-29 04:49:55 +0000937 printf("used portmapper to find NFS port\n");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000938#endif
939 }
940#ifdef NFS_MOUNT_DEBUG
Rob Landley83947292006-05-29 04:49:55 +0000941 printf("using port %d for nfs daemon\n", port);
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000942#endif
943 server_addr.sin_port = htons(port);
Denis Vlasenko39e93cc2006-09-10 18:38:17 +0000944 /*
945 * connect() the socket for kernels 1.3.10 and below only,
946 * to avoid problems with multihomed hosts.
947 * --Swen
948 */
Bernhard Reutner-Fischere2e56c72006-05-19 11:54:02 +0000949 if (get_linux_version_code() <= KERNEL_VERSION(2,3,10)
Eric Andersenda1d1e72000-07-10 23:39:44 +0000950 && connect(fsock, (struct sockaddr *) &server_addr,
Denis Vlasenko2244a212006-09-10 18:28:23 +0000951 sizeof (server_addr)) < 0) {
Rob Landley83947292006-05-29 04:49:55 +0000952 perror("nfs connect");
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000953 goto fail;
954 }
955
956 /* prepare data structure for kernel */
957
958 data.fd = fsock;
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000959 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
960 strncpy(data.hostname, hostname, sizeof(data.hostname));
961
962 /* clean up */
963
964 auth_destroy(mclient->cl_auth);
965 clnt_destroy(mclient);
966 close(msock);
Eric Andersen882cec32004-07-26 12:05:12 +0000967copy_data_and_return:
968 *mount_opts = xrealloc(*mount_opts, sizeof(data));
969 memcpy(*mount_opts, &data, sizeof(data));
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000970 return 0;
971
972 /* abort */
973
Eric Andersenda1d1e72000-07-10 23:39:44 +0000974fail:
Eric Andersen1c43d0c1999-11-18 07:58:07 +0000975 if (msock != -1) {
976 if (mclient) {
977 auth_destroy(mclient->cl_auth);
978 clnt_destroy(mclient);
979 }
980 close(msock);
981 }
982 if (fsock != -1)
983 close(fsock);
984 return retval;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000985}