]> code.ossystems Code Review - openembedded-core.git/commitdiff
distcc: Add patch to poky since upstream keep changing it
authorRichard Purdie <richard@openedhand.com>
Wed, 16 Jan 2008 11:01:35 +0000 (11:01 +0000)
committerRichard Purdie <richard@openedhand.com>
Wed, 16 Jan 2008 11:01:35 +0000 (11:01 +0000)
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@3497 311d38ba-8fff-0310-9ca6-ca027cbcb966

meta/packages/distcc/distcc_2.18.3.bb
meta/packages/distcc/files/distcc-avahi.patch [new file with mode: 0644]

index 82f45e61c209af004a7fddd7758180c432ff8e2f..dd45223603f5618eb0004dac83d81aae4221c51b 100644 (file)
@@ -7,8 +7,10 @@ PR = "r3"
 DEPENDS = "avahi gtk+"
 RRECOMMENDS = "avahi-daemon"
 
+# Upstream change this patch periodically so store locally
+# http://0pointer.de/public/distcc-avahi.patch
 SRC_URI = "http://distcc.samba.org/ftp/distcc/distcc-${PV}.tar.bz2 \
-          http://0pointer.de/public/distcc-avahi.patch;patch=1 \
+           file://distcc-avahi.patch;patch=1 \   
           file://default \
           file://distcc"
 
diff --git a/meta/packages/distcc/files/distcc-avahi.patch b/meta/packages/distcc/files/distcc-avahi.patch
new file mode 100644 (file)
index 0000000..1702ea7
--- /dev/null
@@ -0,0 +1,1736 @@
+--- upstream/aclocal.m4        1970-01-01 01:00:00.000000000 +0100
++++ lennart/aclocal.m4 2005-11-18 04:19:18.000000000 +0100
+@@ -0,0 +1,171 @@
++# generated automatically by aclocal 1.9.6 -*- Autoconf -*-
++
++# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
++# 2005  Free Software Foundation, Inc.
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
++# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
++# PARTICULAR PURPOSE.
++
++# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
++# 
++# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
++#
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++# General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++#
++# As a special exception to the GNU General Public License, if you
++# distribute this file as part of a program that contains a
++# configuration script generated by Autoconf, you may include it under
++# the same distribution terms that you use for the rest of that program.
++
++# PKG_PROG_PKG_CONFIG([MIN-VERSION])
++# ----------------------------------
++AC_DEFUN([PKG_PROG_PKG_CONFIG],
++[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
++m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
++AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
++if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
++      AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
++fi
++if test -n "$PKG_CONFIG"; then
++      _pkg_min_version=m4_default([$1], [0.9.0])
++      AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
++      if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
++              AC_MSG_RESULT([yes])
++      else
++              AC_MSG_RESULT([no])
++              PKG_CONFIG=""
++      fi
++              
++fi[]dnl
++])# PKG_PROG_PKG_CONFIG
++
++# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
++#
++# Check to see whether a particular set of modules exists.  Similar
++# to PKG_CHECK_MODULES(), but does not set variables or print errors.
++#
++#
++# Similar to PKG_CHECK_MODULES, make sure that the first instance of
++# this or PKG_CHECK_MODULES is called, or make sure to call
++# PKG_CHECK_EXISTS manually
++# --------------------------------------------------------------
++AC_DEFUN([PKG_CHECK_EXISTS],
++[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
++if test -n "$PKG_CONFIG" && \
++    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
++  m4_ifval([$2], [$2], [:])
++m4_ifvaln([$3], [else
++  $3])dnl
++fi])
++
++
++# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
++# ---------------------------------------------
++m4_define([_PKG_CONFIG],
++[if test -n "$PKG_CONFIG"; then
++    if test -n "$$1"; then
++        pkg_cv_[]$1="$$1"
++    else
++        PKG_CHECK_EXISTS([$3],
++                         [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
++                       [pkg_failed=yes])
++    fi
++else
++      pkg_failed=untried
++fi[]dnl
++])# _PKG_CONFIG
++
++# _PKG_SHORT_ERRORS_SUPPORTED
++# -----------------------------
++AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
++[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
++if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
++        _pkg_short_errors_supported=yes
++else
++        _pkg_short_errors_supported=no
++fi[]dnl
++])# _PKG_SHORT_ERRORS_SUPPORTED
++
++
++# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
++# [ACTION-IF-NOT-FOUND])
++#
++#
++# Note that if there is a possibility the first call to
++# PKG_CHECK_MODULES might not happen, you should be sure to include an
++# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
++#
++#
++# --------------------------------------------------------------
++AC_DEFUN([PKG_CHECK_MODULES],
++[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
++AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
++AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
++
++pkg_failed=no
++AC_MSG_CHECKING([for $1])
++
++_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
++_PKG_CONFIG([$1][_LIBS], [libs], [$2])
++
++m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
++and $1[]_LIBS to avoid the need to call pkg-config.
++See the pkg-config man page for more details.])
++
++if test $pkg_failed = yes; then
++        _PKG_SHORT_ERRORS_SUPPORTED
++        if test $_pkg_short_errors_supported = yes; then
++              $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"`
++        else 
++              $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
++        fi
++      # Put the nasty error message in config.log where it belongs
++      echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
++
++      ifelse([$4], , [AC_MSG_ERROR(dnl
++[Package requirements ($2) were not met:
++
++$$1_PKG_ERRORS
++
++Consider adjusting the PKG_CONFIG_PATH environment variable if you
++installed software in a non-standard prefix.
++
++_PKG_TEXT
++])],
++              [$4])
++elif test $pkg_failed = untried; then
++      ifelse([$4], , [AC_MSG_FAILURE(dnl
++[The pkg-config script could not be found or is too old.  Make sure it
++is in your PATH or set the PKG_CONFIG environment variable to the full
++path to pkg-config.
++
++_PKG_TEXT
++
++To get pkg-config, see <http://www.freedesktop.org/software/pkgconfig>.])],
++              [$4])
++else
++      $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
++      $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
++        AC_MSG_RESULT([yes])
++      ifelse([$3], , :, [$3])
++fi[]dnl
++])# PKG_CHECK_MODULES
++
++m4_include([acinclude.m4])
+--- upstream/Makefile.in       2005-11-18 16:15:40.000000000 +0100
++++ lennart/Makefile.in        2005-11-18 01:14:43.000000000 +0100
+@@ -171,6 +171,7 @@
+       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                                            \
+@@ -178,6 +179,7 @@
+       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
+--- upstream/src/distcc.c      2005-11-18 16:15:40.000000000 +0100
++++ lennart/src/distcc.c       2005-11-18 01:14:43.000000000 +0100
+@@ -83,6 +83,9 @@
+ "   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 @@
+     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 @@
+             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
+--- upstream/src/distcc.h      2005-11-18 16:15:40.000000000 +0100
++++ lennart/src/distcc.h       2005-11-18 01:14:43.000000000 +0100
+@@ -112,7 +112,7 @@
+                         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_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;
+--- upstream/src/dopt.c        2005-11-18 16:15:40.000000000 +0100
++++ lennart/src/dopt.c 2005-11-18 04:14:26.000000000 +0100
+@@ -93,6 +93,10 @@
+     opt_log_level
+ };
++#ifdef HAVE_AVAHI
++/* Flag for enabling/disabling Zeroconf using Avahi */
++int opt_zeroconf = 0;
++#endif
+ const struct poptOption options[] = {
+     { "allow", 'a',      POPT_ARG_STRING, 0, 'a', 0, 0 },
+@@ -115,6 +119,9 @@
+     { "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_AVAHI    
++    { "zeroconf", 0,     POPT_ARG_NONE, &opt_zeroconf, 0, 0, 0 },
++#endif    
+     { 0, 0, 0, 0, 0, 0, 0 }
+ };
+@@ -137,6 +144,9 @@
+ "    -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_AVAHI
++"    --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"
+--- upstream/src/dopt.h        2005-11-18 16:15:40.000000000 +0100
++++ lennart/src/dopt.h 2005-11-18 02:27:45.000000000 +0100
+@@ -38,3 +38,7 @@
+ extern int opt_lifetime;
+ extern char *opt_listen_addr;
+ extern int opt_niceness;
++
++#ifdef HAVE_AVAHI
++extern int opt_zeroconf;
++#endif
+--- upstream/src/dparent.c     2005-11-18 16:15:40.000000000 +0100
++++ lennart/src/dparent.c      2005-11-18 04:13:23.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 listen_fd;
+     int n_cpus;
+     int ret;
++#ifdef HAVE_AVAHI
++    void *avahi = NULL;
++#endif
+     if ((ret = dcc_socket_listen(arg_port, &listen_fd, opt_listen_addr)) != 0)
+         return ret;
+@@ -131,6 +135,14 @@
+     /* Don't catch signals until we've detached or created a process group. */
+     dcc_daemon_catch_signals();
++#ifdef HAVE_AVAHI      
++    /* Zeroconf registration */
++    if (opt_zeroconf) {
++        if (!(avahi = dcc_zeroconf_register((uint16_t) arg_port, n_cpus)))
++            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 @@
+     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_AVAHI
++    /* Remove zeroconf registration */
++    if (opt_zeroconf) {
++        if (dcc_zeroconf_unregister(avahi) != 0)
++            return EXIT_CONNECT_FAILED;
++    }
++#endif
++    
++    return ret;
+ }
+--- upstream/src/help.c        2005-11-18 16:15:40.000000000 +0100
++++ lennart/src/help.c 2005-11-18 02:27:45.000000000 +0100
+@@ -62,6 +62,9 @@
+ "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_AVAHI
++"\nBuilt with Zeroconf support.\n"
++#endif
+ "\n"
+            ,
+            prog, PACKAGE_VERSION, GNU_HOST, DISTCC_DEFAULT_PORT,
+--- upstream/src/hostfile.c    2005-11-18 16:15:40.000000000 +0100
++++ lennart/src/hostfile.c     2005-11-18 01:14:43.000000000 +0100
+@@ -59,7 +59,7 @@
+     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);
+--- upstream/src/hosts.c       2005-11-18 16:15:40.000000000 +0100
++++ lennart/src/hosts.c        2005-11-18 02:27:45.000000000 +0100
+@@ -96,6 +96,10 @@
+ #include "hosts.h"
+ #include "exitcode.h"
+ #include "snprintf.h"
++#ifdef HAVE_AVAHI
++#include "zeroconf.h"
++#define ZEROCONF_MAGIC "+zeroconf"
++#endif
+ const int dcc_default_port = DISTCC_DEFAULT_PORT;
+@@ -134,9 +138,12 @@
+     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 @@
+         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 @@
+  **/
+ 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 @@
+         token_start = where;
+         token_len = strcspn(where, " #\t\n\f\r");
++#ifdef HAVE_AVAHI
++        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 @@
+         }
+         /* Link into list */
+-        if (prev) {
+-            prev->next = curr;
++        if (*ret_prev) {
++            (*ret_prev)->next = curr;
+         } else {
+             *ret_list = curr;   /* first */
+         }
+@@ -434,10 +452,15 @@
+                 return ret;
+         }
++        (*ret_nhosts)++;
++        *ret_prev = curr;
++
++#ifdef HAVE_AVAHI
++        skip:
++#endif
++        
+         /* continue to next token if any */
+         where = token_start + token_len;
+-        prev = curr;
+-        (*ret_nhosts)++;
+     }
+     
+     if (*ret_nhosts) {
+--- upstream/src/io.c  2005-11-18 16:15:40.000000000 +0100
++++ lennart/src/io.c   2005-11-18 01:14:43.000000000 +0100
+@@ -163,7 +163,7 @@
+                 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));
+@@ -205,9 +205,6 @@
+         } 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;
+--- upstream/src/tempfile.c    2005-11-18 16:15:40.000000000 +0100
++++ lennart/src/tempfile.c     2005-11-18 01:14:43.000000000 +0100
+@@ -161,7 +161,7 @@
+  * 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;
+--- upstream/configure.ac      2005-11-18 16:15:40.000000000 +0100
++++ lennart/configure.ac       2005-11-18 04:18:07.000000000 +0100
+@@ -388,6 +388,23 @@
+     AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1, [define if you have struct sockaddr_storage]),,
+     [#include <sys/socket.h>])
++dnl check for avahi
++PKG_CHECK_MODULES(AVAHI, [avahi-client >= 0.6],
++[AC_DEFINE(HAVE_AVAHI, 1, [defined if Avahi is available])
++CFLAGS="$CFLAGS $AVAHI_CFLAGS"
++LIBS="$LIBS $AVAHI_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)
++
++ACX_PTHREAD
++LIBS="$PTHREAD_LIBS $LIBS"
++CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
++CC="$PTHREAD_CC"
++
+ dnl ##### Output
+ AC_SUBST(docdir)
+ AC_SUBST(CFLAGS)
+--- upstream/acinclude.m4      1970-01-01 01:00:00.000000000 +0100
++++ lennart/acinclude.m4       2005-11-18 04:17:08.000000000 +0100
+@@ -0,0 +1,235 @@
++dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
++dnl
++dnl This macro figures out how to build C programs using POSIX threads.
++dnl It sets the PTHREAD_LIBS output variable to the threads library and
++dnl linker flags, and the PTHREAD_CFLAGS output variable to any special
++dnl C compiler flags that are needed. (The user can also force certain
++dnl compiler flags/libs to be tested by setting these environment
++dnl variables.)
++dnl
++dnl Also sets PTHREAD_CC to any special C compiler that is needed for
++dnl multi-threaded programs (defaults to the value of CC otherwise).
++dnl (This is necessary on AIX to use the special cc_r compiler alias.)
++dnl
++dnl NOTE: You are assumed to not only compile your program with these
++dnl flags, but also link it with them as well. e.g. you should link
++dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
++dnl $LIBS
++dnl
++dnl If you are only building threads programs, you may wish to use
++dnl these variables in your default LIBS, CFLAGS, and CC:
++dnl
++dnl        LIBS="$PTHREAD_LIBS $LIBS"
++dnl        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
++dnl        CC="$PTHREAD_CC"
++dnl
++dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
++dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
++dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
++dnl
++dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
++dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to
++dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the
++dnl default action will define HAVE_PTHREAD.
++dnl
++dnl Please let the authors know if this macro fails on any platform, or
++dnl if you have any other suggestions or comments. This macro was based
++dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with
++dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros
++dnl posted by Alejandro Forero Cuervo to the autoconf macro repository.
++dnl We are also grateful for the helpful feedback of numerous users.
++dnl
++dnl @category InstalledPackages
++dnl @author Steven G. Johnson <stevenj@alum.mit.edu>
++dnl @version 2005-01-14
++dnl @license GPLWithACException
++
++AC_DEFUN([ACX_PTHREAD], [
++AC_REQUIRE([AC_CANONICAL_HOST])
++AC_LANG_SAVE
++AC_LANG_C
++acx_pthread_ok=no
++
++# We used to check for pthread.h first, but this fails if pthread.h
++# requires special compiler flags (e.g. on True64 or Sequent).
++# It gets checked for in the link test anyway.
++
++# First of all, check if the user has set any of the PTHREAD_LIBS,
++# etcetera environment variables, and if threads linking works using
++# them:
++if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
++        save_CFLAGS="$CFLAGS"
++        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
++        save_LIBS="$LIBS"
++        LIBS="$PTHREAD_LIBS $LIBS"
++        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
++        AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
++        AC_MSG_RESULT($acx_pthread_ok)
++        if test x"$acx_pthread_ok" = xno; then
++                PTHREAD_LIBS=""
++                PTHREAD_CFLAGS=""
++        fi
++        LIBS="$save_LIBS"
++        CFLAGS="$save_CFLAGS"
++fi
++
++# We must check for the threads library under a number of different
++# names; the ordering is very important because some systems
++# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
++# libraries is broken (non-POSIX).
++
++# Create a list of thread flags to try.  Items starting with a "-" are
++# C compiler flags, and other items are library names, except for "none"
++# which indicates that we try without any flags at all, and "pthread-config"
++# which is a program returning the flags for the Pth emulation library.
++
++acx_pthread_flags="pthreads pthread none -Kthread -kthread lthread -pthread -pthreads -mthreads --thread-safe -mt pthread-config"
++
++# The ordering *is* (sometimes) important.  Some notes on the
++# individual items follow:
++
++# pthreads: AIX (must check this before -lpthread)
++# none: in case threads are in libc; should be tried before -Kthread and
++#       other compiler flags to prevent continual compiler warnings
++# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
++# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
++# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
++# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
++# -pthreads: Solaris/gcc
++# -mthreads: Mingw32/gcc, Lynx/gcc
++# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
++#      doesn't hurt to check since this sometimes defines pthreads too;
++#      also defines -D_REENTRANT)
++# pthread: Linux, etcetera
++# --thread-safe: KAI C++
++# pthread-config: use pthread-config program (for GNU Pth library)
++
++case "${host_cpu}-${host_os}" in
++        *solaris*)
++
++        # On Solaris (at least, for some versions), libc contains stubbed
++        # (non-functional) versions of the pthreads routines, so link-based
++        # tests will erroneously succeed.  (We need to link with -pthread or
++        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
++        # a function called by this macro, so we could check for that, but
++        # who knows whether they'll stub that too in a future libc.)  So,
++        # we'll just look for -pthreads and -lpthread first:
++
++        acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags"
++        ;;
++esac
++
++if test x"$acx_pthread_ok" = xno; then
++for flag in $acx_pthread_flags; do
++
++        case $flag in
++                none)
++                AC_MSG_CHECKING([whether pthreads work without any flags])
++                ;;
++
++                -*)
++                AC_MSG_CHECKING([whether pthreads work with $flag])
++                PTHREAD_CFLAGS="$flag"
++                ;;
++
++              pthread-config)
++              AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
++              if test x"$acx_pthread_config" = xno; then continue; fi
++              PTHREAD_CFLAGS="`pthread-config --cflags`"
++              PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
++              ;;
++
++                *)
++                AC_MSG_CHECKING([for the pthreads library -l$flag])
++                PTHREAD_LIBS="-l$flag"
++                ;;
++        esac
++
++        save_LIBS="$LIBS"
++        save_CFLAGS="$CFLAGS"
++        LIBS="$PTHREAD_LIBS $LIBS"
++        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
++
++        # Check for various functions.  We must include pthread.h,
++        # since some functions may be macros.  (On the Sequent, we
++        # need a special flag -Kthread to make this header compile.)
++        # We check for pthread_join because it is in -lpthread on IRIX
++        # while pthread_create is in libc.  We check for pthread_attr_init
++        # due to DEC craziness with -lpthreads.  We check for
++        # pthread_cleanup_push because it is one of the few pthread
++        # functions on Solaris that doesn't have a non-functional libc stub.
++        # We try pthread_create on general principles.
++        AC_TRY_LINK([#include <pthread.h>],
++                    [pthread_t th; pthread_join(th, 0);
++                     pthread_attr_init(0); pthread_cleanup_push(0, 0);
++                     pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
++                    [acx_pthread_ok=yes])
++
++        LIBS="$save_LIBS"
++        CFLAGS="$save_CFLAGS"
++
++        AC_MSG_RESULT($acx_pthread_ok)
++        if test "x$acx_pthread_ok" = xyes; then
++                break;
++        fi
++
++        PTHREAD_LIBS=""
++        PTHREAD_CFLAGS=""
++done
++fi
++
++# Various other checks:
++if test "x$acx_pthread_ok" = xyes; then
++        save_LIBS="$LIBS"
++        LIBS="$PTHREAD_LIBS $LIBS"
++        save_CFLAGS="$CFLAGS"
++        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
++
++        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
++      AC_MSG_CHECKING([for joinable pthread attribute])
++      attr_name=unknown
++      for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
++          AC_TRY_LINK([#include <pthread.h>], [int attr=$attr;],
++                        [attr_name=$attr; break])
++      done
++        AC_MSG_RESULT($attr_name)
++        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
++            AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
++                               [Define to necessary symbol if this constant
++                                uses a non-standard name on your system.])
++        fi
++
++        AC_MSG_CHECKING([if more special flags are required for pthreads])
++        flag=no
++        case "${host_cpu}-${host_os}" in
++            *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
++            *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
++        esac
++        AC_MSG_RESULT(${flag})
++        if test "x$flag" != xno; then
++            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
++        fi
++
++        LIBS="$save_LIBS"
++        CFLAGS="$save_CFLAGS"
++
++        # More AIX lossage: must compile with cc_r
++        AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC})
++else
++        PTHREAD_CC="$CC"
++fi
++
++AC_SUBST(PTHREAD_LIBS)
++AC_SUBST(PTHREAD_CFLAGS)
++AC_SUBST(PTHREAD_CC)
++
++# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
++if test x"$acx_pthread_ok" = xyes; then
++        ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
++        :
++else
++        acx_pthread_ok=no
++        $2
++fi
++AC_LANG_RESTORE
++])dnl ACX_PTHREAD
+--- upstream/src/zeroconf.h    1970-01-01 01:00:00.000000000 +0100
++++ lennart/src/zeroconf.h     2005-11-18 04:06:29.000000000 +0100
+@@ -0,0 +1,13 @@
++#ifndef foozeroconfhfoo
++#define foozeroconfhfoo
++
++#include <inttypes.h>
++
++int dcc_zeroconf_add_hosts(struct dcc_hostdef **re_list, int *ret_nhosts, int slots, struct dcc_hostdef **ret_prev);
++
++void * dcc_zeroconf_register(uint16_t port, int n_cpus);
++int dcc_zeroconf_unregister(void*);
++
++#define DCC_DNS_SERVICE_TYPE "_distcc._tcp"
++
++#endif
+--- upstream/src/zeroconf.c    1970-01-01 01:00:00.000000000 +0100
++++ lennart/src/zeroconf.c     2005-11-18 15:51:45.000000000 +0100
+@@ -0,0 +1,602 @@
++/* -*- 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 <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <limits.h>
++
++#include <avahi-common/domain.h>
++#include <avahi-common/error.h>
++#include <avahi-common/malloc.h>
++#include <avahi-common/address.h>
++#include <avahi-common/simple-watch.h>
++#include <avahi-client/lookup.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)
++
++/* General daemon data */
++struct daemon_data {
++    struct host *hosts;
++    int fd;
++    int n_slots;
++
++    AvahiClient *client;
++    AvahiServiceBrowser *browser;
++    AvahiSimplePoll *simple_poll;
++};
++
++/* Zeroconf service wrapper */
++struct host {
++    struct daemon_data *daemon_data;
++    struct host *next;
++    
++    AvahiIfIndex interface;
++    AvahiProtocol protocol;
++    char *service;
++    char *domain;
++
++    AvahiAddress address;
++    uint16_t port;
++    int n_cpus;
++
++    AvahiServiceResolver *resolver;
++};
++
++/* 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[AVAHI_ADDRESS_STR_MAX];
++
++        if (h->resolver)
++            /* Not yet fully resolved */
++            continue;
++        
++        snprintf(t, sizeof(t), "%s:%u/%i\n", avahi_address_snprint(a, sizeof(a), &h->address), 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);
++
++    if (h->resolver)
++        avahi_service_resolver_free(h->resolver);
++    
++    free(h->service);
++    free(h->domain);
++    free(h);
++}
++
++/* Remove a service from the host list */
++static void remove_service(struct daemon_data *d, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *domain) {
++    struct host *h, *p = NULL;
++    assert(d);
++
++    for (h = d->hosts; h; h = h->next) {
++        if (h->interface == interface &&
++            h->protocol == protocol &&
++            !strcmp(h->service, name) &&
++            avahi_domain_equal(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 void resolve_reply(AvahiServiceResolver *UNUSED(r),
++                          AvahiIfIndex UNUSED(interface),
++                          AvahiProtocol UNUSED(protocol),
++                          AvahiResolverEvent event,
++                          const char *name,
++                          const char *UNUSED(type),
++                          const char *UNUSED(domain),
++                          const char *UNUSED(host_name),
++                          const AvahiAddress *a,
++                          uint16_t port,
++                          AvahiStringList *txt,
++                          AvahiLookupResultFlags UNUSED(flags),
++                          void *userdata) {
++    
++    struct host *h = userdata;
++
++    switch (event) {
++        
++    case AVAHI_RESOLVER_FOUND: {
++        AvahiStringList *i;
++        
++        /* Look for the number of CPUs in TXT RRs */
++        for (i = txt; i; i = i->next) {
++            char *key, *value;
++            
++            if (avahi_string_list_get_pair(i, &key, &value, NULL) < 0)
++                continue;
++            
++            if (!strcmp(key, "cpus"))
++                if ((h->n_cpus = atoi(value)) <= 0)
++                    h->n_cpus = 1;
++            
++            avahi_free(key);
++            avahi_free(value);
++        }
++
++        h->address = *a;
++        h->port = port;
++        
++        avahi_service_resolver_free(h->resolver);
++        h->resolver = NULL;
++
++        /* Write modified hosts file */
++        write_hosts(h->daemon_data);
++
++        break;
++    }
++
++    case AVAHI_RESOLVER_FAILURE:
++
++        rs_log_warning("Failed to resolve service '%s': %s\n", name,
++                    avahi_strerror(avahi_client_errno(h->daemon_data->client)));
++
++        free_host(h);
++        break;
++    }
++
++}
++
++/* Called whenever a new service is found or removed */
++static void browse_reply(AvahiServiceBrowser *UNUSED(b),
++                         AvahiIfIndex interface,
++                         AvahiProtocol protocol,
++                         AvahiBrowserEvent event,
++                         const char *name,
++                         const char *type,
++                         const char *domain,
++                         AvahiLookupResultFlags UNUSED(flags),
++                         void *userdata) {
++     
++    struct daemon_data *d = userdata;
++    assert(d);
++    
++    switch (event) {
++    case AVAHI_BROWSER_NEW: {
++        struct host *h;
++
++        h = malloc(sizeof(struct host));
++        assert(h);
++        
++        rs_log_info("new service: %s\n", name);
++
++        if (!(h->resolver = avahi_service_resolver_new(d->client,
++                                                       interface,
++                                                       protocol,
++                                                       name,
++                                                       type,
++                                                       domain,
++                                                       AVAHI_PROTO_UNSPEC, 
++                                                       0,
++                                                       resolve_reply,
++                                                       h))) {
++            rs_log_warning("Failed to create service resolver for '%s': %s\n", name,
++                           avahi_strerror(avahi_client_errno(d->client)));
++
++            free(h);
++            
++        } else {
++
++            /* Fill in missing data */
++            h->service = strdup(name);
++            assert(h->service);
++            h->domain = strdup(domain);
++            assert(h->domain);
++            h->daemon_data = d;
++            h->interface = interface;
++            h->protocol = protocol;
++            h->next = d->hosts;
++            h->n_cpus = 1;
++            d->hosts = h;
++        }
++
++        break;
++    }
++        
++    case AVAHI_BROWSER_REMOVE:
++
++        rs_log_info("Removed service: %s\n", name);
++
++        remove_service(d, interface, protocol, name, domain);
++        write_hosts(d);
++        break;
++
++    case AVAHI_BROWSER_FAILURE:
++        rs_log_crit("Service Browser failure '%s': %s\n", name,
++                       avahi_strerror(avahi_client_errno(d->client)));
++
++        avahi_simple_poll_quit(d->simple_poll);
++        break;
++        
++    case AVAHI_BROWSER_CACHE_EXHAUSTED:
++    case AVAHI_BROWSER_ALL_FOR_NOW:
++        ;
++
++    }
++}
++
++static void client_callback(AvahiClient *client, AvahiClientState state, void *userdata) {
++    struct daemon_data *d = userdata;
++
++    switch (state) {
++        
++    case AVAHI_CLIENT_FAILURE:
++        rs_log_crit("Client failure: %s\n", avahi_strerror(avahi_client_errno(client)));
++        avahi_simple_poll_quit(d->simple_poll);
++        break;
++
++    case AVAHI_CLIENT_S_COLLISION:
++    case AVAHI_CLIENT_S_REGISTERING:
++    case AVAHI_CLIENT_S_RUNNING:
++    case AVAHI_CLIENT_CONNECTING:
++        ;
++    }
++}
++
++/* The main function of the background daemon */
++static void daemon_proc(const char *host_file, const char *lock_file, int n_slots) {
++    int ret = 1;
++    int lock_fd = -1;
++    struct daemon_data d;
++    time_t clip_time;
++    int error;
++
++    rs_add_logger(rs_logger_syslog, RS_LOG_DEBUG, NULL, 0);
++
++    /* Prepare daemon data structure */
++    d.fd = -1;
++    d.hosts = NULL;
++    d.n_slots = n_slots;
++    d.simple_poll = NULL;
++    d.browser = NULL;
++    d.client = NULL;
++    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 (!(d.simple_poll = avahi_simple_poll_new())) {
++        rs_log_crit("Failed to create simple poll object.\n");
++        goto finish;
++    }
++    
++    if (!(d.client = avahi_client_new(avahi_simple_poll_get(d.simple_poll),
++                                    0,
++                                    client_callback,
++                                    &d,
++                                    &error))) {
++        rs_log_crit("Failed to create Avahi client object: %s\n", avahi_strerror(error));
++        goto finish;
++    }
++
++    if (!(d.browser = avahi_service_browser_new(d.client,
++                                    AVAHI_IF_UNSPEC,
++                                    AVAHI_PROTO_UNSPEC,
++                                    DCC_DNS_SERVICE_TYPE,
++                                    NULL,
++                                    0,
++                                    browse_reply,
++                                    &d))) {
++        rs_log_crit("Failed to create service browser object: %s\n", avahi_strerror(avahi_client_errno(d.client)));
++        goto finish;
++    }
++    
++    /* Check whether the host file has been used recently */
++    while (fd_last_used(d.fd, clip_time) <= MAX_IDLE_TIME) {
++
++        /* Iterate the main loop for 500ms */
++        if (avahi_simple_poll_iterate(d.simple_poll, 500) != 0) {
++            rs_log_crit("Event loop exited abnormaly.\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);
++    }
++
++    if (d.client)
++        avahi_client_free(d.client);
++
++    if (d.simple_poll)
++        avahi_simple_poll_free(d.simple_poll);
++    
++    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);         /* 1000 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;
++}
++
+--- upstream/src/zeroconf-reg.c        1970-01-01 01:00:00.000000000 +0100
++++ lennart/src/zeroconf-reg.c 2005-11-18 15:34:00.000000000 +0100
+@@ -0,0 +1,297 @@
++/* -*- 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 <sys/poll.h>
++#include <pthread.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <errno.h>
++
++#include <avahi-common/simple-watch.h>
++#include <avahi-common/error.h>
++#include <avahi-common/alternative.h>
++#include <avahi-common/malloc.h>
++#include <avahi-client/publish.h>
++
++#include "distcc.h"
++#include "zeroconf.h"
++#include "trace.h"
++#include "exitcode.h"
++
++struct context {
++    int thread_running;
++    pthread_t thread_id;
++    pthread_mutex_t mutex;
++    char *name;
++    AvahiSimplePoll *simple_poll;
++    AvahiClient *client;
++    AvahiEntryGroup *group;
++    uint16_t port;
++    int n_cpus;
++};
++
++static void publish_reply(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata);
++
++static void register_stuff(struct context *ctx) {
++
++    if (!ctx->group) {
++
++        if (!(ctx->group = avahi_entry_group_new(ctx->client, publish_reply, ctx))) {
++            rs_log_crit("Failed to create entry group: %s\n", avahi_strerror(avahi_client_errno(ctx->client)));
++            goto fail;
++        }
++        
++    }
++
++    if (avahi_entry_group_is_empty(ctx->group)) {
++        char cpus[32];
++
++        snprintf(cpus, sizeof(cpus), "cpus=%i", ctx->n_cpus);
++
++        /* Register our service */
++        
++        if (avahi_entry_group_add_service(ctx->group,
++                                          AVAHI_IF_UNSPEC,
++                                          AVAHI_PROTO_UNSPEC,
++                                          0,
++                                          ctx->name,
++                                          DCC_DNS_SERVICE_TYPE,
++                                          NULL,
++                                          NULL,
++                                          ctx->port,
++                                          "txtvers=1",
++                                          cpus,
++                                          "distcc="PACKAGE_VERSION,
++                                          "gnuhost="GNU_HOST,
++                                          NULL) < 0) {
++            rs_log_crit("Failed to add service: %s\n", avahi_strerror(avahi_client_errno(ctx->client)));
++            goto fail;
++        }
++
++        if (avahi_entry_group_commit(ctx->group) < 0) {
++            rs_log_crit("Failed to commit entry group: %s\n", avahi_strerror(avahi_client_errno(ctx->client)));
++            goto fail;
++        }
++    }
++
++    return;
++    
++    fail:
++    avahi_simple_poll_quit(ctx->simple_poll);
++}
++
++/* Called when publishing of service data completes */
++static void publish_reply(AvahiEntryGroup *UNUSED(g), AvahiEntryGroupState state, void *userdata) {
++    struct context *ctx = userdata;
++
++    switch (state) {
++        
++    case AVAHI_ENTRY_GROUP_COLLISION: {
++        char *n;
++
++        /* Pick a new name for our service */
++        
++        n = avahi_alternative_service_name(ctx->name);
++        assert(n);
++        
++        avahi_free(ctx->name);
++        ctx->name = n;
++
++        register_stuff(ctx);
++        break;
++    }
++
++    case AVAHI_ENTRY_GROUP_FAILURE: 
++        rs_log_crit("Failed to register service: %s\n", avahi_strerror(avahi_client_errno(ctx->client)));
++        avahi_simple_poll_quit(ctx->simple_poll);
++        break;
++        
++    case AVAHI_ENTRY_GROUP_UNCOMMITED:
++    case AVAHI_ENTRY_GROUP_REGISTERING:
++    case AVAHI_ENTRY_GROUP_ESTABLISHED:
++        ;
++    }
++}
++
++static void client_callback(AvahiClient *client, AvahiClientState state, void *userdata) {
++    struct context *ctx = userdata;
++
++    ctx->client = client;
++    
++    switch (state) {
++
++    case AVAHI_CLIENT_S_RUNNING:
++
++        register_stuff(ctx);
++        break;
++
++    case AVAHI_CLIENT_S_COLLISION:
++
++        if (ctx->group)
++            avahi_entry_group_reset(ctx->group);
++        break;
++
++    case AVAHI_CLIENT_FAILURE:
++
++        if (avahi_client_errno(client) == AVAHI_ERR_DISCONNECTED) {
++            int error;
++
++            avahi_client_free(ctx->client);
++            ctx->client = NULL;
++            ctx->group = NULL;
++
++            /* Reconnect to the server */
++
++            if (!(ctx->client = avahi_client_new(avahi_simple_poll_get(ctx->simple_poll),
++                                                 AVAHI_CLIENT_NO_FAIL,
++                                                 client_callback,
++                                                 ctx,
++                                                 &error))) {
++                
++                rs_log_crit("Failed to contact server: %s\n", avahi_strerror(error));
++                avahi_simple_poll_quit(ctx->simple_poll);
++            }
++            
++        } else {
++            rs_log_crit("Client failure: %s\n", avahi_strerror(avahi_client_errno(client)));
++            avahi_simple_poll_quit(ctx->simple_poll);
++        }
++
++        break;
++        
++    case AVAHI_CLIENT_S_REGISTERING:
++    case AVAHI_CLIENT_CONNECTING:
++        ;
++    }
++}
++
++static void* thread(void *userdata) {
++    struct context *ctx = userdata;
++    sigset_t mask;
++    int r;
++
++    /* Make sure that signals are delivered to the main thread */
++    sigfillset(&mask);
++    pthread_sigmask(SIG_BLOCK, &mask, NULL);
++    
++    pthread_mutex_lock(&ctx->mutex);
++
++    /* Run the main loop */
++    r = avahi_simple_poll_loop(ctx->simple_poll);
++
++    /* Cleanup some stuff */
++    if (ctx->client)
++        avahi_client_free(ctx->client);
++    ctx->client = NULL;
++    ctx->group = NULL;
++    
++    pthread_mutex_unlock(&ctx->mutex);
++    
++    return NULL;
++}
++
++static int poll_func(struct pollfd *ufds, unsigned int nfds, int timeout, void *userdata) {
++    pthread_mutex_t *mutex = userdata;
++    int r;
++
++    /* Before entering poll() we unlock the mutex, so that
++     * avahi_simple_poll_quit() can succeed from another thread. */
++    
++    pthread_mutex_unlock(mutex);
++    r = poll(ufds, nfds, timeout);
++    pthread_mutex_lock(mutex);
++
++    return r;
++}
++
++/* register a distcc service in DNS-SD/mDNS with the given port and number of CPUs */
++void* dcc_zeroconf_register(uint16_t port, int n_cpus) {
++    struct context *ctx = NULL;
++    
++    char service[256] = "distcc@";
++    int error, ret;
++
++    ctx = malloc(sizeof(struct context));
++    assert(ctx);
++    ctx->client = NULL;
++    ctx->group = NULL;
++    ctx->simple_poll = NULL;
++    ctx->thread_running = 0;
++    ctx->port = port;
++    ctx->n_cpus = n_cpus;
++    pthread_mutex_init(&ctx->mutex, NULL);
++    
++    /* Prepare service name */
++    gethostname(service+7, sizeof(service)-8);
++    service[sizeof(service)-1] = 0;
++
++    ctx->name = strdup(service);
++    assert(ctx->name);
++
++    if (!(ctx->simple_poll = avahi_simple_poll_new())) {
++        rs_log_crit("Failed to create event loop object.\n");
++        goto fail;
++    }
++
++    avahi_simple_poll_set_func(ctx->simple_poll, poll_func, &ctx->mutex);
++    
++    if (!(ctx->client = avahi_client_new(avahi_simple_poll_get(ctx->simple_poll), AVAHI_CLIENT_NO_FAIL, client_callback, ctx, &error))) {
++        rs_log_crit("Failed to create client object: %s\n", avahi_strerror(avahi_client_errno(ctx->client)));
++        goto fail;
++    }
++
++    /* Create the mDNS event handler */
++    if ((ret = pthread_create(&ctx->thread_id, NULL, thread, ctx)) < 0) {
++        rs_log_crit("Failed to create thread: %s\n", strerror(ret));
++        goto fail;
++    }
++
++    ctx->thread_running = 1;
++    
++    return ctx;
++    
++ fail:
++
++    if (ctx)
++        dcc_zeroconf_unregister(ctx);
++    
++    return NULL;
++}
++
++/* Unregister this server from DNS-SD/mDNS */
++int dcc_zeroconf_unregister(void *u) {
++    struct context *ctx = u;
++
++    if (ctx->thread_running) {
++        pthread_mutex_lock(&ctx->mutex);
++        avahi_simple_poll_quit(ctx->simple_poll);
++        pthread_mutex_unlock(&ctx->mutex);
++        
++        pthread_join(ctx->thread_id, NULL);
++        ctx->thread_running = 0;
++    }
++
++    avahi_free(ctx->name);
++
++    if (ctx->client)
++        avahi_client_free(ctx->client);
++
++    if (ctx->simple_poll)
++        avahi_simple_poll_free(ctx->simple_poll);
++
++    pthread_mutex_destroy(&ctx->mutex);
++
++    free(ctx);
++    
++    return 0;
++}