From 1374c3861abdc66f3a1410e26cc85f86760b51dd Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Mon, 2 Apr 2007 13:26:05 +1000 Subject: [PATCH] exportfs - test exportability of filesystems when exportfs is run. When exporting a filesystem test to see if the kernel is likely to accept the export and print suitable warning message if not. Don't actually fail the 'exportfs' as by the time a MOUNT request arrives, the filesystem might be exportable. Signed-off-by: Neil Brown --- utils/exportfs/exportfs.c | 86 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c index 8c3f634..99618c9 100644 --- a/utils/exportfs/exportfs.c +++ b/utils/exportfs/exportfs.c @@ -12,6 +12,7 @@ #include #endif +#include #include #include #include @@ -32,7 +33,7 @@ static void exports_update(int verbose); static void dump(int verbose); static void error(nfs_export *exp, int err); static void usage(void); - +static void validate_export(nfs_export *exp); int main(int argc, char **argv) @@ -219,6 +220,7 @@ export_all(int verbose) exp->m_mayexport = 1; exp->m_changed = 1; exp->m_warned = 0; + validate_export(exp); } } } @@ -276,6 +278,7 @@ exportfs(char *arg, char *options, int verbose) exp->m_mayexport = 1; exp->m_changed = 1; exp->m_warned = 0; + validate_export(exp); if (hp) free (hp); } @@ -340,6 +343,87 @@ unexportfs(char *arg, int verbose) if (hp) free (hp); } +static int can_test(void) +{ + int fd; + int n; + char *setup = "nfsd 0.0.0.0 2147483647 -test-client-\n"; + fd = open("/proc/net/rpc/auth.unix.ip/channel", O_WRONLY); + if ( fd < 0) return 0; + n = write(fd, setup, strlen(setup)); + close(fd); + if (n < 0) + return 0; + fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); + if ( fd < 0) return 0; + close(fd); + return 1; +} + +static int test_export(char *path, int with_fsid) +{ + char buf[1024]; + int fd, n; + + sprintf(buf, "-test-client- %s 3 %d -1 -1 0\n", + path, + with_fsid ? NFSEXP_FSID : 0); + fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); + if (fd < 0) + return 0; + n = write(fd, buf, strlen(buf)); + close(fd); + if (n < 0) + return 0; + return 1; +} + +static void +validate_export(nfs_export *exp) +{ + /* Check that the given export point is potentially exportable. + * We just give warnings here, don't cause anything to fail. + * If a path doesn't exist, or is not a dir or file, give an warning + * otherwise trial-export to '-test-client-' and check for failure. + */ + struct stat stb; + char *path = exp->m_export.e_path; + + if (stat(path, &stb) < 0) { + fprintf(stderr, "exportfs: Warning: %s does not exist\n", + path); + return; + } + if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) { + fprintf(stderr, "exportfs: Warning: %s is neither " + "a directory nor a file.\n" + " remote access will fail\n", path); + return; + } + if (!can_test()) + return; + + if ((exp->m_export.e_flags & NFSEXP_FSID) || exp->m_export.e_uuid) { + if ( !test_export(path, 1)) { + fprintf(stderr, "exportfs: Warning: %s does not " + "support NFS export.\n", + path); + return; + } + } else if ( ! test_export(path, 0)) { + if (test_export(path, 1)) + fprintf(stderr, "exportfs: Warning: %s requires fsid= " + "for NFS export\n", path); + else + fprintf(stderr, "exportfs: Warning: %s does not " + "support NFS export.\n", + path); + return; + + } +} + + static char dumpopt(char c, char *fmt, ...) { -- 2.39.5