generic-poky/meta/recipes-devtools/distcc/files/distcc-avahi.patch

1739 lines
53 KiB
Diff

Upstream-Status: Pending
--- 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;
+}