X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fexportfs%2Fexportfs.c;h=593a8ebd467e1081b4f7ed4110df89712bc8c248;hp=4c04098e1579475a5f66b5314872db308c599f41;hb=9ccfe0fa5a43dfc4453b09e328565a6c8f999fe4;hpb=37e49789ab1cd849def25ba4c4d97ccdb11d1e61 diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c index 4c04098..593a8eb 100644 --- a/utils/exportfs/exportfs.c +++ b/utils/exportfs/exportfs.c @@ -8,8 +8,12 @@ * Extensive changes, 1999, Neil Brown */ -#include "config.h" +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include #include #include #include @@ -30,7 +34,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) @@ -42,10 +46,14 @@ main(int argc, char **argv) int f_reexport = 0; int f_ignore = 0; int i, c; + int new_cache = 0; + int force_flush = 0; xlog_open("exportfs"); - while ((c = getopt(argc, argv, "aio:ruv")) != EOF) { + export_errno = 0; + + while ((c = getopt(argc, argv, "aio:ruvf")) != EOF) { switch(c) { case 'a': f_all = 1; @@ -66,6 +74,9 @@ main(int argc, char **argv) case 'v': f_verbose = 1; break; + case 'f': + force_flush = 1; + break; default: usage(); break; @@ -84,12 +95,22 @@ main(int argc, char **argv) fprintf(stderr, "exportfs: -r and -u are incompatible.\n"); return 1; } + new_cache = check_new_cache(); if (optind == argc && ! f_all) { - xtab_export_read(); - dump(f_verbose); - return 0; + if (force_flush) { + if (new_cache) + cache_flush(1); + else { + fprintf(stderr, "exportfs: -f: only available with new cache controls: mount /proc/fs/nfsd first\n"); + exit(1); + } + return 0; + } else { + xtab_export_read(); + dump(f_verbose); + return 0; + } } - if (f_export && ! f_ignore) export_read(_PATH_EXPORTS); if (f_export) { @@ -112,44 +133,70 @@ main(int argc, char **argv) if (!f_export) for (i = optind ; i < argc ; i++) unexportfs(argv[i], f_verbose); - rmtab_read(); + if (!new_cache) + rmtab_read(); + } + if (!new_cache) { + xtab_mount_read(); + exports_update(f_verbose); } - xtab_mount_read(); - exports_update(f_verbose); xtab_export_write(); - xtab_mount_write(); + if (new_cache) + cache_flush(force_flush); + if (!new_cache) + xtab_mount_write(); - return 0; + return export_errno; } +static void +exports_update_one(nfs_export *exp, int verbose) +{ + /* 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", + exp->m_exported ?"re":"", + exp->m_client->m_hostname, + exp->m_export.e_path); + if (!export_export(exp)) + error(exp, errno); + } + if (exp->m_exported && ! exp->m_mayexport) { + if (verbose) + printf("unexporting %s:%s from kernel\n", + exp->m_client->m_hostname, + exp->m_export.e_path); + if (!export_unexport(exp)) + error(exp, errno); + } +} + + /* we synchronise intention with reality. * entries with m_mayexport get exported * entries with m_exported but not m_mayexport get unexported - * looking at m_client->m_type == MCL_FQDN only + * looking at m_client->m_type == MCL_FQDN and m_client->m_type == MCL_GSS only */ static void exports_update(int verbose) { nfs_export *exp; - for (exp = exportlist[MCL_FQDN]; exp; exp=exp->m_next) { - if (exp->m_mayexport && ((exp->m_exported<1) || exp->m_changed)) { - if (verbose) - printf("%sexporting %s:%s to kernel\n", - exp->m_exported ?"re":"", - exp->m_client->m_hostname, - exp->m_export.e_path); - if (!export_export(exp)) - error(exp, errno); - } - if (exp->m_exported && ! exp->m_mayexport) { - if (verbose) - printf("unexporting %s:%s from kernel\n", - exp->m_client->m_hostname, - exp->m_export.e_path); - if (!export_unexport(exp)) - error(exp, errno); - } + for (exp = exportlist[MCL_FQDN].p_head; exp; exp=exp->m_next) { + exports_update_one(exp, verbose); + } + for (exp = exportlist[MCL_GSS].p_head; exp; exp=exp->m_next) { + exports_update_one(exp, verbose); } } @@ -164,7 +211,7 @@ export_all(int verbose) int i; for (i = 0; i < MCL_MAXTYPES; i++) { - for (exp = exportlist[i]; exp; exp = exp->m_next) { + for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { if (verbose) printf("exporting %s:%s\n", exp->m_client->m_hostname, @@ -172,6 +219,8 @@ export_all(int verbose) exp->m_xtabent = 1; exp->m_mayexport = 1; exp->m_changed = 1; + exp->m_warned = 0; + validate_export(exp); } } } @@ -206,6 +255,7 @@ exportfs(char *arg, char *options, int verbose) } else hp = hp2; exp = export_find(hp, path); + hname = hp->h_name; } else { exp = export_lookup(hname, path, 0); } @@ -227,6 +277,8 @@ exportfs(char *arg, char *options, int verbose) exp->m_xtabent = 1; exp->m_mayexport = 1; exp->m_changed = 1; + exp->m_warned = 0; + validate_export(exp); if (hp) free (hp); } @@ -255,28 +307,35 @@ unexportfs(char *arg, int verbose) } } - for (exp = exportlist[htype]; exp; exp = exp->m_next) { + for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) { if (path && strcmp(path, exp->m_export.e_path)) continue; - if (htype != exp->m_client->m_type - || (htype == MCL_FQDN - && !matchhostname(exp->m_export.e_hostname, - hname))) + if (htype != exp->m_client->m_type) + continue; + if (htype == MCL_FQDN + && !matchhostname(exp->m_export.e_hostname, + hname)) + continue; + if (htype != MCL_FQDN + && strcasecmp(exp->m_export.e_hostname, hname)) continue; if (verbose) { +#if 0 if (exp->m_exported) { printf("unexporting %s:%s from kernel\n", exp->m_client->m_hostname, exp->m_export.e_path); } - else { + else +#endif printf("unexporting %s:%s\n", exp->m_client->m_hostname, exp->m_export.e_path); - } } +#if 0 if (exp->m_exported && !export_unexport(exp)) error(exp, errno); +#endif exp->m_xtabent = 0; exp->m_mayexport = 0; } @@ -284,6 +343,94 @@ 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; + struct statfs64 stf; + int fs_has_fsid = 0; + + 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 (!statfs64(path, &stf) && + (stf.f_fsid.__val[0] || stf.f_fsid.__val[1])) + fs_has_fsid = 1; + + if ((exp->m_export.e_flags & NFSEXP_FSID) || exp->m_export.e_uuid || + fs_has_fsid) { + 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, ...) { @@ -305,7 +452,7 @@ dump(int verbose) char *hname, c; for (htype = 0; htype < MCL_MAXTYPES; htype++) { - for (exp = exportlist[htype]; exp; exp = exp->m_next) { + for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) { ep = &exp->m_export; if (!exp->m_xtabent) continue; /* neilb */ @@ -330,8 +477,10 @@ dump(int verbose) c = dumpopt(c, "async"); if (ep->e_flags & NFSEXP_GATHERED_WRITES) c = dumpopt(c, "wdelay"); - if (ep->e_flags & NFSEXP_CROSSMNT) + if (ep->e_flags & NFSEXP_NOHIDE) c = dumpopt(c, "nohide"); + if (ep->e_flags & NFSEXP_CROSSMOUNT) + c = dumpopt(c, "crossmnt"); if (ep->e_flags & NFSEXP_INSECURE_PORT) c = dumpopt(c, "insecure"); if (ep->e_flags & NFSEXP_ROOTSQUASH) @@ -344,15 +493,36 @@ dump(int verbose) c = dumpopt(c, "no_subtree_check"); if (ep->e_flags & NFSEXP_NOAUTHNLM) c = dumpopt(c, "insecure_locks"); - if (ep->e_maptype == CLE_MAP_UGIDD) - c = dumpopt(c, "mapping=ugidd"); - else if (ep->e_maptype == CLE_MAP_FILE) - c = dumpopt(c, "mapping=file"); - if (ep->e_anonuid != -2) + if (ep->e_flags & NFSEXP_NOACL) + c = dumpopt(c, "no_acl"); + if (ep->e_flags & NFSEXP_FSID) + c = dumpopt(c, "fsid=%d", ep->e_fsid); + if (ep->e_uuid) + c = dumpopt(c, "fsid=%s", ep->e_uuid); + if (ep->e_mountpoint) + c = dumpopt(c, "mountpoint%s%s", + ep->e_mountpoint[0]?"=":"", + ep->e_mountpoint); + if (ep->e_anonuid != 65534) c = dumpopt(c, "anonuid=%d", ep->e_anonuid); - if (ep->e_anongid != -2) + if (ep->e_anongid != 65534) c = dumpopt(c, "anongid=%d", ep->e_anongid); - + switch(ep->e_fslocmethod) { + case FSLOC_NONE: + break; + case FSLOC_REFER: + c = dumpopt(c, "refer=%s", ep->e_fslocdata); + break; + case FSLOC_REPLICA: + c = dumpopt(c, "replicas=%s", ep->e_fslocdata); + break; +#ifdef DEBUG + case FSLOC_STUB: + c = dumpopt(c, "fsloc=stub"); + break; +#endif + } + secinfo_show(stdout, ep); printf("%c\n", (c != '(')? ')' : ' '); } }