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>
78 #include <tsol/label.h>
81 #include <rpcsvc/nfs4_prot.h>
87 #include <nfs/nfssys.h>
88 extern int _nfssys(enum nfssys_op
, void *);
100 #define RET_MNTERR 1000
101 #define ERR_PROTO_NONE 0
102 #define ERR_PROTO_INVALID 901
103 #define ERR_PROTO_UNSUPP 902
104 #define ERR_NETPATH 903
105 #define ERR_NOHOST 904
106 #define ERR_RPCERROR 905
108 typedef struct err_ret
{
113 #define SET_ERR_RET(errst, etype, eval) \
115 (errst)->error_type = etype; \
116 (errst)->error_value = eval; \
119 /* number of transports to try */
120 #define MNT_PREF_LISTLEN 2
124 #define BIGRETRY 10000
126 /* maximum length of RPC header for NFS messages */
127 #define NFS_RPC_HDR 432
129 #define NFS_ARGS_EXTB_secdata(args, secdata) \
130 { (args)->nfs_args_ext = NFS_ARGS_EXTB, \
131 (args)->nfs_ext_u.nfs_extB.secdata = secdata; }
133 extern int __clnt_bindresvport(CLIENT
*);
134 extern char *nfs_get_qop_name();
135 extern AUTH
* nfs_create_ah();
136 extern enum snego_stat
nfs_sec_nego();
138 static void usage(void);
139 static int retry(struct mnttab
*, int);
140 static int set_args(int *, struct nfs_args
*, char *, struct mnttab
*);
141 static int get_fh_via_pub(struct nfs_args
*, char *, char *, bool_t
, bool_t
,
142 int *, struct netconfig
**, ushort_t
);
143 static int get_fh(struct nfs_args
*, char *, char *, int *, bool_t
,
144 struct netconfig
**, ushort_t
);
145 static int make_secure(struct nfs_args
*, char *, struct netconfig
*,
147 static int mount_nfs(struct mnttab
*, int, err_ret_t
*);
148 static int getaddr_nfs(struct nfs_args
*, char *, struct netconfig
**,
149 bool_t
, char *, ushort_t
, err_ret_t
*, bool_t
);
150 static void pr_err(const char *fmt
, ...);
151 static void usage(void);
152 static struct netbuf
*get_addr(char *, rpcprog_t
, rpcvers_t
,
153 struct netconfig
**, char *, ushort_t
, struct t_info
*,
154 caddr_t
*, bool_t
, char *, err_ret_t
*);
156 static struct netbuf
*get_the_addr(char *, rpcprog_t
, rpcvers_t
,
157 struct netconfig
*, ushort_t
, struct t_info
*, caddr_t
*,
158 bool_t
, char *, err_ret_t
*);
160 extern int self_check(char *);
162 static void read_default(void);
164 static char typename
[64];
167 static int backgrounded
= 0;
168 static int posix
= 0;
169 static int retries
= BIGRETRY
;
170 static ushort_t nfs_port
= 0;
171 static char *nfs_proto
= NULL
;
174 static int Oflg
= 0; /* Overlay mounts */
175 static int qflg
= 0; /* quiet - don't print warnings on bad options */
177 static char *fstype
= MNTTYPE_NFS
;
179 static seconfig_t nfs_sec
;
180 static int sec_opt
= 0; /* any security option ? */
181 static bool_t snego_done
;
182 static void sigusr1(int);
184 extern void set_nfsv4_ephemeral_mount_to(void);
187 * list of support services needed
189 static char *service_list
[] = { STATD
, LOCKD
, NULL
};
190 static char *service_list_v4
[] = { STATD
, LOCKD
, NFS4CBD
, NFSMAPID
, NULL
};
193 * These two variables control the NFS version number to be used.
195 * nfsvers defaults to 0 which means to use the highest number that
196 * both the client and the server support. It can also be set to
197 * a particular value, either 2, 3, or 4 to indicate the version
198 * number of choice. If the server (or the client) do not support
199 * the version indicated, then the mount attempt will be failed.
201 * nfsvers_to_use is the actual version number found to use. It
202 * is determined in get_fh by pinging the various versions of the
203 * NFS service on the server to see which responds positively.
205 * nfsretry_vers is the version number set when we retry the mount
206 * command with the version decremented from nfsvers_to_use.
207 * nfsretry_vers is set from nfsvers_to_use when we retry the mount
208 * for errors other than RPC errors; it helps un know why we are
209 * retrying. It is an indication that the retry is due to
212 static rpcvers_t nfsvers
= 0;
213 static rpcvers_t nfsvers_to_use
= 0;
214 static rpcvers_t nfsretry_vers
= 0;
217 * There are the defaults (range) for the client when determining
218 * which NFS version to use when probing the server (see above).
219 * These will only be used when the vers mount option is not used and
220 * these may be reset if NFS SMF is configured to do so.
222 static rpcvers_t vers_max_default
= NFS_VERSMAX_DEFAULT
;
223 static rpcvers_t vers_min_default
= NFS_VERSMIN_DEFAULT
;
226 * This variable controls whether to try the public file handle.
228 static bool_t public_opt
;
231 main(int argc
, char *argv
[])
236 char optbuf
[MAX_MNTOPT_STR
];
241 err_ret_t retry_error
;
243 (void) setlocale(LC_ALL
, "");
244 #if !defined(TEXT_DOMAIN)
245 #define TEXT_DOMAIN "SYS_TEST"
247 (void) textdomain(TEXT_DOMAIN
);
249 myname
= strrchr(argv
[0], '/');
250 myname
= myname
? myname
+ 1 : argv
[0];
251 (void) snprintf(typename
, sizeof (typename
), "%s %s",
252 MNTTYPE_NFS
, myname
);
255 mnt
.mnt_mntopts
= optbuf
;
256 (void) strcpy(optbuf
, "rw");
261 while ((c
= getopt(argc
, argv
, "ro:mOq")) != EOF
) {
267 if (strlen(optarg
) >= MAX_MNTOPT_STR
) {
268 pr_err(gettext("option string too long"));
271 (void) strcpy(mnt
.mnt_mntopts
, optarg
);
272 #ifdef LATER /* XXX */
273 if (strstr(optarg
, MNTOPT_REMOUNT
)) {
275 * If remount is specified, only rw is allowed.
277 if ((strcmp(optarg
, MNTOPT_REMOUNT
) != 0) &&
278 (strcmp(optarg
, "remount,rw") != 0) &&
279 (strcmp(optarg
, "rw,remount") != 0)) {
280 pr_err(gettext("Invalid options\n"));
284 #endif /* LATER */ /* XXX */
300 if (argc
- optind
!= 2) {
305 mnt
.mnt_special
= argv
[optind
];
306 mnt
.mnt_mountp
= argv
[optind
+1];
308 if (!priv_ineffect(PRIV_SYS_MOUNT
) ||
309 !priv_ineffect(PRIV_NET_PRIVADDR
)) {
310 pr_err(gettext("insufficient privileges\n"));
315 * On a labeled system, allow read-down nfs mounts if privileged
316 * (PRIV_NET_MAC_AWARE) to do so. Otherwise, ignore the error
317 * and "mount equal label only" behavior will result.
319 if (is_system_labeled())
320 (void) setpflags(NET_MAC_AWARE
, 1);
323 * Read the NFS SMF defaults to see if the min/max versions have
324 * been set and therefore would override the encoded defaults.
325 * Then check to make sure that if they were set that the
326 * values are reasonable.
329 if (vers_min_default
> vers_max_default
||
330 vers_min_default
< NFS_VERSMIN
||
331 vers_max_default
> NFS_VERSMAX
) {
332 pr_err("%s\n%s %s\n",
333 gettext("Incorrect configuration of client\'s"),
334 gettext("client_versmin or client_versmax"),
335 gettext("is either out of range or overlaps."));
338 SET_ERR_RET(&retry_error
, ERR_PROTO_NONE
, 0);
339 r
= mount_nfs(&mnt
, ro
, &retry_error
);
340 if (r
== RET_RETRY
&& retries
) {
342 * Check the error code from the last mount attempt if it was
343 * an RPC error, then retry as is. Otherwise we retry with the
344 * nfsretry_vers set. It is set by decrementing nfsvers_to_use.
345 * If we are retrying with nfsretry_vers then we don't print any
346 * retry messages, since we are not retrying due to an RPC
349 if (retry_error
.error_type
) {
350 if (retry_error
.error_type
!= ERR_RPCERROR
) {
351 nfsretry_vers
= nfsvers_to_use
=
353 if (nfsretry_vers
< NFS_VERSMIN
)
367 pr_err(const char *fmt
, ...)
372 if (backgrounded
!= 0) {
373 (void) vsyslog(LOG_ERR
, fmt
, ap
);
375 (void) fprintf(stderr
, "%s: ", typename
);
376 (void) vfprintf(stderr
, fmt
, ap
);
377 (void) fflush(stderr
);
385 (void) fprintf(stderr
,
386 gettext("Usage: nfs mount [-r] [-o opts] [server:]path dir\n"));
391 mount_nfs(struct mnttab
*mntp
, int ro
, err_ret_t
*retry_error
)
393 struct nfs_args
*args
= NULL
, *argp
= NULL
, *prev_argp
= NULL
;
394 struct netconfig
*nconf
= NULL
;
395 struct replica
*list
= NULL
;
398 int oldvers
= 0, vers
= 0;
399 int last_error
= RET_OK
;
404 char *special
= NULL
;
405 char *oldpath
= NULL
;
406 char *newpath
= NULL
;
410 char *saveopts
= NULL
;
413 mntp
->mnt_fstype
= MNTTYPE_NFS
;
416 mntflags
|= MS_RDONLY
;
417 /* convert "rw"->"ro" */
418 if (p
= strstr(mntp
->mnt_mntopts
, "rw")) {
419 if (*(p
+2) == ',' || *(p
+2) == '\0')
425 mntflags
|= MS_OVERLAY
;
427 list
= parse_replica(mntp
->mnt_special
, &n
);
430 pr_err(gettext("nfs file system; use [host:]path\n"));
432 pr_err(gettext("no memory\n"));
436 replicated
= (n
> 1);
439 * There are some free() calls at the bottom of this loop, so be
440 * careful about adding continue statements.
442 for (i
= 0; i
< n
; i
++) {
447 argp
= (struct nfs_args
*)malloc(sizeof (*argp
));
449 pr_err(gettext("no memory\n"));
450 last_error
= RET_ERR
;
453 memset(argp
, 0, sizeof (*argp
));
455 memset(&nfs_sec
, 0, sizeof (nfs_sec
));
463 * Looking for resources of the form
464 * nfs://server_host[:port_number]/path_name
466 if (strcmp(list
[i
].host
, "nfs") == 0 && strncmp(list
[i
].path
,
470 oldpath
= strdup(list
[i
].path
);
471 if (oldpath
== NULL
) {
472 pr_err(gettext("memory allocation failure\n"));
473 last_error
= RET_ERR
;
476 host
= list
[i
].path
+2;
477 path
= strchr(host
, '/');
481 "illegal nfs url syntax\n"));
482 last_error
= RET_ERR
;
488 cb
= strchr(host
, ']');
491 "illegal nfs url syntax\n"));
492 last_error
= RET_ERR
;
499 port
= htons((ushort_t
)
503 sport
= strchr(host
, ':');
505 if (sport
!= NULL
&& sport
< path
) {
507 port
= htons((ushort_t
)atoi(sport
+1));
520 if (r
= set_args(&mntflags
, argp
, host
, mntp
)) {
525 if (public_opt
== TRUE
)
530 } else if (nfs_port
!= 0 && nfs_port
!= port
) {
532 "port (%u) in nfs URL not the same"
533 " as port (%u) in port option\n"),
534 (unsigned int)ntohs(port
),
535 (unsigned int)ntohs(nfs_port
));
536 last_error
= RET_ERR
;
541 if (replicated
&& !(mntflags
& MS_RDONLY
)) {
543 "replicated mounts must be read-only\n"));
544 last_error
= RET_ERR
;
548 if (replicated
&& (argp
->flags
& NFSMNT_SOFT
)) {
550 "replicated mounts must not be soft\n"));
551 last_error
= RET_ERR
;
561 * If -o public was specified, and/or a URL was specified,
562 * then try the public file handle method.
564 if ((use_pubfh
== TRUE
) || (url
== TRUE
)) {
565 r
= get_fh_via_pub(argp
, host
, path
, url
, use_pubfh
,
566 &vers
, &nconf
, port
);
570 * If -o public was specified, then return the
573 if (use_pubfh
== TRUE
) {
579 argp
->flags
|= NFSMNT_PUBLIC
;
582 if ((r
!= RET_OK
) || (vers
== NFS_V4
)) {
583 bool_t loud_on_mnt_err
;
586 * This can happen if -o public is not specified,
587 * special is a URL, and server doesn't support
588 * public file handle.
595 * If the path portion of the URL didn't have
596 * a leading / then there is good possibility
597 * that a mount without a leading slash will
600 if (url
== TRUE
&& *path
!= '/')
601 loud_on_mnt_err
= FALSE
;
603 loud_on_mnt_err
= TRUE
;
605 r
= get_fh(argp
, host
, path
, &vers
,
606 loud_on_mnt_err
, &nconf
, port
);
611 * If there was no leading / and the path was
612 * derived from a URL, then try again
615 if ((r
== RET_MNTERR
) &&
616 (loud_on_mnt_err
== FALSE
)) {
618 newpath
= malloc(strlen(path
)+2);
620 if (newpath
== NULL
) {
621 pr_err(gettext("memory "
622 "allocation failure\n"));
623 last_error
= RET_ERR
;
627 strcpy(newpath
, "/");
628 strcat(newpath
, path
);
630 r
= get_fh(argp
, host
, newpath
, &vers
,
638 * map exit code back to RET_ERR.
649 free(argp
->pathconf
);
660 if (oldvers
&& vers
!= oldvers
) {
662 gettext("replicas must have the same version\n"));
663 last_error
= RET_ERR
;
668 * decide whether to use remote host's
669 * lockd or do local locking
671 if (!(argp
->flags
& NFSMNT_LLOCK
) && vers
== NFS_VERSION
&&
672 remote_lock(host
, argp
->fh
)) {
673 (void) fprintf(stderr
, gettext(
674 "WARNING: No network locking on %s:%s:"),
676 (void) fprintf(stderr
, gettext(
677 " contact admin to install server change\n"));
678 argp
->flags
|= NFSMNT_LLOCK
;
681 if (self_check(host
))
682 argp
->flags
|= NFSMNT_LOOPBACK
;
684 if (use_pubfh
== FALSE
) {
686 * Call to get_fh() above may have obtained the
687 * netconfig info and NULL proc'd the server.
688 * This would be the case with v4
690 if (!(argp
->flags
& NFSMNT_KNCONF
)) {
692 if (r
= getaddr_nfs(argp
, host
, &nconf
,
693 FALSE
, path
, port
, retry_error
,
701 if (make_secure(argp
, host
, nconf
, use_pubfh
, vers
) < 0) {
702 last_error
= RET_ERR
;
706 if ((url
== TRUE
) && (use_pubfh
== FALSE
)) {
708 * Convert the special from
713 if (convert_special(&special
, host
, oldpath
, path
,
714 mntp
->mnt_special
) == -1) {
715 (void) fprintf(stderr
, gettext(
716 "could not convert URL nfs:%s to %s:%s\n"),
717 oldpath
, host
, path
);
718 last_error
= RET_ERR
;
721 mntp
->mnt_special
= special
;
725 if (prev_argp
== NULL
)
728 prev_argp
->nfs_ext_u
.nfs_extB
.next
= argp
;
732 if (oldpath
!= NULL
) {
737 if (newpath
!= NULL
) {
746 last_error
= RET_RETRY
;
750 /* Determine which services are appropriate for the NFS version */
751 if (strcmp(fstype
, MNTTYPE_NFS4
) == 0)
752 sl
= service_list_v4
;
757 * enable services as needed.
761 mntflags
|= MS_DATA
| MS_OPTIONSTR
;
764 mntflags
|= MS_NOMNTTAB
;
767 saveopts
= strdup(mntp
->mnt_mntopts
);
770 * And make sure that we have the ephemeral mount_to
773 set_nfsv4_ephemeral_mount_to();
775 if (mount(mntp
->mnt_special
, mntp
->mnt_mountp
, mntflags
, fstype
, args
,
776 sizeof (*args
), mntp
->mnt_mntopts
, MAX_MNTOPT_STR
) < 0) {
777 if (errno
!= ENOENT
) {
778 pr_err(gettext("mount: %s: %s\n"),
779 mntp
->mnt_mountp
, strerror(errno
));
782 if (stat(mntp
->mnt_mountp
, &sb
) < 0 && errno
== ENOENT
)
783 pr_err(gettext("mount: %s: %s\n"),
784 mntp
->mnt_mountp
, strerror(ENOENT
));
786 pr_err("%s: %s\n", mntp
->mnt_special
,
790 last_error
= RET_ERR
;
794 if (!qflg
&& saveopts
!= NULL
) {
795 cmp_requested_to_actual_options(saveopts
, mntp
->mnt_mntopts
,
796 mntp
->mnt_special
, mntp
->mnt_mountp
);
800 if (saveopts
!= NULL
)
809 free_replica(list
, n
);
813 * If we had a new entry which was not added to the
814 * list yet, then add it now that it can be freed.
816 if (prev_argp
== NULL
)
819 prev_argp
->nfs_ext_u
.nfs_extB
.next
= argp
;
822 while (argp
!= NULL
) {
826 free(argp
->pathconf
);
830 free(argp
->addr
->buf
);
833 nfs_free_secdata(argp
->nfs_ext_u
.nfs_extB
.secdata
);
834 if (argp
->syncaddr
) {
835 free(argp
->syncaddr
->buf
);
836 free(argp
->syncaddr
);
841 argp
= argp
->nfs_ext_u
.nfs_extB
.next
;
849 * These options are duplicated in uts/common/fs/nfs/nfs_dlinet.c
850 * Changes must be made to both lists.
852 static char *optlist
[] = {
859 #define OPT_NOQUOTA 3
871 #define OPT_REMOUNT 9
877 #define OPT_NOINTR 12
881 #define OPT_SECURE 14
889 #define OPT_RETRANS 18
891 #define OPT_ACTIMEO 19
893 #define OPT_ACREGMIN 20
895 #define OPT_ACREGMAX 21
897 #define OPT_ACDIRMIN 22
899 #define OPT_ACDIRMAX 23
919 #define OPT_SEMISOFT 33
921 #define OPT_NOPRINT 34
925 #define OPT_LARGEFILES 36
927 #define OPT_NOLARGEFILES 37
929 #define OPT_PUBLIC 38
931 #define OPT_DIRECTIO 39
932 MNTOPT_FORCEDIRECTIO
,
933 #define OPT_NODIRECTIO 40
934 MNTOPT_NOFORCEDIRECTIO
,
937 #define OPT_NOXATTR 42
939 #define OPT_DEVICES 43
941 #define OPT_NODEVICES 44
943 #define OPT_SETUID 45
945 #define OPT_NOSETUID 46
949 #define OPT_NOEXEC 48
955 convert_int(int *val
, char *str
)
959 if (str
== NULL
|| !isdigit(*str
))
962 lval
= strtol(str
, &str
, 10);
963 if (*str
!= '\0' || lval
> INT_MAX
)
971 set_args(int *mntflags
, struct nfs_args
*args
, char *fshost
, struct mnttab
*mnt
)
973 char *saveopt
, *optstr
, *opts
, *newopts
, *val
;
980 args
->flags
= NFSMNT_INT
; /* default is "intr" */
981 args
->flags
|= NFSMNT_HOSTNAME
;
982 args
->flags
|= NFSMNT_NEWARGS
; /* using extented nfs_args structure */
983 args
->hostname
= fshost
;
985 optstr
= opts
= strdup(mnt
->mnt_mntopts
);
986 /* sizeof (MNTOPT_XXX) includes one extra byte we may need for "," */
987 optlen
= strlen(mnt
->mnt_mntopts
) + sizeof (MNTOPT_XATTR
) + 1;
988 if (optlen
> MAX_MNTOPT_STR
) {
989 pr_err(gettext("option string too long"));
992 newopts
= malloc(optlen
);
993 if (opts
== NULL
|| newopts
== NULL
) {
994 pr_err(gettext("no memory"));
1006 switch (getsubopt(&opts
, optlist
, &val
)) {
1008 *mntflags
|= MS_RDONLY
;
1011 *mntflags
&= ~(MS_RDONLY
);
1017 args
->flags
|= NFSMNT_SOFT
;
1018 args
->flags
&= ~(NFSMNT_SEMISOFT
);
1021 args
->flags
|= NFSMNT_SOFT
;
1022 args
->flags
|= NFSMNT_SEMISOFT
;
1025 args
->flags
&= ~(NFSMNT_SOFT
);
1026 args
->flags
&= ~(NFSMNT_SEMISOFT
);
1029 *mntflags
&= ~(MS_NOSUID
);
1032 *mntflags
|= MS_NOSUID
;
1035 args
->flags
|= NFSMNT_GRPID
;
1038 *mntflags
|= MS_REMOUNT
;
1041 args
->flags
|= NFSMNT_INT
;
1044 args
->flags
&= ~(NFSMNT_INT
);
1047 args
->flags
|= NFSMNT_NOAC
;
1050 if (convert_int(&num
, val
) != 0)
1052 nfs_port
= htons((ushort_t
)num
);
1056 if (nfs_getseconfig_byname("dh", &nfs_sec
)) {
1057 pr_err(gettext("can not get \"dh\" from %s\n"),
1065 args
->flags
|= NFSMNT_NOCTO
;
1069 if (convert_int(&args
->rsize
, val
) != 0)
1071 args
->flags
|= NFSMNT_RSIZE
;
1074 if (convert_int(&args
->wsize
, val
) != 0)
1076 args
->flags
|= NFSMNT_WSIZE
;
1079 if (convert_int(&args
->timeo
, val
) != 0)
1081 args
->flags
|= NFSMNT_TIMEO
;
1084 if (convert_int(&args
->retrans
, val
) != 0)
1086 args
->flags
|= NFSMNT_RETRANS
;
1089 if (convert_int(&args
->acregmax
, val
) != 0)
1091 args
->acdirmin
= args
->acregmin
= args
->acdirmax
1093 args
->flags
|= NFSMNT_ACDIRMAX
;
1094 args
->flags
|= NFSMNT_ACREGMAX
;
1095 args
->flags
|= NFSMNT_ACDIRMIN
;
1096 args
->flags
|= NFSMNT_ACREGMIN
;
1099 if (convert_int(&args
->acregmin
, val
) != 0)
1101 args
->flags
|= NFSMNT_ACREGMIN
;
1104 if (convert_int(&args
->acregmax
, val
) != 0)
1106 args
->flags
|= NFSMNT_ACREGMAX
;
1109 if (convert_int(&args
->acdirmin
, val
) != 0)
1111 args
->flags
|= NFSMNT_ACDIRMIN
;
1114 if (convert_int(&args
->acdirmax
, val
) != 0)
1116 args
->flags
|= NFSMNT_ACDIRMAX
;
1125 if (convert_int(&retries
, val
) != 0)
1129 args
->flags
|= NFSMNT_LLOCK
;
1135 if (convert_int(&num
, val
) != 0)
1137 nfsvers
= (rpcvers_t
)num
;
1143 nfs_proto
= (char *)malloc(strlen(val
)+1);
1145 pr_err(gettext("no memory"));
1149 (void) strncpy(nfs_proto
, val
, strlen(val
)+1);
1153 args
->flags
|= NFSMNT_NOPRINT
;
1156 case OPT_LARGEFILES
:
1160 case OPT_NOLARGEFILES
:
1161 pr_err(gettext("NFS can't support \"nolargefiles\"\n"));
1168 "\"sec\" option requires argument\n"));
1171 if (nfs_getseconfig_byname(val
, &nfs_sec
)) {
1172 pr_err(gettext("can not get \"%s\" from %s\n"),
1184 args
->flags
|= NFSMNT_DIRECTIO
;
1187 case OPT_NODIRECTIO
:
1188 args
->flags
&= ~(NFSMNT_DIRECTIO
);
1194 * VFS options; just need to get them into the
1195 * new mount option string and note we've seen them
1201 * Note that this could be a valid OPT_* option so
1202 * we can't use "val" but need to use "saveopt".
1204 if (fsisstdopt(saveopt
))
1208 (void) fprintf(stderr
, gettext(
1209 "mount: %s on %s - WARNING unknown option"
1210 " \"%s\"\n"), mnt
->mnt_special
,
1211 mnt
->mnt_mountp
, saveopt
);
1216 strcat(newopts
, ",");
1217 strcat(newopts
, saveopt
);
1220 /* Default is to turn extended attrs on */
1223 strcat(newopts
, ",");
1224 strcat(newopts
, MNTOPT_XATTR
);
1226 strcpy(mnt
->mnt_mntopts
, newopts
);
1230 /* ensure that only one secure mode is requested */
1232 pr_err(gettext("Security options conflict\n"));
1236 /* ensure that the user isn't trying to get large files over V2 */
1237 if (nfsvers
== NFS_VERSION
&& largefiles
) {
1238 pr_err(gettext("NFS V2 can't support \"largefiles\"\n"));
1242 if (nfsvers
== NFS_V4
&&
1243 nfs_proto
!= NULL
&&
1244 strncasecmp(nfs_proto
, NC_UDP
, strlen(NC_UDP
)) == 0) {
1245 pr_err(gettext("NFS V4 does not support %s\n"), nfs_proto
);
1252 pr_err(gettext("invalid option: \"%s\"\n"), saveopt
);
1258 make_secure(struct nfs_args
*args
, char *hostname
, struct netconfig
*nconf
,
1259 bool_t use_pubfh
, rpcvers_t vers
)
1261 sec_data_t
*secdata
;
1263 struct netbuf
*syncaddr
= NULL
;
1264 struct nd_addrlist
*retaddrs
= NULL
;
1265 char netname
[MAXNETNAMELEN
+1];
1268 * check to see if any secure mode is requested.
1269 * if not, use default security mode.
1271 if (!snego_done
&& !sec_opt
) {
1273 * Get default security mode.
1274 * AUTH_UNIX has been the default choice for a long time.
1275 * The better NFS security service becomes, the better chance
1276 * we will set stronger security service as the default NFS
1279 if (nfs_getseconfig_default(&nfs_sec
)) {
1280 pr_err(gettext("error getting default"
1281 " security entry\n"));
1284 args
->flags
|= NFSMNT_SECDEFAULT
;
1288 * Get the network address for the time service on the server.
1289 * If an RPC based time service is not available then try the
1292 * This is for AUTH_DH processing. We will also pass down syncaddr
1293 * and netname for NFS V4 even if AUTH_DH is not requested right now.
1294 * NFS V4 does security negotiation in the kernel via SECINFO.
1295 * These information might be needed later in the kernel.
1297 * Eventurally, we want to move this code to nfs_clnt_secdata()
1298 * when autod_nfs.c and mount.c can share the same get_the_addr()
1304 if (nfs_sec
.sc_rpcnum
== AUTH_DH
|| vers
== NFS_V4
) {
1306 * If using the public fh or nfsv4, we will not contact the
1307 * remote RPCBINDer, since it is possibly behind a firewall.
1309 if (use_pubfh
== FALSE
&& vers
!= NFS_V4
)
1310 syncaddr
= get_the_addr(hostname
, RPCBPROG
, RPCBVERS
,
1311 nconf
, 0, NULL
, NULL
, FALSE
, NULL
, NULL
);
1313 if (syncaddr
!= NULL
) {
1314 /* for flags in sec_data */
1315 flags
|= AUTH_F_RPCTIMESYNC
;
1317 struct nd_hostserv hs
;
1320 hs
.h_host
= hostname
;
1321 hs
.h_serv
= "timserver";
1323 error
= netdir_getbyname(nconf
, &hs
, &retaddrs
);
1325 if (error
!= ND_OK
&& (nfs_sec
.sc_rpcnum
== AUTH_DH
)) {
1326 pr_err(gettext("%s: secure: no time service\n"),
1332 syncaddr
= retaddrs
->n_addrs
;
1335 * For NFS_V4 if AUTH_DH is negotiated later in the
1336 * kernel thru SECINFO, it will need syncaddr
1339 if (vers
== NFS_V4
&& syncaddr
&&
1340 host2netname(netname
, hostname
, NULL
)) {
1341 args
->syncaddr
= malloc(sizeof (struct netbuf
));
1342 args
->syncaddr
->buf
= malloc(syncaddr
->len
);
1343 (void) memcpy(args
->syncaddr
->buf
,
1344 syncaddr
->buf
, syncaddr
->len
);
1345 args
->syncaddr
->len
= syncaddr
->len
;
1346 args
->syncaddr
->maxlen
= syncaddr
->maxlen
;
1347 args
->netname
= strdup(netname
);
1348 args
->flags
|= NFSMNT_SECURE
;
1354 * For the initial chosen flavor (any flavor defined in nfssec.conf),
1355 * the data will be stored in the sec_data structure via
1356 * nfs_clnt_secdata() and be passed to the kernel via nfs_args_*
1357 * extended data structure.
1359 if (!(secdata
= nfs_clnt_secdata(&nfs_sec
, hostname
, args
->knconf
,
1360 syncaddr
, flags
))) {
1361 pr_err(gettext("errors constructing security related data\n"));
1362 if (flags
& AUTH_F_RPCTIMESYNC
) {
1363 free(syncaddr
->buf
);
1365 } else if (retaddrs
)
1366 netdir_free((void *)retaddrs
, ND_ADDRLIST
);
1370 NFS_ARGS_EXTB_secdata(args
, secdata
);
1371 if (flags
& AUTH_F_RPCTIMESYNC
) {
1372 free(syncaddr
->buf
);
1374 } else if (retaddrs
)
1375 netdir_free((void *)retaddrs
, ND_ADDRLIST
);
1380 * Get the network address on "hostname" for program "prog"
1381 * with version "vers" by using the nconf configuration data
1384 * If the address of a netconfig pointer is null then
1385 * information is not sufficient and no netbuf will be returned.
1387 * Finally, ping the null procedure of that service.
1389 * A similar routine is also defined in ../../autofs/autod_nfs.c.
1390 * This is a potential routine to move to ../lib for common usage.
1392 static struct netbuf
*
1393 get_the_addr(char *hostname
, ulong_t prog
, ulong_t vers
,
1394 struct netconfig
*nconf
, ushort_t port
, struct t_info
*tinfo
,
1395 caddr_t
*fhp
, bool_t get_pubfh
, char *fspath
, err_ret_t
*error
)
1397 struct netbuf
*nb
= NULL
;
1398 struct t_bind
*tbind
= NULL
;
1403 AUTH
*new_ah
= NULL
;
1404 struct snego_t snego
;
1409 if ((fd
= t_open(nconf
->nc_device
, O_RDWR
, tinfo
)) == -1)
1412 /* LINTED pointer alignment */
1413 if ((tbind
= (struct t_bind
*)t_alloc(fd
, T_BIND
, T_ADDR
))
1418 * In the case of public filehandle usage or NFSv4 we want to
1419 * avoid use of the rpcbind/portmap protocol
1421 if ((get_pubfh
== TRUE
) || (vers
== NFS_V4
)) {
1422 struct nd_hostserv hs
;
1423 struct nd_addrlist
*retaddrs
;
1425 hs
.h_host
= hostname
;
1427 /* NFS where vers==4 does not support UDP */
1428 if (vers
== NFS_V4
&&
1429 strncasecmp(nconf
->nc_proto
, NC_UDP
,
1430 strlen(NC_UDP
)) == 0) {
1431 SET_ERR_RET(error
, ERR_PROTO_UNSUPP
, 0);
1440 if ((retval
= netdir_getbyname(nconf
, &hs
, &retaddrs
))
1443 * Carefully set the error value here. Want to signify
1444 * that the error was an unknown host.
1446 if (retval
== ND_NOHOST
) {
1447 SET_ERR_RET(error
, ERR_NOHOST
, retval
);
1452 memcpy(tbind
->addr
.buf
, retaddrs
->n_addrs
->buf
,
1453 retaddrs
->n_addrs
->len
);
1454 tbind
->addr
.len
= retaddrs
->n_addrs
->len
;
1455 netdir_free((void *)retaddrs
, ND_ADDRLIST
);
1456 (void) netdir_options(nconf
, ND_SET_RESERVEDPORT
, fd
, NULL
);
1459 if (rpcb_getaddr(prog
, vers
, nconf
, &tbind
->addr
,
1460 hostname
) == FALSE
) {
1466 /* LINTED pointer alignment */
1467 if (strcmp(nconf
->nc_protofmly
, NC_INET
) == 0)
1468 ((struct sockaddr_in
*)tbind
->addr
.buf
)->sin_port
1470 else if (strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0)
1471 ((struct sockaddr_in6
*)tbind
->addr
.buf
)->sin6_port
1476 cl
= clnt_tli_create(fd
, nconf
, &tbind
->addr
, prog
, vers
, 0, 0);
1479 * clnt_tli_create() returns either RPC_SYSTEMERROR,
1480 * RPC_UNKNOWNPROTO or RPC_TLIERROR. The RPC_TLIERROR translates
1481 * to "Misc. TLI error". This is not too helpful. Most likely
1482 * the connection to the remote server timed out, so this
1483 * error is at least less perplexing.
1484 * See: usr/src/cmd/rpcinfo/rpcinfo.c
1486 if (rpc_createerr
.cf_stat
== RPC_TLIERROR
) {
1487 SET_ERR_RET(error
, ERR_RPCERROR
, RPC_PMAPFAILURE
);
1489 SET_ERR_RET(error
, ERR_RPCERROR
, rpc_createerr
.cf_stat
);
1494 ah
= authsys_create_default();
1501 (void) clnt_control(cl
, CLSET_TIMEOUT
, (char *)&tv
);
1503 if ((get_pubfh
== TRUE
) && (vers
!= NFS_V4
)) {
1504 enum snego_stat sec
;
1508 * negotiate sec flavor.
1511 if ((sec
= nfs_sec_nego(vers
, cl
, fspath
, &snego
)) ==
1516 * check if server supports the one
1517 * specified in the sec= option.
1520 for (jj
= 0; jj
< snego
.cnt
; jj
++) {
1521 if (snego
.array
[jj
] ==
1522 nfs_sec
.sc_nfsnum
) {
1530 * find a common sec flavor
1535 "Server does not support"
1536 " the security flavor"
1540 for (jj
= 0; jj
< snego
.cnt
; jj
++) {
1541 if (!nfs_getseconfig_bynumber(
1545 #define EMSG80SUX "Security flavor %d was negotiated and will be used.\n"
1560 * Now that the flavor has been
1561 * negotiated, get the fh.
1563 * First, create an auth handle using the
1564 * negotiated sec flavor in the next lookup to
1565 * fetch the filehandle.
1567 new_ah
= nfs_create_ah(cl
, hostname
, &nfs_sec
);
1570 cl
->cl_auth
= new_ah
;
1571 } else if (sec
== SNEGO_ARRAY_TOO_SMALL
|| sec
==
1577 * Note that if sec == SNEGO_DEF_VALID
1578 * default sec flavor is acceptable.
1579 * Use it to get the filehandle.
1583 if (vers
== NFS_VERSION
) {
1587 memset((char *)&arg
.dir
, 0, sizeof (wnl_fh
));
1589 memset((char *)&res
, 0, sizeof (wnl_diropres
));
1590 if (wnlproc_lookup_2(&arg
, &res
, cl
) !=
1591 RPC_SUCCESS
|| res
.status
!= WNL_OK
)
1594 *fhp
= malloc(sizeof (wnl_fh
));
1597 pr_err(gettext("no memory\n"));
1601 memcpy((char *)*fhp
,
1602 (char *)&res
.wnl_diropres_u
.wnl_diropres
.file
,
1605 WNL_LOOKUP3args arg
;
1609 memset((char *)&arg
.what
.dir
, 0, sizeof (wnl_fh3
));
1610 arg
.what
.name
= fspath
;
1611 memset((char *)&res
, 0, sizeof (WNL_LOOKUP3res
));
1612 if (wnlproc3_lookup_3(&arg
, &res
, cl
) !=
1613 RPC_SUCCESS
|| res
.status
!= WNL3_OK
)
1616 fh3p
= (nfs_fh3
*)malloc(sizeof (*fh3p
));
1619 pr_err(gettext("no memory\n"));
1624 res
.WNL_LOOKUP3res_u
.res_ok
.object
.data
.data_len
;
1625 memcpy(fh3p
->fh3_u
.data
,
1626 res
.WNL_LOOKUP3res_u
.res_ok
.object
.data
.data_val
,
1629 *fhp
= (caddr_t
)fh3p
;
1632 struct rpc_err r_err
;
1636 * NULL procedures need not have an argument or
1639 if (vers
== NFS_VERSION
)
1640 rc
= wnlproc_null_2(NULL
, NULL
, cl
);
1641 else if (vers
== NFS_V3
)
1642 rc
= wnlproc3_null_3(NULL
, NULL
, cl
);
1644 rc
= wnlproc4_null_4(NULL
, NULL
, cl
);
1646 if (rc
!= RPC_SUCCESS
) {
1647 clnt_geterr(cl
, &r_err
);
1648 if (strcmp(nconf
->nc_protofmly
, NC_LOOPBACK
) == 0) {
1649 switch (r_err
.re_status
) {
1653 r_err
.re_status
= RPC_PROGVERSMISMATCH
;
1656 SET_ERR_RET(error
, ERR_RPCERROR
, r_err
.re_status
);
1662 * Make a copy of the netbuf to return
1664 nb
= (struct netbuf
*)malloc(sizeof (*nb
));
1666 pr_err(gettext("no memory\n"));
1670 nb
->buf
= (char *)malloc(nb
->maxlen
);
1671 if (nb
->buf
== NULL
) {
1672 pr_err(gettext("no memory\n"));
1677 (void) memcpy(nb
->buf
, tbind
->addr
.buf
, tbind
->addr
.len
);
1684 AUTH_DESTROY(cl
->cl_auth
);
1691 t_free((char *)tbind
, T_BIND
);
1700 check_nconf(struct netconfig
*nconf
, int nthtry
, int *valid_proto
)
1707 if (nthtry
== FIRST_TRY
) {
1708 try_test
= ((nconf
->nc_semantics
== NC_TPI_COTS_ORD
) ||
1709 (nconf
->nc_semantics
== NC_TPI_COTS
));
1711 } else if (nthtry
== SECOND_TRY
) {
1712 try_test
= (nconf
->nc_semantics
== NC_TPI_CLTS
);
1717 (strcmp(nconf
->nc_protofmly
, NC_INET
) == 0 ||
1718 strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0) &&
1719 (strcmp(nconf
->nc_proto
, proto
) == 0))
1720 *valid_proto
= TRUE
;
1722 *valid_proto
= FALSE
;
1728 * Get a network address on "hostname" for program "prog"
1729 * with version "vers". If the port number is specified (non zero)
1730 * then try for a TCP/UDP transport and set the port number of the
1731 * resulting IP address.
1733 * If the address of a netconfig pointer was passed and
1734 * if it's not null, use it as the netconfig otherwise
1735 * assign the address of the netconfig that was used to
1736 * establish contact with the service.
1738 * A similar routine is also defined in ../../autofs/autod_nfs.c.
1739 * This is a potential routine to move to ../lib for common usage.
1741 * "error" refers to a more descriptive term when get_addr fails
1742 * and returns NULL: ERR_PROTO_NONE if no error introduced by
1743 * -o proto option, ERR_NETPATH if error found in NETPATH
1744 * environment variable, ERR_PROTO_INVALID if an unrecognized
1745 * protocol is specified by user, and ERR_PROTO_UNSUPP for a
1746 * recognized but invalid protocol (eg. ticlts, ticots, etc.).
1747 * "error" is ignored if get_addr returns non-NULL result.
1750 static struct netbuf
*
1751 get_addr(char *hostname
, ulong_t prog
, ulong_t vers
, struct netconfig
**nconfp
,
1752 char *proto
, ushort_t port
, struct t_info
*tinfo
, caddr_t
*fhp
,
1753 bool_t get_pubfh
, char *fspath
, err_ret_t
*error
)
1755 struct netbuf
*nb
= NULL
;
1756 struct netconfig
*nconf
= NULL
;
1757 NCONF_HANDLE
*nc
= NULL
;
1758 int nthtry
= FIRST_TRY
;
1759 err_ret_t errsave_nohost
, errsave_rpcerr
;
1761 SET_ERR_RET(&errsave_nohost
, ERR_PROTO_NONE
, 0);
1762 SET_ERR_RET(&errsave_rpcerr
, ERR_PROTO_NONE
, 0);
1764 SET_ERR_RET(error
, ERR_PROTO_NONE
, 0);
1766 if (nconfp
&& *nconfp
)
1767 return (get_the_addr(hostname
, prog
, vers
, *nconfp
, port
,
1768 tinfo
, fhp
, get_pubfh
, fspath
, error
));
1770 * No nconf passed in.
1772 * Try to get a nconf from /etc/netconfig filtered by
1773 * the NETPATH environment variable.
1774 * First search for COTS, second for CLTS unless proto
1775 * is specified. When we retry, we reset the
1776 * netconfig list so that we would search the whole list
1780 if ((nc
= setnetpath()) == NULL
) {
1781 /* should only return an error if problems with NETPATH */
1782 /* In which case you are hosed */
1783 SET_ERR_RET(error
, ERR_NETPATH
, 0);
1788 * If proto is specified, then only search for the match,
1789 * otherwise try COTS first, if failed, try CLTS.
1792 /* no matching proto name */
1793 SET_ERR_RET(error
, ERR_PROTO_INVALID
, 0);
1795 while (nconf
= getnetpath(nc
)) {
1796 if (strcmp(nconf
->nc_netid
, proto
))
1799 /* may be unsupported */
1800 SET_ERR_RET(error
, ERR_PROTO_UNSUPP
, 0);
1803 ((strcmp(nconf
->nc_protofmly
, NC_INET
) == 0 ||
1804 strcmp(nconf
->nc_protofmly
, NC_INET6
) == 0) &&
1805 (strcmp(nconf
->nc_proto
, NC_TCP
) != 0 &&
1806 strcmp(nconf
->nc_proto
, NC_UDP
) != 0))) {
1809 nb
= get_the_addr(hostname
, prog
,
1810 vers
, nconf
, port
, tinfo
,
1811 fhp
, get_pubfh
, fspath
, error
);
1816 /* nb is NULL - deal with errors */
1818 if (error
->error_type
== ERR_NOHOST
)
1819 SET_ERR_RET(&errsave_nohost
,
1821 error
->error_value
);
1822 if (error
->error_type
== ERR_RPCERROR
)
1823 SET_ERR_RET(&errsave_rpcerr
,
1825 error
->error_value
);
1828 * continue with same protocol
1833 } /* end of while */
1838 if ((nb
= get_the_addr(hostname
, prog
, vers
, nconf
, port
,
1839 tinfo
, fhp
, get_pubfh
, fspath
, error
)) == NULL
)
1843 SET_ERR_RET(error
, ERR_NETPATH
, 0);
1844 while (nconf
= getnetpath(nc
)) {
1845 SET_ERR_RET(error
, ERR_PROTO_NONE
, 0);
1847 if (nconf
->nc_flag
& NC_VISIBLE
) {
1850 if (check_nconf(nconf
,
1851 nthtry
, &valid_proto
)) {
1855 if (valid_proto
== TRUE
)
1860 if (nconf
== NULL
) {
1861 if (++nthtry
<= MNT_PREF_LISTLEN
) {
1863 if ((nc
= setnetpath()) == NULL
)
1869 if ((nb
= get_the_addr(hostname
, prog
, vers
, nconf
,
1870 port
, tinfo
, fhp
, get_pubfh
, fspath
, error
))
1872 /* nb is NULL - deal with errors */
1874 if (error
->error_type
== ERR_NOHOST
)
1875 SET_ERR_RET(&errsave_nohost
,
1877 error
->error_value
);
1878 if (error
->error_type
== ERR_RPCERROR
)
1879 SET_ERR_RET(&errsave_rpcerr
,
1881 error
->error_value
);
1884 * Continue the same search path in the
1885 * netconfig db until no more matched
1886 * nconf (nconf == NULL).
1892 SET_ERR_RET(error
, ERR_PROTO_NONE
, 0);
1895 * Got nconf and nb. Now dup the netconfig structure (nconf)
1896 * and return it thru nconfp.
1898 *nconfp
= getnetconfigent(nconf
->nc_netid
);
1899 if (*nconfp
== NULL
) {
1900 syslog(LOG_ERR
, "no memory\n");
1910 * Check the saved errors. The RPC error has *
1911 * precedence over the no host error.
1913 if (errsave_nohost
.error_type
!= ERR_PROTO_NONE
)
1914 SET_ERR_RET(error
, errsave_nohost
.error_type
,
1915 errsave_nohost
.error_value
);
1917 if (errsave_rpcerr
.error_type
!= ERR_PROTO_NONE
)
1918 SET_ERR_RET(error
, errsave_rpcerr
.error_type
,
1919 errsave_rpcerr
.error_value
);
1926 * Get a file handle usinging multi-component lookup with the public
1930 get_fh_via_pub(struct nfs_args
*args
, char *fshost
, char *fspath
, bool_t url
,
1931 bool_t loud
, int *versp
, struct netconfig
**nconfp
, ushort_t port
)
1939 vers_max
= vers_min
= nfsvers
;
1941 vers_max
= vers_max_default
;
1942 vers_min
= vers_min_default
;
1946 path
= malloc(strlen(fspath
) + 2);
1949 pr_err(gettext("no memory\n"));
1953 path
[0] = (char)WNL_NATIVEPATH
;
1954 (void) strcpy(&path
[1], fspath
);
1960 for (nfsvers_to_use
= vers_max
; nfsvers_to_use
>= vers_min
;
1963 * getaddr_nfs will also fill in the fh for us.
1965 r
= getaddr_nfs(args
, fshost
, nconfp
,
1966 TRUE
, path
, port
, NULL
, FALSE
);
1970 * Since we are using the public fh, and NLM is
1971 * not firewall friendly, use local locking.
1972 * Not the case for v4.
1974 *versp
= nfsvers_to_use
;
1975 switch (nfsvers_to_use
) {
1977 fstype
= MNTTYPE_NFS4
;
1980 fstype
= MNTTYPE_NFS3
;
1981 /* fall through to pick up llock option */
1983 args
->flags
|= NFSMNT_LLOCK
;
1997 pr_err(gettext("Could not use public filehandle in request to"
1998 " server %s\n"), fshost
);
2005 * get fhandle of remote path from server's mountd
2008 get_fh(struct nfs_args
*args
, char *fshost
, char *fspath
, int *versp
,
2009 bool_t loud_on_mnt_err
, struct netconfig
**nconfp
, ushort_t port
)
2011 static struct fhstatus fhs
;
2012 static struct mountres3 mountres3
;
2013 static struct pathcnf p
;
2015 struct timeval timeout
= { 25, 0};
2017 enum clnt_stat rpc_stat
;
2018 rpcvers_t outvers
= 0;
2019 rpcvers_t vers_to_try
;
2021 static int printed
= 0;
2022 int count
, i
, *auths
;
2026 case 2: /* version 2 specified try that only */
2027 vers_to_try
= MOUNTVERS_POSIX
;
2028 vers_min
= MOUNTVERS
;
2030 case 3: /* version 3 specified try that only */
2031 vers_to_try
= MOUNTVERS3
;
2032 vers_min
= MOUNTVERS3
;
2034 case 4: /* version 4 specified try that only */
2036 * This assignment is in the wrong version sequence.
2037 * The above are MOUNT program and this is NFS
2038 * program. However, it happens to work out since the
2039 * two don't collide for NFSv4.
2041 vers_to_try
= NFS_V4
;
2044 default: /* no version specified, start with default */
2046 * If the retry version is set, use that. This will
2047 * be set if the last mount attempt returned any other
2048 * besides an RPC error.
2051 vers_to_try
= nfsretry_vers
;
2053 vers_to_try
= vers_max_default
;
2054 vers_min
= vers_min_default
;
2061 * In the case of version 4, just NULL proc the server since
2062 * there is no MOUNT program. If this fails, then decrease
2063 * vers_to_try and continue on with regular MOUNT program
2066 if (vers_to_try
== NFS_V4
) {
2067 int savevers
= nfsvers_to_use
;
2070 SET_ERR_RET(&error
, ERR_PROTO_NONE
, 0);
2072 /* Let's hope for the best */
2073 nfsvers_to_use
= NFS_V4
;
2074 retval
= getaddr_nfs(args
, fshost
, nconfp
, FALSE
,
2075 fspath
, port
, &error
, vers_min
== NFS_V4
);
2077 if (retval
== RET_OK
) {
2078 *versp
= nfsvers_to_use
= NFS_V4
;
2079 fstype
= MNTTYPE_NFS4
;
2080 args
->fh
= strdup(fspath
);
2081 if (args
->fh
== NULL
) {
2082 pr_err(gettext("no memory\n"));
2083 *versp
= nfsvers_to_use
= savevers
;
2088 nfsvers_to_use
= savevers
;
2091 /* If no more versions to try, let the user know. */
2092 if (vers_to_try
< vers_min
)
2096 * If we are here, there are more versions to try but
2097 * there has been an error of some sort. If it is not
2098 * an RPC error (e.g. host unknown), we just stop and
2099 * return the error since the other versions would see
2100 * the same error as well.
2102 if (retval
== RET_ERR
&& error
.error_type
!= ERR_RPCERROR
)
2106 while ((cl
= clnt_create_vers(fshost
, MOUNTPROG
, &outvers
,
2107 vers_min
, vers_to_try
, "datagram_v")) == NULL
) {
2108 if (rpc_createerr
.cf_stat
== RPC_UNKNOWNHOST
) {
2109 pr_err(gettext("%s: %s\n"), fshost
,
2110 clnt_spcreateerror(""));
2115 * We don't want to downgrade version on lost packets
2117 if ((rpc_createerr
.cf_stat
== RPC_TIMEDOUT
) ||
2118 (rpc_createerr
.cf_stat
== RPC_PMAPFAILURE
)) {
2119 pr_err(gettext("%s: %s\n"), fshost
,
2120 clnt_spcreateerror(""));
2125 * back off and try the previous version - patch to the
2126 * problem of version numbers not being contigous and
2127 * clnt_create_vers failing (SunOS4.1 clients & SGI servers)
2128 * The problem happens with most non-Sun servers who
2129 * don't support mountd protocol #2. So, in case the
2130 * call fails, we re-try the call anyway.
2133 if (vers_to_try
< vers_min
) {
2134 if (rpc_createerr
.cf_stat
== RPC_PROGVERSMISMATCH
) {
2137 "%s:%s: no applicable versions of NFS supported\n"),
2141 "%s:%s: NFS Version %d not supported\n"),
2142 fshost
, fspath
, nfsvers
);
2147 pr_err(gettext("%s: %s\n"), fshost
,
2148 clnt_spcreateerror(""));
2154 if (posix
&& outvers
< MOUNTVERS_POSIX
) {
2155 pr_err(gettext("%s: %s: no pathconf info\n"),
2156 fshost
, clnt_sperror(cl
, ""));
2161 if (__clnt_bindresvport(cl
) < 0) {
2162 pr_err(gettext("Couldn't bind to reserved port\n"));
2167 if ((cl
->cl_auth
= authsys_create_default()) == NULL
) {
2169 gettext("Couldn't create default authentication handle\n"));
2176 case MOUNTVERS_POSIX
:
2177 *versp
= nfsvers_to_use
= NFS_VERSION
;
2178 rpc_stat
= clnt_call(cl
, MOUNTPROC_MNT
, xdr_dirpath
,
2179 (caddr_t
)&fspath
, xdr_fhstatus
, (caddr_t
)&fhs
, timeout
);
2180 if (rpc_stat
!= RPC_SUCCESS
) {
2181 pr_err(gettext("%s:%s: server not responding %s\n"),
2182 fshost
, fspath
, clnt_sperror(cl
, ""));
2187 if ((errno
= fhs
.fhs_status
) != MNT_OK
) {
2188 if (loud_on_mnt_err
) {
2189 if (errno
== EACCES
) {
2191 "%s:%s: access denied\n"),
2194 pr_err(gettext("%s:%s: %s\n"), fshost
,
2195 fspath
, errno
>= 0 ?
2196 strerror(errno
) : "invalid error "
2197 "returned by server");
2201 return (RET_MNTERR
);
2203 args
->fh
= malloc(sizeof (fhs
.fhstatus_u
.fhs_fhandle
));
2204 if (args
->fh
== NULL
) {
2205 pr_err(gettext("no memory\n"));
2208 memcpy((caddr_t
)args
->fh
, (caddr_t
)&fhs
.fhstatus_u
.fhs_fhandle
,
2209 sizeof (fhs
.fhstatus_u
.fhs_fhandle
));
2210 if (!errno
&& posix
) {
2211 rpc_stat
= clnt_call(cl
, MOUNTPROC_PATHCONF
,
2212 xdr_dirpath
, (caddr_t
)&fspath
, xdr_ppathcnf
,
2213 (caddr_t
)&p
, timeout
);
2214 if (rpc_stat
!= RPC_SUCCESS
) {
2216 "%s:%s: server not responding %s\n"),
2217 fshost
, fspath
, clnt_sperror(cl
, ""));
2222 if (_PC_ISSET(_PC_ERROR
, p
.pc_mask
)) {
2224 "%s:%s: no pathconf info\n"),
2230 args
->flags
|= NFSMNT_POSIX
;
2231 args
->pathconf
= malloc(sizeof (p
));
2232 if (args
->pathconf
== NULL
) {
2233 pr_err(gettext("no memory\n"));
2238 memcpy((caddr_t
)args
->pathconf
, (caddr_t
)&p
,
2244 *versp
= nfsvers_to_use
= NFS_V3
;
2245 rpc_stat
= clnt_call(cl
, MOUNTPROC_MNT
, xdr_dirpath
,
2246 (caddr_t
)&fspath
, xdr_mountres3
, (caddr_t
)&mountres3
,
2248 if (rpc_stat
!= RPC_SUCCESS
) {
2249 pr_err(gettext("%s:%s: server not responding %s\n"),
2250 fshost
, fspath
, clnt_sperror(cl
, ""));
2256 * Assume here that most of the MNT3ERR_*
2257 * codes map into E* errors.
2259 if ((errno
= mountres3
.fhs_status
) != MNT_OK
) {
2260 if (loud_on_mnt_err
) {
2262 case MNT3ERR_NAMETOOLONG
:
2263 msg
= "path name is too long";
2265 case MNT3ERR_NOTSUPP
:
2266 msg
= "operation not supported";
2268 case MNT3ERR_SERVERFAULT
:
2269 msg
= "server fault";
2273 msg
= strerror(errno
);
2275 msg
= "invalid error returned "
2279 pr_err(gettext("%s:%s: %s\n"), fshost
,
2283 return (RET_MNTERR
);
2286 fh3p
= (nfs_fh3
*)malloc(sizeof (*fh3p
));
2288 pr_err(gettext("no memory\n"));
2292 mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_len
;
2293 (void) memcpy(fh3p
->fh3_u
.data
,
2294 mountres3
.mountres3_u
.mountinfo
.fhandle
.fhandle3_val
,
2296 args
->fh
= (caddr_t
)fh3p
;
2297 fstype
= MNTTYPE_NFS3
;
2300 * Check the security flavor to be used.
2302 * If "secure" or "sec=flavor" is a mount
2303 * option, check if the server supports the "flavor".
2304 * If the server does not support the flavor, return
2307 * If no mount option is given then look for default auth
2308 * (default auth entry in /etc/nfssec.conf) in the auth list
2309 * returned from server. If default auth not found, then use
2310 * the first supported security flavor (by the client) in the
2311 * auth list returned from the server.
2315 mountres3
.mountres3_u
.mountinfo
.auth_flavors
2318 mountres3
.mountres3_u
.mountinfo
.auth_flavors
2323 "server %s did not return any security mode\n"),
2330 for (i
= 0; i
< count
; i
++) {
2331 if (auths
[i
] == nfs_sec
.sc_nfsnum
)
2337 seconfig_t default_sec
;
2340 * Get client configured default auth.
2342 nfs_sec
.sc_nfsnum
= -1;
2343 default_sec
.sc_nfsnum
= -1;
2344 (void) nfs_getseconfig_default(&default_sec
);
2347 * Look for clients default auth in servers list.
2349 if (default_sec
.sc_nfsnum
!= -1) {
2350 for (i
= 0; i
< count
; i
++) {
2351 if (auths
[i
] == default_sec
.sc_nfsnum
) {
2353 nfs_sec
= default_sec
;
2360 * Could not find clients default auth in servers list.
2361 * Pick the first auth from servers list that is
2362 * also supported on the client.
2364 if (nfs_sec
.sc_nfsnum
== -1) {
2365 for (i
= 0; i
< count
; i
++) {
2366 if (!nfs_getseconfig_bynumber(auths
[i
],
2380 pr_err(gettext("%s:%s: Unknown MOUNT version %d\n"),
2381 fshost
, fspath
, outvers
);
2391 "security mode does not match the server exporting %s:%s\n"),
2398 * Fill in the address for the server's NFS service and
2399 * fill in a knetconfig structure for the transport that
2400 * the service is available on.
2403 getaddr_nfs(struct nfs_args
*args
, char *fshost
, struct netconfig
**nconfp
,
2404 bool_t get_pubfh
, char *fspath
, ushort_t port
, err_ret_t
*error
,
2405 bool_t print_rpcerror
)
2408 struct netconfig
*nconf
;
2409 struct knetconfig
*knconfp
;
2410 static int printed
= 0;
2411 struct t_info tinfo
;
2412 err_ret_t addr_error
;
2414 SET_ERR_RET(error
, ERR_PROTO_NONE
, 0);
2415 SET_ERR_RET(&addr_error
, ERR_PROTO_NONE
, 0);
2419 * If a proto is specified and its rdma try this. The kernel
2420 * will later do the reachablity test and fail form there
2421 * if rdma transport is not available to kernel rpc
2423 if (strcmp(nfs_proto
, "rdma") == 0) {
2424 args
->addr
= get_addr(fshost
, NFS_PROGRAM
,
2425 nfsvers_to_use
, nconfp
, NULL
, port
, &tinfo
,
2426 &args
->fh
, get_pubfh
, fspath
, &addr_error
);
2428 args
->flags
|= NFSMNT_DORDMA
;
2430 args
->addr
= get_addr(fshost
, NFS_PROGRAM
,
2431 nfsvers_to_use
, nconfp
, nfs_proto
, port
, &tinfo
,
2432 &args
->fh
, get_pubfh
, fspath
, &addr_error
);
2435 args
->addr
= get_addr(fshost
, NFS_PROGRAM
, nfsvers_to_use
,
2436 nconfp
, nfs_proto
, port
, &tinfo
, &args
->fh
, get_pubfh
,
2437 fspath
, &addr_error
);
2439 * If no proto is specified set this flag.
2440 * Kernel mount code will try to use RDMA if its on the
2441 * system, otherwise it will keep on using the protocol
2442 * selected here, through the above get_addr call.
2444 if (nfs_proto
== NULL
)
2445 args
->flags
|= NFSMNT_TRYRDMA
;
2448 if (args
->addr
== NULL
) {
2450 * We could have failed because the server had no public
2451 * file handle support. So don't print a message and don't
2454 if (get_pubfh
== TRUE
)
2458 switch (addr_error
.error_type
) {
2463 if (!print_rpcerror
)
2464 /* no error print at this time */
2466 pr_err(gettext("%s NFS service not"
2467 " available %s\n"), fshost
,
2468 clnt_sperrno(addr_error
.error_value
));
2472 pr_err(gettext("%s: Error in NETPATH.\n"),
2476 case ERR_PROTO_INVALID
:
2477 pr_err(gettext("%s: NFS service does not"
2478 " recognize protocol: %s.\n"), fshost
,
2482 case ERR_PROTO_UNSUPP
:
2483 if (nfsvers
|| nfsvers_to_use
== NFS_VERSMIN
) {
2485 * Don't set "printed" here. Since we
2486 * have to keep checking here till we
2487 * exhaust transport errors on all vers.
2489 * Print this message if:
2490 * 1. After we have tried all versions
2491 * of NFS and none support the asked
2494 * 2. If a version is specified and it
2495 * does'nt support the asked
2498 * Otherwise we decrement the version
2501 pr_err(gettext("%s: NFS service does"
2502 " not support protocol: %s.\n"),
2507 pr_err("%s: %s\n", fshost
, "Unknown host");
2511 /* case ERR_PROTO_NONE falls through */
2512 pr_err(gettext("%s: NFS service not responding"
2519 addr_error
.error_type
, addr_error
.error_value
);
2520 if (addr_error
.error_type
== ERR_PROTO_NONE
)
2522 else if (addr_error
.error_type
== ERR_RPCERROR
&&
2523 !IS_UNRECOVERABLE_RPC(addr_error
.error_value
)) {
2525 } else if (nfsvers
== 0 && addr_error
.error_type
==
2526 ERR_PROTO_UNSUPP
&& nfsvers_to_use
!= NFS_VERSMIN
) {
2528 * If no version is specified, and the error is due
2529 * to an unsupported transport, then decrement the
2530 * version and retry.
2538 if (stat(nconf
->nc_device
, &sb
) < 0) {
2539 pr_err(gettext("getaddr_nfs: couldn't stat: %s: %s\n"),
2540 nconf
->nc_device
, strerror(errno
));
2544 knconfp
= (struct knetconfig
*)malloc(sizeof (*knconfp
));
2546 pr_err(gettext("no memory\n"));
2549 knconfp
->knc_semantics
= nconf
->nc_semantics
;
2550 knconfp
->knc_protofmly
= nconf
->nc_protofmly
;
2551 knconfp
->knc_proto
= nconf
->nc_proto
;
2552 knconfp
->knc_rdev
= sb
.st_rdev
;
2554 /* make sure we don't overload the transport */
2555 if (tinfo
.tsdu
> 0 && tinfo
.tsdu
< NFS_MAXDATA
+ NFS_RPC_HDR
) {
2556 args
->flags
|= (NFSMNT_RSIZE
| NFSMNT_WSIZE
);
2557 if (args
->rsize
== 0 || args
->rsize
> tinfo
.tsdu
- NFS_RPC_HDR
)
2558 args
->rsize
= tinfo
.tsdu
- NFS_RPC_HDR
;
2559 if (args
->wsize
== 0 || args
->wsize
> tinfo
.tsdu
- NFS_RPC_HDR
)
2560 args
->wsize
= tinfo
.tsdu
- NFS_RPC_HDR
;
2563 args
->flags
|= NFSMNT_KNCONF
;
2564 args
->knconf
= knconfp
;
2569 retry(struct mnttab
*mntp
, int ro
)
2572 int count
= retries
;
2576 * Please see comments on nfsretry_vers in the beginning of this file
2577 * and in main() routine.
2584 pr_err(gettext("backgrounding: %s\n"), mntp
->mnt_mountp
);
2587 pr_err(gettext("retrying: %s\n"), mntp
->mnt_mountp
);
2591 if ((r
= mount_nfs(mntp
, ro
, NULL
)) == RET_OK
) {
2592 pr_err(gettext("%s: mounted OK\n"), mntp
->mnt_mountp
);
2599 (void) sleep(delay
);
2607 pr_err(gettext("giving up on: %s\n"), mntp
->mnt_mountp
);
2613 * Read the NFS SMF Parameters to determine if the
2614 * client has been configured for a new min/max for the NFS version to
2622 int tmp
= 0, bufsz
= 0, ret
= 0;
2624 /* Maximum number of bytes expected. */
2626 ret
= nfs_smf_get_prop("client_versmin", value
, DEFAULT_INSTANCE
,
2627 SCF_TYPE_INTEGER
, SVC_NFS_CLIENT
, &bufsz
);
2630 tmp
= strtol(value
, (char **)NULL
, 10);
2632 vers_min_default
= tmp
;
2636 /* Maximum number of bytes expected. */
2638 ret
= nfs_smf_get_prop("client_versmax", value
, DEFAULT_INSTANCE
,
2639 SCF_TYPE_INTEGER
, SVC_NFS_CLIENT
, &bufsz
);
2642 tmp
= strtol(value
, (char **)NULL
, 10);
2644 vers_max_default
= tmp
;