/* * Copyright (c) 1997-1999 Erez Zadok * Copyright (c) 1990 Jan-Simon Pendry * Copyright (c) 1990 Imperial College of Science, Technology & Medicine * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Jan-Simon Pendry at Imperial College, London. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgment: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * %W% (Berkeley) %G% * * $Id: amfs_toplvl.c,v 1.5 1999/02/04 07:24:14 ezk Exp $ * */ /* * Top-level file system */ #ifdef HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include /**************************************************************************** *** FORWARD DEFINITIONS *** ****************************************************************************/ /**************************************************************************** *** OPS STRUCTURES *** ****************************************************************************/ am_ops amfs_toplvl_ops = { "toplvl", amfs_auto_match, 0, /* amfs_auto_init */ amfs_toplvl_mount, 0, amfs_toplvl_umount, 0, amfs_auto_lookuppn, amfs_auto_readdir, /* browsable version of readdir() */ 0, /* amfs_toplvl_readlink */ amfs_toplvl_mounted, 0, /* amfs_toplvl_umounted */ find_amfs_auto_srvr, FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO | FS_DIRECTORY }; /**************************************************************************** *** FUNCTIONS *** ****************************************************************************/ /* * 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 the top-level */ int amfs_toplvl_mount(am_node *mp) { mntfs *mf = mp->am_mnt; struct stat stb; char opts[256], preopts[256]; int error; char *mnttype; /* * Mounting the automounter. * Make sure the mount directory exists, construct * the mount options and call the mount_amfs_toplvl routine. */ if (stat(mp->am_path, &stb) < 0) { return errno; } else if ((stb.st_mode & S_IFMT) != S_IFDIR) { plog(XLOG_WARNING, "%s is not a directory", mp->am_path); return ENOTDIR; } if (mf->mf_ops == &amfs_toplvl_ops) mnttype = "indirect"; else if (mf->mf_ops == &amfs_direct_ops) mnttype = "direct"; #ifdef HAVE_AM_FS_UNION else if (mf->mf_ops == &amfs_union_ops) mnttype = "union"; #endif /* HAVE_AM_FS_UNION */ else mnttype = "auto"; /* * Construct some mount options: * * Tack on magic map= option in mtab to emulate * SunOS automounter behavior. */ preopts[0] = '\0'; #ifdef MNTTAB_OPT_INTR strcat(preopts, MNTTAB_OPT_INTR); strcat(preopts, ","); #endif /* MNTTAB_OPT_INTR */ #ifdef MNTTAB_OPT_IGNORE strcat(preopts, MNTTAB_OPT_IGNORE); strcat(preopts, ","); #endif /* MNTTAB_OPT_IGNORE */ sprintf(opts, "%s%s,%s=%d,%s=%d,%s=%d,%s,map=%s", preopts, MNTTAB_OPT_RW, MNTTAB_OPT_PORT, nfs_port, MNTTAB_OPT_TIMEO, gopt.amfs_auto_timeo, MNTTAB_OPT_RETRANS, gopt.amfs_auto_retrans, mnttype, mf->mf_info); /* now do the mount */ error = mount_amfs_toplvl(mf->mf_mount, opts); if (error) { errno = error; plog(XLOG_FATAL, "mount_amfs_toplvl: %m"); return error; } return 0; } void amfs_toplvl_mounted(mntfs *mf) { amfs_auto_mkcacheref(mf); } /* * Unmount a top-level automount node */ int amfs_toplvl_umount(am_node *mp) { int error; struct stat stb; again: /* * The lstat is needed if this mount is type=direct. * When that happens, the kernel cache gets confused * between the underlying type (dir) and the mounted * type (link) and so needs to be re-synced before * the unmount. This is all because the unmount system * call follows links and so can't actually unmount * a link (stupid!). It was noted that doing an ls -ld * of the mount point to see why things were not working * actually fixed the problem - so simulate an ls -ld here. */ if (lstat(mp->am_path, &stb) < 0) { #ifdef DEBUG dlog("lstat(%s): %m", mp->am_path); #endif /* DEBUG */ } error = UMOUNT_FS(mp->am_path, mnttab_file_name); if (error == EBUSY) { plog(XLOG_WARNING, "amfs_toplvl_unmount retrying %s in 1s", mp->am_path); sleep(1); /* XXX */ goto again; } return error; }