/* * Mount an automounter directory. * The automounter is connected into the system * as a user-level NFS server. mount_amfs_toplvl constructs * the necessary NFS parameters to be given to the * kernel so that it will talk back to us. * * NOTE: automounter mounts in themselves are using NFS Version 2. */ static int mount_amfs_toplvl(char *dir, char *opts) { char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1]; int retry, error, genflags; mntent_t mnt; nfs_args_t nfs_args; am_nfs_fh *fhp; am_nfs_handle_t anh; MTYPE_TYPE type = MOUNT_TYPE_NFS; #ifndef HAVE_TRANSPORT_TYPE_TLI u_short port; struct sockaddr_in sin; #endif /* not HAVE_TRANSPORT_TYPE_TLI */ memset((voidp) &mnt, 0, sizeof(mnt)); mnt.mnt_dir = dir; mnt.mnt_fsname = pid_fsname; mnt.mnt_opts = opts; /* * Make sure that amd's top-level NFS mounts are hidden by default * from df. * If they don't appear to support the either the "ignore" mnttab * option entry, or the "auto" one, set the mount type to "nfs". */ mnt.mnt_type = HIDE_MOUNT_TYPE; retry = hasmntval(&mnt, MNTTAB_OPT_RETRY); if (retry <= 0) retry = 2; /* XXX */ /* * SET MOUNT ARGS */ /* * get fhandle of remote path for automount point */ fhp = root_fh(dir); if (!fhp) { plog(XLOG_FATAL, "Can't find root file handle for %s", dir); return EINVAL; } #ifndef HAVE_TRANSPORT_TYPE_TLI /* * Create sockaddr to point to the local machine. 127.0.0.1 * is not used since that will not work in HP-UX clusters and * this is no more expensive. */ memset((voidp) &sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr = myipaddr; port = hasmntval(&mnt, MNTTAB_OPT_PORT); if (port) { sin.sin_port = htons(port); } else { plog(XLOG_ERROR, "no port number specified for %s", dir); return EINVAL; } #endif /* not HAVE_TRANSPORT_TYPE_TLI */ /* * Make a ``hostname'' string for the kernel */ sprintf(fs_hostname, "pid%ld@%s:%s", (long) (foreground ? am_mypid : getppid()), am_get_hostname(), dir); /* * Most kernels have a name length restriction (64 bytes)... */ if (strlen(fs_hostname) >= MAXHOSTNAMELEN) strcpy(fs_hostname + MAXHOSTNAMELEN - 3, ".."); #ifdef HOSTNAMESZ /* * ... and some of these restrictions are 32 bytes (HOSTNAMESZ) * If you need to get the definition for HOSTNAMESZ found, you may * add the proper header file to the conf/nfs_prot/nfs_prot_*.h file. */ if (strlen(fs_hostname) >= HOSTNAMESZ) strcpy(fs_hostname + HOSTNAMESZ - 3, ".."); #endif /* HOSTNAMESZ */ /* * Finally we can compute the mount genflags set above, * and add any automounter specific flags. */ genflags = compute_mount_flags(&mnt); genflags |= compute_automounter_mount_flags(&mnt); /* setup the many fields and flags within nfs_args */ memmove(&anh.v2.fhs_fh, fhp, sizeof(*fhp)); #ifdef HAVE_TRANSPORT_TYPE_TLI compute_nfs_args(&nfs_args, &mnt, genflags, nfsncp, NULL, /* remote host IP addr is set below */ NFS_VERSION, /* version 2 */ "udp", &anh, fs_hostname, pid_fsname); /* * IMPORTANT: set the correct IP address AFTERWARDS. It cannot * be done using the normal mechanism of compute_nfs_args(), because * that one will allocate a new address and use NFS_SA_DREF() to copy * parts to it, while assuming that the ip_addr passed is always * a "struct sockaddr_in". That assumption is incorrect on TLI systems, * because they define a special macro HOST_SELF which is DIFFERENT * than localhost (127.0.0.1)! */ nfs_args.addr = &nfsxprt->xp_ltaddr; #else /* not HAVE_TRANSPORT_TYPE_TLI */ compute_nfs_args(&nfs_args, &mnt, genflags, &sin, NFS_VERSION, /* version 2 */ "udp", &anh, fs_hostname, pid_fsname); #endif /* not HAVE_TRANSPORT_TYPE_TLI */ /************************************************************************* * NOTE: while compute_nfs_args() works ok for regular NFS mounts * * the toplvl one is not, and so some options must be corrected by hand * * more carefully, *after* compute_nfs_args() runs. * *************************************************************************/ compute_automounter_nfs_args(&nfs_args, &mnt); /* This is it! Here we try to mount amd on its mount points */ #ifdef DEBUG amuDebug(D_TRACE) { print_nfs_args(&nfs_args, 0); plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags); } #endif /* DEBUG */ error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name); #ifdef HAVE_TRANSPORT_TYPE_TLI free_knetconfig(nfs_args.knconf); /* * local automounter mounts do not allocate a special address, so * no need to XFREE(nfs_args.addr) under TLI. */ #endif /* HAVE_TRANSPORT_TYPE_TLI */ return error; }
/* * Mount an automounter directory. * The automounter is connected into the system * as a user-level NFS server. amfs_mount constructs * the necessary NFS parameters to be given to the * kernel so that it will talk back to us. * * NOTE: automounter mounts in themselves are using NFS Version 2 (UDP). * * NEW: on certain systems, mounting can be done using the * kernel-level automount (autofs) support. In that case, * we don't need NFS at all here. */ int amfs_mount(am_node *mp, mntfs *mf, char *opts) { char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1]; int retry, error = 0, genflags; int on_autofs = mf->mf_flags & MFF_ON_AUTOFS; char *dir = mf->mf_mount; mntent_t mnt; MTYPE_TYPE type; int forced_unmount = 0; /* are we using forced unmounts? */ u_long nfs_version = get_nfs_dispatcher_version(nfs_dispatcher); memset(&mnt, 0, sizeof(mnt)); mnt.mnt_dir = dir; mnt.mnt_fsname = pid_fsname; mnt.mnt_opts = opts; #ifdef HAVE_FS_AUTOFS if (mf->mf_flags & MFF_IS_AUTOFS) { type = MOUNT_TYPE_AUTOFS; /* * Make sure that amd's top-level autofs mounts are hidden by default * from df. * XXX: It works ok on Linux, might not work on other systems. */ mnt.mnt_type = "autofs"; } else #endif /* HAVE_FS_AUTOFS */ { type = MOUNT_TYPE_NFS; /* * Make sure that amd's top-level NFS mounts are hidden by default * from df. * If they don't appear to support the either the "ignore" mnttab * option entry, or the "auto" one, set the mount type to "nfs". */ mnt.mnt_type = HIDE_MOUNT_TYPE; } retry = hasmntval(&mnt, MNTTAB_OPT_RETRY); if (retry <= 0) retry = 2; /* XXX: default to 2 retries */ /* * SET MOUNT ARGS */ /* * Make a ``hostname'' string for the kernel */ xsnprintf(fs_hostname, sizeof(fs_hostname), "pid%ld@%s:%s", get_server_pid(), am_get_hostname(), dir); /* * Most kernels have a name length restriction (64 bytes)... */ if (strlen(fs_hostname) >= MAXHOSTNAMELEN) xstrlcpy(fs_hostname + MAXHOSTNAMELEN - 3, "..", sizeof(fs_hostname) - MAXHOSTNAMELEN + 3); #ifdef HOSTNAMESZ /* * ... and some of these restrictions are 32 bytes (HOSTNAMESZ) * If you need to get the definition for HOSTNAMESZ found, you may * add the proper header file to the conf/nfs_prot/nfs_prot_*.h file. */ if (strlen(fs_hostname) >= HOSTNAMESZ) xstrlcpy(fs_hostname + HOSTNAMESZ - 3, "..", sizeof(fs_hostname) - HOSTNAMESZ + 3); #endif /* HOSTNAMESZ */ /* * Finally we can compute the mount genflags set above, * and add any automounter specific flags. */ genflags = compute_mount_flags(&mnt); #ifdef HAVE_FS_AUTOFS if (on_autofs) genflags |= autofs_compute_mount_flags(&mnt); #endif /* HAVE_FS_AUTOFS */ genflags |= compute_automounter_mount_flags(&mnt); again: if (!(mf->mf_flags & MFF_IS_AUTOFS)) { nfs_args_t nfs_args; am_nfs_handle_t *fhp, anh; #ifndef HAVE_TRANSPORT_TYPE_TLI u_short port; struct sockaddr_in sin; #endif /* not HAVE_TRANSPORT_TYPE_TLI */ /* * get fhandle of remote path for automount point */ fhp = get_root_nfs_fh(dir, &anh); if (!fhp) { plog(XLOG_FATAL, "Can't find root file handle for %s", dir); return EINVAL; } #ifndef HAVE_TRANSPORT_TYPE_TLI /* * Create sockaddr to point to the local machine. */ memset(&sin, 0, sizeof(sin)); /* as per POSIX, sin_len need not be set (used internally by kernel) */ sin.sin_family = AF_INET; sin.sin_addr = myipaddr; port = hasmntval(&mnt, MNTTAB_OPT_PORT); if (port) { sin.sin_port = htons(port); } else { plog(XLOG_ERROR, "no port number specified for %s", dir); return EINVAL; } #endif /* not HAVE_TRANSPORT_TYPE_TLI */ /* setup the many fields and flags within nfs_args */ #ifdef HAVE_TRANSPORT_TYPE_TLI compute_nfs_args(&nfs_args, &mnt, genflags, nfsncp, NULL, /* remote host IP addr is set below */ nfs_version, "udp", fhp, fs_hostname, pid_fsname); /* * IMPORTANT: set the correct IP address AFTERWARDS. It cannot * be done using the normal mechanism of compute_nfs_args(), because * that one will allocate a new address and use NFS_SA_DREF() to copy * parts to it, while assuming that the ip_addr passed is always * a "struct sockaddr_in". That assumption is incorrect on TLI systems, * because they define a special macro HOST_SELF which is DIFFERENT * than localhost (127.0.0.1)! */ nfs_args.addr = &nfsxprt->xp_ltaddr; #else /* not HAVE_TRANSPORT_TYPE_TLI */ compute_nfs_args(&nfs_args, &mnt, genflags, NULL, &sin, nfs_version, "udp", fhp, fs_hostname, pid_fsname); #endif /* not HAVE_TRANSPORT_TYPE_TLI */ /************************************************************************* * NOTE: while compute_nfs_args() works ok for regular NFS mounts * * the toplvl one is not quite regular, and so some options must be * * corrected by hand more carefully, *after* compute_nfs_args() runs. * *************************************************************************/ compute_automounter_nfs_args(&nfs_args, &mnt); if (amuDebug(D_TRACE)) { print_nfs_args(&nfs_args, 0); plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags); } /* This is it! Here we try to mount amd on its mount points */ error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name, on_autofs); #ifdef HAVE_TRANSPORT_TYPE_TLI free_knetconfig(nfs_args.knconf); /* * local automounter mounts do not allocate a special address, so * no need to XFREE(nfs_args.addr) under TLI. */ #endif /* HAVE_TRANSPORT_TYPE_TLI */ #ifdef HAVE_FS_AUTOFS } else { /* This is it! Here we try to mount amd on its mount points */ error = mount_fs(&mnt, genflags, (caddr_t) mp->am_autofs_fh, retry, type, 0, NULL, mnttab_file_name, on_autofs); #endif /* HAVE_FS_AUTOFS */ } if (error == 0 || forced_unmount) return error; /* * If user wants forced/lazy unmount semantics, then try it iff the * current mount failed with EIO or ESTALE. */ if (gopt.flags & CFM_FORCED_UNMOUNTS) { switch (errno) { case ESTALE: case EIO: forced_unmount = errno; plog(XLOG_WARNING, "Mount %s failed (%m); force unmount.", mp->am_path); if ((error = UMOUNT_FS(mp->am_path, mnttab_file_name, AMU_UMOUNT_FORCE | AMU_UMOUNT_DETACH)) < 0) { plog(XLOG_WARNING, "Forced umount %s failed: %m.", mp->am_path); errno = forced_unmount; } else goto again; default: break; } } return error; }