2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 static const char copyright[] =
38 "@(#) Copyright (c) 1992, 1993, 1994\n\
39 The Regents of the University of California. All rights reserved.\n";
43 static char sccsid[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95";
46 #include <sys/cdefs.h>
47 __FBSDID("$FreeBSD$");
49 #include <sys/param.h>
50 #include <sys/linker.h>
51 #include <sys/module.h>
52 #include <sys/mount.h>
53 #include <sys/socket.h>
55 #include <sys/syslog.h>
59 #include <rpc/pmap_clnt.h>
60 #include <rpc/pmap_prot.h>
61 #include <rpcsvc/nfs_prot.h>
62 #include <rpcsvc/mount.h>
64 #include <fs/nfs/nfsproto.h>
65 #include <fs/nfs/nfsv4_errstr.h>
67 #include <arpa/inet.h>
84 /* Table for af,sotype -> netid conversions. */
85 static struct nc_protos {
90 {"udp", AF_INET, SOCK_DGRAM},
91 {"tcp", AF_INET, SOCK_STREAM},
92 {"udp6", AF_INET6, SOCK_DGRAM},
93 {"tcp6", AF_INET6, SOCK_STREAM},
102 u_char nfh[NFS3_FHSIZE];
108 static int retrycnt = -1;
109 static int opflags = 0;
110 static int nfsproto = IPPROTO_TCP;
111 static int mnttcp_ok = 1;
112 static int noconn = 0;
113 /* The 'portspec' is the server nfs port; NULL means look up via rpcbind. */
114 static const char *portspec = NULL;
115 static struct sockaddr *addr;
116 static int addrlen = 0;
117 static u_char *fh = NULL;
118 static int fhsize = 0;
119 static int secflavor = -1;
120 static int got_principal = 0;
122 static enum mountmode {
129 /* Return codes for nfs_tryproto. */
132 TRYRET_TIMEOUT, /* No response received. */
133 TRYRET_REMOTEERR, /* Error received from remote server. */
134 TRYRET_LOCALERR /* Local failure. */
137 static int sec_name_to_num(const char *sec);
138 static const char *sec_num_to_name(int num);
139 static int getnfsargs(char *, struct iovec **iov, int *iovlen);
140 /* void set_rpc_maxgrouplist(int); */
141 static struct netconfig *getnetconf_cached(const char *netid);
142 static const char *netidbytype(int af, int sotype);
143 static void usage(void) __dead2;
144 static int xdr_dir(XDR *, char *);
145 static int xdr_fh(XDR *, struct nfhret *);
146 static enum tryret nfs_tryproto(struct addrinfo *ai, char *hostp, char *spec,
147 char **errstr, struct iovec **iov, int *iovlen);
148 static enum tryret returncode(enum clnt_stat stat, struct rpc_err *rpcerr);
151 main(int argc, char *argv[])
156 char *mntname, *p, *spec, *tmp;
157 char mntpath[MAXPATHLEN], errmsg[255];
158 char hostname[MAXHOSTNAMELEN + 1], gssn[MAXHOSTNAMELEN + 50];
159 const char *gssname, *nmount_errstr;
163 memset(errmsg, 0, sizeof(errmsg));
166 while ((c = getopt(argc, argv,
167 "23a:bcdD:g:I:iLlNo:PR:r:sTt:w:x:U")) != -1)
176 printf("-a deprecated, use -o readahead=<value>\n");
177 build_iovec(&iov, &iovlen, "readahead", optarg, (size_t)-1);
183 printf("-c deprecated, use -o noconn\n");
184 build_iovec(&iov, &iovlen, "noconn", NULL, 0);
188 printf("-D deprecated, use -o deadthresh=<value>\n");
189 build_iovec(&iov, &iovlen, "deadthresh", optarg, (size_t)-1);
192 printf("-d deprecated, use -o dumbtimer");
193 build_iovec(&iov, &iovlen, "dumbtimer", NULL, 0);
196 printf("-g deprecated, use -o maxgroups");
197 num = strtol(optarg, &p, 10);
199 errx(1, "illegal -g value -- %s", optarg);
200 //set_rpc_maxgrouplist(num);
201 build_iovec(&iov, &iovlen, "maxgroups", optarg, (size_t)-1);
204 printf("-I deprecated, use -o readdirsize=<value>\n");
205 build_iovec(&iov, &iovlen, "readdirsize", optarg, (size_t)-1);
208 printf("-i deprecated, use -o intr\n");
209 build_iovec(&iov, &iovlen, "intr", NULL, 0);
212 printf("-L deprecated, use -o nolockd\n");
213 build_iovec(&iov, &iovlen, "nolockd", NULL, 0);
216 printf("-l deprecated, -o rdirplus\n");
217 build_iovec(&iov, &iovlen, "rdirplus", NULL, 0);
220 printf("-N deprecated, do not specify -o resvport\n");
223 int pass_flag_to_nmount;
227 char *pnextopt = NULL;
228 const char *val = "";
229 pass_flag_to_nmount = 1;
230 pnextopt = strchr(opt, ',');
231 if (pnextopt != NULL) {
235 pval = strchr(opt, '=');
240 if (strcmp(opt, "bg") == 0) {
242 pass_flag_to_nmount=0;
243 } else if (strcmp(opt, "fg") == 0) {
244 /* same as not specifying -o bg */
245 pass_flag_to_nmount=0;
246 } else if (strcmp(opt, "gssname") == 0) {
247 pass_flag_to_nmount = 0;
249 } else if (strcmp(opt, "mntudp") == 0) {
251 nfsproto = IPPROTO_UDP;
252 } else if (strcmp(opt, "udp") == 0) {
253 nfsproto = IPPROTO_UDP;
254 } else if (strcmp(opt, "tcp") == 0) {
255 nfsproto = IPPROTO_TCP;
256 } else if (strcmp(opt, "noinet4") == 0) {
257 pass_flag_to_nmount=0;
258 opflags |= OF_NOINET4;
259 } else if (strcmp(opt, "noinet6") == 0) {
260 pass_flag_to_nmount=0;
261 opflags |= OF_NOINET6;
262 } else if (strcmp(opt, "noconn") == 0) {
264 } else if (strcmp(opt, "nfsv2") == 0) {
265 pass_flag_to_nmount=0;
267 } else if (strcmp(opt, "nfsv3") == 0) {
269 } else if (strcmp(opt, "nfsv4") == 0) {
270 pass_flag_to_nmount=0;
272 nfsproto = IPPROTO_TCP;
273 if (portspec == NULL)
275 } else if (strcmp(opt, "port") == 0) {
276 pass_flag_to_nmount=0;
277 asprintf(&tmp, "%d", atoi(val));
281 } else if (strcmp(opt, "principal") == 0) {
283 } else if (strcmp(opt, "proto") == 0) {
284 pass_flag_to_nmount=0;
285 if (strcmp(val, "tcp") == 0) {
286 nfsproto = IPPROTO_TCP;
287 opflags |= OF_NOINET6;
288 build_iovec(&iov, &iovlen,
290 } else if (strcmp(val, "udp") == 0) {
292 nfsproto = IPPROTO_UDP;
293 opflags |= OF_NOINET6;
294 build_iovec(&iov, &iovlen,
296 } else if (strcmp(val, "tcp6") == 0) {
297 nfsproto = IPPROTO_TCP;
298 opflags |= OF_NOINET4;
299 build_iovec(&iov, &iovlen,
301 } else if (strcmp(val, "udp6") == 0) {
303 nfsproto = IPPROTO_UDP;
304 opflags |= OF_NOINET4;
305 build_iovec(&iov, &iovlen,
309 "illegal proto value -- %s",
312 } else if (strcmp(opt, "sec") == 0) {
314 * Don't add this option to
315 * the iovec yet - we will
316 * negotiate which sec flavor
317 * to use with the remote
320 pass_flag_to_nmount=0;
321 secflavor = sec_name_to_num(val);
324 "illegal sec value -- %s",
327 } else if (strcmp(opt, "retrycnt") == 0) {
328 pass_flag_to_nmount=0;
329 num = strtol(val, &p, 10);
331 errx(1, "illegal retrycnt value -- %s", val);
333 } else if (strcmp(opt, "maxgroups") == 0) {
334 num = strtol(val, &p, 10);
336 errx(1, "illegal maxgroups value -- %s", val);
337 //set_rpc_maxgrouplist(num);
338 } else if (strcmp(opt, "vers") == 0) {
339 num = strtol(val, &p, 10);
341 errx(1, "illegal vers value -- "
349 build_iovec(&iov, &iovlen,
354 nfsproto = IPPROTO_TCP;
355 if (portspec == NULL)
359 errx(1, "illegal nfs version "
362 pass_flag_to_nmount=0;
364 if (pass_flag_to_nmount) {
365 build_iovec(&iov, &iovlen, opt,
366 __DECONST(void *, val),
374 /* obsolete for -o noresvport now default */
375 printf("-P deprecated, use -o noresvport\n");
376 build_iovec(&iov, &iovlen, "noresvport", NULL, 0);
379 printf("-R deprecated, use -o retrycnt=<retrycnt>\n");
380 num = strtol(optarg, &p, 10);
382 errx(1, "illegal -R value -- %s", optarg);
386 printf("-r deprecated, use -o rsize=<rsize>\n");
387 build_iovec(&iov, &iovlen, "rsize", optarg, (size_t)-1);
390 printf("-s deprecated, use -o soft\n");
391 build_iovec(&iov, &iovlen, "soft", NULL, 0);
394 nfsproto = IPPROTO_TCP;
395 printf("-T deprecated, use -o tcp\n");
398 printf("-t deprecated, use -o timeout=<value>\n");
399 build_iovec(&iov, &iovlen, "timeout", optarg, (size_t)-1);
402 printf("-w deprecated, use -o wsize=<value>\n");
403 build_iovec(&iov, &iovlen, "wsize", optarg, (size_t)-1);
406 printf("-x deprecated, use -o retrans=<value>\n");
407 build_iovec(&iov, &iovlen, "retrans", optarg, (size_t)-1);
410 printf("-U deprecated, use -o mntudp\n");
412 nfsproto = IPPROTO_UDP;
413 build_iovec(&iov, &iovlen, "mntudp", NULL, 0);
431 /* The default is to keep retrying forever. */
434 if (modfind("nfscl") < 0) {
435 /* Not present in kernel, try loading it */
436 if (kldload("nfscl") < 0 ||
437 modfind("nfscl") < 0)
438 errx(1, "nfscl is not available");
442 * Add the fqdn to the gssname, as required.
444 if (gssname != NULL) {
445 if (strchr(gssname, '@') == NULL &&
446 gethostname(hostname, MAXHOSTNAMELEN) == 0) {
447 snprintf(gssn, sizeof (gssn), "%s@%s", gssname,
451 build_iovec(&iov, &iovlen, "gssname",
452 __DECONST(void *, gssname), strlen(gssname) + 1);
455 if (!getnfsargs(spec, &iov, &iovlen))
458 /* resolve the mountpoint with realpath(3) */
459 if (checkpath(mntname, mntpath) != 0)
460 err(1, "%s", mntpath);
462 build_iovec_argf(&iov, &iovlen, "fstype", "nfs");
463 build_iovec(&iov, &iovlen, "fspath", mntpath, (size_t)-1);
464 build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
466 if (nmount(iov, iovlen, 0)) {
467 nmount_errstr = nfsv4_geterrstr(errno);
468 if (mountmode == V4 && nmount_errstr != NULL)
469 errx(1, "nmount: %s, %s", mntpath, nmount_errstr);
471 err(1, "nmount: %s%s%s", mntpath, errmsg[0] ? ", " : "",
479 sec_name_to_num(const char *sec)
481 if (!strcmp(sec, "krb5"))
482 return (RPCSEC_GSS_KRB5);
483 if (!strcmp(sec, "krb5i"))
484 return (RPCSEC_GSS_KRB5I);
485 if (!strcmp(sec, "krb5p"))
486 return (RPCSEC_GSS_KRB5P);
487 if (!strcmp(sec, "sys"))
493 sec_num_to_name(int flavor)
496 case RPCSEC_GSS_KRB5:
498 case RPCSEC_GSS_KRB5I:
500 case RPCSEC_GSS_KRB5P:
509 getnfsargs(char *spec, struct iovec **iov, int *iovlen)
511 struct addrinfo hints, *ai_nfs, *ai;
513 int ecode, speclen, remoteerr, offset, have_bracket = 0;
514 char *hostp, *delimp, *errstr;
516 static char nam[MNAMELEN + 1], pname[MAXHOSTNAMELEN + 5];
518 if (*spec == '[' && (delimp = strchr(spec + 1, ']')) != NULL &&
519 *(delimp + 1) == ':') {
523 } else if ((delimp = strrchr(spec, ':')) != NULL) {
526 } else if ((delimp = strrchr(spec, '@')) != NULL) {
527 warnx("path@server syntax is deprecated, use server:path");
530 warnx("no <host>:<dirpath> nfs-name");
536 * If there has been a trailing slash at mounttime it seems
537 * that some mountd implementations fail to remove the mount
538 * entries from their mountlist while unmounting.
540 for (speclen = strlen(spec);
541 speclen > 1 && spec[speclen - 1] == '/';
543 spec[speclen - 1] = '\0';
544 if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) {
545 warnx("%s:%s: %s", hostp, spec, strerror(ENAMETOOLONG));
548 /* Make both '@' and ':' notations equal */
549 if (*hostp != '\0') {
554 memmove(nam + offset, hostp, len);
556 nam[len + offset++] = ']';
557 nam[len + offset++] = ':';
558 memmove(nam + len + offset, spec, speclen);
559 nam[len + speclen + offset] = '\0';
563 * Handle an internet host address.
565 memset(&hints, 0, sizeof hints);
566 hints.ai_flags = AI_NUMERICHOST;
567 if (nfsproto == IPPROTO_TCP)
568 hints.ai_socktype = SOCK_STREAM;
569 else if (nfsproto == IPPROTO_UDP)
570 hints.ai_socktype = SOCK_DGRAM;
572 if (getaddrinfo(hostp, portspec, &hints, &ai_nfs) != 0) {
573 hints.ai_flags = AI_CANONNAME;
574 if ((ecode = getaddrinfo(hostp, portspec, &hints, &ai_nfs))
576 if (portspec == NULL)
577 errx(1, "%s: %s", hostp, gai_strerror(ecode));
579 errx(1, "%s:%s: %s", hostp, portspec,
580 gai_strerror(ecode));
585 * For a Kerberized nfs mount where the "principal"
586 * argument has not been set, add it here.
588 if (got_principal == 0 && secflavor != AUTH_SYS &&
589 ai_nfs->ai_canonname != NULL) {
590 snprintf(pname, sizeof (pname), "nfs@%s",
591 ai_nfs->ai_canonname);
592 build_iovec(iov, iovlen, "principal", pname,
597 ret = TRYRET_LOCALERR;
600 * Try each entry returned by getaddrinfo(). Note the
601 * occurrence of remote errors by setting `remoteerr'.
604 for (ai = ai_nfs; ai != NULL; ai = ai->ai_next) {
605 if ((ai->ai_family == AF_INET6) &&
606 (opflags & OF_NOINET6))
608 if ((ai->ai_family == AF_INET) &&
609 (opflags & OF_NOINET4))
611 ret = nfs_tryproto(ai, hostp, spec, &errstr, iov,
613 if (ret == TRYRET_SUCCESS)
615 if (ret != TRYRET_LOCALERR)
617 if ((opflags & ISBGRND) == 0)
618 fprintf(stderr, "%s\n", errstr);
620 if (ret == TRYRET_SUCCESS)
623 /* Exit if all errors were local. */
628 * If retrycnt == 0, we are to keep retrying forever.
629 * Otherwise decrement it, and exit if it hits zero.
631 if (retrycnt != 0 && --retrycnt == 0)
634 if ((opflags & (BGRND | ISBGRND)) == BGRND) {
635 warnx("Cannot immediately mount %s:%s, backgrounding",
638 if (daemon(0, 0) != 0)
643 freeaddrinfo(ai_nfs);
645 build_iovec(iov, iovlen, "hostname", nam, (size_t)-1);
646 /* Add mounted file system to PATH_MOUNTTAB */
647 if (mountmode != V4 && !add_mtab(hostp, spec))
648 warnx("can't update %s for %s:%s", PATH_MOUNTTAB, hostp, spec);
653 * Try to set up the NFS arguments according to the address
654 * family, protocol (and possibly port) specified in `ai'.
656 * Returns TRYRET_SUCCESS if successful, or:
657 * TRYRET_TIMEOUT The server did not respond.
658 * TRYRET_REMOTEERR The server reported an error.
659 * TRYRET_LOCALERR Local failure.
661 * In all error cases, *errstr will be set to a statically-allocated string
662 * describing the error.
665 nfs_tryproto(struct addrinfo *ai, char *hostp, char *spec, char **errstr,
666 struct iovec **iov, int *iovlen)
668 static char errbuf[256];
669 struct sockaddr_storage nfs_ss;
670 struct netbuf nfs_nb;
671 struct nfhret nfhret;
673 struct rpc_err rpcerr;
675 struct netconfig *nconf, *nconf_mnt;
676 const char *netid, *netid_mnt, *secname;
677 int doconnect, nfsvers, mntvers, sotype;
678 enum clnt_stat clntstat;
679 enum mountmode trymntmode;
682 trymntmode = mountmode;
686 if (nfsproto == IPPROTO_TCP)
687 sotype = SOCK_STREAM;
688 else if (nfsproto == IPPROTO_UDP)
691 if ((netid = netidbytype(ai->ai_family, sotype)) == NULL) {
692 snprintf(errbuf, sizeof errbuf,
693 "af %d sotype %d not supported", ai->ai_family, sotype);
694 return (TRYRET_LOCALERR);
696 if ((nconf = getnetconf_cached(netid)) == NULL) {
697 snprintf(errbuf, sizeof errbuf, "%s: %s", netid, nc_sperror());
698 return (TRYRET_LOCALERR);
700 /* The RPCPROG_MNT netid may be different. */
705 if ((netid_mnt = netidbytype(ai->ai_family, SOCK_DGRAM))
707 snprintf(errbuf, sizeof errbuf,
708 "af %d sotype SOCK_DGRAM not supported",
710 return (TRYRET_LOCALERR);
712 if ((nconf_mnt = getnetconf_cached(netid_mnt)) == NULL) {
713 snprintf(errbuf, sizeof errbuf, "%s: %s", netid_mnt,
715 return (TRYRET_LOCALERR);
720 if (trymntmode == V4) {
722 mntvers = 3; /* Workaround for GCC. */
723 } else if (trymntmode == V2) {
731 if (portspec != NULL) {
732 /* `ai' contains the complete nfsd sockaddr. */
733 nfs_nb.buf = ai->ai_addr;
734 nfs_nb.len = nfs_nb.maxlen = ai->ai_addrlen;
736 /* Ask the remote rpcbind. */
737 nfs_nb.buf = &nfs_ss;
738 nfs_nb.len = nfs_nb.maxlen = sizeof nfs_ss;
740 if (!rpcb_getaddr(NFS_PROGRAM, nfsvers, nconf, &nfs_nb,
742 if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH &&
747 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s",
749 clnt_spcreateerror("RPCPROG_NFS"));
750 return (returncode(rpc_createerr.cf_stat,
751 &rpc_createerr.cf_error));
755 /* Check that the server (nfsd) responds on the port we have chosen. */
756 clp = clnt_tli_create(RPC_ANYFD, nconf, &nfs_nb, NFS_PROGRAM, nfsvers,
759 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid,
760 hostp, spec, clnt_spcreateerror("nfsd: RPCPROG_NFS"));
761 return (returncode(rpc_createerr.cf_stat,
762 &rpc_createerr.cf_error));
764 if (sotype == SOCK_DGRAM && noconn == 0) {
766 * Use connect(), to match what the kernel does. This
767 * catches cases where the server responds from the
768 * wrong source address.
771 if (!clnt_control(clp, CLSET_CONNECT, (char *)&doconnect)) {
773 snprintf(errbuf, sizeof errbuf,
774 "[%s] %s:%s: CLSET_CONNECT failed", netid, hostp,
776 return (TRYRET_LOCALERR);
782 clntstat = clnt_call(clp, NFSPROC_NULL, (xdrproc_t)xdr_void, NULL,
783 (xdrproc_t)xdr_void, NULL, try);
784 if (clntstat != RPC_SUCCESS) {
785 if (clntstat == RPC_PROGVERSMISMATCH && trymntmode == ANY) {
790 clnt_geterr(clp, &rpcerr);
791 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid,
792 hostp, spec, clnt_sperror(clp, "NFSPROC_NULL"));
794 return (returncode(clntstat, &rpcerr));
799 * For NFSv4, there is no mount protocol.
801 if (trymntmode == V4) {
803 * Store the server address in nfsargsp, making
804 * sure to copy any locally allocated structures.
806 addrlen = nfs_nb.len;
807 addr = malloc(addrlen);
810 bcopy(nfs_nb.buf, addr, addrlen);
812 build_iovec(iov, iovlen, "addr", addr, addrlen);
813 secname = sec_num_to_name(secflavor);
814 if (secname != NULL) {
815 build_iovec(iov, iovlen, "sec",
816 __DECONST(void *, secname), (size_t)-1);
818 build_iovec(iov, iovlen, "nfsv4", NULL, 0);
819 build_iovec(iov, iovlen, "dirpath", spec, (size_t)-1);
821 return (TRYRET_SUCCESS);
824 /* Send the MOUNTPROC_MNT RPC to get the root filehandle. */
827 clp = clnt_tp_create(hostp, MOUNTPROG, mntvers, nconf_mnt);
829 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt,
830 hostp, spec, clnt_spcreateerror("RPCMNT: clnt_create"));
831 return (returncode(rpc_createerr.cf_stat,
832 &rpc_createerr.cf_error));
834 clp->cl_auth = authsys_create_default();
835 nfhret.auth = secflavor;
836 nfhret.vers = mntvers;
837 clntstat = clnt_call(clp, MOUNTPROC_MNT, (xdrproc_t)xdr_dir, spec,
838 (xdrproc_t)xdr_fh, &nfhret,
840 auth_destroy(clp->cl_auth);
841 if (clntstat != RPC_SUCCESS) {
842 if (clntstat == RPC_PROGVERSMISMATCH && trymntmode == ANY) {
847 clnt_geterr(clp, &rpcerr);
848 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt,
849 hostp, spec, clnt_sperror(clp, "RPCPROG_MNT"));
851 return (returncode(clntstat, &rpcerr));
855 if (nfhret.stat != 0) {
856 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt,
857 hostp, spec, strerror(nfhret.stat));
858 return (TRYRET_REMOTEERR);
862 * Store the filehandle and server address in nfsargsp, making
863 * sure to copy any locally allocated structures.
865 addrlen = nfs_nb.len;
866 addr = malloc(addrlen);
867 fhsize = nfhret.fhsize;
869 if (addr == NULL || fh == NULL)
871 bcopy(nfs_nb.buf, addr, addrlen);
872 bcopy(nfhret.nfh, fh, fhsize);
874 build_iovec(iov, iovlen, "addr", addr, addrlen);
875 build_iovec(iov, iovlen, "fh", fh, fhsize);
876 secname = sec_num_to_name(nfhret.auth);
878 build_iovec(iov, iovlen, "sec",
879 __DECONST(void *, secname), (size_t)-1);
882 build_iovec(iov, iovlen, "nfsv3", NULL, 0);
884 return (TRYRET_SUCCESS);
888 * Catagorise a RPC return status and error into an `enum tryret'
892 returncode(enum clnt_stat clntstat, struct rpc_err *rpcerr)
897 return (TRYRET_TIMEOUT);
898 case RPC_PMAPFAILURE:
899 case RPC_PROGNOTREGISTERED:
900 case RPC_PROGVERSMISMATCH:
901 /* XXX, these can be local or remote. */
904 return (TRYRET_REMOTEERR);
905 case RPC_SYSTEMERROR:
906 switch (rpcerr->re_errno) {
908 return (TRYRET_TIMEOUT);
912 return (TRYRET_REMOTEERR);
918 return (TRYRET_LOCALERR);
922 * Look up a netid based on an address family and socket type.
923 * `af' is the address family, and `sotype' is SOCK_DGRAM or SOCK_STREAM.
925 * XXX there should be a library function for this.
928 netidbytype(int af, int sotype)
932 for (p = nc_protos; p->netid != NULL; p++) {
933 if (af != p->af || sotype != p->sotype)
941 * Look up a netconfig entry based on a netid, and cache the result so
942 * that we don't need to remember to call freenetconfigent().
944 * Otherwise it behaves just like getnetconfigent(), so nc_*error()
947 static struct netconfig *
948 getnetconf_cached(const char *netid)
950 static struct nc_entry {
951 struct netconfig *nconf;
952 struct nc_entry *next;
955 struct netconfig *nconf;
957 for (p = head; p != NULL; p = p->next)
958 if (strcmp(netid, p->nconf->nc_netid) == 0)
961 if ((nconf = getnetconfigent(netid)) == NULL)
963 if ((p = malloc(sizeof(*p))) == NULL)
973 * xdr routines for mount rpc's
976 xdr_dir(XDR *xdrsp, char *dirp)
978 return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
982 xdr_fh(XDR *xdrsp, struct nfhret *np)
985 long auth, authcnt, authfnd = 0;
987 if (!xdr_u_long(xdrsp, &np->stat))
993 np->fhsize = NFS_FHSIZE;
994 return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFS_FHSIZE));
996 if (!xdr_long(xdrsp, &np->fhsize))
998 if (np->fhsize <= 0 || np->fhsize > NFS3_FHSIZE)
1000 if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize))
1002 if (!xdr_long(xdrsp, &authcnt))
1004 for (i = 0; i < authcnt; i++) {
1005 if (!xdr_long(xdrsp, &auth))
1007 if (np->auth == -1) {
1010 } else if (auth == np->auth) {
1015 * Some servers, such as DEC's OSF/1 return a nil authenticator
1016 * list to indicate RPCAUTH_UNIX.
1018 if (authcnt == 0 && np->auth == -1)
1019 np->auth = AUTH_SYS;
1020 if (!authfnd && (authcnt > 0 || np->auth != AUTH_SYS))
1030 (void)fprintf(stderr, "%s\n%s\n%s\n%s\n",
1031 "usage: mount_nfs [-23bcdiLlNPsTU] [-a maxreadahead] [-D deadthresh]",
1032 " [-g maxgroups] [-I readdirsize] [-o options] [-R retrycnt]",
1033 " [-r readsize] [-t timeout] [-w writesize] [-x retrans]",
1034 " rhost:path node");