From d38ea02d0e4bcdc4e0114567028596f7bcba45b9 Mon Sep 17 00:00:00 2001 From: neilbrown Date: Fri, 30 May 2003 05:16:52 +0000 Subject: [PATCH 1/1] new "mountpoint" export option. --- ChangeLog | 12 ++++++++++++ support/export/export.c | 2 ++ support/include/misc.h | 2 ++ support/include/nfslib.h | 1 + support/misc/Makefile | 2 +- support/misc/mountpoint.c | 34 ++++++++++++++++++++++++++++++++++ support/nfs/exports.c | 17 +++++++++++++++++ utils/exportfs/Makefile | 2 +- utils/exportfs/exportfs.c | 14 ++++++++++++++ utils/exportfs/exports.man | 19 +++++++++++++++++++ utils/mountd/cache.c | 28 +++++++++++++++++++++++++++- utils/mountd/mountd.c | 7 +++++++ 12 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 support/misc/mountpoint.c diff --git a/ChangeLog b/ChangeLog index 60fd487..414a526 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2003-05-30 NeilBrown + + * 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 * 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 +#include +#include + +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, -- 2.39.2