1 /* $NetBSD: mount_fs.c,v 1.3 2015/01/17 17:46:31 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997-2014 Erez Zadok 5 * Copyright (c) 1990 Jan-Simon Pendry 6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 7 * Copyright (c) 1990 The Regents of the University of California. 8 * All rights reserved. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * Jan-Simon Pendry at Imperial College, London. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * 38 * File: am-utils/libamu/mount_fs.c 39 * 40 */ 41 42 #ifdef HAVE_CONFIG_H 43 # include <config.h> 44 #endif /* HAVE_CONFIG_H */ 45 #include <am_defs.h> 46 #include <amu.h> 47 #include <nfs_common.h> 48 49 50 /* ensure that mount table options are delimited by a comma */ 51 #define append_opts(old, l, new) { \ 52 if (*(old) != '\0') \ 53 xstrlcat(old, ",", l); \ 54 xstrlcat(old, new, l); } 55 56 /* 57 * Standard mount flags 58 */ 59 struct opt_tab mnt_flags[] = 60 { 61 #if defined(MNT2_GEN_OPT_RDONLY) && defined(MNTTAB_OPT_RO) 62 {MNTTAB_OPT_RO, MNT2_GEN_OPT_RDONLY}, 63 #endif /* defined(MNT2_GEN_OPT_RDONLY) && defined(MNTTAB_OPT_RO) */ 64 65 #if defined(MNT2_GEN_OPT_NOCACHE) && defined(MNTTAB_OPT_NOCACHE) 66 {MNTTAB_OPT_NOCACHE, MNT2_GEN_OPT_NOCACHE}, 67 #endif /* defined(MNT2_GEN_OPT_NOCACHE) && defined(MNTTAB_OPT_NOCACHE) */ 68 69 /* the "grpid" mount option can be offered as generic of NFS */ 70 #ifdef MNTTAB_OPT_GRPID 71 # ifdef MNT2_GEN_OPT_GRPID 72 {MNTTAB_OPT_GRPID, MNT2_GEN_OPT_GRPID}, 73 # endif /* MNT2_GEN_OPT_GRPID */ 74 # ifdef MNT2_NFS_OPT_GRPID 75 {MNTTAB_OPT_GRPID, MNT2_NFS_OPT_GRPID}, 76 # endif /* MNT2_NFS_OPT_GRPID */ 77 #endif /* MNTTAB_OPT_GRPID */ 78 79 #if defined(MNT2_GEN_OPT_MULTI) && defined(MNTTAB_OPT_MULTI) 80 {MNTTAB_OPT_MULTI, MNT2_GEN_OPT_MULTI}, 81 #endif /* defined(MNT2_GEN_OPT_MULTI) && defined(MNTTAB_OPT_MULTI) */ 82 83 #if defined(MNT2_GEN_OPT_NODEV) && defined(MNTTAB_OPT_NODEV) 84 {MNTTAB_OPT_NODEV, MNT2_GEN_OPT_NODEV}, 85 #endif /* defined(MNT2_GEN_OPT_NODEV) && defined(MNTTAB_OPT_NODEV) */ 86 87 #if defined(MNT2_GEN_OPT_NOEXEC) && defined(MNTTAB_OPT_NOEXEC) 88 {MNTTAB_OPT_NOEXEC, MNT2_GEN_OPT_NOEXEC}, 89 #endif /* defined(MNT2_GEN_OPT_NOEXEC) && defined(MNTTAB_OPT_NOEXEC) */ 90 91 #if defined(MNT2_GEN_OPT_NOSUB) && defined(MNTTAB_OPT_NOSUB) 92 {MNTTAB_OPT_NOSUB, MNT2_GEN_OPT_NOSUB}, 93 #endif /* defined(MNT2_GEN_OPT_NOSUB) && defined(MNTTAB_OPT_NOSUB) */ 94 95 #if defined(MNT2_GEN_OPT_NOSUID) && defined(MNTTAB_OPT_NOSUID) 96 {MNTTAB_OPT_NOSUID, MNT2_GEN_OPT_NOSUID}, 97 #endif /* defined(MNT2_GEN_OPT_NOSUID) && defined(MNTTAB_OPT_NOSUID) */ 98 99 #if defined(MNT2_GEN_OPT_SYNC) && defined(MNTTAB_OPT_SYNC) 100 {MNTTAB_OPT_SYNC, MNT2_GEN_OPT_SYNC}, 101 #endif /* defined(MNT2_GEN_OPT_SYNC) && defined(MNTTAB_OPT_SYNC) */ 102 103 #if defined(MNT2_GEN_OPT_OVERLAY) && defined(MNTTAB_OPT_OVERLAY) 104 {MNTTAB_OPT_OVERLAY, MNT2_GEN_OPT_OVERLAY}, 105 #endif /* defined(MNT2_GEN_OPT_OVERLAY) && defined(MNTTAB_OPT_OVERLAY) */ 106 107 #if defined(MNT2_GEN_OPT_LOG) && defined(MNTTAB_OPT_LOG) 108 {MNTTAB_OPT_LOG, MNT2_GEN_OPT_LOG}, 109 #endif /* defined(MNT2_GEN_OPT_LOG) && defined(MNTTAB_OPT_LOG) */ 110 111 #if defined(MNT2_GEN_OPT_NOATIME) && defined(MNTTAB_OPT_NOATIME) 112 {MNTTAB_OPT_NOATIME, MNT2_GEN_OPT_NOATIME}, 113 #endif /* defined(MNT2_GEN_OPT_NOATIME) && defined(MNTTAB_OPT_NOATIME) */ 114 115 #if defined(MNT2_GEN_OPT_NODEVMTIME) && defined(MNTTAB_OPT_NODEVMTIME) 116 {MNTTAB_OPT_NODEVMTIME, MNT2_GEN_OPT_NODEVMTIME}, 117 #endif /* defined(MNT2_GEN_OPT_NODEVMTIME) && defined(MNTTAB_OPT_NODEVMTIME) */ 118 119 #if defined(MNT2_GEN_OPT_SOFTDEP) && defined(MNTTAB_OPT_SOFTDEP) 120 {MNTTAB_OPT_SOFTDEP, MNT2_GEN_OPT_SOFTDEP}, 121 #endif /* defined(MNT2_GEN_OPT_SOFTDEP) && defined(MNTTAB_OPT_SOFTDEP) */ 122 123 #if defined(MNT2_GEN_OPT_SYMPERM) && defined(MNTTAB_OPT_SYMPERM) 124 {MNTTAB_OPT_SYMPERM, MNT2_GEN_OPT_SYMPERM}, 125 #endif /* defined(MNT2_GEN_OPT_SYMPERM) && defined(MNTTAB_OPT_SYMPERM) */ 126 127 #if defined(MNT2_GEN_OPT_UNION) && defined(MNTTAB_OPT_UNION) 128 {MNTTAB_OPT_UNION, MNT2_GEN_OPT_UNION}, 129 #endif /* defined(MNT2_GEN_OPT_UNION) && defined(MNTTAB_OPT_UNION) */ 130 131 /* 132 * Do not define MNT2_NFS_OPT_* entries here! This is for generic 133 * mount(2) options only, not for NFS mount options. If you need to put 134 * something here, it's probably not the right place: see 135 * include/am_compat.h. 136 */ 137 138 {0, 0} 139 }; 140 141 142 /* compute generic mount flags */ 143 int 144 compute_mount_flags(mntent_t *mntp) 145 { 146 struct opt_tab *opt; 147 int flags = 0; 148 149 #ifdef MNT2_GEN_OPT_NEWTYPE 150 flags |= MNT2_GEN_OPT_NEWTYPE; 151 #endif /* MNT2_GEN_OPT_NEWTYPE */ 152 #ifdef MNT2_GEN_OPT_AUTOMOUNTED 153 flags |= MNT2_GEN_OPT_AUTOMOUNTED; 154 #endif /* not MNT2_GEN_OPT_AUTOMOUNTED */ 155 156 /* 157 * Crack basic mount options 158 */ 159 for (opt = mnt_flags; opt->opt; opt++) { 160 flags |= amu_hasmntopt(mntp, opt->opt) ? opt->flag : 0; 161 } 162 163 return flags; 164 } 165 166 167 /* compute generic mount flags for automounter mounts */ 168 int 169 compute_automounter_mount_flags(mntent_t *mntp) 170 { 171 int flags = 0; 172 173 #ifdef MNT2_GEN_OPT_IGNORE 174 flags |= MNT2_GEN_OPT_IGNORE; 175 #endif /* not MNT2_GEN_OPT_IGNORE */ 176 #ifdef MNT2_GEN_OPT_AUTOMNTFS 177 flags |= MNT2_GEN_OPT_AUTOMNTFS; 178 #endif /* not MNT2_GEN_OPT_AUTOMNTFS */ 179 180 return flags; 181 } 182 183 184 #if defined(MOUNT_TABLE_ON_FILE) && defined(MNTTAB_OPT_VERS) 185 /* 186 * add the extra vers={2,3} field to the mount table, 187 * unless already specified by user 188 */ 189 static void 190 addvers(char *zopts, size_t l, mntent_t *mnt, u_long have_vers, 191 u_long want_vers) 192 { 193 if (have_vers == want_vers && 194 hasmntval(mnt, MNTTAB_OPT_VERS) != want_vers) { 195 char optsbuf[48]; 196 xsnprintf(optsbuf, sizeof(optsbuf), 197 "%s=%d", MNTTAB_OPT_VERS, want_vers); 198 append_opts(zopts, l, optsbuf); 199 } 200 } 201 #endif /* MOUNT_TABLE_ON_FILE && MNTTAB_OPT_VERS */ 202 203 int 204 mount_fs(mntent_t *mnt, int flags, caddr_t mnt_data, int retry, MTYPE_TYPE type, u_long nfs_version, const char *nfs_proto, const char *mnttabname, int on_autofs) 205 { 206 int error = 0; 207 #ifdef MOUNT_TABLE_ON_FILE 208 char *zopts = NULL, *xopts = NULL; 209 size_t l; 210 #endif /* MOUNT_TABLE_ON_FILE */ 211 char *mnt_dir = NULL; 212 213 #ifdef NEED_AUTOFS_SPACE_HACK 214 char *old_mnt_dir = NULL; 215 /* perform space hack */ 216 if (on_autofs) { 217 old_mnt_dir = mnt->mnt_dir; 218 mnt->mnt_dir = mnt_dir = autofs_strdup_space_hack(old_mnt_dir); 219 } else 220 #endif /* NEED_AUTOFS_SPACE_HACK */ 221 mnt_dir = xstrdup(mnt->mnt_dir); 222 223 dlog("'%s' fstype " MTYPE_PRINTF_TYPE " (%s) flags %#x (%s)", 224 mnt_dir, type, mnt->mnt_type, flags, mnt->mnt_opts); 225 226 again: 227 error = MOUNT_TRAP(type, mnt, flags, mnt_data); 228 229 if (error < 0) { 230 plog(XLOG_ERROR, "'%s': mount: %m", mnt_dir); 231 /* 232 * The following code handles conditions which shouldn't 233 * occur. They are possible either because amd screws up 234 * in preparing for the mount, or because some human 235 * messed with the mount point. Both have been known to 236 * happen. -- stolcke 2/22/95 237 */ 238 if (errno == EBUSY) { 239 /* 240 * Also, sometimes unmount isn't called, e.g., because 241 * our mountlist is garbled. This leaves old mount 242 * points around which need to be removed before we 243 * can mount something new in their place. 244 */ 245 errno = umount_fs(mnt_dir, mnttabname, on_autofs); 246 if (errno != 0) 247 plog(XLOG_ERROR, "'%s': umount: %m", mnt_dir); 248 else { 249 plog(XLOG_WARNING, "extra umount required for '%s'", mnt_dir); 250 error = MOUNT_TRAP(type, mnt, flags, mnt_data); 251 } 252 } 253 } 254 255 if (error < 0 && --retry > 0) { 256 sleep(1); 257 goto again; 258 } 259 260 #ifdef NEED_AUTOFS_SPACE_HACK 261 /* Undo space hack */ 262 if (on_autofs) 263 mnt->mnt_dir = old_mnt_dir; 264 #endif /* NEED_AUTOFS_SPACE_HACK */ 265 266 if (error < 0) { 267 error = errno; 268 goto out; 269 } 270 271 #ifdef MOUNT_TABLE_ON_FILE 272 /* 273 * Allocate memory for options: 274 * dev=..., vers={2,3}, proto={tcp,udp} 275 */ 276 l = strlen(mnt->mnt_opts) + 48; 277 zopts = (char *) xmalloc(l); 278 279 /* copy standard options */ 280 xopts = mnt->mnt_opts; 281 282 xstrlcpy(zopts, xopts, l); 283 284 # ifdef MNTTAB_OPT_DEV 285 { 286 /* add the extra dev= field to the mount table */ 287 struct stat stb; 288 if (lstat(mnt_dir, &stb) == 0) { 289 char optsbuf[48]; 290 if (sizeof(stb.st_dev) == 2) /* e.g. SunOS 4.1 */ 291 xsnprintf(optsbuf, sizeof(optsbuf), "%s=%04lx", 292 MNTTAB_OPT_DEV, (u_long) stb.st_dev & 0xffff); 293 else /* e.g. System Vr4 */ 294 xsnprintf(optsbuf, sizeof(optsbuf), "%s=%08lx", 295 MNTTAB_OPT_DEV, (u_long) stb.st_dev); 296 append_opts(zopts, l, optsbuf); 297 } 298 } 299 # endif /* MNTTAB_OPT_DEV */ 300 301 # if defined(HAVE_FS_NFS4) && defined(MNTTAB_OPT_VERS) 302 addvers(zopts, l, mnt, nfs_version, NFS_VERSION4); 303 # endif /* defined(HAVE_FS_NFS4) && defined(MNTTAB_OPT_VERS) */ 304 # if defined(HAVE_FS_NFS3) && defined(MNTTAB_OPT_VERS) 305 addvers(zopts, l, mnt, nfs_version, NFS_VERSION3); 306 # endif /* defined(HAVE_FS_NFS3) && defined(MNTTAB_OPT_VERS) */ 307 # ifdef MNTTAB_OPT_VERS 308 addvers(zopts, l, mnt, nfs_version, NFS_VERSION2); 309 # endif /* MNTTAB_OPT_VERS */ 310 311 # ifdef MNTTAB_OPT_PROTO 312 /* 313 * add the extra proto={tcp,udp} field to the mount table, 314 * unless already specified by user. 315 */ 316 if (nfs_proto && !amu_hasmntopt(mnt, MNTTAB_OPT_PROTO)) { 317 char optsbuf[48]; 318 xsnprintf(optsbuf, sizeof(optsbuf), "%s=%s", MNTTAB_OPT_PROTO, nfs_proto); 319 append_opts(zopts, l, optsbuf); 320 } 321 # endif /* MNTTAB_OPT_PROTO */ 322 323 /* finally, store the options into the mount table structure */ 324 mnt->mnt_opts = zopts; 325 326 /* 327 * Additional fields in mntent_t 328 * are fixed up here 329 */ 330 # ifdef HAVE_MNTENT_T_MNT_CNODE 331 mnt->mnt_cnode = 0; 332 # endif /* HAVE_MNTENT_T_MNT_CNODE */ 333 334 # ifdef HAVE_MNTENT_T_MNT_RO 335 mnt->mnt_ro = (amu_hasmntopt(mnt, MNTTAB_OPT_RO) != NULL); 336 # endif /* HAVE_MNTENT_T_MNT_RO */ 337 338 # ifdef HAVE_MNTENT_T_MNT_TIME 339 # ifdef HAVE_MNTENT_T_MNT_TIME_STRING 340 { /* allocate enough space for a long */ 341 size_t l = 13 * sizeof(char); 342 char *str = (char *) xmalloc(l); 343 xsnprintf(str, l, "%ld", time((time_t *) NULL)); 344 mnt->mnt_time = str; 345 } 346 # else /* not HAVE_MNTENT_T_MNT_TIME_STRING */ 347 mnt->mnt_time = time((time_t *) NULL); 348 # endif /* not HAVE_MNTENT_T_MNT_TIME_STRING */ 349 # endif /* HAVE_MNTENT_T_MNT_TIME */ 350 351 write_mntent(mnt, mnttabname); 352 353 # ifdef MNTTAB_OPT_DEV 354 if (xopts) { 355 XFREE(mnt->mnt_opts); 356 mnt->mnt_opts = xopts; 357 } 358 # endif /* MNTTAB_OPT_DEV */ 359 #endif /* MOUNT_TABLE_ON_FILE */ 360 361 out: 362 XFREE(mnt_dir); 363 return error; 364 } 365 366 367 /* 368 * Compute all NFS attribute cache related flags separately. Note that this 369 * function now computes attribute-cache flags for both Amd's automount 370 * points (NFS) as well as any normal NFS mount that Amd performs. Edit 371 * with caution. 372 */ 373 static void 374 compute_nfs_attrcache_flags(struct nfs_common_args *nap, mntent_t *mntp) 375 { 376 int acval = 0; 377 int err_acval = 1; /* 1 means we found no 'actimeo' value */ 378 #if defined(HAVE_NFS_ARGS_T_ACREGMIN) || defined(HAVE_NFS_ARGS_T_ACREGMAX) || defined(HAVE_NFS_ARGS_T_ACDIRMIN) || defined(HAVE_NFS_ARGS_T_ACDIRMAX) 379 int err_acrdmm; /* for ac{reg,dir}{min,max} */ 380 #endif /* HAVE_NFS_ARGS_T_AC{REG,DIR}{MIN,MAX} */ 381 382 /************************************************************************/ 383 /*** ATTRIBUTE CACHES ***/ 384 /************************************************************************/ 385 /* 386 * acval is set to 0 at the top of the function. If actimeo mount option 387 * exists and defined in mntopts, then its acval is set to it. 388 * If the value is non-zero, then we set all attribute cache fields to it. 389 * If acval is zero, it means it was never defined in mntopts or the 390 * actimeo mount option does not exist, in which case we check for 391 * individual mount options per attribute cache. 392 * Regardless of the value of acval, mount flags are set based directly 393 * on the values of the attribute caches. 394 */ 395 #ifdef MNTTAB_OPT_ACTIMEO 396 err_acval = hasmntvalerr(mntp, MNTTAB_OPT_ACTIMEO, &acval); /* attr cache timeout (sec) */ 397 #endif /* MNTTAB_OPT_ACTIMEO */ 398 399 /*** acregmin ***/ 400 #ifdef HAVE_NFS_ARGS_T_ACREGMIN 401 err_acrdmm = 1; /* 1 means we found no acregmin value */ 402 if (!err_acval) { 403 nap->acregmin = acval; /* min ac timeout for reg files (sec) */ 404 } else { 405 # ifdef MNTTAB_OPT_ACREGMIN 406 int tmp; 407 err_acrdmm = hasmntvalerr(mntp, MNTTAB_OPT_ACREGMIN, &tmp); 408 nap->acregmin = tmp; 409 # else /* not MNTTAB_OPT_ACREGMIN */ 410 nap->acregmin = 0; 411 # endif /* not MNTTAB_OPT_ACREGMIN */ 412 } 413 /* set this flag iff we changed acregmin (possibly to zero) */ 414 # ifdef MNT2_NFS_OPT_ACREGMIN 415 if (!err_acval || !err_acrdmm) 416 nap->flags |= MNT2_NFS_OPT_ACREGMIN; 417 # endif /* MNT2_NFS_OPT_ACREGMIN */ 418 #endif /* HAVE_NFS_ARGS_T_ACREGMIN */ 419 420 /*** acregmax ***/ 421 #ifdef HAVE_NFS_ARGS_T_ACREGMAX 422 err_acrdmm = 1; /* 1 means we found no acregmax value */ 423 if (!err_acval) { 424 nap->acregmax = acval; /* max ac timeout for reg files (sec) */ 425 } else { 426 # ifdef MNTTAB_OPT_ACREGMAX 427 int tmp; 428 err_acrdmm = hasmntvalerr(mntp, MNTTAB_OPT_ACREGMAX, &tmp); 429 nap->acregmax = tmp; 430 # else /* not MNTTAB_OPT_ACREGMAX */ 431 nap->acregmax = 0; 432 # endif /* not MNTTAB_OPT_ACREGMAX */ 433 } 434 /* set this flag iff we changed acregmax (possibly to zero) */ 435 # ifdef MNT2_NFS_OPT_ACREGMAX 436 if (!err_acval || !err_acrdmm) 437 nap->flags |= MNT2_NFS_OPT_ACREGMAX; 438 # endif /* MNT2_NFS_OPT_ACREGMAX */ 439 #endif /* HAVE_NFS_ARGS_T_ACREGMAX */ 440 441 /*** acdirmin ***/ 442 #ifdef HAVE_NFS_ARGS_T_ACDIRMIN 443 err_acrdmm = 1; /* 1 means we found no acdirmin value */ 444 if (!err_acval) { 445 nap->acdirmin = acval; /* min ac timeout for dirs (sec) */ 446 } else { 447 # ifdef MNTTAB_OPT_ACDIRMIN 448 int tmp; 449 err_acrdmm = hasmntvalerr(mntp, MNTTAB_OPT_ACDIRMIN, &tmp); 450 nap->acdirmin = tmp; 451 # else /* not MNTTAB_OPT_ACDIRMIN */ 452 nap->acdirmin = 0; 453 # endif /* not MNTTAB_OPT_ACDIRMIN */ 454 } 455 /* set this flag iff we changed acdirmin (possibly to zero) */ 456 # ifdef MNT2_NFS_OPT_ACDIRMIN 457 if (!err_acval || !err_acrdmm) 458 nap->flags |= MNT2_NFS_OPT_ACDIRMIN; 459 # endif /* MNT2_NFS_OPT_ACDIRMIN */ 460 #endif /* HAVE_NFS_ARGS_T_ACDIRMIN */ 461 462 /*** acdirmax ***/ 463 #ifdef HAVE_NFS_ARGS_T_ACDIRMAX 464 err_acrdmm = 1; /* 1 means we found no acdirmax value */ 465 if (!err_acval) { 466 nap->acdirmax = acval; /* max ac timeout for dirs (sec) */ 467 } else { 468 # ifdef MNTTAB_OPT_ACDIRMAX 469 int tmp; 470 err_acrdmm = hasmntvalerr(mntp, MNTTAB_OPT_ACDIRMAX, &tmp); 471 nap->acdirmax = tmp; 472 # else /* not MNTTAB_OPT_ACDIRMAX */ 473 nap->acdirmax = 0; 474 # endif /* not MNTTAB_OPT_ACDIRMAX */ 475 } 476 /* set this flag iff we changed acdirmax (possibly to zero) */ 477 # ifdef MNT2_NFS_OPT_ACDIRMAX 478 if (!err_acval || !err_acrdmm) 479 nap->flags |= MNT2_NFS_OPT_ACDIRMAX; 480 # endif /* MNT2_NFS_OPT_ACDIRMAX */ 481 #endif /* HAVE_NFS_ARGS_T_ACDIRMAX */ 482 483 484 /* don't cache attributes */ 485 #if defined(MNTTAB_OPT_NOAC) && defined(MNT2_NFS_OPT_NOAC) 486 if (amu_hasmntopt(mntp, MNTTAB_OPT_NOAC) != NULL) 487 nap->flags |= MNT2_NFS_OPT_NOAC; 488 #endif /* defined(MNTTAB_OPT_NOAC) && defined(MNT2_NFS_OPT_NOAC) */ 489 (void)err_acval; 490 } 491 492 493 494 static void 495 compute_nfs_common_args(struct nfs_common_args *nap, mntent_t *mntp, 496 const char *nfs_proto, u_long nfs_version) 497 { 498 #ifdef MNT2_NFS_OPT_TCP 499 if (nfs_proto && STREQ(nfs_proto, "tcp")) 500 nap->flags |= MNT2_NFS_OPT_TCP; 501 #endif /* MNT2_NFS_OPT_TCP */ 502 503 #ifdef MNT2_NFS_OPT_NOCONN 504 /* check if user specified to use unconnected or connected sockets */ 505 if (amu_hasmntopt(mntp, MNTTAB_OPT_NOCONN) != NULL) 506 nap->flags |= MNT2_NFS_OPT_NOCONN; 507 else if (amu_hasmntopt(mntp, MNTTAB_OPT_CONN) != NULL) 508 nap->flags &= ~MNT2_NFS_OPT_NOCONN; 509 else { 510 /* 511 * Some OSs want you to set noconn always. Some want you to always turn 512 * it off. Others want you to turn it on/off only if NFS V.3 is used. 513 * And all of that changes from revision to another. This is 514 * particularly true of OpenBSD, NetBSD, and FreeBSD. So, rather than 515 * attempt to auto-detect this, I'm forced to "fix" it in the individual 516 * conf/nfs_prot/nfs_prot_*.h files. 517 */ 518 # ifdef USE_UNCONNECTED_NFS_SOCKETS 519 if (!(nap->flags & MNT2_NFS_OPT_NOCONN)) { 520 nap->flags |= MNT2_NFS_OPT_NOCONN; 521 plog(XLOG_WARNING, "noconn option not specified, and was just turned ON (OS override)! (May cause NFS hangs on some systems...)"); 522 } 523 # endif /* USE_UNCONNECTED_NFS_SOCKETS */ 524 # ifdef USE_CONNECTED_NFS_SOCKETS 525 if (nap->flags & MNT2_NFS_OPT_NOCONN) { 526 nap->flags &= ~MNT2_NFS_OPT_NOCONN; 527 plog(XLOG_WARNING, "noconn option specified, and was just turned OFF (OS override)! (May cause NFS hangs on some systems...)"); 528 } 529 # endif /* USE_CONNECTED_NFS_SOCKETS */ 530 } 531 #endif /* MNT2_NFS_OPT_NOCONN */ 532 533 #ifdef MNT2_NFS_OPT_RESVPORT 534 # ifdef MNTTAB_OPT_RESVPORT 535 if (amu_hasmntopt(mntp, MNTTAB_OPT_RESVPORT) != NULL) 536 nap->flags |= MNT2_NFS_OPT_RESVPORT; 537 # else /* not MNTTAB_OPT_RESVPORT */ 538 nap->flags |= MNT2_NFS_OPT_RESVPORT; 539 # endif /* not MNTTAB_OPT_RESVPORT */ 540 #endif /* MNT2_NFS_OPT_RESVPORT */ 541 542 nap->rsize = hasmntval(mntp, MNTTAB_OPT_RSIZE); 543 #ifdef MNT2_NFS_OPT_RSIZE 544 if (nap->rsize) 545 nap->flags |= MNT2_NFS_OPT_RSIZE; 546 #endif /* MNT2_NFS_OPT_RSIZE */ 547 if (nfs_version == NFS_VERSION && nap->rsize > 8192) 548 nap->rsize = 8192; 549 550 nap->wsize = hasmntval(mntp, MNTTAB_OPT_WSIZE); 551 #ifdef MNT2_NFS_OPT_WSIZE 552 if (nap->wsize) 553 nap->flags |= MNT2_NFS_OPT_WSIZE; 554 #endif /* MNT2_NFS_OPT_WSIZE */ 555 if (nfs_version == NFS_VERSION && nap->wsize > 8192) 556 nap->wsize = 8192; 557 558 nap->timeo = hasmntval(mntp, MNTTAB_OPT_TIMEO); 559 #ifdef MNT2_NFS_OPT_TIMEO 560 if (nap->timeo) 561 nap->flags |= MNT2_NFS_OPT_TIMEO; 562 #endif /* MNT2_NFS_OPT_TIMEO */ 563 564 nap->retrans = hasmntval(mntp, MNTTAB_OPT_RETRANS); 565 #ifdef MNT2_NFS_OPT_RETRANS 566 if (nap->retrans) 567 nap->flags |= MNT2_NFS_OPT_RETRANS; 568 #endif /* MNT2_NFS_OPT_RETRANS */ 569 570 #ifdef MNT2_NFS_OPT_SOFT 571 if (amu_hasmntopt(mntp, MNTTAB_OPT_SOFT) != NULL) 572 nap->flags |= MNT2_NFS_OPT_SOFT; 573 #endif /* MNT2_NFS_OPT_SOFT */ 574 575 #ifdef MNT2_NFS_OPT_SPONGY 576 if (amu_hasmntopt(mntp, MNTTAB_OPT_SPONGY) != NULL) { 577 nap->flags |= MNT2_NFS_OPT_SPONGY; 578 if (*flags & MNT2_NFS_OPT_SOFT) { 579 plog(XLOG_USER, "Mount opts soft and spongy are incompatible - soft ignored"); 580 nap->flags &= ~MNT2_NFS_OPT_SOFT; 581 } 582 } 583 #endif /* MNT2_NFS_OPT_SPONGY */ 584 585 #if defined(MNT2_GEN_OPT_RONLY) && defined(MNT2_NFS_OPT_RONLY) 586 /* Ultrix has separate generic and NFS ro flags */ 587 if (genflags & MNT2_GEN_OPT_RONLY) 588 nap->flags |= MNT2_NFS_OPT_RONLY; 589 #endif /* defined(MNT2_GEN_OPT_RONLY) && defined(MNT2_NFS_OPT_RONLY) */ 590 591 #ifdef MNTTAB_OPT_INTR 592 if (amu_hasmntopt(mntp, MNTTAB_OPT_INTR) != NULL) 593 /* 594 * Either turn on the "allow interrupts" option, or 595 * turn off the "disallow interrupts" option" 596 */ 597 # ifdef MNT2_NFS_OPT_INTR 598 nap->flags |= MNT2_NFS_OPT_INTR; 599 # endif /* MNT2_NFS_OPT_INTR */ 600 # ifdef MNT2_NFS_OPT_NOINTR 601 nap->flags &= ~MNT2_NFS_OPT_NOINTR; 602 # endif /* MNT2_NFS_OPT_NOINTR */ 603 # ifdef MNT2_NFS_OPT_INT 604 nap->flags |= MNT2_NFS_OPT_INT; 605 # endif /* MNT2_NFS_OPT_INT */ 606 # ifdef MNT2_NFS_OPT_NOINT 607 nap->flags &= ~MNT2_NFS_OPT_NOINT; 608 # endif /* MNT2_NFS_OPT_NOINT */ 609 #endif /* MNTTAB_OPT_INTR */ 610 611 #ifdef MNT2_NFS_OPT_NOACL 612 if (amu_hasmntopt(mntp, MNTTAB_OPT_NOACL) != NULL) 613 nap->flags |= MNT2_NFS_OPT_NOACL; 614 #endif /* MNT2_NFS_OPT_NOACL */ 615 616 #ifdef MNTTAB_OPT_NODEVS 617 if (amu_hasmntopt(mntp, MNTTAB_OPT_NODEVS) != NULL) 618 nap->flags |= MNT2_NFS_OPT_NODEVS; 619 #endif /* MNTTAB_OPT_NODEVS */ 620 621 #ifdef MNTTAB_OPT_COMPRESS 622 if (amu_hasmntopt(mntp, MNTTAB_OPT_COMPRESS) != NULL) 623 nap->flags |= MNT2_NFS_OPT_COMPRESS; 624 #endif /* MNTTAB_OPT_COMPRESS */ 625 626 #ifdef MNTTAB_OPT_PRIVATE /* mount private, single-client tree */ 627 if (amu_hasmntopt(mntp, MNTTAB_OPT_PRIVATE) != NULL) 628 nap->flags |= MNT2_NFS_OPT_PRIVATE; 629 #endif /* MNTTAB_OPT_PRIVATE */ 630 631 632 #if defined(MNT2_NFS_OPT_NOCTO) && defined(MNTTAB_OPT_NOCTO) 633 if (amu_hasmntopt(mntp, MNTTAB_OPT_NOCTO) != NULL) 634 nap->flags |= MNT2_NFS_OPT_NOCTO; 635 #endif /* defined(MNT2_NFS_OPT_NOCTO) && defined(MNTTAB_OPT_NOCTO) */ 636 637 #if defined(MNT2_NFS_OPT_PROPLIST) && defined(MNTTAB_OPT_PROPLIST) 638 if (amu_hasmntopt(mntp, MNTTAB_OPT_PROPLIST) != NULL) 639 nap->flags |= MNT2_NFS_OPT_PROPLIST; 640 #endif /* defined(MNT2_NFS_OPT_PROPLIST) && defined(MNTTAB_OPT_PROPLIST) */ 641 642 #if defined(MNT2_NFS_OPT_NONLM) && defined(MNTTAB_OPT_NOLOCK) 643 if (amu_hasmntopt(mntp, MNTTAB_OPT_NOLOCK) != NULL) 644 nap->flags |= MNT2_NFS_OPT_NONLM; 645 #endif /* defined(MNT2_NFS_OPT_NONLM) && defined(MNTTAB_OPT_NOLOCK) */ 646 647 #if defined(MNT2_NFS_OPT_XLATECOOKIE) && defined(MNTTAB_OPT_XLATECOOKIE) 648 if (amu_hasmntopt(mntp, MNTTAB_OPT_XLATECOOKIE) != NULL) 649 nap->flags |= MNT2_NFS_OPT_XLATECOOKIE; 650 #endif /* defined(MNT2_NFS_OPT_XLATECOOKIE) && defined(MNTTAB_OPT_XLATECOOKIE) */ 651 } 652 653 #ifdef DEBUG 654 static void 655 print_nfs_common_args(const struct nfs_common_args *a) 656 { 657 plog(XLOG_DEBUG, "NA->flags = 0x%lx", a->flags); 658 659 plog(XLOG_DEBUG, "NA->rsize = %lu", a->rsize); 660 plog(XLOG_DEBUG, "NA->wsize = %lu", a->wsize); 661 plog(XLOG_DEBUG, "NA->timeo = %lu", a->timeo); 662 plog(XLOG_DEBUG, "NA->retrans = %lu", a->retrans); 663 664 #ifdef HAVE_NFS_ARGS_T_ACREGMIN 665 plog(XLOG_DEBUG, "NA->acregmin = %lu", a->acregmin); 666 plog(XLOG_DEBUG, "NA->acregmax = %lu", a->acregmax); 667 plog(XLOG_DEBUG, "NA->acdirmin = %lu", a->acdirmin); 668 plog(XLOG_DEBUG, "NA->acdirmax = %lu", a->acdirmax); 669 #endif /* HAVE_NFS_ARGS_T_ACREGMIN */ 670 } 671 #endif 672 673 static void 674 discard_nfs23_args(nfs_args_t *nap) 675 { 676 #ifdef HAVE_TRANSPORT_TYPE_TLI 677 free_knetconfig(nap->knconf); 678 if (nap->addr) 679 XFREE(nap->addr); /* allocated in compute_nfs_args() */ 680 #endif /* HAVE_TRANSPORT_TYPE_TLI */ 681 } 682 683 #ifdef DEBUG 684 /* get string version (in hex) of identifier */ 685 static char * 686 get_hex_string(u_int len, const char *fhdata) 687 { 688 u_int i; 689 static u_int xlen; 690 static char *buf; 691 static u_short *arr; 692 char str[16]; 693 694 if (!fhdata || len == 0 || len > 10240) 695 return NULL; 696 i = len * 4 + 1; 697 if (xlen < i) { 698 buf = xrealloc(buf, i); 699 arr = xrealloc(arr, len * sizeof(*arr)); 700 xlen = i; 701 } 702 703 buf[0] = '\0'; 704 memset(arr, 0, len * sizeof(*arr)); 705 memcpy(arr, fhdata, len); 706 len /= sizeof(*arr); 707 for (i = 0; i < len; i++) { 708 xsnprintf(str, sizeof(str), "%04x", ntohs(arr[i])); 709 xstrlcat(buf, str, xlen); 710 } 711 return buf; 712 } 713 714 static void 715 print_nfs_sockaddr_in(const char *tag, const struct sockaddr_in *sap) 716 { 717 char name[64]; 718 plog(XLOG_DEBUG, "NA->%s.sin_family = %d", tag, sap->sin_family); 719 plog(XLOG_DEBUG, "NA->%s.sin_port = %d", tag, ntohs(sap->sin_port)); 720 if (inet_ntop(AF_INET, &sap->sin_addr, name, sizeof(name)) == NULL) 721 return; 722 plog(XLOG_DEBUG, "NA->%s.sin_addr = \"%s\"", tag, name); 723 } 724 725 /* 726 * print a subset of fields from "struct nfs_args" that are otherwise 727 * not being provided anywhere else. 728 */ 729 static void 730 print_nfs23_args(const nfs_args_t *nap, u_long nfs_version) 731 { 732 int fhlen = 32; /* default: NFS V.2 file handle length is 32 */ 733 #ifdef HAVE_TRANSPORT_TYPE_TLI 734 struct netbuf *nbp; 735 struct knetconfig *kncp; 736 #else /* not HAVE_TRANSPORT_TYPE_TLI */ 737 struct sockaddr_in *sap; 738 #endif /* not HAVE_TRANSPORT_TYPE_TLI */ 739 struct nfs_common_args a; 740 741 if (!nap) { 742 plog(XLOG_DEBUG, "NULL nfs_args!"); 743 return; 744 } 745 746 /* override default file handle size */ 747 #ifdef FHSIZE 748 fhlen = FHSIZE; 749 #endif /* FHSIZE */ 750 #ifdef NFS_FHSIZE 751 fhlen = NFS_FHSIZE; 752 #endif /* NFS_FHSIZE */ 753 754 #ifdef HAVE_TRANSPORT_TYPE_TLI 755 nbp = nap->addr; 756 plog(XLOG_DEBUG, "NA->addr {netbuf} (maxlen=%d, len=%d) = \"%s\"", 757 nbp->maxlen, nbp->len, 758 get_hex_string(nbp->len, nbp->buf)); 759 nbp = nap->syncaddr; 760 plog(XLOG_DEBUG, "NA->syncaddr {netbuf} %p", nbp); 761 kncp = nap->knconf; 762 plog(XLOG_DEBUG, "NA->knconf->semantics %lu", (u_long) kncp->knc_semantics); 763 plog(XLOG_DEBUG, "NA->knconf->protofmly \"%s\"", kncp->knc_protofmly); 764 plog(XLOG_DEBUG, "NA->knconf->proto \"%s\"", kncp->knc_proto); 765 plog(XLOG_DEBUG, "NA->knconf->rdev %lu", (u_long) kncp->knc_rdev); 766 /* don't print knconf->unused field */ 767 #else /* not HAVE_TRANSPORT_TYPE_TLI */ 768 # ifdef NFS_ARGS_T_ADDR_IS_POINTER 769 sap = (struct sockaddr_in *) nap->addr; 770 # else /* not NFS_ARGS_T_ADDR_IS_POINTER */ 771 sap = (struct sockaddr_in *) &nap->addr; 772 # endif /* not NFS_ARGS_T_ADDR_IS_POINTER */ 773 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 774 /* as per POSIX, sin_len need not be set (used internally by kernel) */ 775 plog(XLOG_DEBUG, "NA->addr.sin_len = %d", sap->sin_len); 776 #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ 777 print_nfs_sockaddr_in("addr", sap); 778 #endif /* not HAVE_TRANSPORT_TYPE_TLI */ 779 #ifdef HAVE_NFS_ARGS_T_ADDRLEN 780 plog(XLOG_DEBUG, "NA->addrlen = %d", nap->addrlen); 781 #endif /* ifdef HAVE_NFS_ARGS_T_ADDRLEN */ 782 783 plog(XLOG_DEBUG, "NA->hostname = \"%s\"", nap->hostname ? nap->hostname : "null"); 784 #ifdef HAVE_NFS_ARGS_T_NAMLEN 785 plog(XLOG_DEBUG, "NA->namlen = %d", nap->namlen); 786 #endif /* HAVE_NFS_ARGS_T_NAMLEN */ 787 788 #ifdef MNT2_NFS_OPT_FSNAME 789 plog(XLOG_DEBUG, "NA->fsname = \"%s\"", nap->fsname ? nap->fsname : "null"); 790 #endif /* MNT2_NFS_OPT_FSNAME */ 791 792 #ifdef HAVE_NFS_ARGS_T_FHSIZE 793 plog(XLOG_DEBUG, "NA->fhsize = %d", nap->fhsize); 794 fhlen = nap->fhsize; 795 #endif /* HAVE_NFS_ARGS_T_FHSIZE */ 796 #ifdef HAVE_NFS_ARGS_T_FH_LEN 797 plog(XLOG_DEBUG, "NA->fh_len = %d", nap->fh_len); 798 fhlen = nap->fh_len; 799 #endif /* HAVE_NFS_ARGS_T_FH_LEN */ 800 801 /* 802 * XXX: need to figure out how to correctly print file handles, 803 * since some times they are pointers, and sometimes the real structure 804 * is stored in nfs_args. Even if it is a pointer, it can be the actual 805 * char[] array, or a structure containing multiple fields. 806 */ 807 plog(XLOG_DEBUG, "NA->filehandle = \"%s\"", 808 get_hex_string(fhlen, (const char *) &nap->NFS_FH_FIELD)); 809 810 #ifdef HAVE_NFS_ARGS_T_SOTYPE 811 plog(XLOG_DEBUG, "NA->sotype = %d", nap->sotype); 812 #endif /* HAVE_NFS_ARGS_T_SOTYPE */ 813 #ifdef HAVE_NFS_ARGS_T_PROTO 814 plog(XLOG_DEBUG, "NA->proto = %d", (int) nap->proto); 815 #endif /* HAVE_NFS_ARGS_T_PROTO */ 816 #ifdef HAVE_NFS_ARGS_T_VERSION 817 plog(XLOG_DEBUG, "NA->version = %d", nap->version); 818 #endif /* HAVE_NFS_ARGS_T_VERSION */ 819 820 put_nfs_common_args(nap, a); 821 print_nfs_common_args(&a); 822 823 #ifdef HAVE_NFS_ARGS_T_BSIZE 824 plog(XLOG_DEBUG, "NA->bsize = %d", nap->bsize); 825 #endif /* HAVE_NFS_ARGS_T_BSIZE */ 826 827 #ifdef MNTTAB_OPT_SYMTTL 828 plog(XLOG_DEBUG, "NA->symttl = %d", nap->symttl); 829 #endif /* MNTTAB_OPT_SYMTTL */ 830 #ifdef MNTTAB_OPT_PG_THRESH 831 plog(XLOG_DEBUG, "NA->pg_thresh = %d", nap->pg_thresh); 832 #endif /* MNTTAB_OPT_PG_THRESH */ 833 834 #ifdef MNT2_NFS_OPT_BIODS 835 plog(XLOG_DEBUG, "NA->biods = %d", nap->biods); 836 #endif /* MNT2_NFS_OPT_BIODS */ 837 838 } 839 #endif /* DEBUG */ 840 841 /* 842 * Fill in the many possible fields and flags of struct nfs_args. 843 * 844 * nap: pre-allocated structure to fill in. 845 * mntp: mount entry structure (includes options) 846 * genflags: generic mount flags already determined 847 * nfsncp: (TLI only) netconfig entry for this NFS mount 848 * ip_addr: IP address of file server 849 * nfs_version: 2, 3, or 0 if unknown 850 * nfs_proto: "udp", "tcp", or NULL. 851 * fhp: file handle structure pointer 852 * host_name: name of remote NFS host 853 * fs_name: remote file system name to mount 854 */ 855 static void 856 compute_nfs23_args(nfs_args_t *nap, 857 mntent_t *mntp, 858 int genflags, 859 struct netconfig *nfsncp, 860 struct sockaddr_in *ip_addr, 861 u_long nfs_version, 862 char *nfs_proto, 863 am_nfs_handle_t *fhp, 864 char *host_name, 865 char *fs_name) 866 { 867 struct nfs_common_args a; 868 /* initialize just in case */ 869 memset((voidp) nap, 0, sizeof(nfs_args_t)); 870 871 /* compute all of the NFS attribute-cache flags */ 872 memset(&a, 0, sizeof(a)); 873 compute_nfs_attrcache_flags(&a, mntp); 874 compute_nfs_common_args(&a, mntp, nfs_proto, nfs_version); 875 get_nfs_common_args(nap, a); 876 877 /************************************************************************/ 878 /*** FILEHANDLE DATA AND LENGTH ***/ 879 /************************************************************************/ 880 #ifdef HAVE_FS_NFS3 881 if (nfs_version == NFS_VERSION3) { 882 if (fhp == NULL) { 883 plog(XLOG_FATAL, "cannot pass NULL fh for NFSv%lu", nfs_version); 884 going_down(1); 885 return; 886 } 887 888 # if defined(HAVE_NFS_ARGS_T_FHSIZE) || defined(HAVE_NFS_ARGS_T_FH_LEN) 889 /* 890 * Some systems (Irix/bsdi3) have a separate field in nfs_args for 891 * the length of the file handle for NFS V3. They insist that 892 * the file handle set in nfs_args be plain bytes, and not 893 * include the length field. 894 */ 895 NFS_FH_DREF(nap->NFS_FH_FIELD, &fhp->v3.am_fh3_data); 896 # else /* not defined(HAVE_NFS_ARGS_T_FHSIZE) || defined(HAVE_NFS_ARGS_T_FH_LEN) */ 897 NFS_FH_DREF(nap->NFS_FH_FIELD, &fhp->v3); 898 # endif /* not defined(HAVE_NFS_ARGS_T_FHSIZE) || defined(HAVE_NFS_ARGS_T_FH_LEN) */ 899 # ifdef MNT2_NFS_OPT_NFSV3 900 nap->flags |= MNT2_NFS_OPT_NFSV3; 901 # endif /* MNT2_NFS_OPT_NFSV3 */ 902 # ifdef MNT2_NFS_OPT_VER3 903 nap->flags |= MNT2_NFS_OPT_VER3; 904 # endif /* MNT2_NFS_OPT_VER3 */ 905 } else 906 #endif /* HAVE_FS_NFS3 */ 907 { 908 if (fhp == NULL) { 909 plog(XLOG_FATAL, "cannot pass NULL fh for NFSv%lu", nfs_version); 910 going_down(1); 911 return; 912 } 913 NFS_FH_DREF(nap->NFS_FH_FIELD, &fhp->v2); 914 } 915 916 #ifdef HAVE_NFS_ARGS_T_FHSIZE 917 # ifdef HAVE_FS_NFS3 918 if (nfs_version == NFS_VERSION3) 919 nap->fhsize = fhp->v3.am_fh3_length; 920 else 921 # endif /* HAVE_FS_NFS3 */ 922 nap->fhsize = FHSIZE; 923 #endif /* HAVE_NFS_ARGS_T_FHSIZE */ 924 925 /* this is the version of the nfs_args structure, not of NFS! */ 926 #ifdef HAVE_NFS_ARGS_T_FH_LEN 927 # ifdef HAVE_FS_NFS3 928 if (nfs_version == NFS_VERSION3) 929 nap->fh_len = fhp->v3.am_fh3_length; 930 else 931 # endif /* HAVE_FS_NFS3 */ 932 nap->fh_len = FHSIZE; 933 #endif /* HAVE_NFS_ARGS_T_FH_LEN */ 934 935 /************************************************************************/ 936 /*** HOST NAME ***/ 937 /************************************************************************/ 938 /* 939 * XXX: warning, using xstrlcpy in NFS_HN_DREF, which may corrupt a 940 * struct nfs_args, or truncate our concocted "hostname:/path" 941 * string prematurely. 942 */ 943 NFS_HN_DREF(nap->hostname, host_name); 944 #ifdef MNT2_NFS_OPT_HOSTNAME 945 nap->flags |= MNT2_NFS_OPT_HOSTNAME; 946 #endif /* MNT2_NFS_OPT_HOSTNAME */ 947 948 /************************************************************************/ 949 /*** IP ADDRESS OF REMOTE HOST ***/ 950 /************************************************************************/ 951 if (ip_addr) { 952 #ifdef HAVE_TRANSPORT_TYPE_TLI 953 nap->addr = ALLOC(struct netbuf); /* free()'ed at end of mount_nfs_fh() */ 954 #endif /* HAVE_TRANSPORT_TYPE_TLI */ 955 NFS_SA_DREF(nap, ip_addr); 956 } 957 958 /************************************************************************/ 959 /*** NFS PROTOCOL (UDP, TCP) AND VERSION ***/ 960 /************************************************************************/ 961 #ifdef HAVE_NFS_ARGS_T_SOTYPE 962 /* bsdi3 uses this */ 963 if (nfs_proto) { 964 if (STREQ(nfs_proto, "tcp")) 965 nap->sotype = SOCK_STREAM; 966 else if (STREQ(nfs_proto, "udp")) 967 nap->sotype = SOCK_DGRAM; 968 } 969 #endif /* HAVE_NFS_ARGS_T_SOTYPE */ 970 971 #ifdef HAVE_NFS_ARGS_T_PROTO 972 nap->proto = 0; /* bsdi3 sets this field to zero */ 973 # ifdef IPPROTO_TCP 974 if (nfs_proto) { 975 if (STREQ(nfs_proto, "tcp")) /* AIX 4.2.x needs this */ 976 nap->proto = IPPROTO_TCP; 977 else if (STREQ(nfs_proto, "udp")) 978 nap->proto = IPPROTO_UDP; 979 } 980 # endif /* IPPROTO_TCP */ 981 #endif /* HAVE_NFS_ARGS_T_SOTYPE */ 982 983 #ifdef HAVE_NFS_ARGS_T_VERSION 984 # ifdef NFS_ARGSVERSION 985 nap->version = NFS_ARGSVERSION; /* BSDI 3.0 and OpenBSD 2.2 */ 986 # endif /* NFS_ARGSVERSION */ 987 # ifdef DG_MOUNT_NFS_VERSION 988 nap->version = DG_MOUNT_NFS_VERSION; /* dg-ux */ 989 # endif /* DG_MOUNT_NFS_VERSION */ 990 #endif /* HAVE_NFS_ARGS_VERSION */ 991 992 /************************************************************************/ 993 /*** OTHER NFS SOCKET RELATED OPTIONS AND FLAGS ***/ 994 /************************************************************************/ 995 996 /************************************************************************/ 997 /*** OTHER FLAGS AND OPTIONS ***/ 998 /************************************************************************/ 999 1000 #ifdef MNT2_NFS_OPT_BIODS 1001 if ((nap->biods = hasmntval(mntp, MNTTAB_OPT_BIODS))) 1002 nap->flags |= MNT2_NFS_OPT_BIODS; 1003 #endif /* MNT2_NFS_OPT_BIODS */ 1004 1005 #ifdef MNTTAB_OPT_SYMTTL /* symlink cache time-to-live */ 1006 if ((nap->symttl = hasmntval(mntp, MNTTAB_OPT_SYMTTL))) 1007 nap->args.flags |= MNT2_NFS_OPT_SYMTTL; 1008 #endif /* MNTTAB_OPT_SYMTTL */ 1009 1010 #ifdef MNT2_NFS_OPT_PGTHRESH /* paging threshold */ 1011 if ((nap->pg_thresh = hasmntval(mntp, MNTTAB_OPT_PGTHRESH))) 1012 nap->args.flags |= MNT2_NFS_OPT_PGTHRESH; 1013 #endif /* MNT2_NFS_OPT_PGTHRESH */ 1014 1015 #if defined(MNT2_NFS_OPT_POSIX) && defined(MNTTAB_OPT_POSIX) 1016 if (amu_hasmntopt(mntp, MNTTAB_OPT_POSIX) != NULL) { 1017 nap->flags |= MNT2_NFS_OPT_POSIX; 1018 # ifdef HAVE_NFS_ARGS_T_PATHCONF 1019 nap->pathconf = NULL; 1020 # endif /* HAVE_NFS_ARGS_T_PATHCONF */ 1021 } 1022 #endif /* MNT2_NFS_OPT_POSIX && MNTTAB_OPT_POSIX */ 1023 1024 #ifdef HAVE_TRANSPORT_TYPE_TLI 1025 /* set up syncaddr field */ 1026 nap->syncaddr = (struct netbuf *) NULL; 1027 1028 /* set up knconf field */ 1029 if (get_knetconfig(&nap->knconf, nfsncp, nfs_proto) < 0) { 1030 plog(XLOG_FATAL, "cannot fill knetconfig structure for nfs_args"); 1031 going_down(1); 1032 return; 1033 } 1034 /* update the flags field for knconf */ 1035 nap->args.flags |= MNT2_NFS_OPT_KNCONF; 1036 #endif /* HAVE_TRANSPORT_TYPE_TLI */ 1037 1038 #ifdef MNT2_NFS_OPT_FSNAME 1039 nap->fsname = fs_name; 1040 nap->args.flags |= MNT2_NFS_OPT_FSNAME; 1041 #endif /* MNT2_NFS_OPT_FSNAME */ 1042 1043 1044 #ifdef HAVE_NFS_ARGS_T_OPTSTR 1045 nap->optstr = mntp->mnt_opts; 1046 #endif /* HAVE_NFS_ARGS_T_OPTSTR */ 1047 1048 #if defined(MNT2_NFS_OPT_MAXGRPS) && defined(MNTTAB_OPT_MAXGROUPS) 1049 nap->maxgrouplist = hasmntval(mntp, MNTTAB_OPT_MAXGROUPS); 1050 if (nap->maxgrouplist != 0) 1051 nap->flags |= MNT2_NFS_OPT_MAXGRPS; 1052 #endif /* defined(MNT2_NFS_OPT_MAXGRPS) && defined(MNTTAB_OPT_MAXGROUPS) */ 1053 1054 /************************************************************************/ 1055 /*** FINAL ACTIONS ***/ 1056 /************************************************************************/ 1057 1058 #ifdef HAVE_NFS_ARGS_T_GFS_FLAGS 1059 /* Ultrix stores generic flags in nfs_args.gfs_flags. */ 1060 nap->gfs_flags = genflags; 1061 #endif /* HAVE_NFS_ARGS_T_FLAGS */ 1062 1063 return; /* end of compute_nfs_args() function */ 1064 } 1065 1066 #ifdef HAVE_FS_NFS4 1067 1068 #define RPC_AUTH_GSS_KRB5 390003 1069 #define RPC_AUTH_GSS_KRB5I 390004 1070 #define RPC_AUTH_GSS_KRB5P 390005 1071 #define RPC_AUTH_GSS_LKEY 390006 1072 #define RPC_AUTH_GSS_LKEYI 390007 1073 #define RPC_AUTH_GSS_LKEYP 390008 1074 #define RPC_AUTH_GSS_SPKM 390009 1075 #define RPC_AUTH_GSS_SPKMI 390010 1076 #define RPC_AUTH_GSS_SPKMP 390011 1077 1078 struct { 1079 const char *name; 1080 int num; 1081 } flavours[] = { 1082 { "unix", AUTH_UNIX }, 1083 { "krb5", RPC_AUTH_GSS_KRB5 }, 1084 { "krb5i", RPC_AUTH_GSS_KRB5I }, 1085 { "krb5p", RPC_AUTH_GSS_KRB5P }, 1086 { "lkey", RPC_AUTH_GSS_LKEY }, 1087 { "lkeyi", RPC_AUTH_GSS_LKEYI }, 1088 { "lkeyp", RPC_AUTH_GSS_LKEYP }, 1089 { "spkm", RPC_AUTH_GSS_SPKM }, 1090 { "spkmi", RPC_AUTH_GSS_SPKMI }, 1091 { "spkmp", RPC_AUTH_GSS_SPKMP }, 1092 }; 1093 1094 static char * 1095 set_nfs4_security(nfs4_args_t *nap, mntent_t *mntp) 1096 { 1097 const char *o = hasmnteq(mntp, MNTTAB_OPT_SEC); 1098 char *q, *s, *ss; 1099 size_t l, i; 1100 1101 if (o == NULL) 1102 o = "unix"; 1103 1104 for (l = 1, q = strchr(o, ','); q; q = strchr(q + 1, ',')) 1105 l++; 1106 1107 nap->auth_flavours = xmalloc(l * sizeof(*nap->auth_flavours)); 1108 1109 s = ss = xstrdup(o); 1110 for (;;) { 1111 q = strchr(s, ','); 1112 if (q) 1113 *q = '\0'; 1114 1115 for (l = 0, i = 0; i < sizeof(flavours) / sizeof(flavours[0]); i++) 1116 if (strcmp(flavours[i].name, s) == 0) { 1117 nap->auth_flavours[l++] = flavours[i].num; 1118 break; 1119 } 1120 1121 if (i == sizeof(flavours) / sizeof(flavours[0])) 1122 plog(XLOG_ERROR, "Unknown NFSv4 security mechanism %s\n", s); 1123 1124 if (q == NULL) 1125 break; 1126 1127 *q = ':'; 1128 s = ++q; 1129 } 1130 1131 nap->auth_flavourlen = l; 1132 return ss; 1133 } 1134 1135 static int 1136 get_my_ipv4addr(struct nfs_string *ns) 1137 { 1138 struct hostent *hp; 1139 char myname[MAXHOSTNAMELEN]; 1140 1141 if (gethostname(myname, sizeof(myname)) == -1) 1142 return -1; 1143 if ((hp = gethostbyname(myname)) == NULL) 1144 return -1; 1145 if (inet_ntop(AF_INET, hp->h_addr, myname, sizeof(myname)) == NULL) 1146 return -1; 1147 ns->len = strlen(myname); 1148 ns->data = xmalloc(ns->len + 1); 1149 memcpy(ns->data, myname, ns->len + 1); 1150 return 0; 1151 } 1152 1153 static void 1154 add_nfs4_mntopts(const nfs4_args_t *nap, mntent_t *mntp, char *sec) 1155 { 1156 char *opts = mntp->mnt_opts; 1157 char buf[1024], addr[128]; 1158 size_t len = strlen(mntp->mnt_opts); 1159 1160 if (inet_ntop(AF_INET, 1161 &((const struct sockaddr_in *)nap->host_addr)->sin_addr, 1162 addr, sizeof(addr)) == NULL) 1163 return; 1164 1165 xsnprintf(buf, sizeof(buf), ",clientaddr=%s,addr=%s", nap->client_addr.data, 1166 addr); 1167 1168 len += strlen(buf) + 1; 1169 1170 if (sec && strcmp(sec, "unix") != 0) { 1171 len += strlen(sec) + strlen(MNTTAB_OPT_SEC) + 2; /* 2 = ",=" */ 1172 } else 1173 sec = NULL; 1174 1175 opts = xrealloc(mntp->mnt_opts, len); 1176 xstrlcat(opts, buf, len); 1177 1178 if (sec) { 1179 xstrlcat(opts, ",", len); 1180 xstrlcat(opts, MNTTAB_OPT_SEC, len); 1181 xstrlcat(opts, "=", len); 1182 xstrlcat(opts, sec, len); 1183 } 1184 1185 mntp->mnt_opts = opts; 1186 } 1187 1188 static void 1189 print_nfs4_security(const nfs4_args_t *nap) 1190 { 1191 char buf[1024]; 1192 char num[64]; 1193 size_t i, j; 1194 1195 buf[0] = '\0'; 1196 1197 for (i = 0; i < nap->auth_flavourlen; i++) { 1198 1199 for (j = 0; j < sizeof(flavours) / sizeof(flavours[0]); j++) 1200 if (flavours[j].num == nap->auth_flavours[i]) { 1201 xstrlcpy(num, flavours[j].name, sizeof(num)); 1202 break; 1203 } 1204 1205 if (j == sizeof(flavours) / sizeof(flavours[0])) { 1206 plog(XLOG_ERROR, "Unknown NFSv4 security mechanism %d\n", 1207 nap->auth_flavours[i]); 1208 xsnprintf(num, sizeof(num), "*%d*", nap->auth_flavours[i]); 1209 } 1210 1211 if (buf[0]) 1212 xstrlcat(buf, ":", sizeof(buf)); 1213 1214 xstrlcat(buf, num, sizeof(buf)); 1215 } 1216 1217 plog(XLOG_DEBUG, "NA->auth_flavours \"%s\"\n", buf); 1218 } 1219 1220 static void 1221 discard_nfs4_args(nfs4_args_t *nap) 1222 { 1223 if (nap->client_addr.data) 1224 free(nap->client_addr.data); 1225 if (nap->hostname.data) 1226 free(nap->hostname.data); 1227 if (nap->mnt_path.data) 1228 free(nap->mnt_path.data); 1229 if (nap->host_addr) 1230 free(nap->host_addr); 1231 if (nap->auth_flavours) 1232 free(nap->auth_flavours); 1233 } 1234 1235 /* 1236 * Fill in the many possible fields and flags of struct nfs4_args. 1237 * 1238 * nap: pre-allocated structure to fill in. 1239 * mntp: mount entry structure (includes options) 1240 * genflags: generic mount flags already determined 1241 * nfsncp: (TLI only) netconfig entry for this NFS mount 1242 * ip_addr: IP address of file server 1243 * nfs_version: 4, or 0 if unknown 1244 * nfs_proto: "udp", "tcp", or NULL. 1245 * fhp: file handle structure pointer 1246 * host_name: name of remote NFS host 1247 * fs_name: remote file system name to mount 1248 */ 1249 static void 1250 compute_nfs4_args(nfs4_args_t *nap, 1251 mntent_t *mntp, 1252 int genflags, 1253 struct netconfig *nfsncp, 1254 struct sockaddr_in *ip_addr, 1255 u_long nfs_version, 1256 char *nfs_proto, 1257 am_nfs_handle_t *fhp, 1258 char *host_name, 1259 char *fs_name) 1260 { 1261 char *s; 1262 struct nfs_common_args a; 1263 uint16_t nfs_port; 1264 1265 /* initialize just in case */ 1266 memset((voidp) nap, 0, sizeof(nfs4_args_t)); 1267 1268 /* compute all of the NFS attribute-cache flags */ 1269 memset(&a, 0, sizeof(a)); 1270 compute_nfs_attrcache_flags(&a, mntp); 1271 compute_nfs_common_args(&a, mntp, nfs_proto, nfs_version); 1272 get_nfs_common_args(nap, a); 1273 1274 get_my_ipv4addr(&nap->client_addr); 1275 1276 /************************************************************************/ 1277 /*** HOST NAME ***/ 1278 /************************************************************************/ 1279 nap->hostname.len = strlen(host_name); 1280 nap->hostname.data = xmalloc(nap->hostname.len + 1); 1281 memcpy(nap->hostname.data, host_name, nap->hostname.len + 1); 1282 1283 if ((s = strchr(fs_name, ':')) != NULL) 1284 s++; 1285 else 1286 s = fs_name; 1287 1288 nap->mnt_path.len = strlen(s); 1289 nap->mnt_path.data = xmalloc(nap->mnt_path.len + 1); 1290 memcpy(nap->mnt_path.data, s, nap->mnt_path.len + 1); 1291 plog(XLOG_DEBUG, "dir name %s\n", nap->mnt_path.data); 1292 1293 /************************************************************************/ 1294 /*** IP ADDRESS OF REMOTE HOST ***/ 1295 /************************************************************************/ 1296 nap->host_addrlen = sizeof(*ip_addr); 1297 nap->host_addr = xmalloc(nap->host_addrlen); 1298 memcpy(nap->host_addr, ip_addr, nap->host_addrlen); 1299 1300 nfs_port = hasmntval(mntp, MNTTAB_OPT_PORT); 1301 if (nfs_port == 0) 1302 nfs_port = htons(NFS_PORT); 1303 else 1304 nfs_port = htons(nfs_port); 1305 1306 ((struct sockaddr_in *)nap->host_addr)->sin_port = nfs_port; 1307 1308 nap->proto = 0; /* bsdi3 sets this field to zero */ 1309 if (nfs_proto) { 1310 if (STREQ(nfs_proto, "tcp")) /* AIX 4.2.x needs this */ 1311 nap->proto = IPPROTO_TCP; 1312 else if (STREQ(nfs_proto, "udp")) 1313 nap->proto = IPPROTO_UDP; 1314 } 1315 1316 nap->version = NFS4_MOUNT_VERSION; /* BSDI 3.0 and OpenBSD 2.2 */ 1317 1318 /************************************************************************/ 1319 /*** OTHER NFS SOCKET RELATED OPTIONS AND FLAGS ***/ 1320 /************************************************************************/ 1321 1322 1323 /************************************************************************/ 1324 /*** OTHER FLAGS AND OPTIONS ***/ 1325 /************************************************************************/ 1326 1327 #if defined(MNT2_NFS_OPT_POSIX) && defined(MNTTAB_OPT_POSIX) 1328 if (amu_hasmntopt(mntp, MNTTAB_OPT_POSIX) != NULL) { 1329 nap->args.flags |= MNT2_NFS_OPT_POSIX; 1330 # ifdef HAVE_NFS_ARGS_T_PATHCONF 1331 nap->pathconf = NULL; 1332 # endif /* HAVE_NFS_ARGS_T_PATHCONF */ 1333 } 1334 #endif /* MNT2_NFS_OPT_POSIX && MNTTAB_OPT_POSIX */ 1335 1336 #if defined(MNT2_NFS_OPT_MAXGRPS) && defined(MNTTAB_OPT_MAXGROUPS) 1337 nap->maxgrouplist = hasmntval(mntp, MNTTAB_OPT_MAXGROUPS); 1338 if (nap->maxgrouplist != 0) 1339 nap->args.flags |= MNT2_NFS_OPT_MAXGRPS; 1340 #endif /* defined(MNT2_NFS_OPT_MAXGRPS) && defined(MNTTAB_OPT_MAXGROUPS) */ 1341 1342 #ifdef HAVE_NFS_ARGS_T_OPTSTR 1343 nap->optstr = mntp->mnt_opts; 1344 #endif /* HAVE_NFS_ARGS_T_OPTSTR */ 1345 1346 /************************************************************************/ 1347 /*** FINAL ACTIONS ***/ 1348 /************************************************************************/ 1349 1350 #ifdef HAVE_NFS_ARGS_T_GFS_FLAGS 1351 /* Ultrix stores generic flags in nfs_args.gfs_flags. */ 1352 nap->gfs_flags = genflags; 1353 #endif /* HAVE_NFS_ARGS_T_FLAGS */ 1354 1355 s = set_nfs4_security(nap, mntp); 1356 1357 /* Add addresses to the mount options */ 1358 add_nfs4_mntopts(nap, mntp, s); 1359 1360 return; /* end of compute_nfs4_args() function */ 1361 } 1362 1363 #ifdef DEBUG 1364 static void 1365 print_nfs4_args(const nfs4_args_t *nap, u_long nfs_version) 1366 { 1367 struct sockaddr_in *sap; 1368 struct nfs_common_args a; 1369 1370 if (!nap) { 1371 plog(XLOG_DEBUG, "NULL nfs_args!"); 1372 return; 1373 } 1374 1375 plog(XLOG_DEBUG, "NA->client_addr \"%s\"\n", nap->client_addr.data); 1376 plog(XLOG_DEBUG, "NA->mnt_path = \"%s\"", nap->mnt_path.data); 1377 plog(XLOG_DEBUG, "NA->hostname = \"%s\"", nap->hostname.data); 1378 sap = (struct sockaddr_in *) nap->host_addr; 1379 print_nfs_sockaddr_in("host_addr", sap); 1380 plog(XLOG_DEBUG, "NA->proto = %d", (int) nap->proto); 1381 #ifdef HAVE_NFS_ARGS_T_VERSION 1382 plog(XLOG_DEBUG, "NA->version = %d", nap->version); 1383 #endif /* HAVE_NFS_ARGS_T_VERSION */ 1384 print_nfs4_security(nap); 1385 1386 put_nfs_common_args(nap, a); 1387 print_nfs_common_args(&a); 1388 } 1389 #endif 1390 #endif /* HAVE_FS_NFS4 */ 1391 1392 void 1393 compute_nfs_args(void *nap, 1394 mntent_t *mntp, 1395 int genflags, 1396 struct netconfig *nfsncp, 1397 struct sockaddr_in *ip_addr, 1398 u_long nfs_version, 1399 char *nfs_proto, 1400 am_nfs_handle_t *fhp, 1401 char *host_name, 1402 char *fs_name) 1403 { 1404 #ifdef HAVE_FS_NFS4 1405 if (nfs_version == NFS_VERSION4) 1406 compute_nfs4_args(nap, mntp, genflags, nfsncp, ip_addr, nfs_version, 1407 nfs_proto, fhp, host_name, fs_name); 1408 else 1409 #endif /* HAVE_FS_NFS4 */ 1410 compute_nfs23_args(nap, mntp, genflags, nfsncp, ip_addr, nfs_version, 1411 nfs_proto, fhp, host_name, fs_name); 1412 } 1413 1414 void 1415 discard_nfs_args(void *nap, u_long nfs_version) 1416 { 1417 #ifdef HAVE_FS_NFS4 1418 if (nfs_version == NFS_VERSION4) 1419 discard_nfs4_args(nap); 1420 else 1421 #endif /* HAVE_FS_NFS4 */ 1422 discard_nfs23_args(nap); 1423 } 1424 1425 #ifdef DEBUG 1426 void 1427 print_nfs_args(const void *nap, u_long nfs_version) 1428 { 1429 #ifdef HAVE_FS_NFS4 1430 if (nfs_version == NFS_VERSION4) 1431 print_nfs4_args(nap, nfs_version); 1432 else 1433 #endif /* HAVE_FS_NFS4 */ 1434 print_nfs23_args(nap, nfs_version); 1435 } 1436 #endif 1437 1438 1439 /* 1440 * Fill in special values for flags and fields of nfs_args, for an 1441 * automounter NFS mount. 1442 */ 1443 void 1444 compute_automounter_nfs_args(nfs_args_t *nap, mntent_t *mntp) 1445 { 1446 struct nfs_common_args a; 1447 1448 #ifdef MNT2_NFS_OPT_SYMTTL 1449 /* 1450 * Don't let the kernel cache symbolic links we generate, or else lookups 1451 * will bypass amd and fail to remount stuff as needed. 1452 */ 1453 plog(XLOG_INFO, "turning on NFS option symttl and setting value to 0"); 1454 nap->flags |= MNT2_NFS_OPT_SYMTTL; 1455 nap->symttl = 0; 1456 #endif /* MNT2_NFS_OPT_SYMTTL */ 1457 1458 /* 1459 * This completes the flags for the HIDE_MOUNT_TYPE code in the 1460 * mount_amfs_toplvl() function in amd/amfs_toplvl.c. 1461 * Some systems don't have a mount type, but a mount flag. 1462 */ 1463 #ifdef MNT2_NFS_OPT_AUTO 1464 nap->flags |= MNT2_NFS_OPT_AUTO; 1465 #endif /* MNT2_NFS_OPT_AUTO */ 1466 #ifdef MNT2_NFS_OPT_IGNORE 1467 nap->flags |= MNT2_NFS_OPT_IGNORE; 1468 #endif /* MNT2_NFS_OPT_IGNORE */ 1469 #ifdef MNT2_GEN_OPT_AUTOMNTFS 1470 nap->flags |= MNT2_GEN_OPT_AUTOMNTFS; 1471 #endif /* not MNT2_GEN_OPT_AUTOMNTFS */ 1472 1473 #ifdef MNT2_NFS_OPT_DUMBTIMR 1474 /* 1475 * Don't let the kernel start computing throughput of Amd. The numbers 1476 * will be meaningless because of the way Amd does mount retries. 1477 */ 1478 plog(XLOG_INFO, "%s: disabling nfs congestion window", mntp->mnt_dir); 1479 nap->flags |= MNT2_NFS_OPT_DUMBTIMR; 1480 #endif /* MNT2_NFS_OPT_DUMBTIMR */ 1481 1482 /* compute all of the NFS attribute-cache flags */ 1483 memset(&a, 0, sizeof(a)); 1484 a.flags = nap->flags; 1485 compute_nfs_attrcache_flags(&a, mntp); 1486 get_nfs_common_args(nap, a); 1487 1488 /* 1489 * Provide a slight bit more security by requiring the kernel to use 1490 * reserved ports. 1491 */ 1492 #ifdef MNT2_NFS_OPT_RESVPORT 1493 nap->flags |= MNT2_NFS_OPT_RESVPORT; 1494 #endif /* MNT2_NFS_OPT_RESVPORT */ 1495 } 1496 1497 int 1498 nfs_valid_version(u_long v) 1499 { 1500 return v >= NFS_VERS_MIN && v <= NFS_VERS_MAX; 1501 } 1502