BSD 4_4 release
[unix-history] / usr / src / usr.sbin / amd / amd / host_ops.c
index dfe8763..ba0dedb 100644 (file)
@@ -1,29 +1,44 @@
 /*
 /*
- * $Id: host_ops.c,v 5.2 90/06/23 22:19:26 jsp Rel $
- *
  * Copyright (c) 1990 Jan-Simon Pendry
  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
  * 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.
+ * Copyright (c) 1990, 1993
+ *     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.
  *
  *
  * 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 are permitted provided
- * that: (1) source distributions retain this entire copyright notice and
- * comment, and (2) distributions including binaries display the following
- * acknowledgement:  ``This product includes software developed by the
- * University of California, Berkeley and its contributors'' in the
- * documentation or other materials provided with the distribution and in
- * all advertising materials mentioning features or use of this software.
- * 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 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 acknowledgement:
+ *     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.
+ *
+ *     @(#)host_ops.c  8.1 (Berkeley) 6/6/93
+ *
+ * $Id: host_ops.c,v 5.2.2.2 1992/05/31 16:36:08 jsp Exp $
  *
  *
- *     @(#)host_ops.c  5.1 (Berkeley) 6/29/90
  */
 
 #include "am.h"
  */
 
 #include "am.h"
 #include <sys/stat.h>
 
 /*
 #include <sys/stat.h>
 
 /*
- * NFS host file system
+ * NFS host file system.
+ * Mounts all exported filesystems from a given host.
+ * This has now degenerated into a mess but will not
+ * be rewritten.  Amd 6 will support the abstractions
+ * needed to make this work correctly.
  */
 
 /*
  * Define HOST_RPC_UDP to use dgram instead of stream RPC.
  * Datagrams are generally much faster.
  */
  */
 
 /*
  * Define HOST_RPC_UDP to use dgram instead of stream RPC.
  * Datagrams are generally much faster.
  */
-#define        HOST_RPC_UDP
+/*#define      HOST_RPC_UDP*/
 
 /*
  * Define HOST_MKDIRS to make Amd automatically try
 
 /*
  * Define HOST_MKDIRS to make Amd automatically try
  */
 #define HOST_MKDIRS
 
  */
 #define HOST_MKDIRS
 
+/*
+ * Determine the mount point
+ */
+#define MAKE_MNTPT(mntpt, ex, mf) { \
+                       if (strcmp((ex)->ex_dir, "/") == 0) \
+                               strcpy((mntpt), (mf)->mf_mount); \
+                       else \
+                               sprintf((mntpt), "%s%s", (mf)->mf_mount, (ex)->ex_dir); \
+}
+
 /*
  * Execute needs the same as NFS plus a helper command
  */
 /*
  * Execute needs the same as NFS plus a helper command
  */
-static int host_match(fo)
+static char *host_match P((am_opts *fo));
+static char *host_match(fo)
 am_opts *fo;
 {
 #ifdef HOST_EXEC
 am_opts *fo;
 {
 #ifdef HOST_EXEC
@@ -68,10 +98,8 @@ am_opts *fo;
        if (!fo->opt_rfs)
                fo->opt_rfs = "/";
 
        if (!fo->opt_rfs)
                fo->opt_rfs = "/";
 
-       if (!(*nfs_ops.fs_match)(fo))
-               return FALSE;
-
-       return TRUE;
+       
+       return (*nfs_ops.fs_match)(fo);
 }
 
 static int host_init(mf)
 }
 
 static int host_init(mf)
@@ -104,6 +132,7 @@ caddr_t args_ptr;
        return ((*xdr_args)(&xdr, args_ptr));
 }
 
        return ((*xdr_args)(&xdr, args_ptr));
 }
 
+static int do_mount P((fhstatus *fhp, char *dir, char *fs_name, char *opts, mntfs *mf));
 static int do_mount(fhp, dir, fs_name, opts, mf)
 fhstatus *fhp;
 char *dir;
 static int do_mount(fhp, dir, fs_name, opts, mf)
 fhstatus *fhp;
 char *dir;
@@ -126,7 +155,8 @@ mntfs *mf;
        return mount_nfs_fh(fhp, dir, fs_name, opts, mf);
 }
 
        return mount_nfs_fh(fhp, dir, fs_name, opts, mf);
 }
 
-static sortfun(a, b)
+static int sortfun P((exports *a, exports *b));
+static int sortfun(a, b)
 exports *a,*b;
 {
        return strcmp((*a)->ex_dir, (*b)->ex_dir);
 exports *a,*b;
 {
        return strcmp((*a)->ex_dir, (*b)->ex_dir);
@@ -135,6 +165,7 @@ exports *a,*b;
 /*
  * Get filehandle
  */
 /*
  * Get filehandle
  */
+static int fetch_fhandle P((CLIENT *client, char *dir, fhstatus *fhp));
 static int fetch_fhandle(client, dir, fhp)
 CLIENT *client;
 char *dir;
 static int fetch_fhandle(client, dir, fhp)
 CLIENT *client;
 char *dir;
@@ -146,7 +177,7 @@ fhstatus *fhp;
        /*
         * Pick a number, any number...
         */
        /*
         * Pick a number, any number...
         */
-       tv.tv_sec = 10;
+       tv.tv_sec = 20;
        tv.tv_usec = 0;
 
 #ifdef DEBUG
        tv.tv_usec = 0;
 
 #ifdef DEBUG
@@ -176,31 +207,57 @@ fhstatus *fhp;
        return 0;
 }
 
        return 0;
 }
 
+/*
+ * Scan mount table to see if something already mounted
+ */
+static int already_mounted P((mntlist *mlist, char*dir));
+static int already_mounted(mlist, dir)
+mntlist *mlist;
+char *dir;
+{
+       mntlist *ml;
+
+       for (ml = mlist; ml; ml = ml->mnext)
+               if (strcmp(ml->mnt->mnt_dir, dir) == 0)
+                       return 1;
+       return 0;
+}
+
 /*
  * Mount the export tree from a host
  */
 /*
  * Mount the export tree from a host
  */
-static int host_mount(mp)
-am_node *mp;
+static int host_fmount P((mntfs *mf));
+static int host_fmount(mf)
+mntfs *mf;
 {
        struct timeval tv2;
        CLIENT *client;
        enum clnt_stat clnt_stat;
        int n_export;
 {
        struct timeval tv2;
        CLIENT *client;
        enum clnt_stat clnt_stat;
        int n_export;
-       int j;
+       int j, k;
        exports exlist = 0, ex;
        exports *ep = 0;
        fhstatus *fp = 0;
        exports exlist = 0, ex;
        exports *ep = 0;
        fhstatus *fp = 0;
-       mntfs *mf = mp->am_mnt;
        char *host = mf->mf_server->fs_host;
        int error = 0;
        struct sockaddr_in sin;
        int sock = RPC_ANYSOCK;
        int ok = FALSE;
        char *host = mf->mf_server->fs_host;
        int error = 0;
        struct sockaddr_in sin;
        int sock = RPC_ANYSOCK;
        int ok = FALSE;
-       
-#ifdef HOST_RPC_UDP
+       mntlist *mlist;
+       char fs_name[MAXPATHLEN], *rfs_dir;
+       char mntpt[MAXPATHLEN];
        struct timeval tv;
        tv.tv_sec = 10; tv.tv_usec = 0;
        struct timeval tv;
        tv.tv_sec = 10; tv.tv_usec = 0;
-#endif /* HOST_RPC_UDP */
+
+       /*
+        * Read the mount list
+        */
+       mlist = read_mtab(mf->mf_mount);
+
+       /*
+        * Unlock the mount list
+        */
+       unlock_mntlist();
 
        /*
         * Take a copy of the server address
 
        /*
         * Take a copy of the server address
@@ -212,25 +269,20 @@ am_node *mp;
         */
        sin.sin_port = 0;
        /*
         */
        sin.sin_port = 0;
        /*
-        * Make a client end-point
+        * Make a client end-point.
+        * Try TCP first
         */
         */
-#ifdef HOST_RPC_UDP
-       if ((client = clntudp_create(&sin, MOUNTPROG, MOUNTVERS, tv, &sock)) == NULL)
-#else
-       if ((client = clnttcp_create(&sin, MOUNTPROG, MOUNTVERS, &sock, 0, 0)) == NULL)
-#endif /* HOST_RPC_UDP */
-       {
+       if ((client = clnttcp_create(&sin, MOUNTPROG, MOUNTVERS, &sock, 0, 0)) == NULL &&
+               (client = clntudp_create(&sin, MOUNTPROG, MOUNTVERS, tv, &sock)) == NULL) {
                plog(XLOG_ERROR, "Failed to make rpc connection to mountd on %s", host);
                error = EIO;
                goto out;
        }
 
        if (!nfs_auth) {
                plog(XLOG_ERROR, "Failed to make rpc connection to mountd on %s", host);
                error = EIO;
                goto out;
        }
 
        if (!nfs_auth) {
-               nfs_auth = authunix_create_default();
-               if (!nfs_auth) {
-                       error = ENOBUFS;
+               error = make_nfs_auth();
+               if (error)
                        goto out;
                        goto out;
-               }
        }
 
        client->cl_auth = nfs_auth;
        }
 
        client->cl_auth = nfs_auth;
@@ -263,11 +315,16 @@ am_node *mp;
 
        /*
         * Allocate an array of pointers into the list
 
        /*
         * Allocate an array of pointers into the list
-        * so that they can be sorted.
+        * so that they can be sorted.  If the filesystem
+        * is already mounted then ignore it.
         */
        ep = (exports *) xmalloc(n_export * sizeof(exports));
         */
        ep = (exports *) xmalloc(n_export * sizeof(exports));
-       for (j = 0, ex = exlist; ex; ex = ex->ex_next, j++)
-               ep[j] = ex;
+       for (j = 0, ex = exlist; ex; ex = ex->ex_next) {
+               MAKE_MNTPT(mntpt, ex, mf);
+               if (!already_mounted(mlist, mntpt))
+                       ep[j++] = ex;
+       }
+       n_export = j;
 
        /*
         * Sort into order.
 
        /*
         * Sort into order.
@@ -287,9 +344,18 @@ am_node *mp;
         * If a fetch fails then just zero out the array
         * reference but discard the error.
         */
         * If a fetch fails then just zero out the array
         * reference but discard the error.
         */
-       for (j = 0; j < n_export; j++) {
-               if (error = fetch_fhandle(client, ep[j]->ex_dir, &fp[j]))
+       for (j = k = 0; j < n_export; j++) {
+               /* Check and avoid a duplicated export entry */
+               if (j > k && ep[k] && strcmp(ep[j]->ex_dir, ep[k]->ex_dir) == 0) {
+#ifdef DEBUG
+                       dlog("avoiding dup fhandle requested for %s", ep[j]->ex_dir);
+#endif
                        ep[j] = 0;
                        ep[j] = 0;
+               } else {
+                       k = j;
+                       if (error = fetch_fhandle(client, ep[j]->ex_dir, &fp[j]))
+                               ep[j] = 0;
+               }
        }
 
        /*
        }
 
        /*
@@ -298,18 +364,19 @@ am_node *mp;
         * error code 0 at the end.  If they all fail then return
         * the last error code.
         */
         * error code 0 at the end.  If they all fail then return
         * the last error code.
         */
+       strncpy(fs_name, mf->mf_info, sizeof(fs_name));
+       if ((rfs_dir = strchr(fs_name, ':')) == (char *) 0) {
+               plog(XLOG_FATAL, "host_fmount: mf_info has no colon");
+               error = EINVAL;
+               goto out;
+       }
+       ++rfs_dir;
        for (j = 0; j < n_export; j++) {
                ex = ep[j];
                if (ex) {
        for (j = 0; j < n_export; j++) {
                ex = ep[j];
                if (ex) {
-                       char fs_name[MAXPATHLEN];
-                       char mntpt[MAXPATHLEN];
-                       sprintf(fs_name, "%s:%s", host, ex->ex_dir);
-                       if (strcmp(ex->ex_dir, "/") == 0)
-                               strcpy(mntpt, mf->mf_mount);
-                       else
-                               sprintf(mntpt, "%s%s", mf->mf_mount, ex->ex_dir);
-                       error = do_mount(&fp[j], mntpt, fs_name, mf->mf_fo->opt_opts, mf);
-                       if (!error)
+                       strcpy(rfs_dir, ex->ex_dir);
+                       MAKE_MNTPT(mntpt, ex, mf);
+                       if (do_mount(&fp[j], mntpt, fs_name, mf->mf_mopts, mf) == 0)
                                ok = TRUE;
                }
        }
                                ok = TRUE;
                }
        }
@@ -318,6 +385,7 @@ am_node *mp;
         * Clean up and exit
         */
 out:
         * Clean up and exit
         */
 out:
+       discard_mntlist(mlist);
        if (ep)
                free(ep);
        if (fp)
        if (ep)
                free(ep);
        if (fp)
@@ -337,6 +405,7 @@ out:
  * TODO:
  * Does not work if pref is "/".
  */
  * TODO:
  * Does not work if pref is "/".
  */
+static int directory_prefix P((char *pref, char *dir));
 static int directory_prefix(pref, dir)
 char *pref;
 char *dir;
 static int directory_prefix(pref, dir)
 char *pref;
 char *dir;
@@ -352,10 +421,10 @@ char *dir;
 /*
  * Unmount a mount tree
  */
 /*
  * Unmount a mount tree
  */
-static int host_umount(mp)
-am_node *mp;
+static int host_fumount P((mntfs *mf));
+static int host_fumount(mf)
+mntfs *mf;
 {
 {
-       mntfs *mf = mp->am_mnt;
        mntlist *ml, *mprev;
        int xerror = 0;
 
        mntlist *ml, *mprev;
        int xerror = 0;
 
@@ -385,7 +454,7 @@ am_node *mp;
        /*
         * Unmount all filesystems...
         */
        /*
         * Unmount all filesystems...
         */
-       for (ml = mlist; ml; ml = ml->mnext) {
+       for (ml = mlist; ml && !xerror; ml = ml->mnext) {
                char *dir = ml->mnt->mnt_dir;
                if (directory_prefix(mf->mf_mount, dir)) {
                        int error;
                char *dir = ml->mnt->mnt_dir;
                if (directory_prefix(mf->mf_mount, dir)) {
                        int error;
@@ -419,11 +488,92 @@ am_node *mp;
         */
        discard_mntlist(mlist);
 
         */
        discard_mntlist(mlist);
 
+       /*
+        * Try to remount, except when we are shutting down.
+        */
+       if (xerror && amd_state != Finishing) {
+               xerror = host_fmount(mf);
+               if (!xerror) {
+                       /*
+                        * Don't log this - it's usually too verbose
+                       plog(XLOG_INFO, "Remounted host %s", mf->mf_info);
+                        */
+                       xerror = EBUSY;
+               }
+       }
        return xerror;
 }
 
        return xerror;
 }
 
+/*
+ * Tell mountd we're done.
+ * This is not quite right, because we may still
+ * have other filesystems mounted, but the existing
+ * mountd protocol is badly broken anyway.
+ */
+static void host_umounted(mp)
+am_node *mp;
+{
+#ifdef INFORM_MOUNTD
+       mntfs *mf = mp->am_mnt;
+       char *host;
+       CLIENT *client;
+       enum clnt_stat clnt_stat;
+       struct sockaddr_in sin;
+       int sock = RPC_ANYSOCK;
+       struct timeval tv;
+       tv.tv_sec = 10; tv.tv_usec = 0;
+
+       if (mf->mf_error || mf->mf_refc > 1 || ! mf->mf_server)
+               return;
+
+       host = mf->mf_server->fs_host;
+       sin = *mf->mf_server->fs_ip;
+
+       /*
+        * Zero out the port - make sure we recompute
+        */
+       sin.sin_port = 0;
+       /*
+        * Make a client end-point.
+        * Try TCP first
+        */
+       if ((client = clnttcp_create(&sin, MOUNTPROG, MOUNTVERS, &sock, 0, 0)) == NULL &&
+               (client = clntudp_create(&sin, MOUNTPROG, MOUNTVERS, tv, &sock)) == NULL) {
+               plog(XLOG_ERROR, "Failed to make rpc connection to mountd on %s", host);
+               goto out;
+       }
+
+       if (!nfs_auth) {
+               if (make_nfs_auth())
+                       goto out;
+       }
+
+       client->cl_auth = nfs_auth;
+
+#ifdef DEBUG
+       dlog("Unmounting all from %s", host);
+#endif /* DEBUG */
+
+       clnt_stat = clnt_call(client, MOUNTPROC_UMNTALL, xdr_void, 0, xdr_void, 0, tv);
+       if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_SYSTEMERROR) {
+               /* RPC_SYSTEMERROR seems to be returned for no good reason ...*/
+               extern char *clnt_sperrno();
+               char *msg = clnt_sperrno(clnt_stat);
+               plog(XLOG_ERROR, "unmount all from %s rpc failed: %s", host, msg, clnt_stat);
+               goto out;
+       }
+
+out:
+       if (client)
+               clnt_destroy(client);
+
+#endif /* INFORM_MOUNTD */
+}
+
+
 #else /* HOST_EXEC */
 
 #else /* HOST_EXEC */
 
+static int host_exec P((char*op, char*host, char*fs, char*opts));
 static int host_exec(op, host, fs, opts)
 char *op;
 char *host;
 static int host_exec(op, host, fs, opts)
 char *op;
 char *host;
@@ -484,14 +634,16 @@ char *opts;
        return error;
 }
 
        return error;
 }
 
+static int host_mount P((am_node *mp));
 static int host_mount(mp)
 am_node *mp;
 {
        mntfs *mf = mp->am_mnt;
 
 static int host_mount(mp)
 am_node *mp;
 {
        mntfs *mf = mp->am_mnt;
 
-       return host_exec("mount", mf->mf_server->fs_host, mf->mf_mount, mf->mf_fo->opt_opts);
+       return host_exec("mount", mf->mf_server->fs_host, mf->mf_mount, mf->mf_opts);
 }
 
 }
 
+static int host_umount P((am_node *mp));
 static int host_umount(mp)
 am_node *mp;
 {
 static int host_umount(mp)
 am_node *mp;
 {
@@ -509,13 +661,19 @@ am_ops host_ops = {
        "host",
        host_match,
        host_init,
        "host",
        host_match,
        host_init,
-       host_mount,
-       host_umount,
+       auto_fmount,
+       host_fmount,
+       auto_fumount,
+       host_fumount,
        efs_lookuppn,
        efs_readdir,
        0, /* host_readlink */
        0, /* host_mounted */
        efs_lookuppn,
        efs_readdir,
        0, /* host_readlink */
        0, /* host_mounted */
+#ifdef HOST_EXEC
        0, /* host_umounted */
        0, /* host_umounted */
+#else
+       host_umounted,
+#endif
        find_nfs_srvr,
        FS_MKMNT|FS_BACKGROUND|FS_AMQINFO
 };
        find_nfs_srvr,
        FS_MKMNT|FS_BACKGROUND|FS_AMQINFO
 };