--- distcc-2.18.1.orig/aclocal.m4	1970-01-01 01:00:00.000000000 +0100
+++ distcc-2.18.1/aclocal.m4	2004-11-27 03:31:27.000000000 +0100
@@ -0,0 +1,57 @@
+
+dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not)
+dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page
+dnl also defines GSTUFF_PKG_ERRORS on error
+AC_DEFUN(PKG_CHECK_MODULES, [
+  succeeded=no
+
+  if test -z "$PKG_CONFIG"; then
+    AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+  fi
+
+  if test "$PKG_CONFIG" = "no" ; then
+     echo "*** The pkg-config script could not be found. Make sure it is"
+     echo "*** in your path, or set the PKG_CONFIG environment variable"
+     echo "*** to the full path to pkg-config."
+     echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config."
+  else
+     PKG_CONFIG_MIN_VERSION=0.9.0
+     if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then
+        AC_MSG_CHECKING(for $2)
+
+        if $PKG_CONFIG --exists "$2" ; then
+            AC_MSG_RESULT(yes)
+            succeeded=yes
+
+            AC_MSG_CHECKING($1_CFLAGS)
+            $1_CFLAGS=`$PKG_CONFIG --cflags "$2"`
+            AC_MSG_RESULT($$1_CFLAGS)
+
+            AC_MSG_CHECKING($1_LIBS)
+            $1_LIBS=`$PKG_CONFIG --libs "$2"`
+            AC_MSG_RESULT($$1_LIBS)
+        else
+            $1_CFLAGS=""
+            $1_LIBS=""
+            ## If we have a custom action on failure, don't print errors, but 
+            ## do set a variable so people can do so.
+            $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
+            ifelse([$4], ,echo $$1_PKG_ERRORS,)
+        fi
+
+        AC_SUBST($1_CFLAGS)
+        AC_SUBST($1_LIBS)
+     else
+        echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer."
+        echo "*** See http://www.freedesktop.org/software/pkgconfig"
+     fi
+  fi
+
+  if test $succeeded = yes; then
+     ifelse([$3], , :, [$3])
+  else
+     ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4])
+  fi
+])
+
+
--- distcc-2.18.1.orig/configure.ac	2004-11-03 03:47:22.000000000 +0100
+++ distcc-2.18.1/configure.ac	2004-11-28 02:59:26.000000000 +0100
@@ -386,6 +386,18 @@ AC_CHECK_MEMBER([struct sockaddr_storage
     AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1, [define if you have struct sockaddr_storage]),,
     [#include <sys/socket.h>])
 
+dnl check for howl
+PKG_CHECK_MODULES(HOWL, [howl],
+[AC_DEFINE(HAVE_HOWL, 1, [defined if howl is available])
+CFLAGS="$CFLAGS $HOWL_CFLAGS"
+LIBS="$LIBS $HOWL_LIBS"
+ZEROCONF_DISTCC_OBJS="src/zeroconf.o"
+ZEROCONF_DISTCCD_OBJS="src/zeroconf-reg.o"],
+[ZEROCONF_DISTCC_OBJS=""
+ZEROCONF_DISTCCD_OBJS=""])
+AC_SUBST(ZEROCONF_DISTCC_OBJS)
+AC_SUBST(ZEROCONF_DISTCCD_OBJS)
+
 dnl ##### Output
 AC_SUBST(docdir)
 AC_SUBST(CFLAGS)
--- distcc-2.18.1.orig/Makefile.in	2004-11-03 03:47:22.000000000 +0100
+++ distcc-2.18.1/Makefile.in	2004-11-28 17:36:47.000000000 +0100
@@ -180,6 +180,7 @@ distcc_obj = src/backoff.o						\
 	src/ssh.o src/state.o src/strip.o				\
 	src/timefile.o src/traceenv.o					\
 	src/where.o							\
+	@ZEROCONF_DISTCC_OBJS@						\
 	$(common_obj)
 
 distccd_obj = src/access.o						\
@@ -187,6 +188,7 @@ distccd_obj = src/access.o						\
 	src/ncpus.o							\
 	src/prefork.o							\
 	src/serve.o src/setuid.o src/srvnet.o src/srvrpc.o src/state.o	\
+	@ZEROCONF_DISTCCD_OBJS@						\
 	$(common_obj) @BUILD_POPT@
 
 # Objects that need to be linked in to build monitors
--- distcc-2.18.1.orig/src/distcc.c	2004-11-03 03:47:22.000000000 +0100
+++ distcc-2.18.1/src/distcc.c	2004-11-27 21:10:43.000000000 +0100
@@ -83,6 +83,9 @@ static void dcc_show_usage(void)
 "   COMPILER                   defaults to \"cc\"\n"
 "   --help                     explain usage and exit\n"
 "   --version                  show version and exit\n"
+"   --show-hosts               show host list and exit\n"
+"   -j                         calculate the concurrency level from\n"
+"                              the host list.\n"
 "\n"
 "Environment variables:\n"
 "   See the manual page for a complete list.\n"
@@ -135,7 +138,46 @@ static void dcc_client_catch_signals(voi
     signal(SIGHUP, &dcc_client_signalled);
 }
 
+static void dcc_free_hostlist(struct dcc_hostdef *list) {
+    while (list) {
+        struct dcc_hostdef *l = list;
+        list = list->next;
+        dcc_free_hostdef(l);
+    }
+}
+
+static void dcc_show_hosts(void) {
+    struct dcc_hostdef *list, *l;
+    int nhosts;
+    
+    if (dcc_get_hostlist(&list, &nhosts) != 0) {
+        rs_log_crit("Failed to get host list");
+        return;
+    }
+
+    for (l = list; l; l = l->next)
+        printf("%s\n", l->hostdef_string);
+
+    dcc_free_hostlist(list);
+}
+
+static void dcc_concurrency_level(void) {
+    struct dcc_hostdef *list, *l;
+    int nhosts;
+    int nslots = 0;
+    
+    if (dcc_get_hostlist(&list, &nhosts) != 0) {
+        rs_log_crit("Failed to get host list");
+        return;
+    }
+
+    for (l = list; l; l = l->next)
+        nslots += l->n_slots;
 
+    dcc_free_hostlist(list);
+
+    printf("%i\n", nslots);
+}
 
 /**
  * distcc client entry point.
@@ -182,6 +224,18 @@ int main(int argc, char **argv)
             ret = 0;
             goto out;
         }
+
+        if (!strcmp(argv[1], "--show-hosts")) {
+            dcc_show_hosts();
+            ret = 0;
+            goto out;
+        }
+
+        if (!strcmp(argv[1], "-j")) {
+            dcc_concurrency_level();
+            ret = 0;
+            goto out;
+        }
         
         dcc_find_compiler(argv, &compiler_args);
         /* compiler_args is now respectively either "cc -c hello.c" or
--- distcc-2.18.1.orig/src/distcc.h	2004-11-03 03:47:22.000000000 +0100
+++ distcc-2.18.1/src/distcc.h	2004-11-28 16:42:47.000000000 +0100
@@ -112,7 +112,7 @@ int dcc_parse_hosts_env(struct dcc_hostd
                         int *ret_nhosts);
 int dcc_parse_hosts(const char *where, const char *source_name,
                     struct dcc_hostdef **ret_list,
-                    int *ret_nhosts);
+                    int *ret_nhosts, struct dcc_hostdef **ret_prev);
 
 /* ncpu.c */
 int dcc_ncpus(int *);
@@ -226,6 +226,7 @@ int dcc_get_tempdir(const char **);
 int dcc_make_tmpnam(const char *, const char *suffix, char **);
 
 int dcc_mkdir(const char *path) WARN_UNUSED;
+int dcc_get_subdir(const char *name, char **path_ret) WARN_UNUSED;
 int dcc_get_lock_dir(char **path_ret) WARN_UNUSED;
 int dcc_get_state_dir(char **path_ret) WARN_UNUSED;
 int dcc_get_top_dir(char **path_ret) WARN_UNUSED;
--- distcc-2.18.1.orig/src/dopt.c	2004-11-03 03:47:22.000000000 +0100
+++ distcc-2.18.1/src/dopt.c	2004-11-28 02:41:31.000000000 +0100
@@ -93,6 +93,9 @@ enum {
     opt_log_level
 };
 
+#ifdef HAVE_HOWL
+int opt_zeroconf = 0;
+#endif
 
 const struct poptOption options[] = {
     { "allow", 'a',      POPT_ARG_STRING, 0, 'a', 0, 0 },
@@ -115,6 +118,9 @@ const struct poptOption options[] = {
     { "verbose", 0,      POPT_ARG_NONE, 0, 'v', 0, 0 },
     { "version", 0,      POPT_ARG_NONE, 0, 'V', 0, 0 },
     { "wizard", 'W',     POPT_ARG_NONE, 0, 'W', 0, 0 },
+#ifdef HAVE_HOWL    
+    { "zeroconf", 0,     POPT_ARG_NONE, &opt_zeroconf, 0, 0, 0 },
+#endif    
     { 0, 0, 0, 0, 0, 0, 0 }
 };
 
@@ -137,6 +143,9 @@ static void distccd_show_usage(void)
 "    -p, --port PORT            TCP port to listen on\n"
 "    --listen ADDRESS           IP address to listen on\n"
 "    -a, --allow IP[/BITS]      client address access control\n"
+#ifdef HAVE_HOWL    
+"    --zeroconf                 register via mDNS/DNS-SD\n"
+#endif
 "  Debug and trace:\n"
 "    --log-level=LEVEL          set detail level for log file\n"
 "      levels: critical, error, warning, notice, info, debug\n"
--- distcc-2.18.1.orig/src/dopt.h	2004-11-03 03:47:22.000000000 +0100
+++ distcc-2.18.1/src/dopt.h	2004-11-28 00:32:09.000000000 +0100
@@ -38,3 +38,5 @@ extern int opt_log_stderr;
 extern int opt_lifetime;
 extern char *opt_listen_addr;
 extern int opt_niceness;
+
+extern int opt_zeroconf;
--- distcc-2.18.1.orig/src/dparent.c	2004-11-03 03:47:22.000000000 +0100
+++ distcc-2.18.1/src/dparent.c	2004-11-28 00:36:11.000000000 +0100
@@ -70,6 +70,7 @@
 #include "types.h"
 #include "daemon.h"
 #include "netutil.h"
+#include "zeroconf.h"
 
 static void dcc_nofork_parent(int listen_fd) NORETURN;
 static void dcc_detach(void);
@@ -94,6 +95,9 @@ int dcc_standalone_server(void)
     int listen_fd;
     int n_cpus;
     int ret;
+#ifdef HAVE_HOWL
+    sw_discovery discovery;
+#endif
 
     if ((ret = dcc_socket_listen(arg_port, &listen_fd, opt_listen_addr)) != 0)
         return ret;
@@ -131,6 +135,14 @@ int dcc_standalone_server(void)
     /* Don't catch signals until we've detached or created a process group. */
     dcc_daemon_catch_signals();
 
+#ifdef HAVE_HOWL        
+    /* Zeroconf registration */
+    if (opt_zeroconf) {
+        if ((ret = dcc_zeroconf_register(&discovery, arg_port, n_cpus)) != 0)
+            return EXIT_CONNECT_FAILED;
+    }
+#endif
+        
     /* This is called in the master daemon, whether that is detached or
      * not.  */
     dcc_master_pid = getpid();
@@ -138,10 +150,21 @@ int dcc_standalone_server(void)
     if (opt_no_fork) {
         dcc_log_daemon_started("non-forking daemon");   
         dcc_nofork_parent(listen_fd);
+        ret = 0;
     } else {
         dcc_log_daemon_started("preforking daemon");
-        return dcc_preforking_parent(listen_fd);
+        ret = dcc_preforking_parent(listen_fd);
     }
+
+#ifdef HAVE_HOWL
+    /* Remove zeroconf registration */
+    if (opt_zeroconf) {
+        if ((ret = dcc_zeroconf_unregister(discovery)) != 0)
+            return EXIT_CONNECT_FAILED;
+    }
+#endif
+    
+    return ret;
 }
 
 
--- distcc-2.18.1.orig/src/tempfile.c	2004-11-03 03:47:22.000000000 +0100
+++ distcc-2.18.1/src/tempfile.c	2004-11-27 03:57:52.000000000 +0100
@@ -161,7 +161,7 @@ int dcc_get_top_dir(char **path_ret)
  * Return a subdirectory of the DISTCC_DIR of the given name, making
  * sure that the directory exists.
  **/
-static int dcc_get_subdir(const char *name,
+int dcc_get_subdir(const char *name,
                           char **dir_ret)
 {
     int ret;
--- distcc-2.18.1.orig/src/zeroconf.c	1970-01-01 01:00:00.000000000 +0100
+++ distcc-2.18.1/src/zeroconf.c	2004-11-28 16:42:15.000000000 +0100
@@ -0,0 +1,493 @@
+/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <sys/select.h>
+#include <signal.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#include "distcc.h"
+#include "hosts.h"
+#include "zeroconf.h"
+#include "trace.h"
+#include "exitcode.h"
+
+/* How long shall the background daemon be idle before i terminates itself? */
+#define MAX_IDLE_TIME 20
+
+/* Maxium size of host file to load */
+#define MAX_FILE_SIZE (1024*100)
+
+/* Zeroconf service wrapper */
+struct host {
+    struct host *next;
+    sw_ipv4_address address;
+    sw_port port;
+    sw_uint32 iface;
+    char *service;
+    char *domain;
+    int n_cpus;
+};
+
+/* General daemon data */
+struct daemon_data {
+    struct host *hosts;
+    int fd;
+    int n_slots;
+};
+
+/* A generic, system independant lock routine, similar to sys_lock,
+ * but more powerful:
+ *        rw:         if non-zero: r/w lock instead of r/o lock
+ *        enable:     lock or unlock
+ *        block:      block when locking */
+static int generic_lock(int fd, int rw, int enable, int block) {
+#if defined(F_SETLK)
+    struct flock lockparam;
+
+    lockparam.l_type = enable ? (rw ? F_WRLCK : F_RDLCK) : F_UNLCK;
+    lockparam.l_whence = SEEK_SET;
+    lockparam.l_start = 0;
+    lockparam.l_len = 0;        /* whole file */
+    
+    return fcntl(fd, block ? F_SETLKW : F_SETLK, &lockparam);
+#elif defined(HAVE_FLOCK)
+    return flock(fd, (enable ? (rw ? LOCK_EX : LOCK_SH) : LOCK_UN) | (block ? LOCK_NB : 0));
+#elif defined(HAVE_LOCKF)
+    return lockf(fd, (enable ? (block ? F_LOCK : F_TLOCK) : F_ULOCK));
+#else
+#  error "No supported lock method.  Please port this code."
+#endif
+}
+
+/* Return the number of seconds, when the specified file was last
+ * read. If the atime of that file is < clip_time, use clip_time
+ * instead */
+static time_t fd_last_used(int fd, time_t clip_time) {
+    struct stat st;
+    time_t now, ft;
+    assert(fd >= 0);
+
+    if (fstat(fd, &st) < 0) {
+        rs_log_crit("fstat() failed: %s\n", strerror(errno));
+        return -1;
+    }
+    
+    if ((now = time(NULL)) == (time_t) -1) {
+        rs_log_crit("time() failed: %s\n", strerror(errno));
+        return -1;
+    }
+
+    ft = clip_time ? (st.st_atime < clip_time ? clip_time : st.st_atime) : st.st_atime;
+    assert(ft <= now);
+
+    return now - ft;
+}
+
+/* Write host data to host file */
+static int write_hosts(struct daemon_data *d) {
+    struct host *h;
+    int r = 0;
+    assert(d);
+
+    rs_log_info("writing zeroconf data.\n");
+
+    if (generic_lock(d->fd, 1, 1, 1) < 0) {
+        rs_log_crit("lock failed: %s\n", strerror(errno));
+        return -1;
+    }
+
+    if (lseek(d->fd, 0, SEEK_SET) < 0) {
+        rs_log_crit("lseek() failed: %s\n", strerror(errno));
+        return -1;
+    }
+
+    if (ftruncate(d->fd, 0) < 0) {
+        rs_log_crit("ftruncate() failed: %s\n", strerror(errno));
+        return -1;
+    }
+
+    for (h = d->hosts; h; h = h->next) {
+        char t[256], a[16];
+        snprintf(t, sizeof(t), "%s:%u/%i\n", sw_ipv4_address_name(h->address, a, sizeof(a)), h->port, d->n_slots * h->n_cpus);
+
+        if (dcc_writex(d->fd, t, strlen(t)) != 0) {
+            rs_log_crit("write() failed: %s\n", strerror(errno));
+            goto finish;
+        }
+    }
+
+    r = 0;
+    
+finish:
+
+    generic_lock(d->fd, 1, 0, 1);
+    return r;
+    
+};
+
+/* Free host data */
+static void free_host(struct host *h) {
+    assert(h);
+    free(h->service);
+    free(h->domain);
+    free(h);
+}
+
+/* Remove a service from the host list */
+static void remove_service(struct daemon_data *d, sw_uint32 iface, const char *name, const char *domain) {
+    struct host *h, *p = NULL;
+    assert(d);
+
+    for (h = d->hosts; h; h = h->next) {
+        if (h->iface == iface && !strcmp(h->service, name) && !strcmp(h->domain, domain)) {
+
+            if (p)
+                p->next = h->next;
+            else
+                d->hosts = h->next;
+
+            free_host(h);
+            
+            break;
+        } else
+            p = h;
+    }
+}
+
+/* Called when a resolve call completes */
+static sw_result resolve_reply(
+    sw_discovery discovery,
+    sw_discovery_oid oid,
+    sw_uint32 interface_index,
+    sw_const_string name,
+    sw_const_string type,
+    sw_const_string domain,
+    sw_ipv4_address address,
+    sw_port port,
+    sw_octets text_record,
+    sw_ulong text_record_len,
+    sw_opaque extra) {
+    
+    struct host *h;
+    struct daemon_data *d = extra;
+    int n_cpus = 1;
+    sw_text_record_iterator it;
+
+    /* Look for the number of CPUs in TXT RRs */
+    if (sw_text_record_iterator_init(&it, text_record, text_record_len) == SW_OKAY) {
+        sw_char key[255];
+        sw_octet val[256];
+        sw_ulong val_len = sizeof(val)-1;
+
+        memset(val, 0, sizeof(val));
+
+        while (sw_text_record_iterator_next(it, key, val, &val_len) == SW_OKAY) {
+            if (!strcmp(key, "cpus")) {
+                if ((n_cpus = atoi((char*) val)) <= 0)
+                    n_cpus = 1;
+            }
+        }
+        
+        sw_text_record_iterator_fina(it);
+    }
+
+    /* Add a new host */
+    h = malloc(sizeof(struct host));
+    assert(h);
+    h->service = strdup(name);
+    assert(h->service);
+    h->domain = strdup(domain);
+    assert(h->domain);
+    h->address = address;
+    h->port = port;
+    h->iface = interface_index;
+    h->next = d->hosts;
+    h->n_cpus = n_cpus;
+    d->hosts = h;
+
+    /* Write modified hosts file */
+    write_hosts(d);
+
+    /* Let's cancel this resolve request, we only need a single adress for this service */
+    sw_discovery_cancel(discovery, oid);
+    
+    return SW_OKAY;
+}
+
+/* Called whenever a new service is found or removed */
+static sw_result browse_reply(
+    sw_discovery discovery,
+    sw_discovery_oid oid,
+    sw_discovery_browse_status status,
+    sw_uint32 interface_index,
+    sw_const_string name,
+    sw_const_string type,
+    sw_const_string domain,
+    sw_opaque extra) {
+
+    struct daemon_data *d = extra;
+    assert(d);
+    
+    switch (status) {
+        case SW_DISCOVERY_BROWSE_ADD_SERVICE: {
+            sw_discovery_oid noid;
+
+            rs_log_info("new service: %s\n", name);
+
+            sw_discovery_resolve(discovery, 0, name, type, domain, resolve_reply, extra, &noid);
+            break;
+        }
+        case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: {
+
+            rs_log_info("removed service: %s\n", name);
+
+            remove_service(d, interface_index, name, domain);
+            write_hosts(d);
+            break;
+        }
+        default:
+            ;
+    }
+
+    return SW_OKAY;
+}
+
+/* The main function of the background daemon */
+static void daemon_proc(const char *host_file, const char *lock_file, int n_slots) {
+    sw_discovery_oid oid;
+    sw_discovery discovery;
+    int ret = 1;
+    int lock_fd = -1;
+    struct daemon_data d;
+    sw_salt salt;
+    time_t clip_time; 
+
+    /* Prepare daemon data structure */
+    d.fd = -1;
+    d.hosts = NULL;
+    d.n_slots = n_slots;
+    clip_time = time(NULL);
+
+    rs_log_info("zeroconf daemon running.\n");
+
+    /* Open daemon lock file and lock it */
+    if ((lock_fd = open(lock_file, O_RDWR|O_CREAT, 0666)) < 0) {
+        rs_log_crit("open('%s') failed: %s\n", lock_file, strerror(errno));
+        goto finish;
+    }
+
+    if (generic_lock(lock_fd, 1, 1, 0) < 0) {
+        /* lock failed, there's probably already another daemon running */
+        goto finish;
+    }
+
+    /* Open host file */
+    if ((d.fd = open(host_file, O_RDWR|O_CREAT, 0666)) < 0) {
+        rs_log_crit("open('%s') failed: %s\n", host_file, strerror(errno));
+        goto finish;
+    }
+
+    /* Clear host file */
+    write_hosts(&d);
+    
+    if (sw_discovery_init(&discovery) != SW_OKAY) {
+        rs_log_crit("sw_discovery_init() failed.\n");
+        goto finish;
+    }
+
+    /* Start discovery */
+    if (sw_discovery_browse(discovery, 0, "_distcc._tcp", NULL, browse_reply, &d, &oid) != SW_OKAY) {
+        rs_log_crit("sw_discovery_browse() failed.\n");
+        goto finish;
+    }
+
+    /* Get "salt" object for the main loop */
+    if (sw_discovery_salt(discovery, &salt) != SW_OKAY) {
+        rs_log_crit("sw_discovery_salt() failed.\n");
+        goto finish;
+    }
+
+    /* Check whether the host file has been used recently */
+    while (fd_last_used(d.fd, clip_time) <= MAX_IDLE_TIME) {
+        sw_ulong msecs = 500;
+
+        /* Iterate the main loop for 500ms */
+        if (sw_salt_step(salt, &msecs) != SW_OKAY) {
+            rs_log_crit("sw_salt_step() failed.\n");
+            goto finish;
+        }
+    }
+
+    /* Wer are idle */
+    rs_log_info("zeroconf daemon unused.\n");
+    
+    ret = 0;
+    
+finish:
+
+    /* Cleanup */
+    if (lock_fd >= 0) {
+        generic_lock(lock_fd, 1, 0, 0);
+        close(lock_fd);
+    }
+    
+    if (d.fd >= 0)
+        close(d.fd);
+
+    while (d.hosts) {
+        struct host *h = d.hosts;
+        d.hosts = d.hosts->next;
+        free_host(h);
+    }
+
+    rs_log_info("zeroconf daemon ended.\n");
+    
+    exit(ret);
+}
+
+/* Return path to the zeroconf directory in ~/.distcc */
+static int get_zeroconf_dir(char **dir_ret) {
+    static char *cached;
+    int ret;
+    
+    if (cached) {
+        *dir_ret = cached;
+        return 0;
+    } else {
+        ret = dcc_get_subdir("zeroconf", dir_ret);
+        if (ret == 0)
+            cached = *dir_ret;
+        return ret;
+    }
+}
+
+/* Get the host list from zeroconf */
+int dcc_zeroconf_add_hosts(struct dcc_hostdef **ret_list, int *ret_nhosts, int n_slots, struct dcc_hostdef **ret_prev) {
+    char host_file[PATH_MAX], lock_file[PATH_MAX], *s = NULL;
+    int lock_fd = -1, host_fd = -1;
+    int fork_daemon = 0;
+    int r = -1;
+    char *dir;
+    struct stat st;
+
+    if (get_zeroconf_dir(&dir) != 0) {
+        rs_log_crit("failed to get zeroconf dir.\n");
+        goto finish;
+    }
+    
+    snprintf(lock_file, sizeof(lock_file), "%s/lock", dir);
+    snprintf(host_file, sizeof(host_file), "%s/hosts", dir);
+
+    /* Open lock file */
+    if ((lock_fd = open(lock_file, O_RDWR|O_CREAT, 0666)) < 0) {
+        rs_log_crit("open('%s') failed: %s\n", lock_file, strerror(errno));
+        goto finish;
+    }
+
+    /* Try to lock the lock file */
+    if (generic_lock(lock_fd, 1, 1, 0) >= 0) {
+        /* The lock succeeded => there's no daemon running yet! */
+        fork_daemon = 1;
+        generic_lock(lock_fd, 1, 0, 0);
+    }
+    
+    close(lock_fd);
+
+    /* Shall we fork a new daemon? */
+    if (fork_daemon) {
+        pid_t pid;
+
+        rs_log_info("Spawning zeroconf daemon.\n");
+
+        if ((pid = fork()) == -1) {
+            rs_log_crit("fork() failed: %s\n", strerror(errno));
+            goto finish;
+        } else if (pid == 0) {
+            int fd;
+            /* Child */
+
+            /* Close file descriptors and replace them by /dev/null */
+            close(0);
+            close(1);
+            close(2);
+            fd = open("/dev/null", O_RDWR);
+            assert(fd == 0);
+            fd = dup(0);
+            assert(fd == 1);
+            fd = dup(0);
+            assert(fd == 2);
+
+#ifdef HAVE_SETSID
+            setsid();
+#endif
+            
+            chdir("/");
+            rs_add_logger(rs_logger_syslog, RS_LOG_DEBUG, NULL, 0);
+            daemon_proc(host_file, lock_file, n_slots);
+        }
+
+        /* Parent */
+
+        /* Wait some time for initial host gathering */
+        usleep(1000000);         /* 100 ms */
+
+    }
+
+    /* Open host list read-only */
+    if ((host_fd = open(host_file, O_RDONLY)) < 0) {
+        rs_log_crit("open('%s') failed: %s\n", host_file, strerror(errno));
+        goto finish;
+    }
+
+    /* A read lock */
+    if (generic_lock(host_fd, 0, 1, 1) < 0) {
+        rs_log_crit("lock failed: %s\n", strerror(errno));
+        goto finish;
+    }
+
+    /* Get file size */
+    if (fstat(host_fd, &st) < 0) {
+        rs_log_crit("stat() failed: %s\n", strerror(errno));
+        goto finish;
+    }
+
+    if (st.st_size >= MAX_FILE_SIZE) {
+        rs_log_crit("file too large.\n");
+        goto finish;
+    }
+
+    /* read file data */
+    s = malloc((size_t) st.st_size+1);
+    assert(s);
+
+    if (dcc_readx(host_fd, s, (size_t) st.st_size) != 0) {
+        rs_log_crit("failed to read from file.\n");
+        goto finish;
+    }
+    s[st.st_size] = 0;
+
+    /* Parse host data */
+    if (dcc_parse_hosts(s, host_file, ret_list, ret_nhosts, ret_prev) != 0) {
+        rs_log_crit("failed to parse host file.\n");
+        goto finish;
+    }
+
+    r = 0;
+
+finish:
+    if (host_fd >= 0) {
+        generic_lock(host_fd, 0, 0, 1);
+        close(host_fd);
+    }
+
+    free(s);
+
+    return r;
+}
+
--- distcc-2.18.1.orig/src/zeroconf.h	1970-01-01 01:00:00.000000000 +0100
+++ distcc-2.18.1/src/zeroconf.h	2004-11-28 16:42:15.000000000 +0100
@@ -0,0 +1,22 @@
+#ifndef foozeroconfhfoo
+#define foozeroconfhfoo
+
+#include <inttypes.h>
+
+/* HOWL 0.9.6 defines PACKAGE_NAME and friends. This is broken. As a
+ * workaround we undfined those macros here */
+
+#undef PACKAGE_NAME
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#undef PACKAGE_STRING
+
+#include <howl.h>
+
+int dcc_zeroconf_add_hosts(struct dcc_hostdef **re_list, int *ret_nhosts, int slots, struct dcc_hostdef **ret_prev);
+
+int dcc_zeroconf_register(sw_discovery *discovery, int port, int n_cpus);
+int dcc_zeroconf_unregister(sw_discovery discovery);
+
+#endif
--- distcc-2.18.1.orig/src/zeroconf-reg.c	1970-01-01 01:00:00.000000000 +0100
+++ distcc-2.18.1/src/zeroconf-reg.c	2004-11-28 02:41:31.000000000 +0100
@@ -0,0 +1,110 @@
+/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <sys/select.h>
+#include <signal.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#include "distcc.h"
+#include "zeroconf.h"
+#include "trace.h"
+#include "exitcode.h"
+
+/* Called when publishing of service data completes */
+static sw_result publish_reply(sw_discovery discovery, sw_discovery_publish_status status, sw_discovery_oid oid, sw_opaque extra) {
+    int *done = extra;
+    *done = 1;
+
+    if (status != SW_DISCOVERY_PUBLISH_STARTED && status != SW_DISCOVERY_PUBLISH_STOPPED)
+        rs_log_crit("zeroconf publishing failed (%i)", status);
+
+    return SW_OKAY;
+}
+
+/* register a distcc service in DNS-SD/mDNS with the given port and number of CPUs */
+int dcc_zeroconf_register(sw_discovery *discovery, int port, int n_cpus) {
+    sw_salt salt;
+    sw_discovery_oid oid;
+    int done = 0;
+    char service[256], hn[256], t[16];
+    sw_text_record txt;
+    
+    if (sw_discovery_init(discovery) != SW_OKAY) {
+        rs_log_crit("sw_discovery_init() failed.\n");
+        return EXIT_CONNECT_FAILED;
+    }
+
+    /* Prepare TXT RR */
+    if (sw_text_record_init(&txt) != SW_OKAY) {
+        rs_log_crit("sw_text_record_init() failed.\n");
+        sw_discovery_fina(*discovery);
+        return EXIT_CONNECT_FAILED;
+    }
+
+    if (sw_discovery_salt(*discovery, &salt) != SW_OKAY) {
+        rs_log_crit("sw_discovery_salt() failed.\n");
+        goto fail;
+    }
+
+    /* Prepare service name */
+    gethostname(hn, sizeof(hn)-1);
+    hn[sizeof(hn)-1] = 0;
+    snprintf(service, sizeof(service), "distcc@%s", hn);
+
+    /* Prepare TXT RR */
+    snprintf(t, sizeof(t), "cpus=%i", n_cpus);
+    sw_text_record_add_string(txt, t);
+
+    /* Publish the info */
+    if (sw_discovery_publish(
+            *discovery,
+            0,
+            service,
+            "_distcc._tcp",
+            NULL,
+            NULL,
+            (sw_port) port,
+            sw_text_record_bytes(txt),
+            sw_text_record_len(txt),
+            publish_reply,
+            &done,
+            &oid) != SW_OKAY) {
+        
+        rs_log_crit("sw_discovery_publish() failed.\n");
+        goto fail;
+    }
+
+    /* Wait until the publishing is finished */
+    while (!done) {
+        if (sw_salt_step(salt, NULL) != SW_OKAY) {
+            rs_log_crit("sw_salt() failed.\n");
+            goto fail;
+        }
+    
+    }
+
+    rs_log_info("zeroconf publishing complete");
+
+    sw_text_record_fina(txt); 
+    
+    return 0;
+    
+ fail:
+    
+    sw_discovery_fina(*discovery);
+    sw_text_record_fina(txt);
+    return EXIT_CONNECT_FAILED;
+}
+
+/* Unregister this server from DNS-SD/mDNS */
+int dcc_zeroconf_unregister(sw_discovery discovery) {
+
+    sw_discovery_fina(discovery);
+    return 0;
+}
--- distcc-2.18.1.orig/src/help.c	2004-11-03 03:47:22.000000000 +0100
+++ distcc-2.18.1/src/help.c	2004-11-28 03:15:49.000000000 +0100
@@ -62,6 +62,9 @@ int dcc_show_version(const char *prog)
 "distcc comes with ABSOLUTELY NO WARRANTY.  distcc is free software, and\n"
 "you may use, modify and redistribute it under the terms of the GNU \n"
 "General Public License version 2 or later.\n"
+#ifdef HAVE_HOWL
+"\nBuilt with Zeroconf support.\n"
+#endif
 "\n"
            ,
            prog, PACKAGE_VERSION, GNU_HOST, DISTCC_DEFAULT_PORT,
--- distcc-2.18.1.orig/src/hosts.c	2004-11-03 03:47:22.000000000 +0100
+++ distcc-2.18.1/src/hosts.c	2004-11-28 16:46:11.000000000 +0100
@@ -96,6 +96,10 @@
 #include "hosts.h"
 #include "exitcode.h"
 #include "snprintf.h"
+#ifdef HAVE_HOWL
+#include "zeroconf.h"
+#define ZEROCONF_MAGIC "+zeroconf"
+#endif
 
 const int dcc_default_port = DISTCC_DEFAULT_PORT;
 
@@ -134,9 +138,12 @@ int dcc_get_hostlist(struct dcc_hostdef 
     char *path, *top;
     int ret;
 
+    *ret_list = NULL;
+    *ret_nhosts = 0;
+
     if ((env = getenv("DISTCC_HOSTS")) != NULL) {
         rs_trace("read hosts from environment");
-        return dcc_parse_hosts(env, "$DISTCC_HOSTS", ret_list, ret_nhosts);
+        return dcc_parse_hosts(env, "$DISTCC_HOSTS", ret_list, ret_nhosts, NULL);
     }
 
     /* $DISTCC_DIR or ~/.distcc */
@@ -163,7 +170,7 @@ int dcc_get_hostlist(struct dcc_hostdef 
         rs_trace("not reading %s: %s", path, strerror(errno));
         free(path);
     }
-    
+
     /* FIXME: Clearer message? */
     rs_log_warning("no hostlist is set; can't distribute work");
 
@@ -346,17 +353,19 @@ static int dcc_parse_localhost(struct dc
  **/
 int dcc_parse_hosts(const char *where, const char *source_name,
                     struct dcc_hostdef **ret_list,
-                    int *ret_nhosts)
+                    int *ret_nhosts, struct dcc_hostdef **ret_prev)
 {
     int ret;
-    struct dcc_hostdef *prev, *curr;
+    struct dcc_hostdef *curr, *_prev;
+
+    if (!ret_prev) {
+        ret_prev = &_prev;
+        _prev = NULL;
+    }
 
     /* TODO: Check for '/' in places where it might cause trouble with
      * a lock file name. */
 
-    prev = NULL;
-    *ret_list = NULL;
-    *ret_nhosts = 0;
     /* A simple, hardcoded scanner.  Some of the GNU routines might be
      * useful here, but they won't work on less capable systems.
      *
@@ -390,6 +399,15 @@ int dcc_parse_hosts(const char *where, c
         token_start = where;
         token_len = strcspn(where, " #\t\n\f\r");
 
+#ifdef HAVE_HOWL
+        if (token_len == sizeof(ZEROCONF_MAGIC)-1 && 
+            !strncmp(token_start, ZEROCONF_MAGIC, (unsigned) token_len)) {
+            if ((ret = dcc_zeroconf_add_hosts(ret_list, ret_nhosts, 4, ret_prev) != 0))
+                return ret;
+            goto skip;
+        }
+#endif
+
         /* Allocate new list item */
         curr = calloc(1, sizeof(struct dcc_hostdef));
         if (!curr) {
@@ -404,8 +422,8 @@ int dcc_parse_hosts(const char *where, c
         }
 
         /* Link into list */
-        if (prev) {
-            prev->next = curr;
+        if (*ret_prev) {
+            (*ret_prev)->next = curr;
         } else {
             *ret_list = curr;   /* first */
         }
@@ -434,10 +452,15 @@ int dcc_parse_hosts(const char *where, c
                 return ret;
         }
 
+        (*ret_nhosts)++;
+        *ret_prev = curr;
+
+#ifdef HAVE_HOWL
+        skip:
+#endif
+        
         /* continue to next token if any */
         where = token_start + token_len;
-        prev = curr;
-        (*ret_nhosts)++;
     }
     
     if (*ret_nhosts) {
--- distcc-2.18.1.orig/src/io.c	2004-11-03 03:47:22.000000000 +0100
+++ distcc-2.18.1/src/io.c	2004-11-27 04:03:45.000000000 +0100
@@ -160,7 +160,7 @@ int dcc_readx(int fd, void *buf, size_t 
                 return ret;
             else
                 continue;
-        } else if (r == -1 && errno == EAGAIN) {
+        } else if (r == -1 && errno == EINTR) {
             continue;
         } else if (r == -1) {
 	    rs_log_error("failed to read: %s", strerror(errno));
@@ -202,9 +202,6 @@ int dcc_writex(int fd, const void *buf, 
         } else if (r == -1) {
             rs_log_error("failed to write: %s", strerror(errno));
             return EXIT_IO_ERROR;
-        } else if (r == 0) {
-            rs_log_error("unexpected eof on fd%d", fd);
-            return EXIT_TRUNCATED;
         } else {
             buf = &((char *) buf)[r];
             len -= r;
--- distcc-2.18.1.orig/src/hostfile.c	2004-11-03 03:47:22.000000000 +0100
+++ distcc-2.18.1/src/hostfile.c	2004-11-28 16:44:58.000000000 +0100
@@ -59,7 +59,7 @@ int dcc_parse_hosts_file(const char *fna
     if ((ret = dcc_load_file_string(fname, &body)) != 0)
         return ret;
 
-    ret = dcc_parse_hosts(body, fname, ret_list, ret_nhosts);
+    ret = dcc_parse_hosts(body, fname, ret_list, ret_nhosts, NULL);
 
     free(body);
 
