Signed-off-by: dank@kegel.com
Copyright 2005, Google
License: GPL

--- distcc-2.18.3.orig/man/distcc.1	2004-10-23 22:05:23.000000000 -0700
+++ distcc-2.18.3/man/distcc.1	2005-09-04 22:24:13.000000000 -0700
@@ -208,9 +208,21 @@
 .B $DISTCC_HOSTS
 environment variable, the user's 
 .B $DISTCC_DIR/hosts
-file, and the system-wide host 
-file.  If no host list can be found, distcc emits a warning and
-compiles locally.
+file, the domain-specific system-wide hosts file (e.g. 
+.B /etc/distcc/{domain}/hosts
+), and finally the system-wide hosts file (e.g.
+.B /etc/distcc/hosts
+).
+.PP
+The value 
+.B {domain}
+above is taken from one of the environment variables
+.B $HOST
+or
+.B $HOSTNAME
+and is the part of the hostname after the first dot, if any.
+.PP
+If no host list can be found, distcc emits a warning and compiles locally.
 .PP
 The host list is a simple whitespace separated list of host
 specifications.  The simplest and most common form is a host names,
@@ -461,6 +473,14 @@
 file descriptor identified by this variable.  This variable is
 intended mainly for automatic use by ccache, which sets it to avoid
 caching transient errors such as network problems.
+.TP
+.B "HOSTNAME"
+or
+.B "HOST"
+If one of these is present, and contains at least one dot,
+it is assumed to be the FQDN of the local machine;
+the portion after the first dot is taken to be the DNS domain,
+and is used in looking up the hosts file.
 .SH "CROSS COMPILING"
 Cross compilation means building programs to run on a
 machine with a different processor, architecture, or
diff -Naur distcc-2.18.3.orig/src/distcc.c distcc-2.18.3/src/distcc.c
--- distcc-2.18.3.orig/src/distcc.c	2005-09-04 17:04:17.000000000 -0700
+++ distcc-2.18.3/src/distcc.c	2005-09-04 17:07:49.000000000 -0700
@@ -93,7 +93,9 @@
 "\n"
 "Server specification:\n"
 "A list of servers is taken from the environment variable $DISTCC_HOSTS, or\n"
-"$DISTCC_DIR/hosts, or ~/.distcc/hosts, or %s/distcc/hosts.\n"
+"$DISTCC_DIR/hosts, ~/.distcc/hosts, %s/distcc/{domain}/hosts, \n"
+"or %s/distcc/hosts, where {domain} is the DNS domain implied \n"
+"by the $HOST or $HOSTNAME environment variable.\n"
 "Each host can be given in any of these forms, see the manual for details:\n"
 "\n"
 "   localhost                  run in place\n"
@@ -107,6 +109,7 @@
 "preprocessing are run locally.  distcc should be used with make's -jN\n"
 "option to execute in parallel on several machines.\n",
     SYSCONFDIR,
+    SYSCONFDIR,
     DISTCC_DEFAULT_PORT);
 }
 
diff -Naur distcc-2.18.3.orig/src/hosts.c distcc-2.18.3/src/hosts.c
--- distcc-2.18.3.orig/src/hosts.c	2005-09-04 17:04:18.000000000 -0700
+++ distcc-2.18.3/src/hosts.c	2005-09-04 17:04:41.000000000 -0700
@@ -123,51 +123,56 @@
 /**
  * Get a list of hosts to use.
  *
- * Hosts are taken from DISTCC_HOSTS, if that exists.  Otherwise, they are
- * taken from $DISTCC_DIR/hosts, if that exists.  Otherwise, they are taken
- * from ${sysconfdir}/distcc/hosts, if that exists.  Otherwise, we fail.
+ * Hosts are taken from DISTCC_HOSTS, if that exists.  Otherwise, 
+ * they are taken from the first existing file from the list 
+ *  $DISTCC_DIR/hosts
+ *  ${sysconfdir}/distcc/{domain}/hosts
+ *  ${sysconfdir}/distcc/hosts
+ * Otherwise, we fail.
  **/
 int dcc_get_hostlist(struct dcc_hostdef **ret_list,
                      int *ret_nhosts)
 {
     char *env;
     char *path, *top;
+    const char *dns_domain;
     int ret;
+    char *paths[10];
+    int npaths;
+    int i;
 
     if ((env = getenv("DISTCC_HOSTS")) != NULL) {
         rs_trace("read hosts from environment");
         return dcc_parse_hosts(env, "$DISTCC_HOSTS", ret_list, ret_nhosts);
     }
 
-    /* $DISTCC_DIR or ~/.distcc */
-    if ((ret = dcc_get_top_dir(&top)) == 0) {
-        /* if we failed to get it, just warn */
-
-        asprintf(&path, "%s/hosts", top);
-        if (access(path, R_OK) == 0) {
-            ret = dcc_parse_hosts_file(path, ret_list, ret_nhosts);
-            free(path);
-            return ret;
-        } else {
-            rs_trace("not reading %s: %s", path, strerror(errno));
-            free(path);
-        }
-    }
-
-    asprintf(&path, "%s/distcc/hosts", SYSCONFDIR);
-    if (access(path, R_OK) == 0) {
-        ret = dcc_parse_hosts_file(path, ret_list, ret_nhosts);
-        free(path);
-        return ret;
-    } else {
-        rs_trace("not reading %s: %s", path, strerror(errno));
-        free(path);
+    /* Build the list of directories to search */
+    npaths=0;
+    if ((ret = dcc_get_top_dir(&top)) == 0)
+        asprintf(&paths[npaths++], "%s/hosts", top);
+    if (dcc_get_dns_domain(&dns_domain) == 0)
+        asprintf(&paths[npaths++], SYSCONFDIR "/distcc/%s/hosts", dns_domain);
+    asprintf(&paths[npaths++], SYSCONFDIR "/distcc/hosts");
+
+    /* Search the list of directories */
+    ret=EXIT_BAD_HOSTSPEC;
+    for (i=0; i<npaths; i++) {
+	if (access(paths[i], R_OK) == 0) {
+	    ret = dcc_parse_hosts_file(paths[i], ret_list, ret_nhosts);
+	    break;
+	} else
+	    rs_trace("not reading %s: %s", paths[i], strerror(errno));
+    }
+    /* Clean up storage */
+    for (i=0; i<npaths; i++)
+	free(paths[i]);
+
+    if (ret == EXIT_BAD_HOSTSPEC) {
+        /* FIXME: Clearer message? */
+        rs_log_warning("no hostlist is set; can't distribute work");
     }
-    
-    /* FIXME: Clearer message? */
-    rs_log_warning("no hostlist is set; can't distribute work");
 
-    return EXIT_BAD_HOSTSPEC;
+    return ret;
 }
 
 
diff -Naur distcc-2.18.3.orig/src/util.c distcc-2.18.3/src/util.c
--- distcc-2.18.3.orig/src/util.c	2005-09-04 17:04:17.000000000 -0700
+++ distcc-2.18.3/src/util.c	2005-09-04 17:04:41.000000000 -0700
@@ -30,6 +30,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <netdb.h>
+#include <ctype.h>
 
 #include <sys/stat.h>
 #include <sys/time.h>
@@ -345,6 +346,69 @@
 }
 
 
+#define IS_LEGAL_DOMAIN_CHAR(c) (isalnum(c) || ((c) == '-') || ((c) == '.'))
+
+/* Copy domain part of hostname to static buffer.
+ * If hostname has no domain part, returns -1.
+ * If domain lookup fails, returns -1.  
+ * Otherwise places pointer to domain in *domain_name and returns 0.
+ *
+ * This should yield the same result as the linux command 
+ * 'dnsdomainname' or 'hostname -d'.
+ **/
+int dcc_get_dns_domain(const char **domain_name)
+{
+#if 0 /* Too expensive */
+
+    static char host_name[1024];
+    struct hostent *h;
+    int ret;
+
+    ret = gethostname(host_name, sizeof(host_name));
+    if (ret != 0)
+        return -1;
+
+    h = gethostbyname(host_name);
+    if (h == NULL) {
+	rs_log_error("failed to look up self \"%s\": %s", host_name,
+                     hstrerror(h_errno));
+	return -1;
+    }
+
+    strncpy(host_name, h->h_name, sizeof(host_name));
+    *domain_name = strchr(h->h_name, '.');
+
+#else  /* cheaper */
+    const char *envh;
+    int i;
+    const int MAXDOMAINLEN = 512;
+
+    /* try to retrieve FQDN from environment */
+    envh = getenv("HOST");           /* Solaris, BSD */
+    if (!envh)
+        envh = getenv("HOSTNAME");   /* Linux */
+    if (!envh)
+        return 0;
+
+    /* validate to avoid possible errors from bad chars or huge value */
+    for (i=0; envh[i] != '\0'; i++) {
+        if (i > MAXDOMAINLEN || !IS_LEGAL_DOMAIN_CHAR(envh[i])) {
+	    rs_log_error("HOST/HOSTNAME present in environment but illegal: '%s'", envh);
+	    return -1;
+        }
+    }
+    *domain_name = strchr(envh, '.');
+#endif
+
+    if (*domain_name == NULL)
+        return -1;
+
+    (*domain_name)++; 
+    /* Return 0 on success, or -1 if the domain name is illegal, e.g. empty */
+    return ((*domain_name)[0] == '\0') ? -1 : 0;
+}
+
+
 
 /**
  * Duplicate the part of the string @p psrc up to a character in @p sep
diff -Naur distcc-2.18.3.orig/src/util.h distcc-2.18.3/src/util.h
--- distcc-2.18.3.orig/src/util.h	2005-09-04 17:04:18.000000000 -0700
+++ distcc-2.18.3/src/util.h	2005-09-04 17:04:41.000000000 -0700
@@ -35,6 +35,7 @@
 int dcc_trim_path(const char *compiler_name);
 int dcc_set_path(const char *newpath);
 char *dcc_abspath(const char *path, int path_len);
+int dcc_get_dns_domain(const char **domain_name);
 
 #define str_equal(a, b) (!strcmp((a), (b)))
 
