diff --git a/dist/am-utils/amd/ops_autofs.c b/dist/am-utils/amd/ops_autofs.c deleted file mode 100644 index 393e6bf4a8e7..000000000000 --- a/dist/am-utils/amd/ops_autofs.c +++ /dev/null @@ -1,1281 +0,0 @@ -/* $NetBSD: ops_autofs.c,v 1.1.1.4 2001/05/13 17:50:14 veego Exp $ */ - -/* - * Copyright (c) 1997-2001 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: ops_autofs.c,v 1.7.2.4 2001/04/24 06:17:40 ib42 Exp - * - */ - -/* - * Automounter filesystem - */ - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ -#include -#include - -/* - * KLUDGE: wrap whole file in HAVE_FS_AUTOFS, because - * not all systems with an automounter file system are supported - * by am-utils yet... - */ - -#ifdef HAVE_FS_AUTOFS - -/* - * MACROS: - */ -#ifndef AUTOFS_NULL -# define AUTOFS_NULL ((u_long)0) -#endif /* not AUTOFS_NULL */ - -/* - * VARIABLES: - */ - -/* forward declarations */ -static int mount_autofs(char *dir, char *opts); -static int autofs_mount_1_svc(struct mntrequest *mr, struct mntres *result, struct authunix_parms *cred); -static int autofs_unmount_1_svc(struct umntrequest *ur, struct umntres *result, struct authunix_parms *cred); - -/* external declarations */ -extern bool_t xdr_mntrequest(XDR *, mntrequest *); -extern bool_t xdr_mntres(XDR *, mntres *); -extern bool_t xdr_umntrequest(XDR *, umntrequest *); -extern bool_t xdr_umntres(XDR *, umntres *); - -/* - * STRUCTURES: - */ - -/* Sun's kernel-based automounter-supporting file system */ -am_ops autofs_ops = -{ - "autofs", - amfs_auto_match, - 0, /* amfs_auto_init */ - autofs_mount, - 0, - autofs_umount, - 0, - amfs_auto_lookuppn, - amfs_auto_readdir, /* browsable version of readdir() */ - 0, /* autofs_readlink */ - autofs_mounted, - 0, /* autofs_umounted */ - find_amfs_auto_srvr, - FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO | FS_DIRECTORY -}; - - -/**************************************************************************** - *** FUNCTIONS *** - ****************************************************************************/ - -/* - * Mount the top-level using autofs - */ -int -autofs_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_autofs 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 == &autofs_ops) - mnttype = "indirect"; - else if (mf->mf_ops == &amfs_direct_ops) - mnttype = "direct"; -#ifdef HAVE_AMU_FS_UNION - else if (mf->mf_ops == &amfs_union_ops) - mnttype = "union"; -#endif /* HAVE_AMU_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_autofs(mf->mf_mount, opts); - if (error) { - errno = error; - plog(XLOG_FATAL, "mount_autofs: %m"); - return error; - } - return 0; -} - - -void -autofs_mounted(mntfs *mf) -{ - amfs_auto_mkcacheref(mf); -} - - -/* - * Unmount a top-level automount node - */ -int -autofs_umount(am_node *mp) -{ - int error; - struct stat stb; - - /* - * 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 && mp->am_flags & AMF_AUTOFS) { - plog(XLOG_WARNING, "autofs_unmount of %s busy (autofs). exit", mp->am_path); - error = 0; /* fake unmount was ok */ - } - return error; -} - - -/* - * Mount an automounter directory. - * The automounter is connected into the system - * as a user-level NFS server. mount_autofs constructs - * the necessary NFS parameters to be given to the - * kernel so that it will talk back to us. - */ -static int -mount_autofs(char *dir, char *opts) -{ - char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1]; - char *map_opt, buf[MAXHOSTNAMELEN]; - int retry, error, flags; - struct utsname utsname; - mntent_t mnt; - autofs_args_t autofs_args; - MTYPE_TYPE type = MOUNT_TYPE_AUTOFS; - - memset((voidp) &autofs_args, 0, sizeof(autofs_args)); /* Paranoid */ - - memset((voidp) &mnt, 0, sizeof(mnt)); - mnt.mnt_dir = dir; - mnt.mnt_fsname = pid_fsname; - mnt.mnt_opts = opts; - mnt.mnt_type = type; - - retry = hasmntval(&mnt, "retry"); - if (retry <= 0) - retry = 2; /* XXX */ - - /* - * SET MOUNT ARGS - */ - if (uname(&utsname) < 0) { - strcpy(buf, "localhost.autofs"); - } else { - strcpy(buf, utsname.nodename); - strcat(buf, ".autofs"); - } -#ifdef HAVE_FIELD_AUTOFS_ARGS_T_ADDR - autofs_args.addr.buf = buf; - autofs_args.addr.len = strlen(autofs_args.addr.buf); - autofs_args.addr.maxlen = autofs_args.addr.len; -#endif /* HAVE_FIELD_AUTOFS_ARGS_T_ADDR */ - - autofs_args.path = dir; - autofs_args.opts = opts; - - map_opt = hasmntopt(&mnt, "map"); - if (map_opt) { - map_opt += sizeof("map="); /* skip the "map=" */ - if (map_opt == NULL) { - plog(XLOG_WARNING, "map= has a null map name. reset to amd.unknown"); - map_opt = "amd.unknown"; - } - } - autofs_args.map = map_opt; - - /* XXX: these I set arbitrarily... */ - autofs_args.mount_to = 300; - autofs_args.rpc_to = 60; - autofs_args.direct = 0; - - /* - * 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. - */ - if (strlen(fs_hostname) >= MAXHOSTNAMELEN) - strcpy(fs_hostname + MAXHOSTNAMELEN - 3, ".."); - - /* - * Finally we can compute the mount flags set above. - */ - flags = compute_mount_flags(&mnt); - - /* - * This is it! Here we try to mount amd on its mount points. - */ - error = mount_fs(&mnt, flags, (caddr_t) &autofs_args, retry, type, 0, NULL, mnttab_file_name); - return error; -} - - -/****************************************************************************/ -/* autofs program dispatcher */ -void -autofs_program_1(struct svc_req *rqstp, SVCXPRT *transp) -{ - int ret; - union { - mntrequest autofs_mount_1_arg; - umntrequest autofs_umount_1_arg; - } argument; - union { - mntres mount_res; - umntres umount_res; - } result; - - bool_t (*xdr_argument)(), (*xdr_result)(); - int (*local)(); - - switch (rqstp->rq_proc) { - - case AUTOFS_NULL: - svc_sendreply(transp, - (XDRPROC_T_TYPE) xdr_void, - (SVC_IN_ARG_TYPE) NULL); - return; - - case AUTOFS_MOUNT: - xdr_argument = xdr_mntrequest; - xdr_result = xdr_mntres; - local = (int (*)()) autofs_mount_1_svc; - break; - - case AUTOFS_UNMOUNT: - xdr_argument = xdr_umntrequest; - xdr_result = xdr_umntres; - local = (int (*)()) autofs_unmount_1_svc; - break; - - default: - svcerr_noproc(transp); - return; - } - - memset((char *) &argument, 0, sizeof(argument)); - if (!svc_getargs(transp, - (XDRPROC_T_TYPE) xdr_argument, - (SVC_IN_ARG_TYPE) &argument)) { - plog(XLOG_ERROR, - "AUTOFS xdr decode failed for %d %d %d", - (int) rqstp->rq_prog, (int) rqstp->rq_vers, (int) rqstp->rq_proc); - svcerr_decode(transp); - return; - } - - ret = (*local) (&argument, &result, rqstp); - if (!svc_sendreply(transp, - (XDRPROC_T_TYPE) xdr_result, - (SVC_IN_ARG_TYPE) &result)) { - svcerr_systemerr(transp); - } - - if (!svc_freeargs(transp, - (XDRPROC_T_TYPE) xdr_argument, - (SVC_IN_ARG_TYPE) &argument)) { - plog(XLOG_FATAL, "unable to free rpc arguments in autofs_program_1"); - going_down(1); - } -} - - -static int -autofs_mount_1_svc(struct mntrequest *mr, struct mntres *result, struct authunix_parms *cred) -{ - int err = 0; - am_node *anp, *anp2; - - plog(XLOG_INFO, "XXX: autofs_mount_1_svc: %s:%s:%s:%s", - mr->map, mr->name, mr->opts, mr->path); - - /* look for map (eg. "/home") */ - anp = find_ap(mr->path); - if (!anp) { - plog(XLOG_ERROR, "map %s not found", mr->path); - err = ENOENT; - goto out; - } - /* turn on autofs in map flags */ - if (!(anp->am_flags & AMF_AUTOFS)) { - plog(XLOG_INFO, "turning on AMF_AUTOFS for node %s", mr->path); - anp->am_flags |= AMF_AUTOFS; - } - - /* - * Look for (and create if needed) the new node. - * - * If an error occurred, return it. If a -1 was returned, that indicates - * that a mount is in progress, so sleep a while (while the backgrounded - * mount is happening), and then signal the autofs to retry the mount. - * - * There's something I don't understand. I was thinking that this code - * here is the one which will succeed eventually and will send an RPC - * reply to the kernel, but apparently that happens somewhere else, not - * here. It works though, just that I don't know how. Arg. -Erez. - * */ - err = 0; - anp2 = autofs_lookuppn(anp, mr->name, &err, VLOOK_CREATE); - if (!anp2) { - if (err == -1) { /* then tell autofs to retry */ - sleep(1); - err = EAGAIN; - } - goto out; - } - -out: - result->status = err; - return err; -} - - -static int -autofs_unmount_1_svc(struct umntrequest *ur, struct umntres *result, struct authunix_parms *cred) -{ - int err = 0; - -#ifdef HAVE_FIELD_UMNTREQUEST_RDEVID - plog(XLOG_INFO, "XXX: autofs_unmount_1_svc: %d:%lu:%lu:0x%lx", - ur->isdirect, (unsigned long) ur->devid, (unsigned long) ur->rdevid, - (unsigned long) ur->next); -#else /* HAVE_FIELD_UMNTREQUEST_RDEVID */ - plog(XLOG_INFO, "XXX: autofs_unmount_1_svc: %d:%lu:0x%lx", - ur->isdirect, (unsigned long) ur->devid, - (unsigned long) ur->next); -#endif /* HAVE_FIELD_UMNTREQUEST_RDEVID */ - - err = EINVAL; /* XXX: not implemented yet */ - goto out; - -out: - result->status = err; - return err; -} - - -/* - * Pick a file system to try mounting and - * do that in the background if necessary - * - For each location: - if it is new -defaults then - extract and process - continue; - fi - if it is a cut then - if a location has been tried then - break; - fi - continue; - fi - parse mount location - discard previous mount location if required - find matching mounted filesystem - if not applicable then - this_error = No such file or directory - continue - fi - if the filesystem failed to be mounted then - this_error = error from filesystem - elif the filesystem is mounting or unmounting then - this_error = -1 - elif the fileserver is down then - this_error = -1 - elif the filesystem is already mounted - this_error = 0 - break - fi - if no error on this mount then - this_error = initialize mount point - fi - if no error on this mount and mount is delayed then - this_error = -1 - fi - if this_error < 0 then - retry = true - fi - if no error on this mount then - make mount point if required - fi - if no error on this mount then - if mount in background then - run mount in background - return -1 - else - this_error = mount in foreground - fi - fi - if an error occurred on this mount then - update stats - save error in mount point - fi - endfor - */ -static int -autofs_bgmount(struct continuation *cp, int mpe) -{ - mntfs *mf = cp->mp->am_mnt; /* Current mntfs */ - mntfs *mf_retry = 0; /* First mntfs which needed retrying */ - int this_error = -1; /* Per-mount error */ - int hard_error = -1; - int mp_error = mpe; - - /* - * Try to mount each location. - * At the end: - * hard_error == 0 indicates something was mounted. - * hard_error > 0 indicates everything failed with a hard error - * hard_error < 0 indicates nothing could be mounted now - */ - for (; this_error && *cp->ivec; cp->ivec++) { - am_ops *p; - am_node *mp = cp->mp; - char *link_dir; - int dont_retry; - - if (hard_error < 0) - hard_error = this_error; - - this_error = -1; - - if (**cp->ivec == '-') { - /* - * Pick up new defaults - */ - if (cp->auto_opts && *cp->auto_opts) - cp->def_opts = str3cat(cp->def_opts, cp->auto_opts, ";", *cp->ivec + 1); - else - cp->def_opts = strealloc(cp->def_opts, *cp->ivec + 1); -#ifdef DEBUG - dlog("Setting def_opts to \"%s\"", cp->def_opts); -#endif /* DEBUG */ - continue; - } - /* - * If a mount has been attempted, and we find - * a cut then don't try any more locations. - */ - if (STREQ(*cp->ivec, "/") || STREQ(*cp->ivec, "||")) { - if (cp->tried) { -#ifdef DEBUG - dlog("Cut: not trying any more locations for %s", - mp->am_path); -#endif /* DEBUG */ - break; - } - continue; - } - - /* match the operators */ - p = ops_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info); - - /* - * Find a mounted filesystem for this node. - */ - mp->am_mnt = mf = realloc_mntfs(mf, p, &cp->fs_opts, - cp->fs_opts.opt_fs, - cp->fs_opts.fs_mtab, - cp->auto_opts, - cp->fs_opts.opt_opts, - cp->fs_opts.opt_remopts); - - p = mf->mf_ops; -#ifdef DEBUG - dlog("Got a hit with %s", p->fs_type); -#endif /* DEBUG */ - - /* - * Note whether this is a real mount attempt - */ - if (p == &amfs_error_ops) { - plog(XLOG_MAP, "Map entry %s for %s did not match", *cp->ivec, mp->am_path); - if (this_error <= 0) - this_error = ENOENT; - continue; - } else { - if (cp->fs_opts.fs_mtab) { - plog(XLOG_MAP, "Trying mount of %s on \"%s\" fstype %s", - cp->fs_opts.fs_mtab, mp->am_path, p->fs_type); - } - cp->tried = TRUE; - } - - this_error = 0; - dont_retry = FALSE; - - if (mp->am_link) { - XFREE(mp->am_link); - mp->am_link = 0; - } - link_dir = mf->mf_fo->opt_sublink; - - if (link_dir && *link_dir) { - if (*link_dir == '/') { - mp->am_link = strdup(link_dir); - } else { - /* - * try getting fs option from continuation, not mountpoint! - * Don't try logging the string from mf, since it may be bad! - */ - if (cp->fs_opts.opt_fs != mf->mf_fo->opt_fs) - plog(XLOG_ERROR, "use %s instead of 0x%lx", - cp->fs_opts.opt_fs, (unsigned long) mf->mf_fo->opt_fs); - - mp->am_link = str3cat((char *) 0, - cp->fs_opts.opt_fs, "/", link_dir); - - normalize_slash(mp->am_link); - } - } - - if (mf->mf_error > 0) { - this_error = mf->mf_error; - } else if (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)) { - /* - * Still mounting - retry later - */ -#ifdef DEBUG - dlog("Duplicate pending mount fstype %s", p->fs_type); -#endif /* DEBUG */ - this_error = -1; - } else if (FSRV_ISDOWN(mf->mf_server)) { - /* - * Would just mount from the same place - * as a hung mount - so give up - */ -#ifdef DEBUG - dlog("%s is already hung - giving up", mf->mf_mount); -#endif /* DEBUG */ - mp_error = EWOULDBLOCK; - dont_retry = TRUE; - this_error = -1; - } else if (mf->mf_flags & MFF_MOUNTED) { -#ifdef DEBUG - dlog("duplicate mount of \"%s\" ...", mf->mf_info); -#endif /* DEBUG */ - - /* - * Just call mounted() - */ - am_mounted(mp); - - this_error = 0; - break; - } - - /* - * Will usually need to play around with the mount nodes - * file attribute structure. This must be done here. - * Try and get things initialized, even if the fileserver - * is not known to be up. In the common case this will - * progress things faster. - */ - if (!this_error) { - /* - * Fill in attribute fields. - */ - if (mf->mf_ops->fs_flags & FS_DIRECTORY) - mk_fattr(mp, NFDIR); - else - mk_fattr(mp, NFLNK); - - if (p->fs_init) - this_error = (*p->fs_init) (mf); - } - - /* - * Make sure the fileserver is UP before doing any more work - */ - if (!FSRV_ISUP(mf->mf_server)) { -#ifdef DEBUG - dlog("waiting for server %s to become available", mf->mf_server->fs_host); -#endif /* DEBUG */ - this_error = -1; - } - - if (!this_error && mf->mf_fo->opt_delay) { - /* - * If there is a delay timer on the mount - * then don't try to mount if the timer - * has not expired. - */ - int i = atoi(mf->mf_fo->opt_delay); - if (i > 0 && clocktime() < (cp->start + i)) { -#ifdef DEBUG - dlog("Mount of %s delayed by %lds", mf->mf_mount, i - clocktime() + cp->start); -#endif /* DEBUG */ - this_error = -1; - } - } - - if (this_error < 0 && !dont_retry) { - if (!mf_retry) - mf_retry = dup_mntfs(mf); - cp->retry = TRUE; - } - - if (!this_error) { - if (p->fs_flags & FS_MBACKGROUND) { - mf->mf_flags |= MFF_MOUNTING; /* XXX */ -#ifdef DEBUG - dlog("backgrounding mount of \"%s\"", mf->mf_mount); -#endif /* DEBUG */ - if (cp->callout) { - untimeout(cp->callout); - cp->callout = 0; - } - run_task(try_mount, (voidp) mp, amfs_auto_cont, (voidp) cp); - mf->mf_flags |= MFF_MKMNT; /* XXX */ - if (mf_retry) - free_mntfs(mf_retry); - return -1; - } else { -#ifdef DEBUG - dlog("foreground mount of \"%s\" ...", mf->mf_info); -#endif /* DEBUG */ - this_error = try_mount((voidp) mp); - if (this_error < 0) { - if (!mf_retry) - mf_retry = dup_mntfs(mf); - cp->retry = TRUE; - } - } - } - - if (this_error >= 0) { - if (this_error > 0) { - amd_stats.d_merr++; - if (mf != mf_retry) { - mf->mf_error = this_error; - mf->mf_flags |= MFF_ERROR; - } - } - - /* - * Wakeup anything waiting for this mount - */ - wakeup((voidp) mf); - } - } - - if (this_error && cp->retry) { - free_mntfs(mf); - mf = cp->mp->am_mnt = mf_retry; - /* - * Not retrying again (so far) - */ - cp->retry = FALSE; - cp->tried = FALSE; - /* - * Start at the beginning. - * Rewind the location vector and - * reset the default options. - */ - cp->ivec = cp->xivec; - cp->def_opts = strealloc(cp->def_opts, cp->auto_opts); - /* - * Arrange that autofs_bgmount is called - * after anything else happens. - */ -#ifdef DEBUG - dlog("Arranging to retry mount of %s", cp->mp->am_path); -#endif /* DEBUG */ - sched_task(amfs_auto_retry, (voidp) cp, (voidp) mf); - if (cp->callout) - untimeout(cp->callout); - cp->callout = timeout(RETRY_INTERVAL, wakeup, (voidp) mf); - - cp->mp->am_ttl = clocktime() + RETRY_INTERVAL; - - /* - * Not done yet - so don't return anything - */ - return -1; - } - - if (hard_error < 0 || this_error == 0) - hard_error = this_error; - - /* - * Discard handle on duff filesystem. - * This should never happen since it - * should be caught by the case above. - */ - if (mf_retry) { - if (hard_error) - plog(XLOG_ERROR, "discarding a retry mntfs for %s", mf_retry->mf_mount); - free_mntfs(mf_retry); - } - - /* - * If we get here, then either the mount succeeded or - * there is no more mount information available. - */ - if (hard_error < 0 && mp_error) - hard_error = cp->mp->am_error = mp_error; - if (hard_error > 0) { - /* - * Set a small(ish) timeout on an error node if - * the error was not a time out. - */ - switch (hard_error) { - case ETIMEDOUT: - case EWOULDBLOCK: - cp->mp->am_timeo = 17; - break; - default: - cp->mp->am_timeo = 5; - break; - } - new_ttl(cp->mp); - } - - /* - * Make sure that the error value in the mntfs has a - * reasonable value. - */ - if (mf->mf_error < 0) { - mf->mf_error = hard_error; - if (hard_error) - mf->mf_flags |= MFF_ERROR; - } - - /* - * In any case we don't need the continuation any more - */ - free_continuation(cp); - - return hard_error; -} - - -/* - * Automount interface to RPC lookup routine - * Find the corresponding entry and return - * the file handle for it. - */ -am_node * -autofs_lookuppn(am_node *mp, char *fname, int *error_return, int op) -{ - am_node *ap, *new_mp, *ap_hung; - char *info; /* Mount info - where to get the file system */ - char **ivec, **xivec; /* Split version of info */ - char *auto_opts; /* Automount options */ - int error = 0; /* Error so far */ - char path_name[MAXPATHLEN]; /* General path name buffer */ - char apath[MAXPATHLEN]; /* autofs path (added space) */ - char *pfname; /* Path for database lookup */ - struct continuation *cp; /* Continuation structure if need to mount */ - int in_progress = 0; /* # of (un)mount in progress */ - char *dflts; - mntfs *mf; - -#ifdef DEBUG - dlog("in autofs_lookuppn"); -#endif /* DEBUG */ - - /* - * If the server is shutting down - * then don't return information - * about the mount point. - */ - if (amd_state == Finishing) { -#ifdef DEBUG - if ((mf = mp->am_mnt) == 0 || mf->mf_ops == &amfs_direct_ops) { - dlog("%s mount ignored - going down", fname); - } else { - dlog("%s/%s mount ignored - going down", mp->am_path, fname); - } -#endif /* DEBUG */ - ereturn(ENOENT); - } - - /* - * Handle special case of "." and ".." - */ - if (fname[0] == '.') { - if (fname[1] == '\0') - return mp; /* "." is the current node */ - if (fname[1] == '.' && fname[2] == '\0') { - if (mp->am_parent) { -#ifdef DEBUG - dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path); -#endif /* DEBUG */ - return mp->am_parent; /* ".." is the parent node */ - } - ereturn(ESTALE); - } - } - - /* - * Check for valid key name. - * If it is invalid then pretend it doesn't exist. - */ - if (!valid_key(fname)) { - plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname); - ereturn(ENOENT); - } - - /* - * Expand key name. - * fname is now a private copy. - */ - fname = expand_key(fname); - - for (ap_hung = 0, ap = mp->am_child; ap; ap = ap->am_osib) { - /* - * Otherwise search children of this node - */ - if (FSTREQ(ap->am_name, fname)) { - mf = ap->am_mnt; - if (ap->am_error) { - error = ap->am_error; - continue; - } - /* - * If the error code is undefined then it must be - * in progress. - */ - if (mf->mf_error < 0) - goto in_progrss; - - /* - * Check for a hung node - */ - if (FSRV_ISDOWN(mf->mf_server)) { -#ifdef DEBUG - dlog("server hung"); -#endif /* DEBUG */ - error = ap->am_error; - ap_hung = ap; - continue; - } - /* - * If there was a previous error with this node - * then return that error code. - */ - if (mf->mf_flags & MFF_ERROR) { - error = mf->mf_error; - continue; - } - if (!(mf->mf_flags & MFF_MOUNTED) || (mf->mf_flags & MFF_UNMOUNTING)) { - in_progrss: - /* - * If the fs is not mounted or it is unmounting then there - * is a background (un)mount in progress. In this case - * we just drop the RPC request (return nil) and - * wait for a retry, by which time the (un)mount may - * have completed. - */ -#ifdef DEBUG - dlog("ignoring mount of %s in %s -- flags (%x) in progress", - fname, mf->mf_mount, mf->mf_flags); -#endif /* DEBUG */ - in_progress++; - continue; - } - - /* - * Otherwise we have a hit: return the current mount point. - */ -#ifdef DEBUG - dlog("matched %s in %s", fname, ap->am_path); -#endif /* DEBUG */ - XFREE(fname); - return ap; - } - } - - if (in_progress) { -#ifdef DEBUG - dlog("Waiting while %d mount(s) in progress", in_progress); -#endif /* DEBUG */ - XFREE(fname); - ereturn(-1); - } - - /* - * If an error occurred then return it. - */ - if (error) { -#ifdef DEBUG - errno = error; /* XXX */ - dlog("Returning error: %m"); -#endif /* DEBUG */ - XFREE(fname); - ereturn(error); - } - - /* - * If doing a delete then don't create again! - */ - switch (op) { - case VLOOK_DELETE: - ereturn(ENOENT); - - case VLOOK_CREATE: - break; - - default: - plog(XLOG_FATAL, "Unknown op to autofs_lookuppn: 0x%x", op); - ereturn(EINVAL); - } - - /* - * If the server is going down then just return, - * don't try to mount any more file systems - */ - if ((int) amd_state >= (int) Finishing) { -#ifdef DEBUG - dlog("not found - server going down anyway"); -#endif /* DEBUG */ - XFREE(fname); - ereturn(ENOENT); - } - - /* - * If we get there then this is a reference to an, - * as yet, unknown name so we need to search the mount - * map for it. - */ - if (mp->am_pref) { - sprintf(path_name, "%s%s", mp->am_pref, fname); - pfname = path_name; - } else { - pfname = fname; - } - - mf = mp->am_mnt; - -#ifdef DEBUG - dlog("will search map info in %s to find %s", mf->mf_info, pfname); -#endif /* DEBUG */ - /* - * Consult the oracle for some mount information. - * info is malloc'ed and belongs to this routine. - * It ends up being free'd in free_continuation(). - * - * Note that this may return -1 indicating that information - * is not yet available. - */ - error = mapc_search((mnt_map *) mf->mf_private, pfname, &info); - if (error) { - if (error > 0) - plog(XLOG_MAP, "No map entry for %s", pfname); - else - plog(XLOG_MAP, "Waiting on map entry for %s", pfname); - XFREE(fname); - ereturn(error); - } -#ifdef DEBUG - dlog("mount info is %s", info); -#endif /* DEBUG */ - - /* - * Split info into an argument vector. - * The vector is malloc'ed and belongs to - * this routine. It is free'd in free_continuation() - */ - xivec = ivec = strsplit(info, ' ', '\"'); - - /* - * Default error code... - */ - if (ap_hung) - error = EWOULDBLOCK; - else - error = ENOENT; - - /* - * Allocate a new map - */ - new_mp = exported_ap_alloc(); - if (new_mp == 0) { - XFREE(xivec); - XFREE(info); - XFREE(fname); - ereturn(ENOSPC); - } - if (mf->mf_auto) - auto_opts = mf->mf_auto; - else - auto_opts = ""; - - auto_opts = strdup(auto_opts); - -#ifdef DEBUG - dlog("searching for /defaults entry"); -#endif /* DEBUG */ - if (mapc_search((mnt_map *) mf->mf_private, "/defaults", &dflts) == 0) { - char *dfl; - char **rvec; -#ifdef DEBUG - dlog("/defaults gave %s", dflts); -#endif /* DEBUG */ - if (*dflts == '-') - dfl = dflts + 1; - else - dfl = dflts; - - /* - * Chop the defaults up - */ - rvec = strsplit(dfl, ' ', '\"'); - - if (gopt.flags & CFM_SELECTORS_IN_DEFAULTS) { - /* - * Pick whichever first entry matched the list of selectors. - * Strip the selectors from the string, and assign to dfl the - * rest of the string. - */ - if (rvec) { - am_opts ap; - am_ops *pt; - char **sp = rvec; - while (*sp) { /* loop until you find something, if any */ - memset((char *) &ap, 0, sizeof(am_opts)); - pt = ops_match(&ap, *sp, "", mp->am_path, "/defaults", - mp->am_parent->am_mnt->mf_info); - free_opts(&ap); /* don't leak */ - if (pt == &amfs_error_ops) { - plog(XLOG_MAP, "did not match defaults for \"%s\"", *sp); - } else { - dfl = strip_selectors(*sp, "/defaults"); - plog(XLOG_MAP, "matched default selectors \"%s\"", dfl); - break; - } - ++sp; - } - } - } else { /* not selectors_in_defaults */ - /* - * Extract first value - */ - dfl = rvec[0]; - } - - /* - * If there were any values at all... - */ - if (dfl) { - /* - * Log error if there were other values - */ - if (!(gopt.flags & CFM_SELECTORS_IN_DEFAULTS) && rvec[1]) { -# ifdef DEBUG - dlog("/defaults chopped into %s", dfl); -# endif /* DEBUG */ - plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info); - } - - /* - * Prepend to existing defaults if they exist, - * otherwise just use these defaults. - */ - if (*auto_opts && *dfl) { - char *nopts = (char *) xmalloc(strlen(auto_opts) + strlen(dfl) + 2); - sprintf(nopts, "%s;%s", dfl, auto_opts); - XFREE(auto_opts); - auto_opts = nopts; - } else if (*dfl) { - auto_opts = strealloc(auto_opts, dfl); - } - } - XFREE(dflts); - /* - * Don't need info vector any more - */ - XFREE(rvec); - } - - /* - * Fill it in - */ - init_map(new_mp, fname); - - /* - * Turn on autofs flag if needed. - */ - if (mp->am_flags & AMF_AUTOFS) { - new_mp->am_flags |= AMF_AUTOFS; - } - - /* - * Put it in the table - */ - insert_am(new_mp, mp); - - /* - * Fill in some other fields, - * path and mount point. - * - * bugfix: do not prepend old am_path if direct map - * William Sebok - */ - - strcpy(apath, fname); - strcat(apath, " "); - new_mp->am_path = str3cat(new_mp->am_path, - mf->mf_ops == &amfs_direct_ops ? "" : mp->am_path, - *fname == '/' ? "" : "/", - apath); - -#ifdef DEBUG - dlog("setting path to \"%s\"", new_mp->am_path); -#endif /* DEBUG */ - - /* - * Take private copy of pfname - */ - pfname = strdup(pfname); - - /* - * Construct a continuation - */ - cp = ALLOC(struct continuation); - cp->callout = 0; - cp->mp = new_mp; - cp->xivec = xivec; - cp->ivec = ivec; - cp->info = info; - cp->key = pfname; - cp->auto_opts = auto_opts; - cp->retry = FALSE; - cp->tried = FALSE; - cp->start = clocktime(); - cp->def_opts = strdup(auto_opts); - memset((voidp) &cp->fs_opts, 0, sizeof(cp->fs_opts)); - - /* - * Try and mount the file system. If this succeeds immediately (possible - * for a ufs file system) then return the attributes, otherwise just - * return an error. - */ - error = autofs_bgmount(cp, error); - reschedule_timeout_mp(); - if (!error) { - XFREE(fname); - return new_mp; - } - - /* - * Code for quick reply. If nfs_program_2_transp is set, then - * its the transp that's been passed down from nfs_program_2(). - * If new_mp->am_transp is not already set, set it by copying in - * nfs_program_2_transp. Once am_transp is set, quick_reply() can - * use it to send a reply to the client that requested this mount. - */ - if (nfs_program_2_transp && !new_mp->am_transp) { - new_mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT)); - *(new_mp->am_transp) = *nfs_program_2_transp; - } - if (error && (new_mp->am_mnt->mf_ops == &amfs_error_ops)) - new_mp->am_error = error; - - assign_error_mntfs(new_mp); - - XFREE(fname); - - ereturn(error); -} -#endif /* HAVE_FS_AUTOFS */