Compare commits
2 Commits
Branch_RK3
...
Branch_NDK
| Author | SHA1 | Date | |
|---|---|---|---|
| 55bc9ca9b5 | |||
| 6ba4175d2b |
17
Makefile
17
Makefile
@ -31,12 +31,12 @@ MULTI_CORES ?= $(shell grep -c ^processor /proc/cpuinfo)
|
|||||||
#*******************************************************************************
|
#*******************************************************************************
|
||||||
# Compile configure
|
# Compile configure
|
||||||
#*******************************************************************************
|
#*******************************************************************************
|
||||||
export ARCH ?= arm
|
export ARCH ?= aarch64
|
||||||
export CROSS_COMPILE ?=
|
export CROSS_COMPILE ?= /home/gaoyang3513/Workspaces/ndk/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-
|
||||||
CC := $(CROSS_COMPILE)gcc
|
export CC := /home/gaoyang3513/Workspaces/ndk/android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/clang
|
||||||
LD := $(CROSS_COMPILE)ld
|
export LD := $(CROSS_COMPILE)ld
|
||||||
AR := $(CROSS_COMPILE)ar
|
export AR := $(CROSS_COMPILE)ar
|
||||||
STRIP := $(CROSS_COMPILE)strip
|
export STRIP := $(CROSS_COMPILE)strip
|
||||||
|
|
||||||
#*******************************************************************************
|
#*******************************************************************************
|
||||||
# Targets
|
# Targets
|
||||||
@ -72,7 +72,10 @@ nfs-utils: checkenv
|
|||||||
fi
|
fi
|
||||||
if [ ! -e $(NFS_DIR)/Makefile ]; then \
|
if [ ! -e $(NFS_DIR)/Makefile ]; then \
|
||||||
cd $(NFS_DIR); \
|
cd $(NFS_DIR); \
|
||||||
./configure --prefix=$(INSTALL_DIR) --disable-nfsv4 --disable-gss --disable-uuid --disable-mount --sbindir=$(INSTALL_DIR)/sbin/ --with-statedir=$(INSTALL_DIR)/var/lig/nfs/; \
|
./configure --prefix=$(INSTALL_DIR) \
|
||||||
|
--target=aarch64-linux-android --host=aarch64-linux-android --build=x86_64-linux \
|
||||||
|
--disable-nfsv4 --disable-gss --disable-uuid --disable-mount \
|
||||||
|
--sbindir=$(INSTALL_DIR)/sbin/ --with-statedir=$(INSTALL_DIR)/var/lig/nfs/; \
|
||||||
fi
|
fi
|
||||||
$(MAKE) -C $(NFS_DIR) all install
|
$(MAKE) -C $(NFS_DIR) all install
|
||||||
|
|
||||||
|
|||||||
34
libtirpc-1.3.1/build.sh
Executable file
34
libtirpc-1.3.1/build.sh
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
LOCAL_DIR=`pwd`
|
||||||
|
#----------------------------------
|
||||||
|
OUTPUT_DIR=${LOCAL_DIR}/output
|
||||||
|
INSTALL_DIR=${LOCAL_DIR}/install
|
||||||
|
|
||||||
|
NDK=${HOME}/Workspaces/ndk/android-ndk-r21e
|
||||||
|
|
||||||
|
# Only choose one of these, depending on your build machine...
|
||||||
|
#export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
|
||||||
|
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64
|
||||||
|
|
||||||
|
# Only choose one of these, depending on your device...
|
||||||
|
export TARGET=aarch64-linux-android
|
||||||
|
#export TARGET=armv7a-linux-androideabi
|
||||||
|
#export TARGET=i686-linux-android
|
||||||
|
#export TARGET=x86_64-linux-android
|
||||||
|
|
||||||
|
# Set this to your minSdkVersion.
|
||||||
|
export API=30
|
||||||
|
|
||||||
|
# Configure and build.
|
||||||
|
export AR=$TOOLCHAIN/bin/llvm-ar
|
||||||
|
export CC=$TOOLCHAIN/bin/$TARGET$API-clang
|
||||||
|
export AS=$CC
|
||||||
|
export CXX=$TOOLCHAIN/bin/$TARGET$API-clang++
|
||||||
|
export LD=$TOOLCHAIN/bin/ld
|
||||||
|
export RANLIB=$TOOLCHAIN/bin/llvm-ranlib
|
||||||
|
export STRIP=$TOOLCHAIN/bin/llvm-strip
|
||||||
|
|
||||||
|
./configure --host=$TARGET --prefix=${PWD}/../_install --disable-static --disable-gssapi CFLAGS="-I../libtirpc-1.3.1/tirpc/rpc/"
|
||||||
|
|
||||||
|
make
|
||||||
35
nfs-utils-2.5.2/build.sh
Executable file
35
nfs-utils-2.5.2/build.sh
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
LOCAL_DIR=`pwd`
|
||||||
|
#----------------------------------
|
||||||
|
OUTPUT_DIR=${LOCAL_DIR}/output
|
||||||
|
INSTALL_DIR=${LOCAL_DIR}/install
|
||||||
|
|
||||||
|
NDK=${HOME}/Workspaces/ndk/android-ndk-r21e
|
||||||
|
|
||||||
|
# Only choose one of these, depending on your build machine...
|
||||||
|
#export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
|
||||||
|
export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64
|
||||||
|
|
||||||
|
# Only choose one of these, depending on your device...
|
||||||
|
export TARGET=aarch64-linux-android
|
||||||
|
#export TARGET=armv7a-linux-androideabi
|
||||||
|
#export TARGET=i686-linux-android
|
||||||
|
#export TARGET=x86_64-linux-android
|
||||||
|
|
||||||
|
# Set this to your minSdkVersion.
|
||||||
|
export API=30
|
||||||
|
|
||||||
|
# Configure and build.
|
||||||
|
export AR=$TOOLCHAIN/bin/llvm-ar
|
||||||
|
export CC=$TOOLCHAIN/bin/$TARGET$API-clang
|
||||||
|
export AS=$CC
|
||||||
|
export CXX=$TOOLCHAIN/bin/$TARGET$API-clang++
|
||||||
|
export LD=$TOOLCHAIN/bin/ld
|
||||||
|
export RANLIB=$TOOLCHAIN/bin/llvm-ranlib
|
||||||
|
export STRIP=$TOOLCHAIN/bin/llvm-strip
|
||||||
|
|
||||||
|
./configure --host=$TARGET --prefix=${INSTALL_DIR} \
|
||||||
|
--disable-ipv6 --disable-tirpc --disable-nfsv4 --disable-gss --disable-uuid --disable-mount;
|
||||||
|
|
||||||
|
make
|
||||||
256
nfs-utils-2.5.2/support/export/xtab.c
Normal file
256
nfs-utils-2.5.2/support/export/xtab.c
Normal file
@ -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;
|
||||||
|
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(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);
|
||||||
|
}
|
||||||
191
nfs-utils-2.5.2/support/nfs/xcommon.c
Normal file
191
nfs-utils-2.5.2/support/nfs/xcommon.c
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
* xcommon.c - various functions put together to avoid basic error checking.
|
||||||
|
*
|
||||||
|
* added fcntl locking by Kjetil T. (kjetilho@math.uio.no) - aeb, 950927
|
||||||
|
*
|
||||||
|
* 1999-02-22 Arkadiusz Miskiewicz <misiek@pld.ORG.PL>
|
||||||
|
* - added Native Language Support
|
||||||
|
*
|
||||||
|
* 2006-06-06 Amit Gud <agud@redhat.com>
|
||||||
|
* - Moved code snippets here from mount/sundries.c of util-linux
|
||||||
|
* and merged code from support/nfs/xmalloc.c by Olaf Kirch <okir@monad.swb.de> here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "xcommon.h"
|
||||||
|
#include "nls.h" /* _() */
|
||||||
|
|
||||||
|
void (*at_die)(void ) = NULL;
|
||||||
|
|
||||||
|
char *
|
||||||
|
xstrndup (const char *s, int n) {
|
||||||
|
char *t;
|
||||||
|
|
||||||
|
if (s == NULL)
|
||||||
|
die (EX_SOFTWARE, _("bug in xstrndup call"));
|
||||||
|
|
||||||
|
t = xmalloc(n+1);
|
||||||
|
strncpy(t,s,n);
|
||||||
|
t[n] = 0;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
xstrconcat2 (const char *s, const char *t) {
|
||||||
|
char *res;
|
||||||
|
|
||||||
|
if (!s) s = "";
|
||||||
|
if (!t) t = "";
|
||||||
|
res = xmalloc(strlen(s) + strlen(t) + 1);
|
||||||
|
strcpy(res, s);
|
||||||
|
strcat(res, t);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* frees its first arg - typical use: s = xstrconcat3(s,t,u); */
|
||||||
|
char *
|
||||||
|
xstrconcat3 (const char *s, const char *t, const char *u) {
|
||||||
|
char *res;
|
||||||
|
|
||||||
|
int dofree = 1;
|
||||||
|
|
||||||
|
if (!s) s = "", dofree=0;
|
||||||
|
if (!t) t = "";
|
||||||
|
if (!u) u = "";
|
||||||
|
res = xmalloc(strlen(s) + strlen(t) + strlen(u) + 1);
|
||||||
|
strcpy(res, s);
|
||||||
|
strcat(res, t);
|
||||||
|
strcat(res, u);
|
||||||
|
if (dofree)
|
||||||
|
free((void *) s);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* frees its first arg - typical use: s = xstrconcat4(s,t,u,v); */
|
||||||
|
char *
|
||||||
|
xstrconcat4 (const char *s, const char *t, const char *u, const char *v) {
|
||||||
|
char *res;
|
||||||
|
|
||||||
|
int dofree = 1;
|
||||||
|
|
||||||
|
if (!s) s = "", dofree=0;
|
||||||
|
if (!t) t = "";
|
||||||
|
if (!u) u = "";
|
||||||
|
if (!v) v = "";
|
||||||
|
res = xmalloc(strlen(s) + strlen(t) + strlen(u) + strlen(v) + 1);
|
||||||
|
strcpy(res, s);
|
||||||
|
strcat(res, t);
|
||||||
|
strcat(res, u);
|
||||||
|
strcat(res, v);
|
||||||
|
if (dofree)
|
||||||
|
free((void *) s);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Non-fatal error. Print message and return. */
|
||||||
|
/* (print the message in a single printf, in an attempt
|
||||||
|
to avoid mixing output of several threads) */
|
||||||
|
void
|
||||||
|
nfs_error (const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
char *fmt2;
|
||||||
|
|
||||||
|
fmt2 = xstrconcat2 (fmt, "\n");
|
||||||
|
va_start (args, fmt);
|
||||||
|
// vfprintf (stderr, fmt2, args);
|
||||||
|
va_end (args);
|
||||||
|
free (fmt2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make a canonical pathname from PATH. Returns a freshly malloced string.
|
||||||
|
It is up the *caller* to ensure that the PATH is sensible. i.e.
|
||||||
|
canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.''
|
||||||
|
is not a legal pathname for ``/dev/fd0''. Anything we cannot parse
|
||||||
|
we return unmodified. */
|
||||||
|
char *canonicalize (const char *path) {
|
||||||
|
char canonical[PATH_MAX+2];
|
||||||
|
|
||||||
|
if (path == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
if (streq(path, "none") ||
|
||||||
|
streq(path, "proc") ||
|
||||||
|
streq(path, "devpts"))
|
||||||
|
return xstrdup(path);
|
||||||
|
#endif
|
||||||
|
if (realpath (path, canonical))
|
||||||
|
return xstrdup(canonical);
|
||||||
|
|
||||||
|
return xstrdup(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fatal error. Print message and exit. */
|
||||||
|
void
|
||||||
|
die(int err, const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
vfprintf(stderr, fmt, args);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (at_die)
|
||||||
|
(*at_die)();
|
||||||
|
|
||||||
|
exit(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
die_if_null(void *t) {
|
||||||
|
if (t == NULL)
|
||||||
|
die(EX_SYSERR, _("not enough memory"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
xmalloc (size_t size) {
|
||||||
|
void *t;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
t = malloc(size);
|
||||||
|
die_if_null(t);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
xrealloc (void *p, size_t size) {
|
||||||
|
void *t;
|
||||||
|
|
||||||
|
t = realloc(p, size);
|
||||||
|
die_if_null(t);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xfree(void *ptr)
|
||||||
|
{
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
xstrdup (const char *s) {
|
||||||
|
char *t;
|
||||||
|
|
||||||
|
if (s == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
t = strdup(s);
|
||||||
|
die_if_null(t);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
780
nfs-utils-2.5.2/utils/exportfs/exportfs.c
Normal file
780
nfs-utils-2.5.2/utils/exportfs/exportfs.c
Normal file
@ -0,0 +1,780 @@
|
|||||||
|
/*
|
||||||
|
* utils/exportfs/exportfs.c
|
||||||
|
*
|
||||||
|
* Export file systems to knfsd
|
||||||
|
*
|
||||||
|
* Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
|
||||||
|
*
|
||||||
|
* Extensive changes, 1999, Neil Brown <neilb@cse.unsw.edu.au>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/vfs.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#define INT_TO_LONG_THRESHOLD_SECS (INT_MAX - (60 * 60 * 24))
|
||||||
|
|
||||||
|
#include "sockaddr.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "nfsd_path.h"
|
||||||
|
#include "nfslib.h"
|
||||||
|
#include "exportfs.h"
|
||||||
|
#include "xlog.h"
|
||||||
|
#include "conffile.h"
|
||||||
|
|
||||||
|
static void export_all(int verbose);
|
||||||
|
static void exportfs(char *arg, char *options, int verbose);
|
||||||
|
static void unexportfs(char *arg, int verbose);
|
||||||
|
static void dump(int verbose, int export_format);
|
||||||
|
static void usage(const char *progname, int n);
|
||||||
|
static void validate_export(nfs_export *exp);
|
||||||
|
static int matchhostname(const char *hostname1, const char *hostname2);
|
||||||
|
static void grab_lockfile(void);
|
||||||
|
static void release_lockfile(void);
|
||||||
|
|
||||||
|
static const char *lockfile = EXP_LOCKFILE;
|
||||||
|
static int _lockfd = -1;
|
||||||
|
|
||||||
|
struct state_paths etab;
|
||||||
|
|
||||||
|
static ssize_t exportfs_write(int fd, const char *buf, size_t len)
|
||||||
|
{
|
||||||
|
return nfsd_path_write(fd, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we aren't careful, changes made by exportfs can be lost
|
||||||
|
* when multiple exports process run at once:
|
||||||
|
*
|
||||||
|
* exportfs process 1 exportfs process 2
|
||||||
|
* ------------------------------------------
|
||||||
|
* reads etab version A reads etab version A
|
||||||
|
* adds new export B adds new export C
|
||||||
|
* writes A+B writes A+C
|
||||||
|
*
|
||||||
|
* The locking in support/export/xtab.c will prevent mountd from
|
||||||
|
* seeing a partially written version of etab, and will prevent
|
||||||
|
* the two writers above from writing simultaneously and
|
||||||
|
* corrupting etab, but to prevent problems like the above we
|
||||||
|
* need these additional lockfile() routines.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
grab_lockfile(void)
|
||||||
|
{
|
||||||
|
_lockfd = open(lockfile, O_CREAT|O_RDWR, 0666);
|
||||||
|
if (_lockfd != -1)
|
||||||
|
lockf(_lockfd, F_LOCK, 0);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
release_lockfile(void)
|
||||||
|
{
|
||||||
|
if (_lockfd != -1) {
|
||||||
|
lockf(_lockfd, F_ULOCK, 0);
|
||||||
|
close(_lockfd);
|
||||||
|
_lockfd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *options = NULL;
|
||||||
|
char *progname = NULL;
|
||||||
|
int f_export = 1;
|
||||||
|
int f_all = 0;
|
||||||
|
int f_verbose = 0;
|
||||||
|
int f_export_format = 0;
|
||||||
|
int f_reexport = 0;
|
||||||
|
int f_ignore = 0;
|
||||||
|
int i, c;
|
||||||
|
int force_flush = 0;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
if ((progname = strrchr(argv[0], '/')) != NULL)
|
||||||
|
progname++;
|
||||||
|
else
|
||||||
|
progname = argv[0];
|
||||||
|
|
||||||
|
xlog_open(progname);
|
||||||
|
xlog_stderr(1);
|
||||||
|
xlog_syslog(0);
|
||||||
|
|
||||||
|
conf_init_file(NFS_CONFFILE);
|
||||||
|
xlog_from_conffile("exportfs");
|
||||||
|
nfsd_path_init();
|
||||||
|
|
||||||
|
/* NOTE: following uses "mountd" section of nfs.conf !!!! */
|
||||||
|
s = conf_get_str("mountd", "state-directory-path");
|
||||||
|
if (s && !state_setup_basedir(argv[0], s))
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, "ad:fhio:ruvs")) != EOF) {
|
||||||
|
switch(c) {
|
||||||
|
case 'a':
|
||||||
|
f_all = 1;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
xlog_sconfig(optarg, 1);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
force_flush = 1;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
usage(progname, 0);
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
f_ignore = 1;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
options = optarg;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
f_reexport = 1;
|
||||||
|
f_all = 1;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
f_export = 0;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
f_verbose = 1;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
f_export_format = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(progname, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind != argc && f_all) {
|
||||||
|
xlog(L_ERROR, "extra arguments are not permitted with -a or -r");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (f_ignore && (f_all || ! f_export)) {
|
||||||
|
xlog(L_ERROR, "-i not meaningful with -a, -r or -u");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (f_reexport && ! f_export) {
|
||||||
|
xlog(L_ERROR, "-r and -u are incompatible");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("point 1\n");
|
||||||
|
if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab))
|
||||||
|
return 1;
|
||||||
|
printf("point 2\n");
|
||||||
|
if (optind == argc && ! f_all) {
|
||||||
|
if (force_flush) {
|
||||||
|
cache_flush(1);
|
||||||
|
free_state_path_names(&etab);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
xtab_export_read();
|
||||||
|
dump(f_verbose, f_export_format);
|
||||||
|
free_state_path_names(&etab);
|
||||||
|
export_freeall();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("point 3\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Serialize things as best we can
|
||||||
|
*/
|
||||||
|
grab_lockfile();
|
||||||
|
atexit(release_lockfile);
|
||||||
|
|
||||||
|
if (f_export && ! f_ignore) {
|
||||||
|
if (! (export_read(_PATH_EXPORTS, 0) +
|
||||||
|
export_d_read(_PATH_EXPORTS_D, 0))) {
|
||||||
|
if (f_verbose)
|
||||||
|
xlog(L_WARNING, "No file systems exported!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (f_export) {
|
||||||
|
if (f_all)
|
||||||
|
export_all(f_verbose);
|
||||||
|
else
|
||||||
|
for (i = optind; i < argc ; i++)
|
||||||
|
exportfs(argv[i], options, f_verbose);
|
||||||
|
}
|
||||||
|
/* If we are unexporting everything, then
|
||||||
|
* don't care about what should be exported, as that
|
||||||
|
* may require DNS lookups..
|
||||||
|
*/
|
||||||
|
if (! ( !f_export && f_all)) {
|
||||||
|
/* note: xtab_*_read does not update entries if they already exist,
|
||||||
|
* so this will not lose new options
|
||||||
|
*/
|
||||||
|
if (!f_reexport)
|
||||||
|
xtab_export_read();
|
||||||
|
if (!f_export)
|
||||||
|
for (i = optind ; i < argc ; i++)
|
||||||
|
unexportfs(argv[i], f_verbose);
|
||||||
|
}
|
||||||
|
xtab_export_write();
|
||||||
|
cache_flush(force_flush);
|
||||||
|
free_state_path_names(&etab);
|
||||||
|
export_freeall();
|
||||||
|
|
||||||
|
return export_errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* export_all finds all entries and
|
||||||
|
* marks them xtabent and mayexport so that they get exported
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
export_all(int verbose)
|
||||||
|
{
|
||||||
|
nfs_export *exp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MCL_MAXTYPES; i++) {
|
||||||
|
for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
|
||||||
|
if (verbose)
|
||||||
|
printf("exporting %s:%s\n",
|
||||||
|
exp->m_client->m_hostname,
|
||||||
|
exp->m_export.e_path);
|
||||||
|
exp->m_xtabent = 1;
|
||||||
|
exp->m_mayexport = 1;
|
||||||
|
exp->m_changed = 1;
|
||||||
|
exp->m_warned = 0;
|
||||||
|
validate_export(exp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
exportfs_parsed(char *hname, char *path, char *options, int verbose)
|
||||||
|
{
|
||||||
|
struct exportent *eep;
|
||||||
|
nfs_export *exp = NULL;
|
||||||
|
struct addrinfo *ai = NULL;
|
||||||
|
int htype;
|
||||||
|
|
||||||
|
if ((htype = client_gettype(hname)) == MCL_FQDN) {
|
||||||
|
ai = host_addrinfo(hname);
|
||||||
|
if (ai != NULL) {
|
||||||
|
exp = export_find(ai, path);
|
||||||
|
hname = ai->ai_canonname;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
exp = export_lookup(hname, path, 0);
|
||||||
|
|
||||||
|
if (!exp) {
|
||||||
|
if (!(eep = mkexportent(hname, path, options)) ||
|
||||||
|
!(exp = export_create(eep, 0)))
|
||||||
|
goto out;
|
||||||
|
} else if (!updateexportent(&exp->m_export, options))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
printf("exporting %s:%s\n", exp->m_client->m_hostname,
|
||||||
|
exp->m_export.e_path);
|
||||||
|
exp->m_xtabent = 1;
|
||||||
|
exp->m_mayexport = 1;
|
||||||
|
exp->m_changed = 1;
|
||||||
|
exp->m_warned = 0;
|
||||||
|
validate_export(exp);
|
||||||
|
|
||||||
|
out:
|
||||||
|
nfs_freeaddrinfo(ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int exportfs_generic(char *arg, char *options, int verbose)
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
if ((path = strchr(arg, ':')) != NULL)
|
||||||
|
*path++ = '\0';
|
||||||
|
|
||||||
|
if (!path || *path != '/')
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
exportfs_parsed(arg, path, options, verbose);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int exportfs_ipv6(char *arg, char *options, int verbose)
|
||||||
|
{
|
||||||
|
char *path, *c;
|
||||||
|
|
||||||
|
arg++;
|
||||||
|
c = strchr(arg, ']');
|
||||||
|
if (c == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* no colon means this is a wildcarded DNS hostname */
|
||||||
|
if (memchr(arg, ':', c - arg) == NULL)
|
||||||
|
return exportfs_generic(--arg, options, verbose);
|
||||||
|
|
||||||
|
path = strstr(c, ":/");
|
||||||
|
if (path == NULL)
|
||||||
|
return 1;
|
||||||
|
*path++ = '\0';
|
||||||
|
|
||||||
|
/* if there's anything between the closing brace and the
|
||||||
|
* path separator, it's probably a prefix length */
|
||||||
|
memmove(c, c + 1, path - c);
|
||||||
|
|
||||||
|
exportfs_parsed(arg, path, options, verbose);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
exportfs(char *arg, char *options, int verbose)
|
||||||
|
{
|
||||||
|
int failed;
|
||||||
|
|
||||||
|
if (*arg == '[')
|
||||||
|
failed = exportfs_ipv6(arg, options, verbose);
|
||||||
|
else
|
||||||
|
failed = exportfs_generic(arg, options, verbose);
|
||||||
|
if (failed)
|
||||||
|
xlog(L_ERROR, "Invalid export syntax: %s", arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
unexportfs_parsed(char *hname, char *path, int verbose)
|
||||||
|
{
|
||||||
|
nfs_export *exp;
|
||||||
|
struct addrinfo *ai = NULL;
|
||||||
|
int htype;
|
||||||
|
int success = 0;
|
||||||
|
|
||||||
|
if ((htype = client_gettype(hname)) == MCL_FQDN) {
|
||||||
|
ai = host_addrinfo(hname);
|
||||||
|
if (ai)
|
||||||
|
hname = ai->ai_canonname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It's possible the specified path ends with a '/'. But
|
||||||
|
* the entry from exportlist won't has the trailing '/',
|
||||||
|
* so need to deal with it.
|
||||||
|
*/
|
||||||
|
size_t nlen = strlen(path);
|
||||||
|
while (path[nlen - 1] == '/')
|
||||||
|
nlen--;
|
||||||
|
|
||||||
|
for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) {
|
||||||
|
if (strlen(exp->m_export.e_path) != nlen)
|
||||||
|
continue;
|
||||||
|
if (path && strncmp(path, exp->m_export.e_path, nlen))
|
||||||
|
continue;
|
||||||
|
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
|
||||||
|
#endif
|
||||||
|
printf("unexporting %s:%s\n",
|
||||||
|
exp->m_client->m_hostname,
|
||||||
|
exp->m_export.e_path);
|
||||||
|
}
|
||||||
|
exp->m_xtabent = 0;
|
||||||
|
exp->m_mayexport = 0;
|
||||||
|
success = 1;
|
||||||
|
}
|
||||||
|
if (!success)
|
||||||
|
xlog(L_ERROR, "Could not find '%s:%s' to unexport.", hname, path);
|
||||||
|
|
||||||
|
nfs_freeaddrinfo(ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int unexportfs_generic(char *arg, int verbose)
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
if ((path = strchr(arg, ':')) != NULL)
|
||||||
|
*path++ = '\0';
|
||||||
|
|
||||||
|
if (!path || *path != '/')
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
unexportfs_parsed(arg, path, verbose);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int unexportfs_ipv6(char *arg, int verbose)
|
||||||
|
{
|
||||||
|
char *path, *c;
|
||||||
|
|
||||||
|
arg++;
|
||||||
|
c = strchr(arg, ']');
|
||||||
|
if (c == NULL)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* no colon means this is a wildcarded DNS hostname */
|
||||||
|
if (memchr(arg, ':', c - arg) == NULL)
|
||||||
|
return unexportfs_generic(--arg, verbose);
|
||||||
|
|
||||||
|
path = strstr(c, ":/");
|
||||||
|
if (path == NULL)
|
||||||
|
return 1;
|
||||||
|
*path++ = '\0';
|
||||||
|
|
||||||
|
/* if there's anything between the closing brace and the
|
||||||
|
* path separator, it's probably a prefix length */
|
||||||
|
memmove(c, c + 1, path - c);
|
||||||
|
|
||||||
|
unexportfs_parsed(arg, path, verbose);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
unexportfs(char *arg, int verbose)
|
||||||
|
{
|
||||||
|
int failed;
|
||||||
|
|
||||||
|
if (*arg == '[')
|
||||||
|
failed = unexportfs_ipv6(arg, verbose);
|
||||||
|
else
|
||||||
|
failed = unexportfs_generic(arg, verbose);
|
||||||
|
if (failed)
|
||||||
|
xlog(L_ERROR, "Invalid export syntax: %s", arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int can_test(void)
|
||||||
|
{
|
||||||
|
char buf[1024] = { 0 };
|
||||||
|
int fd;
|
||||||
|
int n;
|
||||||
|
size_t bufsiz = sizeof(buf);
|
||||||
|
|
||||||
|
fd = open("/proc/net/rpc/auth.unix.ip/channel", O_WRONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We introduce tolerance of 1 day to ensure that we use a
|
||||||
|
* LONG_MAX for the expiry timestamp before it is actually
|
||||||
|
* needed. To use LONG_MAX, the kernel code must have
|
||||||
|
* commit 2f74f972 (sunrpc: prepare NFS for 2038).
|
||||||
|
*/
|
||||||
|
if (time(NULL) > INT_TO_LONG_THRESHOLD_SECS)
|
||||||
|
snprintf(buf, bufsiz-1, "nfsd 0.0.0.0 %ld -test-client-\n", LONG_MAX);
|
||||||
|
else
|
||||||
|
snprintf(buf, bufsiz-1, "nfsd 0.0.0.0 %d -test-client-\n", INT_MAX);
|
||||||
|
|
||||||
|
n = write(fd, buf, strlen(buf));
|
||||||
|
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(nfs_export *exp, int with_fsid)
|
||||||
|
{
|
||||||
|
char *path = exp->m_export.e_path;
|
||||||
|
int flags = exp->m_export.e_flags | (with_fsid ? NFSEXP_FSID : 0);
|
||||||
|
/* beside max path, buf size should take protocol str into account */
|
||||||
|
char buf[NFS_MAXPATHLEN+1+64] = { 0 };
|
||||||
|
char *bp = buf;
|
||||||
|
int len = sizeof(buf);
|
||||||
|
int fd, n;
|
||||||
|
|
||||||
|
n = snprintf(buf, len, "-test-client- ");
|
||||||
|
bp += n;
|
||||||
|
len -= n;
|
||||||
|
qword_add(&bp, &len, path);
|
||||||
|
if (len < 1)
|
||||||
|
return 0;
|
||||||
|
snprintf(bp, len, " 3 %d 65534 65534 0\n", flags);
|
||||||
|
fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
return 0;
|
||||||
|
n = exportfs_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 = exportent_realpath(&exp->m_export);
|
||||||
|
struct statfs64 stf;
|
||||||
|
int fs_has_fsid = 0;
|
||||||
|
|
||||||
|
if (stat(path, &stb) < 0) {
|
||||||
|
xlog(L_ERROR, "Failed to stat %s: %m", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!S_ISDIR(stb.st_mode)) {
|
||||||
|
xlog(L_ERROR, "%s is not a directory. "
|
||||||
|
"Remote access will fail", 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(exp, 1)) {
|
||||||
|
xlog(L_ERROR, "%s does not support NFS export", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if ( !test_export(exp, 0)) {
|
||||||
|
if (test_export(exp, 1))
|
||||||
|
xlog(L_ERROR, "%s requires fsid= for NFS export", path);
|
||||||
|
else
|
||||||
|
xlog(L_ERROR, "%s does not support NFS export", path);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static _Bool
|
||||||
|
is_hostname(const char *sp)
|
||||||
|
{
|
||||||
|
if (*sp == '\0' || *sp == '@')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (; *sp != '\0'; sp++) {
|
||||||
|
if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/')
|
||||||
|
return false;
|
||||||
|
if (*sp == '\\' && sp[1] != '\0')
|
||||||
|
sp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Take care to perform an explicit reverse lookup on presentation
|
||||||
|
* addresses. Otherwise we don't get a real canonical name or a
|
||||||
|
* complete list of addresses.
|
||||||
|
*/
|
||||||
|
static struct addrinfo *
|
||||||
|
address_list(const char *hostname)
|
||||||
|
{
|
||||||
|
struct addrinfo *ai;
|
||||||
|
char *cname;
|
||||||
|
|
||||||
|
ai = host_pton(hostname);
|
||||||
|
if (ai != NULL) {
|
||||||
|
/* @hostname was a presentation address */
|
||||||
|
cname = host_canonname(ai->ai_addr);
|
||||||
|
nfs_freeaddrinfo(ai);
|
||||||
|
if (cname != NULL)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* @hostname was a hostname or had no reverse mapping */
|
||||||
|
cname = strdup(hostname);
|
||||||
|
if (cname == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
out:
|
||||||
|
ai = host_addrinfo(cname);
|
||||||
|
free(cname);
|
||||||
|
return ai;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
matchhostname(const char *hostname1, const char *hostname2)
|
||||||
|
{
|
||||||
|
struct addrinfo *results1 = NULL, *results2 = NULL;
|
||||||
|
struct addrinfo *ai1, *ai2;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
if (strcasecmp(hostname1, hostname2) == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't pass export wildcards or netgroup names to DNS
|
||||||
|
*/
|
||||||
|
if (!is_hostname(hostname1) || !is_hostname(hostname2))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
results1 = address_list(hostname1);
|
||||||
|
if (results1 == NULL)
|
||||||
|
goto out;
|
||||||
|
results2 = address_list(hostname2);
|
||||||
|
if (results2 == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (strcasecmp(results1->ai_canonname, results2->ai_canonname) == 0) {
|
||||||
|
result = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ai1 = results1; ai1 != NULL; ai1 = ai1->ai_next)
|
||||||
|
for (ai2 = results2; ai2 != NULL; ai2 = ai2->ai_next)
|
||||||
|
if (nfs_compare_sockaddr(ai1->ai_addr, ai2->ai_addr)) {
|
||||||
|
result = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
nfs_freeaddrinfo(results1);
|
||||||
|
nfs_freeaddrinfo(results2);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_FUNC_ATTRIBUTE_FORMAT
|
||||||
|
__attribute__((format (printf, 2, 3)))
|
||||||
|
#endif
|
||||||
|
static char
|
||||||
|
dumpopt(char c, char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
printf("%c", c);
|
||||||
|
vprintf(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return ',';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dump(int verbose, int export_format)
|
||||||
|
{
|
||||||
|
/* buf[] size should >= sizeof(struct exportent->e_path) */
|
||||||
|
char buf[NFS_MAXPATHLEN+1] = { 0 };
|
||||||
|
char *bp;
|
||||||
|
int len;
|
||||||
|
nfs_export *exp;
|
||||||
|
struct exportent *ep;
|
||||||
|
int htype;
|
||||||
|
char *hname, c;
|
||||||
|
|
||||||
|
for (htype = 0; htype < MCL_MAXTYPES; htype++) {
|
||||||
|
for (exp = exportlist[htype].p_head; exp; exp = exp->m_next) {
|
||||||
|
ep = &exp->m_export;
|
||||||
|
if (!exp->m_xtabent)
|
||||||
|
continue; /* neilb */
|
||||||
|
if (htype == MCL_ANONYMOUS)
|
||||||
|
hname = (export_format) ? "*" : "<world>";
|
||||||
|
else
|
||||||
|
hname = ep->e_hostname;
|
||||||
|
if (strlen(ep->e_path) > 14 && !export_format)
|
||||||
|
printf("%-14s\n\t\t%s", ep->e_path, hname);
|
||||||
|
else
|
||||||
|
if (export_format) {
|
||||||
|
bp = buf;
|
||||||
|
len = sizeof(buf) - 1;
|
||||||
|
qword_add(&bp, &len, ep->e_path);
|
||||||
|
*bp = '\0';
|
||||||
|
printf("%s %s", buf, hname);
|
||||||
|
} else {
|
||||||
|
printf("%-14s\t%s", ep->e_path, hname);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!verbose && !export_format) {
|
||||||
|
printf("\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
c = '(';
|
||||||
|
if (ep->e_flags & NFSEXP_ASYNC)
|
||||||
|
c = dumpopt(c, "async");
|
||||||
|
else
|
||||||
|
c = dumpopt(c, "sync");
|
||||||
|
if (ep->e_flags & NFSEXP_GATHERED_WRITES)
|
||||||
|
c = dumpopt(c, "wdelay");
|
||||||
|
else
|
||||||
|
c = dumpopt(c, "no_wdelay");
|
||||||
|
if (ep->e_flags & NFSEXP_NOHIDE)
|
||||||
|
c = dumpopt(c, "nohide");
|
||||||
|
else
|
||||||
|
c = dumpopt(c, "hide");
|
||||||
|
if (ep->e_flags & NFSEXP_CROSSMOUNT)
|
||||||
|
c = dumpopt(c, "crossmnt");
|
||||||
|
if (ep->e_flags & NFSEXP_NOSUBTREECHECK)
|
||||||
|
c = dumpopt(c, "no_subtree_check");
|
||||||
|
if (ep->e_flags & NFSEXP_NOAUTHNLM)
|
||||||
|
c = dumpopt(c, "insecure_locks");
|
||||||
|
if (ep->e_flags & NFSEXP_NOREADDIRPLUS)
|
||||||
|
c = dumpopt(c, "nordirplus");
|
||||||
|
if (ep->e_flags & NFSEXP_SECURITY_LABEL)
|
||||||
|
c = dumpopt(c, "security_label");
|
||||||
|
if (ep->e_flags & NFSEXP_NOACL)
|
||||||
|
c = dumpopt(c, "no_acl");
|
||||||
|
if (ep->e_flags & NFSEXP_PNFS)
|
||||||
|
c = dumpopt(c, "pnfs");
|
||||||
|
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 != 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 != '(')? ')' : ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(const char *progname, int n)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "usage: %s [-adfhioruvs] [host:/path]\n", progname);
|
||||||
|
exit(n);
|
||||||
|
}
|
||||||
316
nfs-utils-2.5.2/utils/mountd/auth.c
Normal file
316
nfs-utils-2.5.2/utils/mountd/auth.c
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
/*
|
||||||
|
* utils/mountd/auth.c
|
||||||
|
*
|
||||||
|
* Authentication procedures for mountd.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "sockaddr.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "nfslib.h"
|
||||||
|
#include "exportfs.h"
|
||||||
|
#include "mountd.h"
|
||||||
|
#include "v4root.h"
|
||||||
|
|
||||||
|
enum auth_error
|
||||||
|
{
|
||||||
|
bad_path,
|
||||||
|
unknown_host,
|
||||||
|
no_entry,
|
||||||
|
not_exported,
|
||||||
|
illegal_port,
|
||||||
|
success
|
||||||
|
};
|
||||||
|
|
||||||
|
static void auth_fixpath(char *path);
|
||||||
|
static nfs_export my_exp;
|
||||||
|
static nfs_client my_client;
|
||||||
|
|
||||||
|
extern int use_ipaddr;
|
||||||
|
|
||||||
|
extern struct state_paths etab;
|
||||||
|
|
||||||
|
void
|
||||||
|
auth_init(void)
|
||||||
|
{
|
||||||
|
auth_reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A client can match many different netgroups and it's tough to know
|
||||||
|
* beforehand whether it will. If the concatenated string of netgroup
|
||||||
|
* m_hostnames is >512 bytes, then enable the "use_ipaddr" mode. This
|
||||||
|
* makes mountd change how it matches a client ip address when a mount
|
||||||
|
* request comes in. It's more efficient at handling netgroups at the
|
||||||
|
* expense of larger kernel caches.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
check_useipaddr(void)
|
||||||
|
{
|
||||||
|
nfs_client *clp;
|
||||||
|
int old_use_ipaddr = use_ipaddr;
|
||||||
|
unsigned int len = 0;
|
||||||
|
|
||||||
|
/* add length of m_hostname + 1 for the comma */
|
||||||
|
for (clp = clientlist[MCL_NETGROUP]; clp; clp = clp->m_next)
|
||||||
|
len += (strlen(clp->m_hostname) + 1);
|
||||||
|
|
||||||
|
if (len > (NFSCLNT_IDMAX / 2))
|
||||||
|
use_ipaddr = 1;
|
||||||
|
else
|
||||||
|
use_ipaddr = 0;
|
||||||
|
|
||||||
|
if (use_ipaddr != old_use_ipaddr)
|
||||||
|
cache_flush(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
auth_reload(void)
|
||||||
|
{
|
||||||
|
struct stat stb;
|
||||||
|
static ino_t last_inode;
|
||||||
|
static int last_fd = -1;
|
||||||
|
static unsigned int counter;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if ((fd = open(etab.statefn, O_RDONLY)) < 0) {
|
||||||
|
xlog(L_FATAL, "couldn't open %s", etab.statefn);
|
||||||
|
} else if (fstat(fd, &stb) < 0) {
|
||||||
|
xlog(L_FATAL, "couldn't stat %s", etab.statefn);
|
||||||
|
close(fd);
|
||||||
|
} else if (last_fd != -1 && stb.st_ino == last_inode) {
|
||||||
|
/* We opened the etab file before, and its inode
|
||||||
|
* number hasn't changed since then.
|
||||||
|
*/
|
||||||
|
close(fd);
|
||||||
|
return counter;
|
||||||
|
} else {
|
||||||
|
/* Need to process entries from the etab file. Close
|
||||||
|
* the file descriptor from the previous open (last_fd),
|
||||||
|
* and keep the current file descriptor open to prevent
|
||||||
|
* the file system reusing the current inode number
|
||||||
|
* (last_inode).
|
||||||
|
*/
|
||||||
|
if (last_fd != -1)
|
||||||
|
close(last_fd);
|
||||||
|
last_fd = fd;
|
||||||
|
last_inode = stb.st_ino;
|
||||||
|
}
|
||||||
|
|
||||||
|
export_freeall();
|
||||||
|
memset(&my_client, 0, sizeof(my_client));
|
||||||
|
xtab_export_read();
|
||||||
|
check_useipaddr();
|
||||||
|
v4root_set();
|
||||||
|
|
||||||
|
++counter;
|
||||||
|
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *get_client_ipaddr_name(const struct sockaddr *caller)
|
||||||
|
{
|
||||||
|
char buf[INET6_ADDRSTRLEN + 1];
|
||||||
|
|
||||||
|
buf[0] = '$';
|
||||||
|
host_ntop(caller, buf + 1, sizeof(buf) - 1);
|
||||||
|
return strdup(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
get_client_hostname(const struct sockaddr *caller, struct addrinfo *ai,
|
||||||
|
enum auth_error *error)
|
||||||
|
{
|
||||||
|
char *n;
|
||||||
|
|
||||||
|
if (use_ipaddr)
|
||||||
|
return get_client_ipaddr_name(caller);
|
||||||
|
n = client_compose(ai);
|
||||||
|
*error = unknown_host;
|
||||||
|
if (!n)
|
||||||
|
return NULL;
|
||||||
|
if (*n)
|
||||||
|
return n;
|
||||||
|
free(n);
|
||||||
|
return strdup("DEFAULT");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ipaddr_client_matches(nfs_export *exp, struct addrinfo *ai)
|
||||||
|
{
|
||||||
|
return client_check(exp->m_client, ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool namelist_client_matches(nfs_export *exp, char *dom)
|
||||||
|
{
|
||||||
|
return client_member(dom, exp->m_client->m_hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool client_matches(nfs_export *exp, char *dom, struct addrinfo *ai)
|
||||||
|
{
|
||||||
|
if (is_ipaddr_client(dom))
|
||||||
|
return ipaddr_client_matches(exp, ai);
|
||||||
|
return namelist_client_matches(exp, dom);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return static nfs_export with details filled in */
|
||||||
|
static nfs_export *
|
||||||
|
auth_authenticate_newcache(const struct sockaddr *caller,
|
||||||
|
const char *path, struct addrinfo *ai,
|
||||||
|
enum auth_error *error)
|
||||||
|
{
|
||||||
|
nfs_export *exp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
free(my_client.m_hostname);
|
||||||
|
|
||||||
|
my_client.m_hostname = get_client_hostname(caller, ai, error);
|
||||||
|
if (my_client.m_hostname == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
my_client.m_naddr = 1;
|
||||||
|
set_addrlist(&my_client, 0, caller);
|
||||||
|
my_exp.m_client = &my_client;
|
||||||
|
|
||||||
|
exp = NULL;
|
||||||
|
for (i = 0; !exp && i < MCL_MAXTYPES; i++)
|
||||||
|
for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
|
||||||
|
if (strcmp(path, exp->m_export.e_path))
|
||||||
|
continue;
|
||||||
|
if (!client_matches(exp, my_client.m_hostname, ai))
|
||||||
|
continue;
|
||||||
|
if (exp->m_export.e_flags & NFSEXP_V4ROOT)
|
||||||
|
/* not acceptable for v[23] export */
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*error = not_exported;
|
||||||
|
if (!exp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
my_exp.m_export = exp->m_export;
|
||||||
|
exp = &my_exp;
|
||||||
|
return exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static nfs_export *
|
||||||
|
auth_authenticate_internal(const struct sockaddr *caller, const char *path,
|
||||||
|
struct addrinfo *ai, enum auth_error *error)
|
||||||
|
{
|
||||||
|
nfs_export *exp;
|
||||||
|
|
||||||
|
exp = auth_authenticate_newcache(caller, path, ai, error);
|
||||||
|
if (!exp)
|
||||||
|
return NULL;
|
||||||
|
if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) &&
|
||||||
|
nfs_get_port(caller) >= IPPORT_RESERVED) {
|
||||||
|
*error = illegal_port;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*error = success;
|
||||||
|
|
||||||
|
return exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
nfs_export *
|
||||||
|
auth_authenticate(const char *what, const struct sockaddr *caller,
|
||||||
|
const char *path)
|
||||||
|
{
|
||||||
|
nfs_export *exp = NULL;
|
||||||
|
char epath[MAXPATHLEN+1];
|
||||||
|
char *p = NULL;
|
||||||
|
char buf[INET6_ADDRSTRLEN];
|
||||||
|
struct addrinfo *ai = NULL;
|
||||||
|
enum auth_error error = bad_path;
|
||||||
|
|
||||||
|
if (path[0] != '/') {
|
||||||
|
xlog(L_WARNING, "Bad path in %s request from %s: \"%s\"",
|
||||||
|
what, host_ntop(caller, buf, sizeof(buf)), path);
|
||||||
|
return exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(epath, path, sizeof (epath) - 1);
|
||||||
|
epath[sizeof (epath) - 1] = '\0';
|
||||||
|
auth_fixpath(epath); /* strip duplicate '/' etc */
|
||||||
|
|
||||||
|
ai = client_resolve(caller);
|
||||||
|
if (ai == NULL)
|
||||||
|
return exp;
|
||||||
|
|
||||||
|
/* Try the longest matching exported pathname. */
|
||||||
|
while (1) {
|
||||||
|
exp = auth_authenticate_internal(caller, epath, ai, &error);
|
||||||
|
if (exp || (error != not_exported && error != no_entry))
|
||||||
|
break;
|
||||||
|
/* We have to treat the root, "/", specially. */
|
||||||
|
if (p == &epath[1]) break;
|
||||||
|
p = strrchr(epath, '/');
|
||||||
|
if (p == epath) p++;
|
||||||
|
*p = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
host_ntop(caller, buf, sizeof(buf));
|
||||||
|
switch (error) {
|
||||||
|
case bad_path:
|
||||||
|
xlog(L_WARNING, "bad path in %s request from %s: \"%s\"",
|
||||||
|
what, buf, path);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case unknown_host:
|
||||||
|
xlog(L_WARNING, "refused %s request from %s for %s (%s): unmatched host",
|
||||||
|
what, buf, path, epath);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case no_entry:
|
||||||
|
xlog(L_WARNING, "refused %s request from %s for %s (%s): no export entry",
|
||||||
|
what, buf, path, epath);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case not_exported:
|
||||||
|
xlog(L_WARNING, "refused %s request from %s for %s (%s): not exported",
|
||||||
|
what, buf, path, epath);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case illegal_port:
|
||||||
|
xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %u",
|
||||||
|
what, buf, path, epath, nfs_get_port(caller));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case success:
|
||||||
|
xlog(L_NOTICE, "authenticated %s request from %s:%u for %s (%s)",
|
||||||
|
what, buf, nfs_get_port(caller), path, epath);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
xlog(L_NOTICE, "%s request from %s:%u for %s (%s) gave %d",
|
||||||
|
what, buf, nfs_get_port(caller), path, epath, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
nfs_freeaddrinfo(ai);
|
||||||
|
return exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
auth_fixpath(char *path)
|
||||||
|
{
|
||||||
|
char *sp, *cp;
|
||||||
|
|
||||||
|
for (sp = cp = path; *sp; sp++) {
|
||||||
|
if (*sp != '/' || sp[1] != '/')
|
||||||
|
*cp++ = *sp;
|
||||||
|
}
|
||||||
|
while (cp > path+1 && cp[-1] == '/')
|
||||||
|
cp--;
|
||||||
|
*cp = '\0';
|
||||||
|
}
|
||||||
214
nfs-utils-2.5.2/utils/mountd/v4root.c
Normal file
214
nfs-utils-2.5.2/utils/mountd/v4root.c
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 Red Hat <nfs@redhat.com>
|
||||||
|
*
|
||||||
|
* support/export/v4root.c
|
||||||
|
*
|
||||||
|
* Routines used to support NFSv4 pseudo roots
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "xlog.h"
|
||||||
|
#include "exportfs.h"
|
||||||
|
#include "nfslib.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "v4root.h"
|
||||||
|
#include "pseudoflavors.h"
|
||||||
|
|
||||||
|
static nfs_export pseudo_root = {
|
||||||
|
.m_next = NULL,
|
||||||
|
.m_client = NULL,
|
||||||
|
.m_export = {
|
||||||
|
.e_hostname = "*",
|
||||||
|
.e_path = "/",
|
||||||
|
.e_flags = NFSEXP_READONLY | NFSEXP_ROOTSQUASH
|
||||||
|
| NFSEXP_NOSUBTREECHECK | NFSEXP_FSID
|
||||||
|
| NFSEXP_V4ROOT,
|
||||||
|
.e_anonuid = 65534,
|
||||||
|
.e_anongid = 65534,
|
||||||
|
.e_squids = NULL,
|
||||||
|
.e_nsquids = 0,
|
||||||
|
.e_sqgids = NULL,
|
||||||
|
.e_nsqgids = 0,
|
||||||
|
.e_fsid = 0,
|
||||||
|
.e_mountpoint = NULL,
|
||||||
|
.e_ttl = DEFAULT_TTL,
|
||||||
|
},
|
||||||
|
.m_exported = 0,
|
||||||
|
.m_xtabent = 1,
|
||||||
|
.m_mayexport = 1,
|
||||||
|
.m_changed = 0,
|
||||||
|
.m_warned = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_pseudofs_security(struct exportent *pseudo, int flags)
|
||||||
|
{
|
||||||
|
struct flav_info *flav;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (flags & NFSEXP_INSECURE_PORT)
|
||||||
|
pseudo->e_flags |= NFSEXP_INSECURE_PORT;
|
||||||
|
if ((flags & NFSEXP_ROOTSQUASH) == 0)
|
||||||
|
pseudo->e_flags &= ~NFSEXP_ROOTSQUASH;
|
||||||
|
for (flav = flav_map; flav < flav_map + flav_map_size; flav++) {
|
||||||
|
struct sec_entry *new;
|
||||||
|
|
||||||
|
if (!flav->fnum)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
i = secinfo_addflavor(flav, pseudo);
|
||||||
|
new = &pseudo->e_secinfo[i];
|
||||||
|
|
||||||
|
if (flags & NFSEXP_INSECURE_PORT)
|
||||||
|
new->flags |= NFSEXP_INSECURE_PORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a pseudo export
|
||||||
|
*/
|
||||||
|
static struct exportent *
|
||||||
|
v4root_create(char *path, nfs_export *export)
|
||||||
|
{
|
||||||
|
nfs_export *exp;
|
||||||
|
struct exportent eep;
|
||||||
|
struct exportent *curexp = &export->m_export;
|
||||||
|
|
||||||
|
dupexportent(&eep, &pseudo_root.m_export);
|
||||||
|
eep.e_hostname = curexp->e_hostname;
|
||||||
|
strncpy(eep.e_path, path, sizeof(eep.e_path)-1);
|
||||||
|
if (strcmp(path, "/") != 0)
|
||||||
|
eep.e_flags &= ~NFSEXP_FSID;
|
||||||
|
set_pseudofs_security(&eep, curexp->e_flags);
|
||||||
|
exp = export_create(&eep, 0);
|
||||||
|
if (exp == NULL)
|
||||||
|
return NULL;
|
||||||
|
xlog(D_CALL, "v4root_create: path '%s' flags 0x%x",
|
||||||
|
exp->m_export.e_path, exp->m_export.e_flags);
|
||||||
|
return &exp->m_export;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure the kernel has pseudo root support.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
v4root_support(void)
|
||||||
|
{
|
||||||
|
struct export_features *ef;
|
||||||
|
static int warned = 0;
|
||||||
|
|
||||||
|
ef = get_export_features();
|
||||||
|
|
||||||
|
if (ef->flags & NFSEXP_V4ROOT)
|
||||||
|
return 1;
|
||||||
|
if (!warned) {
|
||||||
|
xlog(L_WARNING, "Kernel does not have pseudo root support.");
|
||||||
|
xlog(L_WARNING, "NFS v4 mounts will be disabled unless fsid=0");
|
||||||
|
xlog(L_WARNING, "is specfied in /etc/exports file.");
|
||||||
|
warned++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pseudofs_update(char *hostname, char *path, nfs_export *source)
|
||||||
|
{
|
||||||
|
nfs_export *exp;
|
||||||
|
|
||||||
|
exp = export_lookup(hostname, path, 0);
|
||||||
|
if (exp && !(exp->m_export.e_flags & NFSEXP_V4ROOT))
|
||||||
|
return 0;
|
||||||
|
if (!exp) {
|
||||||
|
if (v4root_create(path, source) == NULL) {
|
||||||
|
xlog(L_WARNING, "v4root_set: Unable to create "
|
||||||
|
"pseudo export for '%s'", path);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Update an existing V4ROOT export: */
|
||||||
|
set_pseudofs_security(&exp->m_export, source->m_export.e_flags);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int v4root_add_parents(nfs_export *exp)
|
||||||
|
{
|
||||||
|
char *hostname = exp->m_export.e_hostname;
|
||||||
|
char *path;
|
||||||
|
char *ptr;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
path = strdup(exp->m_export.e_path);
|
||||||
|
if (!path) {
|
||||||
|
xlog(L_WARNING, "v4root_add_parents: Unable to create "
|
||||||
|
"pseudo export for '%s'", exp->m_export.e_path);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
for (ptr = path; ptr; ptr = strchr(ptr, '/')) {
|
||||||
|
char saved;
|
||||||
|
|
||||||
|
saved = *ptr;
|
||||||
|
*ptr = '\0';
|
||||||
|
ret = pseudofs_update(hostname, *path ? path : "/", exp);
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
*ptr = saved;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
free(path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create pseudo exports by running through the real export
|
||||||
|
* looking at the components of the path that make up the export.
|
||||||
|
* Those path components, if not exported, will become pseudo
|
||||||
|
* exports allowing them to be found when the kernel does an upcall
|
||||||
|
* looking for components of the v4 mount.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
v4root_set(void)
|
||||||
|
{
|
||||||
|
nfs_export *exp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!v4root_needed)
|
||||||
|
return;
|
||||||
|
if (!v4root_support())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < MCL_MAXTYPES; i++) {
|
||||||
|
for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
|
||||||
|
if (exp->m_export.e_flags & NFSEXP_V4ROOT)
|
||||||
|
/*
|
||||||
|
* We just added this one, so its
|
||||||
|
* parents are already dealt with!
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strcmp(exp->m_export.e_path, "/") == 0 &&
|
||||||
|
!(exp->m_export.e_flags & NFSEXP_FSID)) {
|
||||||
|
/* Force '/' to be exported as fsid == 0*/
|
||||||
|
exp->m_export.e_flags |= NFSEXP_FSID;
|
||||||
|
exp->m_export.e_fsid = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
v4root_add_parents(exp);
|
||||||
|
/* XXX: error handling! */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user