diff -Nurp autofs-4.1.4.orig/modules/mount_nfs.c autofs-4.1.4/modules/mount_nfs.c --- autofs-4.1.4.orig/modules/mount_nfs.c 2005-04-25 10:55:27.000000000 +0800 +++ autofs-4.1.4/modules/mount_nfs.c 2005-04-25 10:56:15.000000000 +0800 @@ -31,6 +31,7 @@ #include #include #include +#include #define MODULE_MOUNT #include "automount.h" @@ -105,28 +106,117 @@ int is_local_addr(const char *host, cons return 1; } + +/* + * If the entry doesn't contain a ',' or doesn't contain more than + * one ':' then @what is not a replicated server entry. + */ +static int inline is_replicated_entry(char *what) +{ + return strchr(what, ',') || + (strchr(what, ':') != strrchr(what, ':')); +} + +/* + * Check to see if the 'host:path' or 'host' is on the local machine + * Returns < 0 if there is a host lookup problem, otherwise returns 0 + * if it's not a local mount, and returns > 0 if it is a local mount. + */ +int is_local_mount(const char *hostpath) +{ + struct hostent *he; + char **haddr; + char *delim; + char *hostname; + int hostnamelen; + int local = 0; + + debug(MODPREFIX "is_local_mount: %s", hostpath); + delim = strpbrk(hostpath,":"); + + if (delim) + hostnamelen = delim - hostpath; + else + hostnamelen = strlen(hostpath); + + hostname = malloc(hostnamelen+1); + strncpy(hostname, hostpath, hostnamelen); + hostname[hostnamelen] = '\0'; + he = gethostbyname(hostname); + if (!he) { + error(MODPREFIX "host %s: lookup failure", hostname); + return -1; + } + + for (haddr = he->h_addr_list; *haddr; haddr++) { + local = is_local_addr(hostname, *haddr, he->h_length); + if (local < 0) + return local; + if (local) { + debug(MODPREFIX "host %s: is localhost", + hostname); + return local; + } + } + return 0; +} + /* * Given a mount string, return (in the same string) the - * best mount to use based on weight/locality/rpctime + * best mount to use based on locality/weight/rpctime. + * + * If longtimeout is set to 0 then we only do 100 ms pings to hosts. In + * the event that this fails, we call ourself recursively with the + * longtimeout option set to 1. In this case we ping for up to 10s and + * skip logic for detecting if a localhost has been passed. (if a local + * host had been passed, we would have returned that mount as the best + * mount. The skipping of local maps in this case is an optimization). + * * - return -1 and what = '\0' on error, * 1 and what = local mount path if local bind, * else 0 and what = remote mount path */ -int get_best_mount(char *what, const char *original, int longtimeout, int skiplocal) +int get_best_mount(char *what, const char *original, int longtimeout) { char *p = what; char *winner = NULL; int winner_weight = INT_MAX, local = 0; double winner_time = 0; - char *delim; + char *delim, *pstrip; int sec = (longtimeout) ? 10 : 0; int micros = (longtimeout) ? 0 : 100000; + int skiplocal = longtimeout; /* clearly local is not available */ if (!p) { *what = '\0'; return -1; } + /* + * If only one mountpoint has been passed in, we don't need to + * do anything except strip whitespace from the end of the string. + */ + if (!is_replicated_entry(p)) { + for (pstrip = p+strlen(p) - 1; pstrip >= p; pstrip--) + if (isspace(*pstrip)) + *pstrip = '\0'; + + /* Check if the host is the localhost */ + if (is_local_mount(p) > 0) { + debug(MODPREFIX "host %s: is localhost", p); + + /* Strip off hostname and ':' */ + delim = strchr(p,':'); + while (delim && *delim != '\0') { + delim++; + *what = *delim; + what++; + } + return 1; + } + return 0; + } + while (p && *p) { char *next; unsigned int ping_stat = 0; @@ -171,37 +261,17 @@ int get_best_mount(char *what, const cha /* p points to a server, "next is our next parse point */ if (!skiplocal) { /* Check if it's localhost */ - struct hostent *he; - char **haddr; - - he = gethostbyname(p); - if (!he) { - error(MODPREFIX "host %s: lookup failure", p); - p = next; - continue; - } - - /* Check each host in round robin list */ - for (haddr = he->h_addr_list; *haddr; haddr++) { - local = is_local_addr(p, *haddr, he->h_length); - - if (local < 0) - continue; - - if (local) { - winner = p; - break; - } - } - + local = is_local_mount(p); if (local < 0) { local = 0; p = next; continue; } - if (local) + if (local) { + winner = p; break; + } } /* ping each (or the) entry to see if it's alive. */ @@ -214,6 +284,7 @@ int get_best_mount(char *what, const cha /* First unweighted or only host is alive so set winner */ if (!winner) { winner = p; + winner_time = 1; /* No more to check, return it */ if (!next || !*next) break; @@ -256,7 +327,7 @@ int get_best_mount(char *what, const cha */ if (!local && winner_weight == INT_MAX) { /* We had more than one contender and none responded in time */ - if (winner_time != 0 && winner_time > 500) { + if (winner_time == 0 || winner_time > 500) { /* We've already tried a longer timeout */ if (!longtimeout) { /* Reset string and try again */ @@ -267,16 +338,14 @@ int get_best_mount(char *what, const cha "retrying with longer timeout", original); - return get_best_mount(what, original, 1, 1); + return get_best_mount(what, original, 1); } } } - /* No winner found so bail */ - if (!winner) { - *what = '\0'; - return 0; - } + /* No winner found so return first */ + if (!winner) + winner = what; /* * We now have our winner, copy it to the front of the string, @@ -395,7 +464,7 @@ int mount_mount(const char *root, const /* No colon, take this as a bind (local) entry */ local = 1; } else if (!nosymlink) { - local = get_best_mount(whatstr, what, 0, 0); + local = get_best_mount(whatstr, what, 0); if (!*whatstr) { warn(MODPREFIX "no host elected"); return 1;