diff --git a/nfs-utils-1-2-3-rc1.patch b/nfs-utils-1-2-3-rc1.patch new file mode 100644 index 0000000..dfafe7d --- /dev/null +++ b/nfs-utils-1-2-3-rc1.patch @@ -0,0 +1,593 @@ +diff --git a/configure.ac b/configure.ac +index b7520d8..518b6d8 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -81,7 +81,7 @@ AC_ARG_ENABLE(nfsv41, + if test "$enable_nfsv41" = yes; then + AC_DEFINE(NFS41_SUPPORTED, 1, [Define this if you want NFSv41 support compiled in]) + else +- enable_nfsv4= ++ enable_nfsv41= + fi + AC_SUBST(enable_nfsv41) + AM_CONDITIONAL(CONFIG_NFSV41, [test "$enable_nfsv41" = "yes"]) +diff --git a/support/export/client.c b/support/export/client.c +index 6236561..5e937b0 100644 +--- a/support/export/client.c ++++ b/support/export/client.c +@@ -28,6 +28,8 @@ + #if !defined(__GLIBC__) || __GLIBC__ < 2 + extern int innetgr(char *netgr, char *host, char *, char *); + #endif ++ ++static char *add_name(char *old, const char *add); + static void client_init(nfs_client *clp, const char *hname, + struct hostent *hp); + static int client_checkaddr(nfs_client *clp, struct in_addr addr); +@@ -211,28 +213,6 @@ client_freeall(void) + } + } + +-nfs_client * +-client_find(struct hostent *hp) +-{ +- nfs_client *clp; +- int i; +- +- for (i = 0; i < MCL_MAXTYPES; i++) { +- for (clp = clientlist[i]; clp; clp = clp->m_next) { +- if (!client_check(clp, hp)) +- continue; +-#ifdef notdef +- if (clp->m_type == MCL_FQDN) +- return clp; +- return client_dup(clp, hp); +-#else +- return clp; +-#endif +- } +- } +- return NULL; +-} +- + struct hostent * + client_resolve(struct in_addr addr) + { +@@ -246,14 +226,18 @@ client_resolve(struct in_addr addr) + return he; + } + +-/* +- * Find client name given an IP address +- * This is found by gathering all known names that match that IP address, +- * sorting them and joining them with '+' ++/** ++ * client_compose - Make a list of cached hostnames that match an IP address ++ * @he: pointer to hostent containing IP address information to match + * ++ * Gather all known client hostnames that match the IP address, and sort ++ * the result into a comma-separated list. ++ * ++ * Returns a '\0'-terminated ASCII string containing a comma-separated ++ * sorted list of client hostnames, or NULL if no client records matched ++ * the IP address or memory could not be allocated. Caller must free the ++ * returned string with free(3). + */ +-static char *add_name(char *old, char *add); +- + char * + client_compose(struct hostent *he) + { +@@ -271,13 +255,19 @@ client_compose(struct hostent *he) + return name; + } + ++/** ++ * client_member - check if @name is contained in the list @client ++ * @client: '\0'-terminated ASCII string containing ++ * comma-separated list of hostnames ++ * @name: '\0'-terminated ASCII string containing hostname to look for ++ * ++ * Returns 1 if @name was found in @client, otherwise zero is returned. ++ */ + int +-client_member(char *client, char *name) ++client_member(const char *client, const char *name) + { +- /* check if "client" (a ',' separated list of names) +- * contains 'name' as a member +- */ +- int l = strlen(name); ++ size_t l = strlen(name); ++ + while (*client) { + if (strncmp(client, name, l) == 0 && + (client[l] == ',' || client[l] == '\0')) +@@ -290,9 +280,8 @@ client_member(char *client, char *name) + return 0; + } + +- +-int +-name_cmp(char *a, char *b) ++static int ++name_cmp(const char *a, const char *b) + { + /* compare strings a and b, but only upto ',' in a */ + while (*a && *b && *a != ',' && *a == *b) +@@ -305,9 +294,9 @@ name_cmp(char *a, char *b) + } + + static char * +-add_name(char *old, char *add) ++add_name(char *old, const char *add) + { +- int len = strlen(add)+2; ++ size_t len = strlen(add) + 2; + char *new; + char *cp; + if (old) len += strlen(old); +diff --git a/support/export/export.c b/support/export/export.c +index 2943466..42e78f6 100644 +--- a/support/export/export.c ++++ b/support/export/export.c +@@ -128,6 +128,7 @@ export_dup(nfs_export *exp, struct hostent *hp) + + return new; + } ++ + /* + * Add export entry to hash table + */ +@@ -276,15 +277,15 @@ export_freeall(void) + if (exp->m_export.e_mountpoint) + free(exp->m_export.e_mountpoint); + if (exp->m_export.e_fslocdata) +- xfree(exp->m_export.e_fslocdata); ++ free(exp->m_export.e_fslocdata); + xfree(exp->m_export.e_hostname); + xfree(exp); + } +- for(j = 0; j < HASH_TABLE_SIZE; j++) { +- exportlist[i].entries[j].p_first = NULL; +- exportlist[i].entries[j].p_last = NULL; +- } +- exportlist[i].p_head = NULL; ++ for (j = 0; j < HASH_TABLE_SIZE; j++) { ++ exportlist[i].entries[j].p_first = NULL; ++ exportlist[i].entries[j].p_last = NULL; ++ } ++ exportlist[i].p_head = NULL; + } + client_freeall(); + } +diff --git a/support/include/exportfs.h b/support/include/exportfs.h +index 470b2ec..9a19cbb 100644 +--- a/support/include/exportfs.h ++++ b/support/include/exportfs.h +@@ -69,17 +69,16 @@ extern exp_hash_table exportlist[MCL_MAXTYPES]; + extern nfs_client * clientlist[MCL_MAXTYPES]; + + nfs_client * client_lookup(char *hname, int canonical); +-nfs_client * client_find(struct hostent *); + void client_add(nfs_client *); + nfs_client * client_dup(nfs_client *, struct hostent *); + int client_gettype(char *hname); + int client_check(nfs_client *, struct hostent *); +-int client_match(nfs_client *, char *hname); + void client_release(nfs_client *); + void client_freeall(void); + char * client_compose(struct hostent *he); + struct hostent * client_resolve(struct in_addr addr); +-int client_member(char *client, char *name); ++int client_member(const char *client, ++ const char *name); + + int export_read(char *fname); + void export_add(nfs_export *); +diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h +index 4db35ab..6ebefca 100644 +--- a/support/include/nfsrpc.h ++++ b/support/include/nfsrpc.h +@@ -160,4 +160,7 @@ extern int nfs_rpc_ping(const struct sockaddr *sap, + const unsigned short protocol, + const struct timeval *timeout); + ++/* create AUTH_SYS handle with no supplemental groups */ ++extern AUTH * nfs_authsys_create(void); ++ + #endif /* !__NFS_UTILS_NFSRPC_H */ +diff --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c +index bdf5d84..0587ecb 100644 +--- a/support/nfs/cacheio.c ++++ b/support/nfs/cacheio.c +@@ -148,6 +148,11 @@ void qword_printint(FILE *f, int num) + fprintf(f, "%d ", num); + } + ++void qword_printuint(FILE *f, unsigned int num) ++{ ++ fprintf(f, "%u ", num); ++} ++ + int qword_eol(FILE *f) + { + int err; +@@ -236,6 +241,20 @@ int qword_get_int(char **bpp, int *anint) + return 0; + } + ++int qword_get_uint(char *bpp, unsigned int *anint) ++{ ++ char buf[50]; ++ char *ep; ++ unsigned int rv; ++ int len = qword_get(bpp, buf, 50); ++ if (len < 0) return -1; ++ if (len ==0) return -1; ++ rv = strtoul(buf, &ep, 0); ++ if (*ep) return -1; ++ *anint = rv; ++ return 0; ++} ++ + #define READLINE_BUFFER_INCREMENT 2048 + + int readline(int fd, char **buf, int *lenp) +diff --git a/support/nfs/rpc_socket.c b/support/nfs/rpc_socket.c +index 0e20824..c14efe8 100644 +--- a/support/nfs/rpc_socket.c ++++ b/support/nfs/rpc_socket.c +@@ -557,3 +557,24 @@ rpcprog_t nfs_getrpcbyname(const rpcprog_t program, const char *table[]) + + return program; + } ++ ++/* ++ * AUTH_SYS doesn't allow more than 16 gids in the supplemental group list. ++ * If there are more than that, trying to determine which ones to include ++ * in the list is problematic. This function creates an auth handle that ++ * only has the primary gid in the supplemental gids list. It's intended to ++ * be used for protocols where credentials really don't matter much (the MNT ++ * protocol, for instance). ++ */ ++AUTH * ++nfs_authsys_create(void) ++{ ++ char machname[MAXHOSTNAMELEN + 1]; ++ uid_t uid = geteuid(); ++ gid_t gid = getegid(); ++ ++ if (gethostname(machname, sizeof(machname)) == -1) ++ return NULL; ++ ++ return authunix_create(machname, uid, gid, 1, &gid); ++} +diff --git a/utils/mount/network.c b/utils/mount/network.c +index 8dc183a..c541257 100644 +--- a/utils/mount/network.c ++++ b/utils/mount/network.c +@@ -857,7 +857,14 @@ int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen, + return 0; + } + +- client->cl_auth = authunix_create_default(); ++ client->cl_auth = nfs_authsys_create(); ++ if (client->cl_auth == NULL) { ++ if (verbose) ++ nfs_error(_("%s: Failed to create RPC auth handle"), ++ progname); ++ CLNT_DESTROY(client); ++ return 0; ++ } + + res = CLNT_CALL(client, MOUNTPROC_UMNT, + (xdrproc_t)xdr_dirpath, (caddr_t)argp, +@@ -957,8 +964,10 @@ CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock) + } + if (clnt) { + /* try to mount hostname:dirname */ +- clnt->cl_auth = authunix_create_default(); +- return clnt; ++ clnt->cl_auth = nfs_authsys_create(); ++ if (clnt->cl_auth) ++ return clnt; ++ CLNT_DESTROY(clnt); + } + return NULL; + } +diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c +index 9b8c38f..98557d2 100644 +--- a/utils/mount/stropts.c ++++ b/utils/mount/stropts.c +@@ -799,6 +799,7 @@ static int nfs_is_permanent_error(int error) + case ESTALE: + case ETIMEDOUT: + case ECONNREFUSED: ++ case EHOSTUNREACH: + return 0; /* temporary */ + default: + return 1; /* permanent */ +diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c +index d63e10a..6343325 100644 +--- a/utils/mountd/cache.c ++++ b/utils/mountd/cache.c +@@ -125,7 +125,7 @@ void auth_unix_gid(FILE *f) + * reply is + * uid expiry count list of group ids + */ +- int uid; ++ uid_t uid; + struct passwd *pw; + gid_t glist[100], *groups = glist; + int ngroups = 100; +@@ -136,7 +136,7 @@ void auth_unix_gid(FILE *f) + return; + + cp = lbuf; +- if (qword_get_int(&cp, &uid) != 0) ++ if (qword_get_uint(&cp, &uid) != 0) + return; + + pw = getpwuid(uid); +@@ -153,14 +153,14 @@ void auth_unix_gid(FILE *f) + groups, &ngroups); + } + } +- qword_printint(f, uid); +- qword_printint(f, time(0)+30*60); ++ qword_printuint(f, uid); ++ qword_printuint(f, time(0)+30*60); + if (rv >= 0) { +- qword_printint(f, ngroups); ++ qword_printuint(f, ngroups); + for (i=0; icl_auth = authunix_create_default(); ++ mclient->cl_auth = nfs_authsys_create(); ++ if (mclient->cl_auth == NULL) { ++ fprintf(stderr, "%s: unable to create RPC auth handle.\n", ++ program_name); ++ clnt_destroy(mclient); ++ exit(1); ++ } + total_timeout.tv_sec = TOTAL_TIMEOUT; + total_timeout.tv_usec = 0; + +diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c +index 3259a3e..437e37a 100644 +--- a/utils/statd/sm-notify.c ++++ b/utils/statd/sm-notify.c +@@ -54,7 +54,7 @@ struct nsm_host { + uint32_t xid; + }; + +-static char nsm_hostname[256]; ++static char nsm_hostname[SM_MAXSTRLEN + 1]; + static int nsm_state; + static int nsm_family = AF_INET; + static int opt_debug = 0; +@@ -412,12 +412,33 @@ usage: fprintf(stderr, + } + } + +- if (opt_srcaddr) { +- strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname)-1); +- } else +- if (gethostname(nsm_hostname, sizeof(nsm_hostname)) < 0) { +- xlog(L_ERROR, "Failed to obtain name of local host: %m"); +- exit(1); ++ if (opt_srcaddr != NULL) { ++ struct addrinfo *ai = NULL; ++ struct addrinfo hint = { ++ .ai_family = AF_UNSPEC, ++ .ai_flags = AI_NUMERICHOST, ++ }; ++ ++ if (getaddrinfo(opt_srcaddr, NULL, &hint, &ai)) ++ /* not a presentation address - use it */ ++ strncpy(nsm_hostname, opt_srcaddr, sizeof(nsm_hostname)); ++ else { ++ /* was a presentation address - look it up in ++ * /etc/hosts, so it can be used for my_name */ ++ int error; ++ ++ freeaddrinfo(ai); ++ hint.ai_flags = AI_CANONNAME; ++ error = getaddrinfo(opt_srcaddr, NULL, &hint, &ai); ++ if (error != 0) { ++ xlog(L_ERROR, "Bind address %s is unusable: %s", ++ opt_srcaddr, gai_strerror(error)); ++ exit(1); ++ } ++ strncpy(nsm_hostname, ai->ai_canonname, ++ sizeof(nsm_hostname)); ++ freeaddrinfo(ai); ++ } + } + + (void)nsm_retire_monitored_hosts(); +@@ -535,6 +556,8 @@ notify(const int sock) + static int + notify_host(int sock, struct nsm_host *host) + { ++ const char *my_name = (opt_srcaddr != NULL ? ++ nsm_hostname : host->my_name); + struct sockaddr *sap; + socklen_t salen; + +@@ -580,8 +603,8 @@ notify_host(int sock, struct nsm_host *host) + host->xid = nsm_xmit_rpcbind(sock, sap, SM_PROG, SM_VERS); + else + host->xid = nsm_xmit_notify(sock, sap, salen, +- SM_PROG, nsm_hostname, nsm_state); +- ++ SM_PROG, my_name, nsm_state); ++ + return 0; + } + +@@ -611,15 +634,28 @@ recv_rpcbind_reply(struct sockaddr *sap, struct nsm_host *host, XDR *xdr) + } + + /* +- * Successful NOTIFY call. Server returns void, so nothing +- * we need to do here. ++ * Successful NOTIFY call. Server returns void. ++ * ++ * Try sending another SM_NOTIFY with an unqualified "my_name" ++ * argument. Reuse the port number. If "my_name" is already ++ * unqualified, we're done. + */ + static void + recv_notify_reply(struct nsm_host *host) + { +- xlog(D_GENERAL, "Host %s notified successfully", host->name); ++ char *dot = strchr(host->my_name, '.'); + +- smn_forget_host(host); ++ if (dot != NULL) { ++ *dot = '\0'; ++ host->send_next = time(NULL); ++ host->xid = 0; ++ if (host->timeout >= NSM_MAX_TIMEOUT / 4) ++ host->timeout = NSM_MAX_TIMEOUT / 4; ++ insert_host(host); ++ } else { ++ xlog(D_GENERAL, "Host %s notified successfully", host->name); ++ smn_forget_host(host); ++ } + } + + /* +diff --git a/utils/statd/sm-notify.man b/utils/statd/sm-notify.man +index 163713e..7a1cbfa 100644 +--- a/utils/statd/sm-notify.man ++++ b/utils/statd/sm-notify.man +@@ -97,11 +97,9 @@ It uses the + string as the destination. + To identify which host has rebooted, the + .B sm-notify +-command normally sends the results of +-.BR gethostname (3) +-as the ++command normally sends + .I my_name +-string. ++string recorded when that remote was monitored. + The remote + .B rpc.statd + matches incoming SM_NOTIFY requests using this string, +@@ -202,15 +200,22 @@ argument to use when sending SM_NOTIFY requests. + If this option is not specified, + .B sm-notify + uses a wildcard address as the transport bind address, +-and uses the results of +-.BR gethostname (3) +-as the ++and uses the ++.I my_name ++recorded when the remote was monitored as the + .I mon_name +-argument. ++argument when sending SM_NOTIFY requests. + .IP + The + .I ipaddr + form can be expressed as either an IPv4 or an IPv6 presentation address. ++If the ++.I ipaddr ++form is used, the ++.B sm-notify ++command converts this address to a hostname for use as the ++.I mon_name ++argument when sending SM_NOTIFY requests. + .IP + This option can be useful in multi-homed configurations where + the remote requires notification from a specific network address. +@@ -252,13 +257,6 @@ consistent + The hostname the client uses to mount the server should match the server's + .I mon_name + in SM_NOTIFY requests it sends +-.IP +-The use of network addresses as a +-.I mon_name +-or a +-.I my_name +-string should be avoided when +-interoperating with non-Linux NFS implementations. + .PP + Unmounting an NFS file system does not necessarily stop + either the NFS client or server from monitoring each other. +diff --git a/utils/statd/statd.man b/utils/statd/statd.man +index ffc5e95..ca00e24 100644 +--- a/utils/statd/statd.man ++++ b/utils/statd/statd.man +@@ -100,11 +100,9 @@ It uses the + string as the destination. + To identify which host has rebooted, the + .B sm-notify +-command normally sends the results of +-.BR gethostname (3) +-as the ++command sends the + .I my_name +-string. ++string recorded when that remote was monitored. + The remote + .B rpc.statd + matches incoming SM_NOTIFY requests using this string, +@@ -292,7 +290,6 @@ man pages. + .SH ADDITIONAL NOTES + Lock recovery after a reboot is critical to maintaining data integrity + and preventing unnecessary application hangs. +-.PP + To help + .B rpc.statd + match SM_NOTIFY requests to NLM requests, a number of best practices +@@ -309,13 +306,6 @@ consistent + The hostname the client uses to mount the server should match the server's + .I mon_name + in SM_NOTIFY requests it sends +-.IP +-The use of network addresses as a +-.I mon_name +-or a +-.I my_name +-string should be avoided when +-interoperating with non-Linux NFS implementations. + .PP + Unmounting an NFS file system does not necessarily stop + either the NFS client or server from monitoring each other. diff --git a/nfs-utils.spec b/nfs-utils.spec index c21a901..228e7c0 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.2 -Release: 1%{?dist} +Release: 2%{?dist} Epoch: 1 # group all 32bit related archs @@ -18,6 +18,8 @@ Source13: rpcgssd.init Source14: rpcsvcgssd.init Source15: nfs.sysconfig +Patch001: nfs-utils-1-2-3-rc1.patch + Patch100: nfs-utils-1.2.1-statdpath-man.patch Patch101: nfs-utils-1.2.2-statdpath.patch Patch102: nfs-utils-1.2.1-exp-subtree-warn-off.patch @@ -69,6 +71,8 @@ This package also contains the mount.nfs and umount.nfs program. %prep %setup -q +%patch001 -p1 + %patch100 -p1 %patch101 -p1 %patch102 -p1 @@ -245,6 +249,9 @@ fi %attr(4755,root,root) /sbin/umount.nfs4 %changelog +* Mon Mar 22 2010 Steve Dickson 1.2.2-2 +- Update to upstream RC release: nfs-utils-1-2-3-rc1 + * Thu Feb 18 2010 Steve Dickson 1.2.2-1 - Updated to latest upstream version: 1.2.2