2 * nfsmount.c -- Linux NFS mount
3 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
16 * numbers to be specified on the command line.
18 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
19 * Omit the call to connect() for Linux version 1.3.11 or later.
21 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
22 * Implemented the "bg", "fg" and "retry" mount options for NFS.
24 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
25 * - added Native Language Support
27 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
30 * 2006-06-06 Amit Gud <agud@redhat.com>
31 * - Moved with modifcations to nfs-utils/utils/mount from util-linux/mount.
35 * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
51 #include <rpc/pmap_prot.h>
52 #include <rpc/pmap_clnt.h>
53 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
59 #include <sys/mount.h>
65 #include "nfs_mount.h"
66 #include "mount_constants.h"
72 #ifdef HAVE_RPCSVC_NFS_PROT_H
73 #include <rpcsvc/nfs_prot.h>
75 #include <linux/nfs.h>
76 #define nfsstat nfs_stat
86 #ifndef HAVE_INET_ATON
87 #define inet_aton(a,b) (0)
90 typedef dirpath mnt2arg_t
;
91 typedef dirpath mnt3arg_t
;
92 typedef dirpath mntarg_t
;
94 typedef struct fhstatus mnt2res_t
;
95 typedef struct mountres3 mnt3res_t
;
101 extern int nfs_mount_data_version
;
102 extern char *progname
;
106 static inline enum clnt_stat
107 nfs3_mount(CLIENT
*clnt
, mnt3arg_t
*mnt3arg
, mnt3res_t
*mnt3res
)
109 return clnt_call(clnt
, MOUNTPROC3_MNT
,
110 (xdrproc_t
) xdr_dirpath
, (caddr_t
) mnt3arg
,
111 (xdrproc_t
) xdr_mountres3
, (caddr_t
) mnt3res
,
115 static inline enum clnt_stat
116 nfs2_mount(CLIENT
*clnt
, mnt2arg_t
*mnt2arg
, mnt2res_t
*mnt2res
)
118 return clnt_call(clnt
, MOUNTPROC_MNT
,
119 (xdrproc_t
) xdr_dirpath
, (caddr_t
) mnt2arg
,
120 (xdrproc_t
) xdr_fhstatus
, (caddr_t
) mnt2res
,
125 nfs_call_mount(clnt_addr_t
*mnt_server
, clnt_addr_t
*nfs_server
,
126 mntarg_t
*mntarg
, mntres_t
*mntres
)
132 if (!probe_bothports(mnt_server
, nfs_server
))
135 clnt
= mnt_openclnt(mnt_server
, &msock
);
138 /* make pointers in xdr_mountres3 NULL so
139 * that xdr_array allocates memory for us
141 memset(mntres
, 0, sizeof(*mntres
));
142 switch (mnt_server
->pmap
.pm_vers
) {
144 stat
= nfs3_mount(clnt
, mntarg
, &mntres
->nfsv3
);
148 stat
= nfs2_mount(clnt
, mntarg
, &mntres
->nfsv2
);
153 if (stat
!= RPC_SUCCESS
) {
154 clnt_geterr(clnt
, &rpc_createerr
.cf_error
);
155 rpc_createerr
.cf_stat
= stat
;
157 mnt_closeclnt(clnt
, msock
);
158 if (stat
== RPC_SUCCESS
)
165 parse_options(char *old_opts
, struct nfs_mount_data
*data
,
166 int *bg
, int *retry
, clnt_addr_t
*mnt_server
,
167 clnt_addr_t
*nfs_server
, char *new_opts
, const int opt_size
)
169 struct sockaddr_in
*mnt_saddr
= &mnt_server
->saddr
;
170 struct pmap
*mnt_pmap
= &mnt_server
->pmap
;
171 struct pmap
*nfs_pmap
= &nfs_server
->pmap
;
173 char *opt
, *opteq
, *p
, *opt_b
;
174 char *mounthost
= NULL
;
181 len
= strlen(new_opts
);
182 for (p
=old_opts
, opt_b
=NULL
; p
&& *p
; p
++) {
184 opt_b
= p
; /* begin of the option item */
186 open_quote
^= 1; /* reverse the status */
188 continue; /* still in a quoted block */
190 *p
= '\0'; /* terminate the option item */
191 if (*p
== '\0' || *(p
+1) == '\0') {
192 opt
= opt_b
; /* opt is useful now */
196 continue; /* still somewhere in the option item */
198 if (strlen(opt
) >= sizeof(cbuf
))
200 if ((opteq
= strchr(opt
, '=')) && isdigit(opteq
[1])) {
201 int val
= atoi(opteq
+ 1);
203 if (!strcmp(opt
, "rsize"))
205 else if (!strcmp(opt
, "wsize"))
207 else if (!strcmp(opt
, "timeo"))
209 else if (!strcmp(opt
, "retrans"))
211 else if (!strcmp(opt
, "acregmin"))
212 data
->acregmin
= val
;
213 else if (!strcmp(opt
, "acregmax"))
214 data
->acregmax
= val
;
215 else if (!strcmp(opt
, "acdirmin"))
216 data
->acdirmin
= val
;
217 else if (!strcmp(opt
, "acdirmax"))
218 data
->acdirmax
= val
;
219 else if (!strcmp(opt
, "actimeo")) {
220 data
->acregmin
= val
;
221 data
->acregmax
= val
;
222 data
->acdirmin
= val
;
223 data
->acdirmax
= val
;
225 else if (!strcmp(opt
, "retry"))
227 else if (!strcmp(opt
, "port"))
228 nfs_pmap
->pm_port
= val
;
229 else if (!strcmp(opt
, "mountport"))
230 mnt_pmap
->pm_port
= val
;
231 else if (!strcmp(opt
, "mountprog"))
232 mnt_pmap
->pm_prog
= val
;
233 else if (!strcmp(opt
, "mountvers"))
234 mnt_pmap
->pm_vers
= val
;
235 else if (!strcmp(opt
, "mounthost"))
236 mounthost
=xstrndup(opteq
+1, strcspn(opteq
+1," \t\n\r,"));
237 else if (!strcmp(opt
, "nfsprog"))
238 nfs_pmap
->pm_prog
= val
;
239 else if (!strcmp(opt
, "nfsvers") ||
240 !strcmp(opt
, "vers")) {
241 nfs_pmap
->pm_vers
= val
;
243 #if NFS_MOUNT_VERSION >= 2
244 } else if (!strcmp(opt
, "namlen")) {
245 if (nfs_mount_data_version
>= 2)
252 } else if (!strcmp(opt
, "addr")) {
259 sprintf(cbuf
, "%s=%s,", opt
, opteq
+1);
262 if (!strcmp(opt
, "proto")) {
263 if (!strcmp(opteq
+1, "udp")) {
264 nfs_pmap
->pm_prot
= IPPROTO_UDP
;
265 mnt_pmap
->pm_prot
= IPPROTO_UDP
;
266 #if NFS_MOUNT_VERSION >= 2
267 data
->flags
&= ~NFS_MOUNT_TCP
;
268 } else if (!strcmp(opteq
+1, "tcp") &&
269 nfs_mount_data_version
> 2) {
270 nfs_pmap
->pm_prot
= IPPROTO_TCP
;
271 mnt_pmap
->pm_prot
= IPPROTO_TCP
;
272 data
->flags
|= NFS_MOUNT_TCP
;
278 #if NFS_MOUNT_VERSION >= 5
279 } else if (!strcmp(opt
, "sec")) {
280 char *secflavor
= opteq
+1;
282 if (nfs_mount_data_version
< 5) {
283 printf(_("Warning: ignoring sec=%s option\n"),
286 } else if (!strcmp(secflavor
, "none"))
287 data
->pseudoflavor
= AUTH_NONE
;
288 else if (!strcmp(secflavor
, "sys"))
289 data
->pseudoflavor
= AUTH_SYS
;
290 else if (!strcmp(secflavor
, "krb5"))
291 data
->pseudoflavor
= AUTH_GSS_KRB5
;
292 else if (!strcmp(secflavor
, "krb5i"))
293 data
->pseudoflavor
= AUTH_GSS_KRB5I
;
294 else if (!strcmp(secflavor
, "krb5p"))
295 data
->pseudoflavor
= AUTH_GSS_KRB5P
;
296 else if (!strcmp(secflavor
, "lipkey"))
297 data
->pseudoflavor
= AUTH_GSS_LKEY
;
298 else if (!strcmp(secflavor
, "lipkey-i"))
299 data
->pseudoflavor
= AUTH_GSS_LKEYI
;
300 else if (!strcmp(secflavor
, "lipkey-p"))
301 data
->pseudoflavor
= AUTH_GSS_LKEYP
;
302 else if (!strcmp(secflavor
, "spkm3"))
303 data
->pseudoflavor
= AUTH_GSS_SPKM
;
304 else if (!strcmp(secflavor
, "spkm3i"))
305 data
->pseudoflavor
= AUTH_GSS_SPKMI
;
306 else if (!strcmp(secflavor
, "spkm3p"))
307 data
->pseudoflavor
= AUTH_GSS_SPKMP
;
311 printf(_("Warning: Unrecognized security flavor %s.\n"),
315 data
->flags
|= NFS_MOUNT_SECFLAVOUR
;
317 } else if (!strcmp(opt
, "mounthost"))
318 mounthost
=xstrndup(opteq
+1,
319 strcspn(opteq
+1," \t\n\r,"));
320 else if (!strcmp(opt
, "context")) {
321 char *context
= opteq
+ 1;
322 int ctxlen
= strlen(context
);
324 if (ctxlen
> NFS_MAX_CONTEXT_LEN
) {
325 nfs_error(_("context parameter exceeds"
327 NFS_MAX_CONTEXT_LEN
);
330 /* The context string is in the format of
331 * "system_u:object_r:...". We only want
332 * the context str between the quotes.
335 strncpy(data
->context
, context
+1,
338 strncpy(data
->context
, context
,
339 NFS_MAX_CONTEXT_LEN
);
344 sprintf(cbuf
, "%s=%s,", opt
, opteq
+1);
347 if (!strncmp(opt
, "no", 2)) {
351 if (!strcmp(opt
, "bg"))
353 else if (!strcmp(opt
, "fg"))
355 else if (!strcmp(opt
, "soft")) {
356 data
->flags
&= ~NFS_MOUNT_SOFT
;
358 data
->flags
|= NFS_MOUNT_SOFT
;
359 } else if (!strcmp(opt
, "hard")) {
360 data
->flags
&= ~NFS_MOUNT_SOFT
;
362 data
->flags
|= NFS_MOUNT_SOFT
;
363 } else if (!strcmp(opt
, "intr")) {
364 data
->flags
&= ~NFS_MOUNT_INTR
;
366 data
->flags
|= NFS_MOUNT_INTR
;
367 } else if (!strcmp(opt
, "posix")) {
368 data
->flags
&= ~NFS_MOUNT_POSIX
;
370 data
->flags
|= NFS_MOUNT_POSIX
;
371 } else if (!strcmp(opt
, "cto")) {
372 data
->flags
&= ~NFS_MOUNT_NOCTO
;
374 data
->flags
|= NFS_MOUNT_NOCTO
;
375 } else if (!strcmp(opt
, "ac")) {
376 data
->flags
&= ~NFS_MOUNT_NOAC
;
378 data
->flags
|= NFS_MOUNT_NOAC
;
379 #if NFS_MOUNT_VERSION >= 2
380 } else if (!strcmp(opt
, "tcp")) {
381 data
->flags
&= ~NFS_MOUNT_TCP
;
383 if (nfs_mount_data_version
< 2)
385 nfs_pmap
->pm_prot
= IPPROTO_TCP
;
386 mnt_pmap
->pm_prot
= IPPROTO_TCP
;
387 data
->flags
|= NFS_MOUNT_TCP
;
389 mnt_pmap
->pm_prot
= IPPROTO_UDP
;
390 nfs_pmap
->pm_prot
= IPPROTO_UDP
;
392 } else if (!strcmp(opt
, "udp")) {
393 data
->flags
&= ~NFS_MOUNT_TCP
;
395 if (nfs_mount_data_version
< 2)
397 nfs_pmap
->pm_prot
= IPPROTO_TCP
;
398 mnt_pmap
->pm_prot
= IPPROTO_TCP
;
399 data
->flags
|= NFS_MOUNT_TCP
;
401 nfs_pmap
->pm_prot
= IPPROTO_UDP
;
402 mnt_pmap
->pm_prot
= IPPROTO_UDP
;
405 #if NFS_MOUNT_VERSION >= 3
406 } else if (!strcmp(opt
, "lock")) {
407 data
->flags
&= ~NFS_MOUNT_NONLM
;
409 if (nfs_mount_data_version
< 3)
411 data
->flags
|= NFS_MOUNT_NONLM
;
414 #if NFS_MOUNT_VERSION >= 4
415 } else if (!strcmp(opt
, "broken_suid")) {
416 data
->flags
&= ~NFS_MOUNT_BROKEN_SUID
;
418 if (nfs_mount_data_version
< 4)
420 data
->flags
|= NFS_MOUNT_BROKEN_SUID
;
422 } else if (!strcmp(opt
, "acl")) {
423 data
->flags
&= ~NFS_MOUNT_NOACL
;
425 data
->flags
|= NFS_MOUNT_NOACL
;
426 } else if (!strcmp(opt
, "rdirplus")) {
427 data
->flags
&= ~NFS_MOUNT_NORDIRPLUS
;
429 data
->flags
|= NFS_MOUNT_NORDIRPLUS
;
430 } else if (!strcmp(opt
, "sharecache")) {
431 data
->flags
&= ~NFS_MOUNT_UNSHARED
;
433 data
->flags
|= NFS_MOUNT_UNSHARED
;
439 nfs_error(_("%s: Unsupported nfs mount option:"
441 val
? "" : "no", opt
);
444 sprintf(cbuf
, val
? "%s," : "no%s,", opt
);
447 if (len
>= opt_size
) {
448 nfs_error(_("%s: excessively long option argument"),
452 strcat(new_opts
, cbuf
);
454 /* See if the nfs host = mount host. */
456 if (!nfs_gethostbyname(mounthost
, mnt_saddr
))
458 *mnt_server
->hostname
= mounthost
;
462 nfs_error(_("%s: Bad nfs mount parameter: %s\n"), progname
, opt
);
467 static int nfsmnt_check_compat(const struct pmap
*nfs_pmap
,
468 const struct pmap
*mnt_pmap
)
470 unsigned int max_nfs_vers
= (nfs_mount_data_version
>= 4) ? 3 : 2;
471 unsigned int max_mnt_vers
= (nfs_mount_data_version
>= 4) ? 3 : 2;
473 if (nfs_pmap
->pm_vers
== 4) {
474 nfs_error(_("%s: Please use '-t nfs4' "
475 "instead of '-o vers=4'"), progname
);
479 if (nfs_pmap
->pm_vers
) {
480 if (nfs_pmap
->pm_vers
> max_nfs_vers
|| nfs_pmap
->pm_vers
< 2) {
481 nfs_error(_("%s: NFS version %ld is not supported"),
482 progname
, nfs_pmap
->pm_vers
);
487 if (mnt_pmap
->pm_vers
> max_mnt_vers
) {
488 nfs_error(_("%s: NFS mount version %ld is not supported"),
489 progname
, mnt_pmap
->pm_vers
);
500 nfsmount(const char *spec
, const char *node
, int flags
,
501 char **extra_opts
, int fake
, int running_bg
)
504 char *hostname
, *dirname
, *old_opts
, *mounthost
= NULL
;
505 char new_opts
[1024], cbuf
[1024];
506 static struct nfs_mount_data data
;
508 static int doonce
= 0;
510 clnt_addr_t mnt_server
= { &mounthost
, };
511 clnt_addr_t nfs_server
= { &hostname
, };
512 struct sockaddr_in
*nfs_saddr
= &nfs_server
.saddr
;
513 struct pmap
*mnt_pmap
= &mnt_server
.pmap
,
514 *nfs_pmap
= &nfs_server
.pmap
;
515 struct pmap save_mnt
, save_nfs
;
524 int retval
= EX_FAIL
;
529 if (strlen(spec
) >= sizeof(hostdir
)) {
530 nfs_error(_("%s: excessively long host:dir argument"),
534 strcpy(hostdir
, spec
);
535 if ((s
= strchr(hostdir
, ':'))) {
539 /* Ignore all but first hostname in replicated mounts
540 until they can be fully supported. (mack@sgi.com) */
541 if ((s
= strchr(hostdir
, ','))) {
543 nfs_error(_("%s: warning: "
544 "multiple hostnames not supported"),
548 nfs_error(_("%s: directory to mount not in host:dir format"),
553 if (!nfs_gethostbyname(hostname
, nfs_saddr
))
555 mounthost
= hostname
;
556 memcpy (&mnt_server
.saddr
, nfs_saddr
, sizeof (mnt_server
.saddr
));
558 /* add IP address to mtab options for use when unmounting */
560 s
= inet_ntoa(nfs_saddr
->sin_addr
);
561 old_opts
= *extra_opts
;
565 /* Set default options.
566 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
567 * let the kernel decide.
568 * timeo is filled in after we know whether it'll be TCP or UDP. */
569 memset(&data
, 0, sizeof(data
));
574 #if NFS_MOUNT_VERSION >= 2
575 data
.namlen
= NAME_MAX
;
581 memset(mnt_pmap
, 0, sizeof(*mnt_pmap
));
582 mnt_pmap
->pm_prog
= MOUNTPROG
;
583 memset(nfs_pmap
, 0, sizeof(*nfs_pmap
));
584 nfs_pmap
->pm_prog
= NFS_PROGRAM
;
588 if (!parse_options(old_opts
, &data
, &bg
, &retry
, &mnt_server
, &nfs_server
,
589 new_opts
, sizeof(new_opts
)))
591 if (!nfsmnt_check_compat(nfs_pmap
, mnt_pmap
))
596 retry
= 10000; /* 10000 mins == ~1 week*/
598 retry
= 2; /* 2 min default on fg mounts */
601 #ifdef NFS_MOUNT_DEBUG
602 printf(_("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n"),
603 data
.rsize
, data
.wsize
, data
.timeo
, data
.retrans
);
604 printf(_("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n"),
605 data
.acregmin
, data
.acregmax
, data
.acdirmin
, data
.acdirmax
);
606 printf(_("port = %lu, bg = %d, retry = %d, flags = %.8x\n"),
607 nfs_pmap
->pm_port
, bg
, retry
, data
.flags
);
608 printf(_("mountprog = %lu, mountvers = %lu, nfsprog = %lu, nfsvers = %lu\n"),
609 mnt_pmap
->pm_prog
, mnt_pmap
->pm_vers
,
610 nfs_pmap
->pm_prog
, nfs_pmap
->pm_vers
);
611 printf(_("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d"),
612 (data
.flags
& NFS_MOUNT_SOFT
) != 0,
613 (data
.flags
& NFS_MOUNT_INTR
) != 0,
614 (data
.flags
& NFS_MOUNT_POSIX
) != 0,
615 (data
.flags
& NFS_MOUNT_NOCTO
) != 0,
616 (data
.flags
& NFS_MOUNT_NOAC
) != 0);
617 #if NFS_MOUNT_VERSION >= 2
618 printf(_(", tcp = %d"),
619 (data
.flags
& NFS_MOUNT_TCP
) != 0);
621 #if NFS_MOUNT_VERSION >= 4
622 printf(_(", noacl = %d"), (data
.flags
& NFS_MOUNT_NOACL
) != 0);
624 #if NFS_MOUNT_VERSION >= 5
625 printf(_(", sec = %u"), data
.pseudoflavor
);
626 printf(_(", readdirplus = %d"), (data
.flags
& NFS_MOUNT_NORDIRPLUS
) != 0);
631 data
.version
= nfs_mount_data_version
;
633 if (flags
& MS_REMOUNT
)
636 /* create mount deamon client */
639 * The following loop implements the mount retries. On the first
640 * call, "running_bg" is 0. When the mount times out, and the
641 * "bg" option is set, the exit status EX_BG will be returned.
642 * For a backgrounded mount, there will be a second call by the
643 * child process with "running_bg" set to 1.
645 * The case where the mount point is not present and the "bg"
646 * option is set, is treated as a timeout. This is done to
647 * support nested mounts.
649 * The "retry" count specified by the user is the number of
650 * minutes to retry before giving up.
652 * Only the first error message will be displayed.
654 timeout
= time(NULL
) + 60 * retry
;
659 memcpy(&save_nfs
, nfs_pmap
, sizeof(save_nfs
));
660 memcpy(&save_mnt
, mnt_pmap
, sizeof(save_mnt
));
662 if (bg
&& stat(node
, &statbuf
) == -1) {
663 /* no mount point yet - sleep */
665 sleep(val
); /* 1, 2, 4, 8, 16, 30, ... */
672 /* be careful not to use too many CPU cycles */
676 stat
= nfs_call_mount(&mnt_server
, &nfs_server
,
680 memcpy(nfs_pmap
, &save_nfs
, sizeof(*nfs_pmap
));
681 memcpy(mnt_pmap
, &save_mnt
, sizeof(*mnt_pmap
));
685 switch(rpc_createerr
.cf_stat
){
688 case RPC_SYSTEMERROR
:
689 if (errno
== ETIMEDOUT
)
692 rpc_mount_errors(*nfs_server
.hostname
, 0, bg
);
697 rpc_mount_errors(*nfs_server
.hostname
, 0, bg
);
700 rpc_mount_errors(*nfs_server
.hostname
, 1, bg
);
710 rpc_mount_errors(*nfs_server
.hostname
, 0, bg
);
714 rpc_mount_errors(*nfs_server
.hostname
, 1, bg
);
717 if (mnt_pmap
->pm_vers
<= 2) {
718 if (mntres
.nfsv2
.fhs_status
!= 0) {
719 nfs_error(_("%s: %s:%s failed, reason given by server: %s"),
720 progname
, hostname
, dirname
,
721 nfs_strerror(mntres
.nfsv2
.fhs_status
));
724 memcpy(data
.root
.data
,
725 (char *) mntres
.nfsv2
.fhstatus_u
.fhs_fhandle
,
727 #if NFS_MOUNT_VERSION >= 4
728 data
.root
.size
= NFS_FHSIZE
;
729 memcpy(data
.old_root
.data
,
730 (char *) mntres
.nfsv2
.fhstatus_u
.fhs_fhandle
,
734 #if NFS_MOUNT_VERSION >= 4
735 mountres3_ok
*mountres
;
737 int i
, n_flavors
, *flavor
, yum
= 0;
738 if (mntres
.nfsv3
.fhs_status
!= 0) {
739 nfs_error(_("%s: %s:%s failed, reason given by server: %s"),
740 progname
, hostname
, dirname
,
741 nfs_strerror(mntres
.nfsv3
.fhs_status
));
744 #if NFS_MOUNT_VERSION >= 5
745 mountres
= &mntres
.nfsv3
.mountres3_u
.mountinfo
;
746 n_flavors
= mountres
->auth_flavors
.auth_flavors_len
;
750 flavor
= mountres
->auth_flavors
.auth_flavors_val
;
751 for (i
= 0; i
< n_flavors
; ++i
) {
753 * Per RFC2623, section 2.7, we should prefer the
754 * flavour listed first.
755 * If no flavour requested, use the first simple
756 * flavour that is offered.
758 if (! (data
.flags
& NFS_MOUNT_SECFLAVOUR
) &&
759 (flavor
[i
] == AUTH_SYS
||
760 flavor
[i
] == AUTH_NONE
)) {
761 data
.pseudoflavor
= flavor
[i
];
762 data
.flags
|= NFS_MOUNT_SECFLAVOUR
;
764 if (flavor
[i
] == data
.pseudoflavor
)
766 #ifdef NFS_MOUNT_DEBUG
767 printf(_("auth flavor %d: %d\n"), i
, flavor
[i
]);
771 nfs_error(_("%s: %s:%s failed, security flavor "
773 progname
, hostname
, dirname
);
774 /* server has registered us in rmtab, send umount */
775 nfs_call_umount(&mnt_server
, &dirname
);
780 fhandle
= &mntres
.nfsv3
.mountres3_u
.mountinfo
.fhandle
;
781 memset(data
.old_root
.data
, 0, NFS_FHSIZE
);
782 memset(&data
.root
, 0, sizeof(data
.root
));
783 data
.root
.size
= fhandle
->fhandle3_len
;
784 memcpy(data
.root
.data
,
785 (char *) fhandle
->fhandle3_val
,
786 fhandle
->fhandle3_len
);
788 data
.flags
|= NFS_MOUNT_VER3
;
792 if (nfs_mount_data_version
== 1) {
793 /* create nfs socket for kernel */
794 if (nfs_pmap
->pm_prot
== IPPROTO_TCP
)
795 fsock
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
797 fsock
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
799 perror(_("nfs socket"));
802 if (bindresvport(fsock
, 0) < 0) {
803 perror(_("nfs bindresvport"));
808 #ifdef NFS_MOUNT_DEBUG
809 printf(_("using port %lu for nfs deamon\n"), nfs_pmap
->pm_port
);
811 nfs_saddr
->sin_port
= htons(nfs_pmap
->pm_port
);
813 * connect() the socket for kernels 1.3.10 and below only,
814 * to avoid problems with multihomed hosts.
817 if (linux_version_code() <= MAKE_VERSION(1, 3, 10) && fsock
!= -1
818 && connect(fsock
, (struct sockaddr
*) nfs_saddr
,
819 sizeof (*nfs_saddr
)) < 0) {
820 perror(_("nfs connect"));
824 #if NFS_MOUNT_VERSION >= 2
825 if (nfs_pmap
->pm_prot
== IPPROTO_TCP
)
826 data
.flags
|= NFS_MOUNT_TCP
;
828 data
.flags
&= ~NFS_MOUNT_TCP
;
831 /* prepare data structure for kernel */
834 memcpy((char *) &data
.addr
, (char *) nfs_saddr
, sizeof(data
.addr
));
835 strncpy(data
.hostname
, hostname
, sizeof(data
.hostname
));
838 /* Ensure we have enough padding for the following strcat()s */
839 if (strlen(new_opts
) + strlen(s
) + 30 >= sizeof(new_opts
)) {
840 nfs_error(_("%s: excessively long option argument"),
845 snprintf(cbuf
, sizeof(cbuf
)-1, "addr=%s", s
);
846 strcat(new_opts
, cbuf
);
848 *extra_opts
= xstrdup(new_opts
);
850 if (!fake
&& !(data
.flags
& NFS_MOUNT_NONLM
)) {
851 if (!start_statd()) {
852 nfs_error(_("%s: rpc.statd is not running but is "
853 "required for remote locking.\n"
854 " Either use '-o nolock' to keep "
855 "locks local, or start statd."),
862 if (mount(spec
, node
, "nfs",
863 flags
& ~(MS_USER
|MS_USERS
), &data
)) {
864 mount_error(spec
, node
, errno
);