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 */ 57struct 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 */ 141int 142compute_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 */ 166int 167compute_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 */ 187static void 188addvers(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 201int 202mount_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 224again: 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 */ 371static void 372compute_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 491static void 492compute_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 650static void 651print_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 668static void 669discard_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 */ 680static char * 681get_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 709static void 710print_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 */ 724static void 725print_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 */ 850static void 851compute_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 1073struct { 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 1089static char * 1090set_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 1130static int 1131get_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 1148static void 1149add_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 1183static void 1184print_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 1215static void 1216discard_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 */ 1244static void 1245compute_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 1359static void 1360print_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 1387void 1388compute_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 1409void 1410discard_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 1421void 1422print_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 */ 1438void 1439compute_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 1492int 1493nfs_valid_version(u_long v) 1494{ 1495 return v >= NFS_VERS_MIN && v <= NFS_VERS_MAX; 1496} 1497