diff options
Diffstat (limited to 'contrib/amd/amd/restart.c')
-rw-r--r-- | contrib/amd/amd/restart.c | 312 |
1 files changed, 196 insertions, 116 deletions
diff --git a/contrib/amd/amd/restart.c b/contrib/amd/amd/restart.c index 59902f6..4f71e38 100644 --- a/contrib/amd/amd/restart.c +++ b/contrib/amd/amd/restart.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2004 Erez Zadok + * Copyright (c) 1997-2006 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. @@ -36,9 +36,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * %W% (Berkeley) %G% * - * $Id: restart.c,v 1.3.2.4 2004/01/06 03:15:16 ezk Exp $ + * File: am-utils/amd/restart.c * */ @@ -49,14 +48,81 @@ #include <amd.h> +static void +restart_fake_mntfs(mntent_t *me, am_ops *fs_ops) +{ + mntfs *mf; + am_opts mo; + char *cp; + + /* + * Partially fake up an opts structure + */ + memset(&mo, 0, sizeof(mo)); + mo.opt_rhost = 0; + mo.opt_rfs = 0; + cp = strchr(me->mnt_fsname, ':'); + if (cp) { + *cp = '\0'; + mo.opt_rhost = strdup(me->mnt_fsname); + mo.opt_rfs = strdup(cp + 1); + *cp = ':'; + } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) { + /* + * Hacky workaround for mnttab NFS entries that only list the server + */ + plog(XLOG_WARNING, "NFS server entry assumed to be %s:/", me->mnt_fsname); + mo.opt_rhost = strdup(me->mnt_fsname); + mo.opt_rfs = strdup("/"); + me->mnt_fsname = str3cat(me->mnt_fsname, mo.opt_rhost, ":", "/"); + } + mo.opt_fs = me->mnt_dir; + mo.opt_opts = me->mnt_opts; + + /* + * Make a new mounted filesystem + */ + mf = find_mntfs(fs_ops, &mo, me->mnt_dir, + me->mnt_fsname, "", me->mnt_opts, ""); + if (mf->mf_refc == 1) { + mf->mf_flags |= MFF_RESTART | MFF_MOUNTED; + mf->mf_error = 0; /* Already mounted correctly */ + mf->mf_fo = 0; + /* + * Only timeout non-NFS entries + */ + if (!STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) + mf->mf_flags |= MFF_RSTKEEP; + if (fs_ops->fs_init) { + /* + * Don't care whether this worked since + * it is checked again when the fs is + * inherited. + */ + (void) (*fs_ops->fs_init) (mf); + } + plog(XLOG_INFO, "%s restarted fstype %s on %s, flags 0x%x", + me->mnt_fsname, fs_ops->fs_type, me->mnt_dir, mf->mf_flags); + } else { + /* Something strange happened - two mounts at the same place! */ + free_mntfs(mf); + } + /* + * Clean up mo + */ + if (mo.opt_rhost) + XFREE(mo.opt_rhost); + if (mo.opt_rfs) + XFREE(mo.opt_rfs); +} + + /* * Handle an amd restart. * * Scan through the mount list finding all "interesting" mount points. * Next hack up partial data structures and add the mounted file - * system to the list of known filesystems. This will leave a - * dangling reference to that filesystems, so when the filesystem is - * finally inherited, an extra "free" must be done on it. + * system to the list of known filesystems. * * This module relies on internal details of other components. If * you change something else make *sure* restart() still works. @@ -64,26 +130,19 @@ void restart(void) { - /* - * Read the existing mount table - */ mntlist *ml, *mlp; /* - * For each entry, find nfs, ufs or auto mounts - * and create a partial am_node to represent it. + * Read the existing mount table. For each entry, find nfs, ufs or auto + * mounts and create a partial am_node to represent it. */ for (mlp = ml = read_mtab("restart", mnttab_file_name); mlp; mlp = mlp->mnext) { mntent_t *me = mlp->mnt; am_ops *fs_ops = 0; - if (STREQ(me->mnt_type, MNTTAB_TYPE_UFS)) { - /* - * UFS entry - */ - fs_ops = &ufs_ops; - } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) { + + if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) { /* * NFS entry, or possibly an Amd entry... * The mnt_fsname for daemon mount points is @@ -92,117 +151,138 @@ restart(void) * host:daemon(pidXXX) */ char *colon = strchr(me->mnt_fsname, ':'); + if (colon && strstr(colon, "(pid")) + continue; + } - if (colon && strstr(colon, "(pid")) { - plog(XLOG_WARNING, "%s is an existing automount point", me->mnt_dir); - fs_ops = &amfs_link_ops; - } else { - fs_ops = &nfs_ops; - } -#ifdef MNTTAB_TYPE_NFS3 - } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS3)) { - fs_ops = &nfs_ops; -#endif /* MNTTAB_TYPE_NFS3 */ -#ifdef MNTTAB_TYPE_LOFS - } else if (STREQ(me->mnt_type, MNTTAB_TYPE_LOFS)) { - fs_ops = &lofs_ops; -#endif /* MNTTAB_TYPE_LOFS */ -#ifdef MNTTAB_TYPE_CDFS - } else if (STREQ(me->mnt_type, MNTTAB_TYPE_CDFS)) { - fs_ops = &cdfs_ops; -#endif /* MNTTAB_TYPE_CDFS */ -#ifdef MNTTAB_TYPE_PCFS - } else if (STREQ(me->mnt_type, MNTTAB_TYPE_PCFS)) { - fs_ops = &pcfs_ops; -#endif /* MNTTAB_TYPE_PCFS */ -#ifdef MNTTAB_TYPE_MFS - } else if (STREQ(me->mnt_type, MNTTAB_TYPE_MFS)) { - /* - * MFS entry. Fake with a symlink. - */ - fs_ops = &amfs_link_ops; -#endif /* MNTTAB_TYPE_MFS */ - } else { - /* - * Catch everything else with symlinks to - * avoid recursive mounts. This is debatable... - */ + /* Search for the correct filesystem ops */ + fs_ops = ops_search(me->mnt_type); + + /* + * Catch everything else with symlinks to + * avoid recursive mounts. This is debatable... + */ + if (!fs_ops) fs_ops = &amfs_link_ops; + + restart_fake_mntfs(me, fs_ops); + } + + /* + * Free the mount list + */ + free_mntlist(ml); +} + + +/* + * Handle an amd restart for amd's own mount points. + * + * Scan through the mount list finding all daemon mount points + * (determined by the presence of a pid inside the mount info). + * Next hack up partial data structures and add the mounted file + * system to the list of known filesystems. + * + * This module relies on internal details of other components. If + * you change something else make *sure* restart() still works. + */ +void +restart_automounter_nodes(void) +{ + mntlist *ml, *mlp; + /* reasonably sized list of restarted nfs ports */ + u_short old_ports[256]; + + memset((voidp) &old_ports, 0, sizeof(u_short) * 256); + + /* + * Read the existing mount table. For each entry, find nfs, ufs or auto + * mounts and create a partial am_node to represent it. + */ + for (mlp = ml = read_mtab("restart", mnttab_file_name); + mlp; + mlp = mlp->mnext) { + mntent_t *me = mlp->mnt; + am_ops *fs_ops = 0; + char *colon; + long pid; + u_short port; + int err; + + if (!STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) + continue; /* to next mlp */ + /* + * NFS entry, or possibly an Amd entry... + * The mnt_fsname for daemon mount points is + * host:(pidXXX) + * or (seen on Solaris) + * host:daemon(pidXXX) + */ + colon = strchr(me->mnt_fsname, ':'); + if (!colon || !strstr(colon, "(pid")) + continue; + /* if got here, then we matched an existing Amd mount point */ + err = 1; + + plog(XLOG_WARNING, "%s is an existing automount point", me->mnt_dir); + + /* Is the old automounter still alive? */ + if (sscanf(colon, "%*[^(](pid%ld%*[,)]", &pid) != 1) { + plog(XLOG_WARNING, "Can't parse pid in %s", me->mnt_fsname); + goto give_up; + } + if (kill(pid, 0) != -1 || errno != ESRCH) { + plog(XLOG_WARNING, "Automounter (pid: %ld) still alive", pid); + goto give_up; } /* - * If we found something to do + * Do we have a map for this mount point? Who cares, we'll restart + * anyway -- getting ESTALE is way better than hanging. */ - if (fs_ops) { - mntfs *mf; - am_opts mo; - char *cp; - cp = strchr(me->mnt_fsname, ':'); - /* - * Partially fake up an opts structure - */ - mo.opt_rhost = 0; - mo.opt_rfs = 0; - if (cp) { - *cp = '\0'; - mo.opt_rhost = strdup(me->mnt_fsname); - mo.opt_rfs = strdup(cp + 1); - *cp = ':'; - } else if (fs_ops->ffserver == find_nfs_srvr) { - /* - * Prototype 4.4 BSD used to end up here - - * might as well keep the workaround for now - */ - plog(XLOG_WARNING, "NFS server entry assumed to be %s:/", me->mnt_fsname); - mo.opt_rhost = strdup(me->mnt_fsname); - mo.opt_rfs = strdup("/"); - me->mnt_fsname = str3cat(me->mnt_fsname, mo.opt_rhost, ":", "/"); + /* Can we restart it? Only if it tells us what port it was using... */ + if (sscanf(colon, "%*[^,],port%hu)", &port) != 1) { + plog(XLOG_WARNING, "No port specified for %s", me->mnt_fsname); + goto give_up; + } + + /* Maybe we already own that port... */ + if (port != nfs_port) { + int i; + for (i = 0; i < 256; i++) { + if (old_ports[i] == port || + old_ports[i] == 0) + break; + } + if (i == 256) { + plog(XLOG_WARNING, "Too many open ports (256)"); + goto give_up; } - mo.opt_fs = me->mnt_dir; - mo.opt_opts = me->mnt_opts; - /* - * Make a new mounted filesystem - */ - mf = find_mntfs(fs_ops, &mo, me->mnt_dir, - me->mnt_fsname, "", me->mnt_opts, ""); - if (mf->mf_refc == 1) { - mf->mf_flags |= MFF_RESTART | MFF_MOUNTED; - mf->mf_error = 0; /* Already mounted correctly */ - mf->mf_fo = 0; - /* - * If the restarted type is a link then - * don't time out. - */ - if (fs_ops == &amfs_link_ops || fs_ops == &ufs_ops) - mf->mf_flags |= MFF_RSTKEEP; - if (fs_ops->fs_init) { - /* - * Don't care whether this worked since - * it is checked again when the fs is - * inherited. - */ - (void) (*fs_ops->fs_init) (mf); + if (old_ports[i] == 0) { + int soNFS; + SVCXPRT *nfsxprt; + if (create_nfs_service(&soNFS, &port, &nfsxprt, nfs_program_2) != 0) { + plog(XLOG_WARNING, "Can't bind to port %u", port); + goto give_up; } - plog(XLOG_INFO, "%s restarted fstype %s on %s", - me->mnt_fsname, fs_ops->fs_type, me->mnt_dir); - } else { - /* Something strange happened - two mounts at the same place! */ - free_mntfs(mf); + old_ports[i] = nfs_port = port; } - /* - * Clean up mo - */ - if (mo.opt_rhost) - XFREE(mo.opt_rhost); - if (mo.opt_rfs) - XFREE(mo.opt_rfs); } - } + err = 0; - /* - * Free the mount list - */ + give_up: + if (err) { + plog(XLOG_WARNING, "Can't restart %s, leaving it alone", me->mnt_dir); + fs_ops = &amfs_link_ops; + } else { + fs_ops = &amfs_toplvl_ops; + } + + restart_fake_mntfs(me, fs_ops); + } /* end of "for (mlp" */ + + /* free the mount list */ free_mntlist(ml); } |