4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
53 #include <sys/param.h>
58 #include <sys/mount.h>
59 #include <sys/mntent.h>
60 #include <sys/mnttab.h>
62 #include <nfs/mount.h>
63 #include <rpcsvc/mount.h>
64 #include <sys/pathconf.h>
66 #include <netconfig.h>
67 #include <sys/sockio.h>
74 #include <netinet/in.h>
75 #include <nfs/nfs_sec.h>
76 #include <rpcsvc/daemon_utils.h>
80 #include <rpcsvc/nfs4_prot.h>
86 #include <nfs/nfssys.h>
87 extern int _nfssys(enum nfssys_op
, void *);
99 #define RET_MNTERR 1000
100 #define ERR_PROTO_NONE 0
101 #define ERR_PROTO_INVALID 901
102 #define ERR_PROTO_UNSUPP 902
103 #define ERR_NETPATH 903
104 #define ERR_NOHOST 904
105 #define ERR_RPCERROR 905
107 typedef struct err_ret
{
112 #define SET_ERR_RET(errst, etype, eval) \
114 (errst)->error_type = etype; \
115 (errst)->error_value = eval; \
118 /* number of transports to try */
119 #define MNT_PREF_LISTLEN 2
123 #define BIGRETRY 10000
125 /* maximum length of RPC header for NFS messages */
126 #define NFS_RPC_HDR 432
128 #define NFS_ARGS_EXTB_secdata(args, secdata) \
129 { (args)->nfs_args_ext = NFS_ARGS_EXTB, \
130 (args)->nfs_ext_u.nfs_extB.secdata = secdata; }
132 extern int __clnt_bindresvport(CLIENT
*);
133 extern char *nfs_get_qop_name();
134 extern AUTH
* nfs_create_ah();
135 extern enum snego_stat
nfs_sec_nego();
137 static void usage(void);
138 static int retry(struct mnttab
*, int);
139 static int set_args(int *, struct nfs_args
*, char *, struct mnttab
*);
140 static int get_fh_via_pub(struct nfs_args
*, char *, char *, bool_t
, bool_t
,
141 int *, struct netconfig
**, ushort_t
);
142 static int get_fh(struct nfs_args
*, char *, char *, int *, bool_t
,
143 struct netconfig
**, ushort_t
);
144 static int make_secure(struct nfs_args
*, char *, struct netconfig
*,
146 static int mount_nfs(struct mnttab
*, int, err_ret_t
*);
147 static int getaddr_nfs(struct nfs_args
*, char *, struct netconfig
**,
148 bool_t
, char *, ushort_t
, err_ret_t
*, bool_t
);
149 static void pr_err(const char *fmt
, ...);
150 static void usage(void);
151 static struct netbuf
*get_addr(char *, rpcprog_t
, rpcvers_t
,
152 struct netconfig
**, char *, ushort_t
, struct t_info
*,
153 caddr_t
*, bool_t
, char *, err_ret_t
*);
155 static struct netbuf
*get_the_addr(char *, rpcprog_t
, rpcvers_t
,
156 struct netconfig
*, ushort_t
, struct t_info
*, caddr_t
*,
157 bool_t
, char *, err_ret_t
*);
159 extern int self_check(char *);
161 static void read_default(void);
163 static char typename
[64];
166 static int backgrounded
= 0;
167 static int posix
= 0;
168 static int retries
= BIGRETRY
;
169 static ushort_t nfs_port
= 0;
170 static char *nfs_proto
= NULL
;
173 static int Oflg
= 0; /* Overlay mounts */
174 static int qflg
= 0; /* quiet - don't print warnings on bad options */
176 static char *fstype
= MNTTYPE_NFS
;
178 static seconfig_t nfs_sec
;
179 static int sec_opt
= 0; /* any security option ? */
180 static bool_t snego_done
;
181 static void sigusr1(int);
183 extern void set_nfsv4_ephemeral_mount_to(void);
186 * list of support services needed
188 static char *service_list
[] = { STATD
, LOCKD
, NULL
};
189 static char *service_list_v4
[] = { STATD
, LOCKD
, NFS4CBD
, NFSMAPID
, NULL
};
192 * These two variables control the NFS version number to be used.
194 * nfsvers defaults to 0 which means to use the highest number that
195 * both the client and the server support. It can also be set to
196 * a particular value, either 2, 3, or 4 to indicate the version
197 * number of choice. If the server (or the client) do not support
198 * the version indicated, then the mount attempt will be failed.
200 * nfsvers_to_use is the actual version number found to use. It
201 * is determined in get_fh by pinging the various versions of the
202 * NFS service on the server to see which responds positively.
204 * nfsretry_vers is the version number set when we retry the mount
205 * command with the version decremented from nfsvers_to_use.
206 * nfsretry_vers is set from nfsvers_to_use when we retry the mount
207 * for errors other than RPC errors; it helps un know why we are
208 * retrying. It is an indication that the retry is due to
211 static rpcvers_t nfsvers
= 0;
212 static rpcvers_t nfsvers_to_use
= 0;
213 static rpcvers_t nfsretry_vers
= 0;
216 * There are the defaults (range) for the client when determining
217 * which NFS version to use when probing the server (see above).
218 * These will only be used when the vers mount option is not used and
219 * these may be reset if NFS SMF is configured to do so.
221 static rpcvers_t vers_max_default
= NFS_VERSMAX_DEFAULT
;
222 static rpcvers_t vers_min_default
= NFS_VERSMIN_DEFAULT
;
225 * This variable controls whether to try the public file handle.
227 static bool_t public_opt
;
230 main(int argc
, char *argv
[])
235 char optbuf
[MAX_MNTOPT_STR
];
240 err_ret_t retry_error
;
242 (void) setlocale(LC_ALL
, "");
243 #if !defined(TEXT_DOMAIN)
244 #define TEXT_DOMAIN "SYS_TEST"
246 (void) textdomain(TEXT_DOMAIN
);
248 myname
= strrchr(argv
[0], '/');
249 myname
= myname
? myname
+ 1 : argv
[0];
250 (void) snprintf(typename
, sizeof (typename
), "%s %s",
251 MNTTYPE_NFS
, myname
);
254 mnt
.mnt_mntopts
= optbuf
;
255 (void) strcpy(optbuf
, "rw");
260 while ((c
= getopt(argc
, argv
, "ro:mOq")) != EOF
) {
266 if (strlen(optarg
) >= MAX_MNTOPT_STR
) {
267 pr_err(gettext("option string too long"));
270 (void) strcpy(mnt
.mnt_mntopts
, optarg
);
271 #ifdef LATER /* XXX */
272 if (strstr(optarg
, MNTOPT_REMOUNT
)) {
274 * If remount is specified, only rw is allowed.
276 if ((strcmp(optarg
, MNTOPT_REMOUNT
) != 0) &&
277 (strcmp(optarg
, "remount,rw") != 0) &&
278 (strcmp(optarg
, "rw,remount") != 0)) {
279 pr_err(gettext("Invalid options\n"));
283 #endif /* LATER */ /* XXX */
299 if (argc
- optind
!= 2) {
304 mnt
.mnt_special
= argv
[optind
];
305 mnt
.mnt_mountp
= argv
[optind
+1];
307 if (!priv_ineffect(PRIV_SYS_MOUNT
) ||
308 !priv_ineffect(PRIV_NET_PRIVADDR
)) {
309 pr_err(gettext("insufficient privileges\n"));
314 * Read the NFS SMF defaults to see if the min/max versions have
315 * been set and therefore would override the encoded defaults.
316 * Then check to make sure that if they were set that the
317 * values are reasonable.
320 if (vers_min_default
> vers_max_default
||
321 vers_min_default
< NFS_VERSMIN
||
322 vers_max_default
> NFS_VERSMAX
) {
323 pr_err("%s\n%s %s\n",
324 gettext("Incorrect configuration of client\'s"),
325 gettext("client_versmin or client_versmax"),
326 gettext("is either out of range or overlaps."));
329 SET_ERR_RET(&retry_error
, ERR_PROTO_NONE
, 0);
330 r
= mount_nfs(&mnt
, ro
, &retry_error
);
331 if (r
== RET_RETRY
&& retries
) {
333 * Check the error code from the last mount attempt if it was
334 * an RPC error, then retry as is. Otherwise we retry with the
335 * nfsretry_vers set. It is set by decrementing nfsvers_to_use.
336 * If we are retrying with nfsretry_vers then we don't print any
337 * retry messages, since we are not retrying due to an RPC
340 if (retry_error
.error_type
) {
341 if (retry_error
.error_type
!= ERR_RPCERROR
) {
342 nfsretry_vers
= nfsvers_to_use
=
344 if (nfsretry_vers
< NFS_VERSMIN
)
358 pr_err(const char *fmt
, ...)
363 if (backgrounded
!= 0) {
364 (void) vsyslog(LOG_ERR
, fmt
, ap
);
366 (void) fprintf(stderr
, "%s: ", typename
);
367 (void) vfprintf(stderr
, fmt
, ap
);
368 (void) fflush(stderr
);
376 (void) fprintf(stderr
,
377 gettext("Usage: nfs mount [-r] [-o opts] [server:]path dir\n"));
382 mount_nfs(struct mnttab
*mntp
, int ro
, err_ret_t
*retry_error
)
384 struct nfs_args
*args
= NULL
, *argp
= NULL
, *prev_argp
= NULL
;
385 struct netconfig
*nconf
= NULL
;
386 struct replica
*list
= NULL
;
389 int oldvers
= 0, vers
= 0;
390 int last_error
= RET_OK
;
395 char *special
= NULL
;
396 char *oldpath
= NULL
;
397 char *newpath
= NULL
;
401 char *saveopts
= NULL
;
404 mntp
->mnt_fstype
= MNTTYPE_NFS
;
407 mntflags
|= MS_RDONLY
;
408 /* convert "rw"->"ro" */
409 if (p
= strstr(mntp
->mnt_mntopts
, "rw")) {
410 if (*(p
+2) == ',' || *(p
+2) == '\0')
416 mntflags
|= MS_OVERLAY
;
418 list
= parse_replica(mntp
->mnt_special
, &n
);
421 pr_err(gettext("nfs file system; use [host:]path\n"));
423 pr_err(gettext("no memory\n"));
427 replicated
= (n
> 1);
430 * There are some free() calls at the bottom of this loop, so be
431 * careful about adding continue statements.
433 for (i
= 0; i
< n
; i
++) {
438 argp
= (struct nfs_args
*)malloc(sizeof (*argp
));
440 pr_err(gettext("no memory\n"));
441 last_error
= RET_ERR
;
444 memset(argp
, 0, sizeof (*argp
));
446 memset(&nfs_sec
, 0, sizeof (nfs_sec
));
454 * Looking for resources of the form
455 * nfs://server_host[:port_number]/path_name
457 if (strcmp(list
[i
].host
, "nfs") == 0 && strncmp(list
[i
].path
,
461 oldpath
= strdup(list
[i
].path
);
462 if (oldpath
== NULL
) {
463 pr_err(gettext("memory allocation failure\n"));
464 last_error
= RET_ERR
;
467 host
= list
[i
].path
+2;
468 path
= strchr(host
, '/');
472 "illegal nfs url syntax\n"));
473 last_error
= RET_ERR
;
479 cb
= strchr(host
, ']');
482 "illegal nfs url syntax\n"));
483 last_error
= RET_ERR
;
490 port
= htons((ushort_t
)
494 sport
= strchr(host
, ':');
496 if (sport
!= NULL
&& sport
< path
) {
498 port
= htons((ushort_t
)atoi(sport
+1));
511 if (r
= set_args(&mntflags
, argp
, host
, mntp
)) {
516 if (public_opt
== TRUE
)
521 } else if (nfs_port
!= 0 && nfs_port
!= port
) {
523 "port (%u) in nfs URL not the same"
524 " as port (%u) in port option\n"),
525 (unsigned int)ntohs(port
),
526 (unsigned int)ntohs(nfs_port
));
527 last_error
= RET_ERR
;
532 if (replicated
&& !(mntflags
& MS_RDONLY
)) {
534 "replicated mounts must be read-only\n"));
535 last_error
= RET_ERR
;
539 if (replicated
&& (argp
->flags
& NFSMNT_SOFT
)) {
541 "replicated mounts must not be soft\n"));
542 last_error
= RET_ERR
;
552 * If -o public was specified, and/or a URL was specified,
553 * then try the public file handle method.
555 if ((use_pubfh
== TRUE
) || (url
== TRUE
)) {
556 r
= get_fh_via_pub(argp
, host
, path
, url
, use_pubfh
,
557 &vers
, &nconf
, port
);
561 * If -o public was specified, then return the
564 if (use_pubfh
== TRUE
) {
570 argp
->flags
|= NFSMNT_PUBLIC
;
573 if ((r
!= RET_OK
) || (vers
== NFS_V4
)) {
574 bool_t loud_on_mnt_err
;
577 * This can happen if -o public is not specified,
578 * special is a URL, and server doesn't support
579 * public file handle.
586 * If the path portion of the URL didn't have
587 * a leading / then there is good possibility
588 * that a mount without a leading slash will
591 if (url
== TRUE
&& *path
!= '/')
592 loud_on_mnt_err
= FALSE
;
594 loud_on_mnt_err
= TRUE
;
596 r
= get_fh(argp
, host
, path
, &vers
,
597 loud_on_mnt_err
, &nconf
, port
);
602 * If there was no leading / and the path was
603 * derived from a URL, then try again
606 if ((r
== RET_MNTERR
) &&
607 (loud_on_mnt_err
== FALSE
)) {
609 newpath
= malloc(strlen(path
)+2);
611 if (newpath
== NULL
) {
612 pr_err(gettext("memory "
613 "allocation failure\n"));
614 last_error
= RET_ERR
;
618 strcpy(newpath
, "/");
619 strcat(newpath
, path
);
621 r
= get_fh(argp
, host
, newpath
, &vers
,
629 * map exit code back to RET_ERR.
638 free(argp
->pathconf
);
649 if (oldvers
&& vers
!= oldvers
) {
651 gettext("replicas must have the same version\n"));
652 last_error
= RET_ERR
;
657 * decide whether to use remote host's
658 * lockd or do local locking
660 if (!(argp
->flags
& NFSMNT_LLOCK
) && vers
== NFS_VERSION
&&
661 remote_lock(host
, argp
->fh
)) {
662 (void) fprintf(stderr
, gettext(
663 "WARNING: No network locking on %s:%s:"),
665 (void) fprintf(stderr
, gettext(
666 " contact admin to install server change\n"));
667 argp
->flags
|= NFSMNT_LLOCK
;
670 if (self_check(host
))
671 argp
->flags
|= NFSMNT_LOOPBACK
;
673 if (use_pubfh
== FALSE
) {
675 * Call to get_fh() above may have obtained the
676 * netconfig info and NULL proc'd the server.
677 * This would be the case with v4
679 if (!(argp
->flags
& NFSMNT_KNCONF
)) {
681 if (r
= getaddr_nfs(argp
, host
, &nconf
,
682 FALSE
, path
, port
, retry_error
,
690 if (make_secure(argp
, host
, nconf
, use_pubfh
, vers
) < 0) {
691 last_error
= RET_ERR
;
695 if ((url
== TRUE
) && (use_pubfh
== FALSE
)) {
697 * Convert the special from
702 if (convert_special(&special
, host
, oldpath
, path
,
703 mntp
->mnt_special
) == -1) {
704 (void) fprintf(stderr
, gettext(
705 "could not convert URL nfs:%s to %s:%s\n"),
706 oldpath
, host
, path
);
707 last_error
= RET_ERR
;
710 mntp
->mnt_special
= special
;
714 if (prev_argp
== NULL
)
717 prev_argp
->nfs_ext_u
.nfs_extB
.next
= argp
;
721 if (oldpath
!= NULL
) {
726 if (newpath
!= NULL
) {
735 last_error
= RET_RETRY
;
739 /* Determine which services are appropriate for the NFS version */
740 if (strcmp(fstype
, MNTTYPE_NFS4
) == 0)
741 sl
= service_list_v4
;
746 * enable services as needed.
750 mntflags
|= MS_DATA
| MS_OPTIONSTR
;
753 mntflags
|= MS_NOMNTTAB
;
756 saveopts
= strdup(mntp
->mnt_mntopts
);
759 * And make sure that we have the ephemeral mount_to
762 set_nfsv4_ephemeral_mount_to();
764 if (mount(mntp
->mnt_special
, mntp
->mnt_mountp
, mntflags
, fstype
, args
,
765 sizeof (*args
), mntp
->mnt_mntopts
, MAX_MNTOPT_STR
) < 0) {
766 if (errno
!= ENOENT
) {
767 pr_err(gettext("mount: %s: %s\n"),
768 mntp
->mnt_mountp
, strerror(errno
));
771 if (stat(mntp
->mnt_mountp
, &sb
) < 0 && errno
== ENOENT
)
772 pr_err(gettext("mount: %s: %s\n"),
773 mntp
->mnt_mountp
, strerror(ENOENT
));
775 pr_err("%s: %s\n", mntp
->mnt_special
,
779 last_error
= RET_ERR
;
783 if (!qflg
&& saveopts
!= NULL
) {
784 cmp_requested_to_actual_options(saveopts
, mntp
->mnt_mntopts
,
785 mntp
->mnt_special
, mntp
->mnt_mountp
);
794 free_replica(list
, n
);
798 * If we had a new entry which was not added to the
799 * list yet, then add it now that it can be freed.
801 if (prev_argp
== NULL
)
804 prev_argp
->nfs_ext_u
.nfs_extB
.next
= argp
;
807 while (argp
!= NULL
) {
809 free(argp
->pathconf
);
812 free(argp
->addr
->buf
);
815 nfs_free_secdata(argp
->nfs_ext_u
.nfs_extB
.secdata
);
816 if (argp
->syncaddr
) {
817 free(argp
->syncaddr
->buf
);
818 free(argp
->syncaddr
);
822 argp
= argp
->nfs_ext_u
.nfs_extB
.next
;
830 * These options are duplicated in uts/common/fs/nfs/nfs_dlinet.c
831 * Changes must be made to both lists.
833 static char *optlist
[] = {
840 #define OPT_NOQUOTA 3
852 #define OPT_REMOUNT 9
858 #define OPT_NOINTR 12
862 #define OPT_SECURE 14
870 #define OPT_RETRANS 18
872 #define OPT_ACTIMEO 19
874 #define OPT_ACREGMIN 20
876 #define OPT_ACREGMAX 21
878 #define OPT_ACDIRMIN 22
880 #define OPT_ACDIRMAX 23
900 #define OPT_SEMISOFT 33
902 #define OPT_NOPRINT 34
906 #define OPT_LARGEFILES 36
908 #define OPT_NOLARGEFILES 37
910 #define OPT_PUBLIC 38
912 #define OPT_DIRECTIO 39
913 MNTOPT_FORCEDIRECTIO
,
914 #define OPT_NODIRECTIO 40
915 MNTOPT_NOFORCEDIRECTIO
,
918 #define OPT_NOXATTR 42
920 #define OPT_DEVICES 43
922 #define OPT_NODEVICES 44
924 #define OPT_SETUID 45
926 #define OPT_NOSETUID 46
930 #define OPT_NOEXEC 48
936 convert_int(int *val
, char *str
)
940 if (str
== NULL
|| !isdigit(*str
))
943 lval
= strtol(str
, &str
, 10);
944 if (*str
!= '\0' || lval
> INT_MAX
)
952 set_args(int *mntflags
, struct nfs_args
*args
, char *fshost
, struct mnttab
*mnt
)
954 char *saveopt
, *optstr
, *opts
, *newopts
, *val
;
961 args
->flags
= NFSMNT_INT
; /* default is "intr" */
962 args
->flags
|= NFSMNT_HOSTNAME
;
963 args
->flags
|= NFSMNT_NEWARGS
; /* using extented nfs_args structure */
964 args
->hostname
= fshost
;
966 optstr
= opts
= strdup(mnt
->mnt_mntopts
);
967 /* sizeof (MNTOPT_XXX) includes one extra byte we may need for "," */
968 optlen
= strlen(mnt
->mnt_mntopts
) + sizeof (MNTOPT_XATTR
) + 1;
969 if (optlen
> MAX_MNTOPT_STR
) {
970 pr_err(gettext("option string too long"));
973 newopts
= malloc(optlen
);
974 if (opts
== NULL
|| newopts
== NULL
) {
975 pr_err(gettext("no memory"));
985 switch (getsubopt(&opts
, optlist
, &val
)) {
987 *mntflags
|= MS_RDONLY
;
990 *mntflags
&= ~(MS_RDONLY
);
996 args
->flags
|= NFSMNT_SOFT
;
997 args
->flags
&= ~(NFSMNT_SEMISOFT
);
1000 args
->flags
|= NFSMNT_SOFT
;
1001 args
->flags
|= NFSMNT_SEMISOFT
;
1004 args
->flags
&= ~(NFSMNT_SOFT
);
1005 args
->flags
&= ~(NFSMNT_SEMISOFT
);
1008 *mntflags
&= ~(MS_NOSUID
);
1011 *mntflags
|= MS_NOSUID
;
1014 args
->flags
|= NFSMNT_GRPID
;
1017 *mntflags
|= MS_REMOUNT
;
1020 args
->flags
|= NFSMNT_INT
;
1023 args
->flags
&= ~(NFSMNT_INT
);
1026 args
->flags
|= NFSMNT_NOAC
;
1029 if (convert_int(&num
, val
) != 0)
1031 nfs_port
= htons((ushort_t
)num
);
1035 if (nfs_getseconfig_byname("dh", &nfs_sec
)) {
1036 pr_err(gettext("can not get \"dh\" from %s\n"),
1044 args
->flags
|= NFSMNT_NOCTO
;
1048 if (convert_int(&args
->rsize
, val
) != 0)
1050 args
->flags
|= NFSMNT_RSIZE
;
1053 if (convert_int(&args
->wsize
, val
) != 0)
1055 args
->flags
|= NFSMNT_WSIZE
;
1058 if (convert_int(&args
->timeo
, val
) != 0)
1060 args
->flags
|= NFSMNT_TIMEO
;
1063 if (convert_int(&args
->retrans
, val
) != 0)
1065 args
->flags
|= NFSMNT_RETRANS
;
1068 if (convert_int(&args
->acregmax
, val
) != 0)
1070 args
->acdirmin
= args
->acregmin
= args
->acdirmax
1072 args
->flags
|= NFSMNT_ACDIRMAX
;
1073 args
->flags
|= NFSMNT_ACREGMAX
;
1074 args
->flags
|= NFSMNT_ACDIRMIN
;
1075 args
->flags
|= NFSMNT_ACREGMIN
;
1078 if (convert_int(&args
->acregmin
, val
) != 0)
1080 args
->flags
|= NFSMNT_ACREGMIN
;
1083 if (convert_int(&args
->acregmax
, val
) != 0)
1085 args
->flags
|= NFSMNT_ACREGMAX
;
1088 if (convert_int(&args
->acdirmin
, val
) != 0)
1090 args
->flags
|= NFSMNT_ACDIRMIN
;
1093 if (convert_int(&args
->acdirmax
, val
) != 0)
1095 args
->flags
|= NFSMNT_ACDIRMAX
;
1104 if (convert_int(&retries
, val
) != 0)
1108 args
->flags
|= NFSMNT_LLOCK
;
1114 if (convert_int(&num
, val
) != 0)
1116 nfsvers
= (rpcvers_t
)num
;
1122 nfs_proto
= (char *)malloc(strlen(val
)+1);
1124 pr_err(gettext("no memory"));
1128 (void) strncpy(nfs_proto
, val
, strlen(val
)+1);
1132 args
->flags
|= NFSMNT_NOPRINT
;
1135 case OPT_LARGEFILES
:
1139 case OPT_NOLARGEFILES
:
1140 pr_err(gettext("NFS can't support \"nolargefiles\"\n"));
1147 "\"sec\" option requires argument\n"));
1150 if (nfs_getseconfig_byname(val
, &nfs_sec
)) {
1151 pr_err(gettext("can not get \"%s\" from %s\n"),
1163 args
->flags
|= NFSMNT_DIRECTIO
;
1166 case OPT_NODIRECTIO
:
1167 args
->flags
&= ~(NFSMNT_DIRECTIO
);
1173 * VFS options; just need to get them into the
1174 * new mount option string and note we've seen them
1180 * Note that this could be a valid OPT_* option so
1181 * we can't use "val" but need to use "saveopt".
1183 if (fsisstdopt(saveopt
))
1187 (void) fprintf(stderr
, gettext(
1188 "mount: %s on %s - WARNING unknown option"
1189 " \"%s\"\n"), mnt
->mnt_special
,
1190 mnt
->mnt_mountp
, saveopt
);
1195 strcat(newopts
, ",");
1196 strcat(newopts
, saveopt
);
1199 /* Default is to turn extended attrs on */
1202 strcat(newopts
, ",");
1203 strcat(newopts
, MNTOPT_XATTR
);
1205 strcpy(mnt
->mnt_mntopts
, newopts
);
1209 /* ensure that only one secure mode is requested */
1211 pr_err(gettext("Security options conflict\n"));
1215 /* ensure that the user isn't trying to get large files over V2 */
1216 if (nfsvers
== NFS_VERSION
&& largefiles
) {
1217 pr_err(gettext("NFS V2 can't support \"largefiles\"\n"));
1221 if (nfsvers
== NFS_V4
&&
1222 nfs_proto
!= NULL
&&
1223 strncasecmp(nfs_proto
, NC_UDP
, strlen(NC_UDP
)) == 0) {
1224 pr_err(gettext("NFS V4 does not support %s\n"), nfs_proto
);
1231 pr_err(gettext("invalid option: \"%s\"\n"), saveopt
);
1237 make_secure(struct nfs_args
*args
, char *hostname
, struct netconfig
*nconf
,
1238 bool_t use_pubfh
, rpcvers_t vers
)
1240 sec_data_t
*secdata
;
1242 struct netbuf
*syncaddr
= NULL
;
1243 struct nd_addrlist
*retaddrs
= NULL
;
1244 char netname
[MAXNETNAMELEN
+1];
1247 * check to see if any secure mode is requested.
1248 * if not, use default security mode.
1250 if (!snego_done
&& !sec_opt
) {
1252 * Get default security mode.
1253 * AUTH_UNIX has been the default choice for a long time.
1254 * The better NFS security service becomes, the better chance
1255 * we will set stronger security service as the default NFS
1258 if (nfs_getseconfig_default(&nfs_sec
)) {
1259 pr_err(gettext("error getting default"
1260 " security entry\n"));
1263 args
->flags
|= NFSMNT_SECDEFAULT
;
1267 * Get the network address for the time service on the server.
1268 * If an RPC based time service is not available then try the
1271 * This is for AUTH_DH processing. We will also pass down syncaddr
1272 * and netname for NFS V4 even if AUTH_DH is not requested right now.
1273 * NFS V4 does security negotiation in the kernel via SECINFO.
1274 * These information might be needed later in the kernel.
1276 * Eventurally, we want to move this code to nfs_clnt_secdata()
1277 * when autod_nfs.c and mount.c can share the same get_the_addr()
1283 if (nfs_sec
.sc_rpcnum
== AUTH_DH
|| vers
== NFS_V4
) {
1285 * If using the public fh or nfsv4, we will not contact the
1286 * remote RPCBINDer, since it is possibly behind a firewall.
1288 if (use_pubfh
== FALSE
&& vers
!= NFS_V4
)
1289 syncaddr
= get_the_addr(hostname
, RPCBPROG
, RPCBVERS
,
1290 nconf
, 0, NULL
, NULL
, FALSE
, NULL
, NULL
);
1292 if (syncaddr
!= NULL
) {
1293 /* for flags in sec_data */
1294 flags
|= AUTH_F_RPCTIMESYNC
;
1296 struct nd_hostserv hs
;
1299 hs
.h_host
= hostname
;
1300 hs
.h_serv
= "timserver";
1302 error
= netdir_getbyname(nconf
, &hs
, &retaddrs
);
1304 if (error
!= ND_OK
&& (nfs_sec
.sc_rpcnum
== AUTH_DH
)) {
1305 pr_err(gettext("%s: secure: no time service\n"),
1311 syncaddr
= retaddrs
->n_addrs
;
1314 * For NFS_V4 if AUTH_DH is negotiated later in the
1315 * kernel thru SECINFO, it will need syncaddr
1318 if (vers
== NFS_V4
&& syncaddr
&&
1319 host2netname(netname
, hostname
, NULL
)) {
1320 args
->syncaddr
= malloc(sizeof (struct netbuf
));
1321 args
->syncaddr
->buf
= malloc(syncaddr
->len
);
1322 (void) memcpy(args
->syncaddr
->buf
,
1323 syncaddr
->buf
, syncaddr
->len
);
1324 args
->syncaddr
->len
= syncaddr
->len
;
1325 args
->syncaddr
->maxlen
= syncaddr
->maxlen
;
1326 args
->netname
= strdup(netname
);
1327 args
->flags
|= NFSMNT_SECURE
;
1333 * For the initial chosen flavor (any flavor defined in nfssec.conf),
1334 * the data will be stored in the sec_data structure via
1335 * nfs_clnt_secdata() and be passed to the kernel via nfs_args_*
1336 * extended data structure.
1338 if (!(secdata
= nfs_clnt_secdata(&nfs_sec
, hostname
, args
->knconf
,
1339 syncaddr
, flags
))) {
1340 pr_err(gettext("errors constructing security related data\n"));
1341 if (flags
& AUTH_F_RPCTIMESYNC
) {
1342 free(syncaddr
->buf
);
1344 } else if (retaddrs
)
1345 netdir_free((void *)retaddrs
, ND_ADDRLIST
);
1349 NFS_ARGS_EXTB_secdata(args
, secdata
);
1350 if (flags
& AUTH_F_RPCTIMESYNC
) {
1351 free(syncaddr
->buf
);
1353 } else if (retaddrs
)
1354 netdir_free((void *)retaddrs
, ND_ADDRLIST
);
1359 * Get the network address on "hostname" for program "prog"
1360 * with version "vers" by using the nconf configuration data
1363 * If the address of a netconfig pointer is null then
1364 * information is not sufficient and no netbuf will be returned.
1366 * Finally, ping the null procedure of that service.
1368 * A similar routine is also defined in ../../autofs/autod_nfs.c.
1369 * This is a potential routine to move to ../lib for common usage.
1371 static struct netbuf
*
1372 get_the_addr(char *hostname
, ulong_t prog
, ulong_t vers
,
1373 struct netconfig
*nconf
, ushort_t port
, struct t_info
*tinfo
,
1374 caddr_t
*fhp
, bool_t get_pubfh
, char *fspath
, err_ret_t
*error
)
1376 struct netbuf
*nb
= NULL
;
1377 struct t_bind
*tbind
= NULL
;
1382 AUTH
*new_ah
= NULL
;
1383 struct snego_t snego
;
1388 if ((fd
= t_open(nconf
->nc_device
, O_RDWR
, tinfo
)) == -1)
1391 /* LINTED pointer alignment */
1392 if ((tbind
= (struct t_bind
*)t_alloc(fd
, T_BIND
, T_ADDR
))
1397 * In the case of public filehandle usage or NFSv4 we want to
1398 * avoid use of the rpcbind/portmap protocol
1400 if ((get_pubfh
== TRUE
) || (vers
== NFS_V4
)) {
1401 struct nd_hostserv hs
;
1402 struct nd_addrlist
*retaddrs
;
1404 hs
.h_host
= hostname
;
1406 /* NFS where vers==4 does not support UDP */
1407 if (vers
== NFS_V4
&&
1408 strncasecmp(nconf
->nc_proto
, NC_UDP
,
1409 strlen(NC_UDP
)) == 0) {
1410 SET_ERR_RET(error
, ERR_PROTO_UNSUPP
, 0);
1419 if ((retval
= netdir_getbyname(nconf
, &hs
, &retaddrs
))
1422 * Carefully set the error value here. Want to signify
1423 * that the error was an unknown host.
1425 if (retval
== ND_NOHOST
) {
1426 SET_ERR_RET(error
, ERR_NOHOST
, retval
);
1431 memcpy(tbind
->addr
.buf
, retaddrs
->n_addrs
->buf
,
1432 retaddrs
->n_addrs
->len
);
1433 tbind
->addr
.len
= retaddrs
->n_addrs
->len
;
1434 netdir_free((void *)retaddrs
, ND_ADDRLIST
);
1435 (void) netdir_options(nconf
, ND_SET_RESERVEDPORT
, fd
, NULL
);
1438 if (rpcb_getaddr(prog
, vers
, nconf
, &tbind
->addr
,
1439 hostname
) == FALSE
) {
1445 /* LINTED pointer alignment */
1446 if (strcmp(nconf
->nc_protofmly
, NC_INET
) == 0)
1447 ((struct sockaddr_in
*)tbind
->addr
.buf
)->sin_port
1449 else if (strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0)
1450 ((struct sockaddr_in6
*)tbind
->addr
.buf
)->sin6_port
1455 cl
= clnt_tli_create(fd
, nconf
, &tbind
->addr
, prog
, vers
, 0, 0);
1458 * clnt_tli_create() returns either RPC_SYSTEMERROR,
1459 * RPC_UNKNOWNPROTO or RPC_TLIERROR. The RPC_TLIERROR translates
1460 * to "Misc. TLI error". This is not too helpful. Most likely
1461 * the connection to the remote server timed out, so this
1462 * error is at least less perplexing.
1463 * See: usr/src/cmd/rpcinfo/rpcinfo.c
1465 if (rpc_createerr
.cf_stat
== RPC_TLIERROR
) {
1466 SET_ERR_RET(error
, ERR_RPCERROR
, RPC_PMAPFAILURE
);
1468 SET_ERR_RET(error
, ERR_RPCERROR
, rpc_createerr
.cf_stat
);
1473 ah
= authsys_create_default();
1480 (void) clnt_control(cl
, CLSET_TIMEOUT
, (char *)&tv
);
1482 if ((get_pubfh
== TRUE
) && (vers
!= NFS_V4
)) {
1483 enum snego_stat sec
;
1487 * negotiate sec flavor.
1490 if ((sec
= nfs_sec_nego(vers
, cl
, fspath
, &snego
)) ==
1495 * check if server supports the one
1496 * specified in the sec= option.
1499 for (jj
= 0; jj
< snego
.cnt
; jj
++) {
1500 if (snego
.array
[jj
] ==
1501 nfs_sec
.sc_nfsnum
) {
1509 * find a common sec flavor
1514 "Server does not support"
1515 " the security flavor"
1519 for (jj
= 0; jj
< snego
.cnt
; jj
++) {
1520 if (!nfs_getseconfig_bynumber(
1524 #define EMSG80SUX "Security flavor %d was negotiated and will be used.\n"
1539 * Now that the flavor has been
1540 * negotiated, get the fh.
1542 * First, create an auth handle using the
1543 * negotiated sec flavor in the next lookup to
1544 * fetch the filehandle.
1546 new_ah
= nfs_create_ah(cl
, hostname
, &nfs_sec
);
1549 cl
->cl_auth
= new_ah
;
1550 } else if (sec
== SNEGO_ARRAY_TOO_SMALL
|| sec
==
1556 * Note that if sec == SNEGO_DEF_VALID
1557 * default sec flavor is acceptable.
1558 * Use it to get the filehandle.
1562 if (vers
== NFS_VERSION
) {
1566 memset((char *)&arg
.dir
, 0, sizeof (wnl_fh
));
1568 memset((char *)&res
, 0, sizeof (wnl_diropres
));
1569 if (wnlproc_lookup_2(&arg
, &res
, cl
) !=
1570 RPC_SUCCESS
|| res
.status
!= WNL_OK
)
1573 *fhp
= malloc(sizeof (wnl_fh
));
1576 pr_err(gettext("no memory\n"));
1580 memcpy((char *)*fhp
,
1581 (char *)&res
.wnl_diropres_u
.wnl_diropres
.file
,
1584 WNL_LOOKUP3args arg
;
1588 memset((char *)&arg
.what
.dir
, 0, sizeof (wnl_fh3
));
1589 arg
.what
.name
= fspath
;
1590 memset((char *)&res
, 0, sizeof (WNL_LOOKUP3res
));
1591 if (wnlproc3_lookup_3(&arg
, &res
, cl
) !=
1592 RPC_SUCCESS
|| res
.status
!= WNL3_OK
)
1595 fh3p
= (nfs_fh3
*)malloc(sizeof (*fh3p
));
1598 pr_err(gettext("no memory\n"));
1603 res
.WNL_LOOKUP3res_u
.res_ok
.object
.data
.data_len
;
1604 memcpy(fh3p
->fh3_u
.data
,
1605 res
.WNL_LOOKUP3res_u
.res_ok
.object
.data
.data_val
,
1608 *fhp
= (caddr_t
)fh3p
;
1611 struct rpc_err r_err
;
1615 * NULL procedures need not have an argument or
1618 if (vers
== NFS_VERSION
)
1619 rc
= wnlproc_null_2(NULL
, NULL
, cl
);
1620 else if (vers
== NFS_V3
)
1621 rc
= wnlproc3_null_3(NULL
, NULL
, cl
);
1623 rc
= wnlproc4_null_4(NULL
, NULL
, cl
);
1625 if (rc
!= RPC_SUCCESS
) {
1626 clnt_geterr(cl
, &r_err
);
1627 if (strcmp(nconf
->nc_protofmly
, NC_LOOPBACK
) == 0) {
1628 switch (r_err
.re_status
) {
1632 r_err
.re_status
= RPC_PROGVERSMISMATCH
;
1635 SET_ERR_RET(error
, ERR_RPCERROR
, r_err
.re_status
);
1641 * Make a copy of the netbuf to return
1643 nb
= (struct netbuf
*)malloc(sizeof (*nb
));
1645 pr_err(gettext("no memory\n"));
1649 nb
->buf
= (char *)malloc(nb
->maxlen
);
1650 if (nb
->buf
== NULL
) {
1651 pr_err(gettext("no memory\n"));
1656 (void) memcpy(nb
->buf
, tbind
->addr
.buf
, tbind
->addr
.len
);
1663 AUTH_DESTROY(cl
->cl_auth
);
1670 t_free((char *)tbind
, T_BIND
);
1679 check_nconf(struct netconfig
*nconf
, int nthtry
, int *valid_proto
)
1686 if (nthtry
== FIRST_TRY
) {
1687 try_test
= ((nconf
->nc_semantics
== NC_TPI_COTS_ORD
) ||
1688 (nconf
->nc_semantics
== NC_TPI_COTS
));
1690 } else if (nthtry
== SECOND_TRY
) {
1691 try_test
= (nconf
->nc_semantics
== NC_TPI_CLTS
);
1696 (strcmp(nconf
->nc_protofmly
, NC_INET
) == 0 ||
1697 strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0) &&
1698 (strcmp(nconf
->nc_proto
, proto
) == 0))
1699 *valid_proto
= TRUE
;
1701 *valid_proto
= FALSE
;
1707 * Get a network address on "hostname" for program "prog"
1708 * with version "vers". If the port number is specified (non zero)
1709 * then try for a TCP/UDP transport and set the port number of the
1710 * resulting IP address.
1712 * If the address of a netconfig pointer was passed and
1713 * if it's not null, use it as the netconfig otherwise
1714 * assign the address of the netconfig that was used to
1715 * establish contact with the service.
1717 * A similar routine is also defined in ../../autofs/autod_nfs.c.
1718 * This is a potential routine to move to ../lib for common usage.
1720 * "error" refers to a more descriptive term when get_addr fails
1721 * and returns NULL: ERR_PROTO_NONE if no error introduced by
1722 * -o proto option, ERR_NETPATH if error found in NETPATH
1723 * environment variable, ERR_PROTO_INVALID if an unrecognized
1724 * protocol is specified by user, and ERR_PROTO_UNSUPP for a
1725 * recognized but invalid protocol (eg. ticlts, ticots, etc.).
1726 * "error" is ignored if get_addr returns non-NULL result.
1729 static struct netbuf
*
1730 get_addr(char *hostname
, ulong_t prog
, ulong_t vers
, struct netconfig
**nconfp
,
1731 char *proto
, ushort_t port
, struct t_info
*tinfo
, caddr_t
*fhp
,
1732 bool_t get_pubfh
, char *fspath
, err_ret_t
*error
)
1734 struct netbuf
*nb
= NULL
;
1735 struct netconfig
*nconf
= NULL
;
1736 NCONF_HANDLE
*nc
= NULL
;
1737 int nthtry
= FIRST_TRY
;
1738 err_ret_t errsave_nohost
, errsave_rpcerr
;
1740 SET_ERR_RET(&errsave_nohost
, ERR_PROTO_NONE
, 0);
1741 SET_ERR_RET(&errsave_rpcerr
, ERR_PROTO_NONE
, 0);
1743 SET_ERR_RET(error
, ERR_PROTO_NONE
, 0);
1745 if (nconfp
&& *nconfp
)
1746 return (get_the_addr(hostname
, prog
, vers
, *nconfp
, port
,
1747 tinfo
, fhp
, get_pubfh
, fspath
, error
));
1749 * No nconf passed in.
1751 * Try to get a nconf from /etc/netconfig filtered by
1752 * the NETPATH environment variable.
1753 * First search for COTS, second for CLTS unless proto
1754 * is specified. When we retry, we reset the
1755 * netconfig list so that we would search the whole list
1759 if ((nc
= setnetpath()) == NULL
) {
1760 /* should only return an error if problems with NETPATH */
1761 /* In which case you are hosed */
1762 SET_ERR_RET(error
, ERR_NETPATH
, 0);
1767 * If proto is specified, then only search for the match,
1768 * otherwise try COTS first, if failed, try CLTS.
1771 /* no matching proto name */
1772 SET_ERR_RET(error
, ERR_PROTO_INVALID
, 0);
1774 while (nconf
= getnetpath(nc
)) {
1775 if (strcmp(nconf
->nc_netid
, proto
))
1778 /* may be unsupported */
1779 SET_ERR_RET(error
, ERR_PROTO_UNSUPP
, 0);
1782 ((strcmp(nconf
->nc_protofmly
, NC_INET
) == 0 ||
1783 strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0) &&
1784 (strcmp(nconf
->nc_proto
, NC_TCP
) != 0 &&
1785 strcmp(nconf
->nc_proto
, NC_UDP
) != 0))) {
1788 nb
= get_the_addr(hostname
, prog
,
1789 vers
, nconf
, port
, tinfo
,
1790 fhp
, get_pubfh
, fspath
, error
);
1795 /* nb is NULL - deal with errors */
1797 if (error
->error_type
== ERR_NOHOST
)
1798 SET_ERR_RET(&errsave_nohost
,
1800 error
->error_value
);
1801 if (error
->error_type
== ERR_RPCERROR
)
1802 SET_ERR_RET(&errsave_rpcerr
,
1804 error
->error_value
);
1807 * continue with same protocol
1812 } /* end of while */
1817 if ((nb
= get_the_addr(hostname
, prog
, vers
, nconf
, port
,
1818 tinfo
, fhp
, get_pubfh
, fspath
, error
)) == NULL
)
1822 SET_ERR_RET(error
, ERR_NETPATH
, 0);
1823 while (nconf
= getnetpath(nc
)) {
1824 SET_ERR_RET(error
, ERR_PROTO_NONE
, 0);
1826 if (nconf
->nc_flag
& NC_VISIBLE
) {
1829 if (check_nconf(nconf
,
1830 nthtry
, &valid_proto
)) {
1834 if (valid_proto
== TRUE
)
1839 if (nconf
== NULL
) {
1840 if (++nthtry
<= MNT_PREF_LISTLEN
) {
1842 if ((nc
= setnetpath()) == NULL
)
1848 if ((nb
= get_the_addr(hostname
, prog
, vers
, nconf
,
1849 port
, tinfo
, fhp
, get_pubfh
, fspath
, error
))
1851 /* nb is NULL - deal with errors */
1853 if (error
->error_type
== ERR_NOHOST
)
1854 SET_ERR_RET(&errsave_nohost
,
1856 error
->error_value
);
1857 if (error
->error_type
== ERR_RPCERROR
)
1858 SET_ERR_RET(&errsave_rpcerr
,
1860 error
->error_value
);
1863 * Continue the same search path in the
1864 * netconfig db until no more matched
1865 * nconf (nconf == NULL).
1871 SET_ERR_RET(error
, ERR_PROTO_NONE
, 0);
1874 * Got nconf and nb. Now dup the netconfig structure (nconf)
1875 * and return it thru nconfp.
1877 *nconfp
= getnetconfigent(nconf
->nc_netid
);
1878 if (*nconfp
== NULL
) {
1879 syslog(LOG_ERR
, "no memory\n");
1889 * Check the saved errors. The RPC error has *
1890 * precedence over the no host error.
1892 if (errsave_nohost
.error_type
!= ERR_PROTO_NONE
)
1893 SET_ERR_RET(error
, errsave_nohost
.error_type
,
1894 errsave_nohost
.error_value
);
1896 if (errsave_rpcerr
.error_type
!= ERR_PROTO_NONE
)
1897 SET_ERR_RET(error
, errsave_rpcerr
.error_type
,
1898 errsave_rpcerr
.error_value
);
1905 * Get a file handle usinging multi-component lookup with the public
1909 get_fh_via_pub(struct nfs_args
*args
, char *fshost
, char *fspath
, bool_t url
,
1910 bool_t loud
, int *versp
, struct netconfig
**nconfp
, ushort_t port
)
1918 vers_max
= vers_min
= nfsvers
;
1920 vers_max
= vers_max_default
;
1921 vers_min
= vers_min_default
;
1925 path
= malloc(strlen(fspath
) + 2);
1928 pr_err(gettext("no memory\n"));
1932 path
[0] = (char)WNL_NATIVEPATH
;
1933 (void) strcpy(&path
[1], fspath
);
1939 for (nfsvers_to_use
= vers_max
; nfsvers_to_use
>= vers_min
;
1942 * getaddr_nfs will also fill in the fh for us.
1944 r
= getaddr_nfs(args
, fshost
, nconfp
,
1945 TRUE
, path
, port
, NULL
, FALSE
);
1949 * Since we are using the public fh, and NLM is
1950 * not firewall friendly, use local locking.
1951 * Not the case for v4.
1953 *versp
= nfsvers_to_use
;
1954 switch (nfsvers_to_use
) {
1956 fstype
= MNTTYPE_NFS4
;
1959 fstype
= MNTTYPE_NFS3
;
1960 /* fall through to pick up llock option */
1962 args
->flags
|= NFSMNT_LLOCK
;
1976 pr_err(gettext("Could not use public filehandle in request to"
1977 " server %s\n"), fshost
);
1984 * get fhandle of remote path from server's mountd
1987 get_fh(struct nfs_args
*args
, char *fshost
, char *fspath
, int *versp
,
1988 bool_t loud_on_mnt_err
, struct netconfig
**nconfp
, ushort_t port
)
1990 static struct fhstatus fhs
;
1991 static struct mountres3 mountres3
;
1992 static struct pathcnf p
;
1994 struct timeval timeout
= { 25, 0};
1996 enum clnt_stat rpc_stat
;
1997 rpcvers_t outvers
= 0;
1998 rpcvers_t vers_to_try
;
2000 static int printed
= 0;
2001 int count
, i
, *auths
;
2005 case 2: /* version 2 specified try that only */
2006 vers_to_try
= MOUNTVERS_POSIX
;
2007 vers_min
= MOUNTVERS
;
2009 case 3: /* version 3 specified try that only */
2010 vers_to_try
= MOUNTVERS3
;
2011 vers_min
= MOUNTVERS3
;
2013 case 4: /* version 4 specified try that only */
2015 * This assignment is in the wrong version sequence.
2016 * The above are MOUNT program and this is NFS
2017 * program. However, it happens to work out since the
2018 * two don't collide for NFSv4.
2020 vers_to_try
= NFS_V4
;
2023 default: /* no version specified, start with default */
2025 * If the retry version is set, use that. This will
2026 * be set if the last mount attempt returned any other
2027 * besides an RPC error.
2030 vers_to_try
= nfsretry_vers
;
2032 vers_to_try
= vers_max_default
;
2033 vers_min
= vers_min_default
;
2040 * In the case of version 4, just NULL proc the server since
2041 * there is no MOUNT program. If this fails, then decrease
2042 * vers_to_try and continue on with regular MOUNT program
2045 if (vers_to_try
== NFS_V4
) {
2046 int savevers
= nfsvers_to_use
;
2049 SET_ERR_RET(&error
, ERR_PROTO_NONE
, 0);
2051 /* Let's hope for the best */
2052 nfsvers_to_use
= NFS_V4
;
2053 retval
= getaddr_nfs(args
, fshost
, nconfp
, FALSE
,
2054 fspath
, port
, &error
, vers_min
== NFS_V4
);
2056 if (retval
== RET_OK
) {
2057 *versp
= nfsvers_to_use
= NFS_V4
;
2058 fstype
= MNTTYPE_NFS4
;
2059 args
->fh
= strdup(fspath
);
2060 if (args
->fh
== NULL
) {
2061 pr_err(gettext("no memory\n"));
2062 *versp
= nfsvers_to_use
= savevers
;
2067 nfsvers_to_use
= savevers
;
2070 /* If no more versions to try, let the user know. */
2071 if (vers_to_try
< vers_min
)
2075 * If we are here, there are more versions to try but
2076 * there has been an error of some sort. If it is not
2077 * an RPC error (e.g. host unknown), we just stop and
2078 * return the error since the other versions would see
2079 * the same error as well.
2081 if (retval
== RET_ERR
&& error
.error_type
!= ERR_RPCERROR
)
2085 while ((cl
= clnt_create_vers(fshost
, MOUNTPROG
, &outvers
,
2086 vers_min
, vers_to_try
, "datagram_v")) == NULL
) {
2087 if (rpc_createerr
.cf_stat
== RPC_UNKNOWNHOST
) {
2088 pr_err(gettext("%s: %s\n"), fshost
,
2089 clnt_spcreateerror(""));
2094 * We don't want to downgrade version on lost packets
2096 if ((rpc_createerr
.cf_stat
== RPC_TIMEDOUT
) ||
2097 (rpc_createerr
.cf_stat
== RPC_PMAPFAILURE
)) {
2098 pr_err(gettext("%s: %s\n"), fshost
,
2099 clnt_spcreateerror(""));
2104 * back off and try the previous version - patch to the
2105 * problem of version numbers not being contigous and
2106 * clnt_create_vers failing (SunOS4.1 clients & SGI servers)
2107 * The problem happens with most non-Sun servers who
2108 * don't support mountd protocol #2. So, in case the
2109 * call fails, we re-try the call anyway.
2112 if (vers_to_try
< vers_min
) {
2113 if (rpc_createerr
.cf_stat
== RPC_PROGVERSMISMATCH
) {
2116 "%s:%s: no applicable versions of NFS supported\n"),
2120 "%s:%s: NFS Version %d not supported\n"),
2121 fshost
, fspath
, nfsvers
);
2126 pr_err(gettext("%s: %s\n"), fshost
,
2127 clnt_spcreateerror(""));
2133 if (posix
&& outvers
< MOUNTVERS_POSIX
) {
2134 pr_err(gettext("%s: %s: no pathconf info\n"),
2135 fshost
, clnt_sperror(cl
, ""));
2140 if (__clnt_bindresvport(cl
) < 0) {
2141 pr_err(gettext("Couldn't bind to reserved port\n"));
2146 if ((cl
->cl_auth
= authsys_create_default()) == NULL
) {
2148 gettext("Couldn't create default authentication handle\n"));
2155 case MOUNTVERS_POSIX
:
2156 *versp
= nfsvers_to_use
= NFS_VERSION
;
2157 rpc_stat
= clnt_call(cl
, MOUNTPROC_MNT
, xdr_dirpath
,
2158 (caddr_t
)&fspath
, xdr_fhstatus
, (caddr_t
)&fhs
, timeout
);
2159 if (rpc_stat
!= RPC_SUCCESS
) {
2160 pr_err(gettext("%s:%s: server not responding %s\n"),
2161 fshost
, fspath
, clnt_sperror(cl
, ""));
2166 if ((errno
= fhs
.fhs_status
) != MNT_OK
) {
2167 if (loud_on_mnt_err
) {
2168 if (errno
== EACCES
) {
2170 "%s:%s: access denied\n"),
2173 pr_err(gettext("%s:%s: %s\n"), fshost
,
2174 fspath
, errno
>= 0 ?
2175 strerror(errno
) : "invalid error "
2176 "returned by server");
2180 return (RET_MNTERR
);
2182 args
->fh
= malloc(sizeof (fhs
.fhstatus_u
.fhs_fhandle
));
2183 if (args
->fh
== NULL
) {
2184 pr_err(gettext("no memory\n"));
2187 memcpy((caddr_t
)args
->fh
, (caddr_t
)&fhs
.fhstatus_u
.fhs_fhandle
,
2188 sizeof (fhs
.fhstatus_u
.fhs_fhandle
));
2189 if (!errno
&& posix
) {
2190 rpc_stat
= clnt_call(cl
, MOUNTPROC_PATHCONF
,
2191 xdr_dirpath
, (caddr_t
)&fspath
, xdr_ppathcnf
,
2192 (caddr_t
)&p
, timeout
);
2193 if (rpc_stat
!= RPC_SUCCESS
) {
2195 "%s:%s: server not responding %s\n"),
2196 fshost
, fspath
, clnt_sperror(cl
, ""));
2201 if (_PC_ISSET(_PC_ERROR
, p
.pc_mask
)) {
2203 "%s:%s: no pathconf info\n"),
2209 args
->flags
|= NFSMNT_POSIX
;
2210 args
->pathconf
= malloc(sizeof (p
));
2211 if (args
->pathconf
== NULL
) {
2212 pr_err(gettext("no memory\n"));
2217 memcpy((caddr_t
)args
->pathconf
, (caddr_t
)&p
,
2223 *versp
= nfsvers_to_use
= NFS_V3
;
2224 rpc_stat
= clnt_call(cl
, MOUNTPROC_MNT
, xdr_dirpath
,
2225 (caddr_t
)&fspath
, xdr_mountres3
, (caddr_t
)&mountres3
,
2227 if (rpc_stat
!= RPC_SUCCESS
) {
2228 pr_err(gettext("%s:%s: server not responding %s\n"),
2229 fshost
, fspath
, clnt_sperror(cl
, ""));
2235 * Assume here that most of the MNT3ERR_*
2236 * codes map into E* errors.
2238 if ((errno
= mountres3
.fhs_status
) != MNT_OK
) {
2239 if (loud_on_mnt_err
) {
2241 case MNT3ERR_NAMETOOLONG
:
2242 msg
= "path name is too long";
2244 case MNT3ERR_NOTSUPP
:
2245 msg
= "operation not supported";
2247 case MNT3ERR_SERVERFAULT
:
2248 msg
= "server fault";
2252 msg
= strerror(errno
);
2254 msg
= "invalid error returned "
2258 pr_err(gettext("%s:%s: %s\n"), fshost
,
2262 return (RET_MNTERR
);
2265 fh3p
= (nfs_fh3
*)malloc(sizeof (*fh3p
));
2267 pr_err(gettext("no memory\n"));
2271 mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_len
;
2272 (void) memcpy(fh3p
->fh3_u
.data
,
2273 mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_val
,
2275 args
->fh
= (caddr_t
)fh3p
;
2276 fstype
= MNTTYPE_NFS3
;
2279 * Check the security flavor to be used.
2281 * If "secure" or "sec=flavor" is a mount
2282 * option, check if the server supports the "flavor".
2283 * If the server does not support the flavor, return
2286 * If no mount option is given then look for default auth
2287 * (default auth entry in /etc/nfssec.conf) in the auth list
2288 * returned from server. If default auth not found, then use
2289 * the first supported security flavor (by the client) in the
2290 * auth list returned from the server.
2294 mountres3
.mountres3_u
.mountinfo
.auth_flavors
2297 mountres3
.mountres3_u
.mountinfo
.auth_flavors
2302 "server %s did not return any security mode\n"),
2309 for (i
= 0; i
< count
; i
++) {
2310 if (auths
[i
] == nfs_sec
.sc_nfsnum
)
2316 seconfig_t default_sec
;
2319 * Get client configured default auth.
2321 nfs_sec
.sc_nfsnum
= -1;
2322 default_sec
.sc_nfsnum
= -1;
2323 (void) nfs_getseconfig_default(&default_sec
);
2326 * Look for clients default auth in servers list.
2328 if (default_sec
.sc_nfsnum
!= -1) {
2329 for (i
= 0; i
< count
; i
++) {
2330 if (auths
[i
] == default_sec
.sc_nfsnum
) {
2332 nfs_sec
= default_sec
;
2339 * Could not find clients default auth in servers list.
2340 * Pick the first auth from servers list that is
2341 * also supported on the client.
2343 if (nfs_sec
.sc_nfsnum
== -1) {
2344 for (i
= 0; i
< count
; i
++) {
2345 if (!nfs_getseconfig_bynumber(auths
[i
],
2359 pr_err(gettext("%s:%s: Unknown MOUNT version %d\n"),
2360 fshost
, fspath
, outvers
);
2370 "security mode does not match the server exporting %s:%s\n"),
2377 * Fill in the address for the server's NFS service and
2378 * fill in a knetconfig structure for the transport that
2379 * the service is available on.
2382 getaddr_nfs(struct nfs_args
*args
, char *fshost
, struct netconfig
**nconfp
,
2383 bool_t get_pubfh
, char *fspath
, ushort_t port
, err_ret_t
*error
,
2384 bool_t print_rpcerror
)
2387 struct netconfig
*nconf
;
2388 struct knetconfig
*knconfp
;
2389 static int printed
= 0;
2390 struct t_info tinfo
;
2391 err_ret_t addr_error
;
2393 SET_ERR_RET(error
, ERR_PROTO_NONE
, 0);
2394 SET_ERR_RET(&addr_error
, ERR_PROTO_NONE
, 0);
2398 * If a proto is specified and its rdma try this. The kernel
2399 * will later do the reachablity test and fail form there
2400 * if rdma transport is not available to kernel rpc
2402 if (strcmp(nfs_proto
, "rdma") == 0) {
2403 args
->addr
= get_addr(fshost
, NFS_PROGRAM
,
2404 nfsvers_to_use
, nconfp
, NULL
, port
, &tinfo
,
2405 &args
->fh
, get_pubfh
, fspath
, &addr_error
);
2407 args
->flags
|= NFSMNT_DORDMA
;
2409 args
->addr
= get_addr(fshost
, NFS_PROGRAM
,
2410 nfsvers_to_use
, nconfp
, nfs_proto
, port
, &tinfo
,
2411 &args
->fh
, get_pubfh
, fspath
, &addr_error
);
2414 args
->addr
= get_addr(fshost
, NFS_PROGRAM
, nfsvers_to_use
,
2415 nconfp
, nfs_proto
, port
, &tinfo
, &args
->fh
, get_pubfh
,
2416 fspath
, &addr_error
);
2418 * If no proto is specified set this flag.
2419 * Kernel mount code will try to use RDMA if its on the
2420 * system, otherwise it will keep on using the protocol
2421 * selected here, through the above get_addr call.
2423 if (nfs_proto
== NULL
)
2424 args
->flags
|= NFSMNT_TRYRDMA
;
2427 if (args
->addr
== NULL
) {
2429 * We could have failed because the server had no public
2430 * file handle support. So don't print a message and don't
2433 if (get_pubfh
== TRUE
)
2437 switch (addr_error
.error_type
) {
2442 if (!print_rpcerror
)
2443 /* no error print at this time */
2445 pr_err(gettext("%s NFS service not"
2446 " available %s\n"), fshost
,
2447 clnt_sperrno(addr_error
.error_value
));
2451 pr_err(gettext("%s: Error in NETPATH.\n"),
2455 case ERR_PROTO_INVALID
:
2456 pr_err(gettext("%s: NFS service does not"
2457 " recognize protocol: %s.\n"), fshost
,
2461 case ERR_PROTO_UNSUPP
:
2462 if (nfsvers
|| nfsvers_to_use
== NFS_VERSMIN
) {
2464 * Don't set "printed" here. Since we
2465 * have to keep checking here till we
2466 * exhaust transport errors on all vers.
2468 * Print this message if:
2469 * 1. After we have tried all versions
2470 * of NFS and none support the asked
2473 * 2. If a version is specified and it
2474 * does'nt support the asked
2477 * Otherwise we decrement the version
2480 pr_err(gettext("%s: NFS service does"
2481 " not support protocol: %s.\n"),
2486 pr_err("%s: %s\n", fshost
, "Unknown host");
2490 /* case ERR_PROTO_NONE falls through */
2491 pr_err(gettext("%s: NFS service not responding"
2498 addr_error
.error_type
, addr_error
.error_value
);
2499 if (addr_error
.error_type
== ERR_PROTO_NONE
)
2501 else if (addr_error
.error_type
== ERR_RPCERROR
&&
2502 !IS_UNRECOVERABLE_RPC(addr_error
.error_value
)) {
2504 } else if (nfsvers
== 0 && addr_error
.error_type
==
2505 ERR_PROTO_UNSUPP
&& nfsvers_to_use
!= NFS_VERSMIN
) {
2507 * If no version is specified, and the error is due
2508 * to an unsupported transport, then decrement the
2509 * version and retry.
2517 if (stat(nconf
->nc_device
, &sb
) < 0) {
2518 pr_err(gettext("getaddr_nfs: couldn't stat: %s: %s\n"),
2519 nconf
->nc_device
, strerror(errno
));
2523 knconfp
= (struct knetconfig
*)malloc(sizeof (*knconfp
));
2525 pr_err(gettext("no memory\n"));
2528 knconfp
->knc_semantics
= nconf
->nc_semantics
;
2529 knconfp
->knc_protofmly
= nconf
->nc_protofmly
;
2530 knconfp
->knc_proto
= nconf
->nc_proto
;
2531 knconfp
->knc_rdev
= sb
.st_rdev
;
2533 /* make sure we don't overload the transport */
2534 if (tinfo
.tsdu
> 0 && tinfo
.tsdu
< NFS_MAXDATA
+ NFS_RPC_HDR
) {
2535 args
->flags
|= (NFSMNT_RSIZE
| NFSMNT_WSIZE
);
2536 if (args
->rsize
== 0 || args
->rsize
> tinfo
.tsdu
- NFS_RPC_HDR
)
2537 args
->rsize
= tinfo
.tsdu
- NFS_RPC_HDR
;
2538 if (args
->wsize
== 0 || args
->wsize
> tinfo
.tsdu
- NFS_RPC_HDR
)
2539 args
->wsize
= tinfo
.tsdu
- NFS_RPC_HDR
;
2542 args
->flags
|= NFSMNT_KNCONF
;
2543 args
->knconf
= knconfp
;
2548 retry(struct mnttab
*mntp
, int ro
)
2551 int count
= retries
;
2555 * Please see comments on nfsretry_vers in the beginning of this file
2556 * and in main() routine.
2563 pr_err(gettext("backgrounding: %s\n"), mntp
->mnt_mountp
);
2566 pr_err(gettext("retrying: %s\n"), mntp
->mnt_mountp
);
2570 if ((r
= mount_nfs(mntp
, ro
, NULL
)) == RET_OK
) {
2571 pr_err(gettext("%s: mounted OK\n"), mntp
->mnt_mountp
);
2578 (void) sleep(delay
);
2586 pr_err(gettext("giving up on: %s\n"), mntp
->mnt_mountp
);
2592 * Read the NFS SMF Parameters to determine if the
2593 * client has been configured for a new min/max for the NFS version to
2601 int tmp
= 0, bufsz
= 0, ret
= 0;
2603 /* Maximum number of bytes expected. */
2605 ret
= nfs_smf_get_prop("client_versmin", value
, DEFAULT_INSTANCE
,
2606 SCF_TYPE_INTEGER
, SVC_NFS_CLIENT
, &bufsz
);
2609 tmp
= strtol(value
, (char **)NULL
, 10);
2611 vers_min_default
= tmp
;
2615 /* Maximum number of bytes expected. */
2617 ret
= nfs_smf_get_prop("client_versmax", value
, DEFAULT_INSTANCE
,
2618 SCF_TYPE_INTEGER
, SVC_NFS_CLIENT
, &bufsz
);
2621 tmp
= strtol(value
, (char **)NULL
, 10);
2623 vers_max_default
= tmp
;