dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / fs.d / nfs / mount / mount.c
blobb07b97d1cb0c8356e9e7ec05774464493c127290
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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
32 * All Rights Reserved
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
40 * nfs mount
43 #define NFSCLIENT
44 #include <locale.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <memory.h>
48 #include <stdarg.h>
49 #include <unistd.h>
50 #include <ctype.h>
51 #include <stdlib.h>
52 #include <signal.h>
53 #include <sys/param.h>
54 #include <rpc/rpc.h>
55 #include <errno.h>
56 #include <sys/stat.h>
57 #include <netdb.h>
58 #include <sys/mount.h>
59 #include <sys/mntent.h>
60 #include <sys/mnttab.h>
61 #include <nfs/nfs.h>
62 #include <nfs/mount.h>
63 #include <rpcsvc/mount.h>
64 #include <sys/pathconf.h>
65 #include <netdir.h>
66 #include <netconfig.h>
67 #include <sys/sockio.h>
68 #include <net/if.h>
69 #include <syslog.h>
70 #include <fslib.h>
71 #include <deflt.h>
72 #include <sys/wait.h>
73 #include "replica.h"
74 #include <netinet/in.h>
75 #include <nfs/nfs_sec.h>
76 #include <rpcsvc/daemon_utils.h>
77 #include <priv.h>
78 #include "nfs_subr.h"
79 #include "webnfs.h"
80 #include <rpcsvc/nfs4_prot.h>
81 #include <limits.h>
82 #include <libscf.h>
83 #include <libshare.h>
84 #include "smfcfg.h"
86 #include <nfs/nfssys.h>
87 extern int _nfssys(enum nfssys_op, void *);
89 #ifndef NFS_VERSMAX
90 #define NFS_VERSMAX 4
91 #endif
92 #ifndef NFS_VERSMIN
93 #define NFS_VERSMIN 2
94 #endif
96 #define RET_OK 0
97 #define RET_RETRY 32
98 #define RET_ERR 33
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 {
108 int error_type;
109 int error_value;
110 } err_ret_t;
112 #define SET_ERR_RET(errst, etype, eval) \
113 if (errst) { \
114 (errst)->error_type = etype; \
115 (errst)->error_value = eval; \
118 /* number of transports to try */
119 #define MNT_PREF_LISTLEN 2
120 #define FIRST_TRY 1
121 #define SECOND_TRY 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 *,
145 bool_t, rpcvers_t);
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];
165 static int bg = 0;
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;
172 static int mflg = 0;
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
209 * non-RPC errors.
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[])
232 struct mnttab mnt;
233 extern char *optarg;
234 extern int optind;
235 char optbuf[MAX_MNTOPT_STR];
236 int ro = 0;
237 int r;
238 int c;
239 char *myname;
240 err_ret_t retry_error;
242 (void) setlocale(LC_ALL, "");
243 #if !defined(TEXT_DOMAIN)
244 #define TEXT_DOMAIN "SYS_TEST"
245 #endif
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);
252 argv[0] = typename;
254 mnt.mnt_mntopts = optbuf;
255 (void) strcpy(optbuf, "rw");
258 * Set options
260 while ((c = getopt(argc, argv, "ro:mOq")) != EOF) {
261 switch (c) {
262 case 'r':
263 ro++;
264 break;
265 case 'o':
266 if (strlen(optarg) >= MAX_MNTOPT_STR) {
267 pr_err(gettext("option string too long"));
268 return (RET_ERR);
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"));
280 exit(RET_ERR);
283 #endif /* LATER */ /* XXX */
284 break;
285 case 'm':
286 mflg++;
287 break;
288 case 'O':
289 Oflg++;
290 break;
291 case 'q':
292 qflg++;
293 break;
294 default:
295 usage();
296 exit(RET_ERR);
299 if (argc - optind != 2) {
300 usage();
301 exit(RET_ERR);
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"));
310 exit(RET_ERR);
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.
319 read_default();
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
338 * error.
340 if (retry_error.error_type) {
341 if (retry_error.error_type != ERR_RPCERROR) {
342 nfsretry_vers = nfsvers_to_use =
343 nfsvers_to_use - 1;
344 if (nfsretry_vers < NFS_VERSMIN)
345 return (r);
349 r = retry(&mnt, ro);
352 * exit(r);
354 return (r);
357 static void
358 pr_err(const char *fmt, ...)
360 va_list ap;
362 va_start(ap, fmt);
363 if (backgrounded != 0) {
364 (void) vsyslog(LOG_ERR, fmt, ap);
365 } else {
366 (void) fprintf(stderr, "%s: ", typename);
367 (void) vfprintf(stderr, fmt, ap);
368 (void) fflush(stderr);
370 va_end(ap);
373 static void
374 usage()
376 (void) fprintf(stderr,
377 gettext("Usage: nfs mount [-r] [-o opts] [server:]path dir\n"));
378 exit(RET_ERR);
381 static int
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;
387 int mntflags = 0;
388 int i, r, n;
389 int oldvers = 0, vers = 0;
390 int last_error = RET_OK;
391 int replicated = 0;
392 char *p;
393 bool_t url;
394 bool_t use_pubfh;
395 char *special = NULL;
396 char *oldpath = NULL;
397 char *newpath = NULL;
398 char *service;
399 pid_t pi;
400 struct flock f;
401 char *saveopts = NULL;
402 char **sl = NULL;
404 mntp->mnt_fstype = MNTTYPE_NFS;
406 if (ro) {
407 mntflags |= MS_RDONLY;
408 /* convert "rw"->"ro" */
409 if (p = strstr(mntp->mnt_mntopts, "rw")) {
410 if (*(p+2) == ',' || *(p+2) == '\0')
411 *(p+1) = 'o';
415 if (Oflg)
416 mntflags |= MS_OVERLAY;
418 list = parse_replica(mntp->mnt_special, &n);
419 if (list == NULL) {
420 if (n < 0)
421 pr_err(gettext("nfs file system; use [host:]path\n"));
422 else
423 pr_err(gettext("no memory\n"));
424 return (RET_ERR);
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++) {
434 char *path;
435 char *host;
436 ushort_t port;
438 argp = (struct nfs_args *)malloc(sizeof (*argp));
439 if (argp == NULL) {
440 pr_err(gettext("no memory\n"));
441 last_error = RET_ERR;
442 goto out;
444 memset(argp, 0, sizeof (*argp));
446 memset(&nfs_sec, 0, sizeof (nfs_sec));
447 sec_opt = 0;
448 use_pubfh = FALSE;
449 url = FALSE;
450 port = 0;
451 snego_done = FALSE;
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,
458 "//", 2) == 0) {
459 char *sport, *cb;
460 url = TRUE;
461 oldpath = strdup(list[i].path);
462 if (oldpath == NULL) {
463 pr_err(gettext("memory allocation failure\n"));
464 last_error = RET_ERR;
465 goto out;
467 host = list[i].path+2;
468 path = strchr(host, '/');
470 if (path == NULL) {
471 pr_err(gettext(
472 "illegal nfs url syntax\n"));
473 last_error = RET_ERR;
474 goto out;
477 *path = '\0';
478 if (*host == '[') {
479 cb = strchr(host, ']');
480 if (cb == NULL) {
481 pr_err(gettext(
482 "illegal nfs url syntax\n"));
483 last_error = RET_ERR;
484 goto out;
485 } else {
486 *cb = '\0';
487 host++;
488 cb++;
489 if (*cb == ':')
490 port = htons((ushort_t)
491 atoi(cb+1));
493 } else {
494 sport = strchr(host, ':');
496 if (sport != NULL && sport < path) {
497 *sport = '\0';
498 port = htons((ushort_t)atoi(sport+1));
502 path++;
503 if (*path == '\0')
504 path = ".";
506 } else {
507 host = list[i].host;
508 path = list[i].path;
511 if (r = set_args(&mntflags, argp, host, mntp)) {
512 last_error = r;
513 goto out;
516 if (public_opt == TRUE)
517 use_pubfh = TRUE;
519 if (port == 0) {
520 port = nfs_port;
521 } else if (nfs_port != 0 && nfs_port != port) {
522 pr_err(gettext(
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;
528 goto out;
532 if (replicated && !(mntflags & MS_RDONLY)) {
533 pr_err(gettext(
534 "replicated mounts must be read-only\n"));
535 last_error = RET_ERR;
536 goto out;
539 if (replicated && (argp->flags & NFSMNT_SOFT)) {
540 pr_err(gettext(
541 "replicated mounts must not be soft\n"));
542 last_error = RET_ERR;
543 goto out;
546 oldvers = vers;
547 nconf = NULL;
549 r = 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);
559 if (r != RET_OK) {
561 * If -o public was specified, then return the
562 * error now.
564 if (use_pubfh == TRUE) {
565 last_error = r;
566 goto out;
568 } else
569 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.
581 if (url) {
582 URLparse(path);
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
589 * fail.
591 if (url == TRUE && *path != '/')
592 loud_on_mnt_err = FALSE;
593 else
594 loud_on_mnt_err = TRUE;
596 r = get_fh(argp, host, path, &vers,
597 loud_on_mnt_err, &nconf, port);
599 if (r != RET_OK) {
602 * If there was no leading / and the path was
603 * derived from a URL, then try again
604 * with a leading /.
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;
615 goto out;
618 strcpy(newpath, "/");
619 strcat(newpath, path);
621 r = get_fh(argp, host, newpath, &vers,
622 TRUE, &nconf, port);
624 if (r == RET_OK)
625 path = newpath;
629 * map exit code back to RET_ERR.
631 if (r == RET_MNTERR)
632 r = RET_ERR;
634 if (r != RET_OK) {
636 if (replicated) {
637 free(argp->fh);
638 free(argp->pathconf);
639 free(argp);
640 goto cont;
643 last_error = r;
644 goto out;
649 if (oldvers && vers != oldvers) {
650 pr_err(
651 gettext("replicas must have the same version\n"));
652 last_error = RET_ERR;
653 goto out;
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:"),
664 host, path);
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)) {
680 nconf = NULL;
681 if (r = getaddr_nfs(argp, host, &nconf,
682 FALSE, path, port, retry_error,
683 TRUE)) {
684 last_error = r;
685 goto out;
690 if (make_secure(argp, host, nconf, use_pubfh, vers) < 0) {
691 last_error = RET_ERR;
692 goto out;
695 if ((url == TRUE) && (use_pubfh == FALSE)) {
697 * Convert the special from
698 * nfs://host/path
699 * to
700 * host:path
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;
708 goto out;
709 } else {
710 mntp->mnt_special = special;
714 if (prev_argp == NULL)
715 args = argp;
716 else
717 prev_argp->nfs_ext_u.nfs_extB.next = argp;
718 prev_argp = argp;
720 cont:
721 if (oldpath != NULL) {
722 free(oldpath);
723 oldpath = NULL;
726 if (newpath != NULL) {
727 free(newpath);
728 newpath = NULL;
732 argp = NULL;
734 if (args == NULL) {
735 last_error = RET_RETRY;
736 goto out;
739 /* Determine which services are appropriate for the NFS version */
740 if (strcmp(fstype, MNTTYPE_NFS4) == 0)
741 sl = service_list_v4;
742 else
743 sl = service_list;
746 * enable services as needed.
748 _check_services(sl);
750 mntflags |= MS_DATA | MS_OPTIONSTR;
752 if (mflg)
753 mntflags |= MS_NOMNTTAB;
755 if (!qflg)
756 saveopts = strdup(mntp->mnt_mntopts);
759 * And make sure that we have the ephemeral mount_to
760 * set for this zone.
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));
769 } else {
770 struct stat sb;
771 if (stat(mntp->mnt_mountp, &sb) < 0 && errno == ENOENT)
772 pr_err(gettext("mount: %s: %s\n"),
773 mntp->mnt_mountp, strerror(ENOENT));
774 else
775 pr_err("%s: %s\n", mntp->mnt_special,
776 strerror(ENOENT));
779 last_error = RET_ERR;
780 goto out;
783 if (!qflg && saveopts != NULL) {
784 cmp_requested_to_actual_options(saveopts, mntp->mnt_mntopts,
785 mntp->mnt_special, mntp->mnt_mountp);
788 out:
789 free(saveopts);
790 free(special);
791 free(oldpath);
792 free(newpath);
794 free_replica(list, n);
796 if (argp != NULL) {
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)
802 args = argp;
803 else
804 prev_argp->nfs_ext_u.nfs_extB.next = argp;
806 argp = args;
807 while (argp != NULL) {
808 free(argp->fh);
809 free(argp->pathconf);
810 free(argp->knconf);
811 if (argp->addr) {
812 free(argp->addr->buf);
813 free(argp->addr);
815 nfs_free_secdata(argp->nfs_ext_u.nfs_extB.secdata);
816 if (argp->syncaddr) {
817 free(argp->syncaddr->buf);
818 free(argp->syncaddr);
820 free(argp->netname);
821 prev_argp = argp;
822 argp = argp->nfs_ext_u.nfs_extB.next;
823 free(prev_argp);
826 return (last_error);
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[] = {
834 #define OPT_RO 0
835 MNTOPT_RO,
836 #define OPT_RW 1
837 MNTOPT_RW,
838 #define OPT_QUOTA 2
839 MNTOPT_QUOTA,
840 #define OPT_NOQUOTA 3
841 MNTOPT_NOQUOTA,
842 #define OPT_SOFT 4
843 MNTOPT_SOFT,
844 #define OPT_HARD 5
845 MNTOPT_HARD,
846 #define OPT_SUID 6
847 MNTOPT_SUID,
848 #define OPT_NOSUID 7
849 MNTOPT_NOSUID,
850 #define OPT_GRPID 8
851 MNTOPT_GRPID,
852 #define OPT_REMOUNT 9
853 MNTOPT_REMOUNT,
854 #define OPT_NOSUB 10
855 MNTOPT_NOSUB,
856 #define OPT_INTR 11
857 MNTOPT_INTR,
858 #define OPT_NOINTR 12
859 MNTOPT_NOINTR,
860 #define OPT_PORT 13
861 MNTOPT_PORT,
862 #define OPT_SECURE 14
863 MNTOPT_SECURE,
864 #define OPT_RSIZE 15
865 MNTOPT_RSIZE,
866 #define OPT_WSIZE 16
867 MNTOPT_WSIZE,
868 #define OPT_TIMEO 17
869 MNTOPT_TIMEO,
870 #define OPT_RETRANS 18
871 MNTOPT_RETRANS,
872 #define OPT_ACTIMEO 19
873 MNTOPT_ACTIMEO,
874 #define OPT_ACREGMIN 20
875 MNTOPT_ACREGMIN,
876 #define OPT_ACREGMAX 21
877 MNTOPT_ACREGMAX,
878 #define OPT_ACDIRMIN 22
879 MNTOPT_ACDIRMIN,
880 #define OPT_ACDIRMAX 23
881 MNTOPT_ACDIRMAX,
882 #define OPT_BG 24
883 MNTOPT_BG,
884 #define OPT_FG 25
885 MNTOPT_FG,
886 #define OPT_RETRY 26
887 MNTOPT_RETRY,
888 #define OPT_NOAC 27
889 MNTOPT_NOAC,
890 #define OPT_NOCTO 28
891 MNTOPT_NOCTO,
892 #define OPT_LLOCK 29
893 MNTOPT_LLOCK,
894 #define OPT_POSIX 30
895 MNTOPT_POSIX,
896 #define OPT_VERS 31
897 MNTOPT_VERS,
898 #define OPT_PROTO 32
899 MNTOPT_PROTO,
900 #define OPT_SEMISOFT 33
901 MNTOPT_SEMISOFT,
902 #define OPT_NOPRINT 34
903 MNTOPT_NOPRINT,
904 #define OPT_SEC 35
905 MNTOPT_SEC,
906 #define OPT_LARGEFILES 36
907 MNTOPT_LARGEFILES,
908 #define OPT_NOLARGEFILES 37
909 MNTOPT_NOLARGEFILES,
910 #define OPT_PUBLIC 38
911 MNTOPT_PUBLIC,
912 #define OPT_DIRECTIO 39
913 MNTOPT_FORCEDIRECTIO,
914 #define OPT_NODIRECTIO 40
915 MNTOPT_NOFORCEDIRECTIO,
916 #define OPT_XATTR 41
917 MNTOPT_XATTR,
918 #define OPT_NOXATTR 42
919 MNTOPT_NOXATTR,
920 #define OPT_DEVICES 43
921 MNTOPT_DEVICES,
922 #define OPT_NODEVICES 44
923 MNTOPT_NODEVICES,
924 #define OPT_SETUID 45
925 MNTOPT_SETUID,
926 #define OPT_NOSETUID 46
927 MNTOPT_NOSETUID,
928 #define OPT_EXEC 47
929 MNTOPT_EXEC,
930 #define OPT_NOEXEC 48
931 MNTOPT_NOEXEC,
932 NULL
935 static int
936 convert_int(int *val, char *str)
938 long lval;
940 if (str == NULL || !isdigit(*str))
941 return (-1);
943 lval = strtol(str, &str, 10);
944 if (*str != '\0' || lval > INT_MAX)
945 return (-2);
947 *val = (int)lval;
948 return (0);
951 static int
952 set_args(int *mntflags, struct nfs_args *args, char *fshost, struct mnttab *mnt)
954 char *saveopt, *optstr, *opts, *newopts, *val;
955 int num;
956 int largefiles = 0;
957 int invalid = 0;
958 int attrpref = 0;
959 int optlen;
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"));
971 return (RET_ERR);
973 newopts = malloc(optlen);
974 if (opts == NULL || newopts == NULL) {
975 pr_err(gettext("no memory"));
976 free(opts);
977 free(newopts);
978 return (RET_ERR);
980 newopts[0] = '\0';
982 while (*opts) {
983 invalid = 0;
984 saveopt = opts;
985 switch (getsubopt(&opts, optlist, &val)) {
986 case OPT_RO:
987 *mntflags |= MS_RDONLY;
988 break;
989 case OPT_RW:
990 *mntflags &= ~(MS_RDONLY);
991 break;
992 case OPT_QUOTA:
993 case OPT_NOQUOTA:
994 break;
995 case OPT_SOFT:
996 args->flags |= NFSMNT_SOFT;
997 args->flags &= ~(NFSMNT_SEMISOFT);
998 break;
999 case OPT_SEMISOFT:
1000 args->flags |= NFSMNT_SOFT;
1001 args->flags |= NFSMNT_SEMISOFT;
1002 break;
1003 case OPT_HARD:
1004 args->flags &= ~(NFSMNT_SOFT);
1005 args->flags &= ~(NFSMNT_SEMISOFT);
1006 break;
1007 case OPT_SUID:
1008 *mntflags &= ~(MS_NOSUID);
1009 break;
1010 case OPT_NOSUID:
1011 *mntflags |= MS_NOSUID;
1012 break;
1013 case OPT_GRPID:
1014 args->flags |= NFSMNT_GRPID;
1015 break;
1016 case OPT_REMOUNT:
1017 *mntflags |= MS_REMOUNT;
1018 break;
1019 case OPT_INTR:
1020 args->flags |= NFSMNT_INT;
1021 break;
1022 case OPT_NOINTR:
1023 args->flags &= ~(NFSMNT_INT);
1024 break;
1025 case OPT_NOAC:
1026 args->flags |= NFSMNT_NOAC;
1027 break;
1028 case OPT_PORT:
1029 if (convert_int(&num, val) != 0)
1030 goto badopt;
1031 nfs_port = htons((ushort_t)num);
1032 break;
1034 case OPT_SECURE:
1035 if (nfs_getseconfig_byname("dh", &nfs_sec)) {
1036 pr_err(gettext("can not get \"dh\" from %s\n"),
1037 NFSSEC_CONF);
1038 goto badopt;
1040 sec_opt++;
1041 break;
1043 case OPT_NOCTO:
1044 args->flags |= NFSMNT_NOCTO;
1045 break;
1047 case OPT_RSIZE:
1048 if (convert_int(&args->rsize, val) != 0)
1049 goto badopt;
1050 args->flags |= NFSMNT_RSIZE;
1051 break;
1052 case OPT_WSIZE:
1053 if (convert_int(&args->wsize, val) != 0)
1054 goto badopt;
1055 args->flags |= NFSMNT_WSIZE;
1056 break;
1057 case OPT_TIMEO:
1058 if (convert_int(&args->timeo, val) != 0)
1059 goto badopt;
1060 args->flags |= NFSMNT_TIMEO;
1061 break;
1062 case OPT_RETRANS:
1063 if (convert_int(&args->retrans, val) != 0)
1064 goto badopt;
1065 args->flags |= NFSMNT_RETRANS;
1066 break;
1067 case OPT_ACTIMEO:
1068 if (convert_int(&args->acregmax, val) != 0)
1069 goto badopt;
1070 args->acdirmin = args->acregmin = args->acdirmax
1071 = args->acregmax;
1072 args->flags |= NFSMNT_ACDIRMAX;
1073 args->flags |= NFSMNT_ACREGMAX;
1074 args->flags |= NFSMNT_ACDIRMIN;
1075 args->flags |= NFSMNT_ACREGMIN;
1076 break;
1077 case OPT_ACREGMIN:
1078 if (convert_int(&args->acregmin, val) != 0)
1079 goto badopt;
1080 args->flags |= NFSMNT_ACREGMIN;
1081 break;
1082 case OPT_ACREGMAX:
1083 if (convert_int(&args->acregmax, val) != 0)
1084 goto badopt;
1085 args->flags |= NFSMNT_ACREGMAX;
1086 break;
1087 case OPT_ACDIRMIN:
1088 if (convert_int(&args->acdirmin, val) != 0)
1089 goto badopt;
1090 args->flags |= NFSMNT_ACDIRMIN;
1091 break;
1092 case OPT_ACDIRMAX:
1093 if (convert_int(&args->acdirmax, val) != 0)
1094 goto badopt;
1095 args->flags |= NFSMNT_ACDIRMAX;
1096 break;
1097 case OPT_BG:
1098 bg++;
1099 break;
1100 case OPT_FG:
1101 bg = 0;
1102 break;
1103 case OPT_RETRY:
1104 if (convert_int(&retries, val) != 0)
1105 goto badopt;
1106 break;
1107 case OPT_LLOCK:
1108 args->flags |= NFSMNT_LLOCK;
1109 break;
1110 case OPT_POSIX:
1111 posix = 1;
1112 break;
1113 case OPT_VERS:
1114 if (convert_int(&num, val) != 0)
1115 goto badopt;
1116 nfsvers = (rpcvers_t)num;
1117 break;
1118 case OPT_PROTO:
1119 if (val == NULL)
1120 goto badopt;
1122 nfs_proto = (char *)malloc(strlen(val)+1);
1123 if (!nfs_proto) {
1124 pr_err(gettext("no memory"));
1125 return (RET_ERR);
1128 (void) strncpy(nfs_proto, val, strlen(val)+1);
1129 break;
1131 case OPT_NOPRINT:
1132 args->flags |= NFSMNT_NOPRINT;
1133 break;
1135 case OPT_LARGEFILES:
1136 largefiles = 1;
1137 break;
1139 case OPT_NOLARGEFILES:
1140 pr_err(gettext("NFS can't support \"nolargefiles\"\n"));
1141 free(optstr);
1142 return (RET_ERR);
1144 case OPT_SEC:
1145 if (val == NULL) {
1146 pr_err(gettext(
1147 "\"sec\" option requires argument\n"));
1148 return (RET_ERR);
1150 if (nfs_getseconfig_byname(val, &nfs_sec)) {
1151 pr_err(gettext("can not get \"%s\" from %s\n"),
1152 val, NFSSEC_CONF);
1153 return (RET_ERR);
1155 sec_opt++;
1156 break;
1158 case OPT_PUBLIC:
1159 public_opt = TRUE;
1160 break;
1162 case OPT_DIRECTIO:
1163 args->flags |= NFSMNT_DIRECTIO;
1164 break;
1166 case OPT_NODIRECTIO:
1167 args->flags &= ~(NFSMNT_DIRECTIO);
1168 break;
1170 case OPT_XATTR:
1171 case OPT_NOXATTR:
1173 * VFS options; just need to get them into the
1174 * new mount option string and note we've seen them
1176 attrpref = 1;
1177 break;
1178 default:
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))
1184 break;
1185 invalid = 1;
1186 if (!qflg)
1187 (void) fprintf(stderr, gettext(
1188 "mount: %s on %s - WARNING unknown option"
1189 " \"%s\"\n"), mnt->mnt_special,
1190 mnt->mnt_mountp, saveopt);
1191 break;
1193 if (!invalid) {
1194 if (newopts[0])
1195 strcat(newopts, ",");
1196 strcat(newopts, saveopt);
1199 /* Default is to turn extended attrs on */
1200 if (!attrpref) {
1201 if (newopts[0])
1202 strcat(newopts, ",");
1203 strcat(newopts, MNTOPT_XATTR);
1205 strcpy(mnt->mnt_mntopts, newopts);
1206 free(newopts);
1207 free(optstr);
1209 /* ensure that only one secure mode is requested */
1210 if (sec_opt > 1) {
1211 pr_err(gettext("Security options conflict\n"));
1212 return (RET_ERR);
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"));
1218 return (RET_ERR);
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);
1225 return (RET_ERR);
1228 return (RET_OK);
1230 badopt:
1231 pr_err(gettext("invalid option: \"%s\"\n"), saveopt);
1232 free(optstr);
1233 return (RET_ERR);
1236 static int
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;
1241 int flags;
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
1256 * security mode.
1258 if (nfs_getseconfig_default(&nfs_sec)) {
1259 pr_err(gettext("error getting default"
1260 " security entry\n"));
1261 return (-1);
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
1269 * IP time service.
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()
1278 * routine.
1280 flags = 0;
1281 syncaddr = NULL;
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;
1295 } else {
1296 struct nd_hostserv hs;
1297 int error;
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"),
1306 hostname);
1307 return (-1);
1310 if (error == ND_OK)
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
1316 * and netname data.
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);
1343 free(syncaddr);
1344 } else if (retaddrs)
1345 netdir_free((void *)retaddrs, ND_ADDRLIST);
1346 return (-1);
1349 NFS_ARGS_EXTB_secdata(args, secdata);
1350 if (flags & AUTH_F_RPCTIMESYNC) {
1351 free(syncaddr->buf);
1352 free(syncaddr);
1353 } else if (retaddrs)
1354 netdir_free((void *)retaddrs, ND_ADDRLIST);
1355 return (0);
1359 * Get the network address on "hostname" for program "prog"
1360 * with version "vers" by using the nconf configuration data
1361 * passed in.
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;
1378 CLIENT *cl = NULL;
1379 struct timeval tv;
1380 int fd = -1;
1381 AUTH *ah = NULL;
1382 AUTH *new_ah = NULL;
1383 struct snego_t snego;
1385 if (nconf == NULL)
1386 return (NULL);
1388 if ((fd = t_open(nconf->nc_device, O_RDWR, tinfo)) == -1)
1389 goto done;
1391 /* LINTED pointer alignment */
1392 if ((tbind = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR))
1393 == NULL)
1394 goto done;
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;
1403 int retval;
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);
1411 goto done;
1414 if (port == 0)
1415 hs.h_serv = "nfs";
1416 else
1417 hs.h_serv = NULL;
1419 if ((retval = netdir_getbyname(nconf, &hs, &retaddrs))
1420 != ND_OK) {
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);
1429 goto done;
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);
1437 } else {
1438 if (rpcb_getaddr(prog, vers, nconf, &tbind->addr,
1439 hostname) == FALSE) {
1440 goto done;
1444 if (port) {
1445 /* LINTED pointer alignment */
1446 if (strcmp(nconf->nc_protofmly, NC_INET) == 0)
1447 ((struct sockaddr_in *)tbind->addr.buf)->sin_port
1448 = port;
1449 else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0)
1450 ((struct sockaddr_in6 *)tbind->addr.buf)->sin6_port
1451 = port;
1455 cl = clnt_tli_create(fd, nconf, &tbind->addr, prog, vers, 0, 0);
1456 if (cl == NULL) {
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);
1467 } else {
1468 SET_ERR_RET(error, ERR_RPCERROR, rpc_createerr.cf_stat);
1470 goto done;
1473 ah = authsys_create_default();
1474 if (ah != NULL)
1475 cl->cl_auth = ah;
1477 tv.tv_sec = 5;
1478 tv.tv_usec = 0;
1480 (void) clnt_control(cl, CLSET_TIMEOUT, (char *)&tv);
1482 if ((get_pubfh == TRUE) && (vers != NFS_V4)) {
1483 enum snego_stat sec;
1485 if (!snego_done) {
1487 * negotiate sec flavor.
1489 snego.cnt = 0;
1490 if ((sec = nfs_sec_nego(vers, cl, fspath, &snego)) ==
1491 SNEGO_SUCCESS) {
1492 int jj;
1495 * check if server supports the one
1496 * specified in the sec= option.
1498 if (sec_opt) {
1499 for (jj = 0; jj < snego.cnt; jj++) {
1500 if (snego.array[jj] ==
1501 nfs_sec.sc_nfsnum) {
1502 snego_done = TRUE;
1503 break;
1509 * find a common sec flavor
1511 if (!snego_done) {
1512 if (sec_opt) {
1513 pr_err(gettext(
1514 "Server does not support"
1515 " the security flavor"
1516 " specified.\n"));
1519 for (jj = 0; jj < snego.cnt; jj++) {
1520 if (!nfs_getseconfig_bynumber(
1521 snego.array[jj],
1522 &nfs_sec)) {
1523 snego_done = TRUE;
1524 #define EMSG80SUX "Security flavor %d was negotiated and will be used.\n"
1525 if (sec_opt)
1526 pr_err(gettext(
1527 EMSG80SUX),
1528 nfs_sec.
1529 sc_nfsnum);
1530 break;
1535 if (!snego_done)
1536 return (NULL);
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);
1547 if (new_ah == NULL)
1548 goto done;
1549 cl->cl_auth = new_ah;
1550 } else if (sec == SNEGO_ARRAY_TOO_SMALL || sec ==
1551 SNEGO_FAILURE) {
1552 goto done;
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) {
1563 wnl_diropargs arg;
1564 wnl_diropres res;
1566 memset((char *)&arg.dir, 0, sizeof (wnl_fh));
1567 arg.name = fspath;
1568 memset((char *)&res, 0, sizeof (wnl_diropres));
1569 if (wnlproc_lookup_2(&arg, &res, cl) !=
1570 RPC_SUCCESS || res.status != WNL_OK)
1571 goto done;
1573 *fhp = malloc(sizeof (wnl_fh));
1575 if (*fhp == NULL) {
1576 pr_err(gettext("no memory\n"));
1577 goto done;
1580 memcpy((char *)*fhp,
1581 (char *)&res.wnl_diropres_u.wnl_diropres.file,
1582 sizeof (wnl_fh));
1583 } else {
1584 WNL_LOOKUP3args arg;
1585 WNL_LOOKUP3res res;
1586 nfs_fh3 *fh3p;
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)
1593 goto done;
1595 fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
1597 if (fh3p == NULL) {
1598 pr_err(gettext("no memory\n"));
1599 goto done;
1602 fh3p->fh3_length =
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,
1606 fh3p->fh3_length);
1608 *fhp = (caddr_t)fh3p;
1610 } else {
1611 struct rpc_err r_err;
1612 enum clnt_stat rc;
1615 * NULL procedures need not have an argument or
1616 * result param.
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);
1622 else
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) {
1629 case RPC_TLIERROR:
1630 case RPC_CANTRECV:
1631 case RPC_CANTSEND:
1632 r_err.re_status = RPC_PROGVERSMISMATCH;
1635 SET_ERR_RET(error, ERR_RPCERROR, r_err.re_status);
1636 goto done;
1641 * Make a copy of the netbuf to return
1643 nb = (struct netbuf *)malloc(sizeof (*nb));
1644 if (nb == NULL) {
1645 pr_err(gettext("no memory\n"));
1646 goto done;
1648 *nb = tbind->addr;
1649 nb->buf = (char *)malloc(nb->maxlen);
1650 if (nb->buf == NULL) {
1651 pr_err(gettext("no memory\n"));
1652 free(nb);
1653 nb = NULL;
1654 goto done;
1656 (void) memcpy(nb->buf, tbind->addr.buf, tbind->addr.len);
1658 done:
1659 if (cl) {
1660 if (ah != NULL) {
1661 if (new_ah != NULL)
1662 AUTH_DESTROY(ah);
1663 AUTH_DESTROY(cl->cl_auth);
1664 cl->cl_auth = NULL;
1666 clnt_destroy(cl);
1667 cl = NULL;
1669 if (tbind) {
1670 t_free((char *)tbind, T_BIND);
1671 tbind = NULL;
1673 if (fd >= 0)
1674 (void) t_close(fd);
1675 return (nb);
1678 static int
1679 check_nconf(struct netconfig *nconf, int nthtry, int *valid_proto)
1681 int try_test = 0;
1682 int valid_family;
1683 char *proto = NULL;
1686 if (nthtry == FIRST_TRY) {
1687 try_test = ((nconf->nc_semantics == NC_TPI_COTS_ORD) ||
1688 (nconf->nc_semantics == NC_TPI_COTS));
1689 proto = NC_TCP;
1690 } else if (nthtry == SECOND_TRY) {
1691 try_test = (nconf->nc_semantics == NC_TPI_CLTS);
1692 proto = NC_UDP;
1695 if (proto &&
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;
1700 else
1701 *valid_proto = FALSE;
1703 return (try_test);
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
1756 * all over again.
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);
1763 goto done;
1767 * If proto is specified, then only search for the match,
1768 * otherwise try COTS first, if failed, try CLTS.
1770 if (proto) {
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))
1776 continue;
1778 /* may be unsupported */
1779 SET_ERR_RET(error, ERR_PROTO_UNSUPP, 0);
1781 if ((port != 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))) {
1786 continue;
1787 } else {
1788 nb = get_the_addr(hostname, prog,
1789 vers, nconf, port, tinfo,
1790 fhp, get_pubfh, fspath, error);
1792 if (nb != NULL)
1793 break;
1795 /* nb is NULL - deal with errors */
1796 if (error) {
1797 if (error->error_type == ERR_NOHOST)
1798 SET_ERR_RET(&errsave_nohost,
1799 error->error_type,
1800 error->error_value);
1801 if (error->error_type == ERR_RPCERROR)
1802 SET_ERR_RET(&errsave_rpcerr,
1803 error->error_type,
1804 error->error_value);
1807 * continue with same protocol
1808 * selection
1810 continue;
1812 } /* end of while */
1814 if (nconf == NULL)
1815 goto done;
1817 if ((nb = get_the_addr(hostname, prog, vers, nconf, port,
1818 tinfo, fhp, get_pubfh, fspath, error)) == NULL)
1819 goto done;
1820 } else {
1821 retry:
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) {
1827 int valid_proto;
1829 if (check_nconf(nconf,
1830 nthtry, &valid_proto)) {
1831 if (port == 0)
1832 break;
1834 if (valid_proto == TRUE)
1835 break;
1838 } /* while */
1839 if (nconf == NULL) {
1840 if (++nthtry <= MNT_PREF_LISTLEN) {
1841 endnetpath(nc);
1842 if ((nc = setnetpath()) == NULL)
1843 goto done;
1844 goto retry;
1845 } else
1846 goto done;
1847 } else {
1848 if ((nb = get_the_addr(hostname, prog, vers, nconf,
1849 port, tinfo, fhp, get_pubfh, fspath, error))
1850 == NULL) {
1851 /* nb is NULL - deal with errors */
1852 if (error) {
1853 if (error->error_type == ERR_NOHOST)
1854 SET_ERR_RET(&errsave_nohost,
1855 error->error_type,
1856 error->error_value);
1857 if (error->error_type == ERR_RPCERROR)
1858 SET_ERR_RET(&errsave_rpcerr,
1859 error->error_type,
1860 error->error_value);
1863 * Continue the same search path in the
1864 * netconfig db until no more matched
1865 * nconf (nconf == NULL).
1867 goto retry;
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");
1880 free(nb);
1881 nb = NULL;
1883 done:
1884 if (nc)
1885 endnetpath(nc);
1887 if (nb == NULL) {
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);
1901 return (nb);
1905 * Get a file handle usinging multi-component lookup with the public
1906 * file handle.
1908 static int
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)
1912 uint_t vers_min;
1913 uint_t vers_max;
1914 int r;
1915 char *path;
1917 if (nfsvers != 0) {
1918 vers_max = vers_min = nfsvers;
1919 } else {
1920 vers_max = vers_max_default;
1921 vers_min = vers_min_default;
1924 if (url == FALSE) {
1925 path = malloc(strlen(fspath) + 2);
1926 if (path == NULL) {
1927 if (loud == TRUE)
1928 pr_err(gettext("no memory\n"));
1929 return (RET_ERR);
1932 path[0] = (char)WNL_NATIVEPATH;
1933 (void) strcpy(&path[1], fspath);
1935 } else {
1936 path = fspath;
1939 for (nfsvers_to_use = vers_max; nfsvers_to_use >= vers_min;
1940 nfsvers_to_use--) {
1942 * getaddr_nfs will also fill in the fh for us.
1944 r = getaddr_nfs(args, fshost, nconfp,
1945 TRUE, path, port, NULL, FALSE);
1947 if (r == RET_OK) {
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) {
1955 case NFS_V4:
1956 fstype = MNTTYPE_NFS4;
1957 break;
1958 case NFS_V3:
1959 fstype = MNTTYPE_NFS3;
1960 /* fall through to pick up llock option */
1961 default:
1962 args->flags |= NFSMNT_LLOCK;
1963 break;
1965 if (fspath != path)
1966 free(path);
1968 return (r);
1972 if (fspath != path)
1973 free(path);
1975 if (loud == TRUE) {
1976 pr_err(gettext("Could not use public filehandle in request to"
1977 " server %s\n"), fshost);
1980 return (r);
1984 * get fhandle of remote path from server's mountd
1986 static int
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;
1993 nfs_fh3 *fh3p;
1994 struct timeval timeout = { 25, 0};
1995 CLIENT *cl;
1996 enum clnt_stat rpc_stat;
1997 rpcvers_t outvers = 0;
1998 rpcvers_t vers_to_try;
1999 rpcvers_t vers_min;
2000 static int printed = 0;
2001 int count, i, *auths;
2002 char *msg;
2004 switch (nfsvers) {
2005 case 2: /* version 2 specified try that only */
2006 vers_to_try = MOUNTVERS_POSIX;
2007 vers_min = MOUNTVERS;
2008 break;
2009 case 3: /* version 3 specified try that only */
2010 vers_to_try = MOUNTVERS3;
2011 vers_min = MOUNTVERS3;
2012 break;
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;
2021 vers_min = NFS_V4;
2022 break;
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.
2029 if (nfsretry_vers)
2030 vers_to_try = nfsretry_vers;
2031 else {
2032 vers_to_try = vers_max_default;
2033 vers_min = vers_min_default;
2036 break;
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
2043 * processing.
2045 if (vers_to_try == NFS_V4) {
2046 int savevers = nfsvers_to_use;
2047 err_ret_t error;
2048 int retval;
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;
2063 return (RET_ERR);
2065 return (RET_OK);
2067 nfsvers_to_use = savevers;
2069 vers_to_try--;
2070 /* If no more versions to try, let the user know. */
2071 if (vers_to_try < vers_min)
2072 return (retval);
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)
2082 return (retval);
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(""));
2090 return (RET_ERR);
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(""));
2100 return (RET_RETRY);
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.
2111 vers_to_try--;
2112 if (vers_to_try < vers_min) {
2113 if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH) {
2114 if (nfsvers == 0) {
2115 pr_err(gettext(
2116 "%s:%s: no applicable versions of NFS supported\n"),
2117 fshost, fspath);
2118 } else {
2119 pr_err(gettext(
2120 "%s:%s: NFS Version %d not supported\n"),
2121 fshost, fspath, nfsvers);
2123 return (RET_ERR);
2125 if (!printed) {
2126 pr_err(gettext("%s: %s\n"), fshost,
2127 clnt_spcreateerror(""));
2128 printed = 1;
2130 return (RET_RETRY);
2133 if (posix && outvers < MOUNTVERS_POSIX) {
2134 pr_err(gettext("%s: %s: no pathconf info\n"),
2135 fshost, clnt_sperror(cl, ""));
2136 clnt_destroy(cl);
2137 return (RET_ERR);
2140 if (__clnt_bindresvport(cl) < 0) {
2141 pr_err(gettext("Couldn't bind to reserved port\n"));
2142 clnt_destroy(cl);
2143 return (RET_RETRY);
2146 if ((cl->cl_auth = authsys_create_default()) == NULL) {
2147 pr_err(
2148 gettext("Couldn't create default authentication handle\n"));
2149 clnt_destroy(cl);
2150 return (RET_RETRY);
2153 switch (outvers) {
2154 case MOUNTVERS:
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, ""));
2162 clnt_destroy(cl);
2163 return (RET_RETRY);
2166 if ((errno = fhs.fhs_status) != MNT_OK) {
2167 if (loud_on_mnt_err) {
2168 if (errno == EACCES) {
2169 pr_err(gettext(
2170 "%s:%s: access denied\n"),
2171 fshost, fspath);
2172 } else {
2173 pr_err(gettext("%s:%s: %s\n"), fshost,
2174 fspath, errno >= 0 ?
2175 strerror(errno) : "invalid error "
2176 "returned by server");
2179 clnt_destroy(cl);
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"));
2185 return (RET_ERR);
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) {
2194 pr_err(gettext(
2195 "%s:%s: server not responding %s\n"),
2196 fshost, fspath, clnt_sperror(cl, ""));
2197 free(args->fh);
2198 clnt_destroy(cl);
2199 return (RET_RETRY);
2201 if (_PC_ISSET(_PC_ERROR, p.pc_mask)) {
2202 pr_err(gettext(
2203 "%s:%s: no pathconf info\n"),
2204 fshost, fspath);
2205 free(args->fh);
2206 clnt_destroy(cl);
2207 return (RET_ERR);
2209 args->flags |= NFSMNT_POSIX;
2210 args->pathconf = malloc(sizeof (p));
2211 if (args->pathconf == NULL) {
2212 pr_err(gettext("no memory\n"));
2213 free(args->fh);
2214 clnt_destroy(cl);
2215 return (RET_ERR);
2217 memcpy((caddr_t)args->pathconf, (caddr_t)&p,
2218 sizeof (p));
2220 break;
2222 case MOUNTVERS3:
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,
2226 timeout);
2227 if (rpc_stat != RPC_SUCCESS) {
2228 pr_err(gettext("%s:%s: server not responding %s\n"),
2229 fshost, fspath, clnt_sperror(cl, ""));
2230 clnt_destroy(cl);
2231 return (RET_RETRY);
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) {
2240 switch (errno) {
2241 case MNT3ERR_NAMETOOLONG:
2242 msg = "path name is too long";
2243 break;
2244 case MNT3ERR_NOTSUPP:
2245 msg = "operation not supported";
2246 break;
2247 case MNT3ERR_SERVERFAULT:
2248 msg = "server fault";
2249 break;
2250 default:
2251 if (errno >= 0)
2252 msg = strerror(errno);
2253 else
2254 msg = "invalid error returned "
2255 "by server";
2256 break;
2258 pr_err(gettext("%s:%s: %s\n"), fshost,
2259 fspath, msg);
2261 clnt_destroy(cl);
2262 return (RET_MNTERR);
2265 fh3p = (nfs_fh3 *)malloc(sizeof (*fh3p));
2266 if (fh3p == NULL) {
2267 pr_err(gettext("no memory\n"));
2268 return (RET_ERR);
2270 fh3p->fh3_length =
2271 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len;
2272 (void) memcpy(fh3p->fh3_u.data,
2273 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val,
2274 fh3p->fh3_length);
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
2284 * error.
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.
2293 auths =
2294 mountres3.mountres3_u.mountinfo.auth_flavors
2295 .auth_flavors_val;
2296 count =
2297 mountres3.mountres3_u.mountinfo.auth_flavors
2298 .auth_flavors_len;
2300 if (count <= 0) {
2301 pr_err(gettext(
2302 "server %s did not return any security mode\n"),
2303 fshost);
2304 clnt_destroy(cl);
2305 return (RET_ERR);
2308 if (sec_opt) {
2309 for (i = 0; i < count; i++) {
2310 if (auths[i] == nfs_sec.sc_nfsnum)
2311 break;
2313 if (i == count)
2314 goto autherr;
2315 } else {
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) {
2331 sec_opt++;
2332 nfs_sec = default_sec;
2333 break;
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],
2346 &nfs_sec)) {
2347 sec_opt++;
2348 break;
2354 if (i == count)
2355 goto autherr;
2357 break;
2358 default:
2359 pr_err(gettext("%s:%s: Unknown MOUNT version %d\n"),
2360 fshost, fspath, outvers);
2361 clnt_destroy(cl);
2362 return (RET_ERR);
2365 clnt_destroy(cl);
2366 return (RET_OK);
2368 autherr:
2369 pr_err(gettext(
2370 "security mode does not match the server exporting %s:%s\n"),
2371 fshost, fspath);
2372 clnt_destroy(cl);
2373 return (RET_ERR);
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.
2381 static int
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)
2386 struct stat sb;
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);
2396 if (nfs_proto) {
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;
2408 } else {
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);
2413 } else {
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
2431 * retry.
2433 if (get_pubfh == TRUE)
2434 return (RET_ERR);
2436 if (!printed) {
2437 switch (addr_error.error_type) {
2438 case 0:
2439 printed = 1;
2440 break;
2441 case ERR_RPCERROR:
2442 if (!print_rpcerror)
2443 /* no error print at this time */
2444 break;
2445 pr_err(gettext("%s NFS service not"
2446 " available %s\n"), fshost,
2447 clnt_sperrno(addr_error.error_value));
2448 printed = 1;
2449 break;
2450 case ERR_NETPATH:
2451 pr_err(gettext("%s: Error in NETPATH.\n"),
2452 fshost);
2453 printed = 1;
2454 break;
2455 case ERR_PROTO_INVALID:
2456 pr_err(gettext("%s: NFS service does not"
2457 " recognize protocol: %s.\n"), fshost,
2458 nfs_proto);
2459 printed = 1;
2460 break;
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
2471 * transport.
2473 * 2. If a version is specified and it
2474 * does'nt support the asked
2475 * transport.
2477 * Otherwise we decrement the version
2478 * and retry below.
2480 pr_err(gettext("%s: NFS service does"
2481 " not support protocol: %s.\n"),
2482 fshost, nfs_proto);
2484 break;
2485 case ERR_NOHOST:
2486 pr_err("%s: %s\n", fshost, "Unknown host");
2487 printed = 1;
2488 break;
2489 default:
2490 /* case ERR_PROTO_NONE falls through */
2491 pr_err(gettext("%s: NFS service not responding"
2492 "\n"), fshost);
2493 printed = 1;
2494 break;
2497 SET_ERR_RET(error,
2498 addr_error.error_type, addr_error.error_value);
2499 if (addr_error.error_type == ERR_PROTO_NONE)
2500 return (RET_RETRY);
2501 else if (addr_error.error_type == ERR_RPCERROR &&
2502 !IS_UNRECOVERABLE_RPC(addr_error.error_value)) {
2503 return (RET_RETRY);
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.
2511 return (RET_RETRY);
2512 } else
2513 return (RET_ERR);
2515 nconf = *nconfp;
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));
2520 return (RET_ERR);
2523 knconfp = (struct knetconfig *)malloc(sizeof (*knconfp));
2524 if (!knconfp) {
2525 pr_err(gettext("no memory\n"));
2526 return (RET_ERR);
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;
2544 return (RET_OK);
2547 static int
2548 retry(struct mnttab *mntp, int ro)
2550 int delay = 5;
2551 int count = retries;
2552 int r;
2555 * Please see comments on nfsretry_vers in the beginning of this file
2556 * and in main() routine.
2559 if (bg) {
2560 if (fork() > 0)
2561 return (RET_OK);
2562 backgrounded = 1;
2563 pr_err(gettext("backgrounding: %s\n"), mntp->mnt_mountp);
2564 } else {
2565 if (!nfsretry_vers)
2566 pr_err(gettext("retrying: %s\n"), mntp->mnt_mountp);
2569 while (count--) {
2570 if ((r = mount_nfs(mntp, ro, NULL)) == RET_OK) {
2571 pr_err(gettext("%s: mounted OK\n"), mntp->mnt_mountp);
2572 return (RET_OK);
2574 if (r != RET_RETRY)
2575 break;
2577 if (count > 0) {
2578 (void) sleep(delay);
2579 delay *= 2;
2580 if (delay > 120)
2581 delay = 120;
2585 if (!nfsretry_vers)
2586 pr_err(gettext("giving up on: %s\n"), mntp->mnt_mountp);
2588 return (RET_ERR);
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
2594 * use.
2596 static void
2597 read_default(void)
2599 char value[4];
2600 int errno;
2601 int tmp = 0, bufsz = 0, ret = 0;
2603 /* Maximum number of bytes expected. */
2604 bufsz = 4;
2605 ret = nfs_smf_get_prop("client_versmin", value, DEFAULT_INSTANCE,
2606 SCF_TYPE_INTEGER, SVC_NFS_CLIENT, &bufsz);
2607 if (ret == SA_OK) {
2608 errno = 0;
2609 tmp = strtol(value, (char **)NULL, 10);
2610 if (errno == 0) {
2611 vers_min_default = tmp;
2615 /* Maximum number of bytes expected. */
2616 bufsz = 4;
2617 ret = nfs_smf_get_prop("client_versmax", value, DEFAULT_INSTANCE,
2618 SCF_TYPE_INTEGER, SVC_NFS_CLIENT, &bufsz);
2619 if (ret == SA_OK) {
2620 errno = 0;
2621 tmp = strtol(value, (char **)NULL, 10);
2622 if (errno == 0) {
2623 vers_max_default = tmp;
2628 static void
2629 sigusr1(int s)