18fae3551SRodney W. Grimes /* 28fae3551SRodney W. Grimes * Copyright (c) 1992, 1993, 1994 38fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 48fae3551SRodney W. Grimes * 58fae3551SRodney W. Grimes * This code is derived from software contributed to Berkeley by 68fae3551SRodney W. Grimes * Rick Macklem at The University of Guelph. 78fae3551SRodney W. Grimes * 88fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 98fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 108fae3551SRodney W. Grimes * are met: 118fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 128fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 138fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 148fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 158fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 168fae3551SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 178fae3551SRodney W. Grimes * must display the following acknowledgement: 188fae3551SRodney W. Grimes * This product includes software developed by the University of 198fae3551SRodney W. Grimes * California, Berkeley and its contributors. 208fae3551SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 218fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 228fae3551SRodney W. Grimes * without specific prior written permission. 238fae3551SRodney W. Grimes * 248fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 258fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 268fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 278fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 288fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 298fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 308fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 318fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 328fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 338fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 348fae3551SRodney W. Grimes * SUCH DAMAGE. 358fae3551SRodney W. Grimes */ 368fae3551SRodney W. Grimes 378fae3551SRodney W. Grimes #ifndef lint 3846fc8f78SPhilippe Charnier static const char copyright[] = 398fae3551SRodney W. Grimes "@(#) Copyright (c) 1992, 1993, 1994\n\ 408fae3551SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 418fae3551SRodney W. Grimes #endif /* not lint */ 428fae3551SRodney W. Grimes 438fae3551SRodney W. Grimes #ifndef lint 4446fc8f78SPhilippe Charnier #if 0 454a4c5285SPeter Wemm static char sccsid[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95"; 4646fc8f78SPhilippe Charnier #endif 475e074e31SGarrett Wollman static const char rcsid[] = 487f3dea24SPeter Wemm "$FreeBSD$"; 498fae3551SRodney W. Grimes #endif /* not lint */ 508fae3551SRodney W. Grimes 518fae3551SRodney W. Grimes #include <sys/param.h> 528fae3551SRodney W. Grimes #include <sys/mount.h> 538360efbdSAlfred Perlstein #include <sys/socket.h> 548fae3551SRodney W. Grimes #include <sys/stat.h> 558fae3551SRodney W. Grimes #include <sys/syslog.h> 568fae3551SRodney W. Grimes 578fae3551SRodney W. Grimes #include <rpc/rpc.h> 588fae3551SRodney W. Grimes #include <rpc/pmap_clnt.h> 598fae3551SRodney W. Grimes #include <rpc/pmap_prot.h> 608fae3551SRodney W. Grimes 618fae3551SRodney W. Grimes #include <nfs/rpcv2.h> 62a62dc406SDoug Rabson #include <nfs/nfsproto.h> 6391196234SPeter Wemm #include <nfsclient/nfs.h> 6491196234SPeter Wemm #include <nfsclient/nfsargs.h> 658fae3551SRodney W. Grimes 668fae3551SRodney W. Grimes #include <arpa/inet.h> 678fae3551SRodney W. Grimes 688fae3551SRodney W. Grimes #include <ctype.h> 698fae3551SRodney W. Grimes #include <err.h> 708fae3551SRodney W. Grimes #include <errno.h> 718360efbdSAlfred Perlstein #include <fcntl.h> 728fae3551SRodney W. Grimes #include <netdb.h> 738fae3551SRodney W. Grimes #include <stdio.h> 748fae3551SRodney W. Grimes #include <stdlib.h> 758fae3551SRodney W. Grimes #include <strings.h> 765e074e31SGarrett Wollman #include <sysexits.h> 778fae3551SRodney W. Grimes #include <unistd.h> 788fae3551SRodney W. Grimes 798fae3551SRodney W. Grimes #include "mntopts.h" 80a69497d7SMatthew Dillon #include "mounttab.h" 818fae3551SRodney W. Grimes 823fa88decSGarrett Wollman #define ALTF_BG 0x1 833fa88decSGarrett Wollman #define ALTF_NOCONN 0x2 843fa88decSGarrett Wollman #define ALTF_DUMBTIMR 0x4 853fa88decSGarrett Wollman #define ALTF_INTR 0x8 86a62dc406SDoug Rabson #define ALTF_NFSV3 0x20 87a62dc406SDoug Rabson #define ALTF_RDIRPLUS 0x40 88a62dc406SDoug Rabson #define ALTF_MNTUDP 0x80 893fa88decSGarrett Wollman #define ALTF_RESVPORT 0x100 903fa88decSGarrett Wollman #define ALTF_SEQPACKET 0x200 913fa88decSGarrett Wollman #define ALTF_SOFT 0x800 923fa88decSGarrett Wollman #define ALTF_TCP 0x1000 93bc2cfd71SKarl Strickland #define ALTF_PORT 0x2000 942cd1c32cSDoug Rabson #define ALTF_NFSV2 0x4000 95c92e3fa5SPeter Wemm #define ALTF_ACREGMIN 0x8000 96c92e3fa5SPeter Wemm #define ALTF_ACREGMAX 0x10000 97c92e3fa5SPeter Wemm #define ALTF_ACDIRMIN 0x20000 98c92e3fa5SPeter Wemm #define ALTF_ACDIRMAX 0x40000 9913190d87SAlfred Perlstein #define ALTF_NOLOCKD 0x80000 1003fa88decSGarrett Wollman 1018fae3551SRodney W. Grimes struct mntopt mopts[] = { 1028fae3551SRodney W. Grimes MOPT_STDOPTS, 1038fae3551SRodney W. Grimes MOPT_FORCE, 1048fae3551SRodney W. Grimes MOPT_UPDATE, 1056362924fSDoug Rabson MOPT_ASYNC, 1063fa88decSGarrett Wollman { "bg", 0, ALTF_BG, 1 }, 1073fa88decSGarrett Wollman { "conn", 1, ALTF_NOCONN, 1 }, 1083fa88decSGarrett Wollman { "dumbtimer", 0, ALTF_DUMBTIMR, 1 }, 1093fa88decSGarrett Wollman { "intr", 0, ALTF_INTR, 1 }, 110a62dc406SDoug Rabson { "nfsv3", 0, ALTF_NFSV3, 1 }, 111a62dc406SDoug Rabson { "rdirplus", 0, ALTF_RDIRPLUS, 1 }, 112a62dc406SDoug Rabson { "mntudp", 0, ALTF_MNTUDP, 1 }, 1133fa88decSGarrett Wollman { "resvport", 0, ALTF_RESVPORT, 1 }, 1143fa88decSGarrett Wollman { "soft", 0, ALTF_SOFT, 1 }, 1153fa88decSGarrett Wollman { "tcp", 0, ALTF_TCP, 1 }, 116bc2cfd71SKarl Strickland { "port=", 0, ALTF_PORT, 1 }, 1172cd1c32cSDoug Rabson { "nfsv2", 0, ALTF_NFSV2, 1 }, 118c92e3fa5SPeter Wemm { "acregmin=", 0, ALTF_ACREGMIN, 1 }, 119c92e3fa5SPeter Wemm { "acregmax=", 0, ALTF_ACREGMAX, 1 }, 120c92e3fa5SPeter Wemm { "acdirmin=", 0, ALTF_ACDIRMIN, 1 }, 121c92e3fa5SPeter Wemm { "acdirmax=", 0, ALTF_ACDIRMAX, 1 }, 12213190d87SAlfred Perlstein { "lockd", 1, ALTF_NOLOCKD, 1 }, 1238fae3551SRodney W. Grimes { NULL } 1248fae3551SRodney W. Grimes }; 1258fae3551SRodney W. Grimes 1268fae3551SRodney W. Grimes struct nfs_args nfsdefargs = { 1274a4c5285SPeter Wemm NFS_ARGSVERSION, 1283d8f797aSMatthew Dillon NULL, 1298fae3551SRodney W. Grimes sizeof (struct sockaddr_in), 1308fae3551SRodney W. Grimes SOCK_DGRAM, 1318fae3551SRodney W. Grimes 0, 1323d8f797aSMatthew Dillon NULL, 133a62dc406SDoug Rabson 0, 134d5e1fb31SGuido van Rooij NFSMNT_RESVPORT, 1358fae3551SRodney W. Grimes NFS_WSIZE, 1368fae3551SRodney W. Grimes NFS_RSIZE, 137a62dc406SDoug Rabson NFS_READDIRSIZE, 138a62dc406SDoug Rabson 10, 1398fae3551SRodney W. Grimes NFS_RETRANS, 1408fae3551SRodney W. Grimes NFS_MAXGRPS, 1418fae3551SRodney W. Grimes NFS_DEFRAHEAD, 14291196234SPeter Wemm 0, /* was: NQ_DEFLEASE */ 14391196234SPeter Wemm NFS_MAXDEADTHRESH, /* was: NQ_DEADTHRESH */ 1443d8f797aSMatthew Dillon NULL, 145c92e3fa5SPeter Wemm /* args version 4 */ 146c92e3fa5SPeter Wemm NFS_MINATTRTIMO, 147c92e3fa5SPeter Wemm NFS_MAXATTRTIMO, 148c92e3fa5SPeter Wemm NFS_MINDIRATTRTIMO, 149c92e3fa5SPeter Wemm NFS_MAXDIRATTRTIMO, 1508fae3551SRodney W. Grimes }; 1518fae3551SRodney W. Grimes 152a3d8f94bSIan Dowse /* Table for af,sotype -> netid conversions. */ 153a3d8f94bSIan Dowse struct nc_protos { 154a3d8f94bSIan Dowse char *netid; 155a3d8f94bSIan Dowse int af; 156a3d8f94bSIan Dowse int sotype; 157a3d8f94bSIan Dowse } nc_protos[] = { 158a3d8f94bSIan Dowse {"udp", AF_INET, SOCK_DGRAM}, 159a3d8f94bSIan Dowse {"tcp", AF_INET, SOCK_STREAM}, 160a3d8f94bSIan Dowse {"udp6", AF_INET6, SOCK_DGRAM}, 161a3d8f94bSIan Dowse {"tcp6", AF_INET6, SOCK_STREAM}, 162a3d8f94bSIan Dowse {NULL} 163a3d8f94bSIan Dowse }; 164a3d8f94bSIan Dowse 1658fae3551SRodney W. Grimes struct nfhret { 1668fae3551SRodney W. Grimes u_long stat; 167a62dc406SDoug Rabson long vers; 168a62dc406SDoug Rabson long auth; 169a62dc406SDoug Rabson long fhsize; 170a62dc406SDoug Rabson u_char nfh[NFSX_V3FHMAX]; 1718fae3551SRodney W. Grimes }; 1728fae3551SRodney W. Grimes #define BGRND 1 1738fae3551SRodney W. Grimes #define ISBGRND 2 174e16873daSIan Dowse int retrycnt = -1; 1758fae3551SRodney W. Grimes int opflags = 0; 176a62dc406SDoug Rabson int nfsproto = IPPROTO_UDP; 177a62dc406SDoug Rabson int mnttcp_ok = 1; 178317d5933SIan Dowse char *portspec = NULL; /* Server nfs port; NULL means look up via rpcbind. */ 179317d5933SIan Dowse enum mountmode { 1802cd1c32cSDoug Rabson ANY, 1812cd1c32cSDoug Rabson V2, 1822cd1c32cSDoug Rabson V3 1832cd1c32cSDoug Rabson } mountmode = ANY; 1848fae3551SRodney W. Grimes 185317d5933SIan Dowse /* Return codes for nfs_tryproto. */ 186317d5933SIan Dowse enum tryret { 187317d5933SIan Dowse TRYRET_SUCCESS, 188317d5933SIan Dowse TRYRET_TIMEOUT, /* No response received. */ 189317d5933SIan Dowse TRYRET_REMOTEERR, /* Error received from remote server. */ 190317d5933SIan Dowse TRYRET_LOCALERR /* Local failure. */ 191317d5933SIan Dowse }; 192317d5933SIan Dowse 19385429990SWarner Losh int getnfsargs(char *, struct nfs_args *); 19485429990SWarner Losh /* void set_rpc_maxgrouplist(int); */ 195a3d8f94bSIan Dowse struct netconfig *getnetconf_cached(const char *netid); 196a3d8f94bSIan Dowse char *netidbytype(int af, int sotype); 19785429990SWarner Losh void usage(void) __dead2; 19885429990SWarner Losh int xdr_dir(XDR *, char *); 19985429990SWarner Losh int xdr_fh(XDR *, struct nfhret *); 200317d5933SIan Dowse enum tryret nfs_tryproto(struct nfs_args *nfsargsp, struct addrinfo *ai, 201317d5933SIan Dowse char *hostp, char *spec, char **errstr); 202317d5933SIan Dowse enum tryret returncode(enum clnt_stat stat, struct rpc_err *rpcerr); 2038fae3551SRodney W. Grimes 204b91ea324SDoug Rabson /* 205b91ea324SDoug Rabson * Used to set mount flags with getmntopts. Call with dir=TRUE to 20646fc8f78SPhilippe Charnier * initialize altflags from the current mount flags. Call with 207b91ea324SDoug Rabson * dir=FALSE to update mount flags with the new value of altflags after 208b91ea324SDoug Rabson * the call to getmntopts. 209b91ea324SDoug Rabson */ 210b91ea324SDoug Rabson static void 2113306ebd1SBruce Evans set_flags(int* altflags, int* nfsflags, int dir) 212b91ea324SDoug Rabson { 213b91ea324SDoug Rabson #define F2(af, nf) \ 214b91ea324SDoug Rabson if (dir) { \ 215b91ea324SDoug Rabson if (*nfsflags & NFSMNT_##nf) \ 216b91ea324SDoug Rabson *altflags |= ALTF_##af; \ 217b91ea324SDoug Rabson else \ 218b91ea324SDoug Rabson *altflags &= ~ALTF_##af; \ 219b91ea324SDoug Rabson } else { \ 220b91ea324SDoug Rabson if (*altflags & ALTF_##af) \ 221b91ea324SDoug Rabson *nfsflags |= NFSMNT_##nf; \ 222b91ea324SDoug Rabson else \ 223b91ea324SDoug Rabson *nfsflags &= ~NFSMNT_##nf; \ 224b91ea324SDoug Rabson } 225b91ea324SDoug Rabson #define F(f) F2(f,f) 226b91ea324SDoug Rabson 227b91ea324SDoug Rabson F(NOCONN); 228b91ea324SDoug Rabson F(DUMBTIMR); 229b91ea324SDoug Rabson F2(INTR, INT); 230b91ea324SDoug Rabson F(RDIRPLUS); 231b91ea324SDoug Rabson F(RESVPORT); 232b91ea324SDoug Rabson F(SOFT); 2337ed000f7SSemen Ustimenko F(ACREGMIN); 2347ed000f7SSemen Ustimenko F(ACREGMAX); 2357ed000f7SSemen Ustimenko F(ACDIRMIN); 2367ed000f7SSemen Ustimenko F(ACDIRMAX); 23713190d87SAlfred Perlstein F(NOLOCKD); 238b91ea324SDoug Rabson 239b91ea324SDoug Rabson #undef F 240b91ea324SDoug Rabson #undef F2 241b91ea324SDoug Rabson } 242b91ea324SDoug Rabson 2438fae3551SRodney W. Grimes int 2448fae3551SRodney W. Grimes main(argc, argv) 2458fae3551SRodney W. Grimes int argc; 2468fae3551SRodney W. Grimes char *argv[]; 2478fae3551SRodney W. Grimes { 2483d438ad6SDavid E. O'Brien int c; 2493d438ad6SDavid E. O'Brien struct nfs_args *nfsargsp; 2508fae3551SRodney W. Grimes struct nfs_args nfsargs; 251317d5933SIan Dowse int mntflags, altflags, nfssvc_flag, num; 2528fae3551SRodney W. Grimes char *name, *p, *spec; 25373dd3167SPoul-Henning Kamp char mntpath[MAXPATHLEN]; 2548fae3551SRodney W. Grimes 2558fae3551SRodney W. Grimes mntflags = 0; 2563fa88decSGarrett Wollman altflags = 0; 2578fae3551SRodney W. Grimes nfsargs = nfsdefargs; 2588fae3551SRodney W. Grimes nfsargsp = &nfsargs; 2598fae3551SRodney W. Grimes while ((c = getopt(argc, argv, 26013190d87SAlfred Perlstein "23a:bcdD:g:I:iLl:No:PpR:r:sTt:w:x:U")) != -1) 2618fae3551SRodney W. Grimes switch (c) { 2622cd1c32cSDoug Rabson case '2': 2632cd1c32cSDoug Rabson mountmode = V2; 2642cd1c32cSDoug Rabson break; 265a62dc406SDoug Rabson case '3': 2662cd1c32cSDoug Rabson mountmode = V3; 267a62dc406SDoug Rabson break; 2688fae3551SRodney W. Grimes case 'a': 2698fae3551SRodney W. Grimes num = strtol(optarg, &p, 10); 2708fae3551SRodney W. Grimes if (*p || num < 0) 2718fae3551SRodney W. Grimes errx(1, "illegal -a value -- %s", optarg); 2728fae3551SRodney W. Grimes nfsargsp->readahead = num; 2738fae3551SRodney W. Grimes nfsargsp->flags |= NFSMNT_READAHEAD; 2748fae3551SRodney W. Grimes break; 2758fae3551SRodney W. Grimes case 'b': 2768fae3551SRodney W. Grimes opflags |= BGRND; 2778fae3551SRodney W. Grimes break; 2788fae3551SRodney W. Grimes case 'c': 2798fae3551SRodney W. Grimes nfsargsp->flags |= NFSMNT_NOCONN; 2808fae3551SRodney W. Grimes break; 2818fae3551SRodney W. Grimes case 'D': 2828fae3551SRodney W. Grimes num = strtol(optarg, &p, 10); 2838fae3551SRodney W. Grimes if (*p || num <= 0) 2848fae3551SRodney W. Grimes errx(1, "illegal -D value -- %s", optarg); 2858fae3551SRodney W. Grimes nfsargsp->deadthresh = num; 2868fae3551SRodney W. Grimes nfsargsp->flags |= NFSMNT_DEADTHRESH; 2878fae3551SRodney W. Grimes break; 2888fae3551SRodney W. Grimes case 'd': 2898fae3551SRodney W. Grimes nfsargsp->flags |= NFSMNT_DUMBTIMR; 2908fae3551SRodney W. Grimes break; 2918360efbdSAlfred Perlstein #if 0 /* XXXX */ 2928fae3551SRodney W. Grimes case 'g': 2938fae3551SRodney W. Grimes num = strtol(optarg, &p, 10); 2948fae3551SRodney W. Grimes if (*p || num <= 0) 2958fae3551SRodney W. Grimes errx(1, "illegal -g value -- %s", optarg); 2968fae3551SRodney W. Grimes set_rpc_maxgrouplist(num); 2978fae3551SRodney W. Grimes nfsargsp->maxgrouplist = num; 2988fae3551SRodney W. Grimes nfsargsp->flags |= NFSMNT_MAXGRPS; 2998fae3551SRodney W. Grimes break; 3008360efbdSAlfred Perlstein #endif 301a62dc406SDoug Rabson case 'I': 302a62dc406SDoug Rabson num = strtol(optarg, &p, 10); 303a62dc406SDoug Rabson if (*p || num <= 0) 304a62dc406SDoug Rabson errx(1, "illegal -I value -- %s", optarg); 305a62dc406SDoug Rabson nfsargsp->readdirsize = num; 306a62dc406SDoug Rabson nfsargsp->flags |= NFSMNT_READDIRSIZE; 307a62dc406SDoug Rabson break; 3088fae3551SRodney W. Grimes case 'i': 3098fae3551SRodney W. Grimes nfsargsp->flags |= NFSMNT_INT; 3108fae3551SRodney W. Grimes break; 31113190d87SAlfred Perlstein case 'L': 31213190d87SAlfred Perlstein nfsargsp->flags |= NFSMNT_NOLOCKD; 31313190d87SAlfred Perlstein break; 3148fae3551SRodney W. Grimes case 'l': 315a62dc406SDoug Rabson nfsargsp->flags |= NFSMNT_RDIRPLUS; 3168fae3551SRodney W. Grimes break; 317cc75b131SJoerg Wunsch case 'N': 318cc75b131SJoerg Wunsch nfsargsp->flags &= ~NFSMNT_RESVPORT; 319cc75b131SJoerg Wunsch break; 3208fae3551SRodney W. Grimes case 'o': 321b91ea324SDoug Rabson altflags = 0; 3223306ebd1SBruce Evans set_flags(&altflags, &nfsargsp->flags, TRUE); 3232cd1c32cSDoug Rabson if (mountmode == V2) 3242cd1c32cSDoug Rabson altflags |= ALTF_NFSV2; 3252cd1c32cSDoug Rabson else if (mountmode == V3) 3262cd1c32cSDoug Rabson altflags |= ALTF_NFSV3; 3273fa88decSGarrett Wollman getmntopts(optarg, mopts, &mntflags, &altflags); 3283306ebd1SBruce Evans set_flags(&altflags, &nfsargsp->flags, FALSE); 3294db56604SPeter Wemm printf("altflags= %x, optarg = %s\n", altflags, optarg); 330b91ea324SDoug Rabson /* 331b91ea324SDoug Rabson * Handle altflags which don't map directly to 332b91ea324SDoug Rabson * mount flags. 333b91ea324SDoug Rabson */ 3343fa88decSGarrett Wollman if (altflags & ALTF_BG) 3353fa88decSGarrett Wollman opflags |= BGRND; 336a62dc406SDoug Rabson if (altflags & ALTF_MNTUDP) 337a62dc406SDoug Rabson mnttcp_ok = 0; 338a62dc406SDoug Rabson if (altflags & ALTF_TCP) { 3393fa88decSGarrett Wollman nfsargsp->sotype = SOCK_STREAM; 340a62dc406SDoug Rabson nfsproto = IPPROTO_TCP; 341a62dc406SDoug Rabson } 342317d5933SIan Dowse if (altflags & ALTF_PORT) { 343317d5933SIan Dowse /* 344317d5933SIan Dowse * XXX Converting from a string to an int 345317d5933SIan Dowse * and back again is silly, and we should 346317d5933SIan Dowse * allow /etc/services names. 347317d5933SIan Dowse */ 3484db56604SPeter Wemm p = strstr(optarg, "port="); 3494db56604SPeter Wemm if (p) { 350317d5933SIan Dowse asprintf(&portspec, "%d", 3514db56604SPeter Wemm atoi(p + 5)); 352317d5933SIan Dowse if (portspec == NULL) 353317d5933SIan Dowse err(1, "asprintf"); 354317d5933SIan Dowse } 3554db56604SPeter Wemm } 3562cd1c32cSDoug Rabson mountmode = ANY; 3572cd1c32cSDoug Rabson if (altflags & ALTF_NFSV2) 3582cd1c32cSDoug Rabson mountmode = V2; 3592cd1c32cSDoug Rabson if (altflags & ALTF_NFSV3) 3602cd1c32cSDoug Rabson mountmode = V3; 3614db56604SPeter Wemm if (altflags & ALTF_ACREGMIN) { 3624db56604SPeter Wemm p = strstr(optarg, "acregmin="); 3634db56604SPeter Wemm if (p) 3644db56604SPeter Wemm nfsargsp->acregmin = atoi(p + 9); 3654db56604SPeter Wemm } 3664db56604SPeter Wemm if (altflags & ALTF_ACREGMAX) { 3674db56604SPeter Wemm p = strstr(optarg, "acregmax="); 3684db56604SPeter Wemm if (p) 3694db56604SPeter Wemm nfsargsp->acregmax = atoi(p + 9); 3704db56604SPeter Wemm } 3714db56604SPeter Wemm if (altflags & ALTF_ACDIRMIN) { 3724db56604SPeter Wemm p = strstr(optarg, "acdirmin="); 3734db56604SPeter Wemm if (p) 3744db56604SPeter Wemm nfsargsp->acdirmin = atoi(p + 9); 3754db56604SPeter Wemm } 3764db56604SPeter Wemm if (altflags & ALTF_ACDIRMAX) { 3774db56604SPeter Wemm p = strstr(optarg, "acdirmax="); 3784db56604SPeter Wemm if (p) 3794db56604SPeter Wemm nfsargsp->acdirmax = atoi(p + 9); 3804db56604SPeter Wemm } 3818fae3551SRodney W. Grimes break; 3828fae3551SRodney W. Grimes case 'P': 383cc75b131SJoerg Wunsch /* obsolete for NFSMNT_RESVPORT, now default */ 3848fae3551SRodney W. Grimes break; 3858fae3551SRodney W. Grimes case 'R': 3868fae3551SRodney W. Grimes num = strtol(optarg, &p, 10); 387e16873daSIan Dowse if (*p || num < 0) 3888fae3551SRodney W. Grimes errx(1, "illegal -R value -- %s", optarg); 3898fae3551SRodney W. Grimes retrycnt = num; 3908fae3551SRodney W. Grimes break; 3918fae3551SRodney W. Grimes case 'r': 3928fae3551SRodney W. Grimes num = strtol(optarg, &p, 10); 3938fae3551SRodney W. Grimes if (*p || num <= 0) 3948fae3551SRodney W. Grimes errx(1, "illegal -r value -- %s", optarg); 3958fae3551SRodney W. Grimes nfsargsp->rsize = num; 3968fae3551SRodney W. Grimes nfsargsp->flags |= NFSMNT_RSIZE; 3978fae3551SRodney W. Grimes break; 3988fae3551SRodney W. Grimes case 's': 3998fae3551SRodney W. Grimes nfsargsp->flags |= NFSMNT_SOFT; 4008fae3551SRodney W. Grimes break; 4018fae3551SRodney W. Grimes case 'T': 4028fae3551SRodney W. Grimes nfsargsp->sotype = SOCK_STREAM; 403a62dc406SDoug Rabson nfsproto = IPPROTO_TCP; 4048fae3551SRodney W. Grimes break; 4058fae3551SRodney W. Grimes case 't': 4068fae3551SRodney W. Grimes num = strtol(optarg, &p, 10); 4078fae3551SRodney W. Grimes if (*p || num <= 0) 4088fae3551SRodney W. Grimes errx(1, "illegal -t value -- %s", optarg); 4098fae3551SRodney W. Grimes nfsargsp->timeo = num; 4108fae3551SRodney W. Grimes nfsargsp->flags |= NFSMNT_TIMEO; 4118fae3551SRodney W. Grimes break; 4128fae3551SRodney W. Grimes case 'w': 4138fae3551SRodney W. Grimes num = strtol(optarg, &p, 10); 4148fae3551SRodney W. Grimes if (*p || num <= 0) 4158fae3551SRodney W. Grimes errx(1, "illegal -w value -- %s", optarg); 4168fae3551SRodney W. Grimes nfsargsp->wsize = num; 4178fae3551SRodney W. Grimes nfsargsp->flags |= NFSMNT_WSIZE; 4188fae3551SRodney W. Grimes break; 4198fae3551SRodney W. Grimes case 'x': 4208fae3551SRodney W. Grimes num = strtol(optarg, &p, 10); 4218fae3551SRodney W. Grimes if (*p || num <= 0) 4228fae3551SRodney W. Grimes errx(1, "illegal -x value -- %s", optarg); 4238fae3551SRodney W. Grimes nfsargsp->retrans = num; 4248fae3551SRodney W. Grimes nfsargsp->flags |= NFSMNT_RETRANS; 4258fae3551SRodney W. Grimes break; 426a62dc406SDoug Rabson case 'U': 427a62dc406SDoug Rabson mnttcp_ok = 0; 428a62dc406SDoug Rabson break; 4298fae3551SRodney W. Grimes default: 4308fae3551SRodney W. Grimes usage(); 4318fae3551SRodney W. Grimes break; 4328fae3551SRodney W. Grimes } 4338fae3551SRodney W. Grimes argc -= optind; 4348fae3551SRodney W. Grimes argv += optind; 4358fae3551SRodney W. Grimes 4364a4c5285SPeter Wemm if (argc != 2) { 4372f21d07aSDavid Greenman usage(); 4384a4c5285SPeter Wemm /* NOTREACHED */ 4394a4c5285SPeter Wemm } 4408fae3551SRodney W. Grimes 4418fae3551SRodney W. Grimes spec = *argv++; 4428fae3551SRodney W. Grimes name = *argv; 4438fae3551SRodney W. Grimes 444e16873daSIan Dowse if (retrycnt == -1) 4452bc53e11SIan Dowse /* The default is to keep retrying forever. */ 4462bc53e11SIan Dowse retrycnt = 0; 4478fae3551SRodney W. Grimes if (!getnfsargs(spec, nfsargsp)) 4488fae3551SRodney W. Grimes exit(1); 449d599144dSGarrett Wollman 45073dd3167SPoul-Henning Kamp /* resolve the mountpoint with realpath(3) */ 45173dd3167SPoul-Henning Kamp (void)checkpath(name, mntpath); 45273dd3167SPoul-Henning Kamp 453526ba6d3SMaxime Henrion if (mount("nfs", mntpath, mntflags, nfsargsp)) 45473dd3167SPoul-Henning Kamp err(1, "%s", mntpath); 455a62dc406SDoug Rabson 4568fae3551SRodney W. Grimes exit(0); 4578fae3551SRodney W. Grimes } 4588fae3551SRodney W. Grimes 4598fae3551SRodney W. Grimes int 4608fae3551SRodney W. Grimes getnfsargs(spec, nfsargsp) 4618fae3551SRodney W. Grimes char *spec; 4628fae3551SRodney W. Grimes struct nfs_args *nfsargsp; 4638fae3551SRodney W. Grimes { 4648360efbdSAlfred Perlstein struct addrinfo hints, *ai_nfs, *ai; 465317d5933SIan Dowse enum tryret ret; 466317d5933SIan Dowse int ecode, speclen, remoteerr; 467317d5933SIan Dowse char *hostp, *delimp, *errstr; 46866a84ea7SBrian Feldman size_t len; 4698fae3551SRodney W. Grimes static char nam[MNAMELEN + 1]; 4708fae3551SRodney W. Grimes 4718360efbdSAlfred Perlstein if ((delimp = strrchr(spec, ':')) != NULL) { 4728fae3551SRodney W. Grimes hostp = spec; 4738fae3551SRodney W. Grimes spec = delimp + 1; 47473dd3167SPoul-Henning Kamp } else if ((delimp = strrchr(spec, '@')) != NULL) { 47573dd3167SPoul-Henning Kamp warnx("path@server syntax is deprecated, use server:path"); 47673dd3167SPoul-Henning Kamp hostp = delimp + 1; 4778fae3551SRodney W. Grimes } else { 47873dd3167SPoul-Henning Kamp warnx("no <host>:<dirpath> nfs-name"); 4798fae3551SRodney W. Grimes return (0); 4808fae3551SRodney W. Grimes } 4818fae3551SRodney W. Grimes *delimp = '\0'; 48273dd3167SPoul-Henning Kamp 48373dd3167SPoul-Henning Kamp /* 48473dd3167SPoul-Henning Kamp * If there has been a trailing slash at mounttime it seems 48573dd3167SPoul-Henning Kamp * that some mountd implementations fail to remove the mount 48673dd3167SPoul-Henning Kamp * entries from their mountlist while unmounting. 48773dd3167SPoul-Henning Kamp */ 48866a84ea7SBrian Feldman for (speclen = strlen(spec); 48966a84ea7SBrian Feldman speclen > 1 && spec[speclen - 1] == '/'; 49066a84ea7SBrian Feldman speclen--) 49173dd3167SPoul-Henning Kamp spec[speclen - 1] = '\0'; 49273dd3167SPoul-Henning Kamp if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) { 49373dd3167SPoul-Henning Kamp warnx("%s:%s: %s", hostp, spec, strerror(ENAMETOOLONG)); 49473dd3167SPoul-Henning Kamp return (0); 49573dd3167SPoul-Henning Kamp } 49673dd3167SPoul-Henning Kamp /* Make both '@' and ':' notations equal */ 49766a84ea7SBrian Feldman if (*hostp != '\0') { 49866a84ea7SBrian Feldman len = strlen(hostp); 49966a84ea7SBrian Feldman memmove(nam, hostp, len); 50066a84ea7SBrian Feldman nam[len] = ':'; 50166a84ea7SBrian Feldman memmove(nam + len + 1, spec, speclen); 50266a84ea7SBrian Feldman nam[len + speclen + 1] = '\0'; 50366a84ea7SBrian Feldman } 5048fae3551SRodney W. Grimes 5058fae3551SRodney W. Grimes /* 50691196234SPeter Wemm * Handle an internet host address. 5078fae3551SRodney W. Grimes */ 5088360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 5098360efbdSAlfred Perlstein hints.ai_flags = AI_NUMERICHOST; 5108360efbdSAlfred Perlstein hints.ai_socktype = nfsargsp->sotype; 51191196234SPeter Wemm if (getaddrinfo(hostp, portspec, &hints, &ai_nfs) != 0) { 5128360efbdSAlfred Perlstein hints.ai_flags = 0; 513317d5933SIan Dowse if ((ecode = getaddrinfo(hostp, portspec, &hints, &ai_nfs)) 514317d5933SIan Dowse != 0) { 515317d5933SIan Dowse if (portspec == NULL) 516317d5933SIan Dowse errx(1, "%s: %s", hostp, gai_strerror(ecode)); 517317d5933SIan Dowse else 518317d5933SIan Dowse errx(1, "%s:%s: %s", hostp, portspec, 5198360efbdSAlfred Perlstein gai_strerror(ecode)); 5208360efbdSAlfred Perlstein return (0); 5218360efbdSAlfred Perlstein } 5228360efbdSAlfred Perlstein } 5238fae3551SRodney W. Grimes 524317d5933SIan Dowse ret = TRYRET_LOCALERR; 525e16873daSIan Dowse for (;;) { 526deffdffaSAndrey A. Chernov /* 527317d5933SIan Dowse * Try each entry returned by getaddrinfo(). Note the 528317d5933SIan Dowse * occurence of remote errors by setting `remoteerr'. 529deffdffaSAndrey A. Chernov */ 530317d5933SIan Dowse remoteerr = 0; 531317d5933SIan Dowse for (ai = ai_nfs; ai != NULL; ai = ai->ai_next) { 532317d5933SIan Dowse ret = nfs_tryproto(nfsargsp, ai, hostp, spec, &errstr); 533317d5933SIan Dowse if (ret == TRYRET_SUCCESS) 534317d5933SIan Dowse break; 535317d5933SIan Dowse if (ret != TRYRET_LOCALERR) 536317d5933SIan Dowse remoteerr = 1; 537317d5933SIan Dowse if ((opflags & ISBGRND) == 0) 538317d5933SIan Dowse fprintf(stderr, "%s\n", errstr); 539deffdffaSAndrey A. Chernov } 540317d5933SIan Dowse if (ret == TRYRET_SUCCESS) 541317d5933SIan Dowse break; 542deffdffaSAndrey A. Chernov 543e16873daSIan Dowse /* Exit if all errors were local. */ 544e16873daSIan Dowse if (!remoteerr) 545deffdffaSAndrey A. Chernov exit(1); 546317d5933SIan Dowse 547e16873daSIan Dowse /* 548e16873daSIan Dowse * If retrycnt == 0, we are to keep retrying forever. 549e16873daSIan Dowse * Otherwise decrement it, and exit if it hits zero. 550e16873daSIan Dowse */ 551e16873daSIan Dowse if (retrycnt != 0 && --retrycnt == 0) 552317d5933SIan Dowse exit(1); 553317d5933SIan Dowse 554317d5933SIan Dowse if ((opflags & (BGRND | ISBGRND)) == BGRND) { 555317d5933SIan Dowse warnx("Cannot immediately mount %s:%s, backgrounding", 556317d5933SIan Dowse hostp, spec); 557317d5933SIan Dowse opflags |= ISBGRND; 558317d5933SIan Dowse if (daemon(0, 0) != 0) 559317d5933SIan Dowse err(1, "daemon"); 5608fae3551SRodney W. Grimes } 5618fae3551SRodney W. Grimes sleep(60); 5628fae3551SRodney W. Grimes } 5638360efbdSAlfred Perlstein freeaddrinfo(ai_nfs); 5648fae3551SRodney W. Grimes nfsargsp->hostname = nam; 565a69497d7SMatthew Dillon /* Add mounted file system to PATH_MOUNTTAB */ 566a69497d7SMatthew Dillon if (!add_mtab(hostp, spec)) 567a69497d7SMatthew Dillon warnx("can't update %s for %s:%s", PATH_MOUNTTAB, hostp, spec); 5688fae3551SRodney W. Grimes return (1); 5698fae3551SRodney W. Grimes } 5708fae3551SRodney W. Grimes 5718fae3551SRodney W. Grimes /* 572317d5933SIan Dowse * Try to set up the NFS arguments according to the address 573317d5933SIan Dowse * family, protocol (and possibly port) specified in `ai'. 574317d5933SIan Dowse * 575317d5933SIan Dowse * Returns TRYRET_SUCCESS if successful, or: 576317d5933SIan Dowse * TRYRET_TIMEOUT The server did not respond. 577317d5933SIan Dowse * TRYRET_REMOTEERR The server reported an error. 578317d5933SIan Dowse * TRYRET_LOCALERR Local failure. 579317d5933SIan Dowse * 580317d5933SIan Dowse * In all error cases, *errstr will be set to a statically-allocated string 581317d5933SIan Dowse * describing the error. 582317d5933SIan Dowse */ 583317d5933SIan Dowse enum tryret 584317d5933SIan Dowse nfs_tryproto(struct nfs_args *nfsargsp, struct addrinfo *ai, char *hostp, 585317d5933SIan Dowse char *spec, char **errstr) 586317d5933SIan Dowse { 587317d5933SIan Dowse static char errbuf[256]; 588317d5933SIan Dowse struct sockaddr_storage nfs_ss; 589317d5933SIan Dowse struct netbuf nfs_nb; 590317d5933SIan Dowse struct nfhret nfhret; 591317d5933SIan Dowse struct timeval try; 592317d5933SIan Dowse struct rpc_err rpcerr; 593317d5933SIan Dowse CLIENT *clp; 594317d5933SIan Dowse struct netconfig *nconf, *nconf_mnt; 595317d5933SIan Dowse char *netid, *netid_mnt; 596eca1c24eSIan Dowse int doconnect, nfsvers, mntvers; 597317d5933SIan Dowse enum clnt_stat stat; 598317d5933SIan Dowse enum mountmode trymntmode; 599317d5933SIan Dowse 600317d5933SIan Dowse trymntmode = mountmode; 601317d5933SIan Dowse errbuf[0] = '\0'; 602317d5933SIan Dowse *errstr = errbuf; 603317d5933SIan Dowse 604a3d8f94bSIan Dowse if ((netid = netidbytype(ai->ai_family, nfsargsp->sotype)) == NULL) { 605a3d8f94bSIan Dowse snprintf(errbuf, sizeof errbuf, 606a3d8f94bSIan Dowse "af %d sotype %d not supported", ai->ai_family, 607a3d8f94bSIan Dowse nfsargsp->sotype); 608a3d8f94bSIan Dowse return (TRYRET_LOCALERR); 609a3d8f94bSIan Dowse } 610a3d8f94bSIan Dowse if ((nconf = getnetconf_cached(netid)) == NULL) { 611317d5933SIan Dowse snprintf(errbuf, sizeof errbuf, "%s: %s", netid, nc_sperror()); 612317d5933SIan Dowse return (TRYRET_LOCALERR); 613317d5933SIan Dowse } 614317d5933SIan Dowse /* The RPCPROG_MNT netid may be different. */ 615317d5933SIan Dowse if (mnttcp_ok) { 616ba33efd9SIan Dowse netid_mnt = netid; 617317d5933SIan Dowse nconf_mnt = nconf; 618317d5933SIan Dowse } else { 619a3d8f94bSIan Dowse if ((netid_mnt = netidbytype(ai->ai_family, SOCK_DGRAM)) 620a3d8f94bSIan Dowse == NULL) { 621a3d8f94bSIan Dowse snprintf(errbuf, sizeof errbuf, 622a3d8f94bSIan Dowse "af %d sotype SOCK_DGRAM not supported", 623a3d8f94bSIan Dowse ai->ai_family); 624a3d8f94bSIan Dowse return (TRYRET_LOCALERR); 625a3d8f94bSIan Dowse } 626a3d8f94bSIan Dowse if ((nconf_mnt = getnetconf_cached(netid_mnt)) == NULL) { 627ba33efd9SIan Dowse snprintf(errbuf, sizeof errbuf, "%s: %s", netid_mnt, 628317d5933SIan Dowse nc_sperror()); 629317d5933SIan Dowse return (TRYRET_LOCALERR); 630317d5933SIan Dowse } 631317d5933SIan Dowse } 632317d5933SIan Dowse 633317d5933SIan Dowse tryagain: 634317d5933SIan Dowse if (trymntmode == V2) { 635317d5933SIan Dowse nfsvers = 2; 636317d5933SIan Dowse mntvers = 1; 637317d5933SIan Dowse } else { 638317d5933SIan Dowse nfsvers = 3; 639317d5933SIan Dowse mntvers = 3; 640317d5933SIan Dowse } 641317d5933SIan Dowse 642317d5933SIan Dowse if (portspec != NULL) { 643317d5933SIan Dowse /* `ai' contains the complete nfsd sockaddr. */ 644317d5933SIan Dowse nfs_nb.buf = ai->ai_addr; 645317d5933SIan Dowse nfs_nb.len = nfs_nb.maxlen = ai->ai_addrlen; 646317d5933SIan Dowse } else { 647317d5933SIan Dowse /* Ask the remote rpcbind. */ 648317d5933SIan Dowse nfs_nb.buf = &nfs_ss; 649317d5933SIan Dowse nfs_nb.len = nfs_nb.maxlen = sizeof nfs_ss; 650317d5933SIan Dowse 651317d5933SIan Dowse if (!rpcb_getaddr(RPCPROG_NFS, nfsvers, nconf, &nfs_nb, 652317d5933SIan Dowse hostp)) { 653317d5933SIan Dowse if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH && 654317d5933SIan Dowse trymntmode == ANY) { 655317d5933SIan Dowse trymntmode = V2; 656317d5933SIan Dowse goto tryagain; 657317d5933SIan Dowse } 658317d5933SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", 659317d5933SIan Dowse netid, hostp, spec, 660317d5933SIan Dowse clnt_spcreateerror("RPCPROG_NFS")); 661317d5933SIan Dowse return (returncode(rpc_createerr.cf_stat, 662317d5933SIan Dowse &rpc_createerr.cf_error)); 663317d5933SIan Dowse } 664317d5933SIan Dowse } 665317d5933SIan Dowse 666317d5933SIan Dowse /* Check that the server (nfsd) responds on the port we have chosen. */ 667317d5933SIan Dowse clp = clnt_tli_create(RPC_ANYFD, nconf, &nfs_nb, RPCPROG_NFS, nfsvers, 668317d5933SIan Dowse 0, 0); 669317d5933SIan Dowse if (clp == NULL) { 670317d5933SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid, 671317d5933SIan Dowse hostp, spec, clnt_spcreateerror("nfsd: RPCPROG_NFS")); 672317d5933SIan Dowse return (returncode(rpc_createerr.cf_stat, 673317d5933SIan Dowse &rpc_createerr.cf_error)); 674317d5933SIan Dowse } 675fd0b613aSIan Dowse if (nfsargsp->sotype == SOCK_DGRAM && 676fd0b613aSIan Dowse !(nfsargsp->flags & NFSMNT_NOCONN)) { 677eca1c24eSIan Dowse /* 678eca1c24eSIan Dowse * Use connect(), to match what the kernel does. This 679eca1c24eSIan Dowse * catches cases where the server responds from the 680eca1c24eSIan Dowse * wrong source address. 681eca1c24eSIan Dowse */ 682eca1c24eSIan Dowse doconnect = 1; 683eca1c24eSIan Dowse if (!clnt_control(clp, CLSET_CONNECT, (char *)&doconnect)) { 684eca1c24eSIan Dowse clnt_destroy(clp); 685eca1c24eSIan Dowse snprintf(errbuf, sizeof errbuf, 686eca1c24eSIan Dowse "[%s] %s:%s: CLSET_CONNECT failed", netid, hostp, 687eca1c24eSIan Dowse spec); 688eca1c24eSIan Dowse return (TRYRET_LOCALERR); 689eca1c24eSIan Dowse } 690eca1c24eSIan Dowse } 691eca1c24eSIan Dowse 692317d5933SIan Dowse try.tv_sec = 10; 693317d5933SIan Dowse try.tv_usec = 0; 694317d5933SIan Dowse stat = clnt_call(clp, NFSPROC_NULL, xdr_void, NULL, xdr_void, NULL, 695317d5933SIan Dowse try); 696317d5933SIan Dowse if (stat != RPC_SUCCESS) { 697317d5933SIan Dowse if (stat == RPC_PROGVERSMISMATCH && trymntmode == ANY) { 698317d5933SIan Dowse clnt_destroy(clp); 699317d5933SIan Dowse trymntmode = V2; 700317d5933SIan Dowse goto tryagain; 701317d5933SIan Dowse } 702317d5933SIan Dowse clnt_geterr(clp, &rpcerr); 703317d5933SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid, 704317d5933SIan Dowse hostp, spec, clnt_sperror(clp, "NFSPROC_NULL")); 705317d5933SIan Dowse clnt_destroy(clp); 706317d5933SIan Dowse return (returncode(stat, &rpcerr)); 707317d5933SIan Dowse } 708317d5933SIan Dowse clnt_destroy(clp); 709317d5933SIan Dowse 710317d5933SIan Dowse /* Send the RPCMNT_MOUNT RPC to get the root filehandle. */ 711317d5933SIan Dowse try.tv_sec = 10; 712317d5933SIan Dowse try.tv_usec = 0; 713317d5933SIan Dowse clp = clnt_tp_create(hostp, RPCPROG_MNT, mntvers, nconf_mnt); 714317d5933SIan Dowse if (clp == NULL) { 715ba33efd9SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 716317d5933SIan Dowse hostp, spec, clnt_spcreateerror("RPCMNT: clnt_create")); 717317d5933SIan Dowse return (returncode(rpc_createerr.cf_stat, 718317d5933SIan Dowse &rpc_createerr.cf_error)); 719317d5933SIan Dowse } 720317d5933SIan Dowse clp->cl_auth = authsys_create_default(); 721317d5933SIan Dowse nfhret.auth = RPCAUTH_UNIX; 722317d5933SIan Dowse nfhret.vers = mntvers; 723317d5933SIan Dowse stat = clnt_call(clp, RPCMNT_MOUNT, xdr_dir, spec, xdr_fh, &nfhret, 724317d5933SIan Dowse try); 725317d5933SIan Dowse auth_destroy(clp->cl_auth); 726317d5933SIan Dowse if (stat != RPC_SUCCESS) { 727317d5933SIan Dowse if (stat == RPC_PROGVERSMISMATCH && trymntmode == ANY) { 728317d5933SIan Dowse clnt_destroy(clp); 729317d5933SIan Dowse trymntmode = V2; 730317d5933SIan Dowse goto tryagain; 731317d5933SIan Dowse } 732317d5933SIan Dowse clnt_geterr(clp, &rpcerr); 733ba33efd9SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 734317d5933SIan Dowse hostp, spec, clnt_sperror(clp, "RPCPROG_MNT")); 735317d5933SIan Dowse clnt_destroy(clp); 736317d5933SIan Dowse return (returncode(stat, &rpcerr)); 737317d5933SIan Dowse } 738317d5933SIan Dowse clnt_destroy(clp); 739317d5933SIan Dowse 740317d5933SIan Dowse if (nfhret.stat != 0) { 741ba33efd9SIan Dowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 742317d5933SIan Dowse hostp, spec, strerror(nfhret.stat)); 743317d5933SIan Dowse return (TRYRET_REMOTEERR); 744317d5933SIan Dowse } 745317d5933SIan Dowse 746317d5933SIan Dowse /* 747317d5933SIan Dowse * Store the filehandle and server address in nfsargsp, making 748317d5933SIan Dowse * sure to copy any locally allocated structures. 749317d5933SIan Dowse */ 750317d5933SIan Dowse nfsargsp->addrlen = nfs_nb.len; 751317d5933SIan Dowse nfsargsp->addr = malloc(nfsargsp->addrlen); 752317d5933SIan Dowse nfsargsp->fhsize = nfhret.fhsize; 753317d5933SIan Dowse nfsargsp->fh = malloc(nfsargsp->fhsize); 754317d5933SIan Dowse if (nfsargsp->addr == NULL || nfsargsp->fh == NULL) 755317d5933SIan Dowse err(1, "malloc"); 756317d5933SIan Dowse bcopy(nfs_nb.buf, nfsargsp->addr, nfsargsp->addrlen); 757317d5933SIan Dowse bcopy(nfhret.nfh, nfsargsp->fh, nfsargsp->fhsize); 758317d5933SIan Dowse 759317d5933SIan Dowse if (nfsvers == 3) 760317d5933SIan Dowse nfsargsp->flags |= NFSMNT_NFSV3; 761317d5933SIan Dowse else 762317d5933SIan Dowse nfsargsp->flags &= ~NFSMNT_NFSV3; 763317d5933SIan Dowse 764317d5933SIan Dowse return (TRYRET_SUCCESS); 765317d5933SIan Dowse } 766317d5933SIan Dowse 767317d5933SIan Dowse 768317d5933SIan Dowse /* 769317d5933SIan Dowse * Catagorise a RPC return status and error into an `enum tryret' 770317d5933SIan Dowse * return code. 771317d5933SIan Dowse */ 772317d5933SIan Dowse enum tryret 773317d5933SIan Dowse returncode(enum clnt_stat stat, struct rpc_err *rpcerr) 774317d5933SIan Dowse { 775317d5933SIan Dowse switch (stat) { 776317d5933SIan Dowse case RPC_TIMEDOUT: 777317d5933SIan Dowse return (TRYRET_TIMEOUT); 778317d5933SIan Dowse case RPC_PMAPFAILURE: 779317d5933SIan Dowse case RPC_PROGNOTREGISTERED: 780317d5933SIan Dowse case RPC_PROGVERSMISMATCH: 781eca1c24eSIan Dowse /* XXX, these can be local or remote. */ 782eca1c24eSIan Dowse case RPC_CANTSEND: 783eca1c24eSIan Dowse case RPC_CANTRECV: 784317d5933SIan Dowse return (TRYRET_REMOTEERR); 785317d5933SIan Dowse case RPC_SYSTEMERROR: 786317d5933SIan Dowse switch (rpcerr->re_errno) { 787317d5933SIan Dowse case ETIMEDOUT: 788317d5933SIan Dowse return (TRYRET_TIMEOUT); 789317d5933SIan Dowse case ENOMEM: 790317d5933SIan Dowse break; 791317d5933SIan Dowse default: 792317d5933SIan Dowse return (TRYRET_REMOTEERR); 793317d5933SIan Dowse } 794317d5933SIan Dowse /* FALLTHROUGH */ 795317d5933SIan Dowse default: 796317d5933SIan Dowse break; 797317d5933SIan Dowse } 798317d5933SIan Dowse return (TRYRET_LOCALERR); 799317d5933SIan Dowse } 800317d5933SIan Dowse 801317d5933SIan Dowse /* 802a3d8f94bSIan Dowse * Look up a netid based on an address family and socket type. 803a3d8f94bSIan Dowse * `af' is the address family, and `sotype' is SOCK_DGRAM or SOCK_STREAM. 804a3d8f94bSIan Dowse * 805a3d8f94bSIan Dowse * XXX there should be a library function for this. 806a3d8f94bSIan Dowse */ 807a3d8f94bSIan Dowse char * 808a3d8f94bSIan Dowse netidbytype(int af, int sotype) { 809a3d8f94bSIan Dowse struct nc_protos *p; 810a3d8f94bSIan Dowse 811a3d8f94bSIan Dowse for (p = nc_protos; p->netid != NULL; p++) { 812a3d8f94bSIan Dowse if (af != p->af || sotype != p->sotype) 813a3d8f94bSIan Dowse continue; 814a3d8f94bSIan Dowse return (p->netid); 815a3d8f94bSIan Dowse } 816a3d8f94bSIan Dowse return (NULL); 817a3d8f94bSIan Dowse } 818a3d8f94bSIan Dowse 819a3d8f94bSIan Dowse /* 820a3d8f94bSIan Dowse * Look up a netconfig entry based on a netid, and cache the result so 821a3d8f94bSIan Dowse * that we don't need to remember to call freenetconfigent(). 822a3d8f94bSIan Dowse * 823a3d8f94bSIan Dowse * Otherwise it behaves just like getnetconfigent(), so nc_*error() 824a3d8f94bSIan Dowse * work on failure. 825a3d8f94bSIan Dowse */ 826a3d8f94bSIan Dowse struct netconfig * 827a3d8f94bSIan Dowse getnetconf_cached(const char *netid) { 828a3d8f94bSIan Dowse static struct nc_entry { 829a3d8f94bSIan Dowse struct netconfig *nconf; 830a3d8f94bSIan Dowse struct nc_entry *next; 831a3d8f94bSIan Dowse } *head; 832a3d8f94bSIan Dowse struct nc_entry *p; 833a3d8f94bSIan Dowse struct netconfig *nconf; 834a3d8f94bSIan Dowse 835a3d8f94bSIan Dowse for (p = head; p != NULL; p = p->next) 836a3d8f94bSIan Dowse if (strcmp(netid, p->nconf->nc_netid) == 0) 837a3d8f94bSIan Dowse return (p->nconf); 838a3d8f94bSIan Dowse 839a3d8f94bSIan Dowse if ((nconf = getnetconfigent(netid)) == NULL) 840a3d8f94bSIan Dowse return (NULL); 841a3d8f94bSIan Dowse if ((p = malloc(sizeof(*p))) == NULL) 842a3d8f94bSIan Dowse err(1, "malloc"); 843a3d8f94bSIan Dowse p->nconf = nconf; 844a3d8f94bSIan Dowse p->next = head; 845a3d8f94bSIan Dowse head = p; 846a3d8f94bSIan Dowse 847a3d8f94bSIan Dowse return (p->nconf); 848a3d8f94bSIan Dowse } 849a3d8f94bSIan Dowse 850a3d8f94bSIan Dowse /* 8518fae3551SRodney W. Grimes * xdr routines for mount rpc's 8528fae3551SRodney W. Grimes */ 8538fae3551SRodney W. Grimes int 8548fae3551SRodney W. Grimes xdr_dir(xdrsp, dirp) 8558fae3551SRodney W. Grimes XDR *xdrsp; 8568fae3551SRodney W. Grimes char *dirp; 8578fae3551SRodney W. Grimes { 8588fae3551SRodney W. Grimes return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 8598fae3551SRodney W. Grimes } 8608fae3551SRodney W. Grimes 8618fae3551SRodney W. Grimes int 8628fae3551SRodney W. Grimes xdr_fh(xdrsp, np) 8638fae3551SRodney W. Grimes XDR *xdrsp; 8643d438ad6SDavid E. O'Brien struct nfhret *np; 8658fae3551SRodney W. Grimes { 8663d438ad6SDavid E. O'Brien int i; 867a62dc406SDoug Rabson long auth, authcnt, authfnd = 0; 868a62dc406SDoug Rabson 869a62dc406SDoug Rabson if (!xdr_u_long(xdrsp, &np->stat)) 8708fae3551SRodney W. Grimes return (0); 8718fae3551SRodney W. Grimes if (np->stat) 8728fae3551SRodney W. Grimes return (1); 873a62dc406SDoug Rabson switch (np->vers) { 874a62dc406SDoug Rabson case 1: 875a62dc406SDoug Rabson np->fhsize = NFSX_V2FH; 876a62dc406SDoug Rabson return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFSX_V2FH)); 877a62dc406SDoug Rabson case 3: 878a62dc406SDoug Rabson if (!xdr_long(xdrsp, &np->fhsize)) 879a62dc406SDoug Rabson return (0); 880a62dc406SDoug Rabson if (np->fhsize <= 0 || np->fhsize > NFSX_V3FHMAX) 881a62dc406SDoug Rabson return (0); 882a62dc406SDoug Rabson if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize)) 883a62dc406SDoug Rabson return (0); 884a62dc406SDoug Rabson if (!xdr_long(xdrsp, &authcnt)) 885a62dc406SDoug Rabson return (0); 886a62dc406SDoug Rabson for (i = 0; i < authcnt; i++) { 887a62dc406SDoug Rabson if (!xdr_long(xdrsp, &auth)) 888a62dc406SDoug Rabson return (0); 889a62dc406SDoug Rabson if (auth == np->auth) 890a62dc406SDoug Rabson authfnd++; 891a62dc406SDoug Rabson } 892a62dc406SDoug Rabson /* 893a62dc406SDoug Rabson * Some servers, such as DEC's OSF/1 return a nil authenticator 894a62dc406SDoug Rabson * list to indicate RPCAUTH_UNIX. 895a62dc406SDoug Rabson */ 896a62dc406SDoug Rabson if (!authfnd && (authcnt > 0 || np->auth != RPCAUTH_UNIX)) 897a62dc406SDoug Rabson np->stat = EAUTH; 898a62dc406SDoug Rabson return (1); 899a62dc406SDoug Rabson }; 900a62dc406SDoug Rabson return (0); 9018fae3551SRodney W. Grimes } 9028fae3551SRodney W. Grimes 903eaa86f9dSBruce Evans void 9048fae3551SRodney W. Grimes usage() 9058fae3551SRodney W. Grimes { 90646fc8f78SPhilippe Charnier (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", 90746fc8f78SPhilippe Charnier "usage: mount_nfs [-23KNPTUbcdilqs] [-D deadthresh] [-I readdirsize]", 90891196234SPeter Wemm " [-R retrycnt] [-a maxreadahead]", 90946fc8f78SPhilippe Charnier " [-g maxgroups] [-m realm] [-o options] [-r readsize]", 91046fc8f78SPhilippe Charnier " [-t timeout] [-w writesize] [-x retrans] rhost:path node"); 9118fae3551SRodney W. Grimes exit(1); 9128fae3551SRodney W. Grimes } 913