6450 lines
174 KiB
Diff
6450 lines
174 KiB
Diff
|
diff --git a/.gitignore b/.gitignore
|
||
|
index f17db9c..692ab0e 100644
|
||
|
--- a/.gitignore
|
||
|
+++ b/.gitignore
|
||
|
@@ -72,6 +72,7 @@ tests/nsm_client/nlm_sm_inter_clnt.c
|
||
|
tests/nsm_client/nlm_sm_inter_svc.c
|
||
|
tests/nsm_client/nlm_sm_inter_xdr.c
|
||
|
utils/nfsidmap/nfsidmap
|
||
|
+utils/nfsref/nfsref
|
||
|
systemd/nfs-server-generator
|
||
|
systemd/rpc-pipefs-generator
|
||
|
systemd/nfs-config.service
|
||
|
diff --git a/aclocal/libxml2.m4 b/aclocal/libxml2.m4
|
||
|
new file mode 100644
|
||
|
index 0000000..5c399b2
|
||
|
--- /dev/null
|
||
|
+++ b/aclocal/libxml2.m4
|
||
|
@@ -0,0 +1,15 @@
|
||
|
+dnl Checks for libxml2.so
|
||
|
+AC_DEFUN([AC_LIBXML2], [
|
||
|
+
|
||
|
+ if test "$enable_junction" = yes; then
|
||
|
+
|
||
|
+ dnl look for the library; do not add to LIBS if found
|
||
|
+ AC_CHECK_LIB([xml2], [xmlParseFile], [LIBXML2=-lxml2],
|
||
|
+ [AC_MSG_ERROR([libxml2 not found.])])
|
||
|
+ AC_SUBST(LIBXML2)
|
||
|
+
|
||
|
+ dnl XXX should also check for presence of xml headers
|
||
|
+
|
||
|
+ fi
|
||
|
+
|
||
|
+])dnl
|
||
|
diff --git a/configure.ac b/configure.ac
|
||
|
index 672dd40..5a11636 100644
|
||
|
--- a/configure.ac
|
||
|
+++ b/configure.ac
|
||
|
@@ -180,6 +180,13 @@ else
|
||
|
enable_libmount=no
|
||
|
fi
|
||
|
|
||
|
+AC_ARG_ENABLE(junction,
|
||
|
+ [AC_HELP_STRING([--enable-junction],
|
||
|
+ [enable support for NFS junctions @<:@default=no@:>@])],
|
||
|
+ enable_junction=$enableval,
|
||
|
+ enable_junction=no)
|
||
|
+AM_CONDITIONAL(CONFIG_JUNCTION, [test "$enable_junction" = "yes" ])
|
||
|
+
|
||
|
AC_ARG_ENABLE(tirpc,
|
||
|
[AC_HELP_STRING([--disable-tirpc],
|
||
|
[disable use of TI-RPC library @<:@default=no@:>@])],
|
||
|
@@ -244,6 +251,9 @@ AC_LIBTIRPC
|
||
|
dnl Check for -lcap
|
||
|
AC_LIBCAP
|
||
|
|
||
|
+dnl Check for -lxml2
|
||
|
+AC_LIBXML2
|
||
|
+
|
||
|
# Check whether user wants TCP wrappers support
|
||
|
AC_TCP_WRAPPERS
|
||
|
|
||
|
@@ -298,8 +308,6 @@ AC_CHECK_FUNC([getservbyname], ,
|
||
|
|
||
|
AC_CHECK_LIB([crypt], [crypt], [LIBCRYPT="-lcrypt"])
|
||
|
|
||
|
-AC_CHECK_LIB([dl], [dlclose], [LIBDL="-ldl"])
|
||
|
-
|
||
|
if test "$enable_nfsv4" = yes; then
|
||
|
dnl check for libevent libraries and headers
|
||
|
AC_LIBEVENT
|
||
|
@@ -362,7 +370,6 @@ AC_SUBST(LIBSOCKET)
|
||
|
AC_SUBST(LIBCRYPT)
|
||
|
AC_SUBST(LIBBSD)
|
||
|
AC_SUBST(LIBBLKID)
|
||
|
-AC_SUBST(LIBDL)
|
||
|
|
||
|
if test "$enable_libmount" = yes; then
|
||
|
AC_CHECK_LIB(mount, mnt_context_do_mount, [LIBMOUNT="-lmount"], AC_MSG_ERROR([libmount needed]))
|
||
|
@@ -441,7 +448,7 @@ if test -n "$path_plugins" ; then
|
||
|
fi
|
||
|
AM_CONDITIONAL(PATH_PLUGINS, test -n "$path_plugins")
|
||
|
|
||
|
-AC_SUBST(AM_CPPFLAGS, "$AM_CPPFLAGS -I../../support/nfsidmap")
|
||
|
+AC_SUBST(AM_CPPFLAGS, "$AM_CPPFLAGS")
|
||
|
AC_DEFINE([HAVE_NFS4_SET_DEBUG], 1,
|
||
|
[Bundled lib always has the `nfs4_set_debug' function.])
|
||
|
|
||
|
@@ -456,7 +463,7 @@ AC_CHECK_HEADERS([arpa/inet.h fcntl.h libintl.h limits.h \
|
||
|
stdlib.h string.h sys/file.h sys/ioctl.h sys/mount.h \
|
||
|
sys/param.h sys/socket.h sys/time.h sys/vfs.h \
|
||
|
syslog.h unistd.h com_err.h et/com_err.h \
|
||
|
- ifaddrs.h nfs-plugin.h libio.h])
|
||
|
+ ifaddrs.h])
|
||
|
|
||
|
dnl *************************************************************
|
||
|
dnl Checks for typedefs, structures, and compiler characteristics
|
||
|
@@ -536,22 +543,46 @@ AC_SUBST(CXXFLAGS_FOR_BUILD)
|
||
|
AC_SUBST(CPPFLAGS_FOR_BUILD)
|
||
|
AC_SUBST(LDFLAGS_FOR_BUILD)
|
||
|
|
||
|
-dnl *************************************************************
|
||
|
-dnl Set up "global" CFLAGS
|
||
|
-dnl *************************************************************
|
||
|
-dnl Use architecture-specific compile flags
|
||
|
-dnl (We use $host and not $build in case we are cross-compiling)
|
||
|
-dnl *************************************************************
|
||
|
-dnl Note: we no longer have arch specific compile flags, but
|
||
|
-dnl the stub is left here in case they are needed one day.
|
||
|
-case $host in
|
||
|
- *)
|
||
|
- ARCHFLAGS="" ;;
|
||
|
-esac
|
||
|
-
|
||
|
-my_am_cflags="-Wall -Wextra -Wstrict-prototypes $ARCHFLAGS -pipe"
|
||
|
-
|
||
|
-AC_SUBST([AM_CFLAGS], ["$my_am_cflags"])
|
||
|
+my_am_cflags="\
|
||
|
+ -pipe \
|
||
|
+ -Wall \
|
||
|
+ -Wextra \
|
||
|
+ -Werror=strict-prototypes \
|
||
|
+ -Werror=missing-prototypes \
|
||
|
+ -Werror=missing-declarations \
|
||
|
+ -Werror=format=2 \
|
||
|
+ -Werror=undef \
|
||
|
+ -Werror=missing-include-dirs \
|
||
|
+ -Werror=strict-aliasing=2 \
|
||
|
+ -Werror=init-self \
|
||
|
+ -Werror=implicit-function-declaration \
|
||
|
+ -Werror=return-type \
|
||
|
+ -Werror=switch \
|
||
|
+ -Werror=overflow \
|
||
|
+ -Werror=parentheses \
|
||
|
+ -Werror=aggregate-return \
|
||
|
+ -Werror=unused-result \
|
||
|
+ -fno-strict-aliasing \
|
||
|
+"
|
||
|
+
|
||
|
+AC_DEFUN([CHECK_CCSUPPORT], [
|
||
|
+ my_save_cflags="$CFLAGS"
|
||
|
+ CFLAGS=$1
|
||
|
+ AC_MSG_CHECKING([whether CC supports $1])
|
||
|
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
|
||
|
+ [AC_MSG_RESULT([yes])]
|
||
|
+ [$2+=$1],
|
||
|
+ [AC_MSG_RESULT([no])]
|
||
|
+ )
|
||
|
+ CFLAGS="$my_save_cflags"
|
||
|
+])
|
||
|
+
|
||
|
+CHECK_CCSUPPORT([-Werror=format-overflow=2], [flg1])
|
||
|
+CHECK_CCSUPPORT([-Werror=int-conversion], [flg2])
|
||
|
+CHECK_CCSUPPORT([-Werror=incompatible-pointer-types], [flg3])
|
||
|
+CHECK_CCSUPPORT([-Werror=misleading-indentation], [flg4])
|
||
|
+
|
||
|
+AC_SUBST([AM_CFLAGS], ["$my_am_cflags $flg1 $flg2 $flg3 $flg4"])
|
||
|
|
||
|
# Make sure that $ACLOCAL_FLAGS are used during a rebuild
|
||
|
AC_SUBST([ACLOCAL_AMFLAGS], ["-I $ac_macro_dir \$(ACLOCAL_FLAGS)"])
|
||
|
@@ -572,6 +603,7 @@ AC_CONFIG_FILES([
|
||
|
support/include/sys/fs/Makefile
|
||
|
support/include/sys/Makefile
|
||
|
support/include/Makefile
|
||
|
+ support/junction/Makefile
|
||
|
support/misc/Makefile
|
||
|
support/nfs/Makefile
|
||
|
support/nsm/Makefile
|
||
|
@@ -593,6 +625,7 @@ AC_CONFIG_FILES([
|
||
|
utils/mount/Makefile
|
||
|
utils/mountd/Makefile
|
||
|
utils/nfsd/Makefile
|
||
|
+ utils/nfsref/Makefile
|
||
|
utils/nfsstat/Makefile
|
||
|
utils/nfsidmap/Makefile
|
||
|
utils/showmount/Makefile
|
||
|
diff --git a/support/Makefile.am b/support/Makefile.am
|
||
|
index 8365d3b..c962d4d 100644
|
||
|
--- a/support/Makefile.am
|
||
|
+++ b/support/Makefile.am
|
||
|
@@ -6,6 +6,10 @@ if CONFIG_NFSV4
|
||
|
OPTDIRS += nfsidmap
|
||
|
endif
|
||
|
|
||
|
+if CONFIG_JUNCTION
|
||
|
+OPTDIRS += junction
|
||
|
+endif
|
||
|
+
|
||
|
SUBDIRS = export include misc nfs nsm $(OPTDIRS)
|
||
|
|
||
|
MAINTAINERCLEANFILES = Makefile.in
|
||
|
diff --git a/support/export/Makefile.am b/support/export/Makefile.am
|
||
|
index be3de69..13f7a49 100644
|
||
|
--- a/support/export/Makefile.am
|
||
|
+++ b/support/export/Makefile.am
|
||
|
@@ -35,7 +35,7 @@ $(GENFILES_CLNT): %_clnt.c: %.x $(RPCGEN)
|
||
|
|
||
|
$(GENFILES_XDR): %_xdr.c: %.x $(RPCGEN)
|
||
|
test -f $@ && rm -rf $@ || true
|
||
|
- $(RPCGEN) -c -o $@ $<
|
||
|
+ $(RPCGEN) -c -i 0 -o $@ $<
|
||
|
|
||
|
$(GENFILES_H): %.h: %.x $(RPCGEN)
|
||
|
test -f $@ && rm -rf $@ || true
|
||
|
diff --git a/support/include/Makefile.am b/support/include/Makefile.am
|
||
|
index 5c80c8b..599f500 100644
|
||
|
--- a/support/include/Makefile.am
|
||
|
+++ b/support/include/Makefile.am
|
||
|
@@ -6,6 +6,7 @@ noinst_HEADERS = \
|
||
|
cld.h \
|
||
|
exportfs.h \
|
||
|
ha-callout.h \
|
||
|
+ junction.h \
|
||
|
misc.h \
|
||
|
nfs_mntent.h \
|
||
|
nfs_paths.h \
|
||
|
diff --git a/support/include/junction.h b/support/include/junction.h
|
||
|
new file mode 100644
|
||
|
index 0000000..7257d80
|
||
|
--- /dev/null
|
||
|
+++ b/support/include/junction.h
|
||
|
@@ -0,0 +1,167 @@
|
||
|
+/*
|
||
|
+ * @file support/include/junction.h
|
||
|
+ * @brief Declarations for libjunction.a
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Copyright 2010, 2018 Oracle. All rights reserved.
|
||
|
+ *
|
||
|
+ * This file is part of nfs-utils.
|
||
|
+ *
|
||
|
+ * nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License version 2.0 as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License version 2.0 for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * version 2.0 along with nfs-utils. If not, see:
|
||
|
+ *
|
||
|
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+ */
|
||
|
+
|
||
|
+#ifndef _NFS_JUNCTION_H_
|
||
|
+#define _NFS_JUNCTION_H_
|
||
|
+
|
||
|
+#include <stdint.h>
|
||
|
+
|
||
|
+/*
|
||
|
+ * The libjunction APIs use the status codes from the FedFS ADMIN
|
||
|
+ * protocol, which includes non-errno codes like FEDFS_ERR_NOTJUNCT.
|
||
|
+ */
|
||
|
+enum FedFsStatus {
|
||
|
+ FEDFS_OK = 0,
|
||
|
+ FEDFS_ERR_ACCESS = 1,
|
||
|
+ FEDFS_ERR_BADCHAR = 2,
|
||
|
+ FEDFS_ERR_BADNAME = 3,
|
||
|
+ FEDFS_ERR_NAMETOOLONG = 4,
|
||
|
+ FEDFS_ERR_LOOP = 5,
|
||
|
+ FEDFS_ERR_BADXDR = 6,
|
||
|
+ FEDFS_ERR_EXIST = 7,
|
||
|
+ FEDFS_ERR_INVAL = 8,
|
||
|
+ FEDFS_ERR_IO = 9,
|
||
|
+ FEDFS_ERR_NOSPC = 10,
|
||
|
+ FEDFS_ERR_NOTJUNCT = 11,
|
||
|
+ FEDFS_ERR_NOTLOCAL = 12,
|
||
|
+ FEDFS_ERR_PERM = 13,
|
||
|
+ FEDFS_ERR_ROFS = 14,
|
||
|
+ FEDFS_ERR_SVRFAULT = 15,
|
||
|
+ FEDFS_ERR_NOTSUPP = 16,
|
||
|
+ FEDFS_ERR_NSDB_ROUTE = 17,
|
||
|
+ FEDFS_ERR_NSDB_DOWN = 18,
|
||
|
+ FEDFS_ERR_NSDB_CONN = 19,
|
||
|
+ FEDFS_ERR_NSDB_AUTH = 20,
|
||
|
+ FEDFS_ERR_NSDB_LDAP = 21,
|
||
|
+ FEDFS_ERR_NSDB_LDAP_VAL = 22,
|
||
|
+ FEDFS_ERR_NSDB_NONCE = 23,
|
||
|
+ FEDFS_ERR_NSDB_NOFSN = 24,
|
||
|
+ FEDFS_ERR_NSDB_NOFSL = 25,
|
||
|
+ FEDFS_ERR_NSDB_RESPONSE = 26,
|
||
|
+ FEDFS_ERR_NSDB_FAULT = 27,
|
||
|
+ FEDFS_ERR_NSDB_PARAMS = 28,
|
||
|
+ FEDFS_ERR_NSDB_LDAP_REFERRAL = 29,
|
||
|
+ FEDFS_ERR_NSDB_LDAP_REFERRAL_VAL = 30,
|
||
|
+ FEDFS_ERR_NSDB_LDAP_REFERRAL_NOTFOLLOWED = 31,
|
||
|
+ FEDFS_ERR_NSDB_PARAMS_LDAP_REFERRAL = 32,
|
||
|
+ FEDFS_ERR_PATH_TYPE_UNSUPP = 33,
|
||
|
+ FEDFS_ERR_DELAY = 34,
|
||
|
+ FEDFS_ERR_NO_CACHE = 35,
|
||
|
+ FEDFS_ERR_UNKNOWN_CACHE = 36,
|
||
|
+ FEDFS_ERR_NO_CACHE_UPDATE = 37,
|
||
|
+};
|
||
|
+typedef enum FedFsStatus FedFsStatus;
|
||
|
+
|
||
|
+/**
|
||
|
+ * Contains NFS fileset location information
|
||
|
+ *
|
||
|
+ * Each of these represents one server:/rootpath pair. The NFS
|
||
|
+ * implementation can coalesce multiple pairs into a single
|
||
|
+ * fs_location4 result if jfl_rootpath is the same across
|
||
|
+ * multiple servers.
|
||
|
+ *
|
||
|
+ * The nfl_server field can contain either one presentation format
|
||
|
+ * IP address or one DNS hostname.
|
||
|
+ *
|
||
|
+ * See Section 11.9 and 11.10 of RFC 5661 or section 4.2.2.3 and
|
||
|
+ * 4.2.2.4 of the NSDB protocol draft for details.
|
||
|
+ */
|
||
|
+
|
||
|
+struct nfs_fsloc {
|
||
|
+ struct nfs_fsloc *nfl_next;
|
||
|
+
|
||
|
+ char *nfl_hostname;
|
||
|
+ uint16_t nfl_hostport;
|
||
|
+ char **nfl_rootpath;
|
||
|
+
|
||
|
+ struct {
|
||
|
+ _Bool nfl_varsub;
|
||
|
+ } nfl_flags;
|
||
|
+ int32_t nfl_currency;
|
||
|
+ int32_t nfl_validfor;
|
||
|
+
|
||
|
+ struct {
|
||
|
+ _Bool nfl_writable, nfl_going, nfl_split;
|
||
|
+ } nfl_genflags;
|
||
|
+ struct {
|
||
|
+ _Bool nfl_rdma;
|
||
|
+ } nfl_transflags;
|
||
|
+ struct {
|
||
|
+ uint8_t nfl_simul, nfl_handle, nfl_fileid;
|
||
|
+ uint8_t nfl_writever, nfl_change, nfl_readdir;
|
||
|
+ uint8_t nfl_readrank, nfl_writerank;
|
||
|
+ uint8_t nfl_readorder, nfl_writeorder;
|
||
|
+ } nfl_info;
|
||
|
+};
|
||
|
+
|
||
|
+
|
||
|
+/**
|
||
|
+ ** NFS location data management functions
|
||
|
+ **/
|
||
|
+
|
||
|
+void nfs_free_location(struct nfs_fsloc *location);
|
||
|
+void nfs_free_locations(struct nfs_fsloc *locations);
|
||
|
+struct nfs_fsloc *nfs_new_location(void);
|
||
|
+
|
||
|
+__attribute_malloc__
|
||
|
+char **nfs_dup_string_array(char **array);
|
||
|
+void nfs_free_string_array(char **array);
|
||
|
+
|
||
|
+
|
||
|
+/**
|
||
|
+ ** NFS junction management functions
|
||
|
+ **/
|
||
|
+
|
||
|
+FedFsStatus nfs_delete_junction(const char *pathname);
|
||
|
+FedFsStatus nfs_add_junction(const char *pathname,
|
||
|
+ struct nfs_fsloc *locations);
|
||
|
+FedFsStatus nfs_get_locations(const char *pathname,
|
||
|
+ struct nfs_fsloc **locations);
|
||
|
+FedFsStatus nfs_is_prejunction(const char *pathname);
|
||
|
+FedFsStatus nfs_is_junction(const char *pathname);
|
||
|
+
|
||
|
+
|
||
|
+/**
|
||
|
+ ** Flush kernel NFS server's export cache
|
||
|
+ **/
|
||
|
+FedFsStatus junction_flush_exports_cache(void);
|
||
|
+
|
||
|
+/**
|
||
|
+ ** Pathname conversion helpers
|
||
|
+ **/
|
||
|
+void nsdb_free_string_array(char **strings);
|
||
|
+FedFsStatus nsdb_path_array_to_posix(char * const *path_array,
|
||
|
+ char **pathname);
|
||
|
+FedFsStatus nsdb_posix_to_path_array(const char *pathname,
|
||
|
+ char ***path_array);
|
||
|
+
|
||
|
+/**
|
||
|
+ ** Readability helpers
|
||
|
+ **/
|
||
|
+
|
||
|
+const char *nsdb_display_fedfsstatus(const FedFsStatus status);
|
||
|
+void nsdb_print_fedfsstatus(const FedFsStatus status);
|
||
|
+
|
||
|
+#endif /* !_NFS_JUNCTION_H_ */
|
||
|
diff --git a/support/include/sockaddr.h b/support/include/sockaddr.h
|
||
|
index 446b537..eeebcdf 100644
|
||
|
--- a/support/include/sockaddr.h
|
||
|
+++ b/support/include/sockaddr.h
|
||
|
@@ -24,9 +24,7 @@
|
||
|
#include <config.h>
|
||
|
#endif
|
||
|
|
||
|
-#ifdef HAVE_LIBIO_H
|
||
|
-#include <libio.h>
|
||
|
-#endif
|
||
|
+#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <sys/socket.h>
|
||
|
diff --git a/support/junction/Makefile.am b/support/junction/Makefile.am
|
||
|
new file mode 100644
|
||
|
index 0000000..97e7426
|
||
|
--- /dev/null
|
||
|
+++ b/support/junction/Makefile.am
|
||
|
@@ -0,0 +1,34 @@
|
||
|
+##
|
||
|
+## @file support/junction/Makefile.am
|
||
|
+## @brief Process this file with automake to produce src/libjunction/Makefile.in
|
||
|
+##
|
||
|
+
|
||
|
+##
|
||
|
+## Copyright 2010, 2018 Oracle. All rights reserved.
|
||
|
+##
|
||
|
+## This file is part of nfs-utils.
|
||
|
+##
|
||
|
+## nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+## it under the terms of the GNU General Public License version 2.0 as
|
||
|
+## published by the Free Software Foundation.
|
||
|
+##
|
||
|
+## nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+## WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+## GNU General Public License version 2.0 for more details.
|
||
|
+##
|
||
|
+## You should have received a copy of the GNU General Public License
|
||
|
+## version 2.0 along with nfs-utils. If not, see:
|
||
|
+##
|
||
|
+## http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+##
|
||
|
+
|
||
|
+noinst_HEADERS = junction-internal.h
|
||
|
+
|
||
|
+noinst_LTLIBRARIES = libjunction.la
|
||
|
+libjunction_la_SOURCES = display.c export-cache.c junction.c \
|
||
|
+ locations.c nfs.c path.c xml.c
|
||
|
+
|
||
|
+MAINTAINERCLEANFILES = Makefile.in
|
||
|
+
|
||
|
+AM_CPPFLAGS = -I. -I../include -I/usr/include/libxml2
|
||
|
diff --git a/support/junction/display.c b/support/junction/display.c
|
||
|
new file mode 100644
|
||
|
index 0000000..e1e1af1
|
||
|
--- /dev/null
|
||
|
+++ b/support/junction/display.c
|
||
|
@@ -0,0 +1,139 @@
|
||
|
+/**
|
||
|
+ * @file support/junction/display.c
|
||
|
+ * @brief Shared display helper functions
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Copyright 2010, 2018 Oracle. All rights reserved.
|
||
|
+ *
|
||
|
+ * This file is part of nfs-utils.
|
||
|
+ *
|
||
|
+ * nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License version 2.0 as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License version 2.0 for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * version 2.0 along with nfs-utils. If not, see:
|
||
|
+ *
|
||
|
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+ */
|
||
|
+
|
||
|
+#include <stdbool.h>
|
||
|
+#include <stdint.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <string.h>
|
||
|
+
|
||
|
+#include "junction.h"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Return human-readable equivalent of a FedFsStatus value
|
||
|
+ *
|
||
|
+ * @param status FedFsStatus code
|
||
|
+ * @return a static NUL-terminated C string
|
||
|
+ */
|
||
|
+const char *
|
||
|
+nsdb_display_fedfsstatus(const FedFsStatus status)
|
||
|
+{
|
||
|
+ switch (status) {
|
||
|
+ case FEDFS_OK:
|
||
|
+ return "FEDFS_OK";
|
||
|
+ case FEDFS_ERR_ACCESS:
|
||
|
+ return "FEDFS_ERR_ACCESS";
|
||
|
+ case FEDFS_ERR_BADCHAR:
|
||
|
+ return "FEDFS_ERR_BADCHAR";
|
||
|
+ case FEDFS_ERR_BADNAME:
|
||
|
+ return "FEDFS_ERR_BADNAME";
|
||
|
+ case FEDFS_ERR_NAMETOOLONG:
|
||
|
+ return "FEDFS_ERR_NAMETOOLONG";
|
||
|
+ case FEDFS_ERR_LOOP:
|
||
|
+ return "FEDFS_ERR_LOOP";
|
||
|
+ case FEDFS_ERR_BADXDR:
|
||
|
+ return "FEDFS_ERR_BADXDR";
|
||
|
+ case FEDFS_ERR_EXIST:
|
||
|
+ return "FEDFS_ERR_EXIST";
|
||
|
+ case FEDFS_ERR_INVAL:
|
||
|
+ return "FEDFS_ERR_INVAL";
|
||
|
+ case FEDFS_ERR_IO:
|
||
|
+ return "FEDFS_ERR_IO";
|
||
|
+ case FEDFS_ERR_NOSPC:
|
||
|
+ return "FEDFS_ERR_NOSPC";
|
||
|
+ case FEDFS_ERR_NOTJUNCT:
|
||
|
+ return "FEDFS_ERR_NOTJUNCT";
|
||
|
+ case FEDFS_ERR_NOTLOCAL:
|
||
|
+ return "FEDFS_ERR_NOTLOCAL";
|
||
|
+ case FEDFS_ERR_PERM:
|
||
|
+ return "FEDFS_ERR_PERM";
|
||
|
+ case FEDFS_ERR_ROFS:
|
||
|
+ return "FEDFS_ERR_ROFS";
|
||
|
+ case FEDFS_ERR_SVRFAULT:
|
||
|
+ return "FEDFS_ERR_SVRFAULT";
|
||
|
+ case FEDFS_ERR_NOTSUPP:
|
||
|
+ return "FEDFS_ERR_NOTSUPP";
|
||
|
+ case FEDFS_ERR_NSDB_ROUTE:
|
||
|
+ return "FEDFS_ERR_NSDB_ROUTE";
|
||
|
+ case FEDFS_ERR_NSDB_DOWN:
|
||
|
+ return "FEDFS_ERR_NSDB_DOWN";
|
||
|
+ case FEDFS_ERR_NSDB_CONN:
|
||
|
+ return "FEDFS_ERR_NSDB_CONN";
|
||
|
+ case FEDFS_ERR_NSDB_AUTH:
|
||
|
+ return "FEDFS_ERR_NSDB_AUTH";
|
||
|
+ case FEDFS_ERR_NSDB_LDAP:
|
||
|
+ return "FEDFS_ERR_NSDB_LDAP";
|
||
|
+ case FEDFS_ERR_NSDB_LDAP_VAL:
|
||
|
+ return "FEDFS_ERR_NSDB_LDAP_VAL";
|
||
|
+ case FEDFS_ERR_NSDB_NONCE:
|
||
|
+ return "FEDFS_ERR_NSDB_NONCE";
|
||
|
+ case FEDFS_ERR_NSDB_NOFSN:
|
||
|
+ return "FEDFS_ERR_NSDB_NOFSN";
|
||
|
+ case FEDFS_ERR_NSDB_NOFSL:
|
||
|
+ return "FEDFS_ERR_NSDB_NOFSL";
|
||
|
+ case FEDFS_ERR_NSDB_RESPONSE:
|
||
|
+ return "FEDFS_ERR_NSDB_RESPONSE";
|
||
|
+ case FEDFS_ERR_NSDB_FAULT:
|
||
|
+ return "FEDFS_ERR_NSDB_FAULT";
|
||
|
+ case FEDFS_ERR_NSDB_PARAMS:
|
||
|
+ return "FEDFS_ERR_NSDB_PARAMS";
|
||
|
+ case FEDFS_ERR_NSDB_LDAP_REFERRAL:
|
||
|
+ return "FEDFS_ERR_NSDB_LDAP_REFERRAL";
|
||
|
+ case FEDFS_ERR_NSDB_LDAP_REFERRAL_VAL:
|
||
|
+ return "FEDFS_ERR_NSDB_LDAP_REFERRAL_VAL";
|
||
|
+ case FEDFS_ERR_NSDB_PARAMS_LDAP_REFERRAL:
|
||
|
+ return "FEDFS_ERR_NSDB_PARAMS_LDAP_REFERRAL";
|
||
|
+ case FEDFS_ERR_PATH_TYPE_UNSUPP:
|
||
|
+ return "FEDFS_ERR_PATH_TYPE_UNSUPP";
|
||
|
+ case FEDFS_ERR_DELAY:
|
||
|
+ return "FEDFS_ERR_DELAY";
|
||
|
+ case FEDFS_ERR_NO_CACHE:
|
||
|
+ return "FEDFS_ERR_NO_CACHE";
|
||
|
+ case FEDFS_ERR_UNKNOWN_CACHE:
|
||
|
+ return "FEDFS_ERR_UNKNOWN_CACHE";
|
||
|
+ case FEDFS_ERR_NO_CACHE_UPDATE:
|
||
|
+ return "FEDFS_ERR_NO_CACHE_UPDATE";
|
||
|
+ default:
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ return "an unrecognized error code";
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Display human-readable FedFsStatus on stderr
|
||
|
+ *
|
||
|
+ * @param status FedFsStatus value to display
|
||
|
+ */
|
||
|
+void
|
||
|
+nsdb_print_fedfsstatus(const FedFsStatus status)
|
||
|
+{
|
||
|
+ if (status == FEDFS_OK) {
|
||
|
+ printf("Call completed successfully\n");
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ fprintf(stderr, "Server returned %s\n",
|
||
|
+ nsdb_display_fedfsstatus(status));
|
||
|
+}
|
||
|
diff --git a/support/junction/export-cache.c b/support/junction/export-cache.c
|
||
|
new file mode 100644
|
||
|
index 0000000..4e578c9
|
||
|
--- /dev/null
|
||
|
+++ b/support/junction/export-cache.c
|
||
|
@@ -0,0 +1,118 @@
|
||
|
+/**
|
||
|
+ * @file support/junction/export-cache.c
|
||
|
+ * @brief Try to flush NFSD's exports cache
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Copyright 2011, 2018 Oracle. All rights reserved.
|
||
|
+ *
|
||
|
+ * This file is part of nfs-utils.
|
||
|
+ *
|
||
|
+ * nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License version 2.0 as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License version 2.0 for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * version 2.0 along with nfs-utils. If not, see:
|
||
|
+ *
|
||
|
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+ */
|
||
|
+
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+
|
||
|
+#include <stdbool.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <string.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <fcntl.h>
|
||
|
+#include <time.h>
|
||
|
+
|
||
|
+
|
||
|
+#include "junction.h"
|
||
|
+#include "xlog.h"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Ordered list of proc files to poke when requesting an NFSD cache flush
|
||
|
+ */
|
||
|
+static const char *junction_proc_files[] = {
|
||
|
+ "/proc/net/rpc/auth.unix.ip/flush",
|
||
|
+ "/proc/net/rpc/auth.unix.gid/flush",
|
||
|
+ "/proc/net/rpc/nfsd.fh/flush",
|
||
|
+ "/proc/net/rpc/nfsd.export/flush",
|
||
|
+ NULL,
|
||
|
+};
|
||
|
+
|
||
|
+/**
|
||
|
+ * Write time into one file
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing POSIX pathname of file to write
|
||
|
+ * @param flushtime NUL-terminated C string containing current time in seconds since the Epoch
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+junction_write_time(const char *pathname, const char *flushtime)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+ ssize_t len;
|
||
|
+ int fd;
|
||
|
+
|
||
|
+ fd = open(pathname, O_RDWR);
|
||
|
+ if (fd == -1) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to open %s: %m",
|
||
|
+ __func__, pathname);
|
||
|
+ /* If the proc files don't exist, no server
|
||
|
+ * is running on this system */
|
||
|
+ return FEDFS_ERR_NO_CACHE_UPDATE;
|
||
|
+ }
|
||
|
+
|
||
|
+ len = write(fd, flushtime, strlen(flushtime));
|
||
|
+ if (len != (ssize_t)strlen(flushtime)) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to write %s: %m",
|
||
|
+ __func__, pathname);
|
||
|
+ /* If the proc files exist but the update failed,
|
||
|
+ * we don't know the state of the cache */
|
||
|
+ retval = FEDFS_ERR_UNKNOWN_CACHE;
|
||
|
+ } else
|
||
|
+ /* Cache flush succeeded */
|
||
|
+ retval = FEDFS_OK;
|
||
|
+
|
||
|
+ (void)close(fd);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Flush the kernel NFSD's exports cache
|
||
|
+ *
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+junction_flush_exports_cache(void)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+ char flushtime[20];
|
||
|
+ unsigned int i;
|
||
|
+ time_t now;
|
||
|
+
|
||
|
+ xlog(D_CALL, "%s: Flushing NFSD caches...", __func__);
|
||
|
+
|
||
|
+ now = time(NULL);
|
||
|
+ if (now == -1) {
|
||
|
+ xlog(D_GENERAL, "%s: time(3) failed", __func__);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+ snprintf(flushtime, sizeof(flushtime), "%ld\n", now);
|
||
|
+
|
||
|
+ for (i = 0; junction_proc_files[i] != NULL; i++) {
|
||
|
+ retval = junction_write_time(junction_proc_files[i], flushtime);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ }
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
diff --git a/support/junction/junction-internal.h b/support/junction/junction-internal.h
|
||
|
new file mode 100644
|
||
|
index 0000000..3dff4cc
|
||
|
--- /dev/null
|
||
|
+++ b/support/junction/junction-internal.h
|
||
|
@@ -0,0 +1,121 @@
|
||
|
+/*
|
||
|
+ * @file support/junction/junction-internal.h
|
||
|
+ * @brief Internal declarations for libjunction.a
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Copyright 2011, 2018 Oracle. All rights reserved.
|
||
|
+ *
|
||
|
+ * This file is part of nfs-utils.
|
||
|
+ *
|
||
|
+ * nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License version 2.0 as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License version 2.0 for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * version 2.0 along with nfs-utils. If not, see:
|
||
|
+ *
|
||
|
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+ */
|
||
|
+
|
||
|
+#ifndef _FEDFS_JUNCTION_INTERNAL_H_
|
||
|
+#define _FEDFS_JUNCTION_INTERNAL_H_
|
||
|
+
|
||
|
+#include <libxml/tree.h>
|
||
|
+#include <libxml/xpath.h>
|
||
|
+
|
||
|
+/**
|
||
|
+ ** Names of extended attributes that store junction data
|
||
|
+ **/
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of extended attribute containing saved mode bits
|
||
|
+ */
|
||
|
+#define JUNCTION_XATTR_NAME_MODE "trusted.junction.mode"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of extended attribute containing NFS-related junction data
|
||
|
+ */
|
||
|
+#define JUNCTION_XATTR_NAME_NFS "trusted.junction.nfs"
|
||
|
+
|
||
|
+
|
||
|
+/**
|
||
|
+ ** Names of XML elements and attributes that represent junction data
|
||
|
+ **/
|
||
|
+
|
||
|
+/**
|
||
|
+ * Tag name of root element of a junction XML document
|
||
|
+ */
|
||
|
+#define JUNCTION_XML_ROOT_TAG (const xmlChar *)"junction"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Tag name of fileset element of a junction XML document
|
||
|
+ */
|
||
|
+#define JUNCTION_XML_FILESET_TAG (const xmlChar *)"fileset"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Tag name of savedmode element of a junction XML document
|
||
|
+ */
|
||
|
+#define JUNCTION_XML_SAVEDMODE_TAG (const xmlChar *)"savedmode"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of mode bits attribute on a savedmode element
|
||
|
+ */
|
||
|
+#define JUNCTION_XML_MODEBITS_ATTR (const xmlChar *)"bits"
|
||
|
+
|
||
|
+/**
|
||
|
+ ** Junction helper functions
|
||
|
+ **/
|
||
|
+
|
||
|
+FedFsStatus junction_open_path(const char *pathname, int *fd);
|
||
|
+FedFsStatus junction_is_directory(int fd, const char *path);
|
||
|
+FedFsStatus junction_is_sticky_bit_set(int fd, const char *path);
|
||
|
+FedFsStatus junction_set_sticky_bit(int fd, const char *path);
|
||
|
+FedFsStatus junction_is_xattr_present(int fd, const char *path,
|
||
|
+ const char *name);
|
||
|
+FedFsStatus junction_read_xattr(int fd, const char *path, const char *name,
|
||
|
+ char **contents);
|
||
|
+FedFsStatus junction_get_xattr(int fd, const char *path, const char *name,
|
||
|
+ void **contents, size_t *contentlen);
|
||
|
+FedFsStatus junction_set_xattr(int fd, const char *path, const char *name,
|
||
|
+ const void *contents, const size_t contentlen);
|
||
|
+FedFsStatus junction_remove_xattr(int fd, const char *pathname,
|
||
|
+ const char *name);
|
||
|
+FedFsStatus junction_get_mode(const char *pathname, mode_t *mode);
|
||
|
+FedFsStatus junction_save_mode(const char *pathname);
|
||
|
+FedFsStatus junction_restore_mode(const char *pathname);
|
||
|
+
|
||
|
+
|
||
|
+/**
|
||
|
+ ** XML helper functions
|
||
|
+ **/
|
||
|
+
|
||
|
+_Bool junction_xml_is_empty(const xmlChar *content);
|
||
|
+_Bool junction_xml_match_node_name(xmlNodePtr node,
|
||
|
+ const xmlChar *name);
|
||
|
+xmlNodePtr junction_xml_find_child_by_name(xmlNodePtr parent,
|
||
|
+ const xmlChar *name);
|
||
|
+_Bool junction_xml_get_bool_attribute(xmlNodePtr node,
|
||
|
+ const xmlChar *attrname, _Bool *value);
|
||
|
+void junction_xml_set_bool_attribute(xmlNodePtr node,
|
||
|
+ const xmlChar *attrname, _Bool value);
|
||
|
+_Bool junction_xml_get_u8_attribute(xmlNodePtr node,
|
||
|
+ const xmlChar *attrname, uint8_t *value);
|
||
|
+_Bool junction_xml_get_int_attribute(xmlNodePtr node,
|
||
|
+ const xmlChar *attrname, int *value);
|
||
|
+void junction_xml_set_int_attribute(xmlNodePtr node,
|
||
|
+ const xmlChar *attrname, int value);
|
||
|
+_Bool junction_xml_get_int_content(xmlNodePtr node, int *value);
|
||
|
+xmlNodePtr junction_xml_set_int_content(xmlNodePtr parent,
|
||
|
+ const xmlChar *name, int value);
|
||
|
+FedFsStatus junction_xml_parse(const char *pathname, const char *name,
|
||
|
+ xmlDocPtr *doc);
|
||
|
+FedFsStatus junction_xml_write(const char *pathname, const char *name,
|
||
|
+ xmlDocPtr doc);
|
||
|
+
|
||
|
+#endif /* !_FEDFS_JUNCTION_INTERNAL_H_ */
|
||
|
diff --git a/support/junction/junction.c b/support/junction/junction.c
|
||
|
new file mode 100644
|
||
|
index 0000000..ab6caa6
|
||
|
--- /dev/null
|
||
|
+++ b/support/junction/junction.c
|
||
|
@@ -0,0 +1,494 @@
|
||
|
+/**
|
||
|
+ * @file support/junction/junction.c
|
||
|
+ * @brief Common utilities for managing junctions on the local file system
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Copyright 2010, 2018 Oracle. All rights reserved.
|
||
|
+ *
|
||
|
+ * This file is part of nfs-utils.
|
||
|
+ *
|
||
|
+ * nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License version 2.0 as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License version 2.0 for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * version 2.0 along with nfs-utils. If not, see:
|
||
|
+ *
|
||
|
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+ */
|
||
|
+
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+
|
||
|
+#include <stdbool.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <string.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <fcntl.h>
|
||
|
+#include <wchar.h>
|
||
|
+#include <memory.h>
|
||
|
+#include <signal.h>
|
||
|
+#include <errno.h>
|
||
|
+#include <dirent.h>
|
||
|
+
|
||
|
+#include <sys/xattr.h>
|
||
|
+
|
||
|
+#include "junction.h"
|
||
|
+#include "junction-internal.h"
|
||
|
+#include "xlog.h"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Open a file system object
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of an object
|
||
|
+ * @param fd OUT: a file descriptor number is filled in
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+junction_open_path(const char *pathname, int *fd)
|
||
|
+{
|
||
|
+ int tmp;
|
||
|
+
|
||
|
+ if (pathname == NULL || fd == NULL)
|
||
|
+ return FEDFS_ERR_INVAL;
|
||
|
+
|
||
|
+ tmp = open(pathname, O_DIRECTORY);
|
||
|
+ if (tmp == -1) {
|
||
|
+ switch (errno) {
|
||
|
+ case EPERM:
|
||
|
+ return FEDFS_ERR_ACCESS;
|
||
|
+ case EACCES:
|
||
|
+ return FEDFS_ERR_PERM;
|
||
|
+ default:
|
||
|
+ xlog(D_GENERAL, "%s: Failed to open path %s: %m",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_INVAL;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ *fd = tmp;
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Predicate: is object a directory?
|
||
|
+ *
|
||
|
+ * @param fd an open file descriptor
|
||
|
+ * @param path NUL-terminated C string containing pathname of a directory
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+junction_is_directory(int fd, const char *path)
|
||
|
+{
|
||
|
+ struct stat stb;
|
||
|
+
|
||
|
+ if (fstat(fd, &stb) == -1) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to stat %s: %m",
|
||
|
+ __func__, path);
|
||
|
+ return FEDFS_ERR_ACCESS;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!S_ISDIR(stb.st_mode)) {
|
||
|
+ xlog(D_CALL, "%s: %s is not a directory",
|
||
|
+ __func__, path);
|
||
|
+ return FEDFS_ERR_INVAL;
|
||
|
+ }
|
||
|
+
|
||
|
+ xlog(D_CALL, "%s: %s is a directory", __func__, path);
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Predicate: is a directory's sticky bit set?
|
||
|
+ *
|
||
|
+ * @param fd an open file descriptor
|
||
|
+ * @param path NUL-terminated C string containing pathname of a directory
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+junction_is_sticky_bit_set(int fd, const char *path)
|
||
|
+{
|
||
|
+ struct stat stb;
|
||
|
+
|
||
|
+ if (fstat(fd, &stb) == -1) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to stat %s: %m",
|
||
|
+ __func__, path);
|
||
|
+ return FEDFS_ERR_ACCESS;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (stb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) {
|
||
|
+ xlog(D_CALL, "%s: execute bit set on %s",
|
||
|
+ __func__, path);
|
||
|
+ return FEDFS_ERR_NOTJUNCT;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!(stb.st_mode & S_ISVTX)) {
|
||
|
+ xlog(D_CALL, "%s: sticky bit not set on %s",
|
||
|
+ __func__, path);
|
||
|
+ return FEDFS_ERR_NOTJUNCT;
|
||
|
+ }
|
||
|
+
|
||
|
+ xlog(D_CALL, "%s: sticky bit is set on %s", __func__, path);
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Set just a directory's sticky bit
|
||
|
+ *
|
||
|
+ * @param fd an open file descriptor
|
||
|
+ * @param path NUL-terminated C string containing pathname of a directory
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+junction_set_sticky_bit(int fd, const char *path)
|
||
|
+{
|
||
|
+ struct stat stb;
|
||
|
+
|
||
|
+ if (fstat(fd, &stb) == -1) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to stat %s: %m",
|
||
|
+ __func__, path);
|
||
|
+ return FEDFS_ERR_ACCESS;
|
||
|
+ }
|
||
|
+
|
||
|
+ stb.st_mode &= (unsigned int)~ALLPERMS;
|
||
|
+ stb.st_mode |= S_ISVTX;
|
||
|
+
|
||
|
+ if (fchmod(fd, stb.st_mode) == -1) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to set sticky bit on %s: %m",
|
||
|
+ __func__, path);
|
||
|
+ return FEDFS_ERR_ROFS;
|
||
|
+ }
|
||
|
+
|
||
|
+ xlog(D_CALL, "%s: set sticky bit on %s", __func__, path);
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Predicate: does a directory have an xattr named "name"?
|
||
|
+ *
|
||
|
+ * @param fd an open file descriptor
|
||
|
+ * @param path NUL-terminated C string containing pathname of a directory
|
||
|
+ * @param name NUL-terminated C string containing name of xattr to check
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * @note Access to trusted attributes requires CAP_SYS_ADMIN.
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+junction_is_xattr_present(int fd, const char *path, const char *name)
|
||
|
+{
|
||
|
+ ssize_t rc;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Do not assume the total number of extended attributes
|
||
|
+ * this object may have.
|
||
|
+ */
|
||
|
+ rc = fgetxattr(fd, name, NULL, 0);
|
||
|
+ if (rc == -1) {
|
||
|
+ switch (errno) {
|
||
|
+ case EPERM:
|
||
|
+ xlog(D_CALL, "%s: no access to xattr %s on %s",
|
||
|
+ __func__, name, path);
|
||
|
+ return FEDFS_ERR_PERM;
|
||
|
+ case ENODATA:
|
||
|
+ xlog(D_CALL, "%s: no xattr %s present on %s",
|
||
|
+ __func__, name, path);
|
||
|
+ return FEDFS_ERR_NOTJUNCT;
|
||
|
+ default:
|
||
|
+ xlog(D_CALL, "%s: xattr %s not found on %s: %m",
|
||
|
+ __func__, name, path);
|
||
|
+ return FEDFS_ERR_IO;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ xlog(D_CALL, "%s: xattr %s found on %s",
|
||
|
+ __func__, name, path);
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Read the contents of xattr "name"
|
||
|
+ *
|
||
|
+ * @param fd an open file descriptor
|
||
|
+ * @param path NUL-terminated C string containing pathname of a directory
|
||
|
+ * @param name NUL-terminated C string containing name of xattr to retrieve
|
||
|
+ * @param contents OUT: NUL-terminated C string containing contents of xattr
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * If junction_read_xattr() returns FEDFS_OK, the caller must free "*contents"
|
||
|
+ * with free(3).
|
||
|
+ *
|
||
|
+ * @note Access to trusted attributes requires CAP_SYS_ADMIN.
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+junction_read_xattr(int fd, const char *path, const char *name, char **contents)
|
||
|
+{
|
||
|
+ char *xattrbuf = NULL;
|
||
|
+ ssize_t len;
|
||
|
+
|
||
|
+ len = fgetxattr(fd, name, xattrbuf, 0);
|
||
|
+ if (len < 0) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to get size of xattr %s on %s: %m",
|
||
|
+ __func__, name, path);
|
||
|
+ return FEDFS_ERR_ACCESS;
|
||
|
+ }
|
||
|
+
|
||
|
+ xattrbuf = malloc((size_t)len + 1);
|
||
|
+ if (xattrbuf == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to get buffer for xattr %s on %s",
|
||
|
+ __func__, name, path);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (fgetxattr(fd, name, xattrbuf, (size_t)len) == -1) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to get xattr %s on %s: %m",
|
||
|
+ __func__, name, path);
|
||
|
+ free(xattrbuf);
|
||
|
+ return FEDFS_ERR_ACCESS;
|
||
|
+ }
|
||
|
+ xattrbuf[len] = '\0';
|
||
|
+
|
||
|
+ xlog(D_CALL, "%s: read xattr %s from path %s",
|
||
|
+ __func__, name, path);
|
||
|
+ *contents = xattrbuf;
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Retrieve the contents of xattr "name"
|
||
|
+ *
|
||
|
+ * @param fd an open file descriptor
|
||
|
+ * @param path NUL-terminated C string containing pathname of a directory
|
||
|
+ * @param name NUL-terminated C string containing name of xattr to retrieve
|
||
|
+ * @param contents OUT: opaque byte array containing contents of xattr
|
||
|
+ * @param contentlen OUT: size of "contents"
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * If junction_get_xattr() returns FEDFS_OK, the caller must free "*contents"
|
||
|
+ * with free(3).
|
||
|
+ *
|
||
|
+ * @note Access to trusted attributes requires CAP_SYS_ADMIN.
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+junction_get_xattr(int fd, const char *path, const char *name, void **contents,
|
||
|
+ size_t *contentlen)
|
||
|
+{
|
||
|
+ void *xattrbuf = NULL;
|
||
|
+ ssize_t len;
|
||
|
+
|
||
|
+ len = fgetxattr(fd, name, xattrbuf, 0);
|
||
|
+ if (len < 0) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to get size of xattr %s on %s: %m",
|
||
|
+ __func__, name, path);
|
||
|
+ return FEDFS_ERR_ACCESS;
|
||
|
+ }
|
||
|
+
|
||
|
+ xattrbuf = malloc((size_t)len);
|
||
|
+ if (xattrbuf == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to get buffer for xattr %s on %s",
|
||
|
+ __func__, name, path);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (fgetxattr(fd, name, xattrbuf, (size_t)len) == -1) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to get xattr %s on %s: %m",
|
||
|
+ __func__, name, path);
|
||
|
+ free(xattrbuf);
|
||
|
+ return FEDFS_ERR_ACCESS;
|
||
|
+ }
|
||
|
+
|
||
|
+ xlog(D_CALL, "%s: read xattr %s from path %s",
|
||
|
+ __func__, name, path);
|
||
|
+ *contents = xattrbuf;
|
||
|
+ *contentlen = (size_t)len;
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Update the contents of an xattr
|
||
|
+ *
|
||
|
+ * @param fd an open file descriptor
|
||
|
+ * @param path NUL-terminated C string containing pathname of a directory
|
||
|
+ * @param name NUL-terminated C string containing name of xattr to set
|
||
|
+ * @param contents opaque byte array containing contents of xattr
|
||
|
+ * @param contentlen size of "contents"
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * The extended attribute is created if it does not exist.
|
||
|
+ * Its contents are replaced if it does.
|
||
|
+ *
|
||
|
+ * @note Access to trusted attributes requires CAP_SYS_ADMIN.
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+junction_set_xattr(int fd, const char *path, const char *name,
|
||
|
+ const void *contents, const size_t contentlen)
|
||
|
+{
|
||
|
+ /*
|
||
|
+ * XXX: Eventually should distinguish among several errors:
|
||
|
+ * object isn't there, no root access, some other issue
|
||
|
+ */
|
||
|
+ if (fsetxattr(fd, name, contents, contentlen, 0) == -1) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to set xattr %s on %s: %m",
|
||
|
+ __func__, name, path);
|
||
|
+ return FEDFS_ERR_IO;
|
||
|
+ }
|
||
|
+
|
||
|
+ xlog(D_CALL, "%s: Wrote xattr %s from path %s",
|
||
|
+ __func__, name, path);
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Remove one xattr
|
||
|
+ *
|
||
|
+ * @param fd an open file descriptor
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a directory
|
||
|
+ * @param name NUL-terminated C string containing name of xattr to set
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * @note Access to trusted attributes requires CAP_SYS_ADMIN.
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+junction_remove_xattr(int fd, const char *pathname, const char *name)
|
||
|
+{
|
||
|
+ /*
|
||
|
+ * XXX: Eventually should distinguish among several errors:
|
||
|
+ * object isn't there, no root access, some other issue
|
||
|
+ */
|
||
|
+ if (fremovexattr(fd, name) == -1) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to remove xattr %s from %s: %m",
|
||
|
+ __func__, name, pathname);
|
||
|
+ return FEDFS_ERR_ACCESS;
|
||
|
+ }
|
||
|
+ xlog(D_CALL, "%s: removed xattr %s from path %s",
|
||
|
+ __func__, name, pathname);
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Retrieve object's mode bits.
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a directory
|
||
|
+ * @param mode OUT: mode bits
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+junction_get_mode(const char *pathname, mode_t *mode)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+ struct stat stb;
|
||
|
+ int fd;
|
||
|
+
|
||
|
+ retval = junction_open_path(pathname, &fd);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ if (fstat(fd, &stb) == -1) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to stat %s: %m",
|
||
|
+ __func__, pathname);
|
||
|
+ (void)close(fd);
|
||
|
+ return FEDFS_ERR_ACCESS;
|
||
|
+ }
|
||
|
+ (void)close(fd);
|
||
|
+
|
||
|
+ xlog(D_CALL, "%s: pathname %s has mode %o",
|
||
|
+ __func__, pathname, stb.st_mode);
|
||
|
+ *mode = stb.st_mode;
|
||
|
+ return FEDFS_OK;
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Save the object's mode in an xattr. Saved mode is human-readable.
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a directory
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+junction_save_mode(const char *pathname)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+ mode_t mode;
|
||
|
+ char buf[8];
|
||
|
+ int fd;
|
||
|
+
|
||
|
+ retval = junction_get_mode(pathname, &mode);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ (void)snprintf(buf, sizeof(buf), "%o", ALLPERMS & mode);
|
||
|
+
|
||
|
+ retval = junction_open_path(pathname, &fd);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ retval = junction_set_xattr(fd, pathname, JUNCTION_XATTR_NAME_MODE,
|
||
|
+ buf, strlen(buf));
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ retval = junction_set_sticky_bit(fd, pathname);
|
||
|
+ if (retval != FEDFS_OK) {
|
||
|
+ (void)junction_remove_xattr(fd, pathname,
|
||
|
+ JUNCTION_XATTR_NAME_MODE);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ xlog(D_CALL, "%s: saved mode %o to %s", __func__, mode, pathname);
|
||
|
+ retval = FEDFS_OK;
|
||
|
+
|
||
|
+out:
|
||
|
+ (void)close(fd);
|
||
|
+ return retval;
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Restore an object's mode bits
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a directory
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+junction_restore_mode(const char *pathname)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+ char *buf = NULL;
|
||
|
+ mode_t mode;
|
||
|
+ int fd;
|
||
|
+
|
||
|
+ retval = junction_open_path(pathname, &fd);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ retval = junction_read_xattr(fd, pathname, JUNCTION_XATTR_NAME_MODE, &buf);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ retval = FEDFS_ERR_SVRFAULT;
|
||
|
+ if (sscanf((char *)buf, "%o", &mode) != 1) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to parse saved mode on %s",
|
||
|
+ __func__, pathname);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ retval = FEDFS_ERR_ROFS;
|
||
|
+ if (fchmod(fd, mode) == -1) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to set mode of %s to %o: %m",
|
||
|
+ __func__, pathname, mode);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ xlog(D_CALL, "%s: restored mode %o to %s", __func__, mode, pathname);
|
||
|
+ retval = FEDFS_OK;
|
||
|
+
|
||
|
+out:
|
||
|
+ free(buf);
|
||
|
+ (void)close(fd);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
diff --git a/support/junction/locations.c b/support/junction/locations.c
|
||
|
new file mode 100644
|
||
|
index 0000000..c577981
|
||
|
--- /dev/null
|
||
|
+++ b/support/junction/locations.c
|
||
|
@@ -0,0 +1,131 @@
|
||
|
+/**
|
||
|
+ * @file support/junction/locations.c
|
||
|
+ * @brief Utility functions to manage NFS locations data
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Copyright 2011, 2018 Oracle. All rights reserved.
|
||
|
+ *
|
||
|
+ * This file is part of nfs-utils.
|
||
|
+ *
|
||
|
+ * nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License version 2.0 as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License version 2.0 for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * version 2.0 along with nfs-utils. If not, see:
|
||
|
+ *
|
||
|
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+ */
|
||
|
+
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+
|
||
|
+#include <stdbool.h>
|
||
|
+#include <stdint.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <stdio.h>
|
||
|
+
|
||
|
+#include <string.h>
|
||
|
+#include <fcntl.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <errno.h>
|
||
|
+
|
||
|
+#include "junction.h"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Free an array of NUL-terminated C strings
|
||
|
+ *
|
||
|
+ * @param array array of pointers to C strings
|
||
|
+ */
|
||
|
+void
|
||
|
+nfs_free_string_array(char **array)
|
||
|
+{
|
||
|
+ unsigned int i;
|
||
|
+
|
||
|
+ if (array == NULL)
|
||
|
+ return;
|
||
|
+ for (i = 0; array[i] != NULL; i++)
|
||
|
+ free(array[i]);
|
||
|
+ free(array);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Duplicate an array of NUL-terminated C strings
|
||
|
+ *
|
||
|
+ * @param array array of pointers to C strings
|
||
|
+ * @return freshly allocated array of points to C strings, or NULL
|
||
|
+ *
|
||
|
+ * Caller must free the returned array with nfs_free_string_array()
|
||
|
+ */
|
||
|
+__attribute_malloc__ char **
|
||
|
+nfs_dup_string_array(char **array)
|
||
|
+{
|
||
|
+ unsigned int size, i;
|
||
|
+ char **result;
|
||
|
+
|
||
|
+ if (array == NULL)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ for (size = 0; array[size] != NULL; size++);
|
||
|
+
|
||
|
+ result = calloc(size + 1, sizeof(char *));
|
||
|
+ if (result == NULL)
|
||
|
+ return NULL;
|
||
|
+ for (i = 0; i < size; i++) {
|
||
|
+ result[i] = strdup(array[i]);
|
||
|
+ if (result[i] == NULL) {
|
||
|
+ nfs_free_string_array(result);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return result;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Free a single NFS location
|
||
|
+ *
|
||
|
+ * @param location pointer to nfs_fsloc data
|
||
|
+ */
|
||
|
+void
|
||
|
+nfs_free_location(struct nfs_fsloc *location)
|
||
|
+{
|
||
|
+ nfs_free_string_array(location->nfl_rootpath);
|
||
|
+ free(location->nfl_hostname);
|
||
|
+ free(location);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Free a list of NFS locations
|
||
|
+ *
|
||
|
+ * @param locations pointer to list of one or more locations
|
||
|
+ */
|
||
|
+void
|
||
|
+nfs_free_locations(struct nfs_fsloc *locations)
|
||
|
+{
|
||
|
+ struct nfs_fsloc *fsloc;
|
||
|
+
|
||
|
+ while (locations != NULL) {
|
||
|
+ fsloc = locations;
|
||
|
+ locations = fsloc->nfl_next;
|
||
|
+ nfs_free_location(fsloc);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Allocate a fresh nfs_fsloc structure
|
||
|
+ *
|
||
|
+ * @return pointer to new empty nfs_fsloc data structure
|
||
|
+ *
|
||
|
+ * Caller must free returned locations with nfs_free_location().
|
||
|
+ */
|
||
|
+struct nfs_fsloc *
|
||
|
+nfs_new_location(void)
|
||
|
+{
|
||
|
+ return calloc(1, sizeof(struct nfs_fsloc));
|
||
|
+}
|
||
|
diff --git a/support/junction/nfs.c b/support/junction/nfs.c
|
||
|
new file mode 100644
|
||
|
index 0000000..73e3533
|
||
|
--- /dev/null
|
||
|
+++ b/support/junction/nfs.c
|
||
|
@@ -0,0 +1,1564 @@
|
||
|
+/**
|
||
|
+ * @file support/junction/nfs.c
|
||
|
+ * @brief Create, delete, and read NFS junctions on the local file system
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Copyright 2011, 2018 Oracle. All rights reserved.
|
||
|
+ *
|
||
|
+ * This file is part of nfs-utils.
|
||
|
+ *
|
||
|
+ * nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License version 2.0 as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License version 2.0 for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * version 2.0 along with nfs-utils. If not, see:
|
||
|
+ *
|
||
|
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * An NFS junction is a list of NFS FSLs, represented in a well-formed XML
|
||
|
+ * document:
|
||
|
+ *
|
||
|
+ * <?xml version="1.0" encoding="UTF-8"?>
|
||
|
+ * <junction>
|
||
|
+ * <savedmode bits="1777" />
|
||
|
+ * <fileset>
|
||
|
+ * <location>
|
||
|
+ * <host name="fileserver.example.net" port="2049" />
|
||
|
+ * <path>
|
||
|
+ * <component>foo</component>
|
||
|
+ * <component>bar</component>
|
||
|
+ * <component>baz</component>
|
||
|
+ * </path>
|
||
|
+ * <currency>-1</currency>
|
||
|
+ * <genflags writable="false" going="false" split="true" />
|
||
|
+ * <transflags rdma="true" />
|
||
|
+ * <class simul="0" handle="0" fileid="0"
|
||
|
+ * writever="0" change="0" readdir="0" />
|
||
|
+ * <read rank="0" order="0" />
|
||
|
+ * <write rank="0" order="0" />
|
||
|
+ * <flags varsub="false" />
|
||
|
+ * <validfor>0</validfor>
|
||
|
+ * </location>
|
||
|
+ *
|
||
|
+ * ....
|
||
|
+ *
|
||
|
+ * </fileset>
|
||
|
+ * </junction>
|
||
|
+ *
|
||
|
+ * NFS junction XML is stored in an extended attribute called
|
||
|
+ * "trusted.junction.nfs". The parent object is a directory.
|
||
|
+ *
|
||
|
+ * To help file servers discover junctions efficiently, the directory
|
||
|
+ * has no execute bits, and the sticky bit is set. In addition, an
|
||
|
+ * extended attribute called "trusted.junction.type" is added. The
|
||
|
+ * contents are ignored in user space.
|
||
|
+ *
|
||
|
+ * Finally, for pre-existing directories that are converted to
|
||
|
+ * junctions, their mode bits are saved in an extended attribute called
|
||
|
+ * "trusted.junction.mode". When the junction data is removed, the
|
||
|
+ * directory's mode bits are restored from this information.
|
||
|
+ */
|
||
|
+
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+
|
||
|
+#include <stdbool.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <string.h>
|
||
|
+#include <unistd.h>
|
||
|
+
|
||
|
+#include <rpcsvc/nfs_prot.h>
|
||
|
+
|
||
|
+#include "junction.h"
|
||
|
+#include "junction-internal.h"
|
||
|
+#include "xlog.h"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Tag name of NFS location element of a junction XML document
|
||
|
+ */
|
||
|
+#define NFS_XML_LOCATION_TAG (const xmlChar *)"location"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Tag name of host child element of an NFS location element
|
||
|
+ */
|
||
|
+#define NFS_XML_HOST_TAG (const xmlChar *)"host"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of hostname attribute of a host element
|
||
|
+ */
|
||
|
+#define NFS_XML_HOST_NAME_ATTR (const xmlChar *)"name"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of IP port attribute of a host element
|
||
|
+ */
|
||
|
+#define NFS_XML_HOST_PORT_ATTR (const xmlChar *)"port"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Tag name of path child element of an NFS location element
|
||
|
+ */
|
||
|
+#define NFS_XML_PATH_TAG (const xmlChar *)"path"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Tag name of component child element of a path element
|
||
|
+ */
|
||
|
+#define NFS_XML_COMPONENT_TAG (const xmlChar *)"component"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Tag name of currency child element of an NFS location element
|
||
|
+ */
|
||
|
+#define NFS_XML_CURRENCY_TAG (const xmlChar *)"currency"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Tag name of genflags child element of an NFS location element
|
||
|
+ */
|
||
|
+#define NFS_XML_GENFLAGS_TAG (const xmlChar *)"genflags"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of writable attribute of a genflags element
|
||
|
+ */
|
||
|
+#define NFS_XML_GENFLAGS_WRITABLE_ATTR (const xmlChar *)"writable"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of going attribute of a genflags element
|
||
|
+ */
|
||
|
+#define NFS_XML_GENFLAGS_GOING_ATTR (const xmlChar *)"going"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of split attribute of a genflags element
|
||
|
+ */
|
||
|
+#define NFS_XML_GENFLAGS_SPLIT_ATTR (const xmlChar *)"split"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Tag name of transflags child element of an NFS location element
|
||
|
+ */
|
||
|
+#define NFS_XML_TRANSFLAGS_TAG (const xmlChar *)"transflags"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of rdma attribute of a transflags element
|
||
|
+ */
|
||
|
+#define NFS_XML_TRANSFLAGS_RDMA_ATTR (const xmlChar *)"rdma"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Tag name of class child element of an NFS location element
|
||
|
+ */
|
||
|
+#define NFS_XML_CLASS_TAG (const xmlChar *)"class"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of simul attribute of a class element
|
||
|
+ */
|
||
|
+#define NFS_XML_CLASS_SIMUL_ATTR (const xmlChar *)"simul"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of handle attribute of a class element
|
||
|
+ */
|
||
|
+#define NFS_XML_CLASS_HANDLE_ATTR (const xmlChar *)"handle"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of fileid attribute of a class element
|
||
|
+ */
|
||
|
+#define NFS_XML_CLASS_FILEID_ATTR (const xmlChar *)"fileid"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of writever attribute of a class element
|
||
|
+ */
|
||
|
+#define NFS_XML_CLASS_WRITEVER_ATTR (const xmlChar *)"writever"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of change attribute of a class element
|
||
|
+ */
|
||
|
+#define NFS_XML_CLASS_CHANGE_ATTR (const xmlChar *)"change"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of readdir attribute of a class element
|
||
|
+ */
|
||
|
+#define NFS_XML_CLASS_READDIR_ATTR (const xmlChar *)"readdir"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Tag name of read child element of an NFS location element
|
||
|
+ */
|
||
|
+#define NFS_XML_READ_TAG (const xmlChar *)"read"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of rank attribute of a read element
|
||
|
+ */
|
||
|
+#define NFS_XML_READ_RANK_ATTR (const xmlChar *)"rank"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of order attribute of a read element
|
||
|
+ */
|
||
|
+#define NFS_XML_READ_ORDER_ATTR (const xmlChar *)"order"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Tag name of write attribute of an NFS location element
|
||
|
+ */
|
||
|
+#define NFS_XML_WRITE_TAG (const xmlChar *)"write"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of rank attribute of a write element
|
||
|
+ */
|
||
|
+#define NFS_XML_WRITE_RANK_ATTR (const xmlChar *)"rank"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of order attribute of a write element
|
||
|
+ */
|
||
|
+#define NFS_XML_WRITE_ORDER_ATTR (const xmlChar *)"order"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Tag name of flags child element of an NFS location element
|
||
|
+ */
|
||
|
+#define NFS_XML_FLAGS_TAG (const xmlChar *)"flags"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Name of varsub attribute of a flags element
|
||
|
+ */
|
||
|
+#define NFS_XML_FLAGS_VARSUB_ATTR (const xmlChar *)"varsub"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Tag name of a validfor child element of an NFS location element
|
||
|
+ */
|
||
|
+#define NFS_XML_VALIDFOR_TAG (const xmlChar *)"validfor"
|
||
|
+
|
||
|
+/**
|
||
|
+ * XPath path to NFS location elements in a junction document
|
||
|
+ */
|
||
|
+#define NFS_XML_LOCATION_XPATH (const xmlChar *) \
|
||
|
+ "/junction/fileset/location"
|
||
|
+
|
||
|
+
|
||
|
+/**
|
||
|
+ * Remove all NFS-related xattrs from a directory
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a directory
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * @note Access to trusted attributes requires CAP_SYS_ADMIN.
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_remove_locations(const char *pathname)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+ int fd;
|
||
|
+
|
||
|
+ retval = junction_open_path(pathname, &fd);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ retval = junction_remove_xattr(fd, pathname, JUNCTION_XATTR_NAME_NFS);
|
||
|
+
|
||
|
+ (void)close(fd);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Add a "host" child to a "location" element
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param parent parent element to which to add "host" child
|
||
|
+ * @param fsloc NFS location containing host information to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_location_host_xml(const char *pathname, xmlNodePtr parent,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ uint16_t port = fsloc->nfl_hostport;
|
||
|
+ xmlNodePtr new;
|
||
|
+
|
||
|
+ new = xmlNewTextChild(parent, NULL, NFS_XML_HOST_TAG, NULL);
|
||
|
+ if (new == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to add host element for %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ xmlSetProp(new, NFS_XML_HOST_NAME_ATTR,
|
||
|
+ (const xmlChar *)fsloc->nfl_hostname);
|
||
|
+ if (port != NFS_PORT && port != 0)
|
||
|
+ junction_xml_set_int_attribute(new, NFS_XML_HOST_PORT_ATTR,
|
||
|
+ port);
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Add a "path" child to a "location" element
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param parent parent element to which to add "host" child
|
||
|
+ * @param fsloc NFS location containing host information to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_location_path_xml(const char *pathname, xmlNodePtr parent,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr new;
|
||
|
+ int i;
|
||
|
+
|
||
|
+ new = xmlNewTextChild(parent, NULL, NFS_XML_PATH_TAG, NULL);
|
||
|
+ if (new == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to add path element for %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0; fsloc->nfl_rootpath[i] != NULL; i++) {
|
||
|
+ xmlNodePtr component;
|
||
|
+
|
||
|
+ component = xmlNewTextChild(new , NULL,
|
||
|
+ NFS_XML_COMPONENT_TAG,
|
||
|
+ (const xmlChar *)
|
||
|
+ fsloc->nfl_rootpath[i]);
|
||
|
+ if (component == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to add component "
|
||
|
+ "element for %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Add a "currency" child to a "location" element
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param parent parent element to which to add "host" child
|
||
|
+ * @param fsloc NFS location containing host information to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_location_currency_xml(__attribute__((unused)) const char *pathname,
|
||
|
+ xmlNodePtr parent, struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ if (junction_xml_set_int_content(parent, NFS_XML_CURRENCY_TAG,
|
||
|
+ fsloc->nfl_currency) == NULL)
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Add a "genflags" child to a "location" element
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param parent parent element to which to add "host" child
|
||
|
+ * @param fsloc NFS location containing host information to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_location_genflags_xml(const char *pathname, xmlNodePtr parent,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr new;
|
||
|
+
|
||
|
+ new = xmlNewTextChild(parent, NULL, NFS_XML_GENFLAGS_TAG, NULL);
|
||
|
+ if (new == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to add genflags element for %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ junction_xml_set_bool_attribute(new, NFS_XML_GENFLAGS_WRITABLE_ATTR,
|
||
|
+ fsloc->nfl_genflags.nfl_writable);
|
||
|
+ junction_xml_set_bool_attribute(new, NFS_XML_GENFLAGS_GOING_ATTR,
|
||
|
+ fsloc->nfl_genflags.nfl_going);
|
||
|
+ junction_xml_set_bool_attribute(new, NFS_XML_GENFLAGS_SPLIT_ATTR,
|
||
|
+ fsloc->nfl_genflags.nfl_split);
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Add a "transflags" child to a "location" element
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param parent parent element to which to add "host" child
|
||
|
+ * @param fsloc NFS location containing host information to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_location_transflags_xml(const char *pathname, xmlNodePtr parent,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr new;
|
||
|
+
|
||
|
+ new = xmlNewTextChild(parent, NULL, NFS_XML_TRANSFLAGS_TAG, NULL);
|
||
|
+ if (new == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to add transflags element for %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ junction_xml_set_bool_attribute(new, NFS_XML_TRANSFLAGS_RDMA_ATTR,
|
||
|
+ fsloc->nfl_transflags.nfl_rdma);
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Add a "class" child to a "location" element
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param parent parent element to which to add "host" child
|
||
|
+ * @param fsloc NFS location containing host information to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_location_class_xml(const char *pathname, xmlNodePtr parent,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr new;
|
||
|
+
|
||
|
+ new = xmlNewTextChild(parent, NULL, NFS_XML_CLASS_TAG, NULL);
|
||
|
+ if (new == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to add class element for %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ junction_xml_set_int_attribute(new, NFS_XML_CLASS_SIMUL_ATTR,
|
||
|
+ fsloc->nfl_info.nfl_simul);
|
||
|
+ junction_xml_set_int_attribute(new, NFS_XML_CLASS_HANDLE_ATTR,
|
||
|
+ fsloc->nfl_info.nfl_handle);
|
||
|
+ junction_xml_set_int_attribute(new, NFS_XML_CLASS_FILEID_ATTR,
|
||
|
+ fsloc->nfl_info.nfl_fileid);
|
||
|
+ junction_xml_set_int_attribute(new, NFS_XML_CLASS_WRITEVER_ATTR,
|
||
|
+ fsloc->nfl_info.nfl_writever);
|
||
|
+ junction_xml_set_int_attribute(new, NFS_XML_CLASS_CHANGE_ATTR,
|
||
|
+ fsloc->nfl_info.nfl_change);
|
||
|
+ junction_xml_set_int_attribute(new, NFS_XML_CLASS_READDIR_ATTR,
|
||
|
+ fsloc->nfl_info.nfl_readdir);
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Add a "read" child to a "location" element
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param parent parent element to which to add "host" child
|
||
|
+ * @param fsloc NFS location containing host information to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_location_read_xml(const char *pathname, xmlNodePtr parent,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr new;
|
||
|
+
|
||
|
+ new = xmlNewTextChild(parent, NULL, NFS_XML_READ_TAG, NULL);
|
||
|
+ if (new == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to add read element for %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ junction_xml_set_int_attribute(new, NFS_XML_READ_RANK_ATTR,
|
||
|
+ fsloc->nfl_info.nfl_readrank);
|
||
|
+ junction_xml_set_int_attribute(new, NFS_XML_READ_ORDER_ATTR,
|
||
|
+ fsloc->nfl_info.nfl_readorder);
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Add a "write" child to a "location" element
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param parent parent element to which to add "host" child
|
||
|
+ * @param fsloc NFS location containing host information to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_location_write_xml(const char *pathname, xmlNodePtr parent,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr new;
|
||
|
+
|
||
|
+ new = xmlNewTextChild(parent, NULL, NFS_XML_WRITE_TAG, NULL);
|
||
|
+ if (new == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to add write element for %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ junction_xml_set_int_attribute(new, NFS_XML_WRITE_RANK_ATTR,
|
||
|
+ fsloc->nfl_info.nfl_writerank);
|
||
|
+ junction_xml_set_int_attribute(new, NFS_XML_WRITE_ORDER_ATTR,
|
||
|
+ fsloc->nfl_info.nfl_writeorder);
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Add a "flags" child to a "location" element
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param parent parent element to which to add "host" child
|
||
|
+ * @param fsloc NFS location containing host information to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_location_flags_xml(const char *pathname, xmlNodePtr parent,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr new;
|
||
|
+
|
||
|
+ new = xmlNewTextChild(parent, NULL, NFS_XML_FLAGS_TAG, NULL);
|
||
|
+ if (new == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to add flags element for %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ junction_xml_set_bool_attribute(new, NFS_XML_FLAGS_VARSUB_ATTR,
|
||
|
+ fsloc->nfl_flags.nfl_varsub);
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Add a "validfor" child to a "location" element
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param parent parent element to which to add "host" child
|
||
|
+ * @param fsloc NFS location containing host information to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_location_validfor_xml(__attribute__((unused)) const char *pathname,
|
||
|
+ xmlNodePtr parent, struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ if (junction_xml_set_int_content(parent, NFS_XML_VALIDFOR_TAG,
|
||
|
+ fsloc->nfl_validfor) == NULL)
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Construct and add one "location" element to a "fileset"
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param fileset fileset element of junction XML parse tree
|
||
|
+ * @param fsloc one NFS location to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_location_xml(const char *pathname, xmlNodePtr fileset,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+ xmlNodePtr new;
|
||
|
+
|
||
|
+ new = xmlNewTextChild(fileset, NULL, NFS_XML_LOCATION_TAG, NULL);
|
||
|
+ if (new == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to add location element for %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ retval = nfs_location_host_xml(pathname, new, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_location_path_xml(pathname, new, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_location_currency_xml(pathname, new, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_location_genflags_xml(pathname, new, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_location_transflags_xml(pathname, new, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_location_class_xml(pathname, new, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_location_read_xml(pathname, new, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_location_write_xml(pathname, new, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_location_flags_xml(pathname, new, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ return nfs_location_validfor_xml(pathname, new, fsloc);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Construct and add a "fileset" element
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param root root element of junction XML parse tree
|
||
|
+ * @param fslocs list of NFS locations to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_fileset_xml(const char *pathname, xmlNodePtr root,
|
||
|
+ struct nfs_fsloc *fslocs)
|
||
|
+{
|
||
|
+ struct nfs_fsloc *next;
|
||
|
+ xmlNodePtr fileset;
|
||
|
+ FedFsStatus retval;
|
||
|
+
|
||
|
+ fileset = xmlNewTextChild(root, NULL, JUNCTION_XML_FILESET_TAG, NULL);
|
||
|
+ if (fileset == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to add fileset element for %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (next = fslocs; next != NULL; next = next->nfl_next) {
|
||
|
+ retval = nfs_location_xml(pathname, fileset, next);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ }
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Construct a "savedmode" element
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param root root element of XML document tree
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_savedmode_xml(const char *pathname, xmlNodePtr root)
|
||
|
+{
|
||
|
+ xmlNodePtr savedmode;
|
||
|
+ FedFsStatus retval;
|
||
|
+ mode_t mode;
|
||
|
+ char buf[8];
|
||
|
+
|
||
|
+ retval = junction_get_mode(pathname, &mode);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ savedmode = xmlNewTextChild(root, NULL, JUNCTION_XML_SAVEDMODE_TAG, NULL);
|
||
|
+ if (savedmode == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to add savedmode element for %s\n",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ (void)snprintf(buf, sizeof(buf), "%o", ALLPERMS & mode);
|
||
|
+ xmlSetProp(savedmode, JUNCTION_XML_MODEBITS_ATTR, (const xmlChar *)buf);
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Construct NFS junction XML document from list of NFS locations
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param doc an XML parse tree in which to construct the junction XML document
|
||
|
+ * @param fslocs list of NFS locations to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_junction_xml(const char *pathname, xmlDocPtr doc,
|
||
|
+ struct nfs_fsloc *fslocs)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+ xmlNodePtr root;
|
||
|
+
|
||
|
+ root = xmlNewNode(NULL, JUNCTION_XML_ROOT_TAG);
|
||
|
+ if (root == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to create root element for %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+ (void)xmlDocSetRootElement(doc, root);
|
||
|
+
|
||
|
+ retval = nfs_savedmode_xml(pathname, root);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ return nfs_fileset_xml(pathname, root, fslocs);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Write NFS locations information into an NFS junction extended attribute
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param doc an empty XML parse tree in which to construct the junction XML document
|
||
|
+ * @param fslocs list of NFS locations to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * @note Access to trusted attributes requires CAP_SYS_ADMIN.
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_write_junction(const char *pathname, xmlDocPtr doc,
|
||
|
+ struct nfs_fsloc *fslocs)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+
|
||
|
+ retval = nfs_junction_xml(pathname, doc, fslocs);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ return junction_xml_write(pathname, JUNCTION_XATTR_NAME_NFS, doc);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Store NFS locations information into a junction object
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param fslocs list of NFS locations to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * @note Access to trusted attributes requires CAP_SYS_ADMIN.
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_store_locations(const char *pathname, struct nfs_fsloc *fslocs)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+ xmlDocPtr doc;
|
||
|
+
|
||
|
+ doc = xmlNewDoc((xmlChar *)"1.0");
|
||
|
+ if (doc == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to create XML doc for %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ retval = nfs_write_junction(pathname, doc, fslocs);
|
||
|
+
|
||
|
+ xmlFreeDoc(doc);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Add NFS junction information to a pre-existing object
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param fslocs list of NFS locations to add
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * An error occurs if the object referred to by "pathname" does not
|
||
|
+ * exist or contains existing junction data.
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+nfs_add_junction(const char *pathname, struct nfs_fsloc *fslocs)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+
|
||
|
+ if (fslocs == NULL)
|
||
|
+ return FEDFS_ERR_INVAL;
|
||
|
+
|
||
|
+ retval = nfs_is_prejunction(pathname);
|
||
|
+ if (retval != FEDFS_ERR_NOTJUNCT)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ retval = nfs_store_locations(pathname, fslocs);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ retval = junction_save_mode(pathname);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ return retval;
|
||
|
+
|
||
|
+out_err:
|
||
|
+ (void)nfs_remove_locations(pathname);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Remove NFS junction information from an object
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a directory
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * An error occurs if the object referred to by "pathname" does not
|
||
|
+ * exist or does not contain NFS junction data.
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+nfs_delete_junction(const char *pathname)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+
|
||
|
+ retval = nfs_is_junction(pathname);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ retval = junction_restore_mode(pathname);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ return nfs_remove_locations(pathname);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Parse the first "host" child of "location"
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param location XML parse tree containing fileset location element
|
||
|
+ * @param fsloc a blank nfs_fsloc to fill in
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_parse_location_host(const char *pathname, xmlNodePtr location,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+ xmlChar *hostname;
|
||
|
+ xmlNodePtr node;
|
||
|
+ int hostport;
|
||
|
+
|
||
|
+ retval = FEDFS_ERR_NOTJUNCT;
|
||
|
+ node = junction_xml_find_child_by_name(location, NFS_XML_HOST_TAG);
|
||
|
+ if (node == NULL)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ hostname = xmlGetProp(node, NFS_XML_HOST_NAME_ATTR);
|
||
|
+ if (!junction_xml_get_int_attribute(node, NFS_XML_HOST_PORT_ATTR,
|
||
|
+ &hostport))
|
||
|
+ fsloc->nfl_hostport = NFS_PORT;
|
||
|
+ else {
|
||
|
+ if (hostport < 1 || hostport > UINT16_MAX) {
|
||
|
+ xlog(D_GENERAL, "%s: Bad port attribute on %s",
|
||
|
+ __func__, pathname);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ fsloc->nfl_hostport = (uint16_t)hostport;
|
||
|
+ }
|
||
|
+ if (hostname == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: No hostname attribute on %s",
|
||
|
+ __func__, pathname);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ fsloc->nfl_hostname = strdup((const char *)hostname);
|
||
|
+ if (fsloc->nfl_hostname == NULL) {
|
||
|
+ retval = FEDFS_ERR_SVRFAULT;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ retval = FEDFS_OK;
|
||
|
+
|
||
|
+out:
|
||
|
+ xmlFree(hostname);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Parse the first "path" child of "location" into a path array
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param location XML parse tree containing fileset location element
|
||
|
+ * @param fsloc a blank nfs_fsloc to fill in
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_parse_location_path(const char *pathname, xmlNodePtr location,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr node, component;
|
||
|
+ unsigned int count;
|
||
|
+ xmlChar *value;
|
||
|
+ char **result;
|
||
|
+
|
||
|
+ node = junction_xml_find_child_by_name(location, NFS_XML_PATH_TAG);
|
||
|
+ if (node == NULL)
|
||
|
+ return FEDFS_ERR_NOTJUNCT;
|
||
|
+
|
||
|
+ count = 0;
|
||
|
+ for (component = node->children;
|
||
|
+ component != NULL;
|
||
|
+ component = component->next) {
|
||
|
+ if (!junction_xml_match_node_name(component,
|
||
|
+ NFS_XML_COMPONENT_TAG))
|
||
|
+ continue;
|
||
|
+ value = xmlNodeGetContent(component);
|
||
|
+ if (junction_xml_is_empty(value)) {
|
||
|
+ xlog(D_GENERAL, "%s: Bad pathname component in %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_NOTJUNCT;
|
||
|
+ }
|
||
|
+ xmlFree(value);
|
||
|
+ count++;
|
||
|
+ }
|
||
|
+ xlog(D_GENERAL, "%s: Found %u component(s)", __func__, count);
|
||
|
+
|
||
|
+ if (count == 0) {
|
||
|
+ xlog(D_GENERAL, "%s: Zero-component pathname", __func__);
|
||
|
+ fsloc->nfl_rootpath = (char **)calloc(1, sizeof(char *));
|
||
|
+ if (fsloc->nfl_rootpath == NULL)
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ fsloc->nfl_rootpath[0] = NULL;
|
||
|
+ return FEDFS_OK;
|
||
|
+ }
|
||
|
+
|
||
|
+ result = calloc(count + 1, sizeof(char *));
|
||
|
+ if (result == NULL)
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+
|
||
|
+ count = 0;
|
||
|
+ for (component = node->children;
|
||
|
+ component != NULL;
|
||
|
+ component = component->next) {
|
||
|
+ if (!junction_xml_match_node_name(component,
|
||
|
+ NFS_XML_COMPONENT_TAG))
|
||
|
+ continue;
|
||
|
+ value = xmlNodeGetContent(component);
|
||
|
+ result[count] = strdup((const char *)value);
|
||
|
+ xmlFree(value);
|
||
|
+ if (result[count] == NULL) {
|
||
|
+ nfs_free_string_array(result);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+ count++;
|
||
|
+ }
|
||
|
+
|
||
|
+ fsloc->nfl_rootpath = result;
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Parse the first "currency" child of "location"
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param location XML parse tree containing fileset location element
|
||
|
+ * @param fsloc a blank nfs_fsloc to fill in
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_parse_location_currency(const char *pathname, xmlNodePtr location,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr node;
|
||
|
+
|
||
|
+ node = junction_xml_find_child_by_name(location, NFS_XML_CURRENCY_TAG);
|
||
|
+ if (node == NULL)
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ if (!junction_xml_get_int_content(node, &fsloc->nfl_currency))
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+
|
||
|
+out_err:
|
||
|
+ xlog(D_GENERAL, "%s: Missing or invalid currency element in %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_NOTJUNCT;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Parse the first "genflags" child of "location"
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param location XML parse tree containing fileset location element
|
||
|
+ * @param fsloc a blank nfs_fsloc to fill in
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_parse_location_genflags(const char *pathname, xmlNodePtr location,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr node;
|
||
|
+
|
||
|
+ node = junction_xml_find_child_by_name(location, NFS_XML_GENFLAGS_TAG);
|
||
|
+ if (node == NULL)
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ if (!junction_xml_get_bool_attribute(node,
|
||
|
+ NFS_XML_GENFLAGS_WRITABLE_ATTR,
|
||
|
+ &fsloc->nfl_genflags.nfl_writable))
|
||
|
+ goto out_err;
|
||
|
+ if (!junction_xml_get_bool_attribute(node,
|
||
|
+ NFS_XML_GENFLAGS_GOING_ATTR,
|
||
|
+ &fsloc->nfl_genflags.nfl_going))
|
||
|
+ goto out_err;
|
||
|
+ if (!junction_xml_get_bool_attribute(node,
|
||
|
+ NFS_XML_GENFLAGS_SPLIT_ATTR,
|
||
|
+ &fsloc->nfl_genflags.nfl_split))
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+
|
||
|
+out_err:
|
||
|
+ xlog(D_GENERAL, "%s: Missing or invalid genflags element in %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_NOTJUNCT;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Parse the first "transflags" child of "location"
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param location XML parse tree containing fileset location element
|
||
|
+ * @param fsloc a blank nfs_fsloc to fill in
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_parse_location_transflags(const char *pathname, xmlNodePtr location,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr node;
|
||
|
+
|
||
|
+ node = junction_xml_find_child_by_name(location, NFS_XML_TRANSFLAGS_TAG);
|
||
|
+ if (node == NULL)
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ if (!junction_xml_get_bool_attribute(node,
|
||
|
+ NFS_XML_TRANSFLAGS_RDMA_ATTR,
|
||
|
+ &fsloc->nfl_transflags.nfl_rdma))
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+
|
||
|
+out_err:
|
||
|
+ xlog(D_GENERAL, "%s: Missing or invalid transflags element in %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_NOTJUNCT;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Parse the first "class" child of "location"
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param location XML parse tree containing fileset location element
|
||
|
+ * @param fsloc a blank nfs_fsloc to fill in
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_parse_location_class(const char *pathname, xmlNodePtr location,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr node;
|
||
|
+
|
||
|
+ node = junction_xml_find_child_by_name(location, NFS_XML_CLASS_TAG);
|
||
|
+ if (node == NULL)
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ if (!junction_xml_get_u8_attribute(node,
|
||
|
+ NFS_XML_CLASS_SIMUL_ATTR,
|
||
|
+ &fsloc->nfl_info.nfl_simul))
|
||
|
+ goto out_err;
|
||
|
+ if (!junction_xml_get_u8_attribute(node,
|
||
|
+ NFS_XML_CLASS_HANDLE_ATTR,
|
||
|
+ &fsloc->nfl_info.nfl_handle))
|
||
|
+ goto out_err;
|
||
|
+ if (!junction_xml_get_u8_attribute(node,
|
||
|
+ NFS_XML_CLASS_FILEID_ATTR,
|
||
|
+ &fsloc->nfl_info.nfl_fileid))
|
||
|
+ goto out_err;
|
||
|
+ if (!junction_xml_get_u8_attribute(node,
|
||
|
+ NFS_XML_CLASS_WRITEVER_ATTR,
|
||
|
+ &fsloc->nfl_info.nfl_writever))
|
||
|
+ goto out_err;
|
||
|
+ if (!junction_xml_get_u8_attribute(node,
|
||
|
+ NFS_XML_CLASS_WRITEVER_ATTR,
|
||
|
+ &fsloc->nfl_info.nfl_writever))
|
||
|
+ goto out_err;
|
||
|
+ if (!junction_xml_get_u8_attribute(node,
|
||
|
+ NFS_XML_CLASS_CHANGE_ATTR,
|
||
|
+ &fsloc->nfl_info.nfl_change))
|
||
|
+ goto out_err;
|
||
|
+ if (!junction_xml_get_u8_attribute(node,
|
||
|
+ NFS_XML_CLASS_READDIR_ATTR,
|
||
|
+ &fsloc->nfl_info.nfl_readdir))
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+
|
||
|
+out_err:
|
||
|
+ xlog(D_GENERAL, "%s: Missing or invalid class element in %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_NOTJUNCT;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Parse the first "read" child of "location"
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param location XML parse tree containing fileset location element
|
||
|
+ * @param fsloc a blank nfs_fsloc to fill in
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_parse_location_read(const char *pathname, xmlNodePtr location,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr node;
|
||
|
+
|
||
|
+ node = junction_xml_find_child_by_name(location, NFS_XML_READ_TAG);
|
||
|
+ if (node == NULL)
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ if (!junction_xml_get_u8_attribute(node,
|
||
|
+ NFS_XML_READ_RANK_ATTR,
|
||
|
+ &fsloc->nfl_info.nfl_readrank))
|
||
|
+ goto out_err;
|
||
|
+ if (!junction_xml_get_u8_attribute(node,
|
||
|
+ NFS_XML_READ_ORDER_ATTR,
|
||
|
+ &fsloc->nfl_info.nfl_readorder))
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+
|
||
|
+out_err:
|
||
|
+ xlog(D_GENERAL, "%s: Missing or invalid read element in %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_NOTJUNCT;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Parse the first "write" child of "location"
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param location XML parse tree containing fileset location element
|
||
|
+ * @param fsloc a blank nfs_fsloc to fill in
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_parse_location_write(const char *pathname, xmlNodePtr location,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr node;
|
||
|
+
|
||
|
+ node = junction_xml_find_child_by_name(location, NFS_XML_WRITE_TAG);
|
||
|
+ if (node == NULL)
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ if (!junction_xml_get_u8_attribute(node,
|
||
|
+ NFS_XML_WRITE_RANK_ATTR,
|
||
|
+ &fsloc->nfl_info.nfl_writerank))
|
||
|
+ goto out_err;
|
||
|
+ if (!junction_xml_get_u8_attribute(node,
|
||
|
+ NFS_XML_WRITE_ORDER_ATTR,
|
||
|
+ &fsloc->nfl_info.nfl_writeorder))
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+
|
||
|
+out_err:
|
||
|
+ xlog(D_GENERAL, "%s: Missing or invalid write element in %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_NOTJUNCT;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Parse the first "flags" child of "location"
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param location XML parse tree containing fileset location element
|
||
|
+ * @param fsloc a blank nfs_fsloc to fill in
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_parse_location_flags(const char *pathname, xmlNodePtr location,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr node;
|
||
|
+
|
||
|
+ node = junction_xml_find_child_by_name(location, NFS_XML_FLAGS_TAG);
|
||
|
+ if (node == NULL)
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ if (!junction_xml_get_bool_attribute(node,
|
||
|
+ NFS_XML_FLAGS_VARSUB_ATTR,
|
||
|
+ &fsloc->nfl_flags.nfl_varsub))
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+
|
||
|
+out_err:
|
||
|
+ xlog(D_GENERAL, "%s: Missing or invalid flags element in %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_NOTJUNCT;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Parse the first "validfor" child of "location"
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param location XML parse tree containing fileset location element
|
||
|
+ * @param fsloc a blank nfs_fsloc to fill in
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_parse_location_validfor(const char *pathname, xmlNodePtr location,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ xmlNodePtr node;
|
||
|
+
|
||
|
+ node = junction_xml_find_child_by_name(location, NFS_XML_VALIDFOR_TAG);
|
||
|
+ if (node == NULL)
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ if (!junction_xml_get_int_content(node, &fsloc->nfl_validfor))
|
||
|
+ goto out_err;
|
||
|
+
|
||
|
+ return FEDFS_OK;
|
||
|
+
|
||
|
+out_err:
|
||
|
+ xlog(D_GENERAL, "%s: Missing or invalid validfor element in %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_NOTJUNCT;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Parse children of NFS location element in an NFS junction
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param location XML parse tree containing fileset location element
|
||
|
+ * @param fsloc a blank nfs_fsloc to fill in
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * All children are required only-once elements, and may appear in any order.
|
||
|
+ * Extraneous or repeated elements are ignored for now.
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_parse_location_children(const char *pathname, xmlNodePtr location,
|
||
|
+ struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+
|
||
|
+ retval = nfs_parse_location_host(pathname, location, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_parse_location_path(pathname, location, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_parse_location_currency(pathname, location, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_parse_location_genflags(pathname, location, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_parse_location_transflags(pathname, location, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_parse_location_class(pathname, location, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_parse_location_read(pathname, location, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_parse_location_write(pathname, location, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ retval = nfs_parse_location_flags(pathname, location, fsloc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+ return nfs_parse_location_validfor(pathname, location, fsloc);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Parse NFS location element in an NFS junction
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param location XML parse tree containing fileset location element
|
||
|
+ * @param fsloc OUT: a single NFS location item
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * If nfs_parse_location() returns FEDFS_OK, caller must free the returned
|
||
|
+ * location with nfs_free_location().
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_parse_node(const char *pathname, xmlNodePtr location,
|
||
|
+ struct nfs_fsloc **fsloc)
|
||
|
+{
|
||
|
+ struct nfs_fsloc *tmp;
|
||
|
+ FedFsStatus retval;
|
||
|
+
|
||
|
+ tmp = nfs_new_location();
|
||
|
+ if (tmp == NULL)
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+
|
||
|
+ retval = nfs_parse_location_children(pathname, location, tmp);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ nfs_free_location(tmp);
|
||
|
+ else
|
||
|
+ *fsloc = tmp;
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Build list of NFS locations from a nodeset
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param nodeset XML nodeset containing "location" elements
|
||
|
+ * @param fslocs OUT: pointer to a list of NFS locations
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * If nfs_parse_nodeset() returns FEDFS_OK, caller must free the returned
|
||
|
+ * list of locations with nfs_free_locations().
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_parse_nodeset(const char *pathname, xmlNodeSetPtr nodeset,
|
||
|
+ struct nfs_fsloc **fslocs)
|
||
|
+{
|
||
|
+ struct nfs_fsloc *location, *result = NULL;
|
||
|
+ FedFsStatus retval;
|
||
|
+ int i;
|
||
|
+
|
||
|
+ if (xmlXPathNodeSetIsEmpty(nodeset)) {
|
||
|
+ xlog(D_GENERAL, "%s: No fileset locations found in %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_NOTJUNCT;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0; i < nodeset->nodeNr; i++) {
|
||
|
+ xmlNodePtr node = nodeset->nodeTab[i];
|
||
|
+
|
||
|
+ retval = nfs_parse_node(pathname, node, &location);
|
||
|
+ if (retval != FEDFS_OK) {
|
||
|
+ nfs_free_locations(result);
|
||
|
+ return retval;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (result == NULL)
|
||
|
+ result = location;
|
||
|
+ else
|
||
|
+ result->nfl_next = location;
|
||
|
+ }
|
||
|
+
|
||
|
+ *fslocs = result;
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Parse fileset location information from junction XML
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param context XML path context containing junction XML
|
||
|
+ * @param fslocs OUT: pointer to a list of NFS locations
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * If nfs_parse_context() returns FEDFS_OK, caller must free the returned
|
||
|
+ * list of locations with nfs_free_locations().
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_parse_context(const char *pathname, xmlXPathContextPtr context,
|
||
|
+ struct nfs_fsloc **fslocs)
|
||
|
+{
|
||
|
+ xmlXPathObjectPtr object;
|
||
|
+ FedFsStatus retval;
|
||
|
+
|
||
|
+ object = xmlXPathEvalExpression(NFS_XML_LOCATION_XPATH, context);
|
||
|
+ if (object == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to evaluate XML in %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_NOTJUNCT;
|
||
|
+ }
|
||
|
+
|
||
|
+ retval = nfs_parse_nodeset(pathname, object->nodesetval, fslocs);
|
||
|
+
|
||
|
+ xmlXPathFreeObject(object);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Parse NFS locations information from junction XML
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param doc XML parse tree containing junction XML document
|
||
|
+ * @param fslocs OUT: pointer to a list of NFS locations
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * If nfs_parse_xml() returns FEDFS_OK, caller must free the returned
|
||
|
+ * list of locations with nfs_free_locations().
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_parse_xml(const char *pathname, xmlDocPtr doc, struct nfs_fsloc **fslocs)
|
||
|
+{
|
||
|
+ xmlXPathContextPtr context;
|
||
|
+ FedFsStatus retval;
|
||
|
+
|
||
|
+ context = xmlXPathNewContext(doc);
|
||
|
+ if (context == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Failed to create XPath context from %s",
|
||
|
+ __func__, pathname);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ retval = nfs_parse_context(pathname, context, fslocs);
|
||
|
+
|
||
|
+ xmlXPathFreeContext(context);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Retrieve list of NFS locations from an NFS junction
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a junction
|
||
|
+ * @param fslocs OUT: pointer to a list of NFS locations
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * If nfs_get_locations() returns FEDFS_OK, caller must free the returned
|
||
|
+ * list of locations with nfs_free_locations().
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+nfs_get_locations(const char *pathname, struct nfs_fsloc **fslocs)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+ xmlDocPtr doc;
|
||
|
+
|
||
|
+ if (fslocs == NULL)
|
||
|
+ return FEDFS_ERR_INVAL;
|
||
|
+
|
||
|
+ retval = junction_xml_parse(pathname, JUNCTION_XATTR_NAME_NFS, &doc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ retval = nfs_parse_xml(pathname, doc, fslocs);
|
||
|
+
|
||
|
+ xmlFreeDoc(doc);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Predicate: does "pathname" refer to an object that can become an NFS junction?
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a directory
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * Return values:
|
||
|
+ * FEDFS_ERR_NOTJUNCT: "pathname" refers to an object that can be
|
||
|
+ * made into a NFS junction
|
||
|
+ * FEDFS_ERR_EXIST: "pathname" refers to something that is
|
||
|
+ * already a junction
|
||
|
+ * FEDFS_ERR_INVAL: "pathname" does not exist
|
||
|
+ * Other: Some error occurred, "pathname" not
|
||
|
+ * investigated
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+nfs_is_prejunction(const char *pathname)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+ int fd;
|
||
|
+
|
||
|
+ retval = junction_open_path(pathname, &fd);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ retval = junction_is_directory(fd, pathname);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ goto out_close;
|
||
|
+
|
||
|
+ retval = junction_is_sticky_bit_set(fd, pathname);
|
||
|
+ switch (retval) {
|
||
|
+ case FEDFS_ERR_NOTJUNCT:
|
||
|
+ break;
|
||
|
+ case FEDFS_OK:
|
||
|
+ goto out_exist;
|
||
|
+ default:
|
||
|
+ goto out_close;
|
||
|
+ }
|
||
|
+
|
||
|
+ retval = junction_is_xattr_present(fd, pathname, JUNCTION_XATTR_NAME_NFS);
|
||
|
+ switch (retval) {
|
||
|
+ case FEDFS_ERR_NOTJUNCT:
|
||
|
+ break;
|
||
|
+ case FEDFS_OK:
|
||
|
+ goto out_exist;
|
||
|
+ default:
|
||
|
+ goto out_close;
|
||
|
+ }
|
||
|
+
|
||
|
+out_close:
|
||
|
+ (void)close(fd);
|
||
|
+ return retval;
|
||
|
+out_exist:
|
||
|
+ retval = FEDFS_ERR_EXIST;
|
||
|
+ goto out_close;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Verify that junction contains NFS junction XML
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a directory
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * Return values:
|
||
|
+ * FEDFS_OK: "pathname" refers to an NFS junction
|
||
|
+ * FEDFS_ERR_NOTJUNCT: "pathname" refers to something that is
|
||
|
+ * not an NFS junction
|
||
|
+ * FEDFS_ERR_INVAL: "pathname" does not exist
|
||
|
+ * Other: Some error occurred, "pathname" not
|
||
|
+ * investigated
|
||
|
+ *
|
||
|
+ * NB: This is an expensive test. However, it is only done if the object
|
||
|
+ * actually has a junction extended attribute, meaning it should be done
|
||
|
+ * rarely. If this is really a problem, we can make the XML test cheaper.
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfs_is_junction_xml(const char *pathname)
|
||
|
+{
|
||
|
+ struct nfs_fsloc *fslocs = NULL;
|
||
|
+ FedFsStatus retval;
|
||
|
+ xmlDocPtr doc;
|
||
|
+
|
||
|
+ retval = junction_xml_parse(pathname, JUNCTION_XATTR_NAME_NFS, &doc);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ retval = nfs_parse_xml(pathname, doc, &fslocs);
|
||
|
+ nfs_free_locations(fslocs);
|
||
|
+
|
||
|
+ xmlFreeDoc(doc);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Predicate: does "pathname" refer to an NFS junction?
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a directory
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * Return values:
|
||
|
+ * FEDFS_OK: "pathname" refers to an NFS junction
|
||
|
+ * FEDFS_ERR_NOTJUNCT: "pathname" refers to an object that is
|
||
|
+ * not a junction
|
||
|
+ * FEDFS_ERR_INVAL: "pathname" does not exist
|
||
|
+ * Other: Some error occurred, "pathname" not
|
||
|
+ * investigated
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+nfs_is_junction(const char *pathname)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+ int fd;
|
||
|
+
|
||
|
+ retval = junction_open_path(pathname, &fd);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ retval = junction_is_directory(fd, pathname);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ goto out_close;
|
||
|
+
|
||
|
+ retval = junction_is_sticky_bit_set(fd, pathname);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ goto out_close;
|
||
|
+
|
||
|
+ retval = junction_is_xattr_present(fd, pathname, JUNCTION_XATTR_NAME_NFS);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ goto out_close;
|
||
|
+
|
||
|
+ (void)close(fd);
|
||
|
+
|
||
|
+ return nfs_is_junction_xml(pathname);
|
||
|
+
|
||
|
+out_close:
|
||
|
+ (void)close(fd);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
diff --git a/support/junction/path.c b/support/junction/path.c
|
||
|
new file mode 100644
|
||
|
index 0000000..68a1d13
|
||
|
--- /dev/null
|
||
|
+++ b/support/junction/path.c
|
||
|
@@ -0,0 +1,346 @@
|
||
|
+/**
|
||
|
+ * @file support/junction/path.c
|
||
|
+ * @brief Encode and decode FedFS pathnames
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Copyright 2010, 2011, 2018 Oracle. All rights reserved.
|
||
|
+ *
|
||
|
+ * This file is part of nfs-utils.
|
||
|
+ *
|
||
|
+ * nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License version 2.0 as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License version 2.0 for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * version 2.0 along with nfs-utils. If not, see:
|
||
|
+ *
|
||
|
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+ */
|
||
|
+
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+
|
||
|
+#include <stdbool.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <stdint.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <string.h>
|
||
|
+#include <errno.h>
|
||
|
+#include <dirent.h>
|
||
|
+
|
||
|
+#include <netinet/in.h>
|
||
|
+
|
||
|
+#include "junction.h"
|
||
|
+#include "xlog.h"
|
||
|
+
|
||
|
+#define STRLEN_SLASH ((size_t)1) /* strlen("/") */
|
||
|
+
|
||
|
+#define XDR_UINT_BYTES (sizeof(uint32_t))
|
||
|
+
|
||
|
+/**
|
||
|
+ * Compute count of XDR 4-octet units from byte count
|
||
|
+ *
|
||
|
+ * @param bytes number of bytes to convert
|
||
|
+ * @return equivalent number of XDR 4-octet units
|
||
|
+ */
|
||
|
+static inline size_t
|
||
|
+nsdb_quadlen(size_t bytes)
|
||
|
+{
|
||
|
+ return (bytes + 3) >> 2;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Free array of NUL-terminated C strings
|
||
|
+ *
|
||
|
+ * @param strings array of char * to be released
|
||
|
+ */
|
||
|
+void
|
||
|
+nsdb_free_string_array(char **strings)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+
|
||
|
+ if (strings == NULL)
|
||
|
+ return;
|
||
|
+ for (i = 0; strings[i] != NULL; i++)
|
||
|
+ free(strings[i]);
|
||
|
+ free(strings);
|
||
|
+}
|
||
|
+
|
||
|
+static FedFsStatus
|
||
|
+nsdb_alloc_zero_component_pathname(char ***path_array)
|
||
|
+{
|
||
|
+ char **result;
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: Zero-component pathname", __func__);
|
||
|
+
|
||
|
+ result = (char **)calloc(1, sizeof(char *));
|
||
|
+ if (result == NULL)
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ result[0] = NULL;
|
||
|
+ *path_array = result;
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Sanitize an incoming POSIX path
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing a POSIX pathname
|
||
|
+ * @return NUL-terminated C string containing sanitized path
|
||
|
+ *
|
||
|
+ * Caller must free the returned pathname with free(3).
|
||
|
+ *
|
||
|
+ * Remove multiple sequential slashes and any trailing slashes,
|
||
|
+ * but leave "/" by itself alone.
|
||
|
+ */
|
||
|
+static __attribute_malloc__ char *
|
||
|
+nsdb_normalize_path(const char *pathname)
|
||
|
+{
|
||
|
+ size_t i, j, len;
|
||
|
+ char *result;
|
||
|
+
|
||
|
+ len = strlen(pathname);
|
||
|
+ if (len == 0) {
|
||
|
+ xlog(D_CALL, "%s: NULL pathname", __func__);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ result = malloc(len + 1);
|
||
|
+ if (result == NULL)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ for (i = 0, j = 0; i < len; i++) {
|
||
|
+ if (pathname[i] == '/' && pathname[i + 1] == '/')
|
||
|
+ continue;
|
||
|
+ result[j++] = pathname[i];
|
||
|
+ }
|
||
|
+ result[j] = '\0';
|
||
|
+
|
||
|
+ if (j > 1 && result[j - 1] == '/')
|
||
|
+ result[j - 1] = '\0';
|
||
|
+
|
||
|
+ xlog(D_CALL, "%s: result = '%s'", __func__, result);
|
||
|
+ return result;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Count the number of components in a POSIX pathname
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing a POSIX pathname
|
||
|
+ * @param len OUT: number of bytes the encoded XDR stream will consume
|
||
|
+ * @param cnt OUT: component count
|
||
|
+ * @return true when successful
|
||
|
+ */
|
||
|
+static _Bool
|
||
|
+nsdb_count_components(const char *pathname, size_t *len,
|
||
|
+ unsigned int *cnt)
|
||
|
+{
|
||
|
+ char *start, *component;
|
||
|
+ unsigned int count;
|
||
|
+ size_t length;
|
||
|
+
|
||
|
+ /* strtok(3) will tromp on the string */
|
||
|
+ start = strdup(pathname);
|
||
|
+ if (start == NULL)
|
||
|
+ return false;
|
||
|
+
|
||
|
+ length = XDR_UINT_BYTES;
|
||
|
+ count = 0;
|
||
|
+ component = start;
|
||
|
+ for ( ;; ) {
|
||
|
+ char *next;
|
||
|
+ size_t tmp;
|
||
|
+
|
||
|
+ if (*component == '/')
|
||
|
+ component++;
|
||
|
+ if (*component == '\0')
|
||
|
+ break;
|
||
|
+ next = strchrnul(component, '/');
|
||
|
+ tmp = (size_t)(next - component);
|
||
|
+ if (tmp > 255)
|
||
|
+ return false;
|
||
|
+ length += XDR_UINT_BYTES + (nsdb_quadlen(tmp) << 2);
|
||
|
+ count++;
|
||
|
+
|
||
|
+ if (*next == '\0')
|
||
|
+ break;
|
||
|
+ component = next;
|
||
|
+ }
|
||
|
+
|
||
|
+ free(start);
|
||
|
+
|
||
|
+ xlog(D_CALL, "%s: length = %zu, count = %u, path = '%s'",
|
||
|
+ __func__, length, count, pathname);
|
||
|
+ *len = length;
|
||
|
+ *cnt = count;
|
||
|
+ return true;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Predicate: is input character set for a POSIX pathname valid UTF-8?
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing a POSIX path
|
||
|
+ * @return true if the string is valid UTF-8
|
||
|
+ *
|
||
|
+ * XXX: implement this
|
||
|
+ */
|
||
|
+static _Bool
|
||
|
+nsdb_pathname_is_utf8(__attribute__((unused)) const char *pathname)
|
||
|
+{
|
||
|
+ return true;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Construct a local POSIX-style pathname from an array of component strings
|
||
|
+ *
|
||
|
+ * @param path_array array of pointers to NUL-terminated C strings
|
||
|
+ * @param pathname OUT: pointer to NUL-terminated UTF-8 C string containing a POSIX-style path
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * Caller must free the returned pathname with free(3).
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+nsdb_path_array_to_posix(char * const *path_array, char **pathname)
|
||
|
+{
|
||
|
+ char *component, *result;
|
||
|
+ unsigned int i, count;
|
||
|
+ size_t length, len;
|
||
|
+
|
||
|
+ if (path_array == NULL || pathname == NULL)
|
||
|
+ return FEDFS_ERR_INVAL;
|
||
|
+
|
||
|
+ if (path_array[0] == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Zero-component pathname", __func__);
|
||
|
+ result = strdup("/");
|
||
|
+ if (result == NULL)
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ *pathname = result;
|
||
|
+ return FEDFS_OK;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (length = 0, count = 0;
|
||
|
+ path_array[count] != NULL;
|
||
|
+ count++) {
|
||
|
+ component = path_array[count];
|
||
|
+ len = strlen(component);
|
||
|
+
|
||
|
+ if (len == 0) {
|
||
|
+ xlog(D_GENERAL, "%s: Zero-length component", __func__);
|
||
|
+ return FEDFS_ERR_BADNAME;
|
||
|
+ }
|
||
|
+ if (len > NAME_MAX) {
|
||
|
+ xlog(D_GENERAL, "%s: Component length too long", __func__);
|
||
|
+ return FEDFS_ERR_NAMETOOLONG;
|
||
|
+ }
|
||
|
+ if (strchr(component, '/') != NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: Local separator character "
|
||
|
+ "found in component", __func__);
|
||
|
+ return FEDFS_ERR_BADNAME;
|
||
|
+ }
|
||
|
+ if (!nsdb_pathname_is_utf8(component)) {
|
||
|
+ xlog(D_GENERAL, "%s: Bad character in component",
|
||
|
+ __func__);
|
||
|
+ return FEDFS_ERR_BADCHAR;
|
||
|
+ }
|
||
|
+
|
||
|
+ length += STRLEN_SLASH + len;
|
||
|
+
|
||
|
+ if (length > PATH_MAX) {
|
||
|
+ xlog(D_GENERAL, "%s: Pathname too long", __func__);
|
||
|
+ return FEDFS_ERR_NAMETOOLONG;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ result = calloc(1, length + 1);
|
||
|
+ if (result == NULL)
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+
|
||
|
+ for (i = 0; i < count; i++) {
|
||
|
+ strcat(result, "/");
|
||
|
+ strcat(result, path_array[i]);
|
||
|
+ }
|
||
|
+ *pathname = nsdb_normalize_path(result);
|
||
|
+ free(result);
|
||
|
+ if (*pathname == NULL)
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Construct an array of component strings from a local POSIX-style pathname
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing a POSIX-style pathname
|
||
|
+ * @param path_array OUT: pointer to array of pointers to NUL-terminated C strings
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * Caller must free "path_array" with nsdb_free_string_array().
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+nsdb_posix_to_path_array(const char *pathname, char ***path_array)
|
||
|
+{
|
||
|
+ char *normalized, *component, **result;
|
||
|
+ unsigned int i, count;
|
||
|
+ size_t length;
|
||
|
+
|
||
|
+ if (pathname == NULL || path_array == NULL)
|
||
|
+ return FEDFS_ERR_INVAL;
|
||
|
+
|
||
|
+ if (!nsdb_pathname_is_utf8(pathname)) {
|
||
|
+ xlog(D_GENERAL, "%s: Bad character in pathname", __func__);
|
||
|
+ return FEDFS_ERR_BADCHAR;
|
||
|
+ }
|
||
|
+
|
||
|
+ normalized = nsdb_normalize_path(pathname);
|
||
|
+ if (normalized == NULL)
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+
|
||
|
+ if (!nsdb_count_components(normalized, &length, &count)) {
|
||
|
+ free(normalized);
|
||
|
+ return FEDFS_ERR_BADNAME;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (count == 0) {
|
||
|
+ free(normalized);
|
||
|
+ return nsdb_alloc_zero_component_pathname(path_array);
|
||
|
+ }
|
||
|
+
|
||
|
+ result = (char **)calloc(count + 1, sizeof(char *));
|
||
|
+ if (result == NULL) {
|
||
|
+ free(normalized);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ component = normalized;
|
||
|
+ for (i = 0; ; i++) {
|
||
|
+ char *next;
|
||
|
+
|
||
|
+ if (*component == '/')
|
||
|
+ component++;
|
||
|
+ if (*component == '\0')
|
||
|
+ break;
|
||
|
+ next = strchrnul(component, '/');
|
||
|
+ length = (size_t)(next - component);
|
||
|
+ if (length > 255)
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+
|
||
|
+ result[i] = strndup(component, length);
|
||
|
+ if (result[i] == NULL) {
|
||
|
+ nsdb_free_string_array(result);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (*next == '\0')
|
||
|
+ break;
|
||
|
+ component = next;
|
||
|
+ }
|
||
|
+
|
||
|
+ *path_array = result;
|
||
|
+ free(normalized);
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
diff --git a/support/junction/xml.c b/support/junction/xml.c
|
||
|
new file mode 100644
|
||
|
index 0000000..79b0770
|
||
|
--- /dev/null
|
||
|
+++ b/support/junction/xml.c
|
||
|
@@ -0,0 +1,401 @@
|
||
|
+/**
|
||
|
+ * @file support/junction/xml.c
|
||
|
+ * @brief Common utilities for managing junction XML
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Copyright 2011, 2018 Oracle. All rights reserved.
|
||
|
+ *
|
||
|
+ * This file is part of nfs-utils.
|
||
|
+ *
|
||
|
+ * nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License version 2.0 as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License version 2.0 for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * version 2.0 along with nfs-utils. If not, see:
|
||
|
+ *
|
||
|
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+ */
|
||
|
+
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+
|
||
|
+#include <stdbool.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <string.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <errno.h>
|
||
|
+
|
||
|
+#include "junction.h"
|
||
|
+#include "junction-internal.h"
|
||
|
+#include "xlog.h"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Predicate: is element content empty?
|
||
|
+ *
|
||
|
+ * @param content element content to test
|
||
|
+ * @return true if content is empty
|
||
|
+ */
|
||
|
+_Bool
|
||
|
+junction_xml_is_empty(const xmlChar *content)
|
||
|
+{
|
||
|
+ return content == NULL || *content == '\0';
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Match an XML parse tree node by its name
|
||
|
+ *
|
||
|
+ * @param node pointer to a node in an XML parse tree
|
||
|
+ * @param name NUL-terminated C string containing name to match
|
||
|
+ * @return true if "node" is named "name"
|
||
|
+ */
|
||
|
+_Bool
|
||
|
+junction_xml_match_node_name(xmlNodePtr node, const xmlChar *name)
|
||
|
+{
|
||
|
+ return (node->type == XML_ELEMENT_NODE) &&
|
||
|
+ (xmlStrcmp(node->name, name) == 0);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Find a first-level child of "parent" named "name"
|
||
|
+ *
|
||
|
+ * @param parent pointer to node whose children are to be searched
|
||
|
+ * @param name NUL-terminated C string containing name to match
|
||
|
+ * @return pointer to child of "parent" whose name is "name"
|
||
|
+ */
|
||
|
+xmlNodePtr
|
||
|
+junction_xml_find_child_by_name(xmlNodePtr parent, const xmlChar *name)
|
||
|
+{
|
||
|
+ xmlNodePtr node;
|
||
|
+
|
||
|
+ for (node = parent->children; node != NULL; node = node->next)
|
||
|
+ if (junction_xml_match_node_name(node, name))
|
||
|
+ return node;
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Read attribute into a boolean
|
||
|
+ *
|
||
|
+ * @param node pointer to a node in an XML parse tree
|
||
|
+ * @param attrname NUL-terminated C string containing attribute name
|
||
|
+ * @param value OUT: attribute's value converted to an integer
|
||
|
+ * @return true if attribute "attrname" has a valid boolean value
|
||
|
+ */
|
||
|
+_Bool
|
||
|
+junction_xml_get_bool_attribute(xmlNodePtr node, const xmlChar *attrname,
|
||
|
+ _Bool *value)
|
||
|
+{
|
||
|
+ xmlChar *prop;
|
||
|
+ _Bool retval;
|
||
|
+
|
||
|
+ retval = false;
|
||
|
+ prop = xmlGetProp(node, attrname);
|
||
|
+ if (prop == NULL)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ if (xmlStrcmp(prop, (const xmlChar *)"true") == 0) {
|
||
|
+ *value = true;
|
||
|
+ retval = true;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (xmlStrcmp(prop, (const xmlChar *)"false") == 0) {
|
||
|
+ *value = false;
|
||
|
+ retval = true;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+out:
|
||
|
+ xmlFree(prop);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Set attribute to a boolean
|
||
|
+ *
|
||
|
+ * @param node pointer to a node in an XML parse tree
|
||
|
+ * @param attrname NUL-terminated C string containing attribute name
|
||
|
+ * @param value boolean value to set
|
||
|
+ */
|
||
|
+void
|
||
|
+junction_xml_set_bool_attribute(xmlNodePtr node, const xmlChar *attrname,
|
||
|
+ _Bool value)
|
||
|
+{
|
||
|
+ xmlSetProp(node, attrname, (const xmlChar *)(value ? "true" : "false"));
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Read attribute into an uint8_t
|
||
|
+ *
|
||
|
+ * @param node pointer to a node in an XML parse tree
|
||
|
+ * @param attrname NUL-terminated C string containing attribute name
|
||
|
+ * @param value OUT: attribute's value converted to an uint8_t
|
||
|
+ * @return true if attribute "attrname" has a valid uint8_t value
|
||
|
+ */
|
||
|
+_Bool
|
||
|
+junction_xml_get_u8_attribute(xmlNodePtr node, const xmlChar *attrname,
|
||
|
+ uint8_t *value)
|
||
|
+{
|
||
|
+ char *endptr;
|
||
|
+ _Bool retval;
|
||
|
+ char *prop;
|
||
|
+ long tmp;
|
||
|
+
|
||
|
+ retval = false;
|
||
|
+ prop = (char *)xmlGetProp(node, attrname);
|
||
|
+ if (prop == NULL)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ errno = 0;
|
||
|
+ tmp = strtol(prop, &endptr, 10);
|
||
|
+ if (errno != 0 || *endptr != '\0' || tmp > 255 || tmp < 0)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ *value = (uint8_t)tmp;
|
||
|
+ retval = true;
|
||
|
+
|
||
|
+out:
|
||
|
+ xmlFree(prop);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Read attribute into an integer
|
||
|
+ *
|
||
|
+ * @param node pointer to a node in an XML parse tree
|
||
|
+ * @param attrname NUL-terminated C string containing attribute name
|
||
|
+ * @param value OUT: attribute's value converted to an integer
|
||
|
+ * @return true if attribute "attrname" has a valid integer value
|
||
|
+ */
|
||
|
+_Bool
|
||
|
+junction_xml_get_int_attribute(xmlNodePtr node, const xmlChar *attrname,
|
||
|
+ int *value)
|
||
|
+{
|
||
|
+ char *endptr;
|
||
|
+ _Bool retval;
|
||
|
+ char *prop;
|
||
|
+ long tmp;
|
||
|
+
|
||
|
+ retval = false;
|
||
|
+ prop = (char *)xmlGetProp(node, attrname);
|
||
|
+ if (prop == NULL)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ errno = 0;
|
||
|
+ tmp = strtol(prop, &endptr, 10);
|
||
|
+ if (errno != 0 || *endptr != '\0' || tmp > INT32_MAX || tmp < INT32_MIN)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ *value = (int)tmp;
|
||
|
+ retval = true;
|
||
|
+
|
||
|
+out:
|
||
|
+ xmlFree(prop);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Set attribute to an integer
|
||
|
+ *
|
||
|
+ * @param node pointer to a node in an XML parse tree
|
||
|
+ * @param attrname NUL-terminated C string containing attribute name
|
||
|
+ * @param value integer value to set
|
||
|
+ */
|
||
|
+void
|
||
|
+junction_xml_set_int_attribute(xmlNodePtr node, const xmlChar *attrname,
|
||
|
+ int value)
|
||
|
+{
|
||
|
+ char buf[16];
|
||
|
+
|
||
|
+ snprintf(buf, sizeof(buf), "%d", value);
|
||
|
+ xmlSetProp(node, attrname, (const xmlChar *)buf);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Read node content into an integer
|
||
|
+ *
|
||
|
+ * @param node pointer to a node in an XML parse tree
|
||
|
+ * @param value OUT: node's content converted to an integer
|
||
|
+ * @return true if "node" has valid integer content
|
||
|
+ */
|
||
|
+_Bool
|
||
|
+junction_xml_get_int_content(xmlNodePtr node, int *value)
|
||
|
+{
|
||
|
+ xmlChar *content;
|
||
|
+ char *endptr;
|
||
|
+ _Bool retval;
|
||
|
+ long tmp;
|
||
|
+
|
||
|
+ retval = false;
|
||
|
+ content = xmlNodeGetContent(node);
|
||
|
+ if (content == NULL)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ errno = 0;
|
||
|
+ tmp = strtol((const char *)content, &endptr, 10);
|
||
|
+ if (errno != 0 || *endptr != '\0' || tmp > INT32_MAX || tmp < INT32_MIN)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ *value = (int)tmp;
|
||
|
+ retval = true;
|
||
|
+
|
||
|
+out:
|
||
|
+ xmlFree(content);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Add a child node with integer content
|
||
|
+ *
|
||
|
+ * @param parent pointer to a node in an XML parse tree
|
||
|
+ * @param name NUL-terminated C string containing name of child to add
|
||
|
+ * @param value set node content to this value
|
||
|
+ * @return pointer to new child node
|
||
|
+ */
|
||
|
+xmlNodePtr
|
||
|
+junction_xml_set_int_content(xmlNodePtr parent, const xmlChar *name, int value)
|
||
|
+{
|
||
|
+ char buf[16];
|
||
|
+
|
||
|
+ snprintf(buf, sizeof(buf), "%d", value);
|
||
|
+ return xmlNewTextChild(parent, NULL, name, (const xmlChar *)buf);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Parse XML document in a buffer into an XML document tree
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a directory
|
||
|
+ * @param name NUL-terminated C string containing name of xattr to replace
|
||
|
+ * @param buf opaque byte array containing XML to parse
|
||
|
+ * @param len size of "buf" in bytes
|
||
|
+ * @param doc OUT: an XML parse tree containing junction XML
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * If junction_parse_xml_buf() returns success, caller must free "*doc"
|
||
|
+ * using xmlFreeDoc(3).
|
||
|
+ *
|
||
|
+ * @note Access to trusted attributes requires CAP_SYS_ADMIN.
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+junction_parse_xml_buf(const char *pathname, const char *name,
|
||
|
+ void *buf, size_t len, xmlDocPtr *doc)
|
||
|
+{
|
||
|
+ xmlDocPtr tmp;
|
||
|
+
|
||
|
+ tmp = xmlParseMemory(buf, (int)len);
|
||
|
+ if (tmp == NULL) {
|
||
|
+ xlog(D_GENERAL, "Failed to parse XML in %s(%s)\n",
|
||
|
+ pathname, name);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ *doc = tmp;
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Read an XML document from an extended attribute into an XML document tree
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a directory
|
||
|
+ * @param fd an open file descriptor
|
||
|
+ * @param name NUL-terminated C string containing name of xattr to replace
|
||
|
+ * @param doc OUT: an XML parse tree containing junction XML
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * If junction_parse_xml_read() returns success, caller must free "*doc"
|
||
|
+ * using xmlFreeDoc(3).
|
||
|
+ *
|
||
|
+ * @note Access to trusted attributes requires CAP_SYS_ADMIN.
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+junction_parse_xml_read(const char *pathname, int fd, const char *name,
|
||
|
+ xmlDocPtr *doc)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+ void *buf = NULL;
|
||
|
+ size_t len;
|
||
|
+
|
||
|
+ retval = junction_get_xattr(fd, pathname, name, &buf, &len);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ xlog(D_CALL, "%s: XML document contained in junction:\n%.*s",
|
||
|
+ __func__, len, buf);
|
||
|
+
|
||
|
+ retval = junction_parse_xml_buf(pathname, name, buf, len, doc);
|
||
|
+
|
||
|
+ free(buf);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Read an XML document from an extended attribute into an XML document tree
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a directory
|
||
|
+ * @param name NUL-terminated C string containing name of xattr to replace
|
||
|
+ * @param doc OUT: an XML parse tree containing junction XML
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * If junction_parse_xml() returns success, caller must free "*doc"
|
||
|
+ * using xmlFreeDoc(3).
|
||
|
+ *
|
||
|
+ * @note Access to trusted attributes requires CAP_SYS_ADMIN.
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+junction_xml_parse(const char *pathname, const char *name, xmlDocPtr *doc)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+ int fd;
|
||
|
+
|
||
|
+ retval = junction_open_path(pathname, &fd);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ retval = junction_parse_xml_read(pathname, fd, name, doc);
|
||
|
+
|
||
|
+ (void)close(fd);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Write an XML document into an extended attribute
|
||
|
+ *
|
||
|
+ * @param pathname NUL-terminated C string containing pathname of a directory
|
||
|
+ * @param name NUL-terminated C string containing name of xattr to replace
|
||
|
+ * @param doc an XML parse tree containing junction XML
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * @note Access to trusted attributes requires CAP_SYS_ADMIN.
|
||
|
+ */
|
||
|
+FedFsStatus
|
||
|
+junction_xml_write(const char *pathname, const char *name, xmlDocPtr doc)
|
||
|
+{
|
||
|
+ xmlChar *buf = NULL;
|
||
|
+ FedFsStatus retval;
|
||
|
+ int fd, len;
|
||
|
+
|
||
|
+ retval = junction_open_path(pathname, &fd);
|
||
|
+ if (retval != FEDFS_OK)
|
||
|
+ return retval;
|
||
|
+
|
||
|
+ retval = FEDFS_ERR_SVRFAULT;
|
||
|
+ xmlIndentTreeOutput = 1;
|
||
|
+ xmlDocDumpFormatMemoryEnc(doc, &buf, &len, "UTF-8", 1);
|
||
|
+ if (len < 0)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ retval = junction_set_xattr(fd, pathname, name, buf, (size_t)len);
|
||
|
+
|
||
|
+out:
|
||
|
+ xmlFree(buf);
|
||
|
+ (void)close(fd);
|
||
|
+ return retval;
|
||
|
+}
|
||
|
diff --git a/support/misc/mountpoint.c b/support/misc/mountpoint.c
|
||
|
index a72fb92..9f9ce44 100644
|
||
|
--- a/support/misc/mountpoint.c
|
||
|
+++ b/support/misc/mountpoint.c
|
||
|
@@ -6,6 +6,7 @@
|
||
|
#include <string.h>
|
||
|
#include "xcommon.h"
|
||
|
#include <sys/stat.h>
|
||
|
+#include "misc.h"
|
||
|
|
||
|
int
|
||
|
is_mountpoint(char *path)
|
||
|
diff --git a/support/nfs/atomicio.c b/support/nfs/atomicio.c
|
||
|
index aa819ca..0e81838 100644
|
||
|
--- a/support/nfs/atomicio.c
|
||
|
+++ b/support/nfs/atomicio.c
|
||
|
@@ -28,6 +28,8 @@
|
||
|
#include <unistd.h>
|
||
|
#include <errno.h>
|
||
|
|
||
|
+#include "nfslib.h"
|
||
|
+
|
||
|
/*
|
||
|
* ensure all of data on socket comes through. f==read || f==write
|
||
|
*/
|
||
|
diff --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c
|
||
|
index 9912afa..9dc4cf1 100644
|
||
|
--- a/support/nfs/cacheio.c
|
||
|
+++ b/support/nfs/cacheio.c
|
||
|
@@ -212,7 +212,7 @@ cache_flush(int force)
|
||
|
{
|
||
|
struct stat stb;
|
||
|
int c;
|
||
|
- char stime[20];
|
||
|
+ char stime[32];
|
||
|
char path[200];
|
||
|
time_t now;
|
||
|
/* Note: the order of these caches is important.
|
||
|
diff --git a/support/nfs/closeall.c b/support/nfs/closeall.c
|
||
|
index a69bf35..e07253e 100644
|
||
|
--- a/support/nfs/closeall.c
|
||
|
+++ b/support/nfs/closeall.c
|
||
|
@@ -9,6 +9,8 @@
|
||
|
#include <dirent.h>
|
||
|
#include <errno.h>
|
||
|
|
||
|
+#include "nfslib.h"
|
||
|
+
|
||
|
void
|
||
|
closeall(int min)
|
||
|
{
|
||
|
diff --git a/support/nfs/exports.c b/support/nfs/exports.c
|
||
|
index 92bd6e6..b59d187 100644
|
||
|
--- a/support/nfs/exports.c
|
||
|
+++ b/support/nfs/exports.c
|
||
|
@@ -197,6 +197,7 @@ static const struct secinfo_flag_displaymap {
|
||
|
const char *set;
|
||
|
const char *unset;
|
||
|
} secinfo_flag_displaymap[] = {
|
||
|
+ { NFSEXP_READONLY, "ro", "rw" },
|
||
|
{ NFSEXP_INSECURE_PORT, "insecure", "secure" },
|
||
|
{ NFSEXP_ROOTSQUASH, "root_squash", "no_root_squash" },
|
||
|
{ NFSEXP_ALLSQUASH, "all_squash", "no_all_squash" },
|
||
|
diff --git a/support/nfs/nfs_mntent.c b/support/nfs/nfs_mntent.c
|
||
|
index a2118a2..05a4c68 100644
|
||
|
--- a/support/nfs/nfs_mntent.c
|
||
|
+++ b/support/nfs/nfs_mntent.c
|
||
|
@@ -13,6 +13,7 @@
|
||
|
#include <ctype.h> /* for isdigit */
|
||
|
#include <sys/stat.h> /* for umask */
|
||
|
#include <unistd.h> /* for ftruncate */
|
||
|
+#include <errno.h> /* for errno */
|
||
|
|
||
|
#include "nfs_mntent.h"
|
||
|
#include "nls.h"
|
||
|
@@ -148,9 +149,12 @@ nfs_addmntent (mntFILE *mfp, struct mntent *mnt) {
|
||
|
free(m4);
|
||
|
if (res >= 0) {
|
||
|
res = fflush(mfp->mntent_fp);
|
||
|
- if (res < 0)
|
||
|
+ if (res < 0) {
|
||
|
+ nfs_error("Cant't flush out mtab: %s", strerror(errno));
|
||
|
/* Avoid leaving a corrupt mtab file */
|
||
|
- ftruncate(fileno(mfp->mntent_fp), length);
|
||
|
+ if (ftruncate(fileno(mfp->mntent_fp), length))
|
||
|
+ {/* Ignore this failure; Why confuse things */}
|
||
|
+ }
|
||
|
}
|
||
|
return (res < 0) ? 1 : 0;
|
||
|
}
|
||
|
diff --git a/support/nfs/rpcmisc.c b/support/nfs/rpcmisc.c
|
||
|
index ae2c0a6..abe89ba 100644
|
||
|
--- a/support/nfs/rpcmisc.c
|
||
|
+++ b/support/nfs/rpcmisc.c
|
||
|
@@ -32,6 +32,7 @@
|
||
|
#include <unistd.h>
|
||
|
#include <time.h>
|
||
|
#include "nfslib.h"
|
||
|
+#include "rpcmisc.h"
|
||
|
|
||
|
#if SIZEOF_SOCKLEN_T - 0 == 0
|
||
|
#define socklen_t int
|
||
|
diff --git a/support/nfs/strlcat.c b/support/nfs/strlcat.c
|
||
|
index daedd7a..0edee14 100644
|
||
|
--- a/support/nfs/strlcat.c
|
||
|
+++ b/support/nfs/strlcat.c
|
||
|
@@ -38,6 +38,8 @@ static char *rcsid = "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp
|
||
|
#include "config.h"
|
||
|
#endif /* HAVE_CONFIG_H */
|
||
|
|
||
|
+#include "nfslib.h"
|
||
|
+
|
||
|
/*
|
||
|
* Appends src to string dst of size siz (unlike strncat, siz is the
|
||
|
* full size of dst, not space left). At most siz-1 characters
|
||
|
diff --git a/support/nfs/strlcpy.c b/support/nfs/strlcpy.c
|
||
|
index a2653ee..23e3ae9 100644
|
||
|
--- a/support/nfs/strlcpy.c
|
||
|
+++ b/support/nfs/strlcpy.c
|
||
|
@@ -38,6 +38,8 @@ static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp
|
||
|
#include "config.h"
|
||
|
#endif /* HAVE_CONFIG_H */
|
||
|
|
||
|
+#include "nfslib.h"
|
||
|
+
|
||
|
/*
|
||
|
* Copy src to string dst of size siz. At most siz-1 characters
|
||
|
* will be copied. Always NUL terminates (unless siz == 0).
|
||
|
diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c
|
||
|
index 1fa0d15..1239712 100644
|
||
|
--- a/support/nfs/svc_socket.c
|
||
|
+++ b/support/nfs/svc_socket.c
|
||
|
@@ -25,6 +25,8 @@
|
||
|
#include <sys/fcntl.h>
|
||
|
#include <errno.h>
|
||
|
#include "xlog.h"
|
||
|
+#include "rpcmisc.h"
|
||
|
+#include "nfslib.h"
|
||
|
|
||
|
#include "config.h"
|
||
|
|
||
|
diff --git a/support/nfs/wildmat.c b/support/nfs/wildmat.c
|
||
|
index c5b4c78..437b2d1 100644
|
||
|
--- a/support/nfs/wildmat.c
|
||
|
+++ b/support/nfs/wildmat.c
|
||
|
@@ -41,9 +41,16 @@
|
||
|
#endif
|
||
|
|
||
|
#include <ctype.h>
|
||
|
+#include "nfslib.h"
|
||
|
|
||
|
+#ifndef TRUE
|
||
|
#define TRUE 1
|
||
|
+#endif
|
||
|
+
|
||
|
+#ifndef FALSE
|
||
|
#define FALSE 0
|
||
|
+#endif
|
||
|
+
|
||
|
#define ABORT -1
|
||
|
|
||
|
|
||
|
diff --git a/support/nfsidmap/Makefile.am b/support/nfsidmap/Makefile.am
|
||
|
index 9466f92..8b5dfe4 100644
|
||
|
--- a/support/nfsidmap/Makefile.am
|
||
|
+++ b/support/nfsidmap/Makefile.am
|
||
|
@@ -25,7 +25,7 @@ pkgplugin_LTLIBRARIES = nsswitch.la static.la $(UMICH_LDAP_LIB) $(GUMS_MAPPING_L
|
||
|
# <age> The number of previous additional interfaces supported
|
||
|
# by this library.
|
||
|
|
||
|
-libnfsidmap_la_SOURCES = libnfsidmap.c nfsidmap_internal.h nfsidmap_common.c
|
||
|
+libnfsidmap_la_SOURCES = libnfsidmap.c nfsidmap_common.c
|
||
|
libnfsidmap_la_LDFLAGS = -version-info 1:0:0
|
||
|
libnfsidmap_la_LIBADD = -ldl ../../support/nfs/libnfsconf.la
|
||
|
|
||
|
diff --git a/support/nfsidmap/libnfsidmap.c b/support/nfsidmap/libnfsidmap.c
|
||
|
index 3b44da6..35ddf01 100644
|
||
|
--- a/support/nfsidmap/libnfsidmap.c
|
||
|
+++ b/support/nfsidmap/libnfsidmap.c
|
||
|
@@ -64,6 +64,7 @@
|
||
|
|
||
|
#pragma GCC visibility push(hidden)
|
||
|
|
||
|
+void nfs4_cleanup_name_mapping(void);
|
||
|
static char *default_domain;
|
||
|
static struct mapping_plugin **nfs4_plugins = NULL;
|
||
|
static struct mapping_plugin **gss_plugins = NULL;
|
||
|
@@ -103,14 +104,6 @@ nfs4_idmap_log_function_t idmap_log_func = default_logger;
|
||
|
int idmap_verbosity = 2;
|
||
|
#pragma GCC visibility push(hidden)
|
||
|
|
||
|
-static char * toupper_str(char *s)
|
||
|
-{
|
||
|
- size_t i;
|
||
|
- for (i=0; i < strlen(s); i++)
|
||
|
- s[i] = toupper(s[i]);
|
||
|
- return s;
|
||
|
-}
|
||
|
-
|
||
|
static int id_as_chars(char *name, uid_t *id)
|
||
|
{
|
||
|
long int value;
|
||
|
@@ -327,7 +320,7 @@ out:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
-char * get_default_domain(void)
|
||
|
+static char *get_default_domain(void)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
@@ -353,24 +346,22 @@ void nfs4_cleanup_name_mapping(void)
|
||
|
|
||
|
#pragma GCC visibility pop
|
||
|
|
||
|
+const char * nfsidmap_conf_path = PATH_IDMAPDCONF;
|
||
|
+
|
||
|
int nfs4_init_name_mapping(char *conffile)
|
||
|
{
|
||
|
int ret = -ENOENT;
|
||
|
int dflt = 0;
|
||
|
struct conf_list *nfs4_methods, *gss_methods;
|
||
|
char *nobody_user, *nobody_group;
|
||
|
- char *nostrip;
|
||
|
- char *reformatgroup;
|
||
|
- char *conf_path;
|
||
|
|
||
|
/* XXX: need to be able to reload configurations... */
|
||
|
if (nfs4_plugins) /* already succesfully initialized */
|
||
|
return 0;
|
||
|
if (conffile)
|
||
|
- conf_path = conffile;
|
||
|
- else
|
||
|
- conf_path = PATH_IDMAPDCONF;
|
||
|
- conf_init_file(conf_path);
|
||
|
+ nfsidmap_conf_path = conffile;
|
||
|
+ conf_init_file(nfsidmap_conf_path);
|
||
|
+
|
||
|
default_domain = conf_get_str("General", "Domain");
|
||
|
if (default_domain == NULL) {
|
||
|
dflt = 1;
|
||
|
@@ -387,30 +378,8 @@ int nfs4_init_name_mapping(char *conffile)
|
||
|
IDMAP_LOG(1, ("libnfsidmap: using%s domain: %s",
|
||
|
(dflt ? " (default)" : ""), default_domain));
|
||
|
|
||
|
- /* Get list of "local equivalent" realms. Meaning the list of realms
|
||
|
- * where john@REALM.A is considered the same user as john@REALM.B
|
||
|
- * If not specified, default to upper-case of local domain name */
|
||
|
- local_realms = conf_get_list("General", "Local-Realms");
|
||
|
- if (local_realms == NULL) {
|
||
|
- struct conf_list_node *node;
|
||
|
-
|
||
|
- local_realms = malloc(sizeof *local_realms);
|
||
|
- if (local_realms == NULL)
|
||
|
- return -ENOMEM;
|
||
|
- local_realms->cnt = 0;
|
||
|
- TAILQ_INIT(&local_realms->fields);
|
||
|
-
|
||
|
- node = calloc(1, sizeof *node);
|
||
|
- if (node == NULL)
|
||
|
- return -ENOMEM;
|
||
|
- node->field = strdup(get_default_domain());
|
||
|
- if (node->field == NULL)
|
||
|
- return -ENOMEM;
|
||
|
- toupper_str(node->field);
|
||
|
-
|
||
|
- TAILQ_INSERT_TAIL(&local_realms->fields, node, link);
|
||
|
- local_realms->cnt++;
|
||
|
- }
|
||
|
+ struct conf_list *local_realms = get_local_realms();
|
||
|
+ if (local_realms == NULL) return -ENOMEM;
|
||
|
|
||
|
if (idmap_verbosity >= 1) {
|
||
|
struct conf_list_node *r;
|
||
|
@@ -434,26 +403,6 @@ int nfs4_init_name_mapping(char *conffile)
|
||
|
IDMAP_LOG(1, ("libnfsidmap: Realms list: <NULL> "));
|
||
|
}
|
||
|
|
||
|
- nostrip = conf_get_str_with_def("General", "No-Strip", "none");
|
||
|
- if (strcasecmp(nostrip, "both") == 0)
|
||
|
- no_strip = IDTYPE_USER|IDTYPE_GROUP;
|
||
|
- else if (strcasecmp(nostrip, "group") == 0)
|
||
|
- no_strip = IDTYPE_GROUP;
|
||
|
- else if (strcasecmp(nostrip, "user") == 0)
|
||
|
- no_strip = IDTYPE_USER;
|
||
|
- else
|
||
|
- no_strip = 0;
|
||
|
-
|
||
|
- if (no_strip & IDTYPE_GROUP) {
|
||
|
- reformatgroup = conf_get_str_with_def("General", "Reformat-Group", "false");
|
||
|
- if ((strcasecmp(reformatgroup, "true") == 0) ||
|
||
|
- (strcasecmp(reformatgroup, "on") == 0) ||
|
||
|
- (strcasecmp(reformatgroup, "yes") == 0))
|
||
|
- reformat_group = 1;
|
||
|
- else
|
||
|
- reformat_group = 0;
|
||
|
- }
|
||
|
-
|
||
|
nfs4_methods = conf_get_list("Translation", "Method");
|
||
|
if (nfs4_methods) {
|
||
|
IDMAP_LOG(1, ("libnfsidmap: processing 'Method' list"));
|
||
|
diff --git a/support/nfsidmap/nfsidmap_common.c b/support/nfsidmap/nfsidmap_common.c
|
||
|
index 891c855..5242c7e 100644
|
||
|
--- a/support/nfsidmap/nfsidmap_common.c
|
||
|
+++ b/support/nfsidmap/nfsidmap_common.c
|
||
|
@@ -6,6 +6,9 @@
|
||
|
*
|
||
|
* Code common to libnfsidmap and some of its bundled plugins
|
||
|
*
|
||
|
+ * If you make use of these functions you must initialise your own
|
||
|
+ * copy of the config file data using: conf_init_file(nfsidmap_conf_path)
|
||
|
+ * failure to do so will appear as if the config was empty
|
||
|
*/
|
||
|
|
||
|
#include "config.h"
|
||
|
@@ -13,6 +16,8 @@
|
||
|
#include <sys/types.h>
|
||
|
#include <unistd.h>
|
||
|
#include <stdlib.h>
|
||
|
+#include <errno.h>
|
||
|
+#include <string.h>
|
||
|
|
||
|
#include "nfsidmap.h"
|
||
|
#include "nfsidmap_private.h"
|
||
|
@@ -21,13 +26,82 @@
|
||
|
|
||
|
#pragma GCC visibility push(hidden)
|
||
|
|
||
|
-int reformat_group = 0;
|
||
|
-int no_strip = 0;
|
||
|
-
|
||
|
-struct conf_list *local_realms;
|
||
|
+static char * toupper_str(char *s)
|
||
|
+{
|
||
|
+ size_t i;
|
||
|
+ for (i=0; i < strlen(s); i++)
|
||
|
+ s[i] = toupper(s[i]);
|
||
|
+ return s;
|
||
|
+}
|
||
|
|
||
|
+/* Get list of "local equivalent" realms. Meaning the list of realms
|
||
|
+ * where john@REALM.A is considered the same user as john@REALM.B
|
||
|
+ * If not specified, default to upper-case of local domain name */
|
||
|
struct conf_list *get_local_realms(void)
|
||
|
{
|
||
|
+ static struct conf_list *local_realms = NULL;
|
||
|
+ if (local_realms) return local_realms;
|
||
|
+
|
||
|
+ local_realms = conf_get_list("General", "Local-Realms");
|
||
|
+ if (local_realms == NULL) {
|
||
|
+ struct conf_list_node *node;
|
||
|
+
|
||
|
+ local_realms = malloc(sizeof *local_realms);
|
||
|
+ if (local_realms == NULL)
|
||
|
+ return NULL;
|
||
|
+ local_realms->cnt = 0;
|
||
|
+ TAILQ_INIT(&local_realms->fields);
|
||
|
+
|
||
|
+ node = calloc(1, sizeof *node);
|
||
|
+ if (node == NULL)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ node->field = calloc(1, NFS4_MAX_DOMAIN_LEN);
|
||
|
+ if (node->field == NULL)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ nfs4_get_default_domain(NULL, node->field, NFS4_MAX_DOMAIN_LEN);
|
||
|
+ toupper_str(node->field);
|
||
|
+
|
||
|
+ TAILQ_INSERT_TAIL(&local_realms->fields, node, link);
|
||
|
+ local_realms->cnt++;
|
||
|
+ }
|
||
|
return local_realms;
|
||
|
}
|
||
|
|
||
|
+static int no_strip = -1;
|
||
|
+static int reformat_group = 0;
|
||
|
+
|
||
|
+int get_nostrip(void)
|
||
|
+{
|
||
|
+ if (no_strip != -1) return no_strip;
|
||
|
+
|
||
|
+ char * nostrip = conf_get_str_with_def("General", "No-Strip", "none");
|
||
|
+ if (strcasecmp(nostrip, "both") == 0)
|
||
|
+ no_strip = IDTYPE_USER|IDTYPE_GROUP;
|
||
|
+ else if (strcasecmp(nostrip, "group") == 0)
|
||
|
+ no_strip = IDTYPE_GROUP;
|
||
|
+ else if (strcasecmp(nostrip, "user") == 0)
|
||
|
+ no_strip = IDTYPE_USER;
|
||
|
+ else
|
||
|
+ no_strip = 0;
|
||
|
+
|
||
|
+ if (no_strip & IDTYPE_GROUP) {
|
||
|
+ char * reformatgroup = conf_get_str_with_def("General", "Reformat-Group", "false");
|
||
|
+ if ((strcasecmp(reformatgroup, "true") == 0) ||
|
||
|
+ (strcasecmp(reformatgroup, "on") == 0) ||
|
||
|
+ (strcasecmp(reformatgroup, "yes") == 0))
|
||
|
+ reformat_group = 1;
|
||
|
+ else
|
||
|
+ reformat_group = 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ return no_strip;
|
||
|
+}
|
||
|
+
|
||
|
+int get_reformat_group(void)
|
||
|
+{
|
||
|
+ if (no_strip != -1) return reformat_group;
|
||
|
+
|
||
|
+ return reformat_group;
|
||
|
+}
|
||
|
diff --git a/support/nfsidmap/nfsidmap_plugin.h b/support/nfsidmap/nfsidmap_plugin.h
|
||
|
index e19efe5..66fcdaa 100644
|
||
|
--- a/support/nfsidmap/nfsidmap_plugin.h
|
||
|
+++ b/support/nfsidmap/nfsidmap_plugin.h
|
||
|
@@ -51,6 +51,7 @@ struct trans_func {
|
||
|
|
||
|
extern int idmap_verbosity;
|
||
|
extern nfs4_idmap_log_function_t idmap_log_func;
|
||
|
+struct trans_func *libnfsidmap_plugin_init(void);
|
||
|
|
||
|
/* Level zero always prints, others print depending on verbosity level */
|
||
|
#define IDMAP_LOG(LVL, MSG) \
|
||
|
@@ -64,5 +65,6 @@ extern nfs4_idmap_log_function_t idmap_log_func;
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
+extern const char *nfsidmap_conf_path;
|
||
|
extern const char *nfsidmap_config_get(const char *section, const char *tag);
|
||
|
|
||
|
diff --git a/support/nfsidmap/nfsidmap_private.h b/support/nfsidmap/nfsidmap_private.h
|
||
|
index 2cc309e..f1af55f 100644
|
||
|
--- a/support/nfsidmap/nfsidmap_private.h
|
||
|
+++ b/support/nfsidmap/nfsidmap_private.h
|
||
|
@@ -37,16 +37,14 @@
|
||
|
#include "conffile.h"
|
||
|
|
||
|
struct conf_list *get_local_realms(void);
|
||
|
+int get_nostrip(void);
|
||
|
+int get_reformat_group(void);
|
||
|
|
||
|
typedef enum {
|
||
|
IDTYPE_USER = 1,
|
||
|
IDTYPE_GROUP = 2
|
||
|
} idtypes;
|
||
|
|
||
|
-extern int no_strip;
|
||
|
-extern int reformat_group;
|
||
|
-extern struct conf_list *local_realms;
|
||
|
-
|
||
|
typedef struct trans_func * (*libnfsidmap_plugin_init_t)(void);
|
||
|
|
||
|
struct mapping_plugin {
|
||
|
diff --git a/support/nfsidmap/nss.c b/support/nfsidmap/nss.c
|
||
|
index 6f024dc..9d46499 100644
|
||
|
--- a/support/nfsidmap/nss.c
|
||
|
+++ b/support/nfsidmap/nss.c
|
||
|
@@ -38,6 +38,7 @@
|
||
|
#include <errno.h>
|
||
|
#include <unistd.h>
|
||
|
#include <stdlib.h>
|
||
|
+#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <pwd.h>
|
||
|
#include <grp.h>
|
||
|
@@ -103,7 +104,7 @@ static int nss_uid_to_name(uid_t uid, char *domain, char *name, size_t len)
|
||
|
err = -ENOENT;
|
||
|
if (err)
|
||
|
goto out_buf;
|
||
|
- if (no_strip & IDTYPE_USER)
|
||
|
+ if (get_nostrip() & IDTYPE_USER)
|
||
|
err = write_name(name, pw->pw_name, domain, len, 0);
|
||
|
else
|
||
|
err = write_name(name, pw->pw_name, domain, len, 1);
|
||
|
@@ -140,7 +141,7 @@ static int nss_gid_to_name(gid_t gid, char *domain, char *name, size_t len)
|
||
|
|
||
|
if (err)
|
||
|
goto out_buf;
|
||
|
- if (no_strip & IDTYPE_GROUP)
|
||
|
+ if (get_nostrip() & IDTYPE_GROUP)
|
||
|
err = write_name(name, gr->gr_name, domain, len, 0);
|
||
|
else
|
||
|
err = write_name(name, gr->gr_name, domain, len, 1);
|
||
|
@@ -247,7 +248,7 @@ static int nss_name_to_uid(char *name, uid_t *uid)
|
||
|
int err = -ENOENT;
|
||
|
|
||
|
domain = get_default_domain();
|
||
|
- if (no_strip & IDTYPE_USER) {
|
||
|
+ if (get_nostrip() & IDTYPE_USER) {
|
||
|
pw = nss_getpwnam(name, domain, &err, 0);
|
||
|
if (pw != NULL)
|
||
|
goto out_uid;
|
||
|
@@ -315,7 +316,7 @@ static int _nss_name_to_gid(char *name, gid_t *gid, int dostrip)
|
||
|
"into domain '%s'", name, domain));
|
||
|
goto out;
|
||
|
}
|
||
|
- } else if (reformat_group) {
|
||
|
+ } else if (get_reformat_group()) {
|
||
|
ref_name = reformat_name(name);
|
||
|
if (ref_name == NULL) {
|
||
|
IDMAP_LOG(1, ("nss_name_to_gid: failed to reformat name '%s'",
|
||
|
@@ -335,7 +336,7 @@ static int _nss_name_to_gid(char *name, gid_t *gid, int dostrip)
|
||
|
goto out_name;
|
||
|
if (dostrip)
|
||
|
err = -getgrnam_r(localname, &grbuf, buf, buflen, &gr);
|
||
|
- else if (reformat_group)
|
||
|
+ else if (get_reformat_group())
|
||
|
err = -getgrnam_r(ref_name, &grbuf, buf, buflen, &gr);
|
||
|
else
|
||
|
err = -getgrnam_r(name, &grbuf, buf, buflen, &gr);
|
||
|
@@ -343,7 +344,7 @@ static int _nss_name_to_gid(char *name, gid_t *gid, int dostrip)
|
||
|
if (dostrip)
|
||
|
IDMAP_LOG(1, ("nss_name_to_gid: name '%s' not found "
|
||
|
"in domain '%s'", localname, domain));
|
||
|
- else if (reformat_group)
|
||
|
+ else if (get_reformat_group())
|
||
|
IDMAP_LOG(1, ("nss_name_to_gid: name '%s' not found "
|
||
|
"(reformatted)", ref_name));
|
||
|
else
|
||
|
@@ -366,7 +367,7 @@ out_buf:
|
||
|
out_name:
|
||
|
if (dostrip)
|
||
|
free(localname);
|
||
|
- if (reformat_group)
|
||
|
+ if (get_reformat_group())
|
||
|
free(ref_name);
|
||
|
out:
|
||
|
return err;
|
||
|
@@ -376,7 +377,7 @@ static int nss_name_to_gid(char *name, gid_t *gid)
|
||
|
{
|
||
|
int err = 0;
|
||
|
|
||
|
- if (no_strip & IDTYPE_GROUP) {
|
||
|
+ if (get_nostrip() & IDTYPE_GROUP) {
|
||
|
err = _nss_name_to_gid(name, gid, 0);
|
||
|
if (!err)
|
||
|
goto out;
|
||
|
@@ -436,7 +437,7 @@ out:
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
-int nss_gss_princ_to_grouplist(char *secname, char *princ,
|
||
|
+static int nss_gss_princ_to_grouplist(char *secname, char *princ,
|
||
|
gid_t *groups, int *ngroups,
|
||
|
extra_mapping_params **UNUSED(ex))
|
||
|
{
|
||
|
@@ -459,10 +460,17 @@ out:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+static int nss_plugin_init(void)
|
||
|
+{
|
||
|
+ if (nfsidmap_conf_path)
|
||
|
+ conf_init_file(nfsidmap_conf_path);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
|
||
|
struct trans_func nss_trans = {
|
||
|
.name = "nsswitch",
|
||
|
- .init = NULL,
|
||
|
+ .init = nss_plugin_init,
|
||
|
.princ_to_ids = nss_gss_princ_to_ids,
|
||
|
.name_to_uid = nss_name_to_uid,
|
||
|
.name_to_gid = nss_name_to_gid,
|
||
|
diff --git a/support/nfsidmap/static.c b/support/nfsidmap/static.c
|
||
|
index 0b1173f..f7b8a67 100644
|
||
|
--- a/support/nfsidmap/static.c
|
||
|
+++ b/support/nfsidmap/static.c
|
||
|
@@ -317,6 +317,9 @@ static int static_init(void) {
|
||
|
for (i = 0; i < sizeof uid_mappings / sizeof uid_mappings[0]; i++)
|
||
|
LIST_INIT (&uid_mappings[i]);
|
||
|
|
||
|
+ if (nfsidmap_conf_path)
|
||
|
+ conf_init_file(nfsidmap_conf_path);
|
||
|
+
|
||
|
//get all principals for which we have mappings
|
||
|
princ_list = conf_get_tag_list("Static", NULL);
|
||
|
|
||
|
diff --git a/support/nfsidmap/umich_ldap.c b/support/nfsidmap/umich_ldap.c
|
||
|
index e82828c..0e31b1c 100644
|
||
|
--- a/support/nfsidmap/umich_ldap.c
|
||
|
+++ b/support/nfsidmap/umich_ldap.c
|
||
|
@@ -1101,6 +1101,9 @@ umichldap_init(void)
|
||
|
char missing_msg[128] = "";
|
||
|
char *server_in, *canon_name;
|
||
|
|
||
|
+ if (nfsidmap_conf_path)
|
||
|
+ conf_init_file(nfsidmap_conf_path);
|
||
|
+
|
||
|
server_in = conf_get_str(LDAP_SECTION, "LDAP_server");
|
||
|
ldap_info.base = conf_get_str(LDAP_SECTION, "LDAP_base");
|
||
|
ldap_info.people_tree = conf_get_str(LDAP_SECTION, "LDAP_people_base");
|
||
|
diff --git a/support/nsm/Makefile.am b/support/nsm/Makefile.am
|
||
|
index 2038e68..8f5874e 100644
|
||
|
--- a/support/nsm/Makefile.am
|
||
|
+++ b/support/nsm/Makefile.am
|
||
|
@@ -32,11 +32,12 @@ $(GENFILES_SVC): %_svc.c: %.x $(RPCGEN)
|
||
|
|
||
|
$(GENFILES_XDR): %_xdr.c: %.x $(RPCGEN)
|
||
|
test -f $@ && rm -rf $@ || true
|
||
|
- $(RPCGEN) -c -o $@ $<
|
||
|
+ $(RPCGEN) -c -i 0 -o $@ $<
|
||
|
|
||
|
$(GENFILES_H): %.h: %.x $(RPCGEN)
|
||
|
test -f $@ && rm -rf $@ || true
|
||
|
$(RPCGEN) -h -o $@ $<
|
||
|
+ echo "void sm_prog_1(struct svc_req *, SVCXPRT *);" >> $@
|
||
|
rm -f $(top_builddir)/support/include/sm_inter.h
|
||
|
$(LN_S) ../nsm/sm_inter.h $(top_builddir)/support/include/sm_inter.h
|
||
|
|
||
|
diff --git a/systemd/systemd.c b/systemd/systemd.c
|
||
|
index 17820d4..c7bdb4d 100644
|
||
|
--- a/systemd/systemd.c
|
||
|
+++ b/systemd/systemd.c
|
||
|
@@ -8,6 +8,7 @@
|
||
|
#include <stdlib.h>
|
||
|
#include <ctype.h>
|
||
|
#include <string.h>
|
||
|
+#include "systemd.h"
|
||
|
|
||
|
static const char hex[16] =
|
||
|
{
|
||
|
diff --git a/tools/locktest/testlk.c b/tools/locktest/testlk.c
|
||
|
index 82ed765..b392f71 100644
|
||
|
--- a/tools/locktest/testlk.c
|
||
|
+++ b/tools/locktest/testlk.c
|
||
|
@@ -81,7 +81,7 @@ main(int argc, char **argv)
|
||
|
if (fl.l_type == F_UNLCK) {
|
||
|
printf("%s: no conflicting lock\n", fname);
|
||
|
} else {
|
||
|
- printf("%s: conflicting lock by %d on (%lld;%lld)\n",
|
||
|
+ printf("%s: conflicting lock by %d on (%ld;%ld)\n",
|
||
|
fname, fl.l_pid, fl.l_start, fl.l_len);
|
||
|
}
|
||
|
return 0;
|
||
|
diff --git a/utils/Makefile.am b/utils/Makefile.am
|
||
|
index c75a5a0..d361aea 100644
|
||
|
--- a/utils/Makefile.am
|
||
|
+++ b/utils/Makefile.am
|
||
|
@@ -23,6 +23,10 @@ if CONFIG_NFSDCLTRACK
|
||
|
OPTDIRS += nfsdcltrack
|
||
|
endif
|
||
|
|
||
|
+if CONFIG_JUNCTION
|
||
|
+OPTDIRS += nfsref
|
||
|
+endif
|
||
|
+
|
||
|
SUBDIRS = \
|
||
|
exportfs \
|
||
|
mountd \
|
||
|
diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c
|
||
|
index cae8c8d..3a202e0 100644
|
||
|
--- a/utils/blkmapd/device-discovery.c
|
||
|
+++ b/utils/blkmapd/device-discovery.c
|
||
|
@@ -81,7 +81,7 @@ int bl_watch_fd, bl_pipe_fd, nfs_pipedir_wfd, rpc_pipedir_wfd;
|
||
|
int pidfd = -1;
|
||
|
|
||
|
|
||
|
-struct bl_disk_path *bl_get_path(const char *filepath,
|
||
|
+static struct bl_disk_path *bl_get_path(const char *filepath,
|
||
|
struct bl_disk_path *paths)
|
||
|
{
|
||
|
struct bl_disk_path *tmp = paths;
|
||
|
@@ -103,7 +103,7 @@ struct bl_disk_path *bl_get_path(const char *filepath,
|
||
|
* exist for each multipath device. If not, active device path will be
|
||
|
* chosen for device creation.
|
||
|
*/
|
||
|
-int bl_update_path(enum bl_path_state_e state, struct bl_disk *disk)
|
||
|
+static int bl_update_path(enum bl_path_state_e state, struct bl_disk *disk)
|
||
|
{
|
||
|
struct bl_disk_path *valid_path = disk->valid_path;
|
||
|
|
||
|
@@ -112,7 +112,7 @@ int bl_update_path(enum bl_path_state_e state, struct bl_disk *disk)
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
-void bl_release_disk(void)
|
||
|
+static void bl_release_disk(void)
|
||
|
{
|
||
|
struct bl_disk *disk;
|
||
|
struct bl_disk_path *path = NULL;
|
||
|
@@ -133,7 +133,7 @@ void bl_release_disk(void)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
-void bl_add_disk(char *filepath)
|
||
|
+static void bl_add_disk(char *filepath)
|
||
|
{
|
||
|
struct bl_disk *disk = NULL;
|
||
|
int fd = 0;
|
||
|
@@ -239,7 +239,7 @@ int bl_discover_devices(void)
|
||
|
{
|
||
|
FILE *f;
|
||
|
int n;
|
||
|
- char buf[PATH_MAX], devname[PATH_MAX], fulldevname[PATH_MAX];
|
||
|
+ char buf[PATH_MAX], devname[PATH_MAX], fulldevname[PATH_MAX+NAME_MAX];
|
||
|
|
||
|
/* release previous list */
|
||
|
bl_release_disk();
|
||
|
@@ -435,7 +435,7 @@ static int bl_event_helper(void)
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
-void sig_die(int signal)
|
||
|
+static void sig_die(int signal)
|
||
|
{
|
||
|
if (pidfd >= 0) {
|
||
|
close(pidfd);
|
||
|
@@ -504,9 +504,11 @@ int main(int argc, char **argv)
|
||
|
close(pidfd);
|
||
|
exit(1);
|
||
|
}
|
||
|
- ftruncate(pidfd, 0);
|
||
|
+ if (ftruncate(pidfd, 0) < 0)
|
||
|
+ BL_LOG_WARNING("ftruncate on %s failed: m\n", PID_FILE);
|
||
|
sprintf(pidbuf, "%d\n", getpid());
|
||
|
- write(pidfd, pidbuf, strlen(pidbuf));
|
||
|
+ if (write(pidfd, pidbuf, strlen(pidbuf)) != (ssize_t)strlen(pidbuf))
|
||
|
+ BL_LOG_WARNING("write on %s failed: m\n", PID_FILE);
|
||
|
}
|
||
|
|
||
|
signal(SIGINT, sig_die);
|
||
|
diff --git a/utils/blkmapd/dm-device.c b/utils/blkmapd/dm-device.c
|
||
|
index 24ffcbf..f2d4de4 100644
|
||
|
--- a/utils/blkmapd/dm-device.c
|
||
|
+++ b/utils/blkmapd/dm-device.c
|
||
|
@@ -210,7 +210,7 @@ static int dm_device_remove_byname(const char *dev_name)
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
-int dm_device_remove(uint64_t dev)
|
||
|
+static int dm_device_remove(uint64_t dev)
|
||
|
{
|
||
|
struct dm_task *dmt;
|
||
|
struct dm_names *dmnames;
|
||
|
diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
|
||
|
index 448f195..cd3c979 100644
|
||
|
--- a/utils/exportfs/exportfs.c
|
||
|
+++ b/utils/exportfs/exportfs.c
|
||
|
@@ -695,10 +695,6 @@ dump(int verbose, int export_format)
|
||
|
continue;
|
||
|
}
|
||
|
c = '(';
|
||
|
- if (ep->e_flags & NFSEXP_READONLY)
|
||
|
- c = dumpopt(c, "ro");
|
||
|
- else
|
||
|
- c = dumpopt(c, "rw");
|
||
|
if (ep->e_flags & NFSEXP_ASYNC)
|
||
|
c = dumpopt(c, "async");
|
||
|
else
|
||
|
diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am
|
||
|
index beb3e8e..321046b 100644
|
||
|
--- a/utils/gssd/Makefile.am
|
||
|
+++ b/utils/gssd/Makefile.am
|
||
|
@@ -5,6 +5,8 @@ if CONFIG_SVCGSS
|
||
|
man8_MANS += svcgssd.man
|
||
|
endif
|
||
|
|
||
|
+AM_CPPFLAGS += -I ../../support/nfsidmap
|
||
|
+
|
||
|
RPCPREFIX = rpc.
|
||
|
KPREFIX = @kprefix@
|
||
|
sbin_PREFIXED = gssd
|
||
|
diff --git a/utils/gssd/err_util.c b/utils/gssd/err_util.c
|
||
|
index fe09eda..2b1132a 100644
|
||
|
--- a/utils/gssd/err_util.c
|
||
|
+++ b/utils/gssd/err_util.c
|
||
|
@@ -36,6 +36,7 @@
|
||
|
#include <stdarg.h>
|
||
|
#include <string.h>
|
||
|
#include "xlog.h"
|
||
|
+#include "err_util.h"
|
||
|
|
||
|
static int verbosity = 0;
|
||
|
static int fg = 0;
|
||
|
diff --git a/utils/gssd/gss_names.c b/utils/gssd/gss_names.c
|
||
|
index 047069d..2a7f3a1 100644
|
||
|
--- a/utils/gssd/gss_names.c
|
||
|
+++ b/utils/gssd/gss_names.c
|
||
|
@@ -51,6 +51,7 @@
|
||
|
|
||
|
#include "svcgssd.h"
|
||
|
#include "gss_util.h"
|
||
|
+#include "gss_names.h"
|
||
|
#include "err_util.h"
|
||
|
#include "context.h"
|
||
|
#include "misc.h"
|
||
|
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
|
||
|
index 4fc81c3..ce73777 100644
|
||
|
--- a/utils/gssd/gssd_proc.c
|
||
|
+++ b/utils/gssd/gssd_proc.c
|
||
|
@@ -473,7 +473,7 @@ change_identity(uid_t uid)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-AUTH *
|
||
|
+static AUTH *
|
||
|
krb5_not_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname,
|
||
|
int *downcall_err, int *chg_err, CLIENT **rpc_clnt)
|
||
|
{
|
||
|
@@ -519,7 +519,7 @@ out:
|
||
|
return auth;
|
||
|
}
|
||
|
|
||
|
-AUTH *
|
||
|
+static AUTH *
|
||
|
krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname,
|
||
|
char *service, CLIENT **rpc_clnt)
|
||
|
{
|
||
|
diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
|
||
|
index b64818a..b342b06 100644
|
||
|
--- a/utils/gssd/krb5_util.c
|
||
|
+++ b/utils/gssd/krb5_util.c
|
||
|
@@ -188,7 +188,7 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname,
|
||
|
int found = 0;
|
||
|
struct dirent *best_match_dir = NULL;
|
||
|
struct stat best_match_stat, tmp_stat;
|
||
|
- char buf[1030];
|
||
|
+ char buf[PATH_MAX+4+2+256];
|
||
|
char *princname = NULL;
|
||
|
char *realm = NULL;
|
||
|
int score, best_match_score = 0, err = -EACCES;
|
||
|
@@ -202,39 +202,35 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname,
|
||
|
dirname, strerror(errno));
|
||
|
}
|
||
|
else if (n > 0) {
|
||
|
- char statname[1024];
|
||
|
for (i = 0; i < n; i++) {
|
||
|
- snprintf(statname, sizeof(statname),
|
||
|
+ snprintf(buf, sizeof(buf),
|
||
|
"%s/%s", dirname, namelist[i]->d_name);
|
||
|
printerr(3, "CC '%s' being considered, "
|
||
|
"with preferred realm '%s'\n",
|
||
|
- statname, preferred_realm ?
|
||
|
+ buf, preferred_realm ?
|
||
|
preferred_realm : "<none selected>");
|
||
|
- if (lstat(statname, &tmp_stat)) {
|
||
|
- printerr(0, "Error doing stat on '%s'\n",
|
||
|
- statname);
|
||
|
+ if (lstat(buf, &tmp_stat)) {
|
||
|
+ printerr(0, "Error doing stat on '%s'\n", buf);
|
||
|
free(namelist[i]);
|
||
|
continue;
|
||
|
}
|
||
|
/* Only pick caches owned by the user (uid) */
|
||
|
if (tmp_stat.st_uid != uid) {
|
||
|
printerr(3, "CC '%s' owned by %u, not %u\n",
|
||
|
- statname, tmp_stat.st_uid, uid);
|
||
|
+ buf, tmp_stat.st_uid, uid);
|
||
|
free(namelist[i]);
|
||
|
continue;
|
||
|
}
|
||
|
if (!S_ISREG(tmp_stat.st_mode) &&
|
||
|
!S_ISDIR(tmp_stat.st_mode)) {
|
||
|
printerr(3, "CC '%s' is not a regular "
|
||
|
- "file or directory\n",
|
||
|
- statname);
|
||
|
+ "file or directory\n", buf);
|
||
|
free(namelist[i]);
|
||
|
continue;
|
||
|
}
|
||
|
if (uid == 0 && !root_uses_machine_creds &&
|
||
|
strstr(namelist[i]->d_name, "machine_")) {
|
||
|
- printerr(3, "CC '%s' not available to root\n",
|
||
|
- statname);
|
||
|
+ printerr(3, "CC '%s' not available to root\n", buf);
|
||
|
free(namelist[i]);
|
||
|
continue;
|
||
|
}
|
||
|
@@ -333,7 +329,7 @@ gssd_get_single_krb5_cred(krb5_context context,
|
||
|
struct gssd_k5_kt_princ *ple,
|
||
|
int nocache)
|
||
|
{
|
||
|
-#if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS
|
||
|
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS
|
||
|
krb5_get_init_creds_opt *init_opts = NULL;
|
||
|
#else
|
||
|
krb5_get_init_creds_opt options;
|
||
|
@@ -372,7 +368,7 @@ gssd_get_single_krb5_cred(krb5_context context,
|
||
|
if ((krb5_unparse_name(context, ple->princ, &pname)))
|
||
|
pname = NULL;
|
||
|
|
||
|
-#if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS
|
||
|
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS
|
||
|
code = krb5_get_init_creds_opt_alloc(context, &init_opts);
|
||
|
if (code) {
|
||
|
k5err = gssd_k5_err_msg(context, code);
|
||
|
@@ -454,7 +450,7 @@ gssd_get_single_krb5_cred(krb5_context context,
|
||
|
code = 0;
|
||
|
printerr(2, "%s: principal '%s' ccache:'%s'\n", __func__, pname, cc_name);
|
||
|
out:
|
||
|
-#if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS
|
||
|
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS
|
||
|
if (init_opts)
|
||
|
krb5_get_init_creds_opt_free(context, init_opts);
|
||
|
#endif
|
||
|
@@ -865,7 +861,7 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname,
|
||
|
if (strcmp(realm, default_realm) == 0)
|
||
|
tried_default = 1;
|
||
|
for (j = 0; svcnames[j] != NULL; j++) {
|
||
|
- char spn[300];
|
||
|
+ char spn[NI_MAXHOST+2];
|
||
|
|
||
|
/*
|
||
|
* The special svcname "$" means 'try the active
|
||
|
@@ -1059,7 +1055,7 @@ err_cache:
|
||
|
int
|
||
|
gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirpattern)
|
||
|
{
|
||
|
- char buf[MAX_NETOBJ_SZ], dirname[PATH_MAX];
|
||
|
+ char buf[PATH_MAX+2+256], dirname[PATH_MAX];
|
||
|
const char *cctype;
|
||
|
struct dirent *d;
|
||
|
int err, i, j;
|
||
|
diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c
|
||
|
index 3514ae1..8e918cc 100644
|
||
|
--- a/utils/gssd/svcgssd.c
|
||
|
+++ b/utils/gssd/svcgssd.c
|
||
|
@@ -63,7 +63,9 @@
|
||
|
#include "err_util.h"
|
||
|
#include "conffile.h"
|
||
|
|
||
|
-void
|
||
|
+struct state_paths etab;
|
||
|
+
|
||
|
+static void
|
||
|
sig_die(int signal)
|
||
|
{
|
||
|
/* destroy krb5 machine creds */
|
||
|
@@ -71,7 +73,7 @@ sig_die(int signal)
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
-void
|
||
|
+static void
|
||
|
sig_hup(int signal)
|
||
|
{
|
||
|
/* don't exit on SIGHUP */
|
||
|
@@ -101,7 +103,7 @@ main(int argc, char *argv[])
|
||
|
char *principal = NULL;
|
||
|
char *s;
|
||
|
|
||
|
- conf_init(NFS_CONFFILE);
|
||
|
+ conf_init_file(NFS_CONFFILE);
|
||
|
|
||
|
s = conf_get_str("svcgssd", "principal");
|
||
|
if (!s)
|
||
|
diff --git a/utils/gssd/svcgssd_mech2file.c b/utils/gssd/svcgssd_mech2file.c
|
||
|
index ecd908b..c26b435 100644
|
||
|
--- a/utils/gssd/svcgssd_mech2file.c
|
||
|
+++ b/utils/gssd/svcgssd_mech2file.c
|
||
|
@@ -41,6 +41,7 @@
|
||
|
#include <gssapi/gssapi.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
+char * mech2file(gss_OID mech);
|
||
|
|
||
|
#define g_OID_equal(o1,o2) \
|
||
|
(((o1)->length == (o2)->length) && \
|
||
|
diff --git a/utils/idmapd/Makefile.am b/utils/idmapd/Makefile.am
|
||
|
index d768eec..e09e8c5 100644
|
||
|
--- a/utils/idmapd/Makefile.am
|
||
|
+++ b/utils/idmapd/Makefile.am
|
||
|
@@ -2,6 +2,8 @@
|
||
|
|
||
|
man8_MANS = idmapd.man
|
||
|
|
||
|
+AM_CPPFLAGS += -I ../../support/nfsidmap
|
||
|
+
|
||
|
RPCPREFIX = rpc.
|
||
|
KPREFIX = @kprefix@
|
||
|
sbin_PROGRAMS = idmapd
|
||
|
diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c
|
||
|
index 2b9ecea..b87c4dd 100644
|
||
|
--- a/utils/idmapd/idmapd.c
|
||
|
+++ b/utils/idmapd/idmapd.c
|
||
|
@@ -169,7 +169,7 @@ static int
|
||
|
flush_nfsd_cache(char *path, time_t now)
|
||
|
{
|
||
|
int fd;
|
||
|
- char stime[20];
|
||
|
+ char stime[32];
|
||
|
|
||
|
sprintf(stime, "%ld\n", now);
|
||
|
fd = open(path, O_RDWR);
|
||
|
@@ -196,7 +196,7 @@ flush_nfsd_idmap_cache(void)
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
-void usage(char *progname)
|
||
|
+static void usage(char *progname)
|
||
|
{
|
||
|
fprintf(stderr, "Usage: %s [-hfvCS] [-p path] [-c path]\n",
|
||
|
basename(progname));
|
||
|
@@ -420,7 +420,7 @@ dirscancb(int UNUSED(fd), short UNUSED(which), void *data)
|
||
|
int nent, i;
|
||
|
struct dirent **ents;
|
||
|
struct idmap_client *ic, *nextic;
|
||
|
- char path[PATH_MAX];
|
||
|
+ char path[PATH_MAX+256]; /* + sizeof(d_name) */
|
||
|
struct idmap_clientq *icq = data;
|
||
|
|
||
|
nent = scandir(pipefsdir, &ents, NULL, alphasort);
|
||
|
diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c
|
||
|
index 64688bf..b48b25e 100644
|
||
|
--- a/utils/mount/configfile.c
|
||
|
+++ b/utils/mount/configfile.c
|
||
|
@@ -35,6 +35,10 @@
|
||
|
#include "network.h"
|
||
|
#include "conffile.h"
|
||
|
|
||
|
+char *mountopts_convert(char *value);
|
||
|
+char *is_alias(char *opt);
|
||
|
+char *conf_get_mntopts(char *spec, char *mount_point, char *mount_opts);
|
||
|
+
|
||
|
#define KBYTES(x) ((x) * (1024))
|
||
|
#define MEGABYTES(x) ((x) * (1048576))
|
||
|
#define GIGABYTES(x) ((x) * (1073741824))
|
||
|
diff --git a/utils/mount/mount_libmount.c b/utils/mount/mount_libmount.c
|
||
|
index 2d40657..aa4ac5c 100644
|
||
|
--- a/utils/mount/mount_libmount.c
|
||
|
+++ b/utils/mount/mount_libmount.c
|
||
|
@@ -45,6 +45,8 @@
|
||
|
#include "error.h"
|
||
|
#include "utils.h"
|
||
|
|
||
|
+char *retrieve_mount_options(struct libmnt_fs *fs);
|
||
|
+
|
||
|
char *progname;
|
||
|
int nfs_mount_data_version;
|
||
|
int verbose;
|
||
|
diff --git a/utils/mount/network.c b/utils/mount/network.c
|
||
|
index 8ab5be8..9a2c878 100644
|
||
|
--- a/utils/mount/network.c
|
||
|
+++ b/utils/mount/network.c
|
||
|
@@ -811,8 +811,12 @@ int start_statd(void)
|
||
|
switch (pid) {
|
||
|
case 0: /* child */
|
||
|
setgroups(0, NULL);
|
||
|
- setgid(0);
|
||
|
- setuid(0);
|
||
|
+ if (setgid(0) < 0)
|
||
|
+ nfs_error(_("%s: setgid(0) failed: %s"),
|
||
|
+ progname, strerror(errno));
|
||
|
+ if (setuid(0) < 0)
|
||
|
+ nfs_error(_("%s: setuid(0) failed: %s"),
|
||
|
+ progname, strerror(errno));
|
||
|
execle(START_STATD, START_STATD, NULL, envp);
|
||
|
exit(1);
|
||
|
case -1: /* error */
|
||
|
@@ -1275,8 +1279,8 @@ nfs_nfs_version(char *type, struct mount_options *options, struct nfs_version *v
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- if (!found && strcmp(type, "nfs4") == 0)
|
||
|
- version_val = type + 3;
|
||
|
+ if (!found && strncmp(type, "nfs", 3) == 0)
|
||
|
+ version_val = "4";
|
||
|
else if (!found)
|
||
|
return 1;
|
||
|
else if (i <= 2 ) {
|
||
|
@@ -1308,9 +1312,14 @@ nfs_nfs_version(char *type, struct mount_options *options, struct nfs_version *v
|
||
|
if (!(version->minor = strtol(version_val, &cptr, 10)) && cptr == version_val)
|
||
|
goto ret_error;
|
||
|
version->v_mode = V_SPECIFIC;
|
||
|
- } else if (version->major > 3 && *cptr == '\0')
|
||
|
- version->v_mode = V_GENERAL;
|
||
|
-
|
||
|
+ } else if (version->major > 3 && *cptr == '\0') {
|
||
|
+ version_val = po_get(options, "minorversion");
|
||
|
+ if (version_val != NULL) {
|
||
|
+ version->minor = strtol(version_val, &cptr, 10);
|
||
|
+ version->v_mode = V_SPECIFIC;
|
||
|
+ } else
|
||
|
+ version->v_mode = V_GENERAL;
|
||
|
+ }
|
||
|
if (*cptr != '\0')
|
||
|
goto ret_error;
|
||
|
|
||
|
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
|
||
|
index 1217823..d1b0708 100644
|
||
|
--- a/utils/mount/stropts.c
|
||
|
+++ b/utils/mount/stropts.c
|
||
|
@@ -761,9 +761,26 @@ static int nfs_do_mount_v4(struct nfsmount_info *mi,
|
||
|
fmt = "vers=%lu.%lu";
|
||
|
break;
|
||
|
}
|
||
|
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||
|
snprintf(version_opt, sizeof(version_opt) - 1,
|
||
|
fmt, mi->version.major,
|
||
|
mi->version.minor);
|
||
|
+#pragma GCC diagnostic warning "-Wformat-nonliteral"
|
||
|
+
|
||
|
+ if (po_append(options, version_opt) == PO_FAILED) {
|
||
|
+ errno = EINVAL;
|
||
|
+ goto out_fail;
|
||
|
+ }
|
||
|
+ } else if (po_get(options, "minorversion") &&
|
||
|
+ linux_version_code() > MAKE_VERSION(3, 4, 0)) {
|
||
|
+ /*
|
||
|
+ * convert minorversion= into vers=4.x
|
||
|
+ */
|
||
|
+ po_remove_all(options, "minorversion");
|
||
|
+
|
||
|
+ snprintf(version_opt, sizeof(version_opt) - 1,
|
||
|
+ "vers=%lu.%lu", mi->version.major,
|
||
|
+ mi->version.minor);
|
||
|
|
||
|
if (po_append(options, version_opt) == PO_FAILED) {
|
||
|
errno = EINVAL;
|
||
|
diff --git a/utils/mountd/Makefile.am b/utils/mountd/Makefile.am
|
||
|
index 153a90a..73eeb3f 100644
|
||
|
--- a/utils/mountd/Makefile.am
|
||
|
+++ b/utils/mountd/Makefile.am
|
||
|
@@ -1,5 +1,10 @@
|
||
|
## Process this file with automake to produce Makefile.in
|
||
|
|
||
|
+OPTLIBS =
|
||
|
+if CONFIG_JUNCTION
|
||
|
+OPTLIBS += ../../support/junction/libjunction.la $(LIBXML2)
|
||
|
+endif
|
||
|
+
|
||
|
man8_MANS = mountd.man
|
||
|
EXTRA_DIST = $(man8_MANS)
|
||
|
|
||
|
@@ -13,7 +18,8 @@ mountd_SOURCES = mountd.c mount_dispatch.c auth.c rmtab.c cache.c \
|
||
|
mountd_LDADD = ../../support/export/libexport.a \
|
||
|
../../support/nfs/libnfs.la \
|
||
|
../../support/misc/libmisc.a \
|
||
|
- $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) $(LIBDL) $(LIBTIRPC)
|
||
|
+ $(OPTLIBS) \
|
||
|
+ $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) $(LIBTIRPC)
|
||
|
mountd_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \
|
||
|
-I$(top_builddir)/support/include \
|
||
|
-I$(top_srcdir)/support/export
|
||
|
diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
|
||
|
index e49300d..6f42512 100644
|
||
|
--- a/utils/mountd/cache.c
|
||
|
+++ b/utils/mountd/cache.c
|
||
|
@@ -976,10 +976,15 @@ lookup_export(char *dom, char *path, struct addrinfo *ai)
|
||
|
return found;
|
||
|
}
|
||
|
|
||
|
-#ifdef HAVE_NFS_PLUGIN_H
|
||
|
-#include <dlfcn.h>
|
||
|
-#include <link.h>
|
||
|
-#include <nfs-plugin.h>
|
||
|
+#ifdef CONFIG_JUNCTION
|
||
|
+
|
||
|
+#include "junction.h"
|
||
|
+
|
||
|
+struct nfs_fsloc_set {
|
||
|
+ int ns_ttl;
|
||
|
+ struct nfs_fsloc *ns_current;
|
||
|
+ struct nfs_fsloc *ns_list;
|
||
|
+};
|
||
|
|
||
|
/*
|
||
|
* Find the export entry for the parent of "pathname".
|
||
|
@@ -1035,13 +1040,39 @@ out_default:
|
||
|
return mkexportent("*", "/", "insecure");
|
||
|
}
|
||
|
|
||
|
+static int get_next_location(struct nfs_fsloc_set *locset,
|
||
|
+ char **hostname, char **export_path, int *ttl)
|
||
|
+{
|
||
|
+ char *hostname_tmp, *export_path_tmp;
|
||
|
+ struct nfs_fsloc *fsloc;
|
||
|
+
|
||
|
+ if (locset->ns_current == NULL)
|
||
|
+ return ENOENT;
|
||
|
+ fsloc = locset->ns_current;
|
||
|
+
|
||
|
+ hostname_tmp = strdup(fsloc->nfl_hostname);
|
||
|
+ if (hostname_tmp == NULL)
|
||
|
+ return ENOMEM;
|
||
|
+
|
||
|
+ if (nsdb_path_array_to_posix(fsloc->nfl_rootpath,
|
||
|
+ &export_path_tmp)) {
|
||
|
+ free(hostname_tmp);
|
||
|
+ return EINVAL;
|
||
|
+ }
|
||
|
+
|
||
|
+ *hostname = hostname_tmp;
|
||
|
+ *export_path = export_path_tmp;
|
||
|
+ *ttl = locset->ns_ttl;
|
||
|
+ locset->ns_current = locset->ns_current->nfl_next;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
/*
|
||
|
* Walk through a set of FS locations and build an e_fslocdata string.
|
||
|
* Returns true if all went to plan; otherwise, false.
|
||
|
*/
|
||
|
-static bool locations_to_fslocdata(struct jp_ops *ops,
|
||
|
- nfs_fsloc_set_t locations, char *fslocdata,
|
||
|
- size_t remaining, int *ttl)
|
||
|
+static bool locations_to_fslocdata(struct nfs_fsloc_set *locations,
|
||
|
+ char *fslocdata, size_t remaining, int *ttl)
|
||
|
{
|
||
|
char *server, *last_path, *rootpath, *ptr;
|
||
|
_Bool seen = false;
|
||
|
@@ -1056,13 +1087,13 @@ static bool locations_to_fslocdata(struct jp_ops *ops,
|
||
|
enum jp_status status;
|
||
|
int len;
|
||
|
|
||
|
- status = ops->jp_get_next_location(locations, &server,
|
||
|
+ status = get_next_location(locations, &server,
|
||
|
&rootpath, ttl);
|
||
|
- if (status == JP_EMPTY)
|
||
|
+ if (status == ENOENT)
|
||
|
break;
|
||
|
- if (status != JP_OK) {
|
||
|
+ if (status) {
|
||
|
xlog(D_GENERAL, "%s: failed to parse location: %s",
|
||
|
- __func__, ops->jp_error(status));
|
||
|
+ __func__, strerror(status));
|
||
|
goto out_false;
|
||
|
}
|
||
|
xlog(D_GENERAL, "%s: Location: %s:%s",
|
||
|
@@ -1159,116 +1190,73 @@ out_nomem:
|
||
|
* Walk through the set of FS locations and build an exportent.
|
||
|
* Returns pointer to an exportent if "junction" refers to a junction.
|
||
|
*/
|
||
|
-static struct exportent *locations_to_export(struct jp_ops *ops,
|
||
|
- nfs_fsloc_set_t locations, const char *junction,
|
||
|
- struct exportent *parent)
|
||
|
+static struct exportent *locations_to_export(struct nfs_fsloc_set *locations,
|
||
|
+ const char *junction, struct exportent *parent)
|
||
|
{
|
||
|
static char fslocdata[BUFSIZ];
|
||
|
int ttl;
|
||
|
|
||
|
fslocdata[0] = '\0';
|
||
|
- if (!locations_to_fslocdata(ops, locations,
|
||
|
- fslocdata, sizeof(fslocdata), &ttl))
|
||
|
+ if (!locations_to_fslocdata(locations, fslocdata, sizeof(fslocdata), &ttl))
|
||
|
return NULL;
|
||
|
return create_junction_exportent(parent, junction, fslocdata, ttl);
|
||
|
}
|
||
|
|
||
|
-/*
|
||
|
- * Retrieve locations information in "junction" and dump it to the
|
||
|
- * kernel. Returns pointer to an exportent if "junction" refers
|
||
|
- * to a junction.
|
||
|
- */
|
||
|
-static struct exportent *invoke_junction_ops(void *handle, char *dom,
|
||
|
- const char *junction, struct addrinfo *ai)
|
||
|
+static int
|
||
|
+nfs_get_basic_junction(const char *junct_path, struct nfs_fsloc_set **locset)
|
||
|
{
|
||
|
- struct exportent *parent, *exp = NULL;
|
||
|
- nfs_fsloc_set_t locations;
|
||
|
- enum jp_status status;
|
||
|
- struct jp_ops *ops;
|
||
|
- char *error;
|
||
|
-
|
||
|
- ops = (struct jp_ops *)dlsym(handle, "nfs_junction_ops");
|
||
|
- error = dlerror();
|
||
|
- if (error != NULL) {
|
||
|
- xlog(D_GENERAL, "%s: dlsym(jp_junction_ops): %s",
|
||
|
- __func__, error);
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-#ifdef JP_API_VERSION
|
||
|
- if (ops->jp_api_version != JP_API_VERSION) {
|
||
|
- xlog(D_GENERAL, "%s: unrecognized junction API version: %u",
|
||
|
- __func__, ops->jp_api_version);
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-#endif
|
||
|
- status = ops->jp_init(false);
|
||
|
- if (status != JP_OK) {
|
||
|
- xlog(D_GENERAL, "%s: failed to resolve %s: %s",
|
||
|
- __func__, junction, ops->jp_error(status));
|
||
|
- return NULL;
|
||
|
+ struct nfs_fsloc_set *new;
|
||
|
+ FedFsStatus retval;
|
||
|
+
|
||
|
+ new = calloc(1, sizeof(struct nfs_fsloc_set));
|
||
|
+ if (new == NULL)
|
||
|
+ return ENOMEM;
|
||
|
+
|
||
|
+ retval = nfs_get_locations(junct_path, &new->ns_list);
|
||
|
+ if (retval) {
|
||
|
+ nfs_free_locations(new->ns_list);
|
||
|
+ free(new);
|
||
|
+ return EINVAL;
|
||
|
}
|
||
|
|
||
|
- status = ops->jp_get_locations(junction, &locations);
|
||
|
- switch (status) {
|
||
|
- case JP_OK:
|
||
|
- break;
|
||
|
- case JP_NOTJUNCTION:
|
||
|
+ locset->ns_current = locset->ns_list;
|
||
|
+ new->ns_ttl = 300;
|
||
|
+ *locset = new;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static struct exportent *lookup_junction(char *dom, const char *pathname,
|
||
|
+ struct addrinfo *ai)
|
||
|
+{
|
||
|
+ struct exportent *parent, *exp = NULL;
|
||
|
+ struct nfs_fsloc_set *locations;
|
||
|
+ int status;
|
||
|
+
|
||
|
+ xmlInitParser();
|
||
|
+
|
||
|
+ if (nfs_is_junction(pathname)) {
|
||
|
xlog(D_GENERAL, "%s: %s is not a junction",
|
||
|
- __func__, junction);
|
||
|
+ __func__, pathname);
|
||
|
goto out;
|
||
|
- default:
|
||
|
+ }
|
||
|
+ status = nfs_get_basic_junction(pathname, &locations);
|
||
|
+ switch (status) {
|
||
|
xlog(L_WARNING, "Dangling junction %s: %s",
|
||
|
- junction, ops->jp_error(status));
|
||
|
+ pathname, strerro(status));
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
- parent = lookup_parent_export(dom, junction, ai);
|
||
|
+ parent = lookup_parent_export(dom, pathname, ai);
|
||
|
if (parent == NULL)
|
||
|
goto out;
|
||
|
|
||
|
- exp = locations_to_export(ops, locations, junction, parent);
|
||
|
+ exp = locations_to_export(locations, pathname, parent);
|
||
|
|
||
|
- ops->jp_put_locations(locations);
|
||
|
+ nfs_free_locations(locset->ns_list);
|
||
|
+ free(locset);
|
||
|
|
||
|
out:
|
||
|
- ops->jp_done();
|
||
|
- return exp;
|
||
|
-}
|
||
|
-
|
||
|
-/*
|
||
|
- * Load the junction plug-in, then try to resolve "pathname".
|
||
|
- * Returns pointer to an initialized exportent if "junction"
|
||
|
- * refers to a junction, or NULL if not.
|
||
|
- */
|
||
|
-static struct exportent *lookup_junction(char *dom, const char *pathname,
|
||
|
- struct addrinfo *ai)
|
||
|
-{
|
||
|
- struct exportent *exp;
|
||
|
- struct link_map *map;
|
||
|
- void *handle;
|
||
|
-
|
||
|
-#ifdef JP_NFSPLUGIN_SONAME
|
||
|
- handle = dlopen(JP_NFSPLUGIN_SONAME, RTLD_NOW);
|
||
|
-#else
|
||
|
- handle = dlopen("libnfsjunct.so.0", RTLD_NOW);
|
||
|
-#endif
|
||
|
- if (handle == NULL) {
|
||
|
- xlog(D_GENERAL, "%s: dlopen: %s", __func__, dlerror());
|
||
|
- return NULL;
|
||
|
- }
|
||
|
-
|
||
|
- if (dlinfo(handle, RTLD_DI_LINKMAP, &map) == 0)
|
||
|
- xlog(D_GENERAL, "%s: loaded plug-in %s",
|
||
|
- __func__, map->l_name);
|
||
|
-
|
||
|
- (void)dlerror(); /* Clear any error */
|
||
|
-
|
||
|
- exp = invoke_junction_ops(handle, dom, pathname, ai);
|
||
|
-
|
||
|
- /* We could leave it loaded to make junction resolution
|
||
|
- * faster next time. However, if we want to replace the
|
||
|
- * library, that would require restarting mountd. */
|
||
|
- (void)dlclose(handle);
|
||
|
+ xmlCleanupParser();
|
||
|
return exp;
|
||
|
}
|
||
|
|
||
|
@@ -1284,13 +1272,16 @@ static void lookup_nonexport(int f, char *buf, int buflen, char *dom, char *path
|
||
|
exportent_release(eep);
|
||
|
free(eep);
|
||
|
}
|
||
|
-#else /* !HAVE_NFS_PLUGIN_H */
|
||
|
+
|
||
|
+#else /* !CONFIG_JUNCTION */
|
||
|
+
|
||
|
static void lookup_nonexport(int f, char *buf, int buflen, char *dom, char *path,
|
||
|
struct addrinfo *UNUSED(ai))
|
||
|
{
|
||
|
dump_to_cache(f, buf, buflen, dom, path, NULL, 0);
|
||
|
}
|
||
|
-#endif /* !HAVE_NFS_PLUGIN_H */
|
||
|
+
|
||
|
+#endif /* !CONFIG_JUNCTION */
|
||
|
|
||
|
static void nfsd_export(int f)
|
||
|
{
|
||
|
diff --git a/utils/mountd/svc_run.c b/utils/mountd/svc_run.c
|
||
|
index a572441..41b96d7 100644
|
||
|
--- a/utils/mountd/svc_run.c
|
||
|
+++ b/utils/mountd/svc_run.c
|
||
|
@@ -57,6 +57,7 @@
|
||
|
#include <rpc/rpc_com.h>
|
||
|
#endif
|
||
|
|
||
|
+void my_svc_run(void);
|
||
|
void cache_set_fds(fd_set *fdset);
|
||
|
int cache_process_req(fd_set *readfds);
|
||
|
|
||
|
diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c
|
||
|
index fc36792..7923f5d 100644
|
||
|
--- a/utils/nfsd/nfssvc.c
|
||
|
+++ b/utils/nfsd/nfssvc.c
|
||
|
@@ -68,7 +68,7 @@ nfssvc_mount_nfsdfs(char *progname)
|
||
|
* mount nfsdfs when nfsd.ko is plugged in. So, ignore the return
|
||
|
* code from it and just check for the "threads" file afterward.
|
||
|
*/
|
||
|
- system("/bin/mount -t nfsd nfsd " NFSD_FS_DIR " >/dev/null 2>&1");
|
||
|
+ err = system("/bin/mount -t nfsd nfsd " NFSD_FS_DIR " >/dev/null 2>&1");
|
||
|
|
||
|
err = stat(NFSD_THREAD_FILE, &statbuf);
|
||
|
if (err == 0)
|
||
|
@@ -325,7 +325,8 @@ nfssvc_set_time(const char *type, const int seconds)
|
||
|
/* set same value for lockd */
|
||
|
fd = open("/proc/sys/fs/nfs/nlm_grace_period", O_WRONLY);
|
||
|
if (fd >= 0) {
|
||
|
- write(fd, nbuf, strlen(nbuf));
|
||
|
+ if (write(fd, nbuf, strlen(nbuf)) != (ssize_t)strlen(nbuf))
|
||
|
+ xlog(L_ERROR, "Unable to write nlm_grace_period : %m");
|
||
|
close(fd);
|
||
|
}
|
||
|
}
|
||
|
diff --git a/utils/nfsdcltrack/sqlite.c b/utils/nfsdcltrack/sqlite.c
|
||
|
index 1552eba..c59f777 100644
|
||
|
--- a/utils/nfsdcltrack/sqlite.c
|
||
|
+++ b/utils/nfsdcltrack/sqlite.c
|
||
|
@@ -51,6 +51,7 @@
|
||
|
#include <linux/limits.h>
|
||
|
|
||
|
#include "xlog.h"
|
||
|
+#include "sqlite.h"
|
||
|
|
||
|
#define CLTRACK_SQLITE_LATEST_SCHEMA_VERSION 2
|
||
|
|
||
|
@@ -203,7 +204,7 @@ rollback:
|
||
|
* then insert schema version into the parameters table and commit the
|
||
|
* transaction. On any error, rollback the transaction.
|
||
|
*/
|
||
|
-int
|
||
|
+static int
|
||
|
sqlite_maindb_init_v2(void)
|
||
|
{
|
||
|
int ret, ret2;
|
||
|
diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am
|
||
|
index 49158df..e5d7d04 100644
|
||
|
--- a/utils/nfsidmap/Makefile.am
|
||
|
+++ b/utils/nfsidmap/Makefile.am
|
||
|
@@ -3,6 +3,8 @@
|
||
|
man8_MANS = nfsidmap.man
|
||
|
sbin_PROGRAMS = nfsidmap
|
||
|
|
||
|
+AM_CPPFLAGS += -I ../../support/nfsidmap
|
||
|
+
|
||
|
nfsidmap_SOURCES = nfsidmap.c
|
||
|
nfsidmap_LDADD = -lkeyutils \
|
||
|
../../support/nfs/libnfs.la \
|
||
|
diff --git a/utils/nfsref/Makefile.am b/utils/nfsref/Makefile.am
|
||
|
new file mode 100644
|
||
|
index 0000000..2b2bb53
|
||
|
--- /dev/null
|
||
|
+++ b/utils/nfsref/Makefile.am
|
||
|
@@ -0,0 +1,39 @@
|
||
|
+##
|
||
|
+## @file utils/nfsref/Makefile.am
|
||
|
+## @brief Process this file with automake to produce utils/nfsref/Makefile.in
|
||
|
+##
|
||
|
+
|
||
|
+##
|
||
|
+## Copyright 2011, 2018 Oracle. All rights reserved.
|
||
|
+##
|
||
|
+## This file is part of nfs-utils.
|
||
|
+##
|
||
|
+## nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+## it under the terms of the GNU General Public License version 2.0 as
|
||
|
+## published by the Free Software Foundation.
|
||
|
+##
|
||
|
+## nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+## WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+## GNU General Public License version 2.0 for more details.
|
||
|
+##
|
||
|
+## You should have received a copy of the GNU General Public License
|
||
|
+## version 2.0 along with nfs-utils. If not, see:
|
||
|
+##
|
||
|
+## http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+##
|
||
|
+
|
||
|
+noinst_HEADERS = nfsref.h
|
||
|
+
|
||
|
+sbin_PROGRAMS = nfsref
|
||
|
+nfsref_SOURCES = add.c lookup.c nfsref.c remove.c
|
||
|
+LDADD = $(LIBXML2) $(LIBCAP) \
|
||
|
+ ../../support/nfs/libnfs.la \
|
||
|
+ ../../support/junction/libjunction.la
|
||
|
+
|
||
|
+man8_MANS = nfsref.man
|
||
|
+
|
||
|
+MAINTAINERCLEANFILES = Makefile.in
|
||
|
+
|
||
|
+AM_CPPFLAGS = -I. -I../../support/include
|
||
|
+##AM_LDFLAGS = -Wl,--as-needed
|
||
|
diff --git a/utils/nfsref/add.c b/utils/nfsref/add.c
|
||
|
new file mode 100644
|
||
|
index 0000000..781aeee
|
||
|
--- /dev/null
|
||
|
+++ b/utils/nfsref/add.c
|
||
|
@@ -0,0 +1,272 @@
|
||
|
+/**
|
||
|
+ * @file utils/nfsref/add.c
|
||
|
+ * @brief Add junction metadata to a local file system object
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Copyright 2011, 2018 Oracle. All rights reserved.
|
||
|
+ *
|
||
|
+ * This file is part of nfs-utils.
|
||
|
+ *
|
||
|
+ * nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License version 2.0 as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License version 2.0 for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * version 2.0 along with nfs-utils. If not, see:
|
||
|
+ *
|
||
|
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+ */
|
||
|
+
|
||
|
+#include <sys/stat.h>
|
||
|
+#include <sys/types.h>
|
||
|
+
|
||
|
+#include <stdbool.h>
|
||
|
+#include <stdint.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <string.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <errno.h>
|
||
|
+
|
||
|
+#include <uuid/uuid.h>
|
||
|
+
|
||
|
+#include "junction.h"
|
||
|
+#include "xlog.h"
|
||
|
+#include "nfsref.h"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Default cache expiration for FSN information
|
||
|
+ */
|
||
|
+#define FSN_DEFAULT_TTL (300)
|
||
|
+
|
||
|
+/**
|
||
|
+ * Display help message for "add" subcommand
|
||
|
+ *
|
||
|
+ * @param progname NUL-terminated C string containing name of program
|
||
|
+ * @return program exit status
|
||
|
+ */
|
||
|
+int
|
||
|
+nfsref_add_help(const char *progname)
|
||
|
+{
|
||
|
+ fprintf(stderr, " \n");
|
||
|
+
|
||
|
+ fprintf(stderr, "Usage: %s [ -t type ] add <junction path> "
|
||
|
+ "<server> <export> [ <server> <export> ... ]\n\n",
|
||
|
+ progname);
|
||
|
+
|
||
|
+ fprintf(stderr, "Add a new junction containing the specified list "
|
||
|
+ "of fileset locations.\n");
|
||
|
+ fprintf(stderr, "<junction path> is the filename of the new junction. "
|
||
|
+ "<server> is the hostname\n");
|
||
|
+ fprintf(stderr, "or IP address of an NFS server where the fileset is "
|
||
|
+ "located. <export> is the\n");
|
||
|
+ fprintf(stderr, "export pathname of the fileset on that server.\n\n");
|
||
|
+
|
||
|
+ fprintf(stderr, "For NFS basic junctions, the location list is stored "
|
||
|
+ "locally in the junction.\n");
|
||
|
+ fprintf(stderr, "For FedFS junctions, the location list is stored "
|
||
|
+ "as new FSN and FSL records\n");
|
||
|
+ fprintf(stderr, "on an NSDB.\n");
|
||
|
+
|
||
|
+ return EXIT_SUCCESS;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Fill in default settings for NFSv4.0 fs_locations4
|
||
|
+ *
|
||
|
+ * @param new NFS location structure to fill in
|
||
|
+ *
|
||
|
+ * See section 5.1.3.2 of the NSDB protocol draft.
|
||
|
+ */
|
||
|
+static void
|
||
|
+nfsref_add_fsloc_defaults(struct nfs_fsloc *new)
|
||
|
+{
|
||
|
+ new->nfl_hostport = 0;
|
||
|
+ new->nfl_flags.nfl_varsub = false;
|
||
|
+ new->nfl_currency = -1;
|
||
|
+ new->nfl_validfor = 0;
|
||
|
+ new->nfl_genflags.nfl_writable = false;
|
||
|
+ new->nfl_genflags.nfl_going = false;
|
||
|
+ new->nfl_genflags.nfl_split = true;
|
||
|
+ new->nfl_transflags.nfl_rdma = true;
|
||
|
+ new->nfl_info.nfl_simul = 0;
|
||
|
+ new->nfl_info.nfl_handle = 0;
|
||
|
+ new->nfl_info.nfl_fileid = 0;
|
||
|
+ new->nfl_info.nfl_writever = 0;
|
||
|
+ new->nfl_info.nfl_change = 0;
|
||
|
+ new->nfl_info.nfl_readdir = 0;
|
||
|
+ new->nfl_info.nfl_readrank = 0;
|
||
|
+ new->nfl_info.nfl_readorder = 0;
|
||
|
+ new->nfl_info.nfl_writerank = 0;
|
||
|
+ new->nfl_info.nfl_writeorder = 0;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Convert a pair of command line arguments to one nfs_fsloc structure
|
||
|
+ *
|
||
|
+ * @param server NUL-terminated C string containing file server hostname
|
||
|
+ * @param rootpath NUL-terminated C string containing POSIX-style export path
|
||
|
+ * @param fsloc OUT: NFS location structure
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * If nfsref_add_build_fsloc() returns FEDFS_OK, caller must free the
|
||
|
+ * returned fsloc with nfs_free_location().
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfsref_add_build_fsloc(const char *server, const char *rootpath,
|
||
|
+ struct nfs_fsloc **fsloc)
|
||
|
+{
|
||
|
+ struct nfs_fsloc *new;
|
||
|
+ FedFsStatus retval;
|
||
|
+
|
||
|
+ if (server == NULL || rootpath == NULL)
|
||
|
+ return FEDFS_ERR_INVAL;
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: Building fsloc for %s:%s",
|
||
|
+ __func__, server, rootpath);
|
||
|
+
|
||
|
+ new = nfs_new_location();
|
||
|
+ if (new == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: No memory", __func__);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ new->nfl_hostname = strdup(server);
|
||
|
+ if (new->nfl_hostname == NULL) {
|
||
|
+ nfs_free_location(new);
|
||
|
+ xlog(D_GENERAL, "%s: No memory", __func__);
|
||
|
+ return FEDFS_ERR_SVRFAULT;
|
||
|
+ }
|
||
|
+
|
||
|
+ retval = nsdb_posix_to_path_array(rootpath, &new->nfl_rootpath);
|
||
|
+ if (retval != FEDFS_OK) {
|
||
|
+ nfs_free_location(new);
|
||
|
+ return retval;
|
||
|
+ }
|
||
|
+
|
||
|
+ nfsref_add_fsloc_defaults(new);
|
||
|
+ *fsloc = new;
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Convert array of command line arguments to list of nfs_fsloc structures
|
||
|
+ *
|
||
|
+ * @param argv array of pointers to NUL-terminated C strings contains arguments
|
||
|
+ * @param optind index of "argv" where "add" subcommand arguments start
|
||
|
+ * @param fslocs OUT: list of NFS locations
|
||
|
+ * @return a FedFsStatus code
|
||
|
+ *
|
||
|
+ * If nfsref_add_build_fsloc_list() returns FEDFS_OK, caller must free the
|
||
|
+ * returned list of fslocs with nfs_free_locations().
|
||
|
+ */
|
||
|
+static FedFsStatus
|
||
|
+nfsref_add_build_fsloc_list(char **argv, int optind, struct nfs_fsloc **fslocs)
|
||
|
+{
|
||
|
+ struct nfs_fsloc *fsloc, *result = NULL;
|
||
|
+ FedFsStatus retval;
|
||
|
+ int i;
|
||
|
+
|
||
|
+ for (i = optind + 2; argv[i] != NULL; i += 2) {
|
||
|
+ retval = nfsref_add_build_fsloc(argv[i], argv[i + 1], &fsloc);
|
||
|
+ if (retval != FEDFS_OK) {
|
||
|
+ nfs_free_locations(result);
|
||
|
+ return retval;
|
||
|
+ }
|
||
|
+ if (result == NULL)
|
||
|
+ result = fsloc;
|
||
|
+ else
|
||
|
+ result->nfl_next = fsloc;
|
||
|
+ }
|
||
|
+ if (result == NULL)
|
||
|
+ return FEDFS_ERR_INVAL;
|
||
|
+
|
||
|
+ *fslocs = result;
|
||
|
+ return FEDFS_OK;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Add NFS locations to a junction
|
||
|
+ *
|
||
|
+ * @param junct_path NUL-terminated C string containing pathname of junction
|
||
|
+ * @param argv array of pointers to NUL-terminated C strings contains arguments
|
||
|
+ * @param optind index of "argv" where "add" subcommand arguments start
|
||
|
+ * @return program exit status
|
||
|
+ */
|
||
|
+static int
|
||
|
+nfsref_add_nfs_basic(const char *junct_path, char **argv, int optind)
|
||
|
+{
|
||
|
+ struct nfs_fsloc *fslocs = NULL;
|
||
|
+ FedFsStatus retval;
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: Adding basic junction to %s",
|
||
|
+ __func__, junct_path);
|
||
|
+
|
||
|
+ retval = nfsref_add_build_fsloc_list(argv, optind, &fslocs);
|
||
|
+ switch (retval) {
|
||
|
+ case FEDFS_OK:
|
||
|
+ break;
|
||
|
+ case FEDFS_ERR_INVAL:
|
||
|
+ xlog(L_ERROR, "Missing arguments");
|
||
|
+ return EXIT_FAILURE;
|
||
|
+ case FEDFS_ERR_SVRFAULT:
|
||
|
+ xlog(L_ERROR, "No memory");
|
||
|
+ return EXIT_FAILURE;
|
||
|
+ default:
|
||
|
+ xlog(L_ERROR, "Failed to add NFS location metadata to %s: %s",
|
||
|
+ junct_path, nsdb_display_fedfsstatus(retval));
|
||
|
+ return EXIT_FAILURE;
|
||
|
+ }
|
||
|
+
|
||
|
+ retval = nfs_add_junction(junct_path, fslocs);
|
||
|
+ nfs_free_locations(fslocs);
|
||
|
+ switch (retval) {
|
||
|
+ case FEDFS_OK:
|
||
|
+ break;
|
||
|
+ case FEDFS_ERR_EXIST:
|
||
|
+ xlog(L_ERROR, "%s already contains junction metadata",
|
||
|
+ junct_path);
|
||
|
+ return EXIT_FAILURE;
|
||
|
+ default:
|
||
|
+ xlog(L_ERROR, "Failed to add NFS location metadata to %s: %s",
|
||
|
+ junct_path, nsdb_display_fedfsstatus(retval));
|
||
|
+ return EXIT_FAILURE;
|
||
|
+ }
|
||
|
+
|
||
|
+ printf("Created junction %s\n", junct_path);
|
||
|
+ return EXIT_SUCCESS;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Add locations to a junction
|
||
|
+ *
|
||
|
+ * @param type type of junction to add
|
||
|
+ * @param junct_path NUL-terminated C string containing pathname of junction
|
||
|
+ * @param argv array of pointers to NUL-terminated C strings contains arguments
|
||
|
+ * @param optind index of "argv" where "add" subcommand arguments start
|
||
|
+ * @return program exit status
|
||
|
+ */
|
||
|
+int
|
||
|
+nfsref_add(enum nfsref_type type, const char *junct_path, char **argv, int optind)
|
||
|
+{
|
||
|
+ if (mkdir(junct_path, 0755) == -1)
|
||
|
+ if (errno != EEXIST) {
|
||
|
+ xlog(L_ERROR, "Failed to create junction object: %m");
|
||
|
+ return EXIT_FAILURE;
|
||
|
+ }
|
||
|
+
|
||
|
+ switch (type) {
|
||
|
+ case NFSREF_TYPE_UNSPECIFIED:
|
||
|
+ case NFSREF_TYPE_NFS_BASIC:
|
||
|
+ return nfsref_add_nfs_basic(junct_path, argv, optind);
|
||
|
+ default:
|
||
|
+ xlog(L_ERROR, "Unrecognized junction type");
|
||
|
+ }
|
||
|
+ return EXIT_FAILURE;
|
||
|
+}
|
||
|
diff --git a/utils/nfsref/lookup.c b/utils/nfsref/lookup.c
|
||
|
new file mode 100644
|
||
|
index 0000000..16fca2e
|
||
|
--- /dev/null
|
||
|
+++ b/utils/nfsref/lookup.c
|
||
|
@@ -0,0 +1,211 @@
|
||
|
+/**
|
||
|
+ * @file utils/nfsref/lookup.c
|
||
|
+ * @brief Examine junction metadata from a local file system object
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Copyright 2011, 2018 Oracle. All rights reserved.
|
||
|
+ *
|
||
|
+ * This file is part of nfs-utils.
|
||
|
+ *
|
||
|
+ * nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License version 2.0 as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License version 2.0 for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * version 2.0 along with nfs-utils. If not, see:
|
||
|
+ *
|
||
|
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+ */
|
||
|
+
|
||
|
+#include <stdint.h>
|
||
|
+#include <stdbool.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <stdio.h>
|
||
|
+
|
||
|
+#include <rpcsvc/nfs_prot.h>
|
||
|
+
|
||
|
+#include "junction.h"
|
||
|
+#include "xlog.h"
|
||
|
+#include "nfsref.h"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Display help message for "lookup" subcommand
|
||
|
+ *
|
||
|
+ * @param progname NUL-terminated C string containing name of program
|
||
|
+ * @return program exit status
|
||
|
+ */
|
||
|
+int
|
||
|
+nfsref_lookup_help(const char *progname)
|
||
|
+{
|
||
|
+ fprintf(stderr, " \n");
|
||
|
+
|
||
|
+ fprintf(stderr, "Usage: %s [ -t type ] lookup <junction path>\n\n",
|
||
|
+ progname);
|
||
|
+
|
||
|
+ fprintf(stderr, "Display the contents of the junction at "
|
||
|
+ "<junction path>. For NFS basic\n");
|
||
|
+ fprintf(stderr, "junctions, the local contents of the junction "
|
||
|
+ "are displayed. For FedFS\n");
|
||
|
+ fprintf(stderr, "junctions, FSL records are retrieved from the "
|
||
|
+ "NSDB and displayed.\n");
|
||
|
+
|
||
|
+ return EXIT_SUCCESS;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Convert a boolean value into a displayable string constant
|
||
|
+ *
|
||
|
+ * @param value boolean value
|
||
|
+ * @return NUL-terminated static constant C string
|
||
|
+ */
|
||
|
+static const char *
|
||
|
+nfsref_lookup_display_boolean(_Bool value)
|
||
|
+{
|
||
|
+ return value ? "true" : "false";
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Display a single NFS location
|
||
|
+ *
|
||
|
+ * @param fsloc pointer to an NFS location structure
|
||
|
+ */
|
||
|
+static void
|
||
|
+nfsref_lookup_display_nfs_location(struct nfs_fsloc *fsloc)
|
||
|
+{
|
||
|
+ char *rootpath;
|
||
|
+
|
||
|
+ if (nsdb_path_array_to_posix(fsloc->nfl_rootpath, &rootpath) == FEDFS_OK) {
|
||
|
+ printf("%s:%s\n", fsloc->nfl_hostname, rootpath);
|
||
|
+ free(rootpath);
|
||
|
+ } else
|
||
|
+ printf("%s: - Invalid root path -\n", fsloc->nfl_hostname);
|
||
|
+ printf("\n");
|
||
|
+
|
||
|
+ printf("\tNFS port:\t%u\n", fsloc->nfl_hostport);
|
||
|
+ printf("\tValid for:\t%d\n", fsloc->nfl_validfor);
|
||
|
+ printf("\tCurrency:\t%d\n", fsloc->nfl_currency);
|
||
|
+ printf("\tFlags:\t\tvarsub(%s)\n",
|
||
|
+ nfsref_lookup_display_boolean(fsloc->nfl_flags.nfl_varsub));
|
||
|
+
|
||
|
+ printf("\tGenFlags:\twritable(%s), going(%s), split(%s)\n",
|
||
|
+ nfsref_lookup_display_boolean(fsloc->nfl_genflags.nfl_writable),
|
||
|
+ nfsref_lookup_display_boolean(fsloc->nfl_genflags.nfl_going),
|
||
|
+ nfsref_lookup_display_boolean(fsloc->nfl_genflags.nfl_split));
|
||
|
+ printf("\tTransFlags:\trdma(%s)\n",
|
||
|
+ nfsref_lookup_display_boolean(fsloc->nfl_transflags.nfl_rdma));
|
||
|
+
|
||
|
+ printf("\tClass:\t\tsimul(%u), handle(%u), fileid(%u)\n",
|
||
|
+ fsloc->nfl_info.nfl_simul,
|
||
|
+ fsloc->nfl_info.nfl_handle,
|
||
|
+ fsloc->nfl_info.nfl_fileid);
|
||
|
+ printf("\tClass:\t\twritever(%u), change(%u), readdir(%u)\n",
|
||
|
+ fsloc->nfl_info.nfl_writever,
|
||
|
+ fsloc->nfl_info.nfl_change,
|
||
|
+ fsloc->nfl_info.nfl_readdir);
|
||
|
+ printf("\tRead:\t\trank(%u), order(%u)\n",
|
||
|
+ fsloc->nfl_info.nfl_readrank, fsloc->nfl_info.nfl_readorder);
|
||
|
+ printf("\tWrite:\t\trank(%u), order(%u)\n",
|
||
|
+ fsloc->nfl_info.nfl_writerank, fsloc->nfl_info.nfl_writeorder);
|
||
|
+
|
||
|
+ printf("\n");
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Display a list of NFS locations
|
||
|
+ *
|
||
|
+ * @param fslocs list of NFS locations to display
|
||
|
+ */
|
||
|
+static void
|
||
|
+nfsref_lookup_display_nfs_locations(struct nfs_fsloc *fslocs)
|
||
|
+{
|
||
|
+ struct nfs_fsloc *fsloc;
|
||
|
+
|
||
|
+ for (fsloc = fslocs; fsloc != NULL; fsloc = fsloc->nfl_next)
|
||
|
+ nfsref_lookup_display_nfs_location(fsloc);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * List NFS locations in an nfs-basic junction
|
||
|
+ *
|
||
|
+ * @param junct_path NUL-terminated C string containing pathname of junction
|
||
|
+ * @return program exit status
|
||
|
+ */
|
||
|
+static int
|
||
|
+nfsref_lookup_nfs_basic(const char *junct_path)
|
||
|
+{
|
||
|
+ struct nfs_fsloc *fslocs = NULL;
|
||
|
+ FedFsStatus retval;
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: Looking up basic junction in %s",
|
||
|
+ __func__, junct_path);
|
||
|
+
|
||
|
+ retval = nfs_is_junction(junct_path);
|
||
|
+ switch (retval) {
|
||
|
+ case FEDFS_OK:
|
||
|
+ break;
|
||
|
+ case FEDFS_ERR_NOTJUNCT:
|
||
|
+ xlog(L_ERROR, "%s is not an nfs-basic junction", junct_path);
|
||
|
+ return EXIT_FAILURE;
|
||
|
+ default:
|
||
|
+ xlog(L_ERROR, "Failed to access %s: %s",
|
||
|
+ junct_path, nsdb_display_fedfsstatus(retval));
|
||
|
+ return EXIT_FAILURE;
|
||
|
+ }
|
||
|
+
|
||
|
+ retval = nfs_get_locations(junct_path, &fslocs);
|
||
|
+ if (retval != FEDFS_OK) {
|
||
|
+ xlog(L_ERROR, "Failed to access %s: %s",
|
||
|
+ junct_path, nsdb_display_fedfsstatus(retval));
|
||
|
+ return EXIT_FAILURE;
|
||
|
+ }
|
||
|
+
|
||
|
+ nfsref_lookup_display_nfs_locations(fslocs);
|
||
|
+
|
||
|
+ nfs_free_locations(fslocs);
|
||
|
+ return EXIT_SUCCESS;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Resolve either a FedFS or NFS basic junction
|
||
|
+ *
|
||
|
+ * @param junct_path NUL-terminated C string containing pathname of junction
|
||
|
+ * @return program exit status
|
||
|
+ */
|
||
|
+static int
|
||
|
+nfsref_lookup_unspecified(const char *junct_path)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+
|
||
|
+ retval = nfs_is_junction(junct_path);
|
||
|
+ if (retval == FEDFS_OK)
|
||
|
+ return nfsref_lookup_nfs_basic(junct_path);
|
||
|
+ xlog(L_ERROR, "%s is not a junction", junct_path);
|
||
|
+ return EXIT_FAILURE;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Enumerate metadata of a junction
|
||
|
+ *
|
||
|
+ * @param type type of junction to add
|
||
|
+ * @param junct_path NUL-terminated C string containing pathname of junction
|
||
|
+ * @return program exit status
|
||
|
+ */
|
||
|
+int
|
||
|
+nfsref_lookup(enum nfsref_type type, const char *junct_path)
|
||
|
+{
|
||
|
+ switch (type) {
|
||
|
+ case NFSREF_TYPE_UNSPECIFIED:
|
||
|
+ return nfsref_lookup_unspecified(junct_path);
|
||
|
+ case NFSREF_TYPE_NFS_BASIC:
|
||
|
+ return nfsref_lookup_nfs_basic(junct_path);
|
||
|
+ default:
|
||
|
+ xlog(L_ERROR, "Unrecognized junction type");
|
||
|
+ }
|
||
|
+ return EXIT_FAILURE;
|
||
|
+}
|
||
|
diff --git a/utils/nfsref/nfsref.c b/utils/nfsref/nfsref.c
|
||
|
new file mode 100644
|
||
|
index 0000000..7f97d01
|
||
|
--- /dev/null
|
||
|
+++ b/utils/nfsref/nfsref.c
|
||
|
@@ -0,0 +1,189 @@
|
||
|
+/**
|
||
|
+ * @file utils/nfsref/nfsref.c
|
||
|
+ * @brief Manage NFS referrals
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Copyright 2011, 2018 Oracle. All rights reserved.
|
||
|
+ *
|
||
|
+ * This file is part of nfs-utils.
|
||
|
+ *
|
||
|
+ * nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License version 2.0 as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License version 2.0 for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * version 2.0 along with nfs-utils. If not, see:
|
||
|
+ *
|
||
|
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+ */
|
||
|
+
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/capability.h>
|
||
|
+#include <sys/prctl.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+
|
||
|
+#include <stdbool.h>
|
||
|
+#include <stdint.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <string.h>
|
||
|
+#include <fcntl.h>
|
||
|
+#include <getopt.h>
|
||
|
+#include <time.h>
|
||
|
+
|
||
|
+#include <locale.h>
|
||
|
+#include <langinfo.h>
|
||
|
+
|
||
|
+#include "junction.h"
|
||
|
+#include "xlog.h"
|
||
|
+#include "nfsref.h"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Short form command line options
|
||
|
+ */
|
||
|
+static const char nfsref_opts[] = "?dt:";
|
||
|
+
|
||
|
+/**
|
||
|
+ * Long form command line options
|
||
|
+ */
|
||
|
+static const struct option nfsref_longopts[] = {
|
||
|
+ { "debug", 0, NULL, 'd', },
|
||
|
+ { "help", 0, NULL, '?', },
|
||
|
+ { "type", 1, NULL, 't', },
|
||
|
+ { NULL, 0, NULL, 0, },
|
||
|
+};
|
||
|
+
|
||
|
+/**
|
||
|
+ * Display program synopsis
|
||
|
+ *
|
||
|
+ * @param progname NUL-terminated C string containing name of program
|
||
|
+ */
|
||
|
+static void
|
||
|
+nfsref_usage(const char *progname)
|
||
|
+{
|
||
|
+ fprintf(stderr, "Usage: %s [ -t type ] SUBCOMMAND [ ARGUMENTS ]\n\n",
|
||
|
+ progname);
|
||
|
+
|
||
|
+ fprintf(stderr, "SUBCOMMAND is one of:\n");
|
||
|
+ fprintf(stderr, "\tadd Add a new junction\n");
|
||
|
+ fprintf(stderr, "\tremove Remove an existing junction\n");
|
||
|
+ fprintf(stderr, "\tlookup Enumerate a junction\n");
|
||
|
+
|
||
|
+ fprintf(stderr, "\nUse \"%s SUBCOMMAND -?\" for details.\n", progname);
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Program entry point
|
||
|
+ *
|
||
|
+ * @param argc count of command line arguments
|
||
|
+ * @param argv array of NUL-terminated C strings containing command line arguments
|
||
|
+ * @return program exit status
|
||
|
+ */
|
||
|
+int
|
||
|
+main(int argc, char **argv)
|
||
|
+{
|
||
|
+ char *progname, *subcommand, *junct_path;
|
||
|
+ enum nfsref_type type;
|
||
|
+ int arg, exit_status;
|
||
|
+ _Bool help;
|
||
|
+
|
||
|
+ (void)setlocale(LC_ALL, "");
|
||
|
+ (void)umask(S_IWGRP | S_IWOTH);
|
||
|
+
|
||
|
+ exit_status = EXIT_FAILURE;
|
||
|
+
|
||
|
+ /* Set the basename */
|
||
|
+ if ((progname = strrchr(argv[0], '/')) != NULL)
|
||
|
+ progname++;
|
||
|
+ else
|
||
|
+ progname = argv[0];
|
||
|
+
|
||
|
+ xlog_stderr(1);
|
||
|
+ xlog_syslog(0);
|
||
|
+ xlog_open(progname);
|
||
|
+
|
||
|
+ if (argc < 2) {
|
||
|
+ nfsref_usage(progname);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ help = false;
|
||
|
+ type = NFSREF_TYPE_UNSPECIFIED;
|
||
|
+ while ((arg = getopt_long(argc, argv, nfsref_opts,
|
||
|
+ nfsref_longopts, NULL)) != -1) {
|
||
|
+ switch (arg) {
|
||
|
+ case 'd':
|
||
|
+ xlog_config(D_ALL, 1);
|
||
|
+ break;
|
||
|
+ case 't':
|
||
|
+ if (strcmp(optarg, "nfs-basic") == 0)
|
||
|
+ type = NFSREF_TYPE_NFS_BASIC;
|
||
|
+ else if (strcmp(optarg, "nfs-fedfs") == 0)
|
||
|
+ type = NFSREF_TYPE_NFS_FEDFS;
|
||
|
+ else {
|
||
|
+ xlog(L_ERROR,
|
||
|
+ "Unrecognized junction type: %s",
|
||
|
+ optarg);
|
||
|
+ exit(EXIT_FAILURE);
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ case '?':
|
||
|
+ help = true;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (argc < optind + 1) {
|
||
|
+ nfsref_usage(progname);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!help && geteuid() != 0) {
|
||
|
+ xlog(L_ERROR, "Root permission is required");
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ subcommand = argv[optind];
|
||
|
+ junct_path = argv[optind + 1];
|
||
|
+
|
||
|
+ if (strcasecmp(subcommand, "add") == 0) {
|
||
|
+ if (help) {
|
||
|
+ exit_status = nfsref_add_help(progname);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ if (argc < optind + 3) {
|
||
|
+ xlog(L_ERROR, "Not enough positional parameters");
|
||
|
+ nfsref_usage(progname);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ exit_status = nfsref_add(type, junct_path, argv, optind);
|
||
|
+ if (exit_status == EXIT_SUCCESS)
|
||
|
+ (void)junction_flush_exports_cache();
|
||
|
+ } else if (strcasecmp(subcommand, "remove") == 0) {
|
||
|
+ if (help) {
|
||
|
+ exit_status = nfsref_remove_help(progname);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ exit_status = nfsref_remove(type, junct_path);
|
||
|
+ if (exit_status == EXIT_SUCCESS)
|
||
|
+ (void)junction_flush_exports_cache();
|
||
|
+ } else if (strcasecmp(subcommand, "lookup") == 0) {
|
||
|
+ if (help) {
|
||
|
+ exit_status = nfsref_lookup_help(progname);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ exit_status = nfsref_lookup(type, junct_path);
|
||
|
+ } else {
|
||
|
+ xlog(L_ERROR, "Unrecognized subcommand: %s", subcommand);
|
||
|
+ nfsref_usage(progname);
|
||
|
+ }
|
||
|
+
|
||
|
+out:
|
||
|
+ exit(exit_status);
|
||
|
+}
|
||
|
diff --git a/utils/nfsref/nfsref.h b/utils/nfsref/nfsref.h
|
||
|
new file mode 100644
|
||
|
index 0000000..bf0e70e
|
||
|
--- /dev/null
|
||
|
+++ b/utils/nfsref/nfsref.h
|
||
|
@@ -0,0 +1,47 @@
|
||
|
+/**
|
||
|
+ * @file support/nfsref/nfsref.h
|
||
|
+ * @brief Declarations and definitions for nfsref command line tool
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Copyright 2011, 2018 Oracle. All rights reserved.
|
||
|
+ *
|
||
|
+ * This file is part of nfs-utils.
|
||
|
+ *
|
||
|
+ * nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License version 2.0 as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License version 2.0 for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * version 2.0 along with nfs-utils. If not, see:
|
||
|
+ *
|
||
|
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+ */
|
||
|
+
|
||
|
+#ifndef UTILS_NFSREF_H
|
||
|
+#define UTILS_NFSREF_H
|
||
|
+
|
||
|
+/**
|
||
|
+ * Junction types supported by the "nfsref" command
|
||
|
+ */
|
||
|
+enum nfsref_type {
|
||
|
+ NFSREF_TYPE_UNSPECIFIED = 1,
|
||
|
+ NFSREF_TYPE_NFS_BASIC,
|
||
|
+ NFSREF_TYPE_NFS_FEDFS
|
||
|
+};
|
||
|
+
|
||
|
+int nfsref_add(enum nfsref_type type, const char *junct_path, char **argv,
|
||
|
+ int optind);
|
||
|
+int nfsref_remove(enum nfsref_type type, const char *junct_path);
|
||
|
+int nfsref_lookup(enum nfsref_type type, const char *junct_path);
|
||
|
+
|
||
|
+int nfsref_add_help(const char *progname);
|
||
|
+int nfsref_remove_help(const char *progname);
|
||
|
+int nfsref_lookup_help(const char *progname);
|
||
|
+
|
||
|
+#endif /* !UTILS_NFSREF_H */
|
||
|
diff --git a/utils/nfsref/nfsref.man b/utils/nfsref/nfsref.man
|
||
|
new file mode 100644
|
||
|
index 0000000..1261549
|
||
|
--- /dev/null
|
||
|
+++ b/utils/nfsref/nfsref.man
|
||
|
@@ -0,0 +1,180 @@
|
||
|
+.\"@(#)nfsref.8"
|
||
|
+.\"
|
||
|
+.\" @file utils/nfsref/nfsref.man
|
||
|
+.\" @brief man page for nfsref command
|
||
|
+.\"
|
||
|
+
|
||
|
+.\"
|
||
|
+.\" Copyright 2011, 2018 Oracle. All rights reserved.
|
||
|
+.\"
|
||
|
+.\" This file is part of nfs-utils.
|
||
|
+.\"
|
||
|
+.\" nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+.\" it under the terms of the GNU General Public License version 2.0 as
|
||
|
+.\" published by the Free Software Foundation.
|
||
|
+.\"
|
||
|
+.\" nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+.\" WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+.\" GNU General Public License version 2.0 for more details.
|
||
|
+.\"
|
||
|
+.\" You should have received a copy of the GNU General Public License
|
||
|
+.\" version 2.0 along with nfs-utils. If not, see:
|
||
|
+.\"
|
||
|
+.\" http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+.\"
|
||
|
+.TH NFSREF 8 "9 Jan 2018"
|
||
|
+.SH NAME
|
||
|
+nfsref \- manage NFS referrals
|
||
|
+.SH SYNOPSIS
|
||
|
+.B nfsref
|
||
|
+.RB [ \-?d ]
|
||
|
+.RB [ \-t
|
||
|
+.IB type ]
|
||
|
+.B add
|
||
|
+.I pathname server export
|
||
|
+.RI [ " server"
|
||
|
+.IR export " ... ]"
|
||
|
+.P
|
||
|
+.B nfsref
|
||
|
+.RB [ \-?d ]
|
||
|
+.RB [ \-t
|
||
|
+.IB type ]
|
||
|
+.B remove
|
||
|
+.I pathname
|
||
|
+.P
|
||
|
+.B nfsref
|
||
|
+.RB [ \-?d ]
|
||
|
+.RB [ \-t
|
||
|
+.IB type ]
|
||
|
+.B lookup
|
||
|
+.I pathname
|
||
|
+.SH INTRODUCTION
|
||
|
+NFS version 4 introduces the concept of
|
||
|
+.I file system referrals
|
||
|
+to NFS.
|
||
|
+A file system referral is like a symbolic link on a file server
|
||
|
+to another file system share, possibly on another file server.
|
||
|
+On an NFS client, a referral behaves like an automounted directory.
|
||
|
+The client, under the server's direction, mounts a new NFS export
|
||
|
+automatically when an application first accesses that directory.
|
||
|
+.P
|
||
|
+Referrals are typically used to construct a single file name space
|
||
|
+across multiple file servers.
|
||
|
+Because file servers control the shape of the name space,
|
||
|
+no client configuration is required,
|
||
|
+and all clients see the same referral information.
|
||
|
+.P
|
||
|
+The Linux NFS server supports NFS version 4 referrals.
|
||
|
+Administrators can specify the
|
||
|
+.B refer=
|
||
|
+export option in
|
||
|
+.I /etc/exports
|
||
|
+to configure a list of exports from which the client can choose.
|
||
|
+See
|
||
|
+.BR exports (5)
|
||
|
+for details.
|
||
|
+.P
|
||
|
+.SH DESCRIPTION
|
||
|
+The
|
||
|
+.BR nfsref (8)
|
||
|
+command is a simple way to get started managing junction metadata.
|
||
|
+Other administrative commands provide richer access to junction information.
|
||
|
+.SS Subcommands
|
||
|
+Valid
|
||
|
+.BR nfsref (8)
|
||
|
+subcommands are:
|
||
|
+.IP "\fBadd\fP"
|
||
|
+Adds junction information to the directory named by
|
||
|
+.IR pathname .
|
||
|
+The named directory must already exist,
|
||
|
+and must not already contain junction information.
|
||
|
+Regular directory contents are obscured to NFS clients by this operation.
|
||
|
+.IP
|
||
|
+A list of one or more file server and export path pairs
|
||
|
+is also specified on the command line.
|
||
|
+When creating an NFS basic junction, this list is
|
||
|
+stored in an extended attribute of the directory.
|
||
|
+.IP
|
||
|
+If junction creation is successful, the
|
||
|
+.BR nfsref (8)
|
||
|
+command flushes the kernel's export cache
|
||
|
+to remove previously cached junction information.
|
||
|
+.IP "\fBremove\fP"
|
||
|
+Removes junction information from the directory named by
|
||
|
+.IR pathname .
|
||
|
+The named directory must exist,
|
||
|
+and must contain junction information.
|
||
|
+Regular directory contents are made visible to NFS clients again by this operation.
|
||
|
+.IP
|
||
|
+If junction deletion is successful, the
|
||
|
+.BR nfsref (8)
|
||
|
+command flushes the kernel's export cache
|
||
|
+to remove previously cached junction information.
|
||
|
+.IP "\fBlookup\fP"
|
||
|
+Displays junction information stored in the directory named by
|
||
|
+.IR pathname .
|
||
|
+The named directory must exist,
|
||
|
+and must contain junction information.
|
||
|
+.IP
|
||
|
+When looking up an NFS basic junction, the junction information
|
||
|
+in the directory is listed on
|
||
|
+.IR stdout .
|
||
|
+.SS Command line options
|
||
|
+.IP "\fB\-d, \-\-debug"
|
||
|
+Enables debugging messages during operation.
|
||
|
+.IP "\fB\-t, \-\-type=\fIjunction-type\fP"
|
||
|
+Specifies the junction type for the operation. Valid values for
|
||
|
+.I junction-type
|
||
|
+are
|
||
|
+.B nfs-basic
|
||
|
+or
|
||
|
+.BR nfs-fedfs .
|
||
|
+.IP
|
||
|
+For the
|
||
|
+.B add
|
||
|
+subcommand, the default value if this option is not specified is
|
||
|
+.BR nfs-basic .
|
||
|
+For the
|
||
|
+.B remove
|
||
|
+and
|
||
|
+.B lookup
|
||
|
+subcommands, the
|
||
|
+.B \-\-type
|
||
|
+option is not required. The
|
||
|
+.BR nfsref (8)
|
||
|
+command operates on whatever junction contents are available.
|
||
|
+.SH EXAMPLES
|
||
|
+Suppose you have two file servers,
|
||
|
+.I top.example.net
|
||
|
+and
|
||
|
+.IR home.example.net .
|
||
|
+You want all your clients to mount
|
||
|
+.I top.example.net:/
|
||
|
+and then see the files under
|
||
|
+.I home.example.net:/
|
||
|
+automatically in
|
||
|
+.IR top:/home .
|
||
|
+.P
|
||
|
+On
|
||
|
+.IR top.example.net ,
|
||
|
+you might issue this command as root:
|
||
|
+.RS
|
||
|
+.sp
|
||
|
+# mkdir /home
|
||
|
+.br
|
||
|
+# nfsref --type=nfs-basic add /home home.example.net /
|
||
|
+.br
|
||
|
+Created junction /home.
|
||
|
+.sp
|
||
|
+.RE
|
||
|
+.SH FILES
|
||
|
+.TP
|
||
|
+.I /etc/exports
|
||
|
+NFS server export table
|
||
|
+.SH "SEE ALSO"
|
||
|
+.BR exports (5)
|
||
|
+.sp
|
||
|
+RFC 5661 for a description of NFS version 4 referrals
|
||
|
+.SH "AUTHOR"
|
||
|
+Chuck Lever <chuck.lever@oracle.com>
|
||
|
diff --git a/utils/nfsref/remove.c b/utils/nfsref/remove.c
|
||
|
new file mode 100644
|
||
|
index 0000000..1a4e371
|
||
|
--- /dev/null
|
||
|
+++ b/utils/nfsref/remove.c
|
||
|
@@ -0,0 +1,145 @@
|
||
|
+/**
|
||
|
+ * @file utils/nfsref/remove.c
|
||
|
+ * @brief Remove junction metadata from a local file system object
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Copyright 2011, 2018 Oracle. All rights reserved.
|
||
|
+ *
|
||
|
+ * This file is part of nfs-utils.
|
||
|
+ *
|
||
|
+ * nfs-utils is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License version 2.0 as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * nfs-utils is distributed in the hope that it will be useful, but
|
||
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+ * GNU General Public License version 2.0 for more details.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * version 2.0 along with nfs-utils. If not, see:
|
||
|
+ *
|
||
|
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
|
||
|
+ */
|
||
|
+
|
||
|
+#include <stdbool.h>
|
||
|
+#include <stdint.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <stdio.h>
|
||
|
+
|
||
|
+#include <unistd.h>
|
||
|
+#include <errno.h>
|
||
|
+
|
||
|
+#include "junction.h"
|
||
|
+#include "xlog.h"
|
||
|
+#include "nfsref.h"
|
||
|
+
|
||
|
+/**
|
||
|
+ * Display help message for "remove" subcommand
|
||
|
+ *
|
||
|
+ * @param progname NUL-terminated C string containing name of program
|
||
|
+ * @return program exit status
|
||
|
+ */
|
||
|
+int
|
||
|
+nfsref_remove_help(const char *progname)
|
||
|
+{
|
||
|
+ fprintf(stderr, " \n");
|
||
|
+
|
||
|
+ fprintf(stderr, "Usage: %s [ -t type ] remove <junction path>\n\n",
|
||
|
+ progname);
|
||
|
+
|
||
|
+ fprintf(stderr, "Remove the junction at <junction path>. For FedFS "
|
||
|
+ "junctions, FSL and FSN\n");
|
||
|
+ fprintf(stderr, "records are removed from the NSDB.\n");
|
||
|
+
|
||
|
+ return EXIT_SUCCESS;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Remove an NFS locations-style junction
|
||
|
+ *
|
||
|
+ * @param junct_path NUL-terminated C string containing pathname of junction
|
||
|
+ * @return program exit status
|
||
|
+ */
|
||
|
+static int
|
||
|
+nfsref_remove_nfs_basic(const char *junct_path)
|
||
|
+{
|
||
|
+ int status = EXIT_FAILURE;
|
||
|
+ FedFsStatus retval;
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: Removing FedFS junction from %s",
|
||
|
+ __func__, junct_path);
|
||
|
+
|
||
|
+ retval = nfs_delete_junction(junct_path);
|
||
|
+ switch (retval) {
|
||
|
+ case FEDFS_OK:
|
||
|
+ printf("Removed nfs-basic junction from %s\n", junct_path);
|
||
|
+ status = EXIT_SUCCESS;
|
||
|
+ break;
|
||
|
+ case FEDFS_ERR_NOTJUNCT:
|
||
|
+ xlog(L_ERROR, "%s is not an nfs-basic junction", junct_path);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ xlog(L_ERROR, "Failed to delete %s: %s",
|
||
|
+ junct_path, nsdb_display_fedfsstatus(retval));
|
||
|
+ }
|
||
|
+
|
||
|
+ return status;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Remove any NFS junction information
|
||
|
+ *
|
||
|
+ * @param junct_path NUL-terminated C string containing pathname of junction
|
||
|
+ * @return program exit status
|
||
|
+ */
|
||
|
+static int
|
||
|
+nfsref_remove_unspecified(const char *junct_path)
|
||
|
+{
|
||
|
+ FedFsStatus retval;
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: Removing junction from %s",
|
||
|
+ __func__, junct_path);
|
||
|
+
|
||
|
+ retval = nfs_delete_junction(junct_path);
|
||
|
+ if (retval != FEDFS_OK) {
|
||
|
+ if (retval != FEDFS_ERR_NOTJUNCT)
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ printf("Removed junction from %s\n", junct_path);
|
||
|
+ return EXIT_SUCCESS;
|
||
|
+
|
||
|
+out_err:
|
||
|
+ switch (retval) {
|
||
|
+ case FEDFS_ERR_NOTJUNCT:
|
||
|
+ xlog(L_ERROR, "No junction information found in %s", junct_path);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ xlog(L_ERROR, "Failed to delete %s: %s",
|
||
|
+ junct_path, nsdb_display_fedfsstatus(retval));
|
||
|
+ }
|
||
|
+ return EXIT_FAILURE;
|
||
|
+}
|
||
|
+
|
||
|
+/**
|
||
|
+ * Remove an NFS junction
|
||
|
+ *
|
||
|
+ * @param type type of junction to add
|
||
|
+ * @param junct_path NUL-terminated C string containing pathname of junction
|
||
|
+ * @return program exit status
|
||
|
+ */
|
||
|
+int
|
||
|
+nfsref_remove(enum nfsref_type type, const char *junct_path)
|
||
|
+{
|
||
|
+ switch (type) {
|
||
|
+ case NFSREF_TYPE_UNSPECIFIED:
|
||
|
+ return nfsref_remove_unspecified(junct_path);
|
||
|
+ case NFSREF_TYPE_NFS_BASIC:
|
||
|
+ return nfsref_remove_nfs_basic(junct_path);
|
||
|
+ default:
|
||
|
+ xlog(L_ERROR, "Unrecognized junction type");
|
||
|
+ }
|
||
|
+ return EXIT_FAILURE;
|
||
|
+}
|
||
|
diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c
|
||
|
index eddbe9a..c779053 100644
|
||
|
--- a/utils/nfsstat/nfsstat.c
|
||
|
+++ b/utils/nfsstat/nfsstat.c
|
||
|
@@ -300,7 +300,7 @@ int versions[] = {
|
||
|
PRNT_V4
|
||
|
};
|
||
|
|
||
|
-void usage(char *name)
|
||
|
+static void usage(char *name)
|
||
|
{
|
||
|
printf("Usage: %s [OPTION]...\n\
|
||
|
\n\
|
||
|
@@ -980,8 +980,10 @@ more_stats:
|
||
|
}
|
||
|
bufp = buf;
|
||
|
for (; curindex < numvals; curindex++) {
|
||
|
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||
|
n = sscanf(bufp, fmt, &ip->valptr[curindex],
|
||
|
&numconsumed);
|
||
|
+#pragma GCC diagnostic warning "-Wformat-nonliteral"
|
||
|
if (n != 1)
|
||
|
break;
|
||
|
if (is_proc) {
|
||
|
diff --git a/utils/statd/statd.c b/utils/statd/statd.c
|
||
|
index 197d853..563a272 100644
|
||
|
--- a/utils/statd/statd.c
|
||
|
+++ b/utils/statd/statd.c
|
||
|
@@ -225,7 +225,8 @@ static void set_nlm_port(char *type, int port)
|
||
|
fd = open(pathbuf, O_WRONLY);
|
||
|
if (fd < 0 && errno == ENOENT) {
|
||
|
/* probably module not loaded */
|
||
|
- system("modprobe lockd");
|
||
|
+ if (system("modprobe lockd"))
|
||
|
+ {/* ignore return value */};
|
||
|
fd = open(pathbuf, O_WRONLY);
|
||
|
}
|
||
|
if (fd >= 0) {
|
||
|
diff --git a/utils/statd/svc_run.c b/utils/statd/svc_run.c
|
||
|
index 28c1ad6..d1dbd74 100644
|
||
|
--- a/utils/statd/svc_run.c
|
||
|
+++ b/utils/statd/svc_run.c
|
||
|
@@ -56,6 +56,7 @@
|
||
|
#include "statd.h"
|
||
|
#include "notlist.h"
|
||
|
|
||
|
+void my_svc_exit(void);
|
||
|
static int svc_stop = 0;
|
||
|
|
||
|
/*
|