1 /* $NetBSD: mount_nfs.c,v 1.68 2009/11/30 17:17:55 pooka 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.68 2009/11/30 17:17:55 pooka 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 #ifdef ISO 56 #include <netiso/iso.h> 57 #endif 58 59 #include <nfs/rpcv2.h> 60 #include <nfs/nfsproto.h> 61 #include <nfs/nfs.h> 62 #include <nfs/nfsmount.h> 63 64 #include <arpa/inet.h> 65 66 #include <err.h> 67 #include <errno.h> 68 #include <fcntl.h> 69 #include <netdb.h> 70 #include <signal.h> 71 #include <stdio.h> 72 #include <stdlib.h> 73 #include <string.h> 74 #include <unistd.h> 75 #include <util.h> 76 77 #include <mntopts.h> 78 79 #include "mountprog.h" 80 #include "mount_nfs.h" 81 82 #define ALTF_BG 0x00000001 83 #define ALTF_CONN 0x00000002 84 #define ALTF_DUMBTIMR 0x00000004 85 #define ALTF_INTR 0x00000008 86 #define ALTF_NFSV3 0x00000020 87 #define ALTF_RDIRPLUS 0x00000040 88 #define ALTF_MNTUDP 0x00000080 89 #define ALTF_NORESPORT 0x00000100 90 #define ALTF_SEQPACKET 0x00000200 91 #define ALTF_NQNFS 0x00000400 92 #define ALTF_SOFT 0x00000800 93 #define ALTF_TCP 0x00001000 94 #define ALTF_NFSV2 0x00002000 95 #define ALTF_PORT 0x00004000 96 #define ALTF_RSIZE 0x00008000 97 #define ALTF_WSIZE 0x00010000 98 #define ALTF_RDIRSIZE 0x00020000 99 #define ALTF_MAXGRPS 0x00040000 100 #define ALTF_LEASETERM 0x00080000 101 #define ALTF_READAHEAD 0x00100000 102 #define ALTF_DEADTHRESH 0x00200000 103 #define ALTF_TIMEO 0x00400000 104 #define ALTF_RETRANS 0x00800000 105 106 static const struct mntopt mopts[] = { 107 MOPT_STDOPTS, 108 MOPT_FORCE, 109 MOPT_UPDATE, 110 MOPT_GETARGS, 111 { "bg", 0, ALTF_BG, 1 }, 112 { "conn", 0, ALTF_CONN, 1 }, 113 { "dumbtimer", 0, ALTF_DUMBTIMR, 1 }, 114 { "intr", 0, ALTF_INTR, 1 }, 115 { "nfsv3", 0, ALTF_NFSV3, 1 }, 116 { "rdirplus", 0, ALTF_RDIRPLUS, 1 }, 117 { "mntudp", 0, ALTF_MNTUDP, 1 }, 118 { "resport", 1, ALTF_NORESPORT, 1 }, 119 #ifdef ISO 120 { "seqpacket", 0, ALTF_SEQPACKET, 1 }, 121 #endif 122 { "nqnfs", 0, ALTF_NQNFS, 1 }, 123 { "soft", 0, ALTF_SOFT, 1 }, 124 { "tcp", 0, ALTF_TCP, 1 }, 125 { "nfsv2", 0, ALTF_NFSV2, 1 }, 126 { "port", 0, ALTF_PORT, 1 }, 127 { "rsize", 0, ALTF_RSIZE, 1 }, 128 { "wsize", 0, ALTF_WSIZE, 1 }, 129 { "rdirsize", 0, ALTF_RDIRSIZE, 1 }, 130 { "maxgrps", 0, ALTF_MAXGRPS, 1 }, 131 { "leaseterm", 0, ALTF_LEASETERM, 1 }, 132 { "readahead", 0, ALTF_READAHEAD, 1 }, 133 { "deadthresh", 0, ALTF_DEADTHRESH, 1 }, 134 { "timeo", 0, ALTF_TIMEO, 1 }, 135 MOPT_NULL, 136 137 }; 138 139 struct nfs_args nfsdefargs = { 140 .version = NFS_ARGSVERSION, 141 .addr = NULL, 142 .addrlen = sizeof(struct sockaddr_in), 143 .sotype = SOCK_DGRAM, 144 .proto = 0, 145 .fh = NULL, 146 .fhsize = 0, 147 .flags = NFSMNT_NFSV3|NFSMNT_NOCONN|NFSMNT_RESVPORT, 148 .wsize = NFS_WSIZE, 149 .rsize = NFS_RSIZE, 150 .readdirsize = NFS_READDIRSIZE, 151 .timeo = 10, 152 .retrans = NFS_RETRANS, 153 .maxgrouplist = NFS_MAXGRPS, 154 .readahead = NFS_DEFRAHEAD, 155 .leaseterm = 0, /* Ignored; lease term */ 156 .deadthresh = NFS_DEFDEADTHRESH, 157 .hostname = NULL, 158 }; 159 160 #define DEF_RETRY 10000 161 162 int retrycnt = DEF_RETRY; 163 int opflags = 0; 164 int force2 = 0; 165 int force3 = 0; 166 int mnttcp_ok = 1; 167 int port = 0; 168 169 static void shownfsargs(const struct nfs_args *); 170 #ifdef ISO 171 static struct iso_addr *iso_addr(const char *); 172 #endif 173 int mount_nfs(int argc, char **argv); 174 /* void set_rpc_maxgrouplist(int); */ 175 static void usage(void); 176 177 #ifndef MOUNT_NOMAIN 178 int 179 main(int argc, char **argv) 180 { 181 182 setprogname(argv[0]); 183 return mount_nfs(argc, argv); 184 } 185 #endif 186 187 void 188 mount_nfs_dogetargs(struct nfs_args *nfsargsp, int mntflags, const char *spec) 189 { 190 static struct sockaddr_storage sa; 191 char *tspec; 192 193 if ((mntflags & MNT_GETARGS) != 0) { 194 memset(&sa, 0, sizeof(sa)); 195 nfsargsp->addr = (struct sockaddr *)&sa; 196 nfsargsp->addrlen = sizeof(sa); 197 } else { 198 if ((tspec = strdup(spec)) == NULL) { 199 err(1, "strdup"); 200 } 201 if (!getnfsargs(tspec, nfsargsp)) { 202 exit(1); 203 } 204 free(tspec); 205 } 206 } 207 208 void 209 mount_nfs_parseargs(int argc, char *argv[], 210 struct nfs_args *nfsargsp, int *mntflags, 211 char *spec, char *name) 212 { 213 char *p; 214 int altflags, num; 215 int c; 216 mntoptparse_t mp; 217 218 *mntflags = 0; 219 altflags = 0; 220 memset(nfsargsp, 0, sizeof(*nfsargsp)); 221 *nfsargsp = nfsdefargs; 222 while ((c = getopt(argc, argv, 223 "23a:bcCdD:g:I:iKL:lm:o:PpqR:r:sTt:w:x:UX")) != -1) 224 switch (c) { 225 case '3': 226 case 'q': 227 if (force2) 228 errx(1, "conflicting version options"); 229 force3 = 1; 230 break; 231 case '2': 232 if (force3) 233 errx(1, "conflicting version options"); 234 force2 = 1; 235 nfsargsp->flags &= ~NFSMNT_NFSV3; 236 break; 237 case 'a': 238 num = strtol(optarg, &p, 10); 239 if (*p || num < 0) 240 errx(1, "illegal -a value -- %s", optarg); 241 nfsargsp->readahead = num; 242 nfsargsp->flags |= NFSMNT_READAHEAD; 243 break; 244 case 'b': 245 opflags |= BGRND; 246 break; 247 case 'c': 248 nfsargsp->flags |= NFSMNT_NOCONN; 249 break; 250 case 'C': 251 nfsargsp->flags &= ~NFSMNT_NOCONN; 252 break; 253 case 'D': 254 num = strtol(optarg, &p, 10); 255 if (*p || num <= 0) 256 errx(1, "illegal -D value -- %s", optarg); 257 nfsargsp->deadthresh = num; 258 nfsargsp->flags |= NFSMNT_DEADTHRESH; 259 break; 260 case 'd': 261 nfsargsp->flags |= NFSMNT_DUMBTIMR; 262 break; 263 #if 0 /* XXXX */ 264 case 'g': 265 num = strtol(optarg, &p, 10); 266 if (*p || num <= 0) 267 errx(1, "illegal -g value -- %s", optarg); 268 set_rpc_maxgrouplist(num); 269 nfsargsp->maxgrouplist = num; 270 nfsargsp->flags |= NFSMNT_MAXGRPS; 271 break; 272 #endif 273 case 'I': 274 num = strtol(optarg, &p, 10); 275 if (*p || num <= 0) 276 errx(1, "illegal -I value -- %s", optarg); 277 nfsargsp->readdirsize = num; 278 nfsargsp->flags |= NFSMNT_READDIRSIZE; 279 break; 280 case 'i': 281 nfsargsp->flags |= NFSMNT_INT; 282 break; 283 case 'L': 284 /* ignore */ 285 break; 286 case 'l': 287 nfsargsp->flags |= NFSMNT_RDIRPLUS; 288 break; 289 case 'o': 290 mp = getmntopts(optarg, mopts, mntflags, &altflags); 291 if (mp == NULL) 292 err(1, "getmntopts"); 293 if (altflags & ALTF_BG) 294 opflags |= BGRND; 295 if (altflags & ALTF_CONN) 296 nfsargsp->flags &= ~NFSMNT_NOCONN; 297 if (altflags & ALTF_DUMBTIMR) 298 nfsargsp->flags |= NFSMNT_DUMBTIMR; 299 if (altflags & ALTF_INTR) 300 nfsargsp->flags |= NFSMNT_INT; 301 if (altflags & (ALTF_NFSV3|ALTF_NQNFS)) { 302 if (force2) 303 errx(1, "conflicting version options"); 304 force3 = 1; 305 } 306 if (altflags & ALTF_NFSV2) { 307 if (force3) 308 errx(1, "conflicting version options"); 309 force2 = 1; 310 nfsargsp->flags &= ~NFSMNT_NFSV3; 311 } 312 if (altflags & ALTF_RDIRPLUS) 313 nfsargsp->flags |= NFSMNT_RDIRPLUS; 314 if (altflags & ALTF_MNTUDP) 315 mnttcp_ok = 0; 316 if (altflags & ALTF_NORESPORT) 317 nfsargsp->flags &= ~NFSMNT_RESVPORT; 318 #ifdef ISO 319 if (altflags & ALTF_SEQPACKET) 320 nfsargsp->sotype = SOCK_SEQPACKET; 321 #endif 322 if (altflags & ALTF_SOFT) 323 nfsargsp->flags |= NFSMNT_SOFT; 324 if (altflags & ALTF_TCP) { 325 nfsargsp->sotype = SOCK_STREAM; 326 } 327 if (altflags & ALTF_PORT) { 328 port = getmntoptnum(mp, "port"); 329 } 330 if (altflags & ALTF_RSIZE) { 331 nfsargsp->rsize = 332 (int)getmntoptnum(mp, "rsize"); 333 nfsargsp->flags |= NFSMNT_RSIZE; 334 } 335 if (altflags & ALTF_WSIZE) { 336 nfsargsp->wsize = 337 (int)getmntoptnum(mp, "wsize"); 338 nfsargsp->flags |= NFSMNT_WSIZE; 339 } 340 if (altflags & ALTF_RDIRSIZE) { 341 nfsargsp->rsize = 342 (int)getmntoptnum(mp, "rdirsize"); 343 nfsargsp->flags |= NFSMNT_READDIRSIZE; 344 } 345 #if 0 346 if (altflags & ALTF_MAXGRPS) { 347 set_rpc_maxgrouplist(num); 348 nfsargsp->maxgrouplist = 349 (int)getmntoptnum(mp, "maxgrps"); 350 nfsargsp->flags |= NFSMNT_MAXGRPS; 351 } 352 #endif 353 if (altflags & ALTF_LEASETERM) { 354 nfsargsp->leaseterm = 355 (int)getmntoptnum(mp, "leaseterm"); 356 nfsargsp->flags |= NFSMNT_LEASETERM; 357 } 358 if (altflags & ALTF_READAHEAD) { 359 nfsargsp->readahead = 360 (int)getmntoptnum(mp, "readahead"); 361 nfsargsp->flags |= NFSMNT_READAHEAD; 362 } 363 if (altflags & ALTF_DEADTHRESH) { 364 nfsargsp->deadthresh = 365 (int)getmntoptnum(mp, "deadthresh"); 366 nfsargsp->flags |= NFSMNT_DEADTHRESH; 367 } 368 if (altflags & ALTF_TIMEO) { 369 nfsargsp->timeo = 370 (int)getmntoptnum(mp, "timeo"); 371 nfsargsp->flags |= NFSMNT_TIMEO; 372 } 373 if (altflags & ALTF_RETRANS) { 374 nfsargsp->retrans = 375 (int)getmntoptnum(mp, "retrans"); 376 nfsargsp->flags |= NFSMNT_RETRANS; 377 } 378 altflags = 0; 379 freemntopts(mp); 380 break; 381 case 'P': 382 nfsargsp->flags |= NFSMNT_RESVPORT; 383 break; 384 case 'p': 385 nfsargsp->flags &= ~NFSMNT_RESVPORT; 386 break; 387 case 'R': 388 num = strtol(optarg, &p, 10); 389 if (*p || num <= 0) 390 errx(1, "illegal -R value -- %s", optarg); 391 retrycnt = num; 392 break; 393 case 'r': 394 num = strtol(optarg, &p, 10); 395 if (*p || num <= 0) 396 errx(1, "illegal -r value -- %s", optarg); 397 nfsargsp->rsize = num; 398 nfsargsp->flags |= NFSMNT_RSIZE; 399 break; 400 #ifdef ISO 401 case 'S': 402 nfsargsp->sotype = SOCK_SEQPACKET; 403 break; 404 #endif 405 case 's': 406 nfsargsp->flags |= NFSMNT_SOFT; 407 break; 408 case 'T': 409 nfsargsp->sotype = SOCK_STREAM; 410 break; 411 case 't': 412 num = strtol(optarg, &p, 10); 413 if (*p || num <= 0) 414 errx(1, "illegal -t value -- %s", optarg); 415 nfsargsp->timeo = num; 416 nfsargsp->flags |= NFSMNT_TIMEO; 417 break; 418 case 'w': 419 num = strtol(optarg, &p, 10); 420 if (*p || num <= 0) 421 errx(1, "illegal -w value -- %s", optarg); 422 nfsargsp->wsize = num; 423 nfsargsp->flags |= NFSMNT_WSIZE; 424 break; 425 case 'x': 426 num = strtol(optarg, &p, 10); 427 if (*p || num <= 0) 428 errx(1, "illegal -x value -- %s", optarg); 429 nfsargsp->retrans = num; 430 nfsargsp->flags |= NFSMNT_RETRANS; 431 break; 432 case 'X': 433 nfsargsp->flags |= NFSMNT_XLATECOOKIE; 434 break; 435 case 'U': 436 mnttcp_ok = 0; 437 break; 438 default: 439 usage(); 440 break; 441 } 442 argc -= optind; 443 argv += optind; 444 445 if (argc != 2) 446 usage(); 447 448 strlcpy(spec, *argv++, MAXPATHLEN); 449 pathadj(*argv, name); 450 mount_nfs_dogetargs(nfsargsp, *mntflags, spec); 451 } 452 453 int 454 mount_nfs(int argc, char *argv[]) 455 { 456 char spec[MAXPATHLEN], name[MAXPATHLEN]; 457 struct nfs_args args; 458 int mntflags; 459 int retval; 460 461 mount_nfs_parseargs(argc, argv, &args, &mntflags, spec, name); 462 463 retry: 464 if ((retval = mount(MOUNT_NFS, name, mntflags, 465 &args, sizeof args)) == -1) { 466 /* Did we just default to v3 on a v2-only kernel? 467 * If so, default to v2 & try again */ 468 if (errno == EPROGMISMATCH && 469 (args.flags & NFSMNT_NFSV3) != 0 && !force3) { 470 /* 471 * fall back to v2. XXX lack of V3 umount. 472 */ 473 args.flags &= ~NFSMNT_NFSV3; 474 mount_nfs_dogetargs(&args, mntflags, spec); 475 goto retry; 476 } 477 } 478 if (retval == -1) 479 err(1, "%s on %s", spec, name); 480 if (mntflags & MNT_GETARGS) { 481 shownfsargs(&args); 482 return (0); 483 } 484 485 exit(0); 486 } 487 488 static void 489 shownfsargs(const struct nfs_args *nfsargsp) 490 { 491 char fbuf[2048]; 492 char host[NI_MAXHOST], serv[NI_MAXSERV]; 493 int error; 494 495 (void)snprintb(fbuf, sizeof(fbuf), NFSMNT_BITS, nfsargsp->flags); 496 if (nfsargsp->addr != NULL) { 497 error = getnameinfo(nfsargsp->addr, nfsargsp->addrlen, host, 498 sizeof(host), serv, sizeof(serv), 499 NI_NUMERICHOST | NI_NUMERICSERV); 500 if (error != 0) 501 warnx("getnameinfo: %s", gai_strerror(error)); 502 } else 503 error = -1; 504 505 if (error == 0) 506 printf("addr=%s, port=%s, addrlen=%d, ", 507 host, serv, nfsargsp->addrlen); 508 printf("sotype=%d, proto=%d, fhsize=%d, " 509 "flags=%s, wsize=%d, rsize=%d, readdirsize=%d, timeo=%d, " 510 "retrans=%d, maxgrouplist=%d, readahead=%d, leaseterm=%d, " 511 "deadthresh=%d\n", 512 nfsargsp->sotype, 513 nfsargsp->proto, 514 nfsargsp->fhsize, 515 fbuf, 516 nfsargsp->wsize, 517 nfsargsp->rsize, 518 nfsargsp->readdirsize, 519 nfsargsp->timeo, 520 nfsargsp->retrans, 521 nfsargsp->maxgrouplist, 522 nfsargsp->readahead, 523 nfsargsp->leaseterm, 524 nfsargsp->deadthresh); 525 } 526 527 static void 528 usage(void) 529 { 530 (void)fprintf(stderr, "usage: %s %s\n%s\n%s\n%s\n%s\n", getprogname(), 531 "[-23bCcdilPpqsTUX] [-a maxreadahead] [-D deadthresh]", 532 "\t[-g maxgroups] [-I readdirsize] [-L leaseterm]", 533 "\t[-o options] [-R retrycnt] [-r readsize] [-t timeout]", 534 "\t[-w writesize] [-x retrans]", 535 "\trhost:path node"); 536 exit(1); 537 } 538