mount_nfs.c revision 176384
1184588Sdfr/* 2184588Sdfr * copyright (c) 2003 3184588Sdfr * the regents of the university of michigan 4184588Sdfr * all rights reserved 5184588Sdfr * 6184588Sdfr * permission is granted to use, copy, create derivative works and redistribute 7184588Sdfr * this software and such derivative works for any purpose, so long as the name 8184588Sdfr * of the university of michigan is not used in any advertising or publicity 9184588Sdfr * pertaining to the use or distribution of this software without specific, 10184588Sdfr * written prior authorization. if the above copyright notice or any other 11184588Sdfr * identification of the university of michigan is included in any copy of any 12184588Sdfr * portion of this software, then the disclaimer below must also be included. 13184588Sdfr * 14184588Sdfr * this software is provided as is, without representation from the university 15184588Sdfr * of michigan as to its fitness for any purpose, and without warranty by the 16184588Sdfr * university of michigan of any kind, either express or implied, including 17184588Sdfr * without limitation the implied warranties of merchantability and fitness for 18184588Sdfr * a particular purpose. the regents of the university of michigan shall not be 19184588Sdfr * liable for any damages, including special, indirect, incidental, or 20184588Sdfr * consequential damages, with respect to any claim arising out of or in 21184588Sdfr * connection with the use of the software, even if it has been or is hereafter 22184588Sdfr * advised of the possibility of such damages. 23184588Sdfr */ 24184588Sdfr 25184588Sdfr/* 26184588Sdfr * Copyright (c) 1992, 1993, 1994 27184588Sdfr * The Regents of the University of California. All rights reserved. 28184588Sdfr * 29184588Sdfr * This code is derived from software contributed to Berkeley by 30184588Sdfr * Rick Macklem at The University of Guelph. 31184588Sdfr * 32184588Sdfr * Redistribution and use in source and binary forms, with or without 33184588Sdfr * modification, are permitted provided that the following conditions 34184588Sdfr * are met: 35184588Sdfr * 1. Redistributions of source code must retain the above copyright 36184588Sdfr * notice, this list of conditions and the following disclaimer. 37184588Sdfr * 2. Redistributions in binary form must reproduce the above copyright 38184588Sdfr * notice, this list of conditions and the following disclaimer in the 39184588Sdfr * documentation and/or other materials provided with the distribution. 40184588Sdfr * 4. Neither the name of the University nor the names of its contributors 41184588Sdfr * may be used to endorse or promote products derived from this software 42184588Sdfr * without specific prior written permission. 43184588Sdfr * 44184588Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 45184588Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46184588Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47184588Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 48184588Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 49184588Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 50184588Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51184588Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52184588Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53184588Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54184588Sdfr * SUCH DAMAGE. 55184588Sdfr */ 56184588Sdfr 57184588Sdfr#if 0 58184588Sdfr#ifndef lint 59184588Sdfrstatic const char copyright[] = 60184588Sdfr"@(#) Copyright (c) 1992, 1993, 1994\n\ 61184588Sdfr The Regents of the University of California. All rights reserved.\n"; 62184588Sdfr#endif /* not lint */ 63184588Sdfr 64184588Sdfr#ifndef lint 65184588Sdfrstatic char sccsid[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95"; 66184588Sdfr#endif /* not lint */ 67184588Sdfr#endif 68184588Sdfr#include <sys/cdefs.h> 69184588Sdfr__FBSDID("$FreeBSD: head/sbin/mount_nfs/mount_nfs.c 176384 2008-02-18 10:24:47Z yar $"); 70184588Sdfr 71184588Sdfr#include <sys/param.h> 72184588Sdfr#include <sys/mount.h> 73184588Sdfr#include <sys/socket.h> 74184588Sdfr#include <sys/stat.h> 75184588Sdfr#include <sys/syslog.h> 76184588Sdfr#include <sys/uio.h> 77184588Sdfr 78184588Sdfr#include <rpc/rpc.h> 79184588Sdfr#include <rpc/pmap_clnt.h> 80184588Sdfr#include <rpc/pmap_prot.h> 81184588Sdfr 82184588Sdfr#include <nfs/rpcv2.h> 83184588Sdfr#include <nfs/nfsproto.h> 84184588Sdfr#include <nfsclient/nfs.h> 85184588Sdfr#include <nfsclient/nfsargs.h> 86184588Sdfr 87184588Sdfr#include <arpa/inet.h> 88184588Sdfr 89184588Sdfr#include <ctype.h> 90184588Sdfr#include <err.h> 91184588Sdfr#include <errno.h> 92184588Sdfr#include <fcntl.h> 93184588Sdfr#include <netdb.h> 94184588Sdfr#include <stdio.h> 95184588Sdfr#include <stdlib.h> 96184588Sdfr#include <string.h> 97184588Sdfr#include <strings.h> 98184588Sdfr#include <sysexits.h> 99184588Sdfr#include <unistd.h> 100184588Sdfr 101184588Sdfr#include "mntopts.h" 102184588Sdfr#include "mounttab.h" 103184588Sdfr 104184588Sdfr#define ALTF_BG 0x1 105184588Sdfr#define ALTF_NOCONN 0x2 106184588Sdfr#define ALTF_DUMBTIMR 0x4 107184588Sdfr#define ALTF_INTR 0x8 108184588Sdfr#define ALTF_NFSV3 0x20 109184588Sdfr#define ALTF_RDIRPLUS 0x40 110184588Sdfr#define ALTF_MNTUDP 0x80 111184588Sdfr#define ALTF_RESVPORT 0x100 112184588Sdfr#define ALTF_SEQPACKET 0x200 113184588Sdfr#define ALTF_SOFT 0x800 114184588Sdfr#define ALTF_TCP 0x1000 115184588Sdfr#define ALTF_PORT 0x2000 116184588Sdfr#define ALTF_NFSV2 0x4000 117184588Sdfr#define ALTF_ACREGMIN 0x8000 118184588Sdfr#define ALTF_ACREGMAX 0x10000 119184588Sdfr#define ALTF_ACDIRMIN 0x20000 120184588Sdfr#define ALTF_ACDIRMAX 0x40000 121184588Sdfr#define ALTF_NOLOCKD 0x80000 122184588Sdfr#define ALTF_NOINET4 0x100000 123184588Sdfr#define ALTF_NOINET6 0x200000 124184588Sdfr 125184588Sdfrstruct mntopt mopts[] = { 126184588Sdfr MOPT_STDOPTS, 127184588Sdfr MOPT_FORCE, 128184588Sdfr MOPT_UPDATE, 129184588Sdfr MOPT_ASYNC, 130184588Sdfr { "bg", 0, ALTF_BG, 1 }, 131184588Sdfr { "fg", 1, ALTF_BG, 1 }, 132184588Sdfr { "conn", 1, ALTF_NOCONN, 1 }, 133184588Sdfr { "dumbtimer", 0, ALTF_DUMBTIMR, 1 }, 134184588Sdfr { "intr", 0, ALTF_INTR, 1 }, 135184588Sdfr { "nfsv3", 0, ALTF_NFSV3, 1 }, 136184588Sdfr { "rdirplus", 0, ALTF_RDIRPLUS, 1 }, 137184588Sdfr { "mntudp", 0, ALTF_MNTUDP, 1 }, 138184588Sdfr { "resvport", 0, ALTF_RESVPORT, 1 }, 139184588Sdfr { "soft", 0, ALTF_SOFT, 1 }, 140184588Sdfr { "hard", 1, ALTF_SOFT, 1 }, 141184588Sdfr { "tcp", 0, ALTF_TCP, 1 }, 142184588Sdfr { "port=", 0, ALTF_PORT, 1 }, 143184588Sdfr { "nfsv2", 0, ALTF_NFSV2, 1 }, 144223309Srmacklem { "acregmin=", 0, ALTF_ACREGMIN, 1 }, 145223309Srmacklem { "acregmax=", 0, ALTF_ACREGMAX, 1 }, 146223309Srmacklem { "acdirmin=", 0, ALTF_ACDIRMIN, 1 }, 147223309Srmacklem { "acdirmax=", 0, ALTF_ACDIRMAX, 1 }, 148223309Srmacklem { "lockd", 1, ALTF_NOLOCKD, 1 }, 149223309Srmacklem { "inet4", 1, ALTF_NOINET4, 1 }, 150223309Srmacklem { "inet6", 1, ALTF_NOINET6, 1 }, 151223309Srmacklem MOPT_END 152223309Srmacklem}; 153223309Srmacklem 154223309Srmacklemstruct nfs_args nfsdefargs = { 155223309Srmacklem NFS_ARGSVERSION, 156223309Srmacklem NULL, 157223309Srmacklem sizeof (struct sockaddr_in), 158223309Srmacklem SOCK_STREAM, 159223309Srmacklem 0, 160223309Srmacklem NULL, 161223309Srmacklem 0, 162223309Srmacklem NFSMNT_RESVPORT, 163223309Srmacklem NFS_WSIZE, 164223309Srmacklem NFS_RSIZE, 165223309Srmacklem NFS_READDIRSIZE, 166223309Srmacklem 10, 167223309Srmacklem NFS_RETRANS, 168223309Srmacklem NFS_MAXGRPS, 169223309Srmacklem NFS_DEFRAHEAD, 170223309Srmacklem 0, /* was: NQ_DEFLEASE */ 171223309Srmacklem NFS_MAXDEADTHRESH, /* was: NQ_DEADTHRESH */ 172223309Srmacklem NULL, 173223309Srmacklem /* args version 4 */ 174223309Srmacklem NFS_MINATTRTIMO, 175223309Srmacklem NFS_MAXATTRTIMO, 176223309Srmacklem NFS_MINDIRATTRTIMO, 177223309Srmacklem NFS_MAXDIRATTRTIMO, 178223309Srmacklem}; 179223309Srmacklem 180223309Srmacklem/* Table for af,sotype -> netid conversions. */ 181223309Srmacklemstruct nc_protos { 182223309Srmacklem char *netid; 183223309Srmacklem int af; 184223309Srmacklem int sotype; 185223309Srmacklem} nc_protos[] = { 186223309Srmacklem {"udp", AF_INET, SOCK_DGRAM}, 187223309Srmacklem {"tcp", AF_INET, SOCK_STREAM}, 188223309Srmacklem {"udp6", AF_INET6, SOCK_DGRAM}, 189223309Srmacklem {"tcp6", AF_INET6, SOCK_STREAM}, 190223309Srmacklem {NULL, 0, 0} 191223309Srmacklem}; 192223309Srmacklem 193223309Srmacklemstruct nfhret { 194223309Srmacklem u_long stat; 195223309Srmacklem long vers; 196223309Srmacklem long auth; 197223309Srmacklem long fhsize; 198223309Srmacklem u_char nfh[NFSX_V3FHMAX]; 199223309Srmacklem}; 200223309Srmacklem#define BGRND 1 201223309Srmacklem#define ISBGRND 2 202223309Srmacklem#define OF_NOINET4 4 203223309Srmacklem#define OF_NOINET6 8 204223309Srmacklemint retrycnt = -1; 205223309Srmacklemint opflags = 0; 206223309Srmacklemint nfsproto = IPPROTO_UDP; 207223309Srmacklemint mnttcp_ok = 1; 208223309Srmacklemchar *portspec = NULL; /* Server nfs port; NULL means look up via rpcbind. */ 209223309Srmacklemenum mountmode { 210223309Srmacklem ANY, 211223309Srmacklem V2, 212223309Srmacklem V3, 213223309Srmacklem V4 214223309Srmacklem} mountmode = ANY; 215223309Srmacklem 216223309Srmacklem/* Return codes for nfs_tryproto. */ 217223309Srmacklemenum tryret { 218223309Srmacklem TRYRET_SUCCESS, 219223309Srmacklem TRYRET_TIMEOUT, /* No response received. */ 220223309Srmacklem TRYRET_REMOTEERR, /* Error received from remote server. */ 221223309Srmacklem TRYRET_LOCALERR /* Local failure. */ 222223309Srmacklem}; 223223309Srmacklem 224223309Srmacklemint getnfsargs(char *, struct nfs_args *); 225223309Srmacklemint getnfs4args(char *, struct nfs_args *); 226223309Srmacklem/* void set_rpc_maxgrouplist(int); */ 227223309Srmacklemstruct netconfig *getnetconf_cached(const char *netid); 228223309Srmacklemchar *netidbytype(int af, int sotype); 229223309Srmacklemvoid usage(void) __dead2; 230223309Srmacklemint xdr_dir(XDR *, char *); 231223309Srmacklemint xdr_fh(XDR *, struct nfhret *); 232223309Srmacklemenum tryret nfs_tryproto(struct nfs_args *nfsargsp, struct addrinfo *ai, 233223309Srmacklem char *hostp, char *spec, char **errstr); 234223309Srmacklemenum tryret nfs4_tryproto(struct nfs_args *nfsargsp, struct addrinfo *ai, 235223309Srmacklem char *hostp, char *spec, char **errstr); 236223309Srmacklemenum tryret returncode(enum clnt_stat stat, struct rpc_err *rpcerr); 237223309Srmacklem 238223309Srmacklem/* 239223309Srmacklem * Used to set mount flags with getmntopts. Call with dir=TRUE to 240223309Srmacklem * initialize altflags from the current mount flags. Call with 241223309Srmacklem * dir=FALSE to update mount flags with the new value of altflags after 242223309Srmacklem * the call to getmntopts. 243223309Srmacklem */ 244223309Srmacklemstatic void 245223309Srmacklemset_flags(int* altflags, int* nfsflags, int dir) 246223309Srmacklem{ 247223309Srmacklem#define F2(af, nf) \ 248223309Srmacklem if (dir) { \ 249223309Srmacklem if (*nfsflags & NFSMNT_##nf) \ 250223309Srmacklem *altflags |= ALTF_##af; \ 251223309Srmacklem else \ 252223309Srmacklem *altflags &= ~ALTF_##af; \ 253223309Srmacklem } else { \ 254223309Srmacklem if (*altflags & ALTF_##af) \ 255223309Srmacklem *nfsflags |= NFSMNT_##nf; \ 256223309Srmacklem else \ 257223309Srmacklem *nfsflags &= ~NFSMNT_##nf; \ 258223309Srmacklem } 259223309Srmacklem#define F(f) F2(f,f) 260223309Srmacklem 261223309Srmacklem F(NOCONN); 262223309Srmacklem F(DUMBTIMR); 263223309Srmacklem F2(INTR, INT); 264223309Srmacklem F(RDIRPLUS); 265223309Srmacklem F(RESVPORT); 266223309Srmacklem F(SOFT); 267223309Srmacklem F(ACREGMIN); 268223309Srmacklem F(ACREGMAX); 269223309Srmacklem F(ACDIRMIN); 270223309Srmacklem F(ACDIRMAX); 271223309Srmacklem F(NOLOCKD); 272223309Srmacklem 273223309Srmacklem#undef F 274223309Srmacklem#undef F2 275223309Srmacklem} 276223309Srmacklem 277223309Srmacklemint 278223309Srmacklemmain(int argc, char *argv[]) 279223309Srmacklem{ 280223309Srmacklem int c; 281223309Srmacklem struct nfs_args *nfsargsp; 282223309Srmacklem struct nfs_args nfsargs; 283223309Srmacklem struct iovec *iov; 284223309Srmacklem int mntflags, altflags, num; 285223309Srmacklem int iovlen; 286223309Srmacklem char *name, *p, *spec, *fstype; 287223309Srmacklem char mntpath[MAXPATHLEN], errmsg[255]; 288223309Srmacklem 289223309Srmacklem mntflags = 0; 290223309Srmacklem altflags = 0; 291223309Srmacklem nfsargs = nfsdefargs; 292223309Srmacklem nfsargsp = &nfsargs; 293223309Srmacklem iov = NULL; 294223309Srmacklem iovlen = 0; 295223309Srmacklem memset(errmsg, 0, sizeof(errmsg)); 296223309Srmacklem 297223309Srmacklem fstype = strrchr(argv[0], '_'); 298223309Srmacklem if (fstype == NULL) 299223309Srmacklem errx(EX_USAGE, "argv[0] must end in _fstype"); 300223309Srmacklem 301223309Srmacklem ++fstype; 302223309Srmacklem 303223309Srmacklem if (strcmp(fstype, "nfs4") == 0) { 304223309Srmacklem nfsproto = IPPROTO_TCP; 305223309Srmacklem portspec = "2049"; 306223309Srmacklem nfsdefargs.sotype = SOCK_STREAM; 307223309Srmacklem mountmode = V4; 308223309Srmacklem } 309223309Srmacklem 310223309Srmacklem while ((c = getopt(argc, argv, 311223309Srmacklem "234a:bcdD:g:I:iLlNo:PR:r:sTt:w:x:U")) != -1) 312223309Srmacklem switch (c) { 313223309Srmacklem case '2': 314223309Srmacklem mountmode = V2; 315223309Srmacklem break; 316223309Srmacklem case '3': 317223309Srmacklem mountmode = V3; 318223309Srmacklem break; 319223309Srmacklem case '4': 320223309Srmacklem mountmode = V4; 321223309Srmacklem fstype = "nfs4"; 322223309Srmacklem break; 323223309Srmacklem case 'a': 324223309Srmacklem num = strtol(optarg, &p, 10); 325223309Srmacklem if (*p || num < 0) 326223309Srmacklem errx(1, "illegal -a value -- %s", optarg); 327223309Srmacklem nfsargsp->readahead = num; 328223309Srmacklem nfsargsp->flags |= NFSMNT_READAHEAD; 329223309Srmacklem break; 330223309Srmacklem case 'b': 331223309Srmacklem opflags |= BGRND; 332223309Srmacklem break; 333223309Srmacklem case 'c': 334223309Srmacklem nfsargsp->flags |= NFSMNT_NOCONN; 335223309Srmacklem break; 336223309Srmacklem case 'D': 337223309Srmacklem num = strtol(optarg, &p, 10); 338223309Srmacklem if (*p || num <= 0) 339223309Srmacklem errx(1, "illegal -D value -- %s", optarg); 340223309Srmacklem nfsargsp->deadthresh = num; 341223309Srmacklem nfsargsp->flags |= NFSMNT_DEADTHRESH; 342223309Srmacklem break; 343223309Srmacklem case 'd': 344223309Srmacklem nfsargsp->flags |= NFSMNT_DUMBTIMR; 345223309Srmacklem break; 346223309Srmacklem#if 0 /* XXXX */ 347223309Srmacklem case 'g': 348223309Srmacklem num = strtol(optarg, &p, 10); 349223309Srmacklem if (*p || num <= 0) 350223309Srmacklem errx(1, "illegal -g value -- %s", optarg); 351223309Srmacklem set_rpc_maxgrouplist(num); 352223309Srmacklem nfsargsp->maxgrouplist = num; 353223309Srmacklem nfsargsp->flags |= NFSMNT_MAXGRPS; 354223309Srmacklem break; 355223309Srmacklem#endif 356223309Srmacklem case 'I': 357223309Srmacklem num = strtol(optarg, &p, 10); 358223309Srmacklem if (*p || num <= 0) 359223309Srmacklem errx(1, "illegal -I value -- %s", optarg); 360223309Srmacklem nfsargsp->readdirsize = num; 361223309Srmacklem nfsargsp->flags |= NFSMNT_READDIRSIZE; 362223309Srmacklem break; 363223309Srmacklem case 'i': 364223309Srmacklem nfsargsp->flags |= NFSMNT_INT; 365223309Srmacklem break; 366223309Srmacklem case 'L': 367223309Srmacklem nfsargsp->flags |= NFSMNT_NOLOCKD; 368223309Srmacklem break; 369223309Srmacklem case 'l': 370223309Srmacklem nfsargsp->flags |= NFSMNT_RDIRPLUS; 371223309Srmacklem break; 372223309Srmacklem case 'N': 373223309Srmacklem nfsargsp->flags &= ~NFSMNT_RESVPORT; 374223309Srmacklem break; 375223309Srmacklem case 'o': 376223309Srmacklem altflags = 0; 377223309Srmacklem set_flags(&altflags, &nfsargsp->flags, TRUE); 378223309Srmacklem if (mountmode == V2) 379223309Srmacklem altflags |= ALTF_NFSV2; 380223309Srmacklem else if (mountmode == V3) 381223309Srmacklem altflags |= ALTF_NFSV3; 382223309Srmacklem getmntopts(optarg, mopts, &mntflags, &altflags); 383223309Srmacklem set_flags(&altflags, &nfsargsp->flags, FALSE); 384223309Srmacklem /* 385223309Srmacklem * Handle altflags which don't map directly to 386223309Srmacklem * mount flags. 387223309Srmacklem */ 388223309Srmacklem if (altflags & ALTF_BG) 389223309Srmacklem opflags |= BGRND; 390223309Srmacklem if (altflags & ALTF_NOINET4) 391223309Srmacklem opflags |= OF_NOINET4; 392223309Srmacklem if (altflags & ALTF_NOINET6) 393223309Srmacklem opflags |= OF_NOINET6; 394223309Srmacklem if (altflags & ALTF_MNTUDP) 395223309Srmacklem mnttcp_ok = 0; 396223309Srmacklem if (altflags & ALTF_TCP) { 397223309Srmacklem nfsargsp->sotype = SOCK_STREAM; 398223309Srmacklem nfsproto = IPPROTO_TCP; 399223309Srmacklem } 400223309Srmacklem if (altflags & ALTF_PORT) { 401223309Srmacklem /* 402223309Srmacklem * XXX Converting from a string to an int 403223309Srmacklem * and back again is silly, and we should 404223309Srmacklem * allow /etc/services names. 405223309Srmacklem */ 406223309Srmacklem p = strstr(optarg, "port="); 407223309Srmacklem if (p) { 408223309Srmacklem asprintf(&portspec, "%d", 409184588Sdfr atoi(p + 5)); 410184588Sdfr if (portspec == NULL) 411184588Sdfr err(1, "asprintf"); 412184588Sdfr } 413184588Sdfr } 414184588Sdfr mountmode = ANY; 415184588Sdfr if (altflags & ALTF_NFSV2) 416184588Sdfr mountmode = V2; 417184588Sdfr if (altflags & ALTF_NFSV3) 418184588Sdfr mountmode = V3; 419184588Sdfr if (altflags & ALTF_ACREGMIN) { 420184588Sdfr p = strstr(optarg, "acregmin="); 421184588Sdfr if (p) 422184588Sdfr nfsargsp->acregmin = atoi(p + 9); 423184588Sdfr } 424184588Sdfr if (altflags & ALTF_ACREGMAX) { 425184588Sdfr p = strstr(optarg, "acregmax="); 426184588Sdfr if (p) 427184588Sdfr nfsargsp->acregmax = atoi(p + 9); 428184588Sdfr } 429184588Sdfr if (altflags & ALTF_ACDIRMIN) { 430184588Sdfr p = strstr(optarg, "acdirmin="); 431184588Sdfr if (p) 432184588Sdfr nfsargsp->acdirmin = atoi(p + 9); 433184588Sdfr } 434184588Sdfr if (altflags & ALTF_ACDIRMAX) { 435184588Sdfr p = strstr(optarg, "acdirmax="); 436184588Sdfr if (p) 437184588Sdfr nfsargsp->acdirmax = atoi(p + 9); 438184588Sdfr } 439184588Sdfr break; 440184588Sdfr case 'P': 441184588Sdfr /* obsolete for NFSMNT_RESVPORT, now default */ 442184588Sdfr break; 443184588Sdfr case 'R': 444184588Sdfr num = strtol(optarg, &p, 10); 445184588Sdfr if (*p || num < 0) 446184588Sdfr errx(1, "illegal -R value -- %s", optarg); 447184588Sdfr retrycnt = num; 448184588Sdfr break; 449184588Sdfr case 'r': 450184588Sdfr num = strtol(optarg, &p, 10); 451184588Sdfr if (*p || num <= 0) 452184588Sdfr errx(1, "illegal -r value -- %s", optarg); 453184588Sdfr nfsargsp->rsize = num; 454184588Sdfr nfsargsp->flags |= NFSMNT_RSIZE; 455 break; 456 case 's': 457 nfsargsp->flags |= NFSMNT_SOFT; 458 break; 459 case 'T': 460 nfsargsp->sotype = SOCK_STREAM; 461 nfsproto = IPPROTO_TCP; 462 break; 463 case 't': 464 num = strtol(optarg, &p, 10); 465 if (*p || num <= 0) 466 errx(1, "illegal -t value -- %s", optarg); 467 nfsargsp->timeo = num; 468 nfsargsp->flags |= NFSMNT_TIMEO; 469 break; 470 case 'w': 471 num = strtol(optarg, &p, 10); 472 if (*p || num <= 0) 473 errx(1, "illegal -w value -- %s", optarg); 474 nfsargsp->wsize = num; 475 nfsargsp->flags |= NFSMNT_WSIZE; 476 break; 477 case 'x': 478 num = strtol(optarg, &p, 10); 479 if (*p || num <= 0) 480 errx(1, "illegal -x value -- %s", optarg); 481 nfsargsp->retrans = num; 482 nfsargsp->flags |= NFSMNT_RETRANS; 483 break; 484 case 'U': 485 mnttcp_ok = 0; 486 nfsargsp->sotype = SOCK_DGRAM; 487 nfsproto = IPPROTO_UDP; 488 break; 489 default: 490 usage(); 491 break; 492 } 493 argc -= optind; 494 argv += optind; 495 496 if (argc != 2) { 497 usage(); 498 /* NOTREACHED */ 499 } 500 501 spec = *argv++; 502 name = *argv; 503 504 if (retrycnt == -1) 505 /* The default is to keep retrying forever. */ 506 retrycnt = 0; 507 508 if (mountmode == V4) { 509 if (!getnfs4args(spec, nfsargsp)) 510 exit(1); 511 } else { 512 if (!getnfsargs(spec, nfsargsp)) 513 exit(1); 514 } 515 516 /* resolve the mountpoint with realpath(3) */ 517 (void)checkpath(name, mntpath); 518 519 /* 520 * XXX This should go away when this NFS implementation 521 * is fully converted to nmount(2) semantics. 522 */ 523 if (mntflags & MNT_RDONLY) 524 build_iovec(&iov, &iovlen, "ro", NULL, 0); 525 else if (mntflags & MNT_UPDATE) 526 build_iovec(&iov, &iovlen, "noro", NULL, 0); 527 528 build_iovec(&iov, &iovlen, "nfs_args", nfsargsp, sizeof(*nfsargsp)); 529 build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1); 530 build_iovec(&iov, &iovlen, "fspath", mntpath, (size_t)-1); 531 build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 532 533 if (nmount(iov, iovlen, mntflags)) 534 err(1, "%s, %s", mntpath, errmsg); 535 536 exit(0); 537} 538 539int 540getnfsargs(char *spec, struct nfs_args *nfsargsp) 541{ 542 struct addrinfo hints, *ai_nfs, *ai; 543 enum tryret ret; 544 int ecode, speclen, remoteerr; 545 char *hostp, *delimp, *errstr; 546 size_t len; 547 static char nam[MNAMELEN + 1]; 548 549 if ((delimp = strrchr(spec, ':')) != NULL) { 550 hostp = spec; 551 spec = delimp + 1; 552 } else if ((delimp = strrchr(spec, '@')) != NULL) { 553 warnx("path@server syntax is deprecated, use server:path"); 554 hostp = delimp + 1; 555 } else { 556 warnx("no <host>:<dirpath> nfs-name"); 557 return (0); 558 } 559 *delimp = '\0'; 560 561 /* 562 * If there has been a trailing slash at mounttime it seems 563 * that some mountd implementations fail to remove the mount 564 * entries from their mountlist while unmounting. 565 */ 566 for (speclen = strlen(spec); 567 speclen > 1 && spec[speclen - 1] == '/'; 568 speclen--) 569 spec[speclen - 1] = '\0'; 570 if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) { 571 warnx("%s:%s: %s", hostp, spec, strerror(ENAMETOOLONG)); 572 return (0); 573 } 574 /* Make both '@' and ':' notations equal */ 575 if (*hostp != '\0') { 576 len = strlen(hostp); 577 memmove(nam, hostp, len); 578 nam[len] = ':'; 579 memmove(nam + len + 1, spec, speclen); 580 nam[len + speclen + 1] = '\0'; 581 } 582 583 /* 584 * Handle an internet host address. 585 */ 586 memset(&hints, 0, sizeof hints); 587 hints.ai_flags = AI_NUMERICHOST; 588 hints.ai_socktype = nfsargsp->sotype; 589 if (getaddrinfo(hostp, portspec, &hints, &ai_nfs) != 0) { 590 hints.ai_flags = 0; 591 if ((ecode = getaddrinfo(hostp, portspec, &hints, &ai_nfs)) 592 != 0) { 593 if (portspec == NULL) 594 errx(1, "%s: %s", hostp, gai_strerror(ecode)); 595 else 596 errx(1, "%s:%s: %s", hostp, portspec, 597 gai_strerror(ecode)); 598 return (0); 599 } 600 } 601 602 ret = TRYRET_LOCALERR; 603 for (;;) { 604 /* 605 * Try each entry returned by getaddrinfo(). Note the 606 * occurence of remote errors by setting `remoteerr'. 607 */ 608 remoteerr = 0; 609 for (ai = ai_nfs; ai != NULL; ai = ai->ai_next) { 610 if ((ai->ai_family == AF_INET6) && 611 (opflags & OF_NOINET6)) 612 continue; 613 if ((ai->ai_family == AF_INET) && 614 (opflags & OF_NOINET4)) 615 continue; 616 ret = nfs_tryproto(nfsargsp, ai, hostp, spec, &errstr); 617 if (ret == TRYRET_SUCCESS) 618 break; 619 if (ret != TRYRET_LOCALERR) 620 remoteerr = 1; 621 if ((opflags & ISBGRND) == 0) 622 fprintf(stderr, "%s\n", errstr); 623 } 624 if (ret == TRYRET_SUCCESS) 625 break; 626 627 /* Exit if all errors were local. */ 628 if (!remoteerr) 629 exit(1); 630 631 /* 632 * If retrycnt == 0, we are to keep retrying forever. 633 * Otherwise decrement it, and exit if it hits zero. 634 */ 635 if (retrycnt != 0 && --retrycnt == 0) 636 exit(1); 637 638 if ((opflags & (BGRND | ISBGRND)) == BGRND) { 639 warnx("Cannot immediately mount %s:%s, backgrounding", 640 hostp, spec); 641 opflags |= ISBGRND; 642 if (daemon(0, 0) != 0) 643 err(1, "daemon"); 644 } 645 sleep(60); 646 } 647 freeaddrinfo(ai_nfs); 648 nfsargsp->hostname = nam; 649 /* Add mounted file system to PATH_MOUNTTAB */ 650 if (!add_mtab(hostp, spec)) 651 warnx("can't update %s for %s:%s", PATH_MOUNTTAB, hostp, spec); 652 return (1); 653} 654 655 656int 657getnfs4args(char *spec, struct nfs_args *nfsargsp) 658{ 659 struct addrinfo hints, *ai_nfs, *ai; 660 enum tryret ret; 661 int ecode, speclen, remoteerr; 662 char *hostp, *delimp, *errstr; 663 size_t len; 664 static char nam[MNAMELEN + 1]; 665 666 if ((delimp = strrchr(spec, ':')) != NULL) { 667 hostp = spec; 668 spec = delimp + 1; 669 } else if ((delimp = strrchr(spec, '@')) != NULL) { 670 warnx("path@server syntax is deprecated, use server:path"); 671 hostp = delimp + 1; 672 } else { 673 warnx("no <host>:<dirpath> nfs-name"); 674 return (0); 675 } 676 *delimp = '\0'; 677 678 /* 679 * If there has been a trailing slash at mounttime it seems 680 * that some mountd implementations fail to remove the mount 681 * entries from their mountlist while unmounting. 682 */ 683 for (speclen = strlen(spec); 684 speclen > 1 && spec[speclen - 1] == '/'; 685 speclen--) 686 spec[speclen - 1] = '\0'; 687 if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) { 688 warnx("%s:%s: %s", hostp, spec, strerror(ENAMETOOLONG)); 689 return (0); 690 } 691 /* Make both '@' and ':' notations equal */ 692 if (*hostp != '\0') { 693 len = strlen(hostp); 694 memmove(nam, hostp, len); 695 nam[len] = ':'; 696 memmove(nam + len + 1, spec, speclen); 697 nam[len + speclen + 1] = '\0'; 698 } 699 700 /* 701 * Handle an internet host address. 702 */ 703 memset(&hints, 0, sizeof hints); 704 hints.ai_flags = AI_NUMERICHOST; 705 hints.ai_socktype = nfsargsp->sotype; 706 if (getaddrinfo(hostp, portspec, &hints, &ai_nfs) != 0) { 707 hints.ai_flags = 0; 708 if ((ecode = getaddrinfo(hostp, portspec, &hints, &ai_nfs)) 709 != 0) { 710 if (portspec == NULL) 711 errx(1, "%s: %s", hostp, gai_strerror(ecode)); 712 else 713 errx(1, "%s:%s: %s", hostp, portspec, 714 gai_strerror(ecode)); 715 return (0); 716 } 717 } 718 719 ret = TRYRET_LOCALERR; 720 for (;;) { 721 /* 722 * Try each entry returned by getaddrinfo(). Note the 723 * occurence of remote errors by setting `remoteerr'. 724 */ 725 remoteerr = 0; 726 for (ai = ai_nfs; ai != NULL; ai = ai->ai_next) { 727 if ((ai->ai_family == AF_INET6) && 728 (opflags & OF_NOINET6)) 729 continue; 730 if ((ai->ai_family == AF_INET) && 731 (opflags & OF_NOINET4)) 732 continue; 733 ret = nfs4_tryproto(nfsargsp, ai, hostp, spec, &errstr); 734 if (ret == TRYRET_SUCCESS) 735 break; 736 if (ret != TRYRET_LOCALERR) 737 remoteerr = 1; 738 if ((opflags & ISBGRND) == 0) 739 fprintf(stderr, "%s\n", errstr); 740 } 741 if (ret == TRYRET_SUCCESS) 742 break; 743 744 /* Exit if all errors were local. */ 745 if (!remoteerr) 746 exit(1); 747 748 /* 749 * If retrycnt == 0, we are to keep retrying forever. 750 * Otherwise decrement it, and exit if it hits zero. 751 */ 752 if (retrycnt != 0 && --retrycnt == 0) 753 exit(1); 754 755 if ((opflags & (BGRND | ISBGRND)) == BGRND) { 756 warnx("Cannot immediately mount %s:%s, backgrounding", 757 hostp, spec); 758 opflags |= ISBGRND; 759 if (daemon(0, 0) != 0) 760 err(1, "daemon"); 761 } 762 sleep(60); 763 } 764 freeaddrinfo(ai_nfs); 765 nfsargsp->hostname = nam; 766 /* Add mounted file system to PATH_MOUNTTAB */ 767 if (!add_mtab(hostp, spec)) 768 warnx("can't update %s for %s:%s", PATH_MOUNTTAB, hostp, spec); 769 return (1); 770} 771 772/* 773 * Try to set up the NFS arguments according to the address 774 * family, protocol (and possibly port) specified in `ai'. 775 * 776 * Returns TRYRET_SUCCESS if successful, or: 777 * TRYRET_TIMEOUT The server did not respond. 778 * TRYRET_REMOTEERR The server reported an error. 779 * TRYRET_LOCALERR Local failure. 780 * 781 * In all error cases, *errstr will be set to a statically-allocated string 782 * describing the error. 783 */ 784enum tryret 785nfs_tryproto(struct nfs_args *nfsargsp, struct addrinfo *ai, char *hostp, 786 char *spec, char **errstr) 787{ 788 static char errbuf[256]; 789 struct sockaddr_storage nfs_ss; 790 struct netbuf nfs_nb; 791 struct nfhret nfhret; 792 struct timeval try; 793 struct rpc_err rpcerr; 794 CLIENT *clp; 795 struct netconfig *nconf, *nconf_mnt; 796 char *netid, *netid_mnt; 797 int doconnect, nfsvers, mntvers; 798 enum clnt_stat stat; 799 enum mountmode trymntmode; 800 801 trymntmode = mountmode; 802 errbuf[0] = '\0'; 803 *errstr = errbuf; 804 805 if ((netid = netidbytype(ai->ai_family, nfsargsp->sotype)) == NULL) { 806 snprintf(errbuf, sizeof errbuf, 807 "af %d sotype %d not supported", ai->ai_family, 808 nfsargsp->sotype); 809 return (TRYRET_LOCALERR); 810 } 811 if ((nconf = getnetconf_cached(netid)) == NULL) { 812 snprintf(errbuf, sizeof errbuf, "%s: %s", netid, nc_sperror()); 813 return (TRYRET_LOCALERR); 814 } 815 /* The RPCPROG_MNT netid may be different. */ 816 if (mnttcp_ok) { 817 netid_mnt = netid; 818 nconf_mnt = nconf; 819 } else { 820 if ((netid_mnt = netidbytype(ai->ai_family, SOCK_DGRAM)) 821 == NULL) { 822 snprintf(errbuf, sizeof errbuf, 823 "af %d sotype SOCK_DGRAM not supported", 824 ai->ai_family); 825 return (TRYRET_LOCALERR); 826 } 827 if ((nconf_mnt = getnetconf_cached(netid_mnt)) == NULL) { 828 snprintf(errbuf, sizeof errbuf, "%s: %s", netid_mnt, 829 nc_sperror()); 830 return (TRYRET_LOCALERR); 831 } 832 } 833 834tryagain: 835 if (trymntmode == V2) { 836 nfsvers = 2; 837 mntvers = 1; 838 } else { 839 nfsvers = 3; 840 mntvers = 3; 841 } 842 843 if (portspec != NULL) { 844 /* `ai' contains the complete nfsd sockaddr. */ 845 nfs_nb.buf = ai->ai_addr; 846 nfs_nb.len = nfs_nb.maxlen = ai->ai_addrlen; 847 } else { 848 /* Ask the remote rpcbind. */ 849 nfs_nb.buf = &nfs_ss; 850 nfs_nb.len = nfs_nb.maxlen = sizeof nfs_ss; 851 852 if (!rpcb_getaddr(RPCPROG_NFS, nfsvers, nconf, &nfs_nb, 853 hostp)) { 854 if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH && 855 trymntmode == ANY) { 856 trymntmode = V2; 857 goto tryagain; 858 } 859 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", 860 netid, hostp, spec, 861 clnt_spcreateerror("RPCPROG_NFS")); 862 return (returncode(rpc_createerr.cf_stat, 863 &rpc_createerr.cf_error)); 864 } 865 } 866 867 /* Check that the server (nfsd) responds on the port we have chosen. */ 868 clp = clnt_tli_create(RPC_ANYFD, nconf, &nfs_nb, RPCPROG_NFS, nfsvers, 869 0, 0); 870 if (clp == NULL) { 871 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid, 872 hostp, spec, clnt_spcreateerror("nfsd: RPCPROG_NFS")); 873 return (returncode(rpc_createerr.cf_stat, 874 &rpc_createerr.cf_error)); 875 } 876 if (nfsargsp->sotype == SOCK_DGRAM && 877 !(nfsargsp->flags & NFSMNT_NOCONN)) { 878 /* 879 * Use connect(), to match what the kernel does. This 880 * catches cases where the server responds from the 881 * wrong source address. 882 */ 883 doconnect = 1; 884 if (!clnt_control(clp, CLSET_CONNECT, (char *)&doconnect)) { 885 clnt_destroy(clp); 886 snprintf(errbuf, sizeof errbuf, 887 "[%s] %s:%s: CLSET_CONNECT failed", netid, hostp, 888 spec); 889 return (TRYRET_LOCALERR); 890 } 891 } 892 893 try.tv_sec = 10; 894 try.tv_usec = 0; 895 stat = clnt_call(clp, NFSPROC_NULL, (xdrproc_t)xdr_void, NULL, 896 (xdrproc_t)xdr_void, NULL, 897 try); 898 if (stat != RPC_SUCCESS) { 899 if (stat == RPC_PROGVERSMISMATCH && trymntmode == ANY) { 900 clnt_destroy(clp); 901 trymntmode = V2; 902 goto tryagain; 903 } 904 clnt_geterr(clp, &rpcerr); 905 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid, 906 hostp, spec, clnt_sperror(clp, "NFSPROC_NULL")); 907 clnt_destroy(clp); 908 return (returncode(stat, &rpcerr)); 909 } 910 clnt_destroy(clp); 911 912 /* Send the RPCMNT_MOUNT RPC to get the root filehandle. */ 913 try.tv_sec = 10; 914 try.tv_usec = 0; 915 clp = clnt_tp_create(hostp, RPCPROG_MNT, mntvers, nconf_mnt); 916 if (clp == NULL) { 917 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 918 hostp, spec, clnt_spcreateerror("RPCMNT: clnt_create")); 919 return (returncode(rpc_createerr.cf_stat, 920 &rpc_createerr.cf_error)); 921 } 922 clp->cl_auth = authsys_create_default(); 923 nfhret.auth = RPCAUTH_UNIX; 924 nfhret.vers = mntvers; 925 stat = clnt_call(clp, RPCMNT_MOUNT, (xdrproc_t)xdr_dir, spec, 926 (xdrproc_t)xdr_fh, &nfhret, 927 try); 928 auth_destroy(clp->cl_auth); 929 if (stat != RPC_SUCCESS) { 930 if (stat == RPC_PROGVERSMISMATCH && trymntmode == ANY) { 931 clnt_destroy(clp); 932 trymntmode = V2; 933 goto tryagain; 934 } 935 clnt_geterr(clp, &rpcerr); 936 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 937 hostp, spec, clnt_sperror(clp, "RPCPROG_MNT")); 938 clnt_destroy(clp); 939 return (returncode(stat, &rpcerr)); 940 } 941 clnt_destroy(clp); 942 943 if (nfhret.stat != 0) { 944 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 945 hostp, spec, strerror(nfhret.stat)); 946 return (TRYRET_REMOTEERR); 947 } 948 949 /* 950 * Store the filehandle and server address in nfsargsp, making 951 * sure to copy any locally allocated structures. 952 */ 953 nfsargsp->addrlen = nfs_nb.len; 954 nfsargsp->addr = malloc(nfsargsp->addrlen); 955 nfsargsp->fhsize = nfhret.fhsize; 956 nfsargsp->fh = malloc(nfsargsp->fhsize); 957 if (nfsargsp->addr == NULL || nfsargsp->fh == NULL) 958 err(1, "malloc"); 959 bcopy(nfs_nb.buf, nfsargsp->addr, nfsargsp->addrlen); 960 bcopy(nfhret.nfh, nfsargsp->fh, nfsargsp->fhsize); 961 962 if (nfsvers == 3) 963 nfsargsp->flags |= NFSMNT_NFSV3; 964 else 965 nfsargsp->flags &= ~NFSMNT_NFSV3; 966 967 return (TRYRET_SUCCESS); 968} 969 970 971/* 972 * Try to set up the NFS arguments according to the address 973 * family, protocol (and possibly port) specified in `ai'. 974 * 975 * Returns TRYRET_SUCCESS if successful, or: 976 * TRYRET_TIMEOUT The server did not respond. 977 * TRYRET_REMOTEERR The server reported an error. 978 * TRYRET_LOCALERR Local failure. 979 * 980 * In all error cases, *errstr will be set to a statically-allocated string 981 * describing the error. 982 */ 983enum tryret 984nfs4_tryproto(struct nfs_args *nfsargsp, struct addrinfo *ai, char *hostp, 985 char *spec, char **errstr) 986{ 987 static char errbuf[256]; 988 struct sockaddr_storage nfs_ss; 989 struct netbuf nfs_nb; 990 struct netconfig *nconf; 991 char *netid; 992 int nfsvers; 993 994 errbuf[0] = '\0'; 995 *errstr = errbuf; 996 997 if ((netid = netidbytype(ai->ai_family, nfsargsp->sotype)) == NULL) { 998 snprintf(errbuf, sizeof errbuf, 999 "af %d sotype %d not supported", ai->ai_family, 1000 nfsargsp->sotype); 1001 return (TRYRET_LOCALERR); 1002 } 1003 if ((nconf = getnetconf_cached(netid)) == NULL) { 1004 snprintf(errbuf, sizeof errbuf, "%s: %s", netid, nc_sperror()); 1005 return (TRYRET_LOCALERR); 1006 } 1007 1008 nfsvers = 4; 1009 1010 if (portspec != NULL && atoi(portspec) != 0) { 1011 /* `ai' contains the complete nfsd sockaddr. */ 1012 nfs_nb.buf = ai->ai_addr; 1013 nfs_nb.len = nfs_nb.maxlen = ai->ai_addrlen; 1014 } else { 1015 /* Ask the remote rpcbind. */ 1016 nfs_nb.buf = &nfs_ss; 1017 nfs_nb.len = nfs_nb.maxlen = sizeof nfs_ss; 1018 1019 if (!rpcb_getaddr(RPCPROG_NFS, nfsvers, nconf, &nfs_nb, 1020 hostp)) { 1021 snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", 1022 netid, hostp, spec, 1023 clnt_spcreateerror("RPCPROG_NFS")); 1024 return (returncode(rpc_createerr.cf_stat, 1025 &rpc_createerr.cf_error)); 1026 } 1027 } 1028 1029 /* 1030 * Store the filehandle and server address in nfsargsp, making 1031 * sure to copy any locally allocated structures. 1032 */ 1033 nfsargsp->addrlen = nfs_nb.len; 1034 nfsargsp->addr = malloc(nfsargsp->addrlen); 1035 1036 if (nfsargsp->addr == NULL) 1037 err(1, "malloc"); 1038 bcopy(nfs_nb.buf, nfsargsp->addr, nfsargsp->addrlen); 1039 1040 /* XXX hack */ 1041 nfsargsp->flags |= (NFSMNT_NFSV3 | NFSMNT_NFSV4); 1042 1043 return (TRYRET_SUCCESS); 1044} 1045 1046/* 1047 * Catagorise a RPC return status and error into an `enum tryret' 1048 * return code. 1049 */ 1050enum tryret 1051returncode(enum clnt_stat stat, struct rpc_err *rpcerr) 1052{ 1053 switch (stat) { 1054 case RPC_TIMEDOUT: 1055 return (TRYRET_TIMEOUT); 1056 case RPC_PMAPFAILURE: 1057 case RPC_PROGNOTREGISTERED: 1058 case RPC_PROGVERSMISMATCH: 1059 /* XXX, these can be local or remote. */ 1060 case RPC_CANTSEND: 1061 case RPC_CANTRECV: 1062 return (TRYRET_REMOTEERR); 1063 case RPC_SYSTEMERROR: 1064 switch (rpcerr->re_errno) { 1065 case ETIMEDOUT: 1066 return (TRYRET_TIMEOUT); 1067 case ENOMEM: 1068 break; 1069 default: 1070 return (TRYRET_REMOTEERR); 1071 } 1072 /* FALLTHROUGH */ 1073 default: 1074 break; 1075 } 1076 return (TRYRET_LOCALERR); 1077} 1078 1079/* 1080 * Look up a netid based on an address family and socket type. 1081 * `af' is the address family, and `sotype' is SOCK_DGRAM or SOCK_STREAM. 1082 * 1083 * XXX there should be a library function for this. 1084 */ 1085char * 1086netidbytype(int af, int sotype) 1087{ 1088 struct nc_protos *p; 1089 1090 for (p = nc_protos; p->netid != NULL; p++) { 1091 if (af != p->af || sotype != p->sotype) 1092 continue; 1093 return (p->netid); 1094 } 1095 return (NULL); 1096} 1097 1098/* 1099 * Look up a netconfig entry based on a netid, and cache the result so 1100 * that we don't need to remember to call freenetconfigent(). 1101 * 1102 * Otherwise it behaves just like getnetconfigent(), so nc_*error() 1103 * work on failure. 1104 */ 1105struct netconfig * 1106getnetconf_cached(const char *netid) 1107{ 1108 static struct nc_entry { 1109 struct netconfig *nconf; 1110 struct nc_entry *next; 1111 } *head; 1112 struct nc_entry *p; 1113 struct netconfig *nconf; 1114 1115 for (p = head; p != NULL; p = p->next) 1116 if (strcmp(netid, p->nconf->nc_netid) == 0) 1117 return (p->nconf); 1118 1119 if ((nconf = getnetconfigent(netid)) == NULL) 1120 return (NULL); 1121 if ((p = malloc(sizeof(*p))) == NULL) 1122 err(1, "malloc"); 1123 p->nconf = nconf; 1124 p->next = head; 1125 head = p; 1126 1127 return (p->nconf); 1128} 1129 1130/* 1131 * xdr routines for mount rpc's 1132 */ 1133int 1134xdr_dir(XDR *xdrsp, char *dirp) 1135{ 1136 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 1137} 1138 1139int 1140xdr_fh(XDR *xdrsp, struct nfhret *np) 1141{ 1142 int i; 1143 long auth, authcnt, authfnd = 0; 1144 1145 if (!xdr_u_long(xdrsp, &np->stat)) 1146 return (0); 1147 if (np->stat) 1148 return (1); 1149 switch (np->vers) { 1150 case 1: 1151 np->fhsize = NFSX_V2FH; 1152 return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFSX_V2FH)); 1153 case 3: 1154 if (!xdr_long(xdrsp, &np->fhsize)) 1155 return (0); 1156 if (np->fhsize <= 0 || np->fhsize > NFSX_V3FHMAX) 1157 return (0); 1158 if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize)) 1159 return (0); 1160 if (!xdr_long(xdrsp, &authcnt)) 1161 return (0); 1162 for (i = 0; i < authcnt; i++) { 1163 if (!xdr_long(xdrsp, &auth)) 1164 return (0); 1165 if (auth == np->auth) 1166 authfnd++; 1167 } 1168 /* 1169 * Some servers, such as DEC's OSF/1 return a nil authenticator 1170 * list to indicate RPCAUTH_UNIX. 1171 */ 1172 if (!authfnd && (authcnt > 0 || np->auth != RPCAUTH_UNIX)) 1173 np->stat = EAUTH; 1174 return (1); 1175 }; 1176 return (0); 1177} 1178 1179void 1180usage() 1181{ 1182 (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", 1183"usage: mount_nfs [-234bcdiLlNPsTU] [-a maxreadahead] [-D deadthresh]", 1184" [-g maxgroups] [-I readdirsize] [-o options] [-R retrycnt]", 1185" [-r readsize] [-t timeout] [-w writesize] [-x retrans]", 1186" rhost:path node"); 1187 exit(1); 1188} 1189