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