11558Srgrimes/* 21558Srgrimes * Copyright (c) 1992, 1993, 1994 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * This code is derived from software contributed to Berkeley by 61558Srgrimes * Rick Macklem at The University of Guelph. 71558Srgrimes * 81558Srgrimes * Redistribution and use in source and binary forms, with or without 91558Srgrimes * modification, are permitted provided that the following conditions 101558Srgrimes * are met: 111558Srgrimes * 1. Redistributions of source code must retain the above copyright 121558Srgrimes * notice, this list of conditions and the following disclaimer. 131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141558Srgrimes * notice, this list of conditions and the following disclaimer in the 151558Srgrimes * documentation and/or other materials provided with the distribution. 161558Srgrimes * 4. Neither the name of the University nor the names of its contributors 171558Srgrimes * may be used to endorse or promote products derived from this software 181558Srgrimes * without specific prior written permission. 191558Srgrimes * 201558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301558Srgrimes * SUCH DAMAGE. 311558Srgrimes */ 321558Srgrimes 33114589Sobrien#if 0 341558Srgrimes#ifndef lint 3537427Scharnierstatic const char copyright[] = 361558Srgrimes"@(#) Copyright (c) 1992, 1993, 1994\n\ 371558Srgrimes The Regents of the University of California. All rights reserved.\n"; 381558Srgrimes#endif /* not lint */ 391558Srgrimes 401558Srgrimes#ifndef lint 4123680Speterstatic char sccsid[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95"; 42114589Sobrien#endif /* not lint */ 4337427Scharnier#endif 44114589Sobrien#include <sys/cdefs.h> 45114589Sobrien__FBSDID("$FreeBSD: stable/10/sbin/mount_nfs/mount_nfs.c 318683 2017-05-22 21:52:06Z rmacklem $"); 461558Srgrimes 471558Srgrimes#include <sys/param.h> 48192930Srmacklem#include <sys/linker.h> 49192930Srmacklem#include <sys/module.h> 501558Srgrimes#include <sys/mount.h> 5174462Salfred#include <sys/socket.h> 521558Srgrimes#include <sys/stat.h> 531558Srgrimes#include <sys/syslog.h> 54164457Srodrigc#include <sys/uio.h> 551558Srgrimes 561558Srgrimes#include <rpc/rpc.h> 571558Srgrimes#include <rpc/pmap_clnt.h> 581558Srgrimes#include <rpc/pmap_prot.h> 59194880Sdfr#include <rpcsvc/nfs_prot.h> 60194880Sdfr#include <rpcsvc/mount.h> 611558Srgrimes 6283653Speter#include <nfsclient/nfs.h> 631558Srgrimes 641558Srgrimes#include <arpa/inet.h> 651558Srgrimes 661558Srgrimes#include <ctype.h> 671558Srgrimes#include <err.h> 681558Srgrimes#include <errno.h> 6974462Salfred#include <fcntl.h> 701558Srgrimes#include <netdb.h> 711558Srgrimes#include <stdio.h> 721558Srgrimes#include <stdlib.h> 73112570Smdodd#include <string.h> 741558Srgrimes#include <strings.h> 7515770Swollman#include <sysexits.h> 761558Srgrimes#include <unistd.h> 771558Srgrimes 781558Srgrimes#include "mntopts.h" 7953550Sdillon#include "mounttab.h" 801558Srgrimes 8176530Siedowse/* Table for af,sotype -> netid conversions. */ 82275257Straszstatic struct nc_protos { 83183008Srodrigc const char *netid; 8476530Siedowse int af; 8576530Siedowse int sotype; 8676530Siedowse} nc_protos[] = { 8776530Siedowse {"udp", AF_INET, SOCK_DGRAM}, 8876530Siedowse {"tcp", AF_INET, SOCK_STREAM}, 8976530Siedowse {"udp6", AF_INET6, SOCK_DGRAM}, 9076530Siedowse {"tcp6", AF_INET6, SOCK_STREAM}, 91164458Srodrigc {NULL, 0, 0} 9276530Siedowse}; 9376530Siedowse 941558Srgrimesstruct nfhret { 959336Sdfr u_long stat; 969336Sdfr long vers; 979336Sdfr long auth; 989336Sdfr long fhsize; 99194880Sdfr u_char nfh[NFS3_FHSIZE]; 1001558Srgrimes}; 1011558Srgrimes#define BGRND 1 1021558Srgrimes#define ISBGRND 2 103112580Smdodd#define OF_NOINET4 4 104112580Smdodd#define OF_NOINET6 8 105275257Straszstatic int retrycnt = -1; 106275257Straszstatic int opflags = 0; 107275257Straszstatic int nfsproto = IPPROTO_TCP; 108275257Straszstatic int mnttcp_ok = 1; 109275257Straszstatic int noconn = 0; 110275257Strasz/* The 'portspec' is the server nfs port; NULL means look up via rpcbind. */ 111275257Straszstatic const char *portspec = NULL; 112275257Straszstatic struct sockaddr *addr; 113275257Straszstatic int addrlen = 0; 114275257Straszstatic u_char *fh = NULL; 115275257Straszstatic int fhsize = 0; 116275257Straszstatic int secflavor = -1; 117275257Straszstatic int got_principal = 0; 118183008Srodrigc 119275257Straszstatic enum mountmode { 12025004Sdfr ANY, 12125004Sdfr V2, 122166183Srodrigc V3, 123192930Srmacklem V4 12425004Sdfr} mountmode = ANY; 1251558Srgrimes 12675394Siedowse/* Return codes for nfs_tryproto. */ 12775394Siedowseenum tryret { 12875394Siedowse TRYRET_SUCCESS, 12975394Siedowse TRYRET_TIMEOUT, /* No response received. */ 13075394Siedowse TRYRET_REMOTEERR, /* Error received from remote server. */ 13175394Siedowse TRYRET_LOCALERR /* Local failure. */ 13275394Siedowse}; 13375394Siedowse 134275257Straszstatic int sec_name_to_num(const char *sec); 135275257Straszstatic const char *sec_num_to_name(int num); 136203461Sdelphijstatic int getnfsargs(char *, struct iovec **iov, int *iovlen); 13792882Simp/* void set_rpc_maxgrouplist(int); */ 138203461Sdelphijstatic struct netconfig *getnetconf_cached(const char *netid); 139203461Sdelphijstatic const char *netidbytype(int af, int sotype); 140203461Sdelphijstatic void usage(void) __dead2; 141203461Sdelphijstatic int xdr_dir(XDR *, char *); 142203461Sdelphijstatic int xdr_fh(XDR *, struct nfhret *); 143203461Sdelphijstatic enum tryret nfs_tryproto(struct addrinfo *ai, char *hostp, char *spec, 144183008Srodrigc char **errstr, struct iovec **iov, int *iovlen); 145203461Sdelphijstatic enum tryret returncode(enum clnt_stat stat, struct rpc_err *rpcerr); 1461558Srgrimes 1471558Srgrimesint 148156925Simpmain(int argc, char *argv[]) 1491558Srgrimes{ 15092806Sobrien int c; 151164457Srodrigc struct iovec *iov; 152247856Sjkim int num, iovlen; 153275257Strasz char *mntname, *p, *spec, *tmp; 154164733Srodrigc char mntpath[MAXPATHLEN], errmsg[255]; 155275257Strasz char hostname[MAXHOSTNAMELEN + 1], gssn[MAXHOSTNAMELEN + 50]; 156275257Strasz const char *fstype, *gssname; 1571558Srgrimes 158164457Srodrigc iov = NULL; 159164457Srodrigc iovlen = 0; 160164733Srodrigc memset(errmsg, 0, sizeof(errmsg)); 161192930Srmacklem gssname = NULL; 162164457Srodrigc 163164732Srodrigc fstype = strrchr(argv[0], '_'); 164164732Srodrigc if (fstype == NULL) 165164732Srodrigc errx(EX_USAGE, "argv[0] must end in _fstype"); 166164732Srodrigc 167164732Srodrigc ++fstype; 168164732Srodrigc 1691558Srgrimes while ((c = getopt(argc, argv, 170192578Srwatson "23a:bcdD:g:I:iLlNo:PR:r:sTt:w:x:U")) != -1) 1711558Srgrimes switch (c) { 17225004Sdfr case '2': 17325004Sdfr mountmode = V2; 17425004Sdfr break; 1759336Sdfr case '3': 17625004Sdfr mountmode = V3; 1779336Sdfr break; 1781558Srgrimes case 'a': 179214419Sjh printf("-a deprecated, use -o readahead=<value>\n"); 180183008Srodrigc build_iovec(&iov, &iovlen, "readahead", optarg, (size_t)-1); 1811558Srgrimes break; 1821558Srgrimes case 'b': 1831558Srgrimes opflags |= BGRND; 1841558Srgrimes break; 1851558Srgrimes case 'c': 186183008Srodrigc printf("-c deprecated, use -o noconn\n"); 187183008Srodrigc build_iovec(&iov, &iovlen, "noconn", NULL, 0); 188183008Srodrigc noconn = 1; 1891558Srgrimes break; 1901558Srgrimes case 'D': 191183008Srodrigc printf("-D deprecated, use -o deadthresh=<value>\n"); 192183008Srodrigc build_iovec(&iov, &iovlen, "deadthresh", optarg, (size_t)-1); 1931558Srgrimes break; 1941558Srgrimes case 'd': 195183008Srodrigc printf("-d deprecated, use -o dumbtimer"); 196183008Srodrigc build_iovec(&iov, &iovlen, "dumbtimer", NULL, 0); 1971558Srgrimes break; 1981558Srgrimes case 'g': 199183008Srodrigc printf("-g deprecated, use -o maxgroups"); 2001558Srgrimes num = strtol(optarg, &p, 10); 2011558Srgrimes if (*p || num <= 0) 2021558Srgrimes errx(1, "illegal -g value -- %s", optarg); 203183008Srodrigc //set_rpc_maxgrouplist(num); 204183008Srodrigc build_iovec(&iov, &iovlen, "maxgroups", optarg, (size_t)-1); 2051558Srgrimes break; 2069336Sdfr case 'I': 207183008Srodrigc printf("-I deprecated, use -o readdirsize=<value>\n"); 208183008Srodrigc build_iovec(&iov, &iovlen, "readdirsize", optarg, (size_t)-1); 2099336Sdfr break; 2101558Srgrimes case 'i': 211183008Srodrigc printf("-i deprecated, use -o intr\n"); 212183008Srodrigc build_iovec(&iov, &iovlen, "intr", NULL, 0); 2131558Srgrimes break; 21486284Salfred case 'L': 215216725Ssimon printf("-L deprecated, use -o nolockd\n"); 216183008Srodrigc build_iovec(&iov, &iovlen, "nolockd", NULL, 0); 21786284Salfred break; 2181558Srgrimes case 'l': 219183008Srodrigc printf("-l deprecated, -o rdirplus\n"); 220183008Srodrigc build_iovec(&iov, &iovlen, "rdirplus", NULL, 0); 2211558Srgrimes break; 22230580Sjoerg case 'N': 223183008Srodrigc printf("-N deprecated, do not specify -o resvport\n"); 22430580Sjoerg break; 225183008Srodrigc case 'o': { 226183008Srodrigc int pass_flag_to_nmount; 227183008Srodrigc char *opt = optarg; 228183008Srodrigc while (opt) { 229183008Srodrigc char *pval = NULL; 230183008Srodrigc char *pnextopt = NULL; 231275257Strasz const char *val = ""; 232183008Srodrigc pass_flag_to_nmount = 1; 233198491Sjh pnextopt = strchr(opt, ','); 234198491Sjh if (pnextopt != NULL) { 235198491Sjh *pnextopt = '\0'; 236198491Sjh pnextopt++; 237198491Sjh } 238183008Srodrigc pval = strchr(opt, '='); 239183008Srodrigc if (pval != NULL) { 240183008Srodrigc *pval = '\0'; 241183008Srodrigc val = pval + 1; 242183008Srodrigc } 243183008Srodrigc if (strcmp(opt, "bg") == 0) { 244183008Srodrigc opflags |= BGRND; 245183008Srodrigc pass_flag_to_nmount=0; 246183008Srodrigc } else if (strcmp(opt, "fg") == 0) { 247183008Srodrigc /* same as not specifying -o bg */ 248183008Srodrigc pass_flag_to_nmount=0; 249192930Srmacklem } else if (strcmp(opt, "gssname") == 0) { 250192930Srmacklem pass_flag_to_nmount = 0; 251192930Srmacklem gssname = val; 252183008Srodrigc } else if (strcmp(opt, "mntudp") == 0) { 253183008Srodrigc mnttcp_ok = 0; 254183008Srodrigc nfsproto = IPPROTO_UDP; 255183008Srodrigc } else if (strcmp(opt, "udp") == 0) { 256183008Srodrigc nfsproto = IPPROTO_UDP; 257183008Srodrigc } else if (strcmp(opt, "tcp") == 0) { 258183008Srodrigc nfsproto = IPPROTO_TCP; 259183008Srodrigc } else if (strcmp(opt, "noinet4") == 0) { 260183008Srodrigc pass_flag_to_nmount=0; 261183008Srodrigc opflags |= OF_NOINET4; 262183008Srodrigc } else if (strcmp(opt, "noinet6") == 0) { 263183008Srodrigc pass_flag_to_nmount=0; 264183008Srodrigc opflags |= OF_NOINET6; 265183008Srodrigc } else if (strcmp(opt, "noconn") == 0) { 266183008Srodrigc noconn = 1; 267183008Srodrigc } else if (strcmp(opt, "nfsv2") == 0) { 268183008Srodrigc pass_flag_to_nmount=0; 269183008Srodrigc mountmode = V2; 270183008Srodrigc } else if (strcmp(opt, "nfsv3") == 0) { 271183008Srodrigc mountmode = V3; 272192930Srmacklem } else if (strcmp(opt, "nfsv4") == 0) { 273192930Srmacklem pass_flag_to_nmount=0; 274192930Srmacklem mountmode = V4; 275221124Srmacklem fstype = "nfs"; 276192930Srmacklem nfsproto = IPPROTO_TCP; 277192930Srmacklem if (portspec == NULL) 278192930Srmacklem portspec = "2049"; 279183008Srodrigc } else if (strcmp(opt, "port") == 0) { 280183008Srodrigc pass_flag_to_nmount=0; 281275257Strasz asprintf(&tmp, "%d", atoi(val)); 282275257Strasz if (tmp == NULL) 283103039Speter err(1, "asprintf"); 284275257Strasz portspec = tmp; 285192930Srmacklem } else if (strcmp(opt, "principal") == 0) { 286192930Srmacklem got_principal = 1; 287275249Strasz } else if (strcmp(opt, "proto") == 0) { 288275249Strasz pass_flag_to_nmount=0; 289275249Strasz if (strcmp(val, "tcp") == 0) { 290275249Strasz nfsproto = IPPROTO_TCP; 291275249Strasz opflags |= OF_NOINET6; 292275249Strasz build_iovec(&iov, &iovlen, 293275249Strasz "tcp", NULL, 0); 294275249Strasz } else if (strcmp(val, "udp") == 0) { 295275249Strasz mnttcp_ok = 0; 296275249Strasz nfsproto = IPPROTO_UDP; 297275249Strasz opflags |= OF_NOINET6; 298275249Strasz build_iovec(&iov, &iovlen, 299275249Strasz "udp", NULL, 0); 300275249Strasz } else if (strcmp(val, "tcp6") == 0) { 301275249Strasz nfsproto = IPPROTO_TCP; 302275249Strasz opflags |= OF_NOINET4; 303275249Strasz build_iovec(&iov, &iovlen, 304275249Strasz "tcp", NULL, 0); 305275249Strasz } else if (strcmp(val, "udp6") == 0) { 306275249Strasz mnttcp_ok = 0; 307275249Strasz nfsproto = IPPROTO_UDP; 308275249Strasz opflags |= OF_NOINET4; 309275249Strasz build_iovec(&iov, &iovlen, 310275249Strasz "udp", NULL, 0); 311275249Strasz } else { 312275249Strasz errx(1, 313275249Strasz "illegal proto value -- %s", 314275249Strasz val); 315275249Strasz } 316184588Sdfr } else if (strcmp(opt, "sec") == 0) { 317184588Sdfr /* 318184588Sdfr * Don't add this option to 319184588Sdfr * the iovec yet - we will 320184588Sdfr * negotiate which sec flavor 321184588Sdfr * to use with the remote 322184588Sdfr * mountd. 323184588Sdfr */ 324184588Sdfr pass_flag_to_nmount=0; 325184588Sdfr secflavor = sec_name_to_num(val); 326184588Sdfr if (secflavor < 0) { 327184588Sdfr errx(1, 328184588Sdfr "illegal sec value -- %s", 329184588Sdfr val); 330184588Sdfr } 331183008Srodrigc } else if (strcmp(opt, "retrycnt") == 0) { 332183008Srodrigc pass_flag_to_nmount=0; 333183008Srodrigc num = strtol(val, &p, 10); 334183008Srodrigc if (*p || num < 0) 335183008Srodrigc errx(1, "illegal retrycnt value -- %s", val); 336183008Srodrigc retrycnt = num; 337183008Srodrigc } else if (strcmp(opt, "maxgroups") == 0) { 338183008Srodrigc num = strtol(val, &p, 10); 339183008Srodrigc if (*p || num <= 0) 340183008Srodrigc errx(1, "illegal maxgroups value -- %s", val); 341183008Srodrigc //set_rpc_maxgrouplist(num); 342270043Sbz } else if (strcmp(opt, "vers") == 0) { 343270043Sbz num = strtol(val, &p, 10); 344270043Sbz if (*p || num <= 0) 345270043Sbz errx(1, "illegal vers value -- " 346270043Sbz "%s", val); 347270043Sbz switch (num) { 348270043Sbz case 2: 349270043Sbz mountmode = V2; 350270043Sbz break; 351270043Sbz case 3: 352270043Sbz mountmode = V3; 353270043Sbz build_iovec(&iov, &iovlen, 354270043Sbz "nfsv3", NULL, 0); 355270043Sbz break; 356270043Sbz case 4: 357270043Sbz mountmode = V4; 358270043Sbz fstype = "nfs"; 359270043Sbz nfsproto = IPPROTO_TCP; 360270043Sbz if (portspec == NULL) 361270043Sbz portspec = "2049"; 362270043Sbz break; 363270043Sbz default: 364270043Sbz errx(1, "illegal nfs version " 365270043Sbz "value -- %s", val); 366270043Sbz } 367270043Sbz pass_flag_to_nmount=0; 368103039Speter } 369275257Strasz if (pass_flag_to_nmount) { 370275257Strasz build_iovec(&iov, &iovlen, opt, 371275257Strasz __DECONST(void *, val), 372183008Srodrigc strlen(val) + 1); 373275257Strasz } 374183008Srodrigc opt = pnextopt; 37575394Siedowse } 376103039Speter } 3771558Srgrimes break; 3781558Srgrimes case 'P': 379183008Srodrigc /* obsolete for -o noresvport now default */ 380183008Srodrigc printf("-P deprecated, use -o noresvport\n"); 381183008Srodrigc build_iovec(&iov, &iovlen, "noresvport", NULL, 0); 3821558Srgrimes break; 3831558Srgrimes case 'R': 384183008Srodrigc printf("-R deprecated, use -o retrycnt=<retrycnt>\n"); 3851558Srgrimes num = strtol(optarg, &p, 10); 38680006Siedowse if (*p || num < 0) 3871558Srgrimes errx(1, "illegal -R value -- %s", optarg); 3881558Srgrimes retrycnt = num; 3891558Srgrimes break; 3901558Srgrimes case 'r': 391183008Srodrigc printf("-r deprecated, use -o rsize=<rsize>\n"); 392183008Srodrigc build_iovec(&iov, &iovlen, "rsize", optarg, (size_t)-1); 3931558Srgrimes break; 3941558Srgrimes case 's': 395183008Srodrigc printf("-s deprecated, use -o soft\n"); 396183008Srodrigc build_iovec(&iov, &iovlen, "soft", NULL, 0); 3971558Srgrimes break; 3981558Srgrimes case 'T': 3999336Sdfr nfsproto = IPPROTO_TCP; 400183008Srodrigc printf("-T deprecated, use -o tcp\n"); 4011558Srgrimes break; 4021558Srgrimes case 't': 403183008Srodrigc printf("-t deprecated, use -o timeout=<value>\n"); 404183008Srodrigc build_iovec(&iov, &iovlen, "timeout", optarg, (size_t)-1); 4051558Srgrimes break; 4061558Srgrimes case 'w': 407183008Srodrigc printf("-w deprecated, use -o wsize=<value>\n"); 408183008Srodrigc build_iovec(&iov, &iovlen, "wsize", optarg, (size_t)-1); 4091558Srgrimes break; 4101558Srgrimes case 'x': 411183008Srodrigc printf("-x deprecated, use -o retrans=<value>\n"); 412183008Srodrigc build_iovec(&iov, &iovlen, "retrans", optarg, (size_t)-1); 4131558Srgrimes break; 4149336Sdfr case 'U': 415183008Srodrigc printf("-U deprecated, use -o mntudp\n"); 4169336Sdfr mnttcp_ok = 0; 417166183Srodrigc nfsproto = IPPROTO_UDP; 418183008Srodrigc build_iovec(&iov, &iovlen, "mntudp", NULL, 0); 4199336Sdfr break; 4201558Srgrimes default: 4211558Srgrimes usage(); 4221558Srgrimes break; 4231558Srgrimes } 4241558Srgrimes argc -= optind; 4251558Srgrimes argv += optind; 4261558Srgrimes 42723680Speter if (argc != 2) { 4285966Sdg usage(); 42923680Speter /* NOTREACHED */ 43023680Speter } 4311558Srgrimes 4321558Srgrimes spec = *argv++; 433275257Strasz mntname = *argv; 4341558Srgrimes 43580006Siedowse if (retrycnt == -1) 43680086Siedowse /* The default is to keep retrying forever. */ 43780086Siedowse retrycnt = 0; 4382999Swollman 439192930Srmacklem /* 440221124Srmacklem * If the fstye is "oldnfs", run the old NFS client unless the 441221124Srmacklem * "nfsv4" option was specified. 442192930Srmacklem */ 443221124Srmacklem if (strcmp(fstype, "nfs") == 0) { 444192930Srmacklem if (modfind("nfscl") < 0) { 445192930Srmacklem /* Not present in kernel, try loading it */ 446192930Srmacklem if (kldload("nfscl") < 0 || 447192930Srmacklem modfind("nfscl") < 0) 448192930Srmacklem errx(1, "nfscl is not available"); 449192930Srmacklem } 450192930Srmacklem } 451192930Srmacklem 452192930Srmacklem /* 453192930Srmacklem * Add the fqdn to the gssname, as required. 454192930Srmacklem */ 455192930Srmacklem if (gssname != NULL) { 456192930Srmacklem if (strchr(gssname, '@') == NULL && 457192930Srmacklem gethostname(hostname, MAXHOSTNAMELEN) == 0) { 458192930Srmacklem snprintf(gssn, sizeof (gssn), "%s@%s", gssname, 459192930Srmacklem hostname); 460192930Srmacklem gssname = gssn; 461192930Srmacklem } 462275257Strasz build_iovec(&iov, &iovlen, "gssname", 463275257Strasz __DECONST(void *, gssname), strlen(gssname) + 1); 464192930Srmacklem } 465192930Srmacklem 466192578Srwatson if (!getnfsargs(spec, &iov, &iovlen)) 467192578Srwatson exit(1); 468166183Srodrigc 46952055Sphk /* resolve the mountpoint with realpath(3) */ 470275257Strasz if (checkpath(mntname, mntpath) != 0) 471230226Sjh err(1, "%s", mntpath); 47252055Sphk 473275257Strasz build_iovec(&iov, &iovlen, "fstype", 474275257Strasz __DECONST(void *, fstype), (size_t)-1); 475164457Srodrigc build_iovec(&iov, &iovlen, "fspath", mntpath, (size_t)-1); 476164733Srodrigc build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 477164457Srodrigc 478275255Strasz if (nmount(iov, iovlen, 0)) 479275255Strasz err(1, "%s, %s", mntpath, errmsg); 4809336Sdfr 4811558Srgrimes exit(0); 4821558Srgrimes} 4831558Srgrimes 484183008Srodrigcstatic int 485275257Straszsec_name_to_num(const char *sec) 486184588Sdfr{ 487184588Sdfr if (!strcmp(sec, "krb5")) 488184588Sdfr return (RPCSEC_GSS_KRB5); 489184588Sdfr if (!strcmp(sec, "krb5i")) 490184588Sdfr return (RPCSEC_GSS_KRB5I); 491184588Sdfr if (!strcmp(sec, "krb5p")) 492184588Sdfr return (RPCSEC_GSS_KRB5P); 493184588Sdfr if (!strcmp(sec, "sys")) 494184588Sdfr return (AUTH_SYS); 495184588Sdfr return (-1); 496184588Sdfr} 497184588Sdfr 498275257Straszstatic const char * 499184588Sdfrsec_num_to_name(int flavor) 500184588Sdfr{ 501184588Sdfr switch (flavor) { 502184588Sdfr case RPCSEC_GSS_KRB5: 503184588Sdfr return ("krb5"); 504184588Sdfr case RPCSEC_GSS_KRB5I: 505184588Sdfr return ("krb5i"); 506184588Sdfr case RPCSEC_GSS_KRB5P: 507184588Sdfr return ("krb5p"); 508184588Sdfr case AUTH_SYS: 509184588Sdfr return ("sys"); 510184588Sdfr } 511184588Sdfr return (NULL); 512184588Sdfr} 513184588Sdfr 514203461Sdelphijstatic int 515183008Srodrigcgetnfsargs(char *spec, struct iovec **iov, int *iovlen) 516183008Srodrigc{ 51774462Salfred struct addrinfo hints, *ai_nfs, *ai; 51875394Siedowse enum tryret ret; 519203490Sume int ecode, speclen, remoteerr, offset, have_bracket = 0; 52075394Siedowse char *hostp, *delimp, *errstr; 52152679Sgreen size_t len; 522192930Srmacklem static char nam[MNAMELEN + 1], pname[MAXHOSTNAMELEN + 5]; 5231558Srgrimes 524203490Sume if (*spec == '[' && (delimp = strchr(spec + 1, ']')) != NULL && 525203490Sume *(delimp + 1) == ':') { 526203490Sume hostp = spec + 1; 527203490Sume spec = delimp + 2; 528203490Sume have_bracket = 1; 529203490Sume } else if ((delimp = strrchr(spec, ':')) != NULL) { 5301558Srgrimes hostp = spec; 5311558Srgrimes spec = delimp + 1; 53252055Sphk } else if ((delimp = strrchr(spec, '@')) != NULL) { 53352055Sphk warnx("path@server syntax is deprecated, use server:path"); 53452055Sphk hostp = delimp + 1; 5351558Srgrimes } else { 53652055Sphk warnx("no <host>:<dirpath> nfs-name"); 5371558Srgrimes return (0); 5381558Srgrimes } 5391558Srgrimes *delimp = '\0'; 54052055Sphk 5411558Srgrimes /* 54252055Sphk * If there has been a trailing slash at mounttime it seems 54352055Sphk * that some mountd implementations fail to remove the mount 54452055Sphk * entries from their mountlist while unmounting. 54552055Sphk */ 54652679Sgreen for (speclen = strlen(spec); 54752679Sgreen speclen > 1 && spec[speclen - 1] == '/'; 54852679Sgreen speclen--) 54952055Sphk spec[speclen - 1] = '\0'; 55052055Sphk if (strlen(hostp) + strlen(spec) + 1 > MNAMELEN) { 55152055Sphk warnx("%s:%s: %s", hostp, spec, strerror(ENAMETOOLONG)); 55252055Sphk return (0); 55352055Sphk } 55452055Sphk /* Make both '@' and ':' notations equal */ 55552679Sgreen if (*hostp != '\0') { 55652679Sgreen len = strlen(hostp); 557203490Sume offset = 0; 558203490Sume if (have_bracket) 559203490Sume nam[offset++] = '['; 560203490Sume memmove(nam + offset, hostp, len); 561203490Sume if (have_bracket) 562203490Sume nam[len + offset++] = ']'; 563203490Sume nam[len + offset++] = ':'; 564203490Sume memmove(nam + len + offset, spec, speclen); 565203490Sume nam[len + speclen + offset] = '\0'; 56652679Sgreen } 5671558Srgrimes 5681558Srgrimes /* 56983653Speter * Handle an internet host address. 5701558Srgrimes */ 57174462Salfred memset(&hints, 0, sizeof hints); 57274462Salfred hints.ai_flags = AI_NUMERICHOST; 573183008Srodrigc if (nfsproto == IPPROTO_TCP) 574183008Srodrigc hints.ai_socktype = SOCK_STREAM; 575183008Srodrigc else if (nfsproto == IPPROTO_UDP) 576183008Srodrigc hints.ai_socktype = SOCK_DGRAM; 577183008Srodrigc 57883653Speter if (getaddrinfo(hostp, portspec, &hints, &ai_nfs) != 0) { 579192930Srmacklem hints.ai_flags = AI_CANONNAME; 58075394Siedowse if ((ecode = getaddrinfo(hostp, portspec, &hints, &ai_nfs)) 58175394Siedowse != 0) { 58275394Siedowse if (portspec == NULL) 58375394Siedowse errx(1, "%s: %s", hostp, gai_strerror(ecode)); 58475394Siedowse else 58575394Siedowse errx(1, "%s:%s: %s", hostp, portspec, 58675394Siedowse gai_strerror(ecode)); 5871558Srgrimes return (0); 5881558Srgrimes } 589192930Srmacklem 590192930Srmacklem /* 591192930Srmacklem * For a Kerberized nfs mount where the "principal" 592192930Srmacklem * argument has not been set, add it here. 593192930Srmacklem */ 594286483Srmacklem if (got_principal == 0 && secflavor != AUTH_SYS && 595286483Srmacklem ai_nfs->ai_canonname != NULL) { 596192930Srmacklem snprintf(pname, sizeof (pname), "nfs@%s", 597192930Srmacklem ai_nfs->ai_canonname); 598192930Srmacklem build_iovec(iov, iovlen, "principal", pname, 599192930Srmacklem strlen(pname) + 1); 600192930Srmacklem } 60174462Salfred } 6021558Srgrimes 60375394Siedowse ret = TRYRET_LOCALERR; 60480006Siedowse for (;;) { 60575394Siedowse /* 60675394Siedowse * Try each entry returned by getaddrinfo(). Note the 607229778Suqs * occurrence of remote errors by setting `remoteerr'. 60875394Siedowse */ 60975394Siedowse remoteerr = 0; 61075394Siedowse for (ai = ai_nfs; ai != NULL; ai = ai->ai_next) { 611112580Smdodd if ((ai->ai_family == AF_INET6) && 612112580Smdodd (opflags & OF_NOINET6)) 613112580Smdodd continue; 614112580Smdodd if ((ai->ai_family == AF_INET) && 615112580Smdodd (opflags & OF_NOINET4)) 616112580Smdodd continue; 617183008Srodrigc ret = nfs_tryproto(ai, hostp, spec, &errstr, iov, 618183008Srodrigc iovlen); 61975394Siedowse if (ret == TRYRET_SUCCESS) 62075394Siedowse break; 62175394Siedowse if (ret != TRYRET_LOCALERR) 62275394Siedowse remoteerr = 1; 62375394Siedowse if ((opflags & ISBGRND) == 0) 62475394Siedowse fprintf(stderr, "%s\n", errstr); 62575394Siedowse } 62675394Siedowse if (ret == TRYRET_SUCCESS) 62775394Siedowse break; 62874462Salfred 62980006Siedowse /* Exit if all errors were local. */ 63080006Siedowse if (!remoteerr) 63180006Siedowse exit(1); 63280006Siedowse 63374462Salfred /* 63480006Siedowse * If retrycnt == 0, we are to keep retrying forever. 63580006Siedowse * Otherwise decrement it, and exit if it hits zero. 63674462Salfred */ 63780006Siedowse if (retrycnt != 0 && --retrycnt == 0) 63875394Siedowse exit(1); 63975394Siedowse 64075394Siedowse if ((opflags & (BGRND | ISBGRND)) == BGRND) { 64175394Siedowse warnx("Cannot immediately mount %s:%s, backgrounding", 64275394Siedowse hostp, spec); 64375394Siedowse opflags |= ISBGRND; 64475394Siedowse if (daemon(0, 0) != 0) 64575394Siedowse err(1, "daemon"); 64674462Salfred } 64775394Siedowse sleep(60); 64875394Siedowse } 64975394Siedowse freeaddrinfo(ai_nfs); 650183008Srodrigc 651183008Srodrigc build_iovec(iov, iovlen, "hostname", nam, (size_t)-1); 652102231Strhodes /* Add mounted file system to PATH_MOUNTTAB */ 653318683Srmacklem if (mountmode != V4 && !add_mtab(hostp, spec)) 65475394Siedowse warnx("can't update %s for %s:%s", PATH_MOUNTTAB, hostp, spec); 65575394Siedowse return (1); 65675394Siedowse} 65774462Salfred 65875394Siedowse/* 65975394Siedowse * Try to set up the NFS arguments according to the address 66075394Siedowse * family, protocol (and possibly port) specified in `ai'. 66175394Siedowse * 66275394Siedowse * Returns TRYRET_SUCCESS if successful, or: 66375394Siedowse * TRYRET_TIMEOUT The server did not respond. 66475394Siedowse * TRYRET_REMOTEERR The server reported an error. 66575394Siedowse * TRYRET_LOCALERR Local failure. 66675394Siedowse * 66775394Siedowse * In all error cases, *errstr will be set to a statically-allocated string 66875394Siedowse * describing the error. 66975394Siedowse */ 670203461Sdelphijstatic enum tryret 671183008Srodrigcnfs_tryproto(struct addrinfo *ai, char *hostp, char *spec, char **errstr, 672183008Srodrigc struct iovec **iov, int *iovlen) 67375394Siedowse{ 67475394Siedowse static char errbuf[256]; 67575394Siedowse struct sockaddr_storage nfs_ss; 67675394Siedowse struct netbuf nfs_nb; 67775394Siedowse struct nfhret nfhret; 67875394Siedowse struct timeval try; 67975394Siedowse struct rpc_err rpcerr; 68075394Siedowse CLIENT *clp; 68175394Siedowse struct netconfig *nconf, *nconf_mnt; 682275257Strasz const char *netid, *netid_mnt, *secname; 683183008Srodrigc int doconnect, nfsvers, mntvers, sotype; 684275257Strasz enum clnt_stat clntstat; 68575394Siedowse enum mountmode trymntmode; 68674462Salfred 687212195Skevlo sotype = 0; 68875394Siedowse trymntmode = mountmode; 68975394Siedowse errbuf[0] = '\0'; 69075394Siedowse *errstr = errbuf; 69174462Salfred 692183008Srodrigc if (nfsproto == IPPROTO_TCP) 693183008Srodrigc sotype = SOCK_STREAM; 694183008Srodrigc else if (nfsproto == IPPROTO_UDP) 695183008Srodrigc sotype = SOCK_DGRAM; 696183008Srodrigc 697183008Srodrigc if ((netid = netidbytype(ai->ai_family, sotype)) == NULL) { 69876530Siedowse snprintf(errbuf, sizeof errbuf, 699183008Srodrigc "af %d sotype %d not supported", ai->ai_family, sotype); 70076530Siedowse return (TRYRET_LOCALERR); 70176530Siedowse } 70276530Siedowse if ((nconf = getnetconf_cached(netid)) == NULL) { 70375394Siedowse snprintf(errbuf, sizeof errbuf, "%s: %s", netid, nc_sperror()); 70475394Siedowse return (TRYRET_LOCALERR); 70575394Siedowse } 70675394Siedowse /* The RPCPROG_MNT netid may be different. */ 70775394Siedowse if (mnttcp_ok) { 70875401Siedowse netid_mnt = netid; 70975394Siedowse nconf_mnt = nconf; 71075394Siedowse } else { 71176530Siedowse if ((netid_mnt = netidbytype(ai->ai_family, SOCK_DGRAM)) 71276530Siedowse == NULL) { 71376530Siedowse snprintf(errbuf, sizeof errbuf, 71476530Siedowse "af %d sotype SOCK_DGRAM not supported", 71576530Siedowse ai->ai_family); 71676530Siedowse return (TRYRET_LOCALERR); 71776530Siedowse } 71876530Siedowse if ((nconf_mnt = getnetconf_cached(netid_mnt)) == NULL) { 71975401Siedowse snprintf(errbuf, sizeof errbuf, "%s: %s", netid_mnt, 72075394Siedowse nc_sperror()); 72175394Siedowse return (TRYRET_LOCALERR); 72275046Sache } 72375394Siedowse } 72475401Siedowse 72575394Siedowsetryagain: 726192930Srmacklem if (trymntmode == V4) { 727192930Srmacklem nfsvers = 4; 728275257Strasz mntvers = 3; /* Workaround for GCC. */ 729192930Srmacklem } else if (trymntmode == V2) { 73075394Siedowse nfsvers = 2; 73175394Siedowse mntvers = 1; 73275394Siedowse } else { 73375394Siedowse nfsvers = 3; 73475394Siedowse mntvers = 3; 73575394Siedowse } 73675046Sache 73775394Siedowse if (portspec != NULL) { 73875394Siedowse /* `ai' contains the complete nfsd sockaddr. */ 73975394Siedowse nfs_nb.buf = ai->ai_addr; 74075394Siedowse nfs_nb.len = nfs_nb.maxlen = ai->ai_addrlen; 74175394Siedowse } else { 74275394Siedowse /* Ask the remote rpcbind. */ 74375394Siedowse nfs_nb.buf = &nfs_ss; 74475394Siedowse nfs_nb.len = nfs_nb.maxlen = sizeof nfs_ss; 74575394Siedowse 746194880Sdfr if (!rpcb_getaddr(NFS_PROGRAM, nfsvers, nconf, &nfs_nb, 74775394Siedowse hostp)) { 74875394Siedowse if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH && 74975394Siedowse trymntmode == ANY) { 75075394Siedowse trymntmode = V2; 75175394Siedowse goto tryagain; 7521558Srgrimes } 75375394Siedowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", 75475394Siedowse netid, hostp, spec, 75575394Siedowse clnt_spcreateerror("RPCPROG_NFS")); 75675394Siedowse return (returncode(rpc_createerr.cf_stat, 75775394Siedowse &rpc_createerr.cf_error)); 75875046Sache } 75975394Siedowse } 76075394Siedowse 76175394Siedowse /* Check that the server (nfsd) responds on the port we have chosen. */ 762194880Sdfr clp = clnt_tli_create(RPC_ANYFD, nconf, &nfs_nb, NFS_PROGRAM, nfsvers, 76375394Siedowse 0, 0); 76475394Siedowse if (clp == NULL) { 76575394Siedowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid, 76675394Siedowse hostp, spec, clnt_spcreateerror("nfsd: RPCPROG_NFS")); 76775394Siedowse return (returncode(rpc_createerr.cf_stat, 76875394Siedowse &rpc_createerr.cf_error)); 76975394Siedowse } 770183008Srodrigc if (sotype == SOCK_DGRAM && noconn == 0) { 77178679Siedowse /* 77278679Siedowse * Use connect(), to match what the kernel does. This 77378679Siedowse * catches cases where the server responds from the 77478679Siedowse * wrong source address. 77578679Siedowse */ 77678679Siedowse doconnect = 1; 77778679Siedowse if (!clnt_control(clp, CLSET_CONNECT, (char *)&doconnect)) { 77878679Siedowse clnt_destroy(clp); 77978679Siedowse snprintf(errbuf, sizeof errbuf, 78078679Siedowse "[%s] %s:%s: CLSET_CONNECT failed", netid, hostp, 78178679Siedowse spec); 78278679Siedowse return (TRYRET_LOCALERR); 78378679Siedowse } 78478679Siedowse } 78578679Siedowse 78675394Siedowse try.tv_sec = 10; 78775394Siedowse try.tv_usec = 0; 788275257Strasz clntstat = clnt_call(clp, NFSPROC_NULL, (xdrproc_t)xdr_void, NULL, 789192930Srmacklem (xdrproc_t)xdr_void, NULL, try); 790275257Strasz if (clntstat != RPC_SUCCESS) { 791275257Strasz if (clntstat == RPC_PROGVERSMISMATCH && trymntmode == ANY) { 79275394Siedowse clnt_destroy(clp); 79375394Siedowse trymntmode = V2; 79475394Siedowse goto tryagain; 7951558Srgrimes } 79675394Siedowse clnt_geterr(clp, &rpcerr); 79775394Siedowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid, 79875394Siedowse hostp, spec, clnt_sperror(clp, "NFSPROC_NULL")); 79975394Siedowse clnt_destroy(clp); 800275257Strasz return (returncode(clntstat, &rpcerr)); 8011558Srgrimes } 80275394Siedowse clnt_destroy(clp); 80375394Siedowse 804192930Srmacklem /* 805192930Srmacklem * For NFSv4, there is no mount protocol. 806192930Srmacklem */ 807192930Srmacklem if (trymntmode == V4) { 808192930Srmacklem /* 809192930Srmacklem * Store the server address in nfsargsp, making 810192930Srmacklem * sure to copy any locally allocated structures. 811192930Srmacklem */ 812192930Srmacklem addrlen = nfs_nb.len; 813192930Srmacklem addr = malloc(addrlen); 814192930Srmacklem if (addr == NULL) 815192930Srmacklem err(1, "malloc"); 816192930Srmacklem bcopy(nfs_nb.buf, addr, addrlen); 817192930Srmacklem 818192930Srmacklem build_iovec(iov, iovlen, "addr", addr, addrlen); 819192930Srmacklem secname = sec_num_to_name(secflavor); 820275257Strasz if (secname != NULL) { 821275257Strasz build_iovec(iov, iovlen, "sec", 822275257Strasz __DECONST(void *, secname), (size_t)-1); 823275257Strasz } 824192930Srmacklem build_iovec(iov, iovlen, "nfsv4", NULL, 0); 825192930Srmacklem build_iovec(iov, iovlen, "dirpath", spec, (size_t)-1); 826192930Srmacklem 827192930Srmacklem return (TRYRET_SUCCESS); 828192930Srmacklem } 829192930Srmacklem 830194880Sdfr /* Send the MOUNTPROC_MNT RPC to get the root filehandle. */ 83175394Siedowse try.tv_sec = 10; 83275394Siedowse try.tv_usec = 0; 833194880Sdfr clp = clnt_tp_create(hostp, MOUNTPROG, mntvers, nconf_mnt); 83475394Siedowse if (clp == NULL) { 83575401Siedowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 83675394Siedowse hostp, spec, clnt_spcreateerror("RPCMNT: clnt_create")); 83775394Siedowse return (returncode(rpc_createerr.cf_stat, 83875394Siedowse &rpc_createerr.cf_error)); 8391558Srgrimes } 84075394Siedowse clp->cl_auth = authsys_create_default(); 841184588Sdfr nfhret.auth = secflavor; 84275394Siedowse nfhret.vers = mntvers; 843275257Strasz clntstat = clnt_call(clp, MOUNTPROC_MNT, (xdrproc_t)xdr_dir, spec, 844112570Smdodd (xdrproc_t)xdr_fh, &nfhret, 84575394Siedowse try); 84675394Siedowse auth_destroy(clp->cl_auth); 847275257Strasz if (clntstat != RPC_SUCCESS) { 848275257Strasz if (clntstat == RPC_PROGVERSMISMATCH && trymntmode == ANY) { 84975394Siedowse clnt_destroy(clp); 85075394Siedowse trymntmode = V2; 85175394Siedowse goto tryagain; 85275394Siedowse } 85375394Siedowse clnt_geterr(clp, &rpcerr); 85475401Siedowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 85575394Siedowse hostp, spec, clnt_sperror(clp, "RPCPROG_MNT")); 85675394Siedowse clnt_destroy(clp); 857275257Strasz return (returncode(clntstat, &rpcerr)); 8581558Srgrimes } 85975394Siedowse clnt_destroy(clp); 86075394Siedowse 86175394Siedowse if (nfhret.stat != 0) { 86275401Siedowse snprintf(errbuf, sizeof errbuf, "[%s] %s:%s: %s", netid_mnt, 86375394Siedowse hostp, spec, strerror(nfhret.stat)); 86475394Siedowse return (TRYRET_REMOTEERR); 86575394Siedowse } 86675394Siedowse 86775394Siedowse /* 86875394Siedowse * Store the filehandle and server address in nfsargsp, making 86975394Siedowse * sure to copy any locally allocated structures. 87075394Siedowse */ 871183008Srodrigc addrlen = nfs_nb.len; 872183008Srodrigc addr = malloc(addrlen); 873183008Srodrigc fhsize = nfhret.fhsize; 874183008Srodrigc fh = malloc(fhsize); 875183008Srodrigc if (addr == NULL || fh == NULL) 87675394Siedowse err(1, "malloc"); 877183008Srodrigc bcopy(nfs_nb.buf, addr, addrlen); 878183008Srodrigc bcopy(nfhret.nfh, fh, fhsize); 87975394Siedowse 880183008Srodrigc build_iovec(iov, iovlen, "addr", addr, addrlen); 881183008Srodrigc build_iovec(iov, iovlen, "fh", fh, fhsize); 882184588Sdfr secname = sec_num_to_name(nfhret.auth); 883275257Strasz if (secname) { 884275257Strasz build_iovec(iov, iovlen, "sec", 885275257Strasz __DECONST(void *, secname), (size_t)-1); 886275257Strasz } 88775394Siedowse if (nfsvers == 3) 888183008Srodrigc build_iovec(iov, iovlen, "nfsv3", NULL, 0); 88975394Siedowse 89075394Siedowse return (TRYRET_SUCCESS); 8911558Srgrimes} 8921558Srgrimes 8931558Srgrimes/* 89475394Siedowse * Catagorise a RPC return status and error into an `enum tryret' 89575394Siedowse * return code. 89675394Siedowse */ 897203461Sdelphijstatic enum tryret 898275257Straszreturncode(enum clnt_stat clntstat, struct rpc_err *rpcerr) 89975394Siedowse{ 900275257Strasz 901275257Strasz switch (clntstat) { 90275394Siedowse case RPC_TIMEDOUT: 90375394Siedowse return (TRYRET_TIMEOUT); 90475394Siedowse case RPC_PMAPFAILURE: 90575394Siedowse case RPC_PROGNOTREGISTERED: 90675394Siedowse case RPC_PROGVERSMISMATCH: 90778679Siedowse /* XXX, these can be local or remote. */ 90878679Siedowse case RPC_CANTSEND: 90978679Siedowse case RPC_CANTRECV: 91075394Siedowse return (TRYRET_REMOTEERR); 91175394Siedowse case RPC_SYSTEMERROR: 91275394Siedowse switch (rpcerr->re_errno) { 91375394Siedowse case ETIMEDOUT: 91475394Siedowse return (TRYRET_TIMEOUT); 91575394Siedowse case ENOMEM: 91675394Siedowse break; 91775394Siedowse default: 91875394Siedowse return (TRYRET_REMOTEERR); 91975394Siedowse } 92075394Siedowse /* FALLTHROUGH */ 92175394Siedowse default: 92275394Siedowse break; 92375394Siedowse } 92475394Siedowse return (TRYRET_LOCALERR); 92575394Siedowse} 92675394Siedowse 92775394Siedowse/* 92876530Siedowse * Look up a netid based on an address family and socket type. 92976530Siedowse * `af' is the address family, and `sotype' is SOCK_DGRAM or SOCK_STREAM. 93076530Siedowse * 93176530Siedowse * XXX there should be a library function for this. 93276530Siedowse */ 933203461Sdelphijstatic const char * 934156925Simpnetidbytype(int af, int sotype) 935156925Simp{ 93676530Siedowse struct nc_protos *p; 93776530Siedowse 93876530Siedowse for (p = nc_protos; p->netid != NULL; p++) { 93976530Siedowse if (af != p->af || sotype != p->sotype) 94076530Siedowse continue; 94176530Siedowse return (p->netid); 94276530Siedowse } 94376530Siedowse return (NULL); 94476530Siedowse} 94576530Siedowse 94676530Siedowse/* 94776530Siedowse * Look up a netconfig entry based on a netid, and cache the result so 94876530Siedowse * that we don't need to remember to call freenetconfigent(). 94976530Siedowse * 95076530Siedowse * Otherwise it behaves just like getnetconfigent(), so nc_*error() 95176530Siedowse * work on failure. 95276530Siedowse */ 953203461Sdelphijstatic struct netconfig * 954156925Simpgetnetconf_cached(const char *netid) 955156925Simp{ 95676530Siedowse static struct nc_entry { 95776530Siedowse struct netconfig *nconf; 95876530Siedowse struct nc_entry *next; 95976530Siedowse } *head; 96076530Siedowse struct nc_entry *p; 96176530Siedowse struct netconfig *nconf; 96276530Siedowse 96376530Siedowse for (p = head; p != NULL; p = p->next) 96476530Siedowse if (strcmp(netid, p->nconf->nc_netid) == 0) 96576530Siedowse return (p->nconf); 96676530Siedowse 96776530Siedowse if ((nconf = getnetconfigent(netid)) == NULL) 96876530Siedowse return (NULL); 96976530Siedowse if ((p = malloc(sizeof(*p))) == NULL) 97076530Siedowse err(1, "malloc"); 97176530Siedowse p->nconf = nconf; 97276530Siedowse p->next = head; 97376530Siedowse head = p; 97476530Siedowse 97576530Siedowse return (p->nconf); 97676530Siedowse} 97776530Siedowse 97876530Siedowse/* 9791558Srgrimes * xdr routines for mount rpc's 9801558Srgrimes */ 981203461Sdelphijstatic int 982156925Simpxdr_dir(XDR *xdrsp, char *dirp) 9831558Srgrimes{ 984194880Sdfr return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 9851558Srgrimes} 9861558Srgrimes 987203461Sdelphijstatic int 988156925Simpxdr_fh(XDR *xdrsp, struct nfhret *np) 9891558Srgrimes{ 99092806Sobrien int i; 9919336Sdfr long auth, authcnt, authfnd = 0; 9929336Sdfr 9939336Sdfr if (!xdr_u_long(xdrsp, &np->stat)) 9941558Srgrimes return (0); 9951558Srgrimes if (np->stat) 9961558Srgrimes return (1); 9979336Sdfr switch (np->vers) { 9989336Sdfr case 1: 999194880Sdfr np->fhsize = NFS_FHSIZE; 1000194880Sdfr return (xdr_opaque(xdrsp, (caddr_t)np->nfh, NFS_FHSIZE)); 10019336Sdfr case 3: 10029336Sdfr if (!xdr_long(xdrsp, &np->fhsize)) 10039336Sdfr return (0); 1004194880Sdfr if (np->fhsize <= 0 || np->fhsize > NFS3_FHSIZE) 10059336Sdfr return (0); 10069336Sdfr if (!xdr_opaque(xdrsp, (caddr_t)np->nfh, np->fhsize)) 10079336Sdfr return (0); 10089336Sdfr if (!xdr_long(xdrsp, &authcnt)) 10099336Sdfr return (0); 10109336Sdfr for (i = 0; i < authcnt; i++) { 10119336Sdfr if (!xdr_long(xdrsp, &auth)) 10129336Sdfr return (0); 1013183008Srodrigc if (np->auth == -1) { 1014183008Srodrigc np->auth = auth; 10159336Sdfr authfnd++; 1016183008Srodrigc } else if (auth == np->auth) { 1017183008Srodrigc authfnd++; 1018183008Srodrigc } 10199336Sdfr } 10209336Sdfr /* 10219336Sdfr * Some servers, such as DEC's OSF/1 return a nil authenticator 10229336Sdfr * list to indicate RPCAUTH_UNIX. 10239336Sdfr */ 1024183008Srodrigc if (authcnt == 0 && np->auth == -1) 1025183008Srodrigc np->auth = AUTH_SYS; 1026183008Srodrigc if (!authfnd && (authcnt > 0 || np->auth != AUTH_SYS)) 10279336Sdfr np->stat = EAUTH; 10289336Sdfr return (1); 10299336Sdfr }; 10309336Sdfr return (0); 10311558Srgrimes} 10321558Srgrimes 1033203461Sdelphijstatic void 1034203461Sdelphijusage(void) 10351558Srgrimes{ 103637427Scharnier (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", 1037192578Srwatson"usage: mount_nfs [-23bcdiLlNPsTU] [-a maxreadahead] [-D deadthresh]", 1038141611Sru" [-g maxgroups] [-I readdirsize] [-o options] [-R retrycnt]", 1039141611Sru" [-r readsize] [-t timeout] [-w writesize] [-x retrans]", 1040141611Sru" rhost:path node"); 10411558Srgrimes exit(1); 10421558Srgrimes} 1043