From 3936b52ffe14841433a76880b63ab99a85e1e464 Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Tue, 24 Sep 2013 15:38:11 -0400 Subject: [PATCH] Updated to latest upstream RC release: nfs-utils-1-2-9-rc6 Signed-off-by: Steve Dickson --- nfs-utils-1.2.1-exp-subtree-warn-off.patch | 6 +- nfs-utils.1.2.9-rc6.patch | 1597 ++++++++++++++++++++ nfs-utils.spec | 7 +- 3 files changed, 1605 insertions(+), 5 deletions(-) create mode 100644 nfs-utils.1.2.9-rc6.patch diff --git a/nfs-utils-1.2.1-exp-subtree-warn-off.patch b/nfs-utils-1.2.1-exp-subtree-warn-off.patch index ff60c7d..69c4cb5 100644 --- a/nfs-utils-1.2.1-exp-subtree-warn-off.patch +++ b/nfs-utils-1.2.1-exp-subtree-warn-off.patch @@ -1,7 +1,7 @@ diff -up nfs-utils-1.2.8/support/nfs/exports.c.orig nfs-utils-1.2.8/support/nfs/exports.c ---- nfs-utils-1.2.8/support/nfs/exports.c.orig 2013-09-18 15:34:18.655550000 -0400 -+++ nfs-utils-1.2.8/support/nfs/exports.c 2013-09-18 15:35:01.173808000 -0400 -@@ -505,7 +505,7 @@ void fix_pseudoflavor_flags(struct expor +--- nfs-utils-1.2.8/support/nfs/exports.c.orig 2013-09-24 15:35:26.022548905 -0400 ++++ nfs-utils-1.2.8/support/nfs/exports.c 2013-09-24 15:35:51.274547991 -0400 +@@ -508,7 +508,7 @@ void fix_pseudoflavor_flags(struct expor static int parseopts(char *cp, struct exportent *ep, int warn, int *had_subtree_opt_ptr) { diff --git a/nfs-utils.1.2.9-rc6.patch b/nfs-utils.1.2.9-rc6.patch new file mode 100644 index 0000000..998c4b6 --- /dev/null +++ b/nfs-utils.1.2.9-rc6.patch @@ -0,0 +1,1597 @@ +diff --git a/support/include/conffile.h b/support/include/conffile.h +index ce7aa21..05ea5d2 100644 +--- a/support/include/conffile.h ++++ b/support/include/conffile.h +@@ -54,7 +54,7 @@ extern int conf_end(int, int); + extern void conf_free_list(struct conf_list *); + extern struct sockaddr *conf_get_address(char *, char *); + extern struct conf_list *conf_get_list(char *, char *); +-extern struct conf_list *conf_get_tag_list(char *); ++extern struct conf_list *conf_get_tag_list(char *, char *); + extern int conf_get_num(char *, char *, int); + extern char *conf_get_str(char *, char *); + extern char *conf_get_section(char *, char *, char *); +diff --git a/support/include/nfs/nfs.h b/support/include/nfs/nfs.h +index 174c2dd..38db5b5 100644 +--- a/support/include/nfs/nfs.h ++++ b/support/include/nfs/nfs.h +@@ -15,6 +15,10 @@ + #define NFSD_MINVERS 2 + #define NFSD_MAXVERS 4 + ++#define NFS4_MINMINOR 1 ++#define NFS4_MAXMINOR 2 ++#define NFS4_VERDEFAULT 0x1 /* minor verion 1 */ ++ + struct nfs_fh_len { + int fh_size; + u_int8_t fh_handle[NFS3_FHSIZE]; +@@ -52,6 +56,7 @@ struct nfs_fh_old { + #define NFSCTL_UDPISSET(_cltbits) ((_cltbits) & NFSCTL_UDPBIT) + #define NFSCTL_TCPISSET(_cltbits) ((_cltbits) & NFSCTL_TCPBIT) + ++#define NFSCTL_VERDEFAULT (0xc) /* versions 3 and 4 */ + #define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << ((_v) - 1))) + #define NFSCTL_UDPSET(_cltbits) ((_cltbits) |= NFSCTL_UDPBIT) + #define NFSCTL_TCPSET(_cltbits) ((_cltbits) |= NFSCTL_TCPBIT) +diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h +index a0b80e1..1bfae7a 100644 +--- a/support/include/nfsrpc.h ++++ b/support/include/nfsrpc.h +@@ -156,6 +156,11 @@ extern unsigned long nfs_pmap_getport(const struct sockaddr_in *, + const struct timeval *); + + /* ++ * Use nfs_pmap_getport to see if statd is running locally ++ */ ++extern int nfs_probe_statd(void); ++ ++/* + * Contact a remote RPC service to discover whether it is responding + * to requests. + */ +diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c +index 5015e94..c3434d5 100644 +--- a/support/nfs/conffile.c ++++ b/support/nfs/conffile.c +@@ -565,7 +565,7 @@ cleanup: + } + + struct conf_list * +-conf_get_tag_list(char *section) ++conf_get_tag_list(char *section, char *arg) + { + struct conf_list *list = 0; + struct conf_list_node *node; +@@ -579,6 +579,8 @@ conf_get_tag_list(char *section) + cb = LIST_FIRST(&conf_bindings[conf_hash (section)]); + for (; cb; cb = LIST_NEXT(cb, link)) { + if (strcasecmp (section, cb->section) == 0) { ++ if (arg != NULL && strcasecmp(arg, cb->arg) != 0) ++ continue; + list->cnt++; + node = calloc(1, sizeof *node); + if (!node) +diff --git a/support/nfs/exports.c b/support/nfs/exports.c +index dea040f..d3160d3 100644 +--- a/support/nfs/exports.c ++++ b/support/nfs/exports.c +@@ -63,6 +63,7 @@ static int parsesquash(char *list, int **idp, int *lenp, char **ep); + static int parsenum(char **cpp); + static void freesquash(void); + static void syntaxerr(char *msg); ++static struct flav_info *find_flavor(char *name); + + void + setexportent(char *fname, char *type) +@@ -196,11 +197,38 @@ getexportent(int fromkernel, int fromexports) + return ⅇ + } + ++static const struct secinfo_flag_displaymap { ++ unsigned int flag; ++ 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" }, ++ { 0, NULL, NULL } ++}; ++ ++static void secinfo_flags_show(FILE *fp, unsigned int flags, unsigned int mask) ++{ ++ const struct secinfo_flag_displaymap *p; ++ ++ for (p = &secinfo_flag_displaymap[0]; p->flag != 0; p++) { ++ if (!(mask & p->flag)) ++ continue; ++ fprintf(fp, ",%s", (flags & p->flag) ? p->set : p->unset); ++ } ++} ++ + void secinfo_show(FILE *fp, struct exportent *ep) + { ++ const struct export_features *ef; + struct sec_entry *p1, *p2; +- int flags; + ++ ef = get_export_features(); ++ ++ if (ep->e_secinfo[0].flav == NULL) ++ secinfo_addflavor(find_flavor("sys"), ep); + for (p1=ep->e_secinfo; p1->flav; p1=p2) { + + fprintf(fp, ",sec=%s", p1->flav->flavour); +@@ -208,12 +236,7 @@ void secinfo_show(FILE *fp, struct exportent *ep) + p2++) { + fprintf(fp, ":%s", p2->flav->flavour); + } +- flags = p1->flags; +- fprintf(fp, ",%s", (flags & NFSEXP_READONLY) ? "ro" : "rw"); +- fprintf(fp, ",%sroot_squash", (flags & NFSEXP_ROOTSQUASH)? +- "" : "no_"); +- fprintf(fp, ",%sall_squash", (flags & NFSEXP_ALLSQUASH)? +- "" : "no_"); ++ secinfo_flags_show(fp, p1->flags, ef->secinfo_flags); + } + } + +@@ -643,8 +666,6 @@ bad_option: + cp++; + } + +- if (ep->e_secinfo[0].flav == NULL) +- secinfo_addflavor(find_flavor("sys"), ep); + fix_pseudoflavor_flags(ep); + ep->e_squids = squids; + ep->e_sqgids = sqgids; +diff --git a/support/nfs/getport.c b/support/nfs/getport.c +index 3331ad4..081594c 100644 +--- a/support/nfs/getport.c ++++ b/support/nfs/getport.c +@@ -1102,3 +1102,25 @@ unsigned long nfs_pmap_getport(const struct sockaddr_in *sin, + + return port; + } ++ ++static const char *nfs_ns_pgmtbl[] = { ++ "status", ++ NULL, ++}; ++ ++/* ++ * nfs_probe_statd - use nfs_pmap_getport to see if statd is running locally ++ * ++ * Returns non-zero if statd is running locally. ++ */ ++int nfs_probe_statd(void) ++{ ++ struct sockaddr_in addr = { ++ .sin_family = AF_INET, ++ .sin_addr.s_addr = htonl(INADDR_LOOPBACK), ++ }; ++ rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); ++ ++ return nfs_getport_ping((struct sockaddr *)(char *)&addr, sizeof(addr), ++ program, (rpcvers_t)1, IPPROTO_UDP); ++} +diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py +index b95b71d..3f5fea5 100644 +--- a/tools/mountstats/mountstats.py ++++ b/tools/mountstats/mountstats.py +@@ -53,7 +53,7 @@ class DeviceData: + if words[6].find('nfs') != -1: + self.__nfs_data['statvers'] = words[7] + elif words[0] == 'age:': +- self.__nfs_data['age'] = long(words[1]) ++ self.__nfs_data['age'] = int(words[1]) + elif words[0] == 'opts:': + self.__nfs_data['mountoptions'] = ''.join(words[1:]).split(',') + elif words[0] == 'caps:': +@@ -91,12 +91,12 @@ class DeviceData: + self.__nfs_data['shortwrites'] = int(words[22]) + self.__nfs_data['delay'] = int(words[23]) + elif words[0] == 'bytes:': +- self.__nfs_data['normalreadbytes'] = long(words[1]) +- self.__nfs_data['normalwritebytes'] = long(words[2]) +- self.__nfs_data['directreadbytes'] = long(words[3]) +- self.__nfs_data['directwritebytes'] = long(words[4]) +- self.__nfs_data['serverreadbytes'] = long(words[5]) +- self.__nfs_data['serverwritebytes'] = long(words[6]) ++ self.__nfs_data['normalreadbytes'] = int(words[1]) ++ self.__nfs_data['normalwritebytes'] = int(words[2]) ++ self.__nfs_data['directreadbytes'] = int(words[3]) ++ self.__nfs_data['directwritebytes'] = int(words[4]) ++ self.__nfs_data['serverreadbytes'] = int(words[5]) ++ self.__nfs_data['serverwritebytes'] = int(words[6]) + + def __parse_rpc_line(self, words): + if words[0] == 'RPC': +@@ -110,8 +110,8 @@ class DeviceData: + self.__rpc_data['rpcsends'] = int(words[4]) + self.__rpc_data['rpcreceives'] = int(words[5]) + self.__rpc_data['badxids'] = int(words[6]) +- self.__rpc_data['inflightsends'] = long(words[7]) +- self.__rpc_data['backlogutil'] = long(words[8]) ++ self.__rpc_data['inflightsends'] = int(words[7]) ++ self.__rpc_data['backlogutil'] = int(words[8]) + elif words[1] == 'tcp': + self.__rpc_data['port'] = words[2] + self.__rpc_data['bind_count'] = int(words[3]) +@@ -121,7 +121,7 @@ class DeviceData: + self.__rpc_data['rpcsends'] = int(words[7]) + self.__rpc_data['rpcreceives'] = int(words[8]) + self.__rpc_data['badxids'] = int(words[9]) +- self.__rpc_data['inflightsends'] = long(words[10]) ++ self.__rpc_data['inflightsends'] = int(words[10]) + self.__rpc_data['backlogutil'] = int(words[11]) + elif words[1] == 'rdma': + self.__rpc_data['port'] = words[2] +@@ -148,7 +148,7 @@ class DeviceData: + else: + op = words[0][:-1] + self.__rpc_data['ops'] += [op] +- self.__rpc_data[op] = [long(word) for word in words[1:]] ++ self.__rpc_data[op] = [int(word) for word in words[1:]] + + def parse_stats(self, lines): + """Turn a list of lines from a mount stat file into a +@@ -179,81 +179,81 @@ class DeviceData: + def display_nfs_options(self): + """Pretty-print the NFS options + """ +- print 'Stats for %s mounted on %s:' % \ +- (self.__nfs_data['export'], self.__nfs_data['mountpoint']) +- +- print ' NFS mount options: %s' % ','.join(self.__nfs_data['mountoptions']) +- print ' NFS server capabilities: %s' % ','.join(self.__nfs_data['servercapabilities']) +- if self.__nfs_data.has_key('nfsv4flags'): +- print ' NFSv4 capability flags: %s' % ','.join(self.__nfs_data['nfsv4flags']) +- if self.__nfs_data.has_key('pseudoflavor'): +- print ' NFS security flavor: %d pseudoflavor: %d' % \ +- (self.__nfs_data['flavor'], self.__nfs_data['pseudoflavor']) ++ print('Stats for %s mounted on %s:' % \ ++ (self.__nfs_data['export'], self.__nfs_data['mountpoint'])) ++ ++ 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: ++ print(' NFSv4 capability flags: %s' % ','.join(self.__nfs_data['nfsv4flags'])) ++ if 'pseudoflavor' in self.__nfs_data: ++ print(' NFS security flavor: %d pseudoflavor: %d' % \ ++ (self.__nfs_data['flavor'], self.__nfs_data['pseudoflavor'])) + else: +- print ' NFS security flavor: %d' % self.__nfs_data['flavor'] ++ print(' NFS security flavor: %d' % self.__nfs_data['flavor']) + + def display_nfs_events(self): + """Pretty-print the NFS event counters + """ +- print +- print 'Cache events:' +- print ' data cache invalidated %d times' % self.__nfs_data['datainvalidates'] +- print ' attribute cache invalidated %d times' % self.__nfs_data['attrinvalidates'] +- print ' inodes synced %d times' % self.__nfs_data['syncinodes'] +- print +- print 'VFS calls:' +- print ' VFS requested %d inode revalidations' % self.__nfs_data['inoderevalidates'] +- print ' VFS requested %d dentry revalidations' % self.__nfs_data['dentryrevalidates'] +- print +- print ' VFS called nfs_readdir() %d times' % self.__nfs_data['vfsreaddir'] +- print ' VFS called nfs_lookup() %d times' % self.__nfs_data['vfslookup'] +- print ' VFS called nfs_permission() %d times' % self.__nfs_data['vfspermission'] +- print ' VFS called nfs_file_open() %d times' % self.__nfs_data['vfsopen'] +- print ' VFS called nfs_file_flush() %d times' % self.__nfs_data['vfsflush'] +- print ' VFS called nfs_lock() %d times' % self.__nfs_data['vfslock'] +- print ' VFS called nfs_fsync() %d times' % self.__nfs_data['vfsfsync'] +- print ' VFS called nfs_file_release() %d times' % self.__nfs_data['vfsrelease'] +- print +- print 'VM calls:' +- print ' VFS called nfs_readpage() %d times' % self.__nfs_data['vfsreadpage'] +- print ' VFS called nfs_readpages() %d times' % self.__nfs_data['vfsreadpages'] +- print ' VFS called nfs_writepage() %d times' % self.__nfs_data['vfswritepage'] +- print ' VFS called nfs_writepages() %d times' % self.__nfs_data['vfswritepages'] +- print +- print 'Generic NFS counters:' +- print ' File size changing operations:' +- print ' truncating SETATTRs: %d extending WRITEs: %d' % \ +- (self.__nfs_data['setattrtrunc'], self.__nfs_data['extendwrite']) +- print ' %d silly renames' % self.__nfs_data['sillyrenames'] +- print ' short reads: %d short writes: %d' % \ +- (self.__nfs_data['shortreads'], self.__nfs_data['shortwrites']) +- print ' NFSERR_DELAYs from server: %d' % self.__nfs_data['delay'] ++ print() ++ print('Cache events:') ++ print(' data cache invalidated %d times' % self.__nfs_data['datainvalidates']) ++ print(' attribute cache invalidated %d times' % self.__nfs_data['attrinvalidates']) ++ print(' inodes synced %d times' % self.__nfs_data['syncinodes']) ++ print() ++ print('VFS calls:') ++ print(' VFS requested %d inode revalidations' % self.__nfs_data['inoderevalidates']) ++ print(' VFS requested %d dentry revalidations' % self.__nfs_data['dentryrevalidates']) ++ print() ++ print(' VFS called nfs_readdir() %d times' % self.__nfs_data['vfsreaddir']) ++ print(' VFS called nfs_lookup() %d times' % self.__nfs_data['vfslookup']) ++ print(' VFS called nfs_permission() %d times' % self.__nfs_data['vfspermission']) ++ print(' VFS called nfs_file_open() %d times' % self.__nfs_data['vfsopen']) ++ print(' VFS called nfs_file_flush() %d times' % self.__nfs_data['vfsflush']) ++ print(' VFS called nfs_lock() %d times' % self.__nfs_data['vfslock']) ++ print(' VFS called nfs_fsync() %d times' % self.__nfs_data['vfsfsync']) ++ print(' VFS called nfs_file_release() %d times' % self.__nfs_data['vfsrelease']) ++ print() ++ print('VM calls:') ++ print(' VFS called nfs_readpage() %d times' % self.__nfs_data['vfsreadpage']) ++ print(' VFS called nfs_readpages() %d times' % self.__nfs_data['vfsreadpages']) ++ print(' VFS called nfs_writepage() %d times' % self.__nfs_data['vfswritepage']) ++ print(' VFS called nfs_writepages() %d times' % self.__nfs_data['vfswritepages']) ++ print() ++ print('Generic NFS counters:') ++ print(' File size changing operations:') ++ print(' truncating SETATTRs: %d extending WRITEs: %d' % \ ++ (self.__nfs_data['setattrtrunc'], self.__nfs_data['extendwrite'])) ++ print(' %d silly renames' % self.__nfs_data['sillyrenames']) ++ print(' short reads: %d short writes: %d' % \ ++ (self.__nfs_data['shortreads'], self.__nfs_data['shortwrites'])) ++ print(' NFSERR_DELAYs from server: %d' % self.__nfs_data['delay']) + + def display_nfs_bytes(self): + """Pretty-print the NFS event counters + """ +- print +- print 'NFS byte counts:' +- print ' applications read %d bytes via read(2)' % self.__nfs_data['normalreadbytes'] +- print ' applications wrote %d bytes via write(2)' % self.__nfs_data['normalwritebytes'] +- print ' applications read %d bytes via O_DIRECT read(2)' % self.__nfs_data['directreadbytes'] +- print ' applications wrote %d bytes via O_DIRECT write(2)' % self.__nfs_data['directwritebytes'] +- print ' client read %d bytes via NFS READ' % self.__nfs_data['serverreadbytes'] +- print ' client wrote %d bytes via NFS WRITE' % self.__nfs_data['serverwritebytes'] ++ print() ++ print('NFS byte counts:') ++ print(' applications read %d bytes via read(2)' % self.__nfs_data['normalreadbytes']) ++ print(' applications wrote %d bytes via write(2)' % self.__nfs_data['normalwritebytes']) ++ print(' applications read %d bytes via O_DIRECT read(2)' % self.__nfs_data['directreadbytes']) ++ print(' applications wrote %d bytes via O_DIRECT write(2)' % self.__nfs_data['directwritebytes']) ++ print(' client read %d bytes via NFS READ' % self.__nfs_data['serverreadbytes']) ++ print(' client wrote %d bytes via NFS WRITE' % self.__nfs_data['serverwritebytes']) + + def display_rpc_generic_stats(self): + """Pretty-print the generic RPC stats + """ + sends = self.__rpc_data['rpcsends'] + +- print +- print 'RPC statistics:' ++ print() ++ print('RPC statistics:') + +- print ' %d RPC requests sent, %d RPC replies received (%d XIDs not found)' % \ +- (sends, self.__rpc_data['rpcreceives'], self.__rpc_data['badxids']) ++ print(' %d RPC requests sent, %d RPC replies received (%d XIDs not found)' % \ ++ (sends, self.__rpc_data['rpcreceives'], self.__rpc_data['badxids'])) + if sends != 0: +- print ' average backlog queue length: %d' % \ +- (float(self.__rpc_data['backlogutil']) / sends) ++ print(' average backlog queue length: %d' % \ ++ (float(self.__rpc_data['backlogutil']) / sends)) + + def display_rpc_op_stats(self): + """Pretty-print the per-op stats +@@ -261,23 +261,23 @@ class DeviceData: + sends = self.__rpc_data['rpcsends'] + + # XXX: these should be sorted by 'count' +- print ++ print() + for op in self.__rpc_data['ops']: + stats = self.__rpc_data[op] + count = stats[0] + retrans = stats[1] - count + if count != 0: +- print '%s:' % op +- print '\t%d ops (%d%%)' % \ +- (count, ((count * 100) / sends)), +- print '\t%d retrans (%d%%)' % (retrans, ((retrans * 100) / count)), +- print '\t%d major timeouts' % stats[2] +- print '\tavg bytes sent per op: %d\tavg bytes received per op: %d' % \ +- (stats[3] / count, stats[4] / count) +- print '\tbacklog wait: %f' % (float(stats[5]) / count), +- print '\tRTT: %f' % (float(stats[6]) / count), +- print '\ttotal execute time: %f (milliseconds)' % \ +- (float(stats[7]) / count) ++ print('%s:' % op) ++ print('\t%d ops (%d%%)' % \ ++ (count, ((count * 100) / sends)), end=' ') ++ print('\t%d retrans (%d%%)' % (retrans, ((retrans * 100) / count)), end=' ') ++ print('\t%d major timeouts' % stats[2]) ++ print('\tavg bytes sent per op: %d\tavg bytes received per op: %d' % \ ++ (stats[3] / count, stats[4] / count)) ++ print('\tbacklog wait: %f' % (float(stats[5]) / count), end=' ') ++ print('\tRTT: %f' % (float(stats[6]) / count), end=' ') ++ print('\ttotal execute time: %f (milliseconds)' % \ ++ (float(stats[7]) / count)) + + def compare_iostats(self, old_stats): + """Return the difference between two sets of stats +@@ -285,9 +285,9 @@ class DeviceData: + result = DeviceData() + + # copy self into result +- for key, value in self.__nfs_data.iteritems(): ++ for key, value in self.__nfs_data.items(): + result.__nfs_data[key] = value +- for key, value in self.__rpc_data.iteritems(): ++ for key, value in self.__rpc_data.items(): + result.__rpc_data[key] = value + + # compute the difference of each item in the list +@@ -295,7 +295,7 @@ class DeviceData: + # the reference to them. so we build new lists here + # for the result object. + for op in result.__rpc_data['ops']: +- result.__rpc_data[op] = map(difference, self.__rpc_data[op], old_stats.__rpc_data[op]) ++ result.__rpc_data[op] = list(map(difference, self.__rpc_data[op], old_stats.__rpc_data[op])) + + # update the remaining keys we care about + result.__rpc_data['rpcsends'] -= old_stats.__rpc_data['rpcsends'] +@@ -312,17 +312,17 @@ class DeviceData: + if sample_time == 0: + sample_time = float(self.__nfs_data['age']) + +- print +- print '%s mounted on %s:' % \ +- (self.__nfs_data['export'], self.__nfs_data['mountpoint']) ++ print() ++ print('%s mounted on %s:' % \ ++ (self.__nfs_data['export'], self.__nfs_data['mountpoint'])) + +- print '\top/s\trpc bklog' +- print '\t%.2f' % (sends / sample_time), ++ print('\top/s\trpc bklog') ++ print('\t%.2f' % (sends / sample_time), end=' ') + if sends != 0: +- print '\t%.2f' % \ +- ((float(self.__rpc_data['backlogutil']) / sends) / sample_time) ++ print('\t%.2f' % \ ++ ((float(self.__rpc_data['backlogutil']) / sends) / sample_time)) + else: +- print '\t0.00' ++ print('\t0.00') + + # reads: ops/s, kB/s, avg rtt, and avg exe + # XXX: include avg xfer size and retransmits? +@@ -332,15 +332,15 @@ class DeviceData: + rtt = float(read_rpc_stats[6]) + exe = float(read_rpc_stats[7]) + +- print '\treads:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)' +- print '\t\t%.2f' % (ops / sample_time), +- print '\t\t%.2f' % (kilobytes / sample_time), ++ print('\treads:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)') ++ print('\t\t%.2f' % (ops / sample_time), end=' ') ++ print('\t\t%.2f' % (kilobytes / sample_time), end=' ') + if ops != 0: +- print '\t\t%.2f' % (rtt / ops), +- print '\t\t%.2f' % (exe / ops) ++ print('\t\t%.2f' % (rtt / ops), end=' ') ++ print('\t\t%.2f' % (exe / ops)) + else: +- print '\t\t0.00', +- print '\t\t0.00' ++ print('\t\t0.00', end=' ') ++ print('\t\t0.00') + + # writes: ops/s, kB/s, avg rtt, and avg exe + # XXX: include avg xfer size and retransmits? +@@ -350,15 +350,15 @@ class DeviceData: + rtt = float(write_rpc_stats[6]) + exe = float(write_rpc_stats[7]) + +- print '\twrites:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)' +- print '\t\t%.2f' % (ops / sample_time), +- print '\t\t%.2f' % (kilobytes / sample_time), ++ print('\twrites:\tops/s\t\tkB/s\t\tavg RTT (ms)\tavg exe (ms)') ++ print('\t\t%.2f' % (ops / sample_time), end=' ') ++ print('\t\t%.2f' % (kilobytes / sample_time), end=' ') + if ops != 0: +- print '\t\t%.2f' % (rtt / ops), +- print '\t\t%.2f' % (exe / ops) ++ print('\t\t%.2f' % (rtt / ops), end=' ') ++ print('\t\t%.2f' % (exe / ops)) + else: +- print '\t\t0.00', +- print '\t\t0.00' ++ print('\t\t0.00', end=' ') ++ print('\t\t0.00') + + def parse_stats_file(filename): + """pop the contents of a mountstats file into a dictionary, +@@ -388,18 +388,18 @@ def parse_stats_file(filename): + return ms_dict + + def print_mountstats_help(name): +- print 'usage: %s [ options ] ' % name +- print +- print ' Version %s' % Mountstats_version +- print +- print ' Display NFS client per-mount statistics.' +- print +- print ' --version display the version of this command' +- print ' --nfs display only the NFS statistics' +- print ' --rpc display only the RPC statistics' +- print ' --start sample and save statistics' +- print ' --end resample statistics and compare them with saved' +- print ++ print('usage: %s [ options ] ' % name) ++ print() ++ print(' Version %s' % Mountstats_version) ++ print() ++ print(' Display NFS client per-mount statistics.') ++ print() ++ print(' --version display the version of this command') ++ print(' --nfs display only the NFS statistics') ++ print(' --rpc display only the RPC statistics') ++ print(' --start sample and save statistics') ++ print(' --end resample statistics and compare them with saved') ++ print() + + def mountstats_command(): + """Mountstats command +@@ -414,7 +414,7 @@ def mountstats_command(): + return + + if arg in ['-v', '--version', 'version']: +- print '%s version %s' % (sys.argv[0], Mountstats_version) ++ print('%s version %s' % (sys.argv[0], Mountstats_version)) + sys.exit(0) + + if arg in ['-n', '--nfs']: +@@ -426,10 +426,10 @@ def mountstats_command(): + continue + + if arg in ['-s', '--start']: +- raise Exception, 'Sampling is not yet implemented' ++ raise Exception('Sampling is not yet implemented') + + if arg in ['-e', '--end']: +- raise Exception, 'Sampling is not yet implemented' ++ raise Exception('Sampling is not yet implemented') + + if arg == sys.argv[0]: + continue +@@ -448,14 +448,14 @@ def mountstats_command(): + + for mp in mountpoints: + if mp not in mountstats: +- print 'Statistics for mount point %s not found' % mp ++ print('Statistics for mount point %s not found' % mp) + continue + + stats = DeviceData() + stats.parse_stats(mountstats[mp]) + + if not stats.is_nfs_mountpoint(): +- print 'Mount point %s exists but is not an NFS mount' % mp ++ print('Mount point %s exists but is not an NFS mount' % mp) + continue + + if nfs_only: +@@ -472,37 +472,37 @@ def mountstats_command(): + stats.display_rpc_op_stats() + + def print_nfsstat_help(name): +- print 'usage: %s [ options ]' % name +- print +- print ' Version %s' % Mountstats_version +- print +- print ' nfsstat-like program that uses NFS client per-mount statistics.' +- print ++ print('usage: %s [ options ]' % name) ++ print() ++ print(' Version %s' % Mountstats_version) ++ print() ++ print(' nfsstat-like program that uses NFS client per-mount statistics.') ++ print() + + def nfsstat_command(): + print_nfsstat_help(prog) + + def print_iostat_help(name): +- print 'usage: %s [ [ ] ] [ ] ' % name +- print +- print ' Version %s' % Mountstats_version +- print +- print ' iostat-like program to display NFS client per-mount statistics.' +- print +- print ' The parameter specifies the amount of time in seconds between' +- print ' each report. The first report contains statistics for the time since each' +- print ' file system was mounted. Each subsequent report contains statistics' +- print ' collected during the interval since the previous report.' +- print +- print ' If the parameter is specified, the value of determines the' +- print ' number of reports generated at seconds apart. If the interval' +- print ' parameter is specified without the parameter, the command generates' +- print ' reports continuously.' +- print +- print ' If one or more names are specified, statistics for only these' +- print ' mount points will be displayed. Otherwise, all NFS mount points on the' +- print ' client are listed.' +- print ++ print('usage: %s [ [ ] ] [ ] ' % name) ++ print() ++ print(' Version %s' % Mountstats_version) ++ print() ++ print(' iostat-like program to display NFS client per-mount statistics.') ++ print() ++ print(' The parameter specifies the amount of time in seconds between') ++ print(' each report. The first report contains statistics for the time since each') ++ print(' file system was mounted. Each subsequent report contains statistics') ++ print(' collected during the interval since the previous report.') ++ print() ++ print(' If the parameter is specified, the value of determines the') ++ print(' number of reports generated at seconds apart. If the interval') ++ print(' parameter is specified without the parameter, the command generates') ++ print(' reports continuously.') ++ print() ++ print(' If one or more names are specified, statistics for only these') ++ print(' mount points will be displayed. Otherwise, all NFS mount points on the') ++ print(' client are listed.') ++ print() + + def print_iostat_summary(old, new, devices, time): + for device in devices: +@@ -530,7 +530,7 @@ def iostat_command(): + return + + if arg in ['-v', '--version', 'version']: +- print '%s version %s' % (sys.argv[0], Mountstats_version) ++ print('%s version %s' % (sys.argv[0], Mountstats_version)) + return + + if arg == sys.argv[0]: +@@ -543,14 +543,14 @@ def iostat_command(): + if interval > 0: + interval_seen = True + else: +- print 'Illegal value' ++ print('Illegal value') + return + elif not count_seen: + count = int(arg) + if count > 0: + count_seen = True + else: +- print 'Illegal value' ++ print('Illegal value') + return + + # make certain devices contains only NFS mount points +@@ -563,13 +563,13 @@ def iostat_command(): + check += [device] + devices = check + else: +- for device, descr in mountstats.iteritems(): ++ for device, descr in mountstats.items(): + stats = DeviceData() + stats.parse_stats(descr) + if stats.is_nfs_mountpoint(): + devices += [device] + if len(devices) == 0: +- print 'No NFS mount points were found' ++ print('No NFS mount points were found') + return + + old_mountstats = None +@@ -608,7 +608,7 @@ try: + elif prog == 'ms-iostat': + iostat_command() + except KeyboardInterrupt: +- print 'Caught ^C... exiting' ++ print('Caught ^C... exiting') + sys.exit(1) + + sys.exit(0) +diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py +index dfbef87..341cdbf 100644 +--- a/tools/nfs-iostat/nfs-iostat.py ++++ b/tools/nfs-iostat/nfs-iostat.py +@@ -95,7 +95,7 @@ class DeviceData: + if words[6] == 'nfs': + self.__nfs_data['statvers'] = words[7] + elif words[0] == 'age:': +- self.__nfs_data['age'] = long(words[1]) ++ self.__nfs_data['age'] = int(words[1]) + elif words[0] == 'opts:': + self.__nfs_data['mountoptions'] = ''.join(words[1:]).split(',') + elif words[0] == 'caps:': +@@ -116,7 +116,7 @@ class DeviceData: + elif words[0] == 'bytes:': + i = 1 + for key in NfsByteCounters: +- self.__nfs_data[key] = long(words[i]) ++ self.__nfs_data[key] = int(words[i]) + i += 1 + + def __parse_rpc_line(self, words): +@@ -131,8 +131,8 @@ class DeviceData: + self.__rpc_data['rpcsends'] = int(words[4]) + self.__rpc_data['rpcreceives'] = int(words[5]) + self.__rpc_data['badxids'] = int(words[6]) +- self.__rpc_data['inflightsends'] = long(words[7]) +- self.__rpc_data['backlogutil'] = long(words[8]) ++ self.__rpc_data['inflightsends'] = int(words[7]) ++ self.__rpc_data['backlogutil'] = int(words[8]) + elif words[1] == 'tcp': + self.__rpc_data['port'] = words[2] + self.__rpc_data['bind_count'] = int(words[3]) +@@ -142,8 +142,8 @@ class DeviceData: + self.__rpc_data['rpcsends'] = int(words[7]) + self.__rpc_data['rpcreceives'] = int(words[8]) + self.__rpc_data['badxids'] = int(words[9]) +- self.__rpc_data['inflightsends'] = long(words[10]) +- self.__rpc_data['backlogutil'] = long(words[11]) ++ self.__rpc_data['inflightsends'] = int(words[10]) ++ self.__rpc_data['backlogutil'] = int(words[11]) + elif words[1] == 'rdma': + self.__rpc_data['port'] = words[2] + self.__rpc_data['bind_count'] = int(words[3]) +@@ -169,7 +169,7 @@ class DeviceData: + else: + op = words[0][:-1] + self.__rpc_data['ops'] += [op] +- self.__rpc_data[op] = [long(word) for word in words[1:]] ++ self.__rpc_data[op] = [int(word) for word in words[1:]] + + def parse_stats(self, lines): + """Turn a list of lines from a mount stat file into a +@@ -271,7 +271,7 @@ class DeviceData: + nfs_stats = self.__nfs_data + lookup_ops = self.__rpc_data['LOOKUP'][0] + readdir_ops = self.__rpc_data['READDIR'][0] +- if self.__rpc_data.has_key('READDIRPLUS'): ++ if 'READDIRPLUS' in self.__rpc_data: + readdir_ops += self.__rpc_data['READDIRPLUS'][0] + + dentry_revals = nfs_stats['dentryrevalidates'] +@@ -330,7 +330,7 @@ class DeviceData: + def __print_rpc_op_stats(self, op, sample_time): + """Print generic stats for one RPC op + """ +- if not self.__rpc_data.has_key(op): ++ if op not in self.__rpc_data: + return + + rpc_stats = self.__rpc_data[op] +@@ -353,14 +353,14 @@ class DeviceData: + exe_per_op = 0.0 + + op += ':' +- print('%s' % op.lower().ljust(15)) ++ print('%s' % op.lower().ljust(15), end='') + print(' ops/s\t\t kB/s\t\t kB/op\t\tretrans\t\tavg RTT (ms)\tavg exe (ms)') + +- print('\t\t%7.3f' % (ops / sample_time)) +- print('\t%7.3f' % (kilobytes / sample_time)) +- print('\t%7.3f' % kb_per_op) +- print(' %7d (%3.1f%%)' % (retrans, retrans_percent)) +- print('\t%7.3f' % rtt_per_op) ++ print('\t\t%7.3f' % (ops / sample_time), end='') ++ print('\t%7.3f' % (kilobytes / sample_time), end='') ++ print('\t%7.3f' % kb_per_op, end='') ++ print(' %7d (%3.1f%%)' % (retrans, retrans_percent), end='') ++ print('\t%7.3f' % rtt_per_op, end='') + print('\t%7.3f' % exe_per_op) + + def ops(self, sample_time): +@@ -392,7 +392,7 @@ class DeviceData: + print() + + print(' op/s\t\trpc bklog') +- print('%7.2f' % (sends / sample_time)) ++ print('%7.2f' % (sends / sample_time), end='') + print('\t%7.2f' % backlog) + + if which == 0: +@@ -405,7 +405,7 @@ class DeviceData: + elif which == 2: + self.__print_rpc_op_stats('LOOKUP', sample_time) + self.__print_rpc_op_stats('READDIR', sample_time) +- if self.__rpc_data.has_key('READDIRPLUS'): ++ if 'READDIRPLUS' in self.__rpc_data: + self.__print_rpc_op_stats('READDIRPLUS', sample_time) + self.__print_dir_cache_stats(sample_time) + elif which == 3: +@@ -413,6 +413,8 @@ class DeviceData: + self.__print_rpc_op_stats('WRITE', sample_time) + self.__print_page_stats(sample_time) + ++ sys.stdout.flush() ++ + # + # Functions + # +@@ -450,7 +452,7 @@ def print_iostat_summary(old, new, devices, time, options): + if old: + # Trim device list to only include intersection of old and new data, + # this addresses umounts due to autofs mountpoints +- devicelist = filter(lambda x:x in devices,old) ++ devicelist = [x for x in old if x in devices] + else: + devicelist = devices + +diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c +index 9f79541..4331697 100644 +--- a/utils/exportfs/exportfs.c ++++ b/utils/exportfs/exportfs.c +@@ -420,7 +420,7 @@ static int test_export(char *path, int with_fsid) + char buf[1024]; + int fd, n; + +- sprintf(buf, "-test-client- %s 3 %d -1 -1 0\n", ++ sprintf(buf, "-test-client- %s 3 %d 65534 65534 0\n", + path, + with_fsid ? NFSEXP_FSID : 0); + fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); +diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man +index bc1de73..58c0f66 100644 +--- a/utils/exportfs/exports.man ++++ b/utils/exportfs/exports.man +@@ -39,7 +39,7 @@ the export name using a backslash followed by the character code as three + octal digits. + .PP + To apply changes to this file, run +-.BR exportfs \-ra ++.BR "exportfs \-ra" + or restart the NFS server. + .PP + .SS Machine Name Formats +diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man +index 1df75c5..ac13fd4 100644 +--- a/utils/gssd/gssd.man ++++ b/utils/gssd/gssd.man +@@ -195,11 +195,28 @@ option when starting + .BR rpc.gssd . + .SH OPTIONS + .TP +-.B -D +-DNS Reverse lookups are not used for determining the +-server names pass to GSSAPI. This option will reverses that and forces +-the use of DNS Reverse resolution of the server's IP address to +-retrieve the server name to use in GSAPI authentication. ++.B \-D ++The server name passed to GSSAPI for authentication is normally the ++name exactly as requested. e.g. for NFS ++it is the server name in the "servername:/path" mount request. Only if this ++servername appears to be an IP address (IPv4 or IPv6) or an ++unqualified name (no dots) will a reverse DNS lookup ++will be performed to get the canoncial server name. ++ ++If ++.B \-D ++is present, a reverse DNS lookup will ++.I always ++be used, even if the server name looks like a canonical name. So it ++is needed if partially qualified, or non canonical names are regularly ++used. ++ ++Using ++.B \-D ++can introduce a security vulnerability, so it is recommended that ++.B \-D ++not be used, and that canonical names always be used when requesting ++services. + .TP + .B -f + Runs +diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c +index af1844c..e58c341 100644 +--- a/utils/gssd/gssd_proc.c ++++ b/utils/gssd/gssd_proc.c +@@ -67,7 +67,6 @@ + #include + #include + #include +-#include + + #include "gssd.h" + #include "err_util.h" +@@ -176,7 +175,6 @@ get_servername(const char *name, const struct sockaddr *sa, const char *addr) + char *hostname; + char hbuf[NI_MAXHOST]; + unsigned char buf[sizeof(struct in6_addr)]; +- int servername = 0; + + if (avoid_dns) { + /* +@@ -184,15 +182,18 @@ get_servername(const char *name, const struct sockaddr *sa, const char *addr) + * If it is an IP address, do the DNS lookup otherwise + * skip the DNS lookup. + */ +- servername = 0; +- if (strchr(name, '.') && inet_pton(AF_INET, name, buf) == 1) +- servername = 1; /* IPv4 */ +- else if (strchr(name, ':') && inet_pton(AF_INET6, name, buf) == 1) +- servername = 1; /* or IPv6 */ +- +- if (servername) { ++ int is_fqdn = 1; ++ if (strchr(name, '.') == NULL) ++ is_fqdn = 0; /* local name */ ++ else if (inet_pton(AF_INET, name, buf) == 1) ++ is_fqdn = 0; /* IPv4 address */ ++ else if (inet_pton(AF_INET6, name, buf) == 1) ++ is_fqdn = 0; /* IPv6 addrss */ ++ ++ if (is_fqdn) { + return strdup(name); + } ++ /* Sorry, cannot avoid dns after all */ + } + + switch (sa->sa_family) { +@@ -466,8 +467,9 @@ process_clnt_dir(char *dir, char *pdir) + } + sprintf(clp->dirname, "%s/%s", pdir, dir); + if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) { +- printerr(0, "ERROR: can't open %s: %s\n", +- clp->dirname, strerror(errno)); ++ if (errno != ENOENT) ++ printerr(0, "ERROR: can't open %s: %s\n", ++ clp->dirname, strerror(errno)); + goto fail_destroy_client; + } + fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL); +@@ -523,7 +525,7 @@ update_old_clients(struct dirent **namelist, int size, char *pdir) + /* only compare entries in the global list that are from the + * same pipefs parent directory as "pdir" + */ +- if (strncmp(clp->dirname, pdir, strlen(pdir)) != 0) continue; ++ if (strcmp(clp->dirname, pdir) != 0) continue; + + stillhere = 0; + for (i=0; i < size; i++) { +@@ -820,6 +822,7 @@ set_port: + */ + static int + create_auth_rpc_client(struct clnt_info *clp, ++ char *tgtname, + CLIENT **clnt_return, + AUTH **auth_return, + uid_t uid, +@@ -924,14 +927,16 @@ create_auth_rpc_client(struct clnt_info *clp, + clnt_spcreateerror(rpc_errmsg)); + goto out_fail; + } ++ if (!tgtname) ++ tgtname = clp->servicename; + +- printerr(2, "creating context with server %s\n", clp->servicename); +- auth = authgss_create_default(rpc_clnt, clp->servicename, &sec); ++ printerr(2, "creating context with server %s\n", tgtname); ++ auth = authgss_create_default(rpc_clnt, tgtname, &sec); + if (!auth) { + /* Our caller should print appropriate message */ + printerr(2, "WARNING: Failed to create krb5 context for " + "user with uid %d for server %s\n", +- uid, clp->servername); ++ uid, tgtname); + goto out_fail; + } + +@@ -1013,7 +1018,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, + /* Try first to acquire credentials directly via GSSAPI */ + err = gssd_acquire_user_cred(uid, &gss_cred); + if (!err) +- create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, ++ create_resp = create_auth_rpc_client(clp, tgtname, &rpc_clnt, &auth, uid, + AUTHTYPE_KRB5, gss_cred); + /* if create_auth_rplc_client fails try the traditional method of + * trolling for credentials */ +@@ -1022,7 +1027,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, + if (err == -EKEYEXPIRED) + downcall_err = -EKEYEXPIRED; + else if (!err) +- create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, ++ create_resp = create_auth_rpc_client(clp, tgtname, &rpc_clnt, &auth, uid, + AUTHTYPE_KRB5, GSS_C_NO_CREDENTIAL); + } + } +@@ -1033,8 +1038,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, + int success = 0; + do { + gssd_refresh_krb5_machine_credential(clp->servername, +- NULL, service, +- tgtname); ++ NULL, service); + /* + * Get a list of credential cache names and try each + * of them until one works or we've tried them all +@@ -1047,7 +1051,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, + } + for (ccname = credlist; ccname && *ccname; ccname++) { + gssd_setup_krb5_machine_gss_ccache(*ccname); +- if ((create_auth_rpc_client(clp, &rpc_clnt, ++ if ((create_auth_rpc_client(clp, tgtname, &rpc_clnt, + &auth, uid, + AUTHTYPE_KRB5, + GSS_C_NO_CREDENTIAL)) == 0) { +diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c +index 6275dd8..c6e52fd 100644 +--- a/utils/gssd/krb5_util.c ++++ b/utils/gssd/krb5_util.c +@@ -231,7 +231,7 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, + continue; + } + if (uid == 0 && !root_uses_machine_creds && +- strstr(namelist[i]->d_name, "_machine_")) { ++ strstr(namelist[i]->d_name, "machine_")) { + printerr(3, "CC '%s' not available to root\n", + statname); + free(namelist[i]); +@@ -825,8 +825,10 @@ 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) +- goto out; ++ if (retval) { ++ /* Don't use myhostname */ ++ myhostname[0] = 0; ++ } + + code = krb5_get_default_realm(context, &default_realm); + if (code) { +@@ -852,11 +854,19 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, + } + + /* +- * Try the "appropriate" realm first, and if nothing found for that +- * realm, try the default realm (if it hasn't already been tried). ++ * Make sure the preferred_realm, which may have been explicitly set ++ * on the command line, is tried first. If nothing is found go on with ++ * the host and local default realm (if that hasn't already been tried). + */ + i = 0; + realm = realmnames[i]; ++ ++ if (strcmp (realm, preferred_realm) != 0) { ++ realm = preferred_realm; ++ /* resetting the realmnames index */ ++ i = -1; ++ } ++ + while (1) { + if (realm == NULL) { + tried_all = 1; +@@ -883,6 +893,8 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname, + myhostad, + NULL); + } else { ++ if (!myhostname[0]) ++ continue; + snprintf(spn, sizeof(spn), "%s/%s@%s", + svcnames[j], myhostname, realm); + code = krb5_build_principal_ext(context, &princ, +@@ -1137,7 +1149,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) { +@@ -1228,15 +1240,14 @@ gssd_destroy_krb5_machine_creds(void) + int + gssd_refresh_krb5_machine_credential(char *hostname, + struct gssd_k5_kt_princ *ple, +- char *service, +- char *tgtname) ++ char *service) + { + krb5_error_code code = 0; + krb5_context context; + krb5_keytab kt = NULL;; + int retval = 0; + char *k5err = NULL; +- const char *svcnames[5] = { "$", "root", "nfs", "host", NULL }; ++ const char *svcnames[] = { "$", "root", "nfs", "host", NULL }; + + /* + * If a specific service name was specified, use it. +@@ -1268,10 +1279,7 @@ gssd_refresh_krb5_machine_credential(char *hostname, + if (ple == NULL) { + krb5_keytab_entry kte; + +- if (tgtname == NULL) +- tgtname = hostname; +- +- code = find_keytab_entry(context, kt, tgtname, &kte, svcnames); ++ code = find_keytab_entry(context, kt, 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 eed1294..3f0723e 100644 +--- a/utils/gssd/krb5_util.h ++++ b/utils/gssd/krb5_util.h +@@ -31,8 +31,7 @@ void gssd_setup_krb5_machine_gss_ccache(char *servername); + void gssd_destroy_krb5_machine_creds(void); + int gssd_refresh_krb5_machine_credential(char *hostname, + struct gssd_k5_kt_princ *ple, +- char *service, +- char *tgtname); ++ char *service); + 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 beba9c4..b6c6231 100644 +--- a/utils/idmapd/idmapd.c ++++ b/utils/idmapd/idmapd.c +@@ -502,7 +502,7 @@ nfsdcb(int UNUSED(fd), short which, void *data) + struct idmap_client *ic = data; + struct idmap_msg im; + u_char buf[IDMAP_MAXMSGSZ + 1]; +- size_t len; ++ ssize_t len; + ssize_t bsiz; + char *bp, typebuf[IDMAP_MAXMSGSZ], + buf1[IDMAP_MAXMSGSZ], authbuf[IDMAP_MAXMSGSZ], *p; +@@ -511,10 +511,14 @@ nfsdcb(int UNUSED(fd), short which, void *data) + if (which != EV_READ) + goto out; + +- if ((len = read(ic->ic_fd, buf, sizeof(buf))) <= 0) { ++ len = read(ic->ic_fd, buf, sizeof(buf)); ++ if (len == 0) ++ /* No upcall to read; not necessarily a problem: */ ++ return; ++ if (len < 0) { + xlog_warn("nfsdcb: read(%s) failed: errno %d (%s)", +- ic->ic_path, len?errno:0, +- len?strerror(errno):"End of File"); ++ ic->ic_path, errno, ++ strerror(errno)); + nfsdreopen_one(ic); + return; + } +diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c +index 6f2ee75..68b9f93 100644 +--- a/utils/mount/configfile.c ++++ b/utils/mount/configfile.c +@@ -73,6 +73,8 @@ struct mnt_alias { + }; + int mnt_alias_sz = (sizeof(mnt_alias_tab)/sizeof(mnt_alias_tab[0])); + ++static int strict; ++ + /* + * See if the option is an alias, if so return the + * real mount option along with the argument type. +@@ -286,7 +288,7 @@ conf_parse_mntopts(char *section, char *arg, char *opts) + char *nvalue, *ptr; + int argtype; + +- list = conf_get_tag_list(section); ++ list = conf_get_tag_list(section, arg); + TAILQ_FOREACH(node, &list->fields, link) { + /* + * Do not overwrite options if already exists +@@ -310,7 +312,15 @@ conf_parse_mntopts(char *section, char *arg, char *opts) + if (strcasecmp(value, "false") == 0) { + if (argtype != MNT_NOARG) + snprintf(buf, BUFSIZ, "no%s", field); ++ else if (strcasecmp(field, "bg") == 0) ++ snprintf(buf, BUFSIZ, "fg"); ++ else if (strcasecmp(field, "fg") == 0) ++ snprintf(buf, BUFSIZ, "bg"); ++ else if (strcasecmp(field, "sloppy") == 0) ++ strict = 1; + } else if (strcasecmp(value, "true") == 0) { ++ if ((strcasecmp(field, "sloppy") == 0) && strict) ++ continue; + snprintf(buf, BUFSIZ, "%s", field); + } else { + nvalue = strdup(value); +@@ -345,6 +355,7 @@ char *conf_get_mntopts(char *spec, char *mount_point, + char *ptr, *server, *config_opts; + int optlen = 0; + ++ strict = 0; + SLIST_INIT(&head); + list_size = 0; + /* +diff --git a/utils/mount/network.c b/utils/mount/network.c +index 4be48cd..e2cdcaf 100644 +--- a/utils/mount/network.c ++++ b/utils/mount/network.c +@@ -65,11 +65,6 @@ extern int nfs_mount_data_version; + extern char *progname; + extern int verbose; + +-static const char *nfs_ns_pgmtbl[] = { +- "status", +- NULL, +-}; +- + static const char *nfs_mnt_pgmtbl[] = { + "mount", + "mountd", +@@ -761,18 +756,6 @@ int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server) + &nfs_server->pmap); + } + +-static int nfs_probe_statd(void) +-{ +- struct sockaddr_in addr = { +- .sin_family = AF_INET, +- .sin_addr.s_addr = htonl(INADDR_LOOPBACK), +- }; +- rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); +- +- return nfs_getport_ping(SAFE_SOCKADDR(&addr), sizeof(addr), +- program, (rpcvers_t)1, IPPROTO_UDP); +-} +- + /** + * start_statd - attempt to start rpc.statd + * +diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man +index a8ec46c..2a42b93 100644 +--- a/utils/mount/nfs.man ++++ b/utils/mount/nfs.man +@@ -84,6 +84,20 @@ in + .SS "Options supported by all versions" + These options are valid to use with any NFS version. + .TP 1.5i ++.BI nfsvers= n ++The NFS protocol version number used to contact the server's NFS service. ++If the server does not support the requested version, the mount request ++fails. ++If this option is not specified, the client negotiates a suitable version ++with ++the server, trying version 4 first, version 3 second, and version 2 last. ++.TP 1.5i ++.BI vers= n ++This option is an alternative to the ++.B nfsvers ++option. ++It is included for compatibility with other operating systems ++.TP 1.5i + .BR soft " / " hard + Determines the recovery behavior of the NFS client + after an NFS request times out. +@@ -621,18 +635,6 @@ Using this option ensures that + reports the proper maximum component length to applications + in such cases. + .TP 1.5i +-.BI nfsvers= n +-The NFS protocol version number used to contact the server's NFS service. +-If the server does not support the requested version, the mount request fails. +-If this option is not specified, the client negotiates a suitable version with +-the server, trying version 4 first, version 3 second, and version 2 last. +-.TP 1.5i +-.BI vers= n +-This option is an alternative to the +-.B nfsvers +-option. +-It is included for compatibility with other operating systems. +-.TP 1.5i + .BR lock " / " nolock + Selects whether to use the NLM sideband protocol to lock files on the server. + If neither option is specified (or if +diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c +index 737927c..517aa62 100644 +--- a/utils/mountd/cache.c ++++ b/utils/mountd/cache.c +@@ -347,20 +347,26 @@ static char *next_mnt(void **v, char *p) + + static int is_subdirectory(char *child, char *parent) + { ++ /* Check is child is strictly a subdirectory of ++ * parent or a more distant descendant. ++ */ + size_t l = strlen(parent); + +- if (strcmp(parent, "/") == 0) ++ if (strcmp(parent, "/") == 0 && child[1] != 0) + return 1; + +- return strcmp(child, parent) == 0 +- || (strncmp(child, parent, l) == 0 && child[l] == '/'); ++ return (strncmp(child, parent, l) == 0 && child[l] == '/'); + } + + static int path_matches(nfs_export *exp, char *path) + { +- if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) +- return is_subdirectory(path, exp->m_export.e_path); +- return strcmp(path, exp->m_export.e_path) == 0; ++ /* Does the path match the export? I.e. is it an ++ * exact match, or does the export have CROSSMOUNT, and path ++ * is a descendant? ++ */ ++ return strcmp(path, exp->m_export.e_path) == 0 ++ || ((exp->m_export.e_flags & NFSEXP_CROSSMOUNT) ++ && is_subdirectory(path, exp->m_export.e_path)); + } + + static int +@@ -369,15 +375,13 @@ export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai) + return path_matches(exp, path) && client_matches(exp, dom, ai); + } + +-/* True iff e1 is a child of e2 and e2 has crossmnt set: */ ++/* True iff e1 is a child of e2 (or descendant) and e2 has crossmnt set: */ + static bool subexport(struct exportent *e1, struct exportent *e2) + { + char *p1 = e1->e_path, *p2 = e2->e_path; +- size_t l2 = strlen(p2); + + return e2->e_flags & NFSEXP_CROSSMOUNT +- && strncmp(p1, p2, l2) == 0 +- && p1[l2] == '/'; ++ && is_subdirectory(p1, p2); + } + + struct parsed_fsid { +diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c +index e87c0a9..6db92f0 100644 +--- a/utils/nfsd/nfsd.c ++++ b/utils/nfsd/nfsd.c +@@ -99,8 +99,8 @@ main(int argc, char **argv) + char *p, *progname, *port; + char *haddr = NULL; + int socket_up = 0; +- int minorvers41 = 0; /* nfsv4 minor version */ +- unsigned int versbits = NFSCTL_ALLBITS; ++ int minorvers = NFS4_VERDEFAULT; /* nfsv4 minor version */ ++ unsigned int versbits = NFSCTL_VERDEFAULT; + unsigned int protobits = NFSCTL_ALLBITS; + unsigned int proto4 = 0; + unsigned int proto6 = 0; +@@ -160,11 +160,11 @@ main(int argc, char **argv) + case 4: + if (*p == '.') { + int i = atoi(p+1); +- if (i != 1) { ++ if (i > 2) { + fprintf(stderr, "%s: unsupported minor version\n", optarg); + exit(1); + } +- minorvers41 = -1; ++ NFSCTL_VERUNSET(minorvers, i); + break; + } + case 3: +@@ -181,11 +181,11 @@ main(int argc, char **argv) + case 4: + if (*p == '.') { + int i = atoi(p+1); +- if (i != 1) { ++ if (i > 2) { + fprintf(stderr, "%s: unsupported minor version\n", optarg); + exit(1); + } +- minorvers41 = 1; ++ NFSCTL_VERSET(minorvers, i); + break; + } + case 3: +@@ -282,7 +282,7 @@ main(int argc, char **argv) + * registered with rpcbind. Note that on older kernels w/o the right + * interfaces, these are a no-op. + */ +- nfssvc_setvers(versbits, minorvers41); ++ nfssvc_setvers(versbits, minorvers); + + error = nfssvc_set_sockets(AF_INET, proto4, haddr, port); + if (!error) +diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c +index 683008e..8b85846 100644 +--- a/utils/nfsd/nfssvc.c ++++ b/utils/nfsd/nfssvc.c +@@ -269,7 +269,7 @@ nfssvc_set_sockets(const int family, const unsigned int protobits, + } + + void +-nfssvc_setvers(unsigned int ctlbits, int minorvers41) ++nfssvc_setvers(unsigned int ctlbits, int minorvers) + { + int fd, n, off; + char *ptr; +@@ -280,9 +280,12 @@ nfssvc_setvers(unsigned int ctlbits, int minorvers41) + if (fd < 0) + return; + +- if (minorvers41) +- off += snprintf(ptr+off, sizeof(buf) - off, "%c4.1", +- minorvers41 > 0 ? '+' : '-'); ++ for (n = NFS4_MINMINOR; n <= NFS4_MAXMINOR; n++) { ++ if (NFSCTL_VERISSET(minorvers, n)) ++ off += snprintf(ptr+off, sizeof(buf) - off, "+4.%d ", n); ++ else ++ off += snprintf(ptr+off, sizeof(buf) - off, "-4.%d ", n); ++ } + for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) { + if (NFSCTL_VERISSET(ctlbits, n)) + off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n); +diff --git a/utils/nfsdcltrack/nfsdcltrack.man b/utils/nfsdcltrack/nfsdcltrack.man +index 47007df..6940788 100644 +--- a/utils/nfsdcltrack/nfsdcltrack.man ++++ b/utils/nfsdcltrack/nfsdcltrack.man +@@ -1,53 +1,3 @@ +-.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) +-.\" +-.\" Standard preamble: +-.\" ======================================================================== +-.de Sp \" Vertical space (when we can't use .PP) +-.if t .sp .5v +-.if n .sp +-.. +-.de Vb \" Begin verbatim text +-.ft CW +-.nf +-.ne \\$1 +-.. +-.de Ve \" End verbatim text +-.ft R +-.fi +-.. +-.\" Set up some character translations and predefined strings. \*(-- will +-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +-.\" double quote, and \*(R" will give a right double quote. \*(C+ will +-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +-.\" nothing in troff, for use with C<>. +-.tr \(*W- +-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +-.ie n \{\ +-. ds -- \(*W- +-. ds PI pi +-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +-. ds L" "" +-. ds R" "" +-. ds C` "" +-. ds C' "" +-'br\} +-.el\{\ +-. ds -- \|\(em\| +-. ds PI \(*p +-. ds L" `` +-. ds R" '' +-'br\} +-.\" +-.\" Escape single quotes in literal strings from groff's Unicode transform. +-.ie \n(.g .ds Aq \(aq +-.el .ds Aq ' +-.\" +-.\" If the F register is turned on, we'll generate index entries on stderr for +-.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +-.\" entries marked with X<> in POD. Of course, you'll have to process the +-.\" output yourself in some meaningful fashion. + .ie \nF \{\ + . de IX + . tm Index:\\$1\t\\n%\t"\\$2" +@@ -59,70 +9,6 @@ + . de IX + .. + .\} +-.\" +-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +-.\" Fear. Run. Save yourself. No user-serviceable parts. +-. \" fudge factors for nroff and troff +-.if n \{\ +-. ds #H 0 +-. ds #V .8m +-. ds #F .3m +-. ds #[ \f1 +-. ds #] \fP +-.\} +-.if t \{\ +-. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +-. ds #V .6m +-. ds #F 0 +-. ds #[ \& +-. ds #] \& +-.\} +-. \" simple accents for nroff and troff +-.if n \{\ +-. ds ' \& +-. ds ` \& +-. ds ^ \& +-. ds , \& +-. ds ~ ~ +-. ds / +-.\} +-.if t \{\ +-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +-.\} +-. \" troff and (daisy-wheel) nroff accents +-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +-.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +-.ds ae a\h'-(\w'a'u*4/10)'e +-.ds Ae A\h'-(\w'A'u*4/10)'E +-. \" corrections for vroff +-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +-. \" for low resolution devices (crt and lpr) +-.if \n(.H>23 .if \n(.V>19 \ +-\{\ +-. ds : e +-. ds 8 ss +-. ds o a +-. ds d- d\h'-1'\(ga +-. ds D- D\h'-1'\(hy +-. ds th \o'bp' +-. ds Th \o'LP' +-. ds ae ae +-. ds Ae AE +-.\} +-.rm #[ #] #H #V #F C +-.\" ======================================================================== +-.\" + .IX Title "NFSDCLTRACK 8" + .TH NFSDCLTRACK 8 "2012-10-24" "" "" + .\" For nroff, turn off justification. Always turn off hyphenation; it makes +diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am +index c0675c4..737a219 100644 +--- a/utils/nfsidmap/Makefile.am ++++ b/utils/nfsidmap/Makefile.am +@@ -1,9 +1,10 @@ + ## Process this file with automake to produce Makefile.in + + man8_MANS = nfsidmap.man +- + sbin_PROGRAMS = nfsidmap ++ + nfsidmap_SOURCES = nfsidmap.c + nfsidmap_LDADD = $(LIBNFSIDMAP) -lkeyutils ../../support/nfs/libnfs.a + + MAINTAINERCLEANFILES = Makefile.in ++EXTRA_DIST = id_resolver.conf +diff --git a/utils/nfsidmap/id_resolver.conf b/utils/nfsidmap/id_resolver.conf +new file mode 100644 +index 0000000..2c156c6 +--- /dev/null ++++ b/utils/nfsidmap/id_resolver.conf +@@ -0,0 +1 @@ ++create id_resolver * * /usr/sbin/nfsidmap -t 600 %k %d +diff --git a/utils/statd/statd.c b/utils/statd/statd.c +index 652546c..8c51bcc 100644 +--- a/utils/statd/statd.c ++++ b/utils/statd/statd.c +@@ -28,6 +28,7 @@ + + #include "statd.h" + #include "nfslib.h" ++#include "nfsrpc.h" + #include "nsm.h" + + /* Socket operations */ +@@ -237,6 +238,12 @@ int main (int argc, char **argv) + /* Set hostname */ + MY_NAME = NULL; + ++ /* Refuse to start if another statd is running */ ++ if (nfs_probe_statd()) { ++ fprintf(stderr, "Statd service already running!\n"); ++ exit(1); ++ } ++ + /* Process command line switches */ + while ((arg = getopt_long(argc, argv, "h?vVFNH:dn:p:o:P:L", longopts, NULL)) != EOF) { + switch (arg) { diff --git a/nfs-utils.spec b/nfs-utils.spec index c9db9db..9fae510 100644 --- a/nfs-utils.spec +++ b/nfs-utils.spec @@ -2,7 +2,7 @@ Summary: NFS utilities and supporting clients and daemons for the kernel NFS ser Name: nfs-utils URL: http://sourceforge.net/projects/nfs Version: 1.2.8 -Release: 5.0%{?dist} +Release: 6.0%{?dist} Epoch: 1 # group all 32bit related archs @@ -36,7 +36,7 @@ Source51: nfs-server.preconfig Source52: nfs-server.postconfig %define nfs_configs %{SOURCE50} %{SOURCE51} %{SOURCE52} -Patch001: nfs-utils.1.2.9-rc4.patch +Patch001: nfs-utils.1.2.9-rc6.patch Patch100: nfs-utils-1.2.1-statdpath-man.patch Patch101: nfs-utils-1.2.1-exp-subtree-warn-off.patch @@ -312,6 +312,9 @@ fi /sbin/umount.nfs4 %changelog +* Tue Sep 24 2013 Steve Dickson 1.2.8-6.0 +- Updated to latest upstream RC release: nfs-utils-1-2-9-rc6 + * Wed Sep 18 2013 Steve Dickson 1.2.8-5.0 - Updated to latest upstream RC release: nfs-utils-1-2-9-rc5