summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--support/export/export.c2
-rw-r--r--support/include/misc.h2
-rw-r--r--support/include/nfslib.h1
-rw-r--r--support/misc/Makefile2
-rw-r--r--support/misc/mountpoint.c34
-rw-r--r--support/nfs/exports.c17
-rw-r--r--utils/exportfs/Makefile2
-rw-r--r--utils/exportfs/exportfs.c14
-rw-r--r--utils/exportfs/exports.man19
-rw-r--r--utils/mountd/cache.c28
-rw-r--r--utils/mountd/mountd.c7
12 files changed, 137 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 60fd487..414a526 100644
--- 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
diff --git a/support/export/export.c b/support/export/export.c
index ba0d095..eef2c3b 100644
--- a/support/export/export.c
+++ b/support/export/export.c
@@ -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;
diff --git a/support/include/misc.h b/support/include/misc.h
index 7d099d0..9a1b25d 100644
--- a/support/include/misc.h
+++ b/support/include/misc.h
@@ -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 */
diff --git a/support/include/nfslib.h b/support/include/nfslib.h
index 5864305..c41f92e 100644
--- a/support/include/nfslib.h
+++ b/support/include/nfslib.h
@@ -73,6 +73,7 @@ struct exportent {
int * e_sqgids;
int e_nsqgids;
int e_fsid;
+ char * e_mountpoint;
};
struct rmtabent {
diff --git a/support/misc/Makefile b/support/misc/Makefile
index b2f73f8..c738564 100644
--- a/support/misc/Makefile
+++ b/support/misc/Makefile
@@ -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
index 0000000..6d0f34e
--- /dev/null
+++ b/support/misc/mountpoint.c
@@ -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;
+}
diff --git a/support/nfs/exports.c b/support/nfs/exports.c
index dfb241e..4d8665c 100644
--- a/support/nfs/exports.c
+++ b/support/nfs/exports.c
@@ -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);
diff --git a/utils/exportfs/Makefile b/utils/exportfs/Makefile
index 851a294..8cd7029 100644
--- a/utils/exportfs/Makefile
+++ b/utils/exportfs/Makefile
@@ -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
diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
index 936dff5..bd48e98 100644
--- a/utils/exportfs/exportfs.c
+++ b/utils/exportfs/exportfs.c
@@ -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)
diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man
index 7ab7640..6223944 100644
--- a/utils/exportfs/exports.man
+++ b/utils/exportfs/exports.man
@@ -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
diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
index c5bc53f..9d7d20d 100644
--- a/utils/mountd/cache.c
+++ b/utils/mountd/cache.c
@@ -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);
diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c
index b1bce1d..3769c92 100644
--- a/utils/mountd/mountd.c
+++ b/utils/mountd/mountd.c
@@ -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,