new "mountpoint" export option.
authorneilbrown <neilbrown>
Fri, 30 May 2003 05:16:52 +0000 (05:16 +0000)
committerneilbrown <neilbrown>
Fri, 30 May 2003 05:16:52 +0000 (05:16 +0000)
12 files changed:
ChangeLog
support/export/export.c
support/include/misc.h
support/include/nfslib.h
support/misc/Makefile
support/misc/mountpoint.c [new file with mode: 0644]
support/nfs/exports.c
utils/exportfs/Makefile
utils/exportfs/exportfs.c
utils/exportfs/exports.man
utils/mountd/cache.c
utils/mountd/mountd.c

index 60fd487..414a526 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2003-05-30  NeilBrown <neilb@cse.unsw.edu.au>
+
+       * support/export/export.c, support/include/nfslib.h,
+       support/nfs/export.c, utils/exportfs/exportfs.c,
+       utils/mountd/mountd.c: new export option "mountpoint"
+       If no path is given, then the export point must be a
+       mount point, or it won't be exported.  If a path is 
+       given (e.g. mountpoint=/path) then that path must be
+       a mountpoint or the exportpoint won't be exported.
+       * utils/exportfs/exportfs.man: document mountpoint option.
+       * support/misc/mountpoint.c: New file with is_mountpoint()
+       to determine if something is a mountpoint.
 2003-05-23  NeilBrown <neilb@cse.unsw.edu.au>
 
        * utils/mountd/cache.c(cache_get_filehandle): take a separate path
index ba0d095..eef2c3b 100644 (file)
@@ -239,6 +239,8 @@ export_freeall(void)
                                xfree(exp->m_export.e_squids);
                        if (exp->m_export.e_sqgids)
                                xfree(exp->m_export.e_sqgids);
+                       if (exp->m_export.e_mountpoint)
+                               free(exp->m_export.e_mountpoint);
                        xfree(exp);
                }
                exportlist[i] = NULL;
index 7d099d0..9a1b25d 100644 (file)
@@ -22,4 +22,6 @@ struct hostent        *hostent_dup(struct hostent *hp);
 struct hostent *get_hostent (const char *addr, int len, int type);
 struct hostent *get_reliable_hostbyaddr(const char *addr, int len, int type);
 
+extern int is_mountpoint(char *path);
+
 #endif /* MISC_H */
index 5864305..c41f92e 100644 (file)
@@ -73,6 +73,7 @@ struct exportent {
        int *           e_sqgids;
        int             e_nsqgids;
        int             e_fsid;
+       char *          e_mountpoint;
 };
 
 struct rmtabent {
index b2f73f8..c738564 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 LIBNAME        = libmisc.a
-OBJS   = tcpwrapper.o from_local.o
+OBJS   = tcpwrapper.o from_local.o mountpoint.o
 
 include $(TOP)rules.mk
 
diff --git a/support/misc/mountpoint.c b/support/misc/mountpoint.c
new file mode 100644 (file)
index 0000000..6d0f34e
--- /dev/null
@@ -0,0 +1,34 @@
+
+/*
+ * check if a given path is a mountpoint 
+ */
+
+#include <string.h>
+#include <malloc.h>
+#include <sys/stat.h>
+
+int
+is_mountpoint(char *path)
+{
+       /* Check if 'path' is a current mountpoint.
+        * Possibly we should also check it is the mountpoint of the 
+        * filesystem holding the target directory, but there doesn't
+        * seem a lot of point.
+        *
+        * We deem it to be a mountpoint if appending a ".." gives a different
+        * device or the same inode number.
+        */
+       char *dotdot;
+       struct stat stb, pstb;
+
+       dotdot = malloc(strlen(path)+4);
+       strcat(strcpy(dotdot, path), "/..");
+       if (lstat(path, &stb) != 0 ||
+           lstat(dotdot, &pstb) != 0)
+               return 0;
+
+       if (stb.st_dev != pstb.st_dev
+           || stb.st_ino == pstb.st_ino)
+               return 1;
+       return 0;
+}
index dfb241e..4d8665c 100644 (file)
@@ -91,6 +91,7 @@ getexportent(int fromkernel, int fromexports)
        ee.e_anongid = -2;
        ee.e_squids = NULL;
        ee.e_sqgids = NULL;
+       ee.e_mountpoint = NULL;
        ee.e_nsquids = 0;
        ee.e_nsqgids = 0;
 
@@ -187,6 +188,10 @@ putexportent(struct exportent *ep)
        if (ep->e_flags & NFSEXP_FSID) {
                fprintf(fp, "fsid=%d,", ep->e_fsid);
        }
+       if (ep->e_mountpoint)
+               fprintf(fp, "mountpoint%s%s,",
+                       ep->e_mountpoint[0]?"=":"", ep->e_mountpoint);
+
        fprintf(fp, "mapping=");
        switch (ep->e_maptype) {
        case CLE_MAP_IDENT:
@@ -247,6 +252,8 @@ dupexportent(struct exportent *dst, struct exportent *src)
                dst->e_sqgids = (int *) xmalloc(n * sizeof(int));
                memcpy(dst->e_sqgids, src->e_sqgids, n * sizeof(int));
        }
+       if (src->e_mountpoint)
+               dst->e_mountpoint = strdup(src->e_mountpoint);
 }
 
 struct exportent *
@@ -260,6 +267,7 @@ mkexportent(char *hname, char *path, char *options)
        ee.e_anongid = -2;
        ee.e_squids = NULL;
        ee.e_sqgids = NULL;
+       ee.e_mountpoint = NULL;
        ee.e_nsquids = 0;
        ee.e_nsqgids = 0;
 
@@ -408,6 +416,15 @@ bad_option:
                                goto bad_option;
                        }
                        ep->e_flags |= NFSEXP_FSID;
+               } else if (strcmp(opt, "mountpoint")==0 ||
+                          strcmp(opt, "mp") == 0 ||
+                          strncmp(opt, "mountpoint=", 11)==0 ||
+                          strncmp(opt, "mp=", 3) == 0) {
+                       char * mp = strchr(opt, '=');
+                       if (mp)
+                               ep->e_mountpoint = strdup(mp+1);
+                       else
+                               ep->e_mountpoint = strdup("");
                } else {
                        xlog(L_ERROR, "%s:%d: unknown keyword \"%s\"\n",
                                        flname, flline, opt);
index 851a294..8cd7029 100644 (file)
@@ -5,7 +5,7 @@
 PROGRAM        = exportfs
 OBJS   = exportfs.o
 LIBDEPS        = $(TOP)support/lib/libexport.a $(TOP)/support/lib/libnfs.a
-LIBS   = -lexport -lnfs
+LIBS   = -lexport -lnfs -lmisc
 MAN8   = exportfs
 MAN5   = exports
 
index 936dff5..bd48e98 100644 (file)
@@ -147,6 +147,16 @@ exports_update(int verbose)
        nfs_export      *exp;
 
        for (exp = exportlist[MCL_FQDN]; exp; exp=exp->m_next) {
+               /* check mountpoint option */
+               if (exp->m_mayexport && 
+                   exp->m_export.e_mountpoint &&
+                   !is_mountpoint(exp->m_export.e_mountpoint[0]?
+                                  exp->m_export.e_mountpoint:
+                                  exp->m_export.e_path)) {
+                       printf("%s not exported as %s not a mountpoint.\n",
+                              exp->m_export.e_path, exp->m_export.e_mountpoint);
+                       exp->m_mayexport = 0;
+               }
                if (exp->m_mayexport && ((exp->m_exported<1) || exp->m_changed)) {
                        if (verbose)
                                printf("%sexporting %s:%s to kernel\n",
@@ -366,6 +376,10 @@ dump(int verbose)
                                c = dumpopt(c, "insecure_locks");
                        if (ep->e_flags & NFSEXP_FSID)
                                c = dumpopt(c, "fsid=%d", ep->e_fsid);
+                       if (ep->e_mountpoint)
+                               c = dumpopt(c, "mountpoint%s%s", 
+                                           ep->e_mountpoint[0]?"=":"", 
+                                           ep->e_mountpoint);
                        if (ep->e_maptype == CLE_MAP_UGIDD)
                                c = dumpopt(c, "mapping=ugidd");
                        else if (ep->e_maptype == CLE_MAP_FILE)
index 7ab7640..6223944 100644 (file)
@@ -237,6 +237,25 @@ or
 '''.TP
 '''.IR link_absolute
 '''Leave all symbolic link as they are. This is the default operation.
+
+.TP
+.IR mountpoint= path
+.TP
+.I mp
+This option makes it possible to only export a directory if it has
+successfully been mounted.
+If no path is given (e.g.
+.IR mountpoint " or " mp )
+then the export point must also be a mount point.  If it isn't then
+the export point is not exported.  This allows you to be sure that the
+directory underneath a mountpoint will never be exported by accident
+if, for example, the filesystem failed to mount due to a disc error.
+
+If a path is given (e.g.
+.IR mountpoint= "/path or " mp= /path)
+then the nominted path must be a mountpoint for the exportpoint to be
+exported.
+
 .SS User ID Mapping
 .PP
 .I nfsd
index c5bc53f..9d7d20d 100644 (file)
@@ -100,6 +100,7 @@ void nfsd_fh(FILE *f)
        struct exportent *found = NULL;
        nfs_export *exp;
        int i;
+       int dev_missing = 0;
 
        if (readline(fileno(f), &lbuf, &lbuflen) != 1)
                return;
@@ -145,6 +146,11 @@ void nfsd_fh(FILE *f)
                                continue;
                        if (fsidtype == 0) {
                                struct stat stb;
+                               if (exp->m_export.e_mountpoint &&
+                                   !is_mountpoint(exp->m_export.e_mountpoint[0]?
+                                                  exp->m_export.e_mountpoint:
+                                                  exp->m_export.e_path))
+                                       dev_missing ++;
                                if (stat(exp->m_export.e_path, &stb) != 0)
                                        continue;
                                if (stb.st_ino != inode)
@@ -158,11 +164,31 @@ void nfsd_fh(FILE *f)
                                found = &exp->m_export;
                        else if (strcmp(found->e_path, exp->m_export.e_path)!= 0)
                        {
-                               xlog(L_WARNING, "%s and %s have name filehandle for %s, using first",
+                               xlog(L_WARNING, "%s and %s have same filehandle for %s, using first",
                                     found->e_path, exp->m_export.e_path, dom);
                        }
                }
        }
+       if (found && 
+           found->e_mountpoint &&
+           !is_mountpoint(found->e_mountpoint[0]?
+                          found->e_mountpoint:
+                          found->e_path)) {
+               /* Cannot export this yet 
+                * should log a warning, but need to rate limit
+                  xlog(L_WARNING, "%s not exported as %d not a mountpoint",
+                  found->e_path, found->e_mountpoint);
+                */
+               /* FIXME we need to make sure we re-visit this later */
+               goto out;
+       }
+       if (!found && dev_missing) {
+               /* The missing dev could be what we want, so just be
+                * quite rather than returning stale yet
+                */
+               goto out;
+       }
+
        cache_export_ent(dom, found);
 
        qword_print(f, dom);
index b1bce1d..3769c92 100644 (file)
@@ -282,6 +282,13 @@ get_rootfh(struct svc_req *rqstp, dirpath *path, int *error, int v3)
                xlog(L_WARNING, "request to export directory %s below nearest filesystem %s",
                     p, exp->m_export.e_path);
                *error = NFSERR_ACCES;
+       } else if (exp->m_export.e_mountpoint &&
+                  !is_mountpoint(exp->m_export.e_mountpoint[0]?
+                                 exp->m_export.e_mountpoint:
+                                 exp->m_export.e_path)) {
+               xlog(L_WARNING, "request to export an unmounted filesystem: %s",
+                    p);
+               *error = NFSERR_NOENT;
        } else if (new_cache) {
                /* This will be a static private nfs_export with just one
                 * address.  We feed it to kernel then extract the filehandle,