diff options
Diffstat (limited to 'meta/recipes-devtools/distcc')
-rw-r--r-- | meta/recipes-devtools/distcc/distcc_2.18.3.bb | 47 | ||||
-rw-r--r-- | meta/recipes-devtools/distcc/files/default | 19 | ||||
-rwxr-xr-x | meta/recipes-devtools/distcc/files/distcc | 106 | ||||
-rw-r--r-- | meta/recipes-devtools/distcc/files/distcc-avahi.patch | 1736 | ||||
-rw-r--r-- | meta/recipes-devtools/distcc/files/distccmon-gnome.desktop | 12 |
5 files changed, 1920 insertions, 0 deletions
diff --git a/meta/recipes-devtools/distcc/distcc_2.18.3.bb b/meta/recipes-devtools/distcc/distcc_2.18.3.bb new file mode 100644 index 000000000..cce2812b7 --- /dev/null +++ b/meta/recipes-devtools/distcc/distcc_2.18.3.bb @@ -0,0 +1,47 @@ +DESCRIPTION = "distcc is a parallel build system that distributes \ +compilation of C/C++/ObjC code across machines on a network." +SECTION = "devel" +LICENSE = "GPLv2" +PR = "r5" + +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 \ + file://distcc-avahi.patch;patch=1 \ + file://default \ + file://distccmon-gnome.desktop \ + file://distcc" + +inherit autotools pkgconfig update-rc.d + +INITSCRIPT_NAME = "distcc" + +EXTRA_OECONF = " --with-gtk " + +do_install_append() { + install -d ${D}${sysconfdir}/init.d/ + install -d ${D}${sysconfdir}/default + install -m 0755 ${WORKDIR}/distcc ${D}${sysconfdir}/init.d/ + install -m 0755 ${WORKDIR}/default ${D}${sysconfdir}/default/distcc + install -m 0644 ${WORKDIR}/distccmon-gnome.desktop ${D}${datadir}/distcc/ +} + +PACKAGES += "distcc-distmon-gnome" + +FILES_${PN} = " ${sysconfdir} \ + ${bindir}/distcc \ + ${bindir}/distccd \ + ${bindir}/distccmon-text" +FILES_distcc-distmon-gnome = " ${bindir}/distccmon-gnome \ + ${datadir}/distcc" + +pkg_postinst_${PN} () { + if test "x$D" != "x"; then + exit 1 + else + grep distcc /etc/passwd || adduser --system --home /dev/null --no-create-home --empty-password --ingroup nogroup distcc + fi +} diff --git a/meta/recipes-devtools/distcc/files/default b/meta/recipes-devtools/distcc/files/default new file mode 100644 index 000000000..95290f848 --- /dev/null +++ b/meta/recipes-devtools/distcc/files/default @@ -0,0 +1,19 @@ +# Defaults for distcc initscript +# sourced by /etc/init.d/distcc + +# +# should distcc be started on boot? +# +# STARTDISTCC="true" + +STARTDISTCC="true" + +# +# Which networks/hosts should be allowed to connect to the daemon? +# You can list multiple hosts/networks separated by spaces. +# Networks have to be in CIDR notation, f.e. 192.168.1.0/24 +# Hosts are represented by a single IP Adress +# +# ALLOWEDNETS="127.0.0.1" + +ALLOWEDNETS="192.168.7.0/24" diff --git a/meta/recipes-devtools/distcc/files/distcc b/meta/recipes-devtools/distcc/files/distcc new file mode 100755 index 000000000..513bc483e --- /dev/null +++ b/meta/recipes-devtools/distcc/files/distcc @@ -0,0 +1,106 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: distcc +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 1 +# Short-Description: simple distributed compiler client and server +### END INIT INFO +# +# distccd Debian init.d script contributed by Jason Thomas. (Debian #161136) +# +# skeleton example file to build /etc/init.d/ scripts. +# This file should be used to construct scripts for /etc/init.d. +# +# Written by Miquel van Smoorenburg <miquels@cistron.nl>. +# Modified for Debian GNU/Linux +# by Ian Murdock <imurdock@gnu.ai.mit.edu>. +# +# Version: @(#)skeleton 1.9.1 08-Apr-2002 miquels@cistron.nl +# + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/bin/distccd +NAME=distcc +DESC="Distributed Compiler Daemon" +DAEMON_ARGS="--pid-file=/var/run/$NAME.pid --daemon" +# please change those variables by overriding them in /etc/defaults/distcc +ALLOWEDNETS="127.0.0.1" + +# Reads config file (will override defaults above) +[ -r /etc/default/distcc ] && . /etc/default/distcc + +test -x $DAEMON || exit 0 + +set -e + +# construct access list +ALLOW="" +for net in $ALLOWEDNETS +do + ALLOW="$ALLOW --allow $net" +done + +should_start() { + if [ "$STARTDISTCC" != "true" ] && [ "$STARTDISTCC" != "YES" ]; then + echo "STARTDISTCC is set to false in /etc/default/distcc" + echo "$DAEMON not starting" + exit 0 + fi +} + +case "$1" in + start) + should_start + echo -n "Starting $DESC: $NAME" + start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ + --exec $DAEMON -- $DAEMON_ARGS $ALLOW || + { + code=$? + echo "$0: start failed with error code $code" >&2 + exit $code + } + echo "." + ;; + stop) + echo -n "Stopping $DESC: $NAME" + start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ + --exec $DAEMON || + { + code=$? + echo "$0: stop failed with error code $code" >&2 + exit $code + } + echo "." + ;; + restart|force-reload) + # + # If the "reload" option is implemented, move the "force-reload" + # option to the "reload" entry above. If not, "force-reload" is + # just the same as "restart". + # + echo -n "Restarting $DESC: $NAME" + start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ + --exec $DAEMON + sleep 1 + should_start + start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ + --exec $DAEMON -- $DAEMON_ARGS $ALLOW || + { + code=$? + echo "$0: restart failed with error code $code" >&2 + exit $code + } + echo "." + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 + + diff --git a/meta/recipes-devtools/distcc/files/distcc-avahi.patch b/meta/recipes-devtools/distcc/files/distcc-avahi.patch new file mode 100644 index 000000000..1702ea7ea --- /dev/null +++ b/meta/recipes-devtools/distcc/files/distcc-avahi.patch @@ -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; ++} diff --git a/meta/recipes-devtools/distcc/files/distccmon-gnome.desktop b/meta/recipes-devtools/distcc/files/distccmon-gnome.desktop new file mode 100644 index 000000000..7b5d85ce4 --- /dev/null +++ b/meta/recipes-devtools/distcc/files/distccmon-gnome.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Version=0.9.4 +Exec=distccmon-gnome +Name=distcc monitor +GenericName=Distributed Compile Monitor +Comment=Graphical view of distributed compile tasks +Icon=distccmon-gnome-icon +TryExec=distccmon-gnome +Terminal=false +Type=Application +Categories=GNOME;Development; +StartupNotify=true |