summaryrefslogtreecommitdiffstats
path: root/support/export/xtab.c
diff options
context:
space:
mode:
Diffstat (limited to 'support/export/xtab.c')
-rw-r--r--support/export/xtab.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/support/export/xtab.c b/support/export/xtab.c
new file mode 100644
index 0000000..e210ca9
--- /dev/null
+++ b/support/export/xtab.c
@@ -0,0 +1,256 @@
+/*
+ * support/export/xtab.c
+ *
+ * Interface to the etab/exports file.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <libgen.h>
+
+#include "nfslib.h"
+#include "exportfs.h"
+#include "xio.h"
+#include "xlog.h"
+#include "v4root.h"
+#include "misc.h"
+
+static char state_base_dirname[PATH_MAX] = NFS_STATEDIR;
+struct state_paths etab;
+
+int v4root_needed;
+static void cond_rename(char *newfile, char *oldfile);
+
+static int
+xtab_read(char *xtab, char *lockfn, int is_export)
+{
+ /* is_export == 0 => reading /proc/fs/nfs/exports - we know these things are exported to kernel
+ * is_export == 1 => reading /var/lib/nfs/etab - these things are allowed to be exported
+ */
+ struct exportent *xp;
+ nfs_export *exp;
+ int lockid;
+
+ if ((lockid = xflock(lockfn, "r")) < 0)
+ return 0;
+ setexportent(xtab, "r");
+ if (is_export == 1)
+ v4root_needed = 1;
+ while ((xp = getexportent(is_export==0, 0)) != NULL) {
+ if (!(exp = export_lookup(xp->e_hostname, xp->e_path, is_export != 1)) &&
+ !(exp = export_create(xp, is_export!=1))) {
+ if(xp->e_hostname) {
+ free(xp->e_hostname);
+ xp->e_hostname=NULL;
+ }
+ if(xp->e_uuid) {
+ free(xp->e_uuid);
+ xp->e_uuid=NULL;
+ }
+ continue;
+ }
+ switch (is_export) {
+ case 0:
+ exp->m_exported = 1;
+ break;
+ case 1:
+ exp->m_xtabent = 1;
+ exp->m_mayexport = 1;
+ if ((xp->e_flags & NFSEXP_FSID) && xp->e_fsid == 0)
+ v4root_needed = 0;
+ break;
+ }
+ if(xp->e_hostname) {
+ free(xp->e_hostname);
+ xp->e_hostname=NULL;
+ }
+ if(xp->e_uuid) {
+ free(xp->e_uuid);
+ xp->e_uuid=NULL;
+ }
+
+ }
+ endexportent();
+ xfunlock(lockid);
+
+ return 0;
+}
+
+int
+xtab_export_read(void)
+{
+ return xtab_read(etab.statefn, etab.lockfn, 1);
+}
+
+/*
+ * mountd now keeps an open fd for the etab at all times to make sure that the
+ * inode number changes when the xtab_export_write is done. If you change the
+ * routine below such that the files are edited in place, then you'll need to
+ * fix the auth_reload logic as well...
+ */
+static int
+xtab_write(char *xtab, char *xtabtmp, char *lockfn, int is_export)
+{
+ struct exportent xe;
+ nfs_export *exp;
+ int lockid, i;
+
+ if ((lockid = xflock(lockfn, "w")) < 0) {
+ xlog(L_ERROR, "can't lock %s for writing", xtab);
+ return 0;
+ }
+ setexportent(xtabtmp, "w");
+
+ for (i = 0; i < MCL_MAXTYPES; i++) {
+ for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
+ if (is_export && !exp->m_xtabent)
+ continue;
+ if (!is_export && ! exp->m_exported)
+ continue;
+
+ /* write out the export entry using the FQDN */
+ xe = exp->m_export;
+ xe.e_hostname = exp->m_client->m_hostname;
+ putexportent(&xe);
+ }
+ }
+ endexportent();
+
+ cond_rename(xtabtmp, xtab);
+
+ xfunlock(lockid);
+
+ return 1;
+}
+
+int
+xtab_export_write(void)
+{
+ return xtab_write(etab.statefn, etab.tmpfn, etab.lockfn, 1);
+}
+
+/*
+ * rename newfile onto oldfile unless
+ * they are identical
+ */
+static void cond_rename(char *newfile, char *oldfile)
+{
+ int nfd, ofd;
+ char nbuf[4096], obuf[4096];
+ int ncnt, ocnt;
+
+ nfd = open(newfile, 0);
+ if (nfd < 0)
+ return;
+ ofd = open(oldfile, 0);
+ if (ofd < 0) {
+ close(nfd);
+ rename(newfile, oldfile);
+ return;
+ }
+
+ do {
+ ncnt = read(nfd, nbuf, sizeof(nbuf));
+ if (ncnt < 0)
+ break;
+ ocnt = read(ofd, obuf, sizeof(obuf));
+ if (ocnt < 0)
+ break;
+ if (ncnt != ocnt)
+ break;
+ if (ncnt == 0) {
+ close(nfd);
+ close(ofd);
+ unlink(newfile);
+ return;
+ }
+ } while (memcmp(obuf, nbuf, ncnt) == 0);
+
+ /* some mis-match */
+ close(nfd);
+ close(ofd);
+ rename(newfile, oldfile);
+ return;
+}
+
+/*
+ * Returns a dynamically allocated, '\0'-terminated buffer
+ * containing an appropriate pathname, or NULL if an error
+ * occurs. Caller must free the returned result with free(3).
+ */
+static char *
+state_make_pathname(const char *tabname)
+{
+ return generic_make_pathname(state_base_dirname, tabname);
+}
+
+/**
+ * state_setup_basedir - set up basedir
+ * @progname: C string containing name of program, for error messages
+ * @parentdir: C string containing pathname to on-disk state, or NULL
+ *
+ * This runs before logging is set up, so error messages are directed
+ * to stderr.
+ *
+ * Returns true and sets up our basedir, if @parentdir was valid
+ * and usable; otherwise false is returned.
+ */
+_Bool
+state_setup_basedir(const char *progname, const char *parentdir)
+{
+ return generic_setup_basedir(progname, parentdir, state_base_dirname,
+ PATH_MAX);
+}
+
+int
+setup_state_path_names(const char *progname, const char *statefn,
+ const char *tmpfn, const char *lockfn,
+ struct state_paths *paths)
+{
+ paths->statefn = state_make_pathname(statefn);
+ if (!paths->statefn) {
+ fprintf(stderr, "%s: state_make_pathname(%s) failed\n",
+ progname, statefn);
+ goto out_err;
+ }
+ paths->tmpfn = state_make_pathname(tmpfn);
+ if (!paths->tmpfn) {
+ fprintf(stderr, "%s: state_make_pathname(%s) failed\n",
+ progname, tmpfn);
+ goto out_free_statefn;
+ }
+ paths->lockfn = state_make_pathname(lockfn);
+ if (!paths->lockfn) {
+ fprintf(stderr, "%s: state_make_pathname(%s) failed\n",
+ progname, lockfn);
+ goto out_free_tmpfn;
+ }
+ return 1;
+
+out_free_tmpfn:
+ free(paths->tmpfn);
+out_free_statefn:
+ free(paths->statefn);
+out_err:
+ return 0;
+
+}
+
+void
+free_state_path_names(struct state_paths *paths)
+{
+ free(paths->statefn);
+ free(paths->tmpfn);
+ free(paths->lockfn);
+}