257 lines
5.7 KiB
C
257 lines
5.7 KiB
C
/*
|
|
* 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;
|
|
extern 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()
|
|
{
|
|
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);
|
|
}
|