1 /* $NetBSD: mount_nfs.c,v 1.72 2018/05/17 02:34:31 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Rick Macklem at The University of Guelph. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #ifndef lint 37 __COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\ 38 The Regents of the University of California. All rights reserved."); 39 #endif /* not lint */ 40 41 #ifndef lint 42 #if 0 43 static char sccsid[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95"; 44 #else 45 __RCSID("$NetBSD: mount_nfs.c,v 1.72 2018/05/17 02:34:31 thorpej Exp $"); 46 #endif 47 #endif /* not lint */ 48 49 #include <sys/param.h> 50 #include <sys/mount.h> 51 #include <sys/socket.h> 52 #include <sys/stat.h> 53 #include <syslog.h> 54 55 #include <nfs/rpcv2.h> 56 #include <nfs/nfsproto.h> 57 #include <nfs/nfs.h> 58 #include <nfs/nfsmount.h> 59 60 #include <arpa/inet.h> 61 62 #include <err.h> 63 #include <errno.h> 64 #include <fcntl.h> 65 #include <netdb.h> 66 #include <signal.h> 67 #include <stdio.h> 68 #include <stdlib.h> 69 #include <string.h> 70 #include <unistd.h> 71 #include <util.h> 72 73 #include <mntopts.h> 74 75 #include "mountprog.h" 76 #include "mount_nfs.h" 77 78 #define ALTF_BG 0x00000001 79 #define ALTF_CONN 0x00000002 80 #define ALTF_DUMBTIMR 0x00000004 81 #define ALTF_INTR 0x00000008 82 #define ALTF_NFSV3 0x00000020 83 #define ALTF_RDIRPLUS 0x00000040 84 #define ALTF_MNTUDP 0x00000080 85 #define ALTF_NORESPORT 0x00000100 86 #define ALTF_SEQPACKET 0x00000200 87 #define ALTF_NQNFS 0x00000400 88 #define ALTF_SOFT 0x00000800 89 #define ALTF_TCP 0x00001000 90 #define ALTF_NFSV2 0x00002000 91 #define ALTF_PORT 0x00004000 92 #define ALTF_RSIZE 0x00008000 93 #define ALTF_WSIZE 0x00010000 94 #define ALTF_RDIRSIZE 0x00020000 95 #define ALTF_MAXGRPS 0x00040000 96 #define ALTF_LEASETERM 0x00080000 97 #define ALTF_READAHEAD 0x00100000 98 #define ALTF_DEADTHRESH 0x00200000 99 #define ALTF_TIMEO 0x00400000 100 #define ALTF_RETRANS 0x00800000 101 #define ALTF_UDP 0x01000000 102 103 static const struct mntopt mopts[] = { 104 MOPT_STDOPTS, 105 MOPT_FORCE, 106 MOPT_UPDATE, 107 MOPT_GETARGS, 108 { "bg", 0, ALTF_BG, 1 }, 109 { "conn", 0, ALTF_CONN, 1 }, 110 { "dumbtimer", 0, ALTF_DUMBTIMR, 1 }, 111 { "intr", 0, ALTF_INTR, 1 }, 112 { "nfsv3", 0, ALTF_NFSV3, 1 }, 113 { "rdirplus", 0, ALTF_RDIRPLUS, 1 }, 114 { "mntudp", 0, ALTF_MNTUDP, 1 }, 115 { "resport", 1, ALTF_NORESPORT, 1 }, 116 { "nqnfs", 0, ALTF_NQNFS, 1 }, 117 { "soft", 0, ALTF_SOFT, 1 }, 118 { "tcp", 0, ALTF_TCP, 1 }, 119 { "udp", 0, ALTF_UDP, 1 }, 120 { "nfsv2", 0, ALTF_NFSV2, 1 }, 121 { "port", 0, ALTF_PORT, 1 }, 122 { "rsize", 0, ALTF_RSIZE, 1 }, 123 { "wsize", 0, ALTF_WSIZE, 1 }, 124 { "rdirsize", 0, ALTF_RDIRSIZE, 1 }, 125 { "maxgrps", 0, ALTF_MAXGRPS, 1 }, 126 { "leaseterm", 0, ALTF_LEASETERM, 1 }, 127 { "readahead", 0, ALTF_READAHEAD, 1 }, 128 { "deadthresh", 0, ALTF_DEADTHRESH, 1 }, 129 { "timeo", 0, ALTF_TIMEO, 1 }, 130 MOPT_NULL, 131 132 }; 133 134 struct nfs_args nfsdefargs = { 135 .version = NFS_ARGSVERSION, 136 .addr = NULL, 137 .addrlen = sizeof(struct sockaddr_in), 138 .sotype = SOCK_STREAM, 139 .proto = 0, 140 .fh = NULL, 141 .fhsize = 0, 142 .flags = NFSMNT_NFSV3|NFSMNT_NOCONN|NFSMNT_RESVPORT, 143 .wsize = NFS_WSIZE, 144 .rsize = NFS_RSIZE, 145 .readdirsize = NFS_READDIRSIZE, 146 .timeo = 10, 147 .retrans = NFS_RETRANS, 148 .maxgrouplist = NFS_MAXGRPS, 149 .readahead = NFS_DEFRAHEAD, 150 .leaseterm = 0, /* Ignored; lease term */ 151 .deadthresh = NFS_DEFDEADTHRESH, 152 .hostname = NULL, 153 }; 154 155 static void shownfsargs(const struct nfs_args *); 156 int mount_nfs(int argc, char **argv); 157 /* void set_rpc_maxgrouplist(int); */ 158 __dead static void usage(void); 159 160 #ifndef MOUNT_NOMAIN 161 int 162 main(int argc, char **argv) 163 { 164 165 setprogname(argv[0]); 166 return mount_nfs(argc, argv); 167 } 168 #endif 169 170 void 171 mount_nfs_dogetargs(struct nfs_args *nfsargsp, int mntflags, const char *spec) 172 { 173 static struct sockaddr_storage sa; 174 char *tspec; 175 176 if ((mntflags & MNT_GETARGS) != 0) { 177 memset(&sa, 0, sizeof(sa)); 178 nfsargsp->addr = (struct sockaddr *)&sa; 179 nfsargsp->addrlen = sizeof(sa); 180 } else { 181 if ((tspec = strdup(spec)) == NULL) { 182 err(1, "strdup"); 183 } 184 if (!getnfsargs(tspec, nfsargsp)) { 185 exit(1); 186 } 187 free(tspec); 188 } 189 } 190 191 void 192 mount_nfs_parseargs(int argc, char *argv[], 193 struct nfs_args *nfsargsp, int *mntflags, 194 char *spec, char *name) 195 { 196 char *p; 197 int altflags, num; 198 int c; 199 mntoptparse_t mp; 200 201 *mntflags = 0; 202 altflags = 0; 203 memset(nfsargsp, 0, sizeof(*nfsargsp)); 204 *nfsargsp = nfsdefargs; 205 while ((c = getopt(argc, argv, 206 "23a:bcCdD:g:I:iKL:lm:o:PpqR:r:sTt:w:x:UuX")) != -1) 207 switch (c) { 208 case '3': 209 case 'q': 210 if (force2) 211 errx(1, "conflicting version options"); 212 force3 = 1; 213 break; 214 case '2': 215 if (force3) 216 errx(1, "conflicting version options"); 217 force2 = 1; 218 nfsargsp->flags &= ~NFSMNT_NFSV3; 219 break; 220 case 'a': 221 num = strtol(optarg, &p, 10); 222 if (*p || num < 0) 223 errx(1, "illegal -a value -- %s", optarg); 224 nfsargsp->readahead = num; 225 nfsargsp->flags |= NFSMNT_READAHEAD; 226 break; 227 case 'b': 228 opflags |= BGRND; 229 break; 230 case 'c': 231 nfsargsp->flags |= NFSMNT_NOCONN; 232 break; 233 case 'C': 234 nfsargsp->flags &= ~NFSMNT_NOCONN; 235 break; 236 case 'D': 237 num = strtol(optarg, &p, 10); 238 if (*p || num <= 0) 239 errx(1, "illegal -D value -- %s", optarg); 240 nfsargsp->deadthresh = num; 241 nfsargsp->flags |= NFSMNT_DEADTHRESH; 242 break; 243 case 'd': 244 nfsargsp->flags |= NFSMNT_DUMBTIMR; 245 break; 246 #if 0 /* XXXX */ 247 case 'g': 248 num = strtol(optarg, &p, 10); 249 if (*p || num <= 0) 250 errx(1, "illegal -g value -- %s", optarg); 251 set_rpc_maxgrouplist(num); 252 nfsargsp->maxgrouplist = num; 253 nfsargsp->flags |= NFSMNT_MAXGRPS; 254 break; 255 #endif 256 case 'I': 257 num = strtol(optarg, &p, 10); 258 if (*p || num <= 0) 259 errx(1, "illegal -I value -- %s", optarg); 260 nfsargsp->readdirsize = num; 261 nfsargsp->flags |= NFSMNT_READDIRSIZE; 262 break; 263 case 'i': 264 nfsargsp->flags |= NFSMNT_INT; 265 break; 266 case 'L': 267 /* ignore */ 268 break; 269 case 'l': 270 nfsargsp->flags |= NFSMNT_RDIRPLUS; 271 break; 272 case 'o': 273 mp = getmntopts(optarg, mopts, mntflags, &altflags); 274 if (mp == NULL) 275 err(1, "getmntopts"); 276 if (altflags & ALTF_BG) 277 opflags |= BGRND; 278 if (altflags & ALTF_CONN) 279 nfsargsp->flags &= ~NFSMNT_NOCONN; 280 if (altflags & ALTF_DUMBTIMR) 281 nfsargsp->flags |= NFSMNT_DUMBTIMR; 282 if (altflags & ALTF_INTR) 283 nfsargsp->flags |= NFSMNT_INT; 284 if (altflags & (ALTF_NFSV3|ALTF_NQNFS)) { 285 if (force2) 286 errx(1, "conflicting version options"); 287 force3 = 1; 288 } 289 if (altflags & ALTF_NFSV2) { 290 if (force3) 291 errx(1, "conflicting version options"); 292 force2 = 1; 293 nfsargsp->flags &= ~NFSMNT_NFSV3; 294 } 295 if (altflags & ALTF_RDIRPLUS) 296 nfsargsp->flags |= NFSMNT_RDIRPLUS; 297 if (altflags & ALTF_MNTUDP) 298 mnttcp_ok = 0; 299 if (altflags & ALTF_NORESPORT) 300 nfsargsp->flags &= ~NFSMNT_RESVPORT; 301 if (altflags & ALTF_SOFT) 302 nfsargsp->flags |= NFSMNT_SOFT; 303 if (altflags & ALTF_UDP) { 304 nfsargsp->sotype = SOCK_DGRAM; 305 } 306 /* 307 * After UDP, because TCP overrides if both 308 * are present. 309 */ 310 if (altflags & ALTF_TCP) { 311 nfsargsp->sotype = SOCK_STREAM; 312 } 313 if (altflags & ALTF_PORT) { 314 port = getmntoptnum(mp, "port"); 315 } 316 if (altflags & ALTF_RSIZE) { 317 nfsargsp->rsize = 318 (int)getmntoptnum(mp, "rsize"); 319 nfsargsp->flags |= NFSMNT_RSIZE; 320 } 321 if (altflags & ALTF_WSIZE) { 322 nfsargsp->wsize = 323 (int)getmntoptnum(mp, "wsize"); 324 nfsargsp->flags |= NFSMNT_WSIZE; 325 } 326 if (altflags & ALTF_RDIRSIZE) { 327 nfsargsp->rsize = 328 (int)getmntoptnum(mp, "rdirsize"); 329 nfsargsp->flags |= NFSMNT_READDIRSIZE; 330 } 331 #if 0 332 if (altflags & ALTF_MAXGRPS) { 333 set_rpc_maxgrouplist(num); 334 nfsargsp->maxgrouplist = 335 (int)getmntoptnum(mp, "maxgrps"); 336 nfsargsp->flags |= NFSMNT_MAXGRPS; 337 } 338 #endif 339 if (altflags & ALTF_LEASETERM) { 340 nfsargsp->leaseterm = 341 (int)getmntoptnum(mp, "leaseterm"); 342 nfsargsp->flags |= NFSMNT_LEASETERM; 343 } 344 if (altflags & ALTF_READAHEAD) { 345 nfsargsp->readahead = 346 (int)getmntoptnum(mp, "readahead"); 347 nfsargsp->flags |= NFSMNT_READAHEAD; 348 } 349 if (altflags & ALTF_DEADTHRESH) { 350 nfsargsp->deadthresh = 351 (int)getmntoptnum(mp, "deadthresh"); 352 nfsargsp->flags |= NFSMNT_DEADTHRESH; 353 } 354 if (altflags & ALTF_TIMEO) { 355 nfsargsp->timeo = 356 (int)getmntoptnum(mp, "timeo"); 357 nfsargsp->flags |= NFSMNT_TIMEO; 358 } 359 if (altflags & ALTF_RETRANS) { 360 nfsargsp->retrans = 361 (int)getmntoptnum(mp, "retrans"); 362 nfsargsp->flags |= NFSMNT_RETRANS; 363 } 364 altflags = 0; 365 freemntopts(mp); 366 break; 367 case 'P': 368 nfsargsp->flags |= NFSMNT_RESVPORT; 369 break; 370 case 'p': 371 nfsargsp->flags &= ~NFSMNT_RESVPORT; 372 break; 373 case 'R': 374 num = strtol(optarg, &p, 10); 375 if (*p || num <= 0) 376 errx(1, "illegal -R value -- %s", optarg); 377 retrycnt = num; 378 break; 379 case 'r': 380 num = strtol(optarg, &p, 10); 381 if (*p || num <= 0) 382 errx(1, "illegal -r value -- %s", optarg); 383 nfsargsp->rsize = num; 384 nfsargsp->flags |= NFSMNT_RSIZE; 385 break; 386 case 's': 387 nfsargsp->flags |= NFSMNT_SOFT; 388 break; 389 case 'T': 390 nfsargsp->sotype = SOCK_STREAM; 391 break; 392 case 't': 393 num = strtol(optarg, &p, 10); 394 if (*p || num <= 0) 395 errx(1, "illegal -t value -- %s", optarg); 396 nfsargsp->timeo = num; 397 nfsargsp->flags |= NFSMNT_TIMEO; 398 break; 399 case 'w': 400 num = strtol(optarg, &p, 10); 401 if (*p || num <= 0) 402 errx(1, "illegal -w value -- %s", optarg); 403 nfsargsp->wsize = num; 404 nfsargsp->flags |= NFSMNT_WSIZE; 405 break; 406 case 'x': 407 num = strtol(optarg, &p, 10); 408 if (*p || num <= 0) 409 errx(1, "illegal -x value -- %s", optarg); 410 nfsargsp->retrans = num; 411 nfsargsp->flags |= NFSMNT_RETRANS; 412 break; 413 case 'X': 414 nfsargsp->flags |= NFSMNT_XLATECOOKIE; 415 break; 416 case 'u': 417 nfsargsp->sotype = SOCK_DGRAM; 418 break; 419 case 'U': 420 mnttcp_ok = 0; 421 break; 422 default: 423 usage(); 424 break; 425 } 426 argc -= optind; 427 argv += optind; 428 429 if (argc != 2) 430 usage(); 431 432 strlcpy(spec, *argv++, MAXPATHLEN); 433 pathadj(*argv, name); 434 mount_nfs_dogetargs(nfsargsp, *mntflags, spec); 435 } 436 437 int 438 mount_nfs(int argc, char *argv[]) 439 { 440 char spec[MAXPATHLEN], name[MAXPATHLEN]; 441 struct nfs_args args; 442 int mntflags; 443 int retval; 444 445 mount_nfs_parseargs(argc, argv, &args, &mntflags, spec, name); 446 447 retry: 448 if ((retval = mount(MOUNT_NFS, name, mntflags, 449 &args, sizeof args)) == -1) { 450 /* Did we just default to v3 on a v2-only kernel? 451 * If so, default to v2 & try again */ 452 if (errno == EPROGMISMATCH && 453 (args.flags & NFSMNT_NFSV3) != 0 && !force3) { 454 /* 455 * fall back to v2. XXX lack of V3 umount. 456 */ 457 args.flags &= ~NFSMNT_NFSV3; 458 mount_nfs_dogetargs(&args, mntflags, spec); 459 goto retry; 460 } 461 } 462 if (retval == -1) 463 err(1, "%s on %s", spec, name); 464 if (mntflags & MNT_GETARGS) { 465 shownfsargs(&args); 466 return (0); 467 } 468 469 exit(0); 470 } 471 472 static void 473 shownfsargs(const struct nfs_args *nfsargsp) 474 { 475 char fbuf[2048]; 476 char host[NI_MAXHOST], serv[NI_MAXSERV]; 477 int error; 478 479 (void)snprintb(fbuf, sizeof(fbuf), NFSMNT_BITS, nfsargsp->flags); 480 if (nfsargsp->addr != NULL) { 481 error = getnameinfo(nfsargsp->addr, nfsargsp->addrlen, host, 482 sizeof(host), serv, sizeof(serv), 483 NI_NUMERICHOST | NI_NUMERICSERV); 484 if (error != 0) 485 warnx("getnameinfo: %s", gai_strerror(error)); 486 } else 487 error = -1; 488 489 if (error == 0) 490 printf("addr=%s, port=%s, addrlen=%d, ", 491 host, serv, nfsargsp->addrlen); 492 printf("sotype=%d, proto=%d, fhsize=%d, " 493 "flags=%s, wsize=%d, rsize=%d, readdirsize=%d, timeo=%d, " 494 "retrans=%d, maxgrouplist=%d, readahead=%d, leaseterm=%d, " 495 "deadthresh=%d\n", 496 nfsargsp->sotype, 497 nfsargsp->proto, 498 nfsargsp->fhsize, 499 fbuf, 500 nfsargsp->wsize, 501 nfsargsp->rsize, 502 nfsargsp->readdirsize, 503 nfsargsp->timeo, 504 nfsargsp->retrans, 505 nfsargsp->maxgrouplist, 506 nfsargsp->readahead, 507 nfsargsp->leaseterm, 508 nfsargsp->deadthresh); 509 } 510 511 static void 512 usage(void) 513 { 514 (void)fprintf(stderr, "usage: %s %s\n%s\n%s\n%s\n%s\n", getprogname(), 515 "[-23bCcdilPpqsTUuX] [-a maxreadahead] [-D deadthresh]", 516 "\t[-g maxgroups] [-I readdirsize] [-L leaseterm]", 517 "\t[-o options] [-R retrycnt] [-r readsize] [-t timeout]", 518 "\t[-w writesize] [-x retrans]", 519 "\trhost:path node"); 520 exit(1); 521 } 522