blob: 2a43193c35a15345c053b005e46cf45eadabfe1b [file] [log] [blame]
/*
* support/export/xtab.c
*
* Interface to the xtab file.
*
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "xmalloc.h"
#include "nfslib.h"
#include "exportfs.h"
#include "xio.h"
#include "xlog.h"
#include "v4root.h"
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
* is_export == 2 => reading /var/lib/nfs/xtab - these things might be known to kernel
*/
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))) {
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;
case 2:
exp->m_exported = -1;/* may be exported */
break;
}
}
endexportent();
xfunlock(lockid);
return 0;
}
int
xtab_mount_read(void)
{
int fd;
if ((fd=open(_PATH_PROC_EXPORTS, O_RDONLY))>=0) {
close(fd);
return xtab_read(_PATH_PROC_EXPORTS,
_PATH_PROC_EXPORTS, 0);
} else if ((fd=open(_PATH_PROC_EXPORTS_ALT, O_RDONLY) >= 0)) {
close(fd);
return xtab_read(_PATH_PROC_EXPORTS_ALT,
_PATH_PROC_EXPORTS_ALT, 0);
} else
return xtab_read(_PATH_XTAB, _PATH_XTABLCK, 2);
}
int
xtab_export_read(void)
{
return xtab_read(_PATH_ETAB, _PATH_ETABLCK, 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(_PATH_ETAB, _PATH_ETABTMP, _PATH_ETABLCK, 1);
}
int
xtab_mount_write()
{
return xtab_write(_PATH_XTAB, _PATH_XTABTMP, _PATH_XTABLCK, 0);
}
void
xtab_append(nfs_export *exp)
{
struct exportent xe;
int lockid;
if ((lockid = xflock(_PATH_XTABLCK, "w")) < 0)
return;
setexportent(_PATH_XTAB, "a");
xe = exp->m_export;
xe.e_hostname = exp->m_client->m_hostname;
putexportent(&xe);
endexportent();
xfunlock(lockid);
exp->m_xtabent = 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;
}