From 4897093455a2bf08f3db3a1132cc2f6f5484d77c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 08:03:02 +0200 Subject: Adding upstream version 1:2.6.4. Signed-off-by: Daniel Baumann --- support/export/xtab.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 support/export/xtab.c (limited to 'support/export/xtab.c') 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 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} -- cgit v1.2.3