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