diff --git a/nfs-utils-2.2.2-rc1.patch b/nfs-utils-2.2.2-rc1.patch deleted file mode 100644 index 86a9037..0000000 --- a/nfs-utils-2.2.2-rc1.patch +++ /dev/null @@ -1,42 +0,0 @@ -diff --git a/.gitignore b/.gitignore -index 540737d..f17db9c 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -35,6 +35,7 @@ support/include/stamp-h1 - *.o - *.lo - *.la -+*.pc - .libs - lib*.a - test-driver -diff --git a/configure.ac b/configure.ac -index 9b2a502..c7651f2 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -441,6 +441,8 @@ if test -n "$path_plugins" ; then - fi - AM_CONDITIONAL(PATH_PLUGINS, test -n "$path_plugins") - -+AC_SUBST(AM_CPPFLAGS, "$AM_CPPFLAGS -I../../support/nfsidmap") -+ - dnl Check for IPv6 support - AC_IPV6 - -diff --git a/support/nfsidmap/libnfsidmap.pc b/support/nfsidmap/libnfsidmap.pc -deleted file mode 100644 -index 5ec28ae..0000000 ---- a/support/nfsidmap/libnfsidmap.pc -+++ /dev/null -@@ -1,11 +0,0 @@ --prefix=/usr --exec_prefix=${prefix} --libdir=${exec_prefix}/lib64 --includedir=${prefix}/include -- --Name: libnfsidmap --Description: Library that handles mapping between names and ids for NFSv4. --Requires: --Version: 2.1.1 --Libs: -L${exec_prefix}/lib64 -lnfsidmap --Cflags: -I${prefix}/include diff --git a/nfs-utils-2.2.2-rc2.patch b/nfs-utils-2.2.2-rc2.patch deleted file mode 100644 index 0111c1d..0000000 --- a/nfs-utils-2.2.2-rc2.patch +++ /dev/null @@ -1,713 +0,0 @@ -diff --git a/.gitignore b/.gitignore -index 540737d..f17db9c 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -35,6 +35,7 @@ support/include/stamp-h1 - *.o - *.lo - *.la -+*.pc - .libs - lib*.a - test-driver -diff --git a/configure.ac b/configure.ac -index 9b2a502..c7651f2 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -441,6 +441,8 @@ if test -n "$path_plugins" ; then - fi - AM_CONDITIONAL(PATH_PLUGINS, test -n "$path_plugins") - -+AC_SUBST(AM_CPPFLAGS, "$AM_CPPFLAGS -I../../support/nfsidmap") -+ - dnl Check for IPv6 support - AC_IPV6 - -diff --git a/support/include/conffile.h b/support/include/conffile.h -index d4cb6b4..ad20067 100644 ---- a/support/include/conffile.h -+++ b/support/include/conffile.h -@@ -60,7 +60,7 @@ extern _Bool conf_get_bool(const char *, const char *, _Bool); - extern char *conf_get_str(const char *, const char *); - extern char *conf_get_str_with_def(const char *, const char *, char *); - extern char *conf_get_section(const char *, const char *, const char *); --extern void conf_init(const char *); -+extern void conf_init_file(const char *); - extern void conf_cleanup(void); - extern int conf_match_num(const char *, const char *, int); - extern int conf_remove(int, const char *, const char *); -diff --git a/support/nfs/Makefile.am b/support/nfs/Makefile.am -index c037c46..e573b69 100644 ---- a/support/nfs/Makefile.am -+++ b/support/nfs/Makefile.am -@@ -7,10 +7,10 @@ libnfs_la_SOURCES = exports.c rmtab.c xio.c rpcmisc.c rpcdispatch.c \ - xcommon.c wildmat.c mydaemon.c \ - rpc_socket.c getport.c \ - svc_socket.c cacheio.c closeall.c nfs_mntent.c \ -- svc_create.c atomicio.c strlcpy.c strlcat.c -+ svc_create.c atomicio.c strlcat.c - libnfs_la_LIBADD = libnfsconf.la - --libnfsconf_la_SOURCES = conffile.c xlog.c -+libnfsconf_la_SOURCES = conffile.c xlog.c strlcpy.c - - MAINTAINERCLEANFILES = Makefile.in - -diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index 9c5ed8e..dce8148 100644 ---- a/support/nfs/conffile.c -+++ b/support/nfs/conffile.c -@@ -53,11 +53,9 @@ - #include "conffile.h" - #include "xlog.h" - --#pragma GCC visibility push(hidden) -- - static void conf_load_defaults(void); --static char * conf_load(const char *path); --static int conf_set(int , const char *, const char *, const char *, -+static char * conf_readfile(const char *path); -+int conf_set(int , const char *, const char *, const char *, - const char *, int , int ); - static void conf_parse(int trans, char *buf, - char **section, char **subsection); -@@ -79,12 +77,10 @@ TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue; - /* - * Radix-64 Encoding. - */ --#if 0 --static const uint8_t bin2asc[] -+const uint8_t bin2asc[] - = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; --#endif - --static const uint8_t asc2bin[] = -+const uint8_t asc2bin[] = - { - 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, -@@ -370,7 +366,7 @@ conf_parse_line(int trans, char *line, int lineno, char **section, char **subsec - - if (strcasecmp(line, "include")==0) { - /* load and parse subordinate config files */ -- char * subconf = conf_load(val); -+ char * subconf = conf_readfile(val); - if (subconf == NULL) { - xlog_warn("config file error: line %d: " - "error loading included config", lineno); -@@ -435,7 +431,7 @@ conf_load_defaults(void) - } - - static char * --conf_load(const char *path) -+conf_readfile(const char *path) - { - struct stat sb; - if ((stat (path, &sb) == 0) || (errno != ENOENT)) { -@@ -444,19 +440,19 @@ conf_load(const char *path) - int fd = open (path, O_RDONLY, 0); - - if (fd == -1) { -- xlog_warn("conf_reinit: open (\"%s\", O_RDONLY) failed", path); -+ xlog_warn("conf_readfile: open (\"%s\", O_RDONLY) failed", path); - return NULL; - } - - new_conf_addr = malloc(sz+1); - if (!new_conf_addr) { -- xlog_warn("conf_reinit: malloc (%lu) failed", (unsigned long)sz); -+ xlog_warn("conf_readfile: malloc (%lu) failed", (unsigned long)sz); - goto fail; - } - - /* XXX I assume short reads won't happen here. */ - if (read (fd, new_conf_addr, sz) != (int)sz) { -- xlog_warn("conf_reinit: read (%d, %p, %lu) failed", -+ xlog_warn("conf_readfile: read (%d, %p, %lu) failed", - fd, new_conf_addr, (unsigned long)sz); - goto fail; - } -@@ -493,15 +489,19 @@ static void conf_free_bindings(void) - } - } - -+#pragma GCC visibility push(hidden) -+/* these are the real fuinctions, hidden from being exported -+ * by libnfsidmap ABI compatability */ -+ - /* Open the config file and map it into our address space, then parse it. */ - static void --conf_reinit(const char *conf_file) -+conf_load_file(const char *conf_file) - { - int trans; - char * conf_data; - - trans = conf_begin(); -- conf_data = conf_load(conf_file); -+ conf_data = conf_readfile(conf_file); - - if (conf_data == NULL) - return; -@@ -526,7 +526,7 @@ conf_reinit(const char *conf_file) - } - - void --conf_init (const char *conf_file) -+conf_init_file(const char *conf_file) - { - unsigned int i; - -@@ -536,7 +536,7 @@ conf_init (const char *conf_file) - TAILQ_INIT (&conf_trans_queue); - - if (conf_file == NULL) conf_file=NFS_CONFFILE; -- conf_reinit(conf_file); -+ conf_load_file(conf_file); - } - - /* -@@ -560,6 +560,8 @@ conf_cleanup(void) - TAILQ_INIT(&conf_trans_queue); - } - -+#pragma GCC visibility pop -+ - /* - * Return the numeric value denoted by TAG in section SECTION or DEF - * if that tag does not exist. -@@ -575,6 +577,7 @@ conf_get_num(const char *section, const char *tag, int def) - return def; - } - -+#pragma GCC visibility push(hidden) - /* - * Return the Boolean value denoted by TAG in section SECTION, or DEF - * if that tags does not exist. -@@ -606,6 +609,7 @@ conf_get_bool(const char *section, const char *tag, _Bool def) - return false; - return def; - } -+#pragma GCC visibility pop - - /* Validate X according to the range denoted by TAG in section SECTION. */ - int -@@ -651,6 +655,7 @@ conf_get_str_with_def(const char *section, const char *tag, char *def) - return result; - } - -+#pragma GCC visibility push(hidden) - /* - * Find a section that may or may not have an argument - */ -@@ -682,6 +687,7 @@ retry: - } - return 0; - } -+#pragma GCC visibility pop - - /* - * Build a list of string values out of the comma separated value denoted by -@@ -876,7 +882,7 @@ conf_trans_node(int transaction, enum conf_op op) - } - - /* Queue a set operation. */ --static int -+int - conf_set(int transaction, const char *section, const char *arg, - const char *tag, const char *value, int override, int is_default) - { -diff --git a/support/nfsidmap/libnfsidmap.c b/support/nfsidmap/libnfsidmap.c -index 931387a..40011ee 100644 ---- a/support/nfsidmap/libnfsidmap.c -+++ b/support/nfsidmap/libnfsidmap.c -@@ -89,6 +89,10 @@ gid_t nobody_gid = (gid_t)-1; - #define NFS4DNSTXTREC "_nfsv4idmapdomain" - #endif - -+/* DEPRECATED these are for ABI compatibility only */ -+char * conf_path = PATH_IDMAPDCONF; -+void conf_reinit(void); -+void conf_init(void); - - /* Default logging fuction */ - static void default_logger(const char *fmt, ...) -@@ -342,7 +346,6 @@ int nfs4_init_name_mapping(char *conffile) - 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 */ -@@ -351,7 +354,7 @@ int nfs4_init_name_mapping(char *conffile) - conf_path = conffile; - else - conf_path = PATH_IDMAPDCONF; -- conf_init(conf_path); -+ conf_init_file(conf_path); - default_domain = conf_get_str("General", "Domain"); - if (default_domain == NULL) { - dflt = 1; -@@ -710,3 +713,13 @@ void nfs4_set_debug(int dbg_level, void (*logger)(const char *, ...)) - idmap_verbosity = dbg_level; - } - -+void conf_reinit(void) -+{ -+ conf_init_file(conf_path); -+} -+ -+void conf_init(void) -+{ -+ conf_init_file(conf_path); -+} -+ -diff --git a/support/nfsidmap/libnfsidmap.pc b/support/nfsidmap/libnfsidmap.pc -deleted file mode 100644 -index 5ec28ae..0000000 ---- a/support/nfsidmap/libnfsidmap.pc -+++ /dev/null -@@ -1,11 +0,0 @@ --prefix=/usr --exec_prefix=${prefix} --libdir=${exec_prefix}/lib64 --includedir=${prefix}/include -- --Name: libnfsidmap --Description: Library that handles mapping between names and ids for NFSv4. --Requires: --Version: 2.1.1 --Libs: -L${exec_prefix}/lib64 -lnfsidmap --Cflags: -I${prefix}/include -diff --git a/systemd/rpc-pipefs-generator.c b/systemd/rpc-pipefs-generator.c -index 59eee87..6e1d69c 100644 ---- a/systemd/rpc-pipefs-generator.c -+++ b/systemd/rpc-pipefs-generator.c -@@ -121,7 +121,7 @@ int main(int argc, char *argv[]) - exit(1); - } - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - s = conf_get_str("general", "pipefs-directory"); - if (!s) - exit(0); -diff --git a/tools/mountstats/mountstats.man b/tools/mountstats/mountstats.man -index a55130b..ff2f8ba 100644 ---- a/tools/mountstats/mountstats.man -+++ b/tools/mountstats/mountstats.man -@@ -19,6 +19,8 @@ mountstats \- Displays various NFS client per-mount statistics - .RB [ \-r | \-\-rpc ] - | - .RB [ \-R | \-\-raw ] -+| -+.RB [ \-x | \-\-xprt ] - ] - .RI [ mountpoint ] ... - .P -@@ -110,6 +112,9 @@ Display only the raw statistics. This is intended for use with the - and - .BR \-S | \-\-since - options. -+.TP -+.B \-x, \-\-xprt -+Display only the transport statistics - .SS Options specific to the iostat sub-command - .IP "\fIinterval\fP" - Specifies the amount of time in seconds between each report. The first report contains statistics for the time since each file system was mounted. Each subsequent report contains statistics collected during the interval since the previous report. This may not be used with the -diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py -old mode 100644 -new mode 100755 -index 29b5f5a..440aa72 ---- a/tools/mountstats/mountstats.py -+++ b/tools/mountstats/mountstats.py -@@ -87,7 +87,10 @@ XprtUdpCounters = [ - 'rpcreceives', - 'badxids', - 'inflightsends', -- 'backlogutil' -+ 'backlogutil', -+ 'maxslots', -+ 'sendutil', -+ 'pendutil' - ] - - XprtTcpCounters = [ -@@ -100,7 +103,10 @@ XprtTcpCounters = [ - 'rpcreceives', - 'badxids', - 'inflightsends', -- 'backlogutil' -+ 'backlogutil', -+ 'maxslots', -+ 'sendutil', -+ 'pendutil' - ] - - XprtRdmaCounters = [ -@@ -112,6 +118,7 @@ XprtRdmaCounters = [ - 'rpcsends', - 'rpcreceives', - 'badxids', -+ 'inflightsends', - 'backlogutil', - 'read_chunks', - 'write_chunks', -@@ -122,7 +129,14 @@ XprtRdmaCounters = [ - 'fixup', - 'hardway', - 'failed_marshal', -- 'bad_reply' -+ 'bad_reply', -+ 'nomsg_calls', -+ 'recovered_mrs', -+ 'orphaned_mrs', -+ 'allocated_mrs', -+ 'local_invalidates', -+ 'empty_sendctx_q', -+ 'reply_waits_for_send', - ] - - Nfsv3ops = [ -@@ -273,17 +287,20 @@ class DeviceData: - if words[1] == 'udp': - i = 2 - for key in XprtUdpCounters: -- self.__rpc_data[key] = int(words[i]) -+ if i < len(words): -+ self.__rpc_data[key] = int(words[i]) - i += 1 - elif words[1] == 'tcp': - i = 2 - for key in XprtTcpCounters: -- self.__rpc_data[key] = int(words[i]) -+ if i < len(words): -+ self.__rpc_data[key] = int(words[i]) - i += 1 - elif words[1] == 'rdma': - i = 2 - for key in XprtRdmaCounters: -- self.__rpc_data[key] = int(words[i]) -+ if i < len(words): -+ self.__rpc_data[key] = int(words[i]) - i += 1 - elif words[0] == 'per-op': - self.__rpc_data['per-op'] = words -@@ -361,12 +378,11 @@ class DeviceData: - def display_stats_header(self): - print('Stats for %s mounted on %s:' % \ - (self.__nfs_data['export'], self.__nfs_data['mountpoint'])) -+ print() - - def display_nfs_options(self): - """Pretty-print the NFS options - """ -- self.display_stats_header() -- - print(' NFS mount options: %s' % ','.join(self.__nfs_data['mountoptions'])) - print(' NFS server capabilities: %s' % ','.join(self.__nfs_data['servercapabilities'])) - if 'nfsv4flags' in self.__nfs_data: -@@ -432,7 +448,6 @@ class DeviceData: - """ - sends = self.__rpc_data['rpcsends'] - -- print() - print('RPC statistics:') - - print(' %d RPC requests sent, %d RPC replies received (%d XIDs not found)' % \ -@@ -655,6 +670,83 @@ class DeviceData: - self.__print_rpc_op_stats('WRITE', sample_time) - sys.stdout.flush() - -+ def display_xprt_stats(self): -+ """Pretty-print the xprt statistics -+ """ -+ if self.__rpc_data['protocol'] == 'udp': -+ print('\tTransport protocol: udp') -+ print('\tSource port: %d' % self.__rpc_data['port']) -+ print('\tBind count: %d' % self.__rpc_data['bind_count']) -+ print('\tRPC requests: %d' % self.__rpc_data['rpcsends']) -+ print('\tRPC replies: %d' % self.__rpc_data['rpcreceives']) -+ print('\tXIDs not found: %d' % self.__rpc_data['badxids']) -+ print('\tMax slots: %d' % self.__rpc_data['maxslots']) -+ if self.__rpc_data['rpcsends'] != 0: -+ print('\tAvg backlog length: %d' % \ -+ (float(self.__rpc_data['backlogutil']) / self.__rpc_data['rpcsends'])) -+ print('\tAvg send queue length: %d' % \ -+ (float(self.__rpc_data['sendutil']) / self.__rpc_data['rpcsends'])) -+ print('\tAvg pending queue length: %d' % \ -+ (float(self.__rpc_data['pendutil']) / self.__rpc_data['rpcsends'])) -+ elif self.__rpc_data['protocol'] == 'tcp': -+ print('\tTransport protocol: tcp') -+ print('\tSource port: %d' % self.__rpc_data['port']) -+ print('\tBind count: %d' % self.__rpc_data['bind_count']) -+ print('\tConnect count: %d' % self.__rpc_data['connect_count']) -+ print('\tConnect time: %d seconds' % self.__rpc_data['connect_time']) -+ print('\tIdle time: %d seconds' % self.__rpc_data['idle_time']) -+ print('\tRPC requests: %d' % self.__rpc_data['rpcsends']) -+ print('\tRPC replies: %d' % self.__rpc_data['rpcreceives']) -+ print('\tXIDs not found: %d' % self.__rpc_data['badxids']) -+ print('\tMax slots: %d' % self.__rpc_data['maxslots']) -+ if self.__rpc_data['rpcsends'] != 0: -+ print('\tAvg backlog length: %d' % \ -+ (float(self.__rpc_data['backlogutil']) / self.__rpc_data['rpcsends'])) -+ print('\tAvg send queue length: %d' % \ -+ (float(self.__rpc_data['sendutil']) / self.__rpc_data['rpcsends'])) -+ print('\tAvg pending queue length: %d' % \ -+ (float(self.__rpc_data['pendutil']) / self.__rpc_data['rpcsends'])) -+ elif self.__rpc_data['protocol'] == 'rdma': -+ print('\tTransport protocol: rdma') -+ print('\tConnect count: %d' % self.__rpc_data['connect_count']) -+ print('\tConnect time: %d seconds' % self.__rpc_data['connect_time']) -+ print('\tIdle time: %d seconds' % self.__rpc_data['idle_time']) -+ sends = self.__rpc_data['rpcsends'] -+ print('\tRPC requests: %d' % self.__rpc_data['rpcsends']) -+ print('\tRPC replies: %d' % self.__rpc_data['rpcreceives']) -+ print('\tXIDs not found: %d' % self.__rpc_data['badxids']) -+ if self.__rpc_data['rpcsends'] != 0: -+ print('\tAvg backlog length: %d' % \ -+ (float(self.__rpc_data['backlogutil']) / self.__rpc_data['rpcsends'])) -+ print('\tRead chunks: %d' % self.__rpc_data['read_chunks']) -+ print('\tWrite chunks: %d' % self.__rpc_data['write_chunks']) -+ print('\tReply chunks: %d' % self.__rpc_data['reply_chunks']) -+ print('\tRegistered: %d bytes' % self.__rpc_data['total_rdma_req']) -+ print('\tRDMA received: %d bytes' % self.__rpc_data['total_rdma_rep']) -+ print('\tTotal pull-up: %d bytes' % self.__rpc_data['pullup']) -+ print('\tTotal fix-up: %d bytes' % self.__rpc_data['fixup']) -+ print('\tHardway allocations: %d bytes' % self.__rpc_data['hardway']) -+ print('\tFailed marshals: %d' % self.__rpc_data['failed_marshal']) -+ print('\tBad replies: %d' % self.__rpc_data['bad_reply']) -+ -+ """ Counters not present in all kernels """ -+ if 'nomsg_calls' in self.__rpc_data: -+ print('\tRDMA_NOMSG calls: %d' % self.__rpc_data['nomsg_calls']) -+ if 'allocated_mrs' in self.__rpc_data: -+ print('\tAllocated MRs: %d' % self.__rpc_data['allocated_mrs']) -+ if 'recovered_mrs' in self.__rpc_data: -+ print('\tRecovered MRs: %d' % self.__rpc_data['recovered_mrs']) -+ if 'orphaned_mrs' in self.__rpc_data: -+ print('\tOrphaned MRs: %d' % self.__rpc_data['orphaned_mrs']) -+ if 'local_invalidates' in self.__rpc_data: -+ print('\tLocal Invalidates needed: %d' % self.__rpc_data['local_invalidates']) -+ if 'empty_sendctx_q' in self.__rpc_data: -+ print('\tEmpty sendctx queue count: %d' % self.__rpc_data['empty_sendctx_q']) -+ if 'reply_waits_for_send' in self.__rpc_data: -+ print('\tReplies that waited for Send completion: %d' % self.__rpc_data['reply_waits_for_send']) -+ else: -+ raise Exception('Unknown RPC transport protocol %s' % self.__rpc_data['protocol']) -+ - def parse_stats_file(f): - """pop the contents of a mountstats file into a dictionary, - keyed by mount point. each value object is a list of the -@@ -681,8 +773,9 @@ def parse_stats_file(f): - - return ms_dict - --def print_mountstats(stats, nfs_only, rpc_only, raw): -+def print_mountstats(stats, nfs_only, rpc_only, raw, xprt_only): - if nfs_only: -+ stats.display_stats_header() - stats.display_nfs_options() - stats.display_nfs_events() - stats.display_nfs_bytes() -@@ -692,7 +785,11 @@ def print_mountstats(stats, nfs_only, rpc_only, raw): - stats.display_rpc_op_stats() - elif raw: - stats.display_raw_stats() -+ elif xprt_only: -+ stats.display_stats_header() -+ stats.display_xprt_stats() - else: -+ stats.display_stats_header() - stats.display_nfs_options() - stats.display_nfs_bytes() - stats.display_rpc_generic_stats() -@@ -734,14 +831,14 @@ def mountstats_command(args): - stats = DeviceData() - stats.parse_stats(mountstats[mp]) - if not args.since: -- print_mountstats(stats, args.nfs_only, args.rpc_only, args.raw) -+ print_mountstats(stats, args.nfs_only, args.rpc_only, args.raw, args.xprt_only) - elif args.since and mp not in old_mountstats: -- print_mountstats(stats, args.nfs_only, args.rpc_only, args.raw) -+ print_mountstats(stats, args.nfs_only, args.rpc_only, args.raw, args.xprt_only) - else: - old_stats = DeviceData() - old_stats.parse_stats(old_mountstats[mp]) - diff_stats = stats.compare_iostats(old_stats) -- print_mountstats(diff_stats, args.nfs_only, args.rpc_only, args.raw) -+ print_mountstats(diff_stats, args.nfs_only, args.rpc_only, args.raw, args.xprt_only) - - args.infile.close() - if args.since: -@@ -953,6 +1050,8 @@ def main(): - help='Display only the RPC statistics') - group.add_argument('-R', '--raw', action='store_true', - help='Display only the raw statistics') -+ group.add_argument('-x', '--xprt', action='store_true', dest='xprt_only', -+ help='Display only the xprt statistics') - # The mountpoints argument cannot be moved into the common_parser because - # it will screw up the parsing of the iostat arguments (interval and count) - mountstats_parser.add_argument('mountpoints', nargs='*', metavar='mountpoint', -diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c -index 29bafb2..cae8c8d 100644 ---- a/utils/blkmapd/device-discovery.c -+++ b/utils/blkmapd/device-discovery.c -@@ -456,7 +456,7 @@ int main(int argc, char **argv) - char *xrpcpipe_dir = NULL; - - strncpy(rpcpipe_dir, RPCPIPE_DIR, sizeof(rpcpipe_dir)); -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - CONF_SAVE(xrpcpipe_dir, conf_get_str("general", "pipefs-directory")); - if (xrpcpipe_dir != NULL) - strlcpy(rpcpipe_dir, xrpcpipe_dir, sizeof(rpcpipe_dir)); -diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c -index beed1b3..448f195 100644 ---- a/utils/exportfs/exportfs.c -+++ b/utils/exportfs/exportfs.c -@@ -107,7 +107,7 @@ main(int argc, char **argv) - xlog_stderr(1); - xlog_syslog(0); - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - xlog_from_conffile("exportfs"); - - /* NOTE: following uses "mountd" section of nfs.conf !!!! */ -diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c -index 053a223..2c14e5f 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -842,7 +842,7 @@ read_gss_conf(void) - { - char *s; - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - use_memcache = conf_get_bool("gssd", "use-memcache", use_memcache); - root_uses_machine_creds = conf_get_bool("gssd", "use-machine-creds", - root_uses_machine_creds); -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index 4cbe148..2b9ecea 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -252,7 +252,7 @@ main(int argc, char **argv) - warn("Skipping configuration file \"%s\"", conf_path); - conf_path = NULL; - } else { -- conf_init(conf_path); -+ conf_init_file(conf_path); - verbose = conf_get_num("General", "Verbosity", 0); - cache_entry_expiration = conf_get_num("General", - "Cache-Expiration", DEFAULT_IDMAP_CACHE_EXPIRY); -@@ -264,13 +264,13 @@ main(int argc, char **argv) - } - } else { - conf_path = NFS_CONFFILE; -- conf_init(conf_path); -+ conf_init_file(conf_path); - CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory")); - if (xpipefsdir != NULL) - strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir)); - - conf_path = _PATH_IDMAPDCONF; -- conf_init(conf_path); -+ conf_init_file(conf_path); - verbose = conf_get_num("General", "Verbosity", 0); - cache_entry_expiration = conf_get_num("General", - "cache-expiration", DEFAULT_IDMAP_CACHE_EXPIRY); -diff --git a/utils/mount/mount_config.h b/utils/mount/mount_config.h -index e4f8511..7cc72fc 100644 ---- a/utils/mount/mount_config.h -+++ b/utils/mount/mount_config.h -@@ -32,7 +32,7 @@ static inline void mount_config_init(char *program) - /* - * Read the the default mount options - */ -- conf_init(MOUNTOPTS_CONFFILE); -+ conf_init_file(MOUNTOPTS_CONFFILE); - } - - static inline char *mount_config_opts(char *spec, -diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index 4401314..1217823 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -384,7 +384,9 @@ static int nfs_set_version(struct nfsmount_info *mi) - */ - static int nfs_validate_options(struct nfsmount_info *mi) - { -- if (!nfs_parse_devname(mi->spec, &mi->hostname, NULL)) -+ /* For remount, ignore mi->spec: the kernel will. */ -+ if (!(mi->flags & MS_REMOUNT) && -+ !nfs_parse_devname(mi->spec, &mi->hostname, NULL)) - return 0; - - if (!nfs_nfs_proto_family(mi->options, &mi->family)) -diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c -index 829f803..4c68702 100644 ---- a/utils/mountd/mountd.c -+++ b/utils/mountd/mountd.c -@@ -679,7 +679,7 @@ main(int argc, char **argv) - else - progname = argv[0]; - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - xlog_from_conffile("mountd"); - manage_gids = conf_get_bool("mountd", "manage-gids", manage_gids); - descriptors = conf_get_num("mountd", "descriptors", descriptors); -diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index f973203..f41a2de 100644 ---- a/utils/nfsd/nfsd.c -+++ b/utils/nfsd/nfsd.c -@@ -80,7 +80,7 @@ main(int argc, char **argv) - xlog_syslog(0); - xlog_stderr(1); - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - xlog_from_conffile("nfsd"); - count = conf_get_num("nfsd", "threads", count); - grace = conf_get_num("nfsd", "grace-time", grace); -diff --git a/utils/nfsdcltrack/nfsdcltrack.c b/utils/nfsdcltrack/nfsdcltrack.c -index 7830cf4..76b06d2 100644 ---- a/utils/nfsdcltrack/nfsdcltrack.c -+++ b/utils/nfsdcltrack/nfsdcltrack.c -@@ -564,7 +564,7 @@ main(int argc, char **argv) - xlog_syslog(1); - xlog_stderr(0); - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - xlog_from_conffile("nfsdcltrack"); - val = conf_get_str("nfsdcltrack", "storagedir"); - if (val) -diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c -index d961dc0..6d19ec1 100644 ---- a/utils/statd/sm-notify.c -+++ b/utils/statd/sm-notify.c -@@ -494,7 +494,7 @@ main(int argc, char **argv) - else - progname = argv[0]; - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - xlog_from_conffile("sm-notify"); - opt_max_retry = conf_get_num("sm-notify", "retry-time", opt_max_retry / 60) * 60; - opt_srcport = conf_get_str("sm-notify", "outgoing-port"); -diff --git a/utils/statd/statd.c b/utils/statd/statd.c -index 1443715..197d853 100644 ---- a/utils/statd/statd.c -+++ b/utils/statd/statd.c -@@ -273,7 +273,7 @@ int main (int argc, char **argv) - /* Set hostname */ - MY_NAME = NULL; - -- conf_init(NFS_CONFFILE); -+ conf_init_file(NFS_CONFFILE); - xlog_from_conffile("statd"); - out_port = conf_get_num("statd", "outgoing-port", out_port); - port = conf_get_num("statd", "port", port); diff --git a/nfs-utils-2.3.2-rc1.patch b/nfs-utils-2.3.2-rc1.patch deleted file mode 100644 index e066659..0000000 --- a/nfs-utils-2.3.2-rc1.patch +++ /dev/null @@ -1,6480 +0,0 @@ -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 -+ -+/* -+ * 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 - #endif - --#ifdef HAVE_LIBIO_H --#include --#endif -+#include - #include - #include - #include -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 -+#include -+#include -+#include -+#include -+ -+#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 -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#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 -+#include -+ -+/** -+ ** 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 -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#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 -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#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: -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * -+ * foo -+ * bar -+ * baz -+ * -+ * -1 -+ * -+ * -+ * -+ * -+ * -+ * -+ * 0 -+ * -+ * -+ * .... -+ * -+ * -+ * -+ * -+ * 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 -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#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 -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#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 -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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 - #include "xcommon.h" - #include -+#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 - #include - -+#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 - #include - -+#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 /* for isdigit */ - #include /* for umask */ - #include /* for ftruncate */ -+#include /* 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 - #include - #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 - #include - #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 -+#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 - # 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: ")); - } - -- 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 - #include - #include -+#include -+#include - - #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 - #include - #include -+#include - #include - #include - #include -@@ -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 - #include - #include -+#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..ee20d54 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; -@@ -400,15 +400,17 @@ uint64_t dm_device_create(struct bl_volume *vols, int num_vols) - } - dev = node->bv_vols[0]->param.bv_dev; - tmp = table->params; -- BL_LOG_INFO("%s: major %lu minor %lu", __func__, -- MAJOR(dev), MINOR(dev)); -+ BL_LOG_INFO("%s: major %llu minor %llu", __func__, -+ (long long unsigned)MAJOR(dev), -+ (long long unsigned)MINOR(dev)); - if (!dm_format_dev(tmp, DM_PARAMS_LEN, - MAJOR(dev), MINOR(dev))) { - free(table); - goto out; - } - tmp += strlen(tmp); -- sprintf(tmp, " %lu", node->param.bv_offset); -+ sprintf(tmp, " %llu", -+ (long long unsigned)node->param.bv_offset); - add_to_bl_dm_table(&bl_table_head, table); - break; - case BLOCK_VOLUME_STRIPE: -@@ -462,7 +464,8 @@ uint64_t dm_device_create(struct bl_volume *vols, int num_vols) - tmp = table->params; - dev = node->bv_vols[i]->param.bv_dev; - BL_LOG_INFO("%s: major %lu minor %lu", __func__, -- MAJOR(dev), MINOR(dev)); -+ (long unsigned int)MAJOR(dev), -+ (long unsigned int)MINOR(dev)); - if (!dm_format_dev(tmp, DM_PARAMS_LEN, - MAJOR(dev), MINOR(dev))) { - free(table); -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 - #include - #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 : ""); -- 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 - #include - -+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 --#include --#include -+#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 - #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 - - #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 -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#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 " -+ " [ ... ]\n\n", -+ progname); -+ -+ fprintf(stderr, "Add a new junction containing the specified list " -+ "of fileset locations.\n"); -+ fprintf(stderr, " is the filename of the new junction. " -+ " is the hostname\n"); -+ fprintf(stderr, "or IP address of an NFS server where the fileset is " -+ "located. 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 -+#include -+#include -+#include -+ -+#include -+ -+#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 \n\n", -+ progname); -+ -+ fprintf(stderr, "Display the contents of the junction at " -+ ". 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 -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#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 -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 -+#include -+#include -+#include -+ -+#include -+#include -+ -+#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 \n\n", -+ progname); -+ -+ fprintf(stderr, "Remove the junction at . 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; - - /* diff --git a/nfs-utils-2.3.3-rc1.patch b/nfs-utils-2.3.3-rc1.patch deleted file mode 100644 index b38ffe1..0000000 --- a/nfs-utils-2.3.3-rc1.patch +++ /dev/null @@ -1,444 +0,0 @@ -diff --git a/configure.ac b/configure.ac -index 276dec3..4b698dd 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -157,7 +157,7 @@ AC_ARG_WITH(rpcgen, - RPCGEN_PATH=$rpcgen_path - fi - AC_SUBST(RPCGEN_PATH) -- AM_CONDITIONAL(CONFIG_RPCGEN, [test "$RPCGEN_PATH" = ""]) -+ AM_CONDITIONAL(CONFIG_RPCGEN, [test "$RPCGEN_PATH" = "internal"]) - AC_ARG_ENABLE(uuid, - [AC_HELP_STRING([--disable-uuid], - [Exclude uuid support to avoid buggy libblkid. @<:@default=no@:>@])], -diff --git a/support/export/client.c b/support/export/client.c -index 2346f99..baf59c8 100644 ---- a/support/export/client.c -+++ b/support/export/client.c -@@ -482,8 +482,9 @@ add_name(char *old, const char *add) - else - cp = cp + strlen(cp); - } -- if (old) { -- strncpy(new, old, cp-old); -+ len = cp-old; -+ if (old && len > 0) { -+ strncpy(new, old, len); - new[cp-old] = 0; - } else { - new[0] = 0; -diff --git a/support/include/exportfs.h b/support/include/exportfs.h -index 8af47a8..4e0d9d1 100644 ---- a/support/include/exportfs.h -+++ b/support/include/exportfs.h -@@ -97,7 +97,7 @@ typedef struct mexport { - struct mclient * m_client; - struct exportent m_export; - int m_exported; /* known to knfsd. */ -- int m_xtabent : 1, /* xtab entry exists */ -+ unsigned int m_xtabent : 1, /* xtab entry exists */ - m_mayexport: 1, /* derived from xtabbed */ - m_changed : 1, /* options (may) have changed */ - m_warned : 1; /* warned about multiple exports -diff --git a/support/misc/file.c b/support/misc/file.c -index 63597df..4065376 100644 ---- a/support/misc/file.c -+++ b/support/misc/file.c -@@ -96,7 +96,7 @@ generic_setup_basedir(const char *progname, const char *parentdir, char *base, - } - - /* Ensure we have a clean directory pathname */ -- strncpy(buf, parentdir, sizeof(buf)); -+ strncpy(buf, parentdir, sizeof(buf)-1); - path = dirname(buf); - if (*path == '.') { - (void)fprintf(stderr, "%s: Unusable directory %s", -diff --git a/support/nfsidmap/umich_ldap.c b/support/nfsidmap/umich_ldap.c -index 0e31b1c..b661110 100644 ---- a/support/nfsidmap/umich_ldap.c -+++ b/support/nfsidmap/umich_ldap.c -@@ -1125,9 +1125,9 @@ umichldap_init(void) - - /* Verify required information is supplied */ - if (server_in == NULL || strlen(server_in) == 0) -- strncat(missing_msg, "LDAP_server ", sizeof(missing_msg)); -+ strncat(missing_msg, "LDAP_server ", sizeof(missing_msg)-1); - if (ldap_info.base == NULL || strlen(ldap_info.base) == 0) -- strncat(missing_msg, "LDAP_base ", sizeof(missing_msg)); -+ strncat(missing_msg, "LDAP_base ", sizeof(missing_msg)-1); - if (strlen(missing_msg) != 0) { - IDMAP_LOG(0, ("umichldap_init: Missing required information: " - "%s", missing_msg)); -diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c -index 2c14e5f..7b21ee2 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -279,16 +279,16 @@ gssd_read_service_info(int dirfd, struct clnt_info *clp) - * (commit bf19aacecbeebccb2c3d150a8bd9416b7dba81fe) - */ - numfields = fscanf(info, -- "RPC server: %ms\n" -- "service: %ms (%d) version %d\n" -- "address: %ms\n" -- "protocol: %ms\n" -- "port: %ms\n", -- &server, -- &service, &program, &version, -- &address, -- &protoname, -- &port); -+ "RPC server: %s\n" -+ "service: %s (%d) version %d\n" -+ "address: %s\n" -+ "protocol: %s\n" -+ "port: %s\n", -+ (char *)&server, -+ (char *)&service, &program, &version, -+ (char *)&address, -+ (char *)&protoname, -+ (char *)&port); - - - switch (numfields) { -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index ce73777..8767e26 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -520,8 +520,9 @@ out: - } - - static AUTH * --krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, -- char *service, CLIENT **rpc_clnt) -+krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, -+ char *srchost, char *tgtname, char *service, -+ CLIENT **rpc_clnt) - { - AUTH *auth = NULL; - char **credlist = NULL; -@@ -534,7 +535,7 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - - do { - gssd_refresh_krb5_machine_credential(clp->servername, NULL, -- service); -+ service, srchost); - /* - * Get a list of credential cache names and try each - * of them until one works or we've tried them all -@@ -594,8 +595,8 @@ out: - * context on behalf of the kernel - */ - static void --process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, -- char *service) -+process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *srchost, -+ char *tgtname, char *service) - { - CLIENT *rpc_clnt = NULL; - AUTH *auth = NULL; -@@ -643,7 +644,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - if (auth == NULL) { - if (uid == 0 && (root_uses_machine_creds == 1 || - service != NULL)) { -- auth = krb5_use_machine_creds(clp, uid, tgtname, -+ auth = krb5_use_machine_creds(clp, uid, srchost, tgtname, - service, &rpc_clnt); - if (auth == NULL) - goto out_return_error; -@@ -714,7 +715,7 @@ handle_krb5_upcall(struct clnt_upcall_info *info) - - printerr(2, "\n%s: uid %d (%s)\n", __func__, info->uid, clp->relpath); - -- process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL); -+ process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL, NULL); - free(info); - } - -@@ -728,11 +729,12 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - char *uidstr = NULL; - char *target = NULL; - char *service = NULL; -+ char *srchost = NULL; - char *enctypes = NULL; - char *upcall_str; - char *pbuf = info->lbuf; - -- printerr(2, "\n%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath); -+ printerr(2, "%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath); - - upcall_str = strdup(info->lbuf); - if (upcall_str == NULL) { -@@ -751,6 +753,8 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - target = p + strlen("target="); - else if (!strncmp(p, "service=", strlen("service="))) - service = p + strlen("service="); -+ else if (!strncmp(p, "srchost=", strlen("srchost="))) -+ srchost = p + strlen("srchost="); - } - - if (!mech || strlen(mech) < 1) { -@@ -802,7 +806,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - } - - if (strcmp(mech, "krb5") == 0 && clp->servername) -- process_krb5_upcall(clp, uid, clp->gssd_fd, target, service); -+ process_krb5_upcall(clp, uid, clp->gssd_fd, srchost, target, service); - else { - if (clp->servername) - printerr(0, "WARNING: handle_gssd_upcall: " -@@ -815,4 +819,3 @@ out_nomem: - free(info); - return; - } -- -diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c -index b342b06..eba1aac 100644 ---- a/utils/gssd/krb5_util.c -+++ b/utils/gssd/krb5_util.c -@@ -757,7 +757,8 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, - * the server hostname. - */ - static int --find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, -+find_keytab_entry(krb5_context context, krb5_keytab kt, -+ const char *srchost, const char *tgtname, - krb5_keytab_entry *kte, const char **svcnames) - { - krb5_error_code code; -@@ -781,7 +782,9 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - goto out; - - /* Get full local hostname */ -- if (gethostname(myhostname, sizeof(myhostname)) == -1) { -+ if (srchost) { -+ strcpy(myhostname, srchost); -+ } else if (gethostname(myhostname, sizeof(myhostname)) == -1) { - retval = errno; - k5err = gssd_k5_err_msg(context, retval); - printerr(1, "%s while getting local hostname\n", k5err); -@@ -807,10 +810,12 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - myhostad[i+1] = 0; - } - -- retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); -- if (retval) { -- /* Don't use myhostname */ -- myhostname[0] = 0; -+ if (!srchost) { -+ retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); -+ if (retval) { -+ /* Don't use myhostname */ -+ myhostname[0] = 0; -+ } - } - - code = krb5_get_default_realm(context, &default_realm); -@@ -1140,7 +1145,7 @@ gssd_get_krb5_machine_cred_list(char ***list) - if (ple->ccname) { - /* Make sure cred is up-to-date before returning it */ - retval = gssd_refresh_krb5_machine_credential(NULL, ple, -- NULL); -+ NULL, NULL); - if (retval) - continue; - if (i + 1 > listsize) { -@@ -1231,7 +1236,7 @@ gssd_destroy_krb5_machine_creds(void) - int - gssd_refresh_krb5_machine_credential(char *hostname, - struct gssd_k5_kt_princ *ple, -- char *service) -+ char *service, char *srchost) - { - krb5_error_code code = 0; - krb5_context context; -@@ -1240,6 +1245,9 @@ gssd_refresh_krb5_machine_credential(char *hostname, - char *k5err = NULL; - const char *svcnames[] = { "$", "root", "nfs", "host", NULL }; - -+ printerr(2, "%s: hostname=%s ple=%p service=%s srchost=%s\n", -+ __func__, hostname, ple, service, srchost); -+ - /* - * If a specific service name was specified, use it. - * Otherwise, use the default list. -@@ -1270,7 +1278,8 @@ gssd_refresh_krb5_machine_credential(char *hostname, - if (ple == NULL) { - krb5_keytab_entry kte; - -- code = find_keytab_entry(context, kt, hostname, &kte, svcnames); -+ code = find_keytab_entry(context, kt, srchost, hostname, -+ &kte, svcnames); - if (code) { - printerr(0, "ERROR: %s: no usable keytab entry found " - "in keytab %s for connection with host %s\n", -diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h -index e3bbb07..b000b44 100644 ---- a/utils/gssd/krb5_util.h -+++ b/utils/gssd/krb5_util.h -@@ -30,7 +30,7 @@ void gssd_free_krb5_machine_cred_list(char **list); - void gssd_destroy_krb5_machine_creds(void); - int gssd_refresh_krb5_machine_credential(char *hostname, - struct gssd_k5_kt_princ *ple, -- char *service); -+ char *service, char *srchost); - char *gssd_k5_err_msg(krb5_context context, krb5_error_code code); - void gssd_k5_get_default_realm(char **def_realm); - -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index b87c4dd..4811e0f 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -310,7 +310,7 @@ main(int argc, char **argv) - if (!serverstart && !clientstart) - errx(1, "it is illegal to specify both -C and -S"); - -- strncat(pipefsdir, "/nfs", sizeof(pipefsdir)); -+ strncat(pipefsdir, "/nfs", sizeof(pipefsdir)-1); - - daemon_init(fg); - -@@ -923,7 +923,8 @@ static int - getfield(char **bpp, char *fld, size_t fldsz) - { - char *bp; -- int val, n; -+ unsigned int val; -+ int n; - - while ((bp = strsep(bpp, " ")) != NULL && bp[0] == '\0') - ; -diff --git a/utils/mount/nfs4mount.c b/utils/mount/nfs4mount.c -index 89629ed..3e4f1e2 100644 ---- a/utils/mount/nfs4mount.c -+++ b/utils/mount/nfs4mount.c -@@ -218,7 +218,7 @@ int nfs4mount(const char *spec, const char *node, int flags, - goto fail; - } - if (running_bg) -- strncpy(new_opts, old_opts, sizeof(new_opts)); -+ strncpy(new_opts, old_opts, sizeof(new_opts)-1); - else - snprintf(new_opts, sizeof(new_opts), "%s%saddr=%s", - old_opts, *old_opts ? "," : "", s); -diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c -index ae4a3da..952a755 100644 ---- a/utils/mount/nfsmount.c -+++ b/utils/mount/nfsmount.c -@@ -828,7 +828,7 @@ noauth_flavors: - - data.fd = fsock; - memcpy((char *) &data.addr, (char *) nfs_saddr, sizeof(data.addr)); -- strncpy(data.hostname, hostname, sizeof(data.hostname)); -+ strncpy(data.hostname, hostname, sizeof(data.hostname)-1); - - out_ok: - /* Ensure we have enough padding for the following strcat()s */ -diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c -index 4c68702..086c39b 100644 ---- a/utils/mountd/mountd.c -+++ b/utils/mountd/mountd.c -@@ -702,7 +702,7 @@ main(int argc, char **argv) - else - NFSCTL_TCPUNSET(_rpcprotobits); - for (vers = 2; vers <= 4; vers++) { -- char tag[10]; -+ char tag[20]; - sprintf(tag, "vers%d", vers); - if (conf_get_bool("nfsd", tag, NFSCTL_VERISSET(nfs_version, vers))) - NFSCTL_VERSET(nfs_version, vers); -diff --git a/utils/mountd/v4root.c b/utils/mountd/v4root.c -index f978f4c..d735dbf 100644 ---- a/utils/mountd/v4root.c -+++ b/utils/mountd/v4root.c -@@ -92,7 +92,7 @@ v4root_create(char *path, nfs_export *export) - - dupexportent(&eep, &pseudo_root.m_export); - eep.e_hostname = curexp->e_hostname; -- strncpy(eep.e_path, path, sizeof(eep.e_path)); -+ strncpy(eep.e_path, path, sizeof(eep.e_path)-1); - if (strcmp(path, "/") != 0) - eep.e_flags &= ~NFSEXP_FSID; - set_pseudofs_security(&eep, curexp->e_flags); -diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index 2303a5d..f048631 100644 ---- a/utils/nfsd/nfsd.c -+++ b/utils/nfsd/nfsd.c -@@ -98,7 +98,7 @@ main(int argc, char **argv) - else - NFSCTL_TCPUNSET(protobits); - for (i = 2; i <= 4; i++) { -- char tag[10]; -+ char tag[20]; - sprintf(tag, "vers%d", i); - if (conf_get_bool("nfsd", tag, NFSCTL_VERISSET(versbits, i))) - NFSCTL_VERSET(versbits, i); -diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c -index 374bc5d..d3967a3 100644 ---- a/utils/nfsidmap/nfsidmap.c -+++ b/utils/nfsidmap/nfsidmap.c -@@ -283,7 +283,7 @@ static int key_invalidate(char *keystr, int keymask) - { - FILE *fp; - char buf[BUFSIZ], *ptr; -- key_serial_t key; -+ unsigned int key; - int mask; - - xlog_syslog(0); -diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c -index c779053..8fccea7 100644 ---- a/utils/nfsstat/nfsstat.c -+++ b/utils/nfsstat/nfsstat.c -@@ -1013,7 +1013,7 @@ mounts(const char *name) - * be a fatal error -- it usually means the module isn't loaded. - */ - if ((fp = fopen(name, "r")) == NULL) { -- fprintf(stderr, "Warning: %s: %m\n", name); -+ fprintf(stderr, "Warning: %s: %s\n", name, strerror(errno)); - return 0; - } - -@@ -1089,8 +1089,8 @@ out: - fclose(fp); - if (err) { - if (!other_opt) { -- fprintf(stderr, "Error: No %s Stats (%s: %m). \n", -- label, file); -+ fprintf(stderr, "Error: No %s Stats (%s: %s). \n", -+ label, file, strerror(errno)); - exit(2); - } - *opt = 0; -diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c -index 6d19ec1..7a48473 100644 ---- a/utils/statd/sm-notify.c -+++ b/utils/statd/sm-notify.c -@@ -569,7 +569,7 @@ usage: fprintf(stderr, - if (name == NULL) - exit(1); - -- strncpy(nsm_hostname, name, sizeof(nsm_hostname)); -+ strncpy(nsm_hostname, name, sizeof(nsm_hostname)-1); - free(name); - } - -diff --git a/utils/statd/statd.c b/utils/statd/statd.c -index 563a272..2cc6cf3 100644 ---- a/utils/statd/statd.c -+++ b/utils/statd/statd.c -@@ -231,11 +231,12 @@ static void set_nlm_port(char *type, int port) - } - if (fd >= 0) { - if (write(fd, nbuf, strlen(nbuf)) != (ssize_t)strlen(nbuf)) -- fprintf(stderr, "%s: fail to set NLM %s port: %m\n", -- name_p, type); -+ fprintf(stderr, "%s: fail to set NLM %s port: %s\n", -+ name_p, type, strerror(errno)); - close(fd); - } else -- fprintf(stderr, "%s: failed to open %s: %m\n", name_p, pathbuf); -+ fprintf(stderr, "%s: failed to open %s: %s\n", -+ name_p, pathbuf, strerror(errno)); - } - - /* diff --git a/nfs-utils-2.3.3-rc2.patch b/nfs-utils-2.3.3-rc2.patch deleted file mode 100644 index 359f03b..0000000 --- a/nfs-utils-2.3.3-rc2.patch +++ /dev/null @@ -1,1602 +0,0 @@ -diff --git a/configure.ac b/configure.ac -index 276dec3..4b698dd 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -157,7 +157,7 @@ AC_ARG_WITH(rpcgen, - RPCGEN_PATH=$rpcgen_path - fi - AC_SUBST(RPCGEN_PATH) -- AM_CONDITIONAL(CONFIG_RPCGEN, [test "$RPCGEN_PATH" = ""]) -+ AM_CONDITIONAL(CONFIG_RPCGEN, [test "$RPCGEN_PATH" = "internal"]) - AC_ARG_ENABLE(uuid, - [AC_HELP_STRING([--disable-uuid], - [Exclude uuid support to avoid buggy libblkid. @<:@default=no@:>@])], -diff --git a/support/export/client.c b/support/export/client.c -index 2346f99..baf59c8 100644 ---- a/support/export/client.c -+++ b/support/export/client.c -@@ -482,8 +482,9 @@ add_name(char *old, const char *add) - else - cp = cp + strlen(cp); - } -- if (old) { -- strncpy(new, old, cp-old); -+ len = cp-old; -+ if (old && len > 0) { -+ strncpy(new, old, len); - new[cp-old] = 0; - } else { - new[0] = 0; -diff --git a/support/include/conffile.h b/support/include/conffile.h -index bc2d61f..a3340f9 100644 ---- a/support/include/conffile.h -+++ b/support/include/conffile.h -@@ -67,6 +67,7 @@ extern int conf_match_num(const char *, const char *, int); - extern int conf_remove(int, const char *, const char *); - extern int conf_remove_section(int, const char *); - extern void conf_report(FILE *); -+extern int conf_write(const char *, const char *, const char *, const char *, const char *); - - /* - * Convert letter from upper case to lower case -diff --git a/support/include/exportfs.h b/support/include/exportfs.h -index 8af47a8..4e0d9d1 100644 ---- a/support/include/exportfs.h -+++ b/support/include/exportfs.h -@@ -97,7 +97,7 @@ typedef struct mexport { - struct mclient * m_client; - struct exportent m_export; - int m_exported; /* known to knfsd. */ -- int m_xtabent : 1, /* xtab entry exists */ -+ unsigned int m_xtabent : 1, /* xtab entry exists */ - m_mayexport: 1, /* derived from xtabbed */ - m_changed : 1, /* options (may) have changed */ - m_warned : 1; /* warned about multiple exports -diff --git a/support/junction/path.c b/support/junction/path.c -index 68a1d13..e74e4c4 100644 ---- a/support/junction/path.c -+++ b/support/junction/path.c -@@ -326,8 +326,10 @@ nsdb_posix_to_path_array(const char *pathname, char ***path_array) - break; - next = strchrnul(component, '/'); - length = (size_t)(next - component); -- if (length > 255) -+ if (length > 255) { -+ nsdb_free_string_array(result); - return FEDFS_ERR_SVRFAULT; -+ } - - result[i] = strndup(component, length); - if (result[i] == NULL) { -diff --git a/support/misc/file.c b/support/misc/file.c -index 63597df..4065376 100644 ---- a/support/misc/file.c -+++ b/support/misc/file.c -@@ -96,7 +96,7 @@ generic_setup_basedir(const char *progname, const char *parentdir, char *base, - } - - /* Ensure we have a clean directory pathname */ -- strncpy(buf, parentdir, sizeof(buf)); -+ strncpy(buf, parentdir, sizeof(buf)-1); - path = dirname(buf); - if (*path == '.') { - (void)fprintf(stderr, "%s: Unusable directory %s", -diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index ee94031..3845b94 100644 ---- a/support/nfs/conffile.c -+++ b/support/nfs/conffile.c -@@ -255,14 +255,14 @@ conf_parse_line(int trans, char *line, const char *filename, int lineno, char ** - char *inc_section = NULL, *inc_subsection = NULL; - char *relpath, *subconf; - -+ /* Strip off any leading blanks */ -+ while (isspace(*line)) -+ line++; -+ - /* Ignore blank lines */ - if (*line == '\0') - return; - -- /* Strip off any leading blanks */ -- while (isblank(*line)) -- line++; -- - /* Lines starting with '#' or ';' are comments. */ - if (*line == '#' || *line == ';') - return; -@@ -495,7 +495,7 @@ conf_readfile(const char *path) - { - struct stat sb; - if (!path) { -- xlog_err("conf_readfile: no path given"); -+ xlog(L_ERROR, "conf_readfile: no path given"); - return NULL; - } - -@@ -640,7 +640,7 @@ conf_get_num(const char *section, const char *tag, int def) - /* - * Return the Boolean value denoted by TAG in section SECTION, or DEF - * if that tags does not exist. -- * FALSE is returned for case-insensitve comparisons with 0, f, false, n, no, off -+ * FALSE is returned for case-insensitive comparisons with 0, f, false, n, no, off - * TRUE is returned for 1, t, true, y, yes, on - * A failure to match one of these results in DEF - */ -@@ -727,6 +727,8 @@ retry: - continue; - if (arg && (cb->arg == NULL || strcasecmp(arg, cb->arg) != 0)) - continue; -+ if (!arg && cb->arg) -+ continue; - if (strcasecmp(tag, cb->tag) != 0) - continue; - if (cb->value[0] == '$') { -@@ -1321,3 +1323,624 @@ cleanup: - } - return; - } -+ -+/* struct and queue for buffing output lines */ -+TAILQ_HEAD(tailhead, outbuffer); -+ -+struct outbuffer { -+ TAILQ_ENTRY(outbuffer) link; -+ char *text; -+}; -+ -+static struct outbuffer * -+make_outbuffer(char *line) -+{ -+ struct outbuffer *new; -+ -+ if (line == NULL) -+ return NULL; -+ -+ new = calloc(1, sizeof(struct outbuffer)); -+ if (new == NULL) { -+ xlog(L_ERROR, "malloc error creating outbuffer"); -+ return NULL; -+ } -+ new->text = line; -+ return new; -+} -+ -+/* compose a properly escaped tag=value line */ -+static char * -+make_tagline(const char *tag, const char *value) -+{ -+ char *line; -+ int ret; -+ -+ if (!value) -+ return NULL; -+ -+ if (should_escape(value)) -+ ret = asprintf(&line, "%s = \"%s\"\n", tag, value); -+ else -+ ret = asprintf(&line, "%s = %s\n", tag, value); -+ -+ if (ret == -1) { -+ xlog(L_ERROR, "malloc error composing a tag line"); -+ return NULL; -+ } -+ return line; -+} -+ -+/* compose a section header line */ -+static char * -+make_section(const char *section, const char *arg) -+{ -+ char *line; -+ int ret; -+ -+ if (arg) -+ ret = asprintf(&line, "[%s \"%s\"]\n", section, arg); -+ else -+ ret = asprintf(&line, "[%s]\n", section); -+ -+ if (ret == -1) { -+ xlog(L_ERROR, "malloc error composing section header"); -+ return NULL; -+ } -+ return line; -+} -+ -+/* does the supplied line contain the named section header */ -+static bool -+is_section(const char *line, const char *section, const char *arg) -+{ -+ char *end; -+ char *name; -+ char *sub; -+ bool found = false; -+ -+ /* skip leading white space */ -+ while (*line == '[' || isspace(*line)) -+ line++; -+ -+ name = strdup(line); -+ if (name == NULL) { -+ xlog_warn("conf_write: malloc failed "); -+ return false; -+ } -+ -+ /* find the end */ -+ end = strchr(name, ']'); -+ -+ /* malformed line */ -+ if (end == NULL) { -+ xlog_warn("conf_write: warning: malformed section name"); -+ goto cleanup; -+ } -+ -+ while (*end && ( *end == ']' || isblank(*end))) -+ *(end--) = '\0'; -+ -+ /* is there a subsection name (aka arg) */ -+ sub = strchr(name, '"'); -+ if (sub) { -+ end = sub - 1; -+ *(sub++) = '\0'; -+ -+ /* trim whitespace between section name and arg */ -+ while (end > name && isblank(*end)) -+ *(end--) = '\0'; -+ -+ /* trim off closing quote */ -+ end = strchr(sub, '"'); -+ if (end == NULL) { -+ xlog_warn("conf_write: warning: malformed sub-section name"); -+ goto cleanup; -+ } -+ *end = '\0'; -+ } -+ -+ /* ready to compare */ -+ if (strcasecmp(section, name)!=0) -+ goto cleanup; -+ -+ if (arg != NULL) { -+ if (sub == NULL || strcasecmp(arg, sub)!=0) -+ goto cleanup; -+ } else { -+ if (sub != NULL) -+ goto cleanup; -+ } -+ -+ found = true; -+ -+cleanup: -+ free(name); -+ return found; -+} -+ -+/* check that line contains the specified tag assignment */ -+static bool -+is_tag(const char *line, const char *tagname) -+{ -+ char *end; -+ char *name; -+ bool found = false; -+ -+ /* quick check, is this even an assignment line */ -+ end = strchr(line, '='); -+ if (end == NULL) -+ return false; -+ -+ /* skip leading white space before tag name */ -+ while (isblank(*line)) -+ line++; -+ -+ name = strdup(line); -+ if (name == NULL) { -+ xlog_warn("conf_write: malloc failed"); -+ return false; -+ } -+ -+ /* trim any newline characters */ -+ end = strchr(name, '\n'); -+ if (end) -+ *end = '\0'; -+ end = strchr(name, '\r'); -+ if (end) -+ *end = '\0'; -+ -+ /* find the assignment equals sign */ -+ end = strchr(name, '='); -+ -+ /* malformed line, i swear the equals was there earlier */ -+ if (end == NULL) { -+ xlog_warn("conf_write: warning: malformed tag name"); -+ goto cleanup; -+ } -+ -+ /* trim trailing whitespace after tag name */ -+ do { -+ *(end--) = '\0'; -+ }while (end > name && *end && isblank(*end)); -+ -+ /* quoted string, take contents of quotes only */ -+ if (*name == '"') { -+ char * new = strdup(name+1); -+ end = strchr(new, '"'); -+ if (end != NULL) { -+ *end = 0; -+ free(name); -+ name = new; -+ } else { -+ free(new); -+ } -+ } -+ -+ /* now compare */ -+ if (strcasecmp(tagname, name) == 0) -+ found = true; -+ -+cleanup: -+ free(name); -+ return found; -+} -+ -+/* is this an empty line ? */ -+static bool -+is_empty(const char *line) -+{ -+ const char *p = line; -+ -+ if (line == NULL) -+ return true; -+ if (*line == '\0') -+ return true; -+ -+ while (*p != '\0' && isspace(*p)) -+ p++; -+ -+ if (*p == '\0') -+ return true; -+ -+ return false; -+} -+ -+/* is this line just a comment ? */ -+static bool -+is_comment(const char *line) -+{ -+ if (line == NULL) -+ return false; -+ -+ while (isblank(*line)) -+ line++; -+ -+ if (*line == '#') -+ return true; -+ -+ return false; -+} -+ -+/* delete a buffer queue whilst optionally outputting to file */ -+static int -+flush_outqueue(struct tailhead *queue, FILE *fout) -+{ -+ int ret = 0; -+ while (queue->tqh_first != NULL) { -+ struct outbuffer *ob = queue->tqh_first; -+ TAILQ_REMOVE(queue, ob, link); -+ if (ob->text) { -+ if (fout) { -+ ret = fprintf(fout, "%s", ob->text); -+ if (ret == -1) { -+ xlog(L_ERROR, "Error writing to config file: %s", -+ strerror(errno)); -+ fout = NULL; -+ } -+ } -+ free(ob->text); -+ } -+ free(ob); -+ } -+ if (ret == -1) -+ return 1; -+ return 0; -+} -+ -+/* read one line of text from a file, growing the buffer as necessary */ -+static int -+read_line(char **buff, int *buffsize, FILE *in) -+{ -+ char *readp; -+ int used = 0; -+ bool again = false; -+ -+ /* make sure we have a buffer to read into */ -+ if (*buff == NULL) { -+ *buffsize = 4096; -+ *buff = calloc(1, *buffsize); -+ if (*buff == NULL) { -+ xlog(L_ERROR, "malloc error for read buffer"); -+ return -1; -+ } -+ } -+ -+ readp = *buff; -+ -+ do { -+ int len; -+ -+ /* read in a chunk */ -+ if (fgets(readp, *buffsize-used, in)==NULL) -+ return -1; -+ -+ len = strlen(*buff); -+ if (len == 0) -+ return -1; -+ -+ /* was this the end of a line, or partial read */ -+ readp = *buff + len - 1; -+ -+ if (*readp != '\n' && *readp !='\r') { -+ /* no nl/cr must be partial read, go again */ -+ readp++; -+ again = true; -+ } else { -+ /* that was a normal end of line */ -+ again = false; -+ } -+ -+ /* do we need more space */ -+ if (again && *buffsize - len < 1024) { -+ int offset = readp - *buff; -+ char *newbuff; -+ *buffsize += 4096; -+ newbuff = realloc(*buff, *buffsize); -+ if (newbuff == NULL) { -+ xlog(L_ERROR, "malloc error reading line"); -+ return -1; -+ } -+ *buff = newbuff; -+ readp = newbuff + offset; -+ } -+ } while(again); -+ return 0; -+} -+ -+/* append a line to the given location in the queue */ -+static int -+append_line(struct tailhead *queue, struct outbuffer *entry, char *line) -+{ -+ int ret = 0; -+ char *end; -+ bool splitmode = false; -+ char *start = line; -+ -+ if (line == NULL) -+ return -1; -+ -+ /* if there are \n's in the middle of the string -+ * then we need to split it into folded lines */ -+ do { -+ char *thisline; -+ struct outbuffer *qbuff; -+ -+ end = strchr(start, '\n'); -+ if (end && *(end+1) != '\0') { -+ *end = '\0'; -+ -+ ret = asprintf(&thisline, "%s\\\n", start); -+ if (ret == -1) { -+ xlog(L_ERROR, "malloc error composing output"); -+ return -1; -+ } -+ splitmode = true; -+ start = end+1; -+ } else { -+ end = NULL; -+ if (splitmode) { -+ thisline = strdup(start); -+ if (thisline == NULL) -+ return -1; -+ } else { -+ thisline = start; -+ } -+ } -+ -+ qbuff = make_outbuffer(thisline); -+ if (qbuff == NULL) -+ return -1; -+ -+ if (entry) { -+ TAILQ_INSERT_AFTER(queue, entry, qbuff, link); -+ entry = TAILQ_NEXT(entry, link); -+ } else { -+ TAILQ_INSERT_TAIL(queue, qbuff, link); -+ } -+ }while (end != NULL); -+ -+ /* we malloced copies of this, so free the original */ -+ if (splitmode) -+ free(line); -+ -+ return 0; -+} -+ -+/* is this a "folded" line, i.e. ends in backslash */ -+static bool -+is_folded(const char *line) -+{ -+ const char *end; -+ if (line == NULL) -+ return false; -+ -+ end = line + strlen(line); -+ while (end > line) { -+ end--; -+ if (*end != '\n' && *end != '\r') -+ break; -+ } -+ -+ if (*end == '\\') -+ return true; -+ -+ return false; -+} -+ -+/*** -+ * Write a value to an nfs.conf style filename -+ * -+ * create the file if it doesnt already exist -+ * if value==NULL removes the setting (if present) -+ */ -+int -+conf_write(const char *filename, const char *section, const char *arg, -+ const char *tag, const char *value) -+{ -+ int fdout = -1; -+ char *outpath = NULL; -+ FILE *outfile = NULL; -+ FILE *infile = NULL; -+ int ret = 1; -+ struct tailhead outqueue; -+ char * buff = NULL; -+ int buffsize = 0; -+ -+ TAILQ_INIT(&outqueue); -+ -+ if (!filename) { -+ xlog_warn("conf_write: no filename supplied"); -+ return ret; -+ } -+ -+ if (!section || !tag) { -+ xlog_warn("conf_write: section or tag name missing"); -+ return ret; -+ } -+ -+ if (asprintf(&outpath, "%s.XXXXXX", filename) == -1) { -+ xlog(L_ERROR, "conf_write: error composing temp filename"); -+ return ret; -+ } -+ -+ fdout = mkstemp(outpath); -+ if (fdout < 0) { -+ xlog(L_ERROR, "conf_write: open temp file %s failed: %s", -+ outpath, strerror(errno)); -+ goto cleanup; -+ } -+ -+ outfile = fdopen(fdout, "w"); -+ if (!outfile) { -+ xlog(L_ERROR, "conf_write: fdopen temp file failed: %s", -+ strerror(errno)); -+ goto cleanup; -+ } -+ -+ infile = fopen(filename, "r"); -+ if (!infile) { -+ if (!value) { -+ xlog_warn("conf_write: config file \"%s\" not found, nothing to do", filename); -+ ret = 0; -+ goto cleanup; -+ } -+ -+ xlog_warn("conf_write: config file \"%s\" not found, creating.", filename); -+ if (append_line(&outqueue, NULL, make_section(section, arg))) -+ goto cleanup; -+ -+ if (append_line(&outqueue, NULL, make_tagline(tag, value))) -+ goto cleanup; -+ -+ if (flush_outqueue(&outqueue, outfile)) -+ goto cleanup; -+ } else { -+ bool found = false; -+ int err = 0; -+ -+ buffsize = 4096; -+ buff = calloc(1, buffsize); -+ if (buff == NULL) { -+ xlog(L_ERROR, "malloc error for read buffer"); -+ goto cleanup; -+ } -+ -+ buff[0] = '\0'; -+ do { -+ struct outbuffer *where = NULL; -+ -+ /* read in one section worth of lines */ -+ do { -+ if (*buff != '\0') { -+ if (append_line(&outqueue, NULL, strdup(buff))) -+ goto cleanup; -+ } -+ -+ err = read_line(&buff, &buffsize, infile); -+ } while (err == 0 && buff[0] != '['); -+ -+ /* find the section header */ -+ where = TAILQ_FIRST(&outqueue); -+ while (where != NULL) { -+ if (where->text != NULL && where->text[0] == '[') -+ break; -+ where = TAILQ_NEXT(where, link); -+ } -+ -+ /* this is the section we care about */ -+ if (where != NULL && is_section(where->text, section, arg)) { -+ /* is there an existing assignment */ -+ while ((where = TAILQ_NEXT(where, link)) != NULL) { -+ if (is_tag(where->text, tag)) { -+ found = true; -+ break; -+ } -+ } -+ -+ if (found) { -+ struct outbuffer *prev = TAILQ_PREV(where, tailhead, link); -+ bool again = false; -+ -+ /* remove current tag */ -+ do { -+ struct outbuffer *next = TAILQ_NEXT(where, link); -+ TAILQ_REMOVE(&outqueue, where, link); -+ if (is_folded(where->text)) -+ again = true; -+ else -+ again = false; -+ free(where->text); -+ free(where); -+ where = next; -+ } while(again && where != NULL); -+ -+ /* insert new tag */ -+ if (value) { -+ if (append_line(&outqueue, prev, make_tagline(tag, value))) -+ goto cleanup; -+ } -+ } else -+ /* no existing assignment found and we need to add one */ -+ if (value) { -+ /* rewind past blank lines and comments */ -+ struct outbuffer *tail = TAILQ_LAST(&outqueue, tailhead); -+ -+ /* comments immediately before a section usually relate -+ * to the section below them */ -+ while (tail != NULL && is_comment(tail->text)) -+ tail = TAILQ_PREV(tail, tailhead, link); -+ -+ /* there is usually blank line(s) between sections */ -+ while (tail != NULL && is_empty(tail->text)) -+ tail = TAILQ_PREV(tail, tailhead, link); -+ -+ /* now add the tag here */ -+ if (append_line(&outqueue, tail, make_tagline(tag, value))) -+ goto cleanup; -+ -+ found = true; -+ } -+ } -+ -+ /* EOF and correct section not found, so add one */ -+ if (err && !found && value) { -+ /* did the last section end in a blank line */ -+ struct outbuffer *tail = TAILQ_LAST(&outqueue, tailhead); -+ if (tail && !is_empty(tail->text)) { -+ /* no, so add one for clarity */ -+ if (append_line(&outqueue, NULL, strdup("\n"))) -+ goto cleanup; -+ } -+ -+ /* add the new section header */ -+ if (append_line(&outqueue, NULL, make_section(section, arg))) -+ goto cleanup; -+ -+ /* now add the tag */ -+ if (append_line(&outqueue, NULL, make_tagline(tag, value))) -+ goto cleanup; -+ } -+ -+ /* we are done with this section, write it out */ -+ if (flush_outqueue(&outqueue, outfile)) -+ goto cleanup; -+ } while(err == 0); -+ } -+ -+ if (infile) { -+ fclose(infile); -+ infile = NULL; -+ } -+ -+ fdout = -1; -+ if (fclose(outfile)) { -+ xlog(L_ERROR, "Error writing config file: %s", strerror(errno)); -+ goto cleanup; -+ } -+ -+ /* now swap the old file for the new one */ -+ if (rename(outpath, filename)) { -+ xlog(L_ERROR, "Error updating config file: %s: %s\n", filename, strerror(errno)); -+ ret = 1; -+ } else { -+ ret = 0; -+ free(outpath); -+ outpath = NULL; -+ } -+ -+cleanup: -+ flush_outqueue(&outqueue, NULL); -+ -+ if (buff) -+ free(buff); -+ if (infile) -+ fclose(infile); -+ if (fdout != -1) -+ close(fdout); -+ if (outpath) { -+ unlink(outpath); -+ free(outpath); -+ } -+ return ret; -+} -diff --git a/support/nfsidmap/nfsidmap_common.c b/support/nfsidmap/nfsidmap_common.c -index 5242c7e..f89b82e 100644 ---- a/support/nfsidmap/nfsidmap_common.c -+++ b/support/nfsidmap/nfsidmap_common.c -@@ -57,8 +57,10 @@ struct conf_list *get_local_realms(void) - return NULL; - - node->field = calloc(1, NFS4_MAX_DOMAIN_LEN); -- if (node->field == NULL) -+ if (node->field == NULL) { -+ free(node); - return NULL; -+ } - - nfs4_get_default_domain(NULL, node->field, NFS4_MAX_DOMAIN_LEN); - toupper_str(node->field); -diff --git a/support/nfsidmap/umich_ldap.c b/support/nfsidmap/umich_ldap.c -index 0e31b1c..b661110 100644 ---- a/support/nfsidmap/umich_ldap.c -+++ b/support/nfsidmap/umich_ldap.c -@@ -1125,9 +1125,9 @@ umichldap_init(void) - - /* Verify required information is supplied */ - if (server_in == NULL || strlen(server_in) == 0) -- strncat(missing_msg, "LDAP_server ", sizeof(missing_msg)); -+ strncat(missing_msg, "LDAP_server ", sizeof(missing_msg)-1); - if (ldap_info.base == NULL || strlen(ldap_info.base) == 0) -- strncat(missing_msg, "LDAP_base ", sizeof(missing_msg)); -+ strncat(missing_msg, "LDAP_base ", sizeof(missing_msg)-1); - if (strlen(missing_msg) != 0) { - IDMAP_LOG(0, ("umichldap_init: Missing required information: " - "%s", missing_msg)); -diff --git a/systemd/rpc-pipefs-generator.c b/systemd/rpc-pipefs-generator.c -index 6e1d69c..0b5da11 100644 ---- a/systemd/rpc-pipefs-generator.c -+++ b/systemd/rpc-pipefs-generator.c -@@ -35,7 +35,10 @@ static int generate_mount_unit(const char *pipefs_path, const char *pipefs_unit, - sprintf(path, "%s/%s", dirname, pipefs_unit); - f = fopen(path, "w"); - if (!f) -+ { -+ free(path); - return 1; -+ } - - fprintf(f, "# Automatically generated by rpc-pipefs-generator\n\n[Unit]\n"); - fprintf(f, "Description=RPC Pipe File System\n"); -@@ -48,6 +51,7 @@ static int generate_mount_unit(const char *pipefs_path, const char *pipefs_unit, - fprintf(f, "Type=rpc_pipefs\n"); - - fclose(f); -+ free(path); - return 0; - } - -@@ -76,12 +80,16 @@ int generate_target(char *pipefs_path, const char *dirname) - strcat(path, filebase); - f = fopen(path, "w"); - if (!f) -+ { -+ free(path); - return 1; -+ } - - fprintf(f, "# Automatically generated by rpc-pipefs-generator\n\n[Unit]\n"); - fprintf(f, "Requires=%s\n", pipefs_unit); - fprintf(f, "After=%s\n", pipefs_unit); - fclose(f); -+ free(path); - - return 0; - } -diff --git a/tools/nfsconf/nfsconf.man b/tools/nfsconf/nfsconf.man -index 5b5e914..1ae8543 100644 ---- a/tools/nfsconf/nfsconf.man -+++ b/tools/nfsconf/nfsconf.man -@@ -28,6 +28,25 @@ nfsconf \- Query various NFS configuration settings - .IR subsection ] - .IR section - .IR tag -+.P -+.B nfsconf \-\-set -+.RB [ \-v | \-\-verbose ] -+.RB [ \-f | \-\-file -+.IR infile.conf ] -+.RB [ \-a | \-\-arg -+.IR subsection ] -+.IR section -+.IR tag -+.IR value -+.P -+.B nfsconf \-\-unset -+.RB [ \-v | \-\-verbose ] -+.RB [ \-f | \-\-file -+.IR infile.conf ] -+.RB [ \-a | \-\-arg -+.IR subsection ] -+.IR section -+.IR tag - .SH DESCRIPTION - The - .B nfsconf -@@ -41,6 +60,10 @@ Output an alphabetically sorted dump of the current configuration in conf file f - Test if a specific tag has a value set. - .IP "\fB\-g, \-\-get\fP" - Output the current value of the specified tag. -+.IP "\fB\-s, \-\-set\fP" -+Update or Add a tag and value to the config file, creating the file if necessary. -+.IP "\fB\-u, \-\-unset\fP" -+Remove the specified tag and its value from the config file. - .SH OPTIONS - .SS Options valid in all modes - .TP -@@ -56,7 +79,7 @@ Select a different config file to operate upon, default is - Select a specific sub-section - .SH EXIT STATUS - .SS \fB\-\-isset\fR mode --In this mode the command will return success (0) if the selected tag has a value, any other exit code indicates the value is not set, or some other error has occured. -+In this mode the command will return success (0) if the selected tag has a value, any other exit code indicates the value is not set, or some other error has occurred. - .SS all other modes - Success is indicated by an exit status of zero, any other status indicates an error. Error messages are output on stderr, and increasing verbosity will give more detailed explanations if any are available. - .SH EXAMPLES -@@ -64,11 +87,14 @@ Success is indicated by an exit status of zero, any other status indicates an er - .B nfsconf -v --dump --file /tmp/testconf.conf sorted.conf - Check a new config file for syntax errors and output a sorted version for ease of comparison with existing settings. - .TP --.B if ! nfsconf --isset gssd preferred-realm ; then echo 'No prefered realm configured for gss'; fi -+.B if ! nfsconf --isset gssd preferred-realm ; then echo 'No preferred realm configured for gss'; fi - The tool allows for easy testing of configuration values from shell scripts, here we test if a specific value has been set. - .TP - .B nfsconf --file /etc/nfsmount.conf --get --arg /home MountPoint background - Show default value for \fIbackground\fR option for NFS mounts of the \fI/home\fR path. -+.TP -+.B nfsconf --file /etc/nfs.conf --set nfsd debug 1 -+Enable debugging in nfsd - .SH FILES - .TP - .B /etc/nfs.conf -diff --git a/tools/nfsconf/nfsconfcli.c b/tools/nfsconf/nfsconfcli.c -index 034ec51..f98d0d1 100644 ---- a/tools/nfsconf/nfsconfcli.c -+++ b/tools/nfsconf/nfsconfcli.c -@@ -12,7 +12,9 @@ typedef enum { - MODE_NONE, - MODE_GET, - MODE_ISSET, -- MODE_DUMP -+ MODE_DUMP, -+ MODE_SET, -+ MODE_UNSET - } confmode_t; - - static void usage(const char *name) -@@ -29,11 +31,14 @@ static void usage(const char *name) - fprintf(stderr, " Output one specific config value\n"); - fprintf(stderr, " --isset [--arg subsection] {section} {tag}\n"); - fprintf(stderr, " Return code indicates if config value is present\n"); -+ fprintf(stderr, " --set [--arg subsection] {section} {tag} {value}\n"); -+ fprintf(stderr, " Set and Write a config value\n"); -+ fprintf(stderr, " --unset [--arg subsection] {section} {tag}\n"); -+ fprintf(stderr, " Remove an existing config value\n"); - } - - int main(int argc, char **argv) - { -- const char * val; - char * confpath = NFS_CONFFILE; - char * arg = NULL; - int verbose=0; -@@ -47,6 +52,8 @@ int main(int argc, char **argv) - int index = 0; - struct option long_options[] = { - {"get", no_argument, 0, 'g' }, -+ {"set", no_argument, 0, 's' }, -+ {"unset", no_argument, 0, 'u' }, - {"arg", required_argument, 0, 'a' }, - {"isset", no_argument, 0, 'i' }, - {"dump", optional_argument, 0, 'd' }, -@@ -55,14 +62,14 @@ int main(int argc, char **argv) - {NULL, 0, 0, 0 } - }; - -- c = getopt_long(argc, argv, "ga:id::f:v", long_options, &index); -+ c = getopt_long(argc, argv, "gsua:id::f:v", long_options, &index); - if (c == -1) break; - - switch (c) { - case 0: - break; - case 'f': -- /* user specified souce path for config */ -+ /* user specified source path for config */ - confpath = optarg; - break; - case 'a': -@@ -75,6 +82,12 @@ int main(int argc, char **argv) - case 'g': - mode = MODE_GET; - break; -+ case 's': -+ mode = MODE_SET; -+ break; -+ case 'u': -+ mode = MODE_UNSET; -+ break; - case 'i': - mode = MODE_ISSET; - break; -@@ -97,7 +110,7 @@ int main(int argc, char **argv) - xlog_config(D_ALL, 1); - xlog_stderr(1); - xlog_syslog(0); -- xlog_open("nfsconftool"); -+ xlog_open("nfsconf"); - - if (mode == MODE_NONE) { - fprintf(stderr, "Error: No MODE selected.\n"); -@@ -105,14 +118,18 @@ int main(int argc, char **argv) - return 1; - } - -- if (conf_init_file(confpath)) { -- /* config file was missing or had an error, warn about it */ -- if (verbose || mode != MODE_ISSET) -- fprintf(stderr, "Error loading config file %s\n", -- confpath); -- /* this isnt fatal for --isset */ -- if (mode != MODE_ISSET) -- return 1; -+ if (mode != MODE_SET && mode != MODE_UNSET) { -+ if (conf_init_file(confpath)) { -+ /* config file was missing or had an error, warn about it */ -+ if (verbose || mode != MODE_ISSET) { -+ fprintf(stderr, "Error loading config file %s\n", -+ confpath); -+ } -+ -+ /* this isnt fatal for --isset */ -+ if (mode != MODE_ISSET) -+ return 1; -+ } - } - - /* --dump mode, output the current configuration */ -@@ -144,6 +161,7 @@ int main(int argc, char **argv) - if (mode == MODE_GET || mode == MODE_ISSET) { - char * section = NULL; - char * tag = NULL; -+ const char * val; - - /* test they supplied section and tag names */ - if (optind+1 >= argc) { -@@ -169,8 +187,43 @@ int main(int argc, char **argv) - fprintf(stderr, "Tag '%s' not found\n", tag); - ret = 1; - } -+ } else -+ if (mode == MODE_SET || mode == MODE_UNSET) { -+ char * section = NULL; -+ char * tag = NULL; -+ char * val = NULL; -+ int need = 2; -+ -+ if (mode == MODE_UNSET) -+ need = 1; -+ -+ /* test they supplied section and tag names */ -+ if (optind+need >= argc) { -+ fprintf(stderr, "Error: insufficient arguments for mode\n"); -+ usage(argv[0]); -+ ret = 2; -+ goto cleanup; -+ } -+ -+ /* now we have a section and tag name */ -+ section = argv[optind++]; -+ tag = argv[optind++]; -+ if (mode == MODE_SET) -+ val = argv[optind++]; -+ -+ /* setting an empty string is same as unsetting */ -+ if (val!=NULL && *val == '\0') { -+ mode = MODE_UNSET; -+ val = NULL; -+ } -+ -+ if (conf_write(confpath, section, arg, tag, val)) { -+ if (verbose) -+ fprintf(stderr, "Error writing config\n"); -+ ret = 1; -+ } - } else { -- fprintf(stderr, "Mode not yet implimented.\n"); -+ fprintf(stderr, "Mode not yet implemented.\n"); - ret = 2; - } - -diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man -index 4f95f3a..e3a16f6 100644 ---- a/utils/exportfs/exports.man -+++ b/utils/exportfs/exports.man -@@ -131,10 +131,12 @@ this way are ro, rw, no_root_squash, root_squash, and all_squash. - understands the following export options: - .TP - .IR secure --This option requires that requests originate on an Internet port less --than IPPORT_RESERVED (1024). This option is on by default. To turn it --off, specify -+This option requires that requests not using gss originate on an -+Internet port less than IPPORT_RESERVED (1024). This option is on by default. -+To turn it off, specify - .IR insecure . -+(NOTE: older kernels (before upstream kernel version 4.17) enforced this -+requirement on gss requests as well.) - .TP - .IR rw - Allow both read and write requests on this NFS volume. The -diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c -index 2c14e5f..7b21ee2 100644 ---- a/utils/gssd/gssd.c -+++ b/utils/gssd/gssd.c -@@ -279,16 +279,16 @@ gssd_read_service_info(int dirfd, struct clnt_info *clp) - * (commit bf19aacecbeebccb2c3d150a8bd9416b7dba81fe) - */ - numfields = fscanf(info, -- "RPC server: %ms\n" -- "service: %ms (%d) version %d\n" -- "address: %ms\n" -- "protocol: %ms\n" -- "port: %ms\n", -- &server, -- &service, &program, &version, -- &address, -- &protoname, -- &port); -+ "RPC server: %s\n" -+ "service: %s (%d) version %d\n" -+ "address: %s\n" -+ "protocol: %s\n" -+ "port: %s\n", -+ (char *)&server, -+ (char *)&service, &program, &version, -+ (char *)&address, -+ (char *)&protoname, -+ (char *)&port); - - - switch (numfields) { -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index ce73777..8767e26 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -520,8 +520,9 @@ out: - } - - static AUTH * --krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, -- char *service, CLIENT **rpc_clnt) -+krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, -+ char *srchost, char *tgtname, char *service, -+ CLIENT **rpc_clnt) - { - AUTH *auth = NULL; - char **credlist = NULL; -@@ -534,7 +535,7 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - - do { - gssd_refresh_krb5_machine_credential(clp->servername, NULL, -- service); -+ service, srchost); - /* - * Get a list of credential cache names and try each - * of them until one works or we've tried them all -@@ -594,8 +595,8 @@ out: - * context on behalf of the kernel - */ - static void --process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, -- char *service) -+process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *srchost, -+ char *tgtname, char *service) - { - CLIENT *rpc_clnt = NULL; - AUTH *auth = NULL; -@@ -643,7 +644,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - if (auth == NULL) { - if (uid == 0 && (root_uses_machine_creds == 1 || - service != NULL)) { -- auth = krb5_use_machine_creds(clp, uid, tgtname, -+ auth = krb5_use_machine_creds(clp, uid, srchost, tgtname, - service, &rpc_clnt); - if (auth == NULL) - goto out_return_error; -@@ -714,7 +715,7 @@ handle_krb5_upcall(struct clnt_upcall_info *info) - - printerr(2, "\n%s: uid %d (%s)\n", __func__, info->uid, clp->relpath); - -- process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL); -+ process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL, NULL); - free(info); - } - -@@ -728,11 +729,12 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - char *uidstr = NULL; - char *target = NULL; - char *service = NULL; -+ char *srchost = NULL; - char *enctypes = NULL; - char *upcall_str; - char *pbuf = info->lbuf; - -- printerr(2, "\n%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath); -+ printerr(2, "%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath); - - upcall_str = strdup(info->lbuf); - if (upcall_str == NULL) { -@@ -751,6 +753,8 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - target = p + strlen("target="); - else if (!strncmp(p, "service=", strlen("service="))) - service = p + strlen("service="); -+ else if (!strncmp(p, "srchost=", strlen("srchost="))) -+ srchost = p + strlen("srchost="); - } - - if (!mech || strlen(mech) < 1) { -@@ -802,7 +806,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - } - - if (strcmp(mech, "krb5") == 0 && clp->servername) -- process_krb5_upcall(clp, uid, clp->gssd_fd, target, service); -+ process_krb5_upcall(clp, uid, clp->gssd_fd, srchost, target, service); - else { - if (clp->servername) - printerr(0, "WARNING: handle_gssd_upcall: " -@@ -815,4 +819,3 @@ out_nomem: - free(info); - return; - } -- -diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c -index b342b06..eba1aac 100644 ---- a/utils/gssd/krb5_util.c -+++ b/utils/gssd/krb5_util.c -@@ -757,7 +757,8 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, - * the server hostname. - */ - static int --find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, -+find_keytab_entry(krb5_context context, krb5_keytab kt, -+ const char *srchost, const char *tgtname, - krb5_keytab_entry *kte, const char **svcnames) - { - krb5_error_code code; -@@ -781,7 +782,9 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - goto out; - - /* Get full local hostname */ -- if (gethostname(myhostname, sizeof(myhostname)) == -1) { -+ if (srchost) { -+ strcpy(myhostname, srchost); -+ } else if (gethostname(myhostname, sizeof(myhostname)) == -1) { - retval = errno; - k5err = gssd_k5_err_msg(context, retval); - printerr(1, "%s while getting local hostname\n", k5err); -@@ -807,10 +810,12 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - myhostad[i+1] = 0; - } - -- retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); -- if (retval) { -- /* Don't use myhostname */ -- myhostname[0] = 0; -+ if (!srchost) { -+ retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); -+ if (retval) { -+ /* Don't use myhostname */ -+ myhostname[0] = 0; -+ } - } - - code = krb5_get_default_realm(context, &default_realm); -@@ -1140,7 +1145,7 @@ gssd_get_krb5_machine_cred_list(char ***list) - if (ple->ccname) { - /* Make sure cred is up-to-date before returning it */ - retval = gssd_refresh_krb5_machine_credential(NULL, ple, -- NULL); -+ NULL, NULL); - if (retval) - continue; - if (i + 1 > listsize) { -@@ -1231,7 +1236,7 @@ gssd_destroy_krb5_machine_creds(void) - int - gssd_refresh_krb5_machine_credential(char *hostname, - struct gssd_k5_kt_princ *ple, -- char *service) -+ char *service, char *srchost) - { - krb5_error_code code = 0; - krb5_context context; -@@ -1240,6 +1245,9 @@ gssd_refresh_krb5_machine_credential(char *hostname, - char *k5err = NULL; - const char *svcnames[] = { "$", "root", "nfs", "host", NULL }; - -+ printerr(2, "%s: hostname=%s ple=%p service=%s srchost=%s\n", -+ __func__, hostname, ple, service, srchost); -+ - /* - * If a specific service name was specified, use it. - * Otherwise, use the default list. -@@ -1270,7 +1278,8 @@ gssd_refresh_krb5_machine_credential(char *hostname, - if (ple == NULL) { - krb5_keytab_entry kte; - -- code = find_keytab_entry(context, kt, hostname, &kte, svcnames); -+ code = find_keytab_entry(context, kt, srchost, hostname, -+ &kte, svcnames); - if (code) { - printerr(0, "ERROR: %s: no usable keytab entry found " - "in keytab %s for connection with host %s\n", -diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h -index e3bbb07..b000b44 100644 ---- a/utils/gssd/krb5_util.h -+++ b/utils/gssd/krb5_util.h -@@ -30,7 +30,7 @@ void gssd_free_krb5_machine_cred_list(char **list); - void gssd_destroy_krb5_machine_creds(void); - int gssd_refresh_krb5_machine_credential(char *hostname, - struct gssd_k5_kt_princ *ple, -- char *service); -+ char *service, char *srchost); - char *gssd_k5_err_msg(krb5_context context, krb5_error_code code); - void gssd_k5_get_default_realm(char **def_realm); - -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index b87c4dd..4811e0f 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -310,7 +310,7 @@ main(int argc, char **argv) - if (!serverstart && !clientstart) - errx(1, "it is illegal to specify both -C and -S"); - -- strncat(pipefsdir, "/nfs", sizeof(pipefsdir)); -+ strncat(pipefsdir, "/nfs", sizeof(pipefsdir)-1); - - daemon_init(fg); - -@@ -923,7 +923,8 @@ static int - getfield(char **bpp, char *fld, size_t fldsz) - { - char *bp; -- int val, n; -+ unsigned int val; -+ int n; - - while ((bp = strsep(bpp, " ")) != NULL && bp[0] == '\0') - ; -diff --git a/utils/mount/network.c b/utils/mount/network.c -index e490399..356f663 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -50,6 +50,8 @@ - #include - #include - #include -+#include -+#include - - #include "sockaddr.h" - #include "xcommon.h" -@@ -1759,3 +1761,48 @@ int nfs_umount_do_umnt(struct mount_options *options, - - return EX_SUCCESS; - } -+ -+int nfs_is_inaddr_any(struct sockaddr *nfs_saddr) -+{ -+ switch (nfs_saddr->sa_family) { -+ case AF_INET: { -+ if (((struct sockaddr_in *)nfs_saddr)->sin_addr.s_addr == -+ INADDR_ANY) -+ return 1; -+ break; -+ } -+ case AF_INET6: -+ if (!memcmp(&((struct sockaddr_in6 *)nfs_saddr)->sin6_addr, -+ &in6addr_any, sizeof(in6addr_any))) -+ return 1; -+ break; -+ } -+ return 0; -+} -+ -+int nfs_addr_matches_localips(struct sockaddr *nfs_saddr) -+{ -+ struct ifaddrs *myaddrs, *ifa; -+ int found = 0; -+ -+ /* acquire exiting network interfaces */ -+ if (getifaddrs(&myaddrs) != 0) -+ return 0; -+ -+ /* interate over the available interfaces and check if we -+ * we find a match to the supplied clientaddr value -+ */ -+ for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next) { -+ if (ifa->ifa_addr == NULL) -+ continue; -+ if (!(ifa->ifa_flags & IFF_UP)) -+ continue; -+ if (!memcmp(ifa->ifa_addr, nfs_saddr, -+ sizeof(struct sockaddr))) { -+ found = 1; -+ break; -+ } -+ } -+ freeifaddrs(myaddrs); -+ return found; -+} -diff --git a/utils/mount/network.h b/utils/mount/network.h -index ecaac33..0fc98ac 100644 ---- a/utils/mount/network.h -+++ b/utils/mount/network.h -@@ -54,6 +54,8 @@ int nfs_callback_address(const struct sockaddr *, const socklen_t, - int clnt_ping(struct sockaddr_in *, const unsigned long, - const unsigned long, const unsigned int, - struct sockaddr_in *); -+int nfs_is_inaddr_any(struct sockaddr *); -+int nfs_addr_matches_localips(struct sockaddr *); - - struct mount_options; - -diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man -index bd1508c..9ee9bd9 100644 ---- a/utils/mount/nfs.man -+++ b/utils/mount/nfs.man -@@ -835,6 +835,9 @@ to perform NFS version 4.0 callback requests against - files on this mount point. If the server is unable to - establish callback connections to clients, performance - may degrade, or accesses to files may temporarily hang. -+Can specify a value of IPv4_ANY (0.0.0.0) or equivalent -+IPv6 any address which will signal to the NFS server that -+this NFS client does not want delegations. - .IP - If this option is not specified, the - .BR mount (8) -diff --git a/utils/mount/nfs4mount.c b/utils/mount/nfs4mount.c -index 89629ed..3e4f1e2 100644 ---- a/utils/mount/nfs4mount.c -+++ b/utils/mount/nfs4mount.c -@@ -218,7 +218,7 @@ int nfs4mount(const char *spec, const char *node, int flags, - goto fail; - } - if (running_bg) -- strncpy(new_opts, old_opts, sizeof(new_opts)); -+ strncpy(new_opts, old_opts, sizeof(new_opts)-1); - else - snprintf(new_opts, sizeof(new_opts), "%s%saddr=%s", - old_opts, *old_opts ? "," : "", s); -diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c -index ae4a3da..952a755 100644 ---- a/utils/mount/nfsmount.c -+++ b/utils/mount/nfsmount.c -@@ -828,7 +828,7 @@ noauth_flavors: - - data.fd = fsock; - memcpy((char *) &data.addr, (char *) nfs_saddr, sizeof(data.addr)); -- strncpy(data.hostname, hostname, sizeof(data.hostname)); -+ strncpy(data.hostname, hostname, sizeof(data.hostname)-1); - - out_ok: - /* Ensure we have enough padding for the following strcat()s */ -diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index d1b0708..4d2e37e 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -229,7 +229,8 @@ static int nfs_append_addr_option(const struct sockaddr *sap, - - /* - * Called to discover our address and append an appropriate 'clientaddr=' -- * option to the options string. -+ * option to the options string. If the supplied 'clientaddr=' value does -+ * not match either IPV4/IPv6 any or a local address, then fail the mount. - * - * Returns 1 if 'clientaddr=' option created successfully or if - * 'clientaddr=' option is already present; otherwise zero. -@@ -242,8 +243,27 @@ static int nfs_append_clientaddr_option(const struct sockaddr *sap, - struct sockaddr *my_addr = &address.sa; - socklen_t my_len = sizeof(address); - -- if (po_contains(options, "clientaddr") == PO_FOUND) -+ if (po_contains(options, "clientaddr") == PO_FOUND) { -+ char *addr = po_get(options, "clientaddr"); -+ union nfs_sockaddr nfs_address; -+ struct sockaddr *nfs_saddr = &nfs_address.sa; -+ socklen_t nfs_salen = sizeof(nfs_address); -+ -+ /* translate the input for clientaddr to nfs_sockaddr */ -+ if (!nfs_string_to_sockaddr(addr, nfs_saddr, &nfs_salen)) -+ return 0; -+ -+ /* check for IPV4_ANY and IPV6_ANY */ -+ if (nfs_is_inaddr_any(nfs_saddr)) -+ return 1; -+ -+ /* check if ip matches local network addresses */ -+ if (!nfs_addr_matches_localips(nfs_saddr)) -+ nfs_error(_("%s: [warning] supplied clientaddr=%s " -+ "does not match any existing network " -+ "addresses"), progname, addr); - return 1; -+ } - - nfs_callback_address(sap, salen, my_addr, &my_len); - -diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c -index 4c68702..086c39b 100644 ---- a/utils/mountd/mountd.c -+++ b/utils/mountd/mountd.c -@@ -702,7 +702,7 @@ main(int argc, char **argv) - else - NFSCTL_TCPUNSET(_rpcprotobits); - for (vers = 2; vers <= 4; vers++) { -- char tag[10]; -+ char tag[20]; - sprintf(tag, "vers%d", vers); - if (conf_get_bool("nfsd", tag, NFSCTL_VERISSET(nfs_version, vers))) - NFSCTL_VERSET(nfs_version, vers); -diff --git a/utils/mountd/v4root.c b/utils/mountd/v4root.c -index f978f4c..d735dbf 100644 ---- a/utils/mountd/v4root.c -+++ b/utils/mountd/v4root.c -@@ -92,7 +92,7 @@ v4root_create(char *path, nfs_export *export) - - dupexportent(&eep, &pseudo_root.m_export); - eep.e_hostname = curexp->e_hostname; -- strncpy(eep.e_path, path, sizeof(eep.e_path)); -+ strncpy(eep.e_path, path, sizeof(eep.e_path)-1); - if (strcmp(path, "/") != 0) - eep.e_flags &= ~NFSEXP_FSID; - set_pseudofs_security(&eep, curexp->e_flags); -diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index 2303a5d..f048631 100644 ---- a/utils/nfsd/nfsd.c -+++ b/utils/nfsd/nfsd.c -@@ -98,7 +98,7 @@ main(int argc, char **argv) - else - NFSCTL_TCPUNSET(protobits); - for (i = 2; i <= 4; i++) { -- char tag[10]; -+ char tag[20]; - sprintf(tag, "vers%d", i); - if (conf_get_bool("nfsd", tag, NFSCTL_VERISSET(versbits, i))) - NFSCTL_VERSET(versbits, i); -diff --git a/utils/nfsdcltrack/nfsdcltrack.c b/utils/nfsdcltrack/nfsdcltrack.c -index 76b06d2..b45a904 100644 ---- a/utils/nfsdcltrack/nfsdcltrack.c -+++ b/utils/nfsdcltrack/nfsdcltrack.c -@@ -553,7 +553,7 @@ find_cmd(char *cmdname) - int - main(int argc, char **argv) - { -- char arg; -+ int arg; - char *val; - int rc = 0; - char *progname, *cmdarg = NULL; -diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c -index 374bc5d..d3967a3 100644 ---- a/utils/nfsidmap/nfsidmap.c -+++ b/utils/nfsidmap/nfsidmap.c -@@ -283,7 +283,7 @@ static int key_invalidate(char *keystr, int keymask) - { - FILE *fp; - char buf[BUFSIZ], *ptr; -- key_serial_t key; -+ unsigned int key; - int mask; - - xlog_syslog(0); -diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c -index c779053..ca84532 100644 ---- a/utils/nfsstat/nfsstat.c -+++ b/utils/nfsstat/nfsstat.c -@@ -340,7 +340,7 @@ static struct option longopts[] = - { "all", 0, 0, 'v' }, - { "auto", 0, 0, '\3' }, - { "client", 0, 0, 'c' }, -- { "mounted", 0, 0, 'm' }, -+ { "mounts", 0, 0, 'm' }, - { "nfs", 0, 0, 'n' }, - { "rpc", 0, 0, 'r' }, - { "server", 0, 0, 's' }, -@@ -1013,7 +1013,7 @@ mounts(const char *name) - * be a fatal error -- it usually means the module isn't loaded. - */ - if ((fp = fopen(name, "r")) == NULL) { -- fprintf(stderr, "Warning: %s: %m\n", name); -+ fprintf(stderr, "Warning: %s: %s\n", name, strerror(errno)); - return 0; - } - -@@ -1089,8 +1089,8 @@ out: - fclose(fp); - if (err) { - if (!other_opt) { -- fprintf(stderr, "Error: No %s Stats (%s: %m). \n", -- label, file); -+ fprintf(stderr, "Error: No %s Stats (%s: %s). \n", -+ label, file, strerror(errno)); - exit(2); - } - *opt = 0; -diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c -index 6d19ec1..7a48473 100644 ---- a/utils/statd/sm-notify.c -+++ b/utils/statd/sm-notify.c -@@ -569,7 +569,7 @@ usage: fprintf(stderr, - if (name == NULL) - exit(1); - -- strncpy(nsm_hostname, name, sizeof(nsm_hostname)); -+ strncpy(nsm_hostname, name, sizeof(nsm_hostname)-1); - free(name); - } - -diff --git a/utils/statd/statd.c b/utils/statd/statd.c -index 563a272..2cc6cf3 100644 ---- a/utils/statd/statd.c -+++ b/utils/statd/statd.c -@@ -231,11 +231,12 @@ static void set_nlm_port(char *type, int port) - } - if (fd >= 0) { - if (write(fd, nbuf, strlen(nbuf)) != (ssize_t)strlen(nbuf)) -- fprintf(stderr, "%s: fail to set NLM %s port: %m\n", -- name_p, type); -+ fprintf(stderr, "%s: fail to set NLM %s port: %s\n", -+ name_p, type, strerror(errno)); - close(fd); - } else -- fprintf(stderr, "%s: failed to open %s: %m\n", name_p, pathbuf); -+ fprintf(stderr, "%s: failed to open %s: %s\n", -+ name_p, pathbuf, strerror(errno)); - } - - /* diff --git a/nfs-utils-2.3.3-rc3.patch b/nfs-utils-2.3.3-rc3.patch deleted file mode 100644 index 63488f2..0000000 --- a/nfs-utils-2.3.3-rc3.patch +++ /dev/null @@ -1,1620 +0,0 @@ -diff --git a/configure.ac b/configure.ac -index 276dec3..4b698dd 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -157,7 +157,7 @@ AC_ARG_WITH(rpcgen, - RPCGEN_PATH=$rpcgen_path - fi - AC_SUBST(RPCGEN_PATH) -- AM_CONDITIONAL(CONFIG_RPCGEN, [test "$RPCGEN_PATH" = ""]) -+ AM_CONDITIONAL(CONFIG_RPCGEN, [test "$RPCGEN_PATH" = "internal"]) - AC_ARG_ENABLE(uuid, - [AC_HELP_STRING([--disable-uuid], - [Exclude uuid support to avoid buggy libblkid. @<:@default=no@:>@])], -diff --git a/support/export/client.c b/support/export/client.c -index 2346f99..baf59c8 100644 ---- a/support/export/client.c -+++ b/support/export/client.c -@@ -482,8 +482,9 @@ add_name(char *old, const char *add) - else - cp = cp + strlen(cp); - } -- if (old) { -- strncpy(new, old, cp-old); -+ len = cp-old; -+ if (old && len > 0) { -+ strncpy(new, old, len); - new[cp-old] = 0; - } else { - new[0] = 0; -diff --git a/support/include/conffile.h b/support/include/conffile.h -index bc2d61f..a3340f9 100644 ---- a/support/include/conffile.h -+++ b/support/include/conffile.h -@@ -67,6 +67,7 @@ extern int conf_match_num(const char *, const char *, int); - extern int conf_remove(int, const char *, const char *); - extern int conf_remove_section(int, const char *); - extern void conf_report(FILE *); -+extern int conf_write(const char *, const char *, const char *, const char *, const char *); - - /* - * Convert letter from upper case to lower case -diff --git a/support/include/exportfs.h b/support/include/exportfs.h -index 8af47a8..4e0d9d1 100644 ---- a/support/include/exportfs.h -+++ b/support/include/exportfs.h -@@ -97,7 +97,7 @@ typedef struct mexport { - struct mclient * m_client; - struct exportent m_export; - int m_exported; /* known to knfsd. */ -- int m_xtabent : 1, /* xtab entry exists */ -+ unsigned int m_xtabent : 1, /* xtab entry exists */ - m_mayexport: 1, /* derived from xtabbed */ - m_changed : 1, /* options (may) have changed */ - m_warned : 1; /* warned about multiple exports -diff --git a/support/junction/path.c b/support/junction/path.c -index 68a1d13..e74e4c4 100644 ---- a/support/junction/path.c -+++ b/support/junction/path.c -@@ -326,8 +326,10 @@ nsdb_posix_to_path_array(const char *pathname, char ***path_array) - break; - next = strchrnul(component, '/'); - length = (size_t)(next - component); -- if (length > 255) -+ if (length > 255) { -+ nsdb_free_string_array(result); - return FEDFS_ERR_SVRFAULT; -+ } - - result[i] = strndup(component, length); - if (result[i] == NULL) { -diff --git a/support/misc/file.c b/support/misc/file.c -index 63597df..4065376 100644 ---- a/support/misc/file.c -+++ b/support/misc/file.c -@@ -96,7 +96,7 @@ generic_setup_basedir(const char *progname, const char *parentdir, char *base, - } - - /* Ensure we have a clean directory pathname */ -- strncpy(buf, parentdir, sizeof(buf)); -+ strncpy(buf, parentdir, sizeof(buf)-1); - path = dirname(buf); - if (*path == '.') { - (void)fprintf(stderr, "%s: Unusable directory %s", -diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c -index ee94031..3845b94 100644 ---- a/support/nfs/conffile.c -+++ b/support/nfs/conffile.c -@@ -255,14 +255,14 @@ conf_parse_line(int trans, char *line, const char *filename, int lineno, char ** - char *inc_section = NULL, *inc_subsection = NULL; - char *relpath, *subconf; - -+ /* Strip off any leading blanks */ -+ while (isspace(*line)) -+ line++; -+ - /* Ignore blank lines */ - if (*line == '\0') - return; - -- /* Strip off any leading blanks */ -- while (isblank(*line)) -- line++; -- - /* Lines starting with '#' or ';' are comments. */ - if (*line == '#' || *line == ';') - return; -@@ -495,7 +495,7 @@ conf_readfile(const char *path) - { - struct stat sb; - if (!path) { -- xlog_err("conf_readfile: no path given"); -+ xlog(L_ERROR, "conf_readfile: no path given"); - return NULL; - } - -@@ -640,7 +640,7 @@ conf_get_num(const char *section, const char *tag, int def) - /* - * Return the Boolean value denoted by TAG in section SECTION, or DEF - * if that tags does not exist. -- * FALSE is returned for case-insensitve comparisons with 0, f, false, n, no, off -+ * FALSE is returned for case-insensitive comparisons with 0, f, false, n, no, off - * TRUE is returned for 1, t, true, y, yes, on - * A failure to match one of these results in DEF - */ -@@ -727,6 +727,8 @@ retry: - continue; - if (arg && (cb->arg == NULL || strcasecmp(arg, cb->arg) != 0)) - continue; -+ if (!arg && cb->arg) -+ continue; - if (strcasecmp(tag, cb->tag) != 0) - continue; - if (cb->value[0] == '$') { -@@ -1321,3 +1323,624 @@ cleanup: - } - return; - } -+ -+/* struct and queue for buffing output lines */ -+TAILQ_HEAD(tailhead, outbuffer); -+ -+struct outbuffer { -+ TAILQ_ENTRY(outbuffer) link; -+ char *text; -+}; -+ -+static struct outbuffer * -+make_outbuffer(char *line) -+{ -+ struct outbuffer *new; -+ -+ if (line == NULL) -+ return NULL; -+ -+ new = calloc(1, sizeof(struct outbuffer)); -+ if (new == NULL) { -+ xlog(L_ERROR, "malloc error creating outbuffer"); -+ return NULL; -+ } -+ new->text = line; -+ return new; -+} -+ -+/* compose a properly escaped tag=value line */ -+static char * -+make_tagline(const char *tag, const char *value) -+{ -+ char *line; -+ int ret; -+ -+ if (!value) -+ return NULL; -+ -+ if (should_escape(value)) -+ ret = asprintf(&line, "%s = \"%s\"\n", tag, value); -+ else -+ ret = asprintf(&line, "%s = %s\n", tag, value); -+ -+ if (ret == -1) { -+ xlog(L_ERROR, "malloc error composing a tag line"); -+ return NULL; -+ } -+ return line; -+} -+ -+/* compose a section header line */ -+static char * -+make_section(const char *section, const char *arg) -+{ -+ char *line; -+ int ret; -+ -+ if (arg) -+ ret = asprintf(&line, "[%s \"%s\"]\n", section, arg); -+ else -+ ret = asprintf(&line, "[%s]\n", section); -+ -+ if (ret == -1) { -+ xlog(L_ERROR, "malloc error composing section header"); -+ return NULL; -+ } -+ return line; -+} -+ -+/* does the supplied line contain the named section header */ -+static bool -+is_section(const char *line, const char *section, const char *arg) -+{ -+ char *end; -+ char *name; -+ char *sub; -+ bool found = false; -+ -+ /* skip leading white space */ -+ while (*line == '[' || isspace(*line)) -+ line++; -+ -+ name = strdup(line); -+ if (name == NULL) { -+ xlog_warn("conf_write: malloc failed "); -+ return false; -+ } -+ -+ /* find the end */ -+ end = strchr(name, ']'); -+ -+ /* malformed line */ -+ if (end == NULL) { -+ xlog_warn("conf_write: warning: malformed section name"); -+ goto cleanup; -+ } -+ -+ while (*end && ( *end == ']' || isblank(*end))) -+ *(end--) = '\0'; -+ -+ /* is there a subsection name (aka arg) */ -+ sub = strchr(name, '"'); -+ if (sub) { -+ end = sub - 1; -+ *(sub++) = '\0'; -+ -+ /* trim whitespace between section name and arg */ -+ while (end > name && isblank(*end)) -+ *(end--) = '\0'; -+ -+ /* trim off closing quote */ -+ end = strchr(sub, '"'); -+ if (end == NULL) { -+ xlog_warn("conf_write: warning: malformed sub-section name"); -+ goto cleanup; -+ } -+ *end = '\0'; -+ } -+ -+ /* ready to compare */ -+ if (strcasecmp(section, name)!=0) -+ goto cleanup; -+ -+ if (arg != NULL) { -+ if (sub == NULL || strcasecmp(arg, sub)!=0) -+ goto cleanup; -+ } else { -+ if (sub != NULL) -+ goto cleanup; -+ } -+ -+ found = true; -+ -+cleanup: -+ free(name); -+ return found; -+} -+ -+/* check that line contains the specified tag assignment */ -+static bool -+is_tag(const char *line, const char *tagname) -+{ -+ char *end; -+ char *name; -+ bool found = false; -+ -+ /* quick check, is this even an assignment line */ -+ end = strchr(line, '='); -+ if (end == NULL) -+ return false; -+ -+ /* skip leading white space before tag name */ -+ while (isblank(*line)) -+ line++; -+ -+ name = strdup(line); -+ if (name == NULL) { -+ xlog_warn("conf_write: malloc failed"); -+ return false; -+ } -+ -+ /* trim any newline characters */ -+ end = strchr(name, '\n'); -+ if (end) -+ *end = '\0'; -+ end = strchr(name, '\r'); -+ if (end) -+ *end = '\0'; -+ -+ /* find the assignment equals sign */ -+ end = strchr(name, '='); -+ -+ /* malformed line, i swear the equals was there earlier */ -+ if (end == NULL) { -+ xlog_warn("conf_write: warning: malformed tag name"); -+ goto cleanup; -+ } -+ -+ /* trim trailing whitespace after tag name */ -+ do { -+ *(end--) = '\0'; -+ }while (end > name && *end && isblank(*end)); -+ -+ /* quoted string, take contents of quotes only */ -+ if (*name == '"') { -+ char * new = strdup(name+1); -+ end = strchr(new, '"'); -+ if (end != NULL) { -+ *end = 0; -+ free(name); -+ name = new; -+ } else { -+ free(new); -+ } -+ } -+ -+ /* now compare */ -+ if (strcasecmp(tagname, name) == 0) -+ found = true; -+ -+cleanup: -+ free(name); -+ return found; -+} -+ -+/* is this an empty line ? */ -+static bool -+is_empty(const char *line) -+{ -+ const char *p = line; -+ -+ if (line == NULL) -+ return true; -+ if (*line == '\0') -+ return true; -+ -+ while (*p != '\0' && isspace(*p)) -+ p++; -+ -+ if (*p == '\0') -+ return true; -+ -+ return false; -+} -+ -+/* is this line just a comment ? */ -+static bool -+is_comment(const char *line) -+{ -+ if (line == NULL) -+ return false; -+ -+ while (isblank(*line)) -+ line++; -+ -+ if (*line == '#') -+ return true; -+ -+ return false; -+} -+ -+/* delete a buffer queue whilst optionally outputting to file */ -+static int -+flush_outqueue(struct tailhead *queue, FILE *fout) -+{ -+ int ret = 0; -+ while (queue->tqh_first != NULL) { -+ struct outbuffer *ob = queue->tqh_first; -+ TAILQ_REMOVE(queue, ob, link); -+ if (ob->text) { -+ if (fout) { -+ ret = fprintf(fout, "%s", ob->text); -+ if (ret == -1) { -+ xlog(L_ERROR, "Error writing to config file: %s", -+ strerror(errno)); -+ fout = NULL; -+ } -+ } -+ free(ob->text); -+ } -+ free(ob); -+ } -+ if (ret == -1) -+ return 1; -+ return 0; -+} -+ -+/* read one line of text from a file, growing the buffer as necessary */ -+static int -+read_line(char **buff, int *buffsize, FILE *in) -+{ -+ char *readp; -+ int used = 0; -+ bool again = false; -+ -+ /* make sure we have a buffer to read into */ -+ if (*buff == NULL) { -+ *buffsize = 4096; -+ *buff = calloc(1, *buffsize); -+ if (*buff == NULL) { -+ xlog(L_ERROR, "malloc error for read buffer"); -+ return -1; -+ } -+ } -+ -+ readp = *buff; -+ -+ do { -+ int len; -+ -+ /* read in a chunk */ -+ if (fgets(readp, *buffsize-used, in)==NULL) -+ return -1; -+ -+ len = strlen(*buff); -+ if (len == 0) -+ return -1; -+ -+ /* was this the end of a line, or partial read */ -+ readp = *buff + len - 1; -+ -+ if (*readp != '\n' && *readp !='\r') { -+ /* no nl/cr must be partial read, go again */ -+ readp++; -+ again = true; -+ } else { -+ /* that was a normal end of line */ -+ again = false; -+ } -+ -+ /* do we need more space */ -+ if (again && *buffsize - len < 1024) { -+ int offset = readp - *buff; -+ char *newbuff; -+ *buffsize += 4096; -+ newbuff = realloc(*buff, *buffsize); -+ if (newbuff == NULL) { -+ xlog(L_ERROR, "malloc error reading line"); -+ return -1; -+ } -+ *buff = newbuff; -+ readp = newbuff + offset; -+ } -+ } while(again); -+ return 0; -+} -+ -+/* append a line to the given location in the queue */ -+static int -+append_line(struct tailhead *queue, struct outbuffer *entry, char *line) -+{ -+ int ret = 0; -+ char *end; -+ bool splitmode = false; -+ char *start = line; -+ -+ if (line == NULL) -+ return -1; -+ -+ /* if there are \n's in the middle of the string -+ * then we need to split it into folded lines */ -+ do { -+ char *thisline; -+ struct outbuffer *qbuff; -+ -+ end = strchr(start, '\n'); -+ if (end && *(end+1) != '\0') { -+ *end = '\0'; -+ -+ ret = asprintf(&thisline, "%s\\\n", start); -+ if (ret == -1) { -+ xlog(L_ERROR, "malloc error composing output"); -+ return -1; -+ } -+ splitmode = true; -+ start = end+1; -+ } else { -+ end = NULL; -+ if (splitmode) { -+ thisline = strdup(start); -+ if (thisline == NULL) -+ return -1; -+ } else { -+ thisline = start; -+ } -+ } -+ -+ qbuff = make_outbuffer(thisline); -+ if (qbuff == NULL) -+ return -1; -+ -+ if (entry) { -+ TAILQ_INSERT_AFTER(queue, entry, qbuff, link); -+ entry = TAILQ_NEXT(entry, link); -+ } else { -+ TAILQ_INSERT_TAIL(queue, qbuff, link); -+ } -+ }while (end != NULL); -+ -+ /* we malloced copies of this, so free the original */ -+ if (splitmode) -+ free(line); -+ -+ return 0; -+} -+ -+/* is this a "folded" line, i.e. ends in backslash */ -+static bool -+is_folded(const char *line) -+{ -+ const char *end; -+ if (line == NULL) -+ return false; -+ -+ end = line + strlen(line); -+ while (end > line) { -+ end--; -+ if (*end != '\n' && *end != '\r') -+ break; -+ } -+ -+ if (*end == '\\') -+ return true; -+ -+ return false; -+} -+ -+/*** -+ * Write a value to an nfs.conf style filename -+ * -+ * create the file if it doesnt already exist -+ * if value==NULL removes the setting (if present) -+ */ -+int -+conf_write(const char *filename, const char *section, const char *arg, -+ const char *tag, const char *value) -+{ -+ int fdout = -1; -+ char *outpath = NULL; -+ FILE *outfile = NULL; -+ FILE *infile = NULL; -+ int ret = 1; -+ struct tailhead outqueue; -+ char * buff = NULL; -+ int buffsize = 0; -+ -+ TAILQ_INIT(&outqueue); -+ -+ if (!filename) { -+ xlog_warn("conf_write: no filename supplied"); -+ return ret; -+ } -+ -+ if (!section || !tag) { -+ xlog_warn("conf_write: section or tag name missing"); -+ return ret; -+ } -+ -+ if (asprintf(&outpath, "%s.XXXXXX", filename) == -1) { -+ xlog(L_ERROR, "conf_write: error composing temp filename"); -+ return ret; -+ } -+ -+ fdout = mkstemp(outpath); -+ if (fdout < 0) { -+ xlog(L_ERROR, "conf_write: open temp file %s failed: %s", -+ outpath, strerror(errno)); -+ goto cleanup; -+ } -+ -+ outfile = fdopen(fdout, "w"); -+ if (!outfile) { -+ xlog(L_ERROR, "conf_write: fdopen temp file failed: %s", -+ strerror(errno)); -+ goto cleanup; -+ } -+ -+ infile = fopen(filename, "r"); -+ if (!infile) { -+ if (!value) { -+ xlog_warn("conf_write: config file \"%s\" not found, nothing to do", filename); -+ ret = 0; -+ goto cleanup; -+ } -+ -+ xlog_warn("conf_write: config file \"%s\" not found, creating.", filename); -+ if (append_line(&outqueue, NULL, make_section(section, arg))) -+ goto cleanup; -+ -+ if (append_line(&outqueue, NULL, make_tagline(tag, value))) -+ goto cleanup; -+ -+ if (flush_outqueue(&outqueue, outfile)) -+ goto cleanup; -+ } else { -+ bool found = false; -+ int err = 0; -+ -+ buffsize = 4096; -+ buff = calloc(1, buffsize); -+ if (buff == NULL) { -+ xlog(L_ERROR, "malloc error for read buffer"); -+ goto cleanup; -+ } -+ -+ buff[0] = '\0'; -+ do { -+ struct outbuffer *where = NULL; -+ -+ /* read in one section worth of lines */ -+ do { -+ if (*buff != '\0') { -+ if (append_line(&outqueue, NULL, strdup(buff))) -+ goto cleanup; -+ } -+ -+ err = read_line(&buff, &buffsize, infile); -+ } while (err == 0 && buff[0] != '['); -+ -+ /* find the section header */ -+ where = TAILQ_FIRST(&outqueue); -+ while (where != NULL) { -+ if (where->text != NULL && where->text[0] == '[') -+ break; -+ where = TAILQ_NEXT(where, link); -+ } -+ -+ /* this is the section we care about */ -+ if (where != NULL && is_section(where->text, section, arg)) { -+ /* is there an existing assignment */ -+ while ((where = TAILQ_NEXT(where, link)) != NULL) { -+ if (is_tag(where->text, tag)) { -+ found = true; -+ break; -+ } -+ } -+ -+ if (found) { -+ struct outbuffer *prev = TAILQ_PREV(where, tailhead, link); -+ bool again = false; -+ -+ /* remove current tag */ -+ do { -+ struct outbuffer *next = TAILQ_NEXT(where, link); -+ TAILQ_REMOVE(&outqueue, where, link); -+ if (is_folded(where->text)) -+ again = true; -+ else -+ again = false; -+ free(where->text); -+ free(where); -+ where = next; -+ } while(again && where != NULL); -+ -+ /* insert new tag */ -+ if (value) { -+ if (append_line(&outqueue, prev, make_tagline(tag, value))) -+ goto cleanup; -+ } -+ } else -+ /* no existing assignment found and we need to add one */ -+ if (value) { -+ /* rewind past blank lines and comments */ -+ struct outbuffer *tail = TAILQ_LAST(&outqueue, tailhead); -+ -+ /* comments immediately before a section usually relate -+ * to the section below them */ -+ while (tail != NULL && is_comment(tail->text)) -+ tail = TAILQ_PREV(tail, tailhead, link); -+ -+ /* there is usually blank line(s) between sections */ -+ while (tail != NULL && is_empty(tail->text)) -+ tail = TAILQ_PREV(tail, tailhead, link); -+ -+ /* now add the tag here */ -+ if (append_line(&outqueue, tail, make_tagline(tag, value))) -+ goto cleanup; -+ -+ found = true; -+ } -+ } -+ -+ /* EOF and correct section not found, so add one */ -+ if (err && !found && value) { -+ /* did the last section end in a blank line */ -+ struct outbuffer *tail = TAILQ_LAST(&outqueue, tailhead); -+ if (tail && !is_empty(tail->text)) { -+ /* no, so add one for clarity */ -+ if (append_line(&outqueue, NULL, strdup("\n"))) -+ goto cleanup; -+ } -+ -+ /* add the new section header */ -+ if (append_line(&outqueue, NULL, make_section(section, arg))) -+ goto cleanup; -+ -+ /* now add the tag */ -+ if (append_line(&outqueue, NULL, make_tagline(tag, value))) -+ goto cleanup; -+ } -+ -+ /* we are done with this section, write it out */ -+ if (flush_outqueue(&outqueue, outfile)) -+ goto cleanup; -+ } while(err == 0); -+ } -+ -+ if (infile) { -+ fclose(infile); -+ infile = NULL; -+ } -+ -+ fdout = -1; -+ if (fclose(outfile)) { -+ xlog(L_ERROR, "Error writing config file: %s", strerror(errno)); -+ goto cleanup; -+ } -+ -+ /* now swap the old file for the new one */ -+ if (rename(outpath, filename)) { -+ xlog(L_ERROR, "Error updating config file: %s: %s\n", filename, strerror(errno)); -+ ret = 1; -+ } else { -+ ret = 0; -+ free(outpath); -+ outpath = NULL; -+ } -+ -+cleanup: -+ flush_outqueue(&outqueue, NULL); -+ -+ if (buff) -+ free(buff); -+ if (infile) -+ fclose(infile); -+ if (fdout != -1) -+ close(fdout); -+ if (outpath) { -+ unlink(outpath); -+ free(outpath); -+ } -+ return ret; -+} -diff --git a/support/nfsidmap/nfsidmap_common.c b/support/nfsidmap/nfsidmap_common.c -index 5242c7e..f89b82e 100644 ---- a/support/nfsidmap/nfsidmap_common.c -+++ b/support/nfsidmap/nfsidmap_common.c -@@ -57,8 +57,10 @@ struct conf_list *get_local_realms(void) - return NULL; - - node->field = calloc(1, NFS4_MAX_DOMAIN_LEN); -- if (node->field == NULL) -+ if (node->field == NULL) { -+ free(node); - return NULL; -+ } - - nfs4_get_default_domain(NULL, node->field, NFS4_MAX_DOMAIN_LEN); - toupper_str(node->field); -diff --git a/support/nfsidmap/umich_ldap.c b/support/nfsidmap/umich_ldap.c -index 0e31b1c..b661110 100644 ---- a/support/nfsidmap/umich_ldap.c -+++ b/support/nfsidmap/umich_ldap.c -@@ -1125,9 +1125,9 @@ umichldap_init(void) - - /* Verify required information is supplied */ - if (server_in == NULL || strlen(server_in) == 0) -- strncat(missing_msg, "LDAP_server ", sizeof(missing_msg)); -+ strncat(missing_msg, "LDAP_server ", sizeof(missing_msg)-1); - if (ldap_info.base == NULL || strlen(ldap_info.base) == 0) -- strncat(missing_msg, "LDAP_base ", sizeof(missing_msg)); -+ strncat(missing_msg, "LDAP_base ", sizeof(missing_msg)-1); - if (strlen(missing_msg) != 0) { - IDMAP_LOG(0, ("umichldap_init: Missing required information: " - "%s", missing_msg)); -diff --git a/systemd/rpc-pipefs-generator.c b/systemd/rpc-pipefs-generator.c -index 6e1d69c..0b5da11 100644 ---- a/systemd/rpc-pipefs-generator.c -+++ b/systemd/rpc-pipefs-generator.c -@@ -35,7 +35,10 @@ static int generate_mount_unit(const char *pipefs_path, const char *pipefs_unit, - sprintf(path, "%s/%s", dirname, pipefs_unit); - f = fopen(path, "w"); - if (!f) -+ { -+ free(path); - return 1; -+ } - - fprintf(f, "# Automatically generated by rpc-pipefs-generator\n\n[Unit]\n"); - fprintf(f, "Description=RPC Pipe File System\n"); -@@ -48,6 +51,7 @@ static int generate_mount_unit(const char *pipefs_path, const char *pipefs_unit, - fprintf(f, "Type=rpc_pipefs\n"); - - fclose(f); -+ free(path); - return 0; - } - -@@ -76,12 +80,16 @@ int generate_target(char *pipefs_path, const char *dirname) - strcat(path, filebase); - f = fopen(path, "w"); - if (!f) -+ { -+ free(path); - return 1; -+ } - - fprintf(f, "# Automatically generated by rpc-pipefs-generator\n\n[Unit]\n"); - fprintf(f, "Requires=%s\n", pipefs_unit); - fprintf(f, "After=%s\n", pipefs_unit); - fclose(f); -+ free(path); - - return 0; - } -diff --git a/tools/nfsconf/nfsconf.man b/tools/nfsconf/nfsconf.man -index 5b5e914..1ae8543 100644 ---- a/tools/nfsconf/nfsconf.man -+++ b/tools/nfsconf/nfsconf.man -@@ -28,6 +28,25 @@ nfsconf \- Query various NFS configuration settings - .IR subsection ] - .IR section - .IR tag -+.P -+.B nfsconf \-\-set -+.RB [ \-v | \-\-verbose ] -+.RB [ \-f | \-\-file -+.IR infile.conf ] -+.RB [ \-a | \-\-arg -+.IR subsection ] -+.IR section -+.IR tag -+.IR value -+.P -+.B nfsconf \-\-unset -+.RB [ \-v | \-\-verbose ] -+.RB [ \-f | \-\-file -+.IR infile.conf ] -+.RB [ \-a | \-\-arg -+.IR subsection ] -+.IR section -+.IR tag - .SH DESCRIPTION - The - .B nfsconf -@@ -41,6 +60,10 @@ Output an alphabetically sorted dump of the current configuration in conf file f - Test if a specific tag has a value set. - .IP "\fB\-g, \-\-get\fP" - Output the current value of the specified tag. -+.IP "\fB\-s, \-\-set\fP" -+Update or Add a tag and value to the config file, creating the file if necessary. -+.IP "\fB\-u, \-\-unset\fP" -+Remove the specified tag and its value from the config file. - .SH OPTIONS - .SS Options valid in all modes - .TP -@@ -56,7 +79,7 @@ Select a different config file to operate upon, default is - Select a specific sub-section - .SH EXIT STATUS - .SS \fB\-\-isset\fR mode --In this mode the command will return success (0) if the selected tag has a value, any other exit code indicates the value is not set, or some other error has occured. -+In this mode the command will return success (0) if the selected tag has a value, any other exit code indicates the value is not set, or some other error has occurred. - .SS all other modes - Success is indicated by an exit status of zero, any other status indicates an error. Error messages are output on stderr, and increasing verbosity will give more detailed explanations if any are available. - .SH EXAMPLES -@@ -64,11 +87,14 @@ Success is indicated by an exit status of zero, any other status indicates an er - .B nfsconf -v --dump --file /tmp/testconf.conf sorted.conf - Check a new config file for syntax errors and output a sorted version for ease of comparison with existing settings. - .TP --.B if ! nfsconf --isset gssd preferred-realm ; then echo 'No prefered realm configured for gss'; fi -+.B if ! nfsconf --isset gssd preferred-realm ; then echo 'No preferred realm configured for gss'; fi - The tool allows for easy testing of configuration values from shell scripts, here we test if a specific value has been set. - .TP - .B nfsconf --file /etc/nfsmount.conf --get --arg /home MountPoint background - Show default value for \fIbackground\fR option for NFS mounts of the \fI/home\fR path. -+.TP -+.B nfsconf --file /etc/nfs.conf --set nfsd debug 1 -+Enable debugging in nfsd - .SH FILES - .TP - .B /etc/nfs.conf -diff --git a/tools/nfsconf/nfsconfcli.c b/tools/nfsconf/nfsconfcli.c -index 034ec51..f98d0d1 100644 ---- a/tools/nfsconf/nfsconfcli.c -+++ b/tools/nfsconf/nfsconfcli.c -@@ -12,7 +12,9 @@ typedef enum { - MODE_NONE, - MODE_GET, - MODE_ISSET, -- MODE_DUMP -+ MODE_DUMP, -+ MODE_SET, -+ MODE_UNSET - } confmode_t; - - static void usage(const char *name) -@@ -29,11 +31,14 @@ static void usage(const char *name) - fprintf(stderr, " Output one specific config value\n"); - fprintf(stderr, " --isset [--arg subsection] {section} {tag}\n"); - fprintf(stderr, " Return code indicates if config value is present\n"); -+ fprintf(stderr, " --set [--arg subsection] {section} {tag} {value}\n"); -+ fprintf(stderr, " Set and Write a config value\n"); -+ fprintf(stderr, " --unset [--arg subsection] {section} {tag}\n"); -+ fprintf(stderr, " Remove an existing config value\n"); - } - - int main(int argc, char **argv) - { -- const char * val; - char * confpath = NFS_CONFFILE; - char * arg = NULL; - int verbose=0; -@@ -47,6 +52,8 @@ int main(int argc, char **argv) - int index = 0; - struct option long_options[] = { - {"get", no_argument, 0, 'g' }, -+ {"set", no_argument, 0, 's' }, -+ {"unset", no_argument, 0, 'u' }, - {"arg", required_argument, 0, 'a' }, - {"isset", no_argument, 0, 'i' }, - {"dump", optional_argument, 0, 'd' }, -@@ -55,14 +62,14 @@ int main(int argc, char **argv) - {NULL, 0, 0, 0 } - }; - -- c = getopt_long(argc, argv, "ga:id::f:v", long_options, &index); -+ c = getopt_long(argc, argv, "gsua:id::f:v", long_options, &index); - if (c == -1) break; - - switch (c) { - case 0: - break; - case 'f': -- /* user specified souce path for config */ -+ /* user specified source path for config */ - confpath = optarg; - break; - case 'a': -@@ -75,6 +82,12 @@ int main(int argc, char **argv) - case 'g': - mode = MODE_GET; - break; -+ case 's': -+ mode = MODE_SET; -+ break; -+ case 'u': -+ mode = MODE_UNSET; -+ break; - case 'i': - mode = MODE_ISSET; - break; -@@ -97,7 +110,7 @@ int main(int argc, char **argv) - xlog_config(D_ALL, 1); - xlog_stderr(1); - xlog_syslog(0); -- xlog_open("nfsconftool"); -+ xlog_open("nfsconf"); - - if (mode == MODE_NONE) { - fprintf(stderr, "Error: No MODE selected.\n"); -@@ -105,14 +118,18 @@ int main(int argc, char **argv) - return 1; - } - -- if (conf_init_file(confpath)) { -- /* config file was missing or had an error, warn about it */ -- if (verbose || mode != MODE_ISSET) -- fprintf(stderr, "Error loading config file %s\n", -- confpath); -- /* this isnt fatal for --isset */ -- if (mode != MODE_ISSET) -- return 1; -+ if (mode != MODE_SET && mode != MODE_UNSET) { -+ if (conf_init_file(confpath)) { -+ /* config file was missing or had an error, warn about it */ -+ if (verbose || mode != MODE_ISSET) { -+ fprintf(stderr, "Error loading config file %s\n", -+ confpath); -+ } -+ -+ /* this isnt fatal for --isset */ -+ if (mode != MODE_ISSET) -+ return 1; -+ } - } - - /* --dump mode, output the current configuration */ -@@ -144,6 +161,7 @@ int main(int argc, char **argv) - if (mode == MODE_GET || mode == MODE_ISSET) { - char * section = NULL; - char * tag = NULL; -+ const char * val; - - /* test they supplied section and tag names */ - if (optind+1 >= argc) { -@@ -169,8 +187,43 @@ int main(int argc, char **argv) - fprintf(stderr, "Tag '%s' not found\n", tag); - ret = 1; - } -+ } else -+ if (mode == MODE_SET || mode == MODE_UNSET) { -+ char * section = NULL; -+ char * tag = NULL; -+ char * val = NULL; -+ int need = 2; -+ -+ if (mode == MODE_UNSET) -+ need = 1; -+ -+ /* test they supplied section and tag names */ -+ if (optind+need >= argc) { -+ fprintf(stderr, "Error: insufficient arguments for mode\n"); -+ usage(argv[0]); -+ ret = 2; -+ goto cleanup; -+ } -+ -+ /* now we have a section and tag name */ -+ section = argv[optind++]; -+ tag = argv[optind++]; -+ if (mode == MODE_SET) -+ val = argv[optind++]; -+ -+ /* setting an empty string is same as unsetting */ -+ if (val!=NULL && *val == '\0') { -+ mode = MODE_UNSET; -+ val = NULL; -+ } -+ -+ if (conf_write(confpath, section, arg, tag, val)) { -+ if (verbose) -+ fprintf(stderr, "Error writing config\n"); -+ ret = 1; -+ } - } else { -- fprintf(stderr, "Mode not yet implimented.\n"); -+ fprintf(stderr, "Mode not yet implemented.\n"); - ret = 2; - } - -diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man -index 4f95f3a..e3a16f6 100644 ---- a/utils/exportfs/exports.man -+++ b/utils/exportfs/exports.man -@@ -131,10 +131,12 @@ this way are ro, rw, no_root_squash, root_squash, and all_squash. - understands the following export options: - .TP - .IR secure --This option requires that requests originate on an Internet port less --than IPPORT_RESERVED (1024). This option is on by default. To turn it --off, specify -+This option requires that requests not using gss originate on an -+Internet port less than IPPORT_RESERVED (1024). This option is on by default. -+To turn it off, specify - .IR insecure . -+(NOTE: older kernels (before upstream kernel version 4.17) enforced this -+requirement on gss requests as well.) - .TP - .IR rw - Allow both read and write requests on this NFS volume. The -diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c -index ce73777..7a57c4e 100644 ---- a/utils/gssd/gssd_proc.c -+++ b/utils/gssd/gssd_proc.c -@@ -434,6 +434,7 @@ static int - change_identity(uid_t uid) - { - struct passwd *pw; -+ int res; - - /* drop list of supplimentary groups first */ - if (syscall(SYS_setgroups, 0, 0) != 0) { -@@ -459,14 +460,23 @@ change_identity(uid_t uid) - * send a signal to all other threads to synchronize the uid in all - * other threads. To bypass this, we have to call syscall() directly. - */ -- if (syscall(SYS_setresgid, pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) { -+#ifdef __NR_setresuid32 -+ res = syscall(SYS_setresgid32, pw->pw_gid, pw->pw_gid, pw->pw_gid); -+#else -+ res = syscall(SYS_setresgid, pw->pw_gid, pw->pw_gid, pw->pw_gid); -+#endif -+ if (res != 0) { - printerr(0, "WARNING: failed to set gid to %u!\n", pw->pw_gid); - return errno; - } - -- if (syscall(SYS_setresuid, uid, uid, uid) != 0) { -- printerr(0, "WARNING: Failed to setuid for user with uid %u\n", -- uid); -+#ifdef __NR_setresuid32 -+ res = syscall(SYS_setresuid32, uid, uid, uid); -+#else -+ res = syscall(SYS_setresuid, uid, uid, uid); -+#endif -+ if (res != 0) { -+ printerr(0, "WARNING: Failed to setuid for user with uid %u\n", uid); - return errno; - } - -@@ -520,8 +530,9 @@ out: - } - - static AUTH * --krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, -- char *service, CLIENT **rpc_clnt) -+krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, -+ char *srchost, char *tgtname, char *service, -+ CLIENT **rpc_clnt) - { - AUTH *auth = NULL; - char **credlist = NULL; -@@ -534,7 +545,7 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, - - do { - gssd_refresh_krb5_machine_credential(clp->servername, NULL, -- service); -+ service, srchost); - /* - * Get a list of credential cache names and try each - * of them until one works or we've tried them all -@@ -594,8 +605,8 @@ out: - * context on behalf of the kernel - */ - static void --process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, -- char *service) -+process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *srchost, -+ char *tgtname, char *service) - { - CLIENT *rpc_clnt = NULL; - AUTH *auth = NULL; -@@ -643,7 +654,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, - if (auth == NULL) { - if (uid == 0 && (root_uses_machine_creds == 1 || - service != NULL)) { -- auth = krb5_use_machine_creds(clp, uid, tgtname, -+ auth = krb5_use_machine_creds(clp, uid, srchost, tgtname, - service, &rpc_clnt); - if (auth == NULL) - goto out_return_error; -@@ -714,7 +725,7 @@ handle_krb5_upcall(struct clnt_upcall_info *info) - - printerr(2, "\n%s: uid %d (%s)\n", __func__, info->uid, clp->relpath); - -- process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL); -+ process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL, NULL); - free(info); - } - -@@ -728,11 +739,12 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - char *uidstr = NULL; - char *target = NULL; - char *service = NULL; -+ char *srchost = NULL; - char *enctypes = NULL; - char *upcall_str; - char *pbuf = info->lbuf; - -- printerr(2, "\n%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath); -+ printerr(2, "%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath); - - upcall_str = strdup(info->lbuf); - if (upcall_str == NULL) { -@@ -751,6 +763,8 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - target = p + strlen("target="); - else if (!strncmp(p, "service=", strlen("service="))) - service = p + strlen("service="); -+ else if (!strncmp(p, "srchost=", strlen("srchost="))) -+ srchost = p + strlen("srchost="); - } - - if (!mech || strlen(mech) < 1) { -@@ -802,7 +816,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) - } - - if (strcmp(mech, "krb5") == 0 && clp->servername) -- process_krb5_upcall(clp, uid, clp->gssd_fd, target, service); -+ process_krb5_upcall(clp, uid, clp->gssd_fd, srchost, target, service); - else { - if (clp->servername) - printerr(0, "WARNING: handle_gssd_upcall: " -@@ -815,4 +829,3 @@ out_nomem: - free(info); - return; - } -- -diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c -index b342b06..eba1aac 100644 ---- a/utils/gssd/krb5_util.c -+++ b/utils/gssd/krb5_util.c -@@ -757,7 +757,8 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, - * the server hostname. - */ - static int --find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, -+find_keytab_entry(krb5_context context, krb5_keytab kt, -+ const char *srchost, const char *tgtname, - krb5_keytab_entry *kte, const char **svcnames) - { - krb5_error_code code; -@@ -781,7 +782,9 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - goto out; - - /* Get full local hostname */ -- if (gethostname(myhostname, sizeof(myhostname)) == -1) { -+ if (srchost) { -+ strcpy(myhostname, srchost); -+ } else if (gethostname(myhostname, sizeof(myhostname)) == -1) { - retval = errno; - k5err = gssd_k5_err_msg(context, retval); - printerr(1, "%s while getting local hostname\n", k5err); -@@ -807,10 +810,12 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, - myhostad[i+1] = 0; - } - -- retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); -- if (retval) { -- /* Don't use myhostname */ -- myhostname[0] = 0; -+ if (!srchost) { -+ retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); -+ if (retval) { -+ /* Don't use myhostname */ -+ myhostname[0] = 0; -+ } - } - - code = krb5_get_default_realm(context, &default_realm); -@@ -1140,7 +1145,7 @@ gssd_get_krb5_machine_cred_list(char ***list) - if (ple->ccname) { - /* Make sure cred is up-to-date before returning it */ - retval = gssd_refresh_krb5_machine_credential(NULL, ple, -- NULL); -+ NULL, NULL); - if (retval) - continue; - if (i + 1 > listsize) { -@@ -1231,7 +1236,7 @@ gssd_destroy_krb5_machine_creds(void) - int - gssd_refresh_krb5_machine_credential(char *hostname, - struct gssd_k5_kt_princ *ple, -- char *service) -+ char *service, char *srchost) - { - krb5_error_code code = 0; - krb5_context context; -@@ -1240,6 +1245,9 @@ gssd_refresh_krb5_machine_credential(char *hostname, - char *k5err = NULL; - const char *svcnames[] = { "$", "root", "nfs", "host", NULL }; - -+ printerr(2, "%s: hostname=%s ple=%p service=%s srchost=%s\n", -+ __func__, hostname, ple, service, srchost); -+ - /* - * If a specific service name was specified, use it. - * Otherwise, use the default list. -@@ -1270,7 +1278,8 @@ gssd_refresh_krb5_machine_credential(char *hostname, - if (ple == NULL) { - krb5_keytab_entry kte; - -- code = find_keytab_entry(context, kt, hostname, &kte, svcnames); -+ code = find_keytab_entry(context, kt, srchost, hostname, -+ &kte, svcnames); - if (code) { - printerr(0, "ERROR: %s: no usable keytab entry found " - "in keytab %s for connection with host %s\n", -diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h -index e3bbb07..b000b44 100644 ---- a/utils/gssd/krb5_util.h -+++ b/utils/gssd/krb5_util.h -@@ -30,7 +30,7 @@ void gssd_free_krb5_machine_cred_list(char **list); - void gssd_destroy_krb5_machine_creds(void); - int gssd_refresh_krb5_machine_credential(char *hostname, - struct gssd_k5_kt_princ *ple, -- char *service); -+ char *service, char *srchost); - char *gssd_k5_err_msg(krb5_context context, krb5_error_code code); - void gssd_k5_get_default_realm(char **def_realm); - -diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c -index b87c4dd..4811e0f 100644 ---- a/utils/idmapd/idmapd.c -+++ b/utils/idmapd/idmapd.c -@@ -310,7 +310,7 @@ main(int argc, char **argv) - if (!serverstart && !clientstart) - errx(1, "it is illegal to specify both -C and -S"); - -- strncat(pipefsdir, "/nfs", sizeof(pipefsdir)); -+ strncat(pipefsdir, "/nfs", sizeof(pipefsdir)-1); - - daemon_init(fg); - -@@ -923,7 +923,8 @@ static int - getfield(char **bpp, char *fld, size_t fldsz) - { - char *bp; -- int val, n; -+ unsigned int val; -+ int n; - - while ((bp = strsep(bpp, " ")) != NULL && bp[0] == '\0') - ; -diff --git a/utils/mount/network.c b/utils/mount/network.c -index e490399..356f663 100644 ---- a/utils/mount/network.c -+++ b/utils/mount/network.c -@@ -50,6 +50,8 @@ - #include - #include - #include -+#include -+#include - - #include "sockaddr.h" - #include "xcommon.h" -@@ -1759,3 +1761,48 @@ int nfs_umount_do_umnt(struct mount_options *options, - - return EX_SUCCESS; - } -+ -+int nfs_is_inaddr_any(struct sockaddr *nfs_saddr) -+{ -+ switch (nfs_saddr->sa_family) { -+ case AF_INET: { -+ if (((struct sockaddr_in *)nfs_saddr)->sin_addr.s_addr == -+ INADDR_ANY) -+ return 1; -+ break; -+ } -+ case AF_INET6: -+ if (!memcmp(&((struct sockaddr_in6 *)nfs_saddr)->sin6_addr, -+ &in6addr_any, sizeof(in6addr_any))) -+ return 1; -+ break; -+ } -+ return 0; -+} -+ -+int nfs_addr_matches_localips(struct sockaddr *nfs_saddr) -+{ -+ struct ifaddrs *myaddrs, *ifa; -+ int found = 0; -+ -+ /* acquire exiting network interfaces */ -+ if (getifaddrs(&myaddrs) != 0) -+ return 0; -+ -+ /* interate over the available interfaces and check if we -+ * we find a match to the supplied clientaddr value -+ */ -+ for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next) { -+ if (ifa->ifa_addr == NULL) -+ continue; -+ if (!(ifa->ifa_flags & IFF_UP)) -+ continue; -+ if (!memcmp(ifa->ifa_addr, nfs_saddr, -+ sizeof(struct sockaddr))) { -+ found = 1; -+ break; -+ } -+ } -+ freeifaddrs(myaddrs); -+ return found; -+} -diff --git a/utils/mount/network.h b/utils/mount/network.h -index ecaac33..0fc98ac 100644 ---- a/utils/mount/network.h -+++ b/utils/mount/network.h -@@ -54,6 +54,8 @@ int nfs_callback_address(const struct sockaddr *, const socklen_t, - int clnt_ping(struct sockaddr_in *, const unsigned long, - const unsigned long, const unsigned int, - struct sockaddr_in *); -+int nfs_is_inaddr_any(struct sockaddr *); -+int nfs_addr_matches_localips(struct sockaddr *); - - struct mount_options; - -diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man -index bd1508c..9ee9bd9 100644 ---- a/utils/mount/nfs.man -+++ b/utils/mount/nfs.man -@@ -835,6 +835,9 @@ to perform NFS version 4.0 callback requests against - files on this mount point. If the server is unable to - establish callback connections to clients, performance - may degrade, or accesses to files may temporarily hang. -+Can specify a value of IPv4_ANY (0.0.0.0) or equivalent -+IPv6 any address which will signal to the NFS server that -+this NFS client does not want delegations. - .IP - If this option is not specified, the - .BR mount (8) -diff --git a/utils/mount/nfs4mount.c b/utils/mount/nfs4mount.c -index 89629ed..3e4f1e2 100644 ---- a/utils/mount/nfs4mount.c -+++ b/utils/mount/nfs4mount.c -@@ -218,7 +218,7 @@ int nfs4mount(const char *spec, const char *node, int flags, - goto fail; - } - if (running_bg) -- strncpy(new_opts, old_opts, sizeof(new_opts)); -+ strncpy(new_opts, old_opts, sizeof(new_opts)-1); - else - snprintf(new_opts, sizeof(new_opts), "%s%saddr=%s", - old_opts, *old_opts ? "," : "", s); -diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c -index ae4a3da..952a755 100644 ---- a/utils/mount/nfsmount.c -+++ b/utils/mount/nfsmount.c -@@ -828,7 +828,7 @@ noauth_flavors: - - data.fd = fsock; - memcpy((char *) &data.addr, (char *) nfs_saddr, sizeof(data.addr)); -- strncpy(data.hostname, hostname, sizeof(data.hostname)); -+ strncpy(data.hostname, hostname, sizeof(data.hostname)-1); - - out_ok: - /* Ensure we have enough padding for the following strcat()s */ -diff --git a/utils/mount/nfsmount.conf b/utils/mount/nfsmount.conf -index aeb3023..6bdc225 100644 ---- a/utils/mount/nfsmount.conf -+++ b/utils/mount/nfsmount.conf -@@ -122,7 +122,7 @@ - # mountproto=tcp - # - # Server Mountd Version --# mounvers=3 -+# mountvers=3 - # - # Server Mountd Host - # mounthost=hostname -diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c -index d1b0708..4d2e37e 100644 ---- a/utils/mount/stropts.c -+++ b/utils/mount/stropts.c -@@ -229,7 +229,8 @@ static int nfs_append_addr_option(const struct sockaddr *sap, - - /* - * Called to discover our address and append an appropriate 'clientaddr=' -- * option to the options string. -+ * option to the options string. If the supplied 'clientaddr=' value does -+ * not match either IPV4/IPv6 any or a local address, then fail the mount. - * - * Returns 1 if 'clientaddr=' option created successfully or if - * 'clientaddr=' option is already present; otherwise zero. -@@ -242,8 +243,27 @@ static int nfs_append_clientaddr_option(const struct sockaddr *sap, - struct sockaddr *my_addr = &address.sa; - socklen_t my_len = sizeof(address); - -- if (po_contains(options, "clientaddr") == PO_FOUND) -+ if (po_contains(options, "clientaddr") == PO_FOUND) { -+ char *addr = po_get(options, "clientaddr"); -+ union nfs_sockaddr nfs_address; -+ struct sockaddr *nfs_saddr = &nfs_address.sa; -+ socklen_t nfs_salen = sizeof(nfs_address); -+ -+ /* translate the input for clientaddr to nfs_sockaddr */ -+ if (!nfs_string_to_sockaddr(addr, nfs_saddr, &nfs_salen)) -+ return 0; -+ -+ /* check for IPV4_ANY and IPV6_ANY */ -+ if (nfs_is_inaddr_any(nfs_saddr)) -+ return 1; -+ -+ /* check if ip matches local network addresses */ -+ if (!nfs_addr_matches_localips(nfs_saddr)) -+ nfs_error(_("%s: [warning] supplied clientaddr=%s " -+ "does not match any existing network " -+ "addresses"), progname, addr); - return 1; -+ } - - nfs_callback_address(sap, salen, my_addr, &my_len); - -diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c -index 4c68702..086c39b 100644 ---- a/utils/mountd/mountd.c -+++ b/utils/mountd/mountd.c -@@ -702,7 +702,7 @@ main(int argc, char **argv) - else - NFSCTL_TCPUNSET(_rpcprotobits); - for (vers = 2; vers <= 4; vers++) { -- char tag[10]; -+ char tag[20]; - sprintf(tag, "vers%d", vers); - if (conf_get_bool("nfsd", tag, NFSCTL_VERISSET(nfs_version, vers))) - NFSCTL_VERSET(nfs_version, vers); -diff --git a/utils/mountd/v4root.c b/utils/mountd/v4root.c -index f978f4c..d735dbf 100644 ---- a/utils/mountd/v4root.c -+++ b/utils/mountd/v4root.c -@@ -92,7 +92,7 @@ v4root_create(char *path, nfs_export *export) - - dupexportent(&eep, &pseudo_root.m_export); - eep.e_hostname = curexp->e_hostname; -- strncpy(eep.e_path, path, sizeof(eep.e_path)); -+ strncpy(eep.e_path, path, sizeof(eep.e_path)-1); - if (strcmp(path, "/") != 0) - eep.e_flags &= ~NFSEXP_FSID; - set_pseudofs_security(&eep, curexp->e_flags); -diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c -index 2303a5d..f048631 100644 ---- a/utils/nfsd/nfsd.c -+++ b/utils/nfsd/nfsd.c -@@ -98,7 +98,7 @@ main(int argc, char **argv) - else - NFSCTL_TCPUNSET(protobits); - for (i = 2; i <= 4; i++) { -- char tag[10]; -+ char tag[20]; - sprintf(tag, "vers%d", i); - if (conf_get_bool("nfsd", tag, NFSCTL_VERISSET(versbits, i))) - NFSCTL_VERSET(versbits, i); -diff --git a/utils/nfsdcltrack/nfsdcltrack.c b/utils/nfsdcltrack/nfsdcltrack.c -index 76b06d2..b45a904 100644 ---- a/utils/nfsdcltrack/nfsdcltrack.c -+++ b/utils/nfsdcltrack/nfsdcltrack.c -@@ -553,7 +553,7 @@ find_cmd(char *cmdname) - int - main(int argc, char **argv) - { -- char arg; -+ int arg; - char *val; - int rc = 0; - char *progname, *cmdarg = NULL; -diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c -index 374bc5d..d3967a3 100644 ---- a/utils/nfsidmap/nfsidmap.c -+++ b/utils/nfsidmap/nfsidmap.c -@@ -283,7 +283,7 @@ static int key_invalidate(char *keystr, int keymask) - { - FILE *fp; - char buf[BUFSIZ], *ptr; -- key_serial_t key; -+ unsigned int key; - int mask; - - xlog_syslog(0); -diff --git a/utils/nfsstat/nfsstat.c b/utils/nfsstat/nfsstat.c -index c779053..ca84532 100644 ---- a/utils/nfsstat/nfsstat.c -+++ b/utils/nfsstat/nfsstat.c -@@ -340,7 +340,7 @@ static struct option longopts[] = - { "all", 0, 0, 'v' }, - { "auto", 0, 0, '\3' }, - { "client", 0, 0, 'c' }, -- { "mounted", 0, 0, 'm' }, -+ { "mounts", 0, 0, 'm' }, - { "nfs", 0, 0, 'n' }, - { "rpc", 0, 0, 'r' }, - { "server", 0, 0, 's' }, -@@ -1013,7 +1013,7 @@ mounts(const char *name) - * be a fatal error -- it usually means the module isn't loaded. - */ - if ((fp = fopen(name, "r")) == NULL) { -- fprintf(stderr, "Warning: %s: %m\n", name); -+ fprintf(stderr, "Warning: %s: %s\n", name, strerror(errno)); - return 0; - } - -@@ -1089,8 +1089,8 @@ out: - fclose(fp); - if (err) { - if (!other_opt) { -- fprintf(stderr, "Error: No %s Stats (%s: %m). \n", -- label, file); -+ fprintf(stderr, "Error: No %s Stats (%s: %s). \n", -+ label, file, strerror(errno)); - exit(2); - } - *opt = 0; -diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c -index 6d19ec1..7a48473 100644 ---- a/utils/statd/sm-notify.c -+++ b/utils/statd/sm-notify.c -@@ -569,7 +569,7 @@ usage: fprintf(stderr, - if (name == NULL) - exit(1); - -- strncpy(nsm_hostname, name, sizeof(nsm_hostname)); -+ strncpy(nsm_hostname, name, sizeof(nsm_hostname)-1); - free(name); - } - -diff --git a/utils/statd/statd.c b/utils/statd/statd.c -index 563a272..2cc6cf3 100644 ---- a/utils/statd/statd.c -+++ b/utils/statd/statd.c -@@ -231,11 +231,12 @@ static void set_nlm_port(char *type, int port) - } - if (fd >= 0) { - if (write(fd, nbuf, strlen(nbuf)) != (ssize_t)strlen(nbuf)) -- fprintf(stderr, "%s: fail to set NLM %s port: %m\n", -- name_p, type); -+ fprintf(stderr, "%s: fail to set NLM %s port: %s\n", -+ name_p, type, strerror(errno)); - close(fd); - } else -- fprintf(stderr, "%s: failed to open %s: %m\n", name_p, pathbuf); -+ fprintf(stderr, "%s: failed to open %s: %s\n", -+ name_p, pathbuf, strerror(errno)); - } - - /*