+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
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;
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 */
int * e_sqgids;
int e_nsqgids;
int e_fsid;
+ char * e_mountpoint;
};
struct rmtabent {
#
LIBNAME = libmisc.a
-OBJS = tcpwrapper.o from_local.o
+OBJS = tcpwrapper.o from_local.o mountpoint.o
include $(TOP)rules.mk
--- /dev/null
+
+/*
+ * 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;
+}
ee.e_anongid = -2;
ee.e_squids = NULL;
ee.e_sqgids = NULL;
+ ee.e_mountpoint = NULL;
ee.e_nsquids = 0;
ee.e_nsqgids = 0;
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:
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 *
ee.e_anongid = -2;
ee.e_squids = NULL;
ee.e_sqgids = NULL;
+ ee.e_mountpoint = NULL;
ee.e_nsquids = 0;
ee.e_nsqgids = 0;
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);
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
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",
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)
'''.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
struct exportent *found = NULL;
nfs_export *exp;
int i;
+ int dev_missing = 0;
if (readline(fileno(f), &lbuf, &lbuflen) != 1)
return;
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)
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);
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,