diff options
Diffstat (limited to 'meta')
-rw-r--r-- | meta/packages/distcc/distcc_2.18.3.bb | 4 | ||||
-rw-r--r-- | meta/packages/distcc/files/distcc-avahi.patch | 1736 |
2 files changed, 1739 insertions, 1 deletions
diff --git a/meta/packages/distcc/distcc_2.18.3.bb b/meta/packages/distcc/distcc_2.18.3.bb index 82f45e61c2..dd45223603 100644 --- a/meta/packages/distcc/distcc_2.18.3.bb +++ b/meta/packages/distcc/distcc_2.18.3.bb | |||
@@ -7,8 +7,10 @@ PR = "r3" | |||
7 | DEPENDS = "avahi gtk+" | 7 | DEPENDS = "avahi gtk+" |
8 | RRECOMMENDS = "avahi-daemon" | 8 | RRECOMMENDS = "avahi-daemon" |
9 | 9 | ||
10 | # Upstream change this patch periodically so store locally | ||
11 | # http://0pointer.de/public/distcc-avahi.patch | ||
10 | SRC_URI = "http://distcc.samba.org/ftp/distcc/distcc-${PV}.tar.bz2 \ | 12 | SRC_URI = "http://distcc.samba.org/ftp/distcc/distcc-${PV}.tar.bz2 \ |
11 | http://0pointer.de/public/distcc-avahi.patch;patch=1 \ | 13 | file://distcc-avahi.patch;patch=1 \ |
12 | file://default \ | 14 | file://default \ |
13 | file://distcc" | 15 | file://distcc" |
14 | 16 | ||
diff --git a/meta/packages/distcc/files/distcc-avahi.patch b/meta/packages/distcc/files/distcc-avahi.patch new file mode 100644 index 0000000000..1702ea7eab --- /dev/null +++ b/meta/packages/distcc/files/distcc-avahi.patch | |||
@@ -0,0 +1,1736 @@ | |||
1 | --- upstream/aclocal.m4 1970-01-01 01:00:00.000000000 +0100 | ||
2 | +++ lennart/aclocal.m4 2005-11-18 04:19:18.000000000 +0100 | ||
3 | @@ -0,0 +1,171 @@ | ||
4 | +# generated automatically by aclocal 1.9.6 -*- Autoconf -*- | ||
5 | + | ||
6 | +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, | ||
7 | +# 2005 Free Software Foundation, Inc. | ||
8 | +# This file is free software; the Free Software Foundation | ||
9 | +# gives unlimited permission to copy and/or distribute it, | ||
10 | +# with or without modifications, as long as this notice is preserved. | ||
11 | + | ||
12 | +# This program is distributed in the hope that it will be useful, | ||
13 | +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without | ||
14 | +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A | ||
15 | +# PARTICULAR PURPOSE. | ||
16 | + | ||
17 | +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- | ||
18 | +# | ||
19 | +# Copyright © 2004 Scott James Remnant <scott@netsplit.com>. | ||
20 | +# | ||
21 | +# This program is free software; you can redistribute it and/or modify | ||
22 | +# it under the terms of the GNU General Public License as published by | ||
23 | +# the Free Software Foundation; either version 2 of the License, or | ||
24 | +# (at your option) any later version. | ||
25 | +# | ||
26 | +# This program is distributed in the hope that it will be useful, but | ||
27 | +# WITHOUT ANY WARRANTY; without even the implied warranty of | ||
28 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
29 | +# General Public License for more details. | ||
30 | +# | ||
31 | +# You should have received a copy of the GNU General Public License | ||
32 | +# along with this program; if not, write to the Free Software | ||
33 | +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
34 | +# | ||
35 | +# As a special exception to the GNU General Public License, if you | ||
36 | +# distribute this file as part of a program that contains a | ||
37 | +# configuration script generated by Autoconf, you may include it under | ||
38 | +# the same distribution terms that you use for the rest of that program. | ||
39 | + | ||
40 | +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) | ||
41 | +# ---------------------------------- | ||
42 | +AC_DEFUN([PKG_PROG_PKG_CONFIG], | ||
43 | +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) | ||
44 | +m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) | ||
45 | +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl | ||
46 | +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then | ||
47 | + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) | ||
48 | +fi | ||
49 | +if test -n "$PKG_CONFIG"; then | ||
50 | + _pkg_min_version=m4_default([$1], [0.9.0]) | ||
51 | + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) | ||
52 | + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then | ||
53 | + AC_MSG_RESULT([yes]) | ||
54 | + else | ||
55 | + AC_MSG_RESULT([no]) | ||
56 | + PKG_CONFIG="" | ||
57 | + fi | ||
58 | + | ||
59 | +fi[]dnl | ||
60 | +])# PKG_PROG_PKG_CONFIG | ||
61 | + | ||
62 | +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) | ||
63 | +# | ||
64 | +# Check to see whether a particular set of modules exists. Similar | ||
65 | +# to PKG_CHECK_MODULES(), but does not set variables or print errors. | ||
66 | +# | ||
67 | +# | ||
68 | +# Similar to PKG_CHECK_MODULES, make sure that the first instance of | ||
69 | +# this or PKG_CHECK_MODULES is called, or make sure to call | ||
70 | +# PKG_CHECK_EXISTS manually | ||
71 | +# -------------------------------------------------------------- | ||
72 | +AC_DEFUN([PKG_CHECK_EXISTS], | ||
73 | +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl | ||
74 | +if test -n "$PKG_CONFIG" && \ | ||
75 | + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then | ||
76 | + m4_ifval([$2], [$2], [:]) | ||
77 | +m4_ifvaln([$3], [else | ||
78 | + $3])dnl | ||
79 | +fi]) | ||
80 | + | ||
81 | + | ||
82 | +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) | ||
83 | +# --------------------------------------------- | ||
84 | +m4_define([_PKG_CONFIG], | ||
85 | +[if test -n "$PKG_CONFIG"; then | ||
86 | + if test -n "$$1"; then | ||
87 | + pkg_cv_[]$1="$$1" | ||
88 | + else | ||
89 | + PKG_CHECK_EXISTS([$3], | ||
90 | + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], | ||
91 | + [pkg_failed=yes]) | ||
92 | + fi | ||
93 | +else | ||
94 | + pkg_failed=untried | ||
95 | +fi[]dnl | ||
96 | +])# _PKG_CONFIG | ||
97 | + | ||
98 | +# _PKG_SHORT_ERRORS_SUPPORTED | ||
99 | +# ----------------------------- | ||
100 | +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], | ||
101 | +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) | ||
102 | +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then | ||
103 | + _pkg_short_errors_supported=yes | ||
104 | +else | ||
105 | + _pkg_short_errors_supported=no | ||
106 | +fi[]dnl | ||
107 | +])# _PKG_SHORT_ERRORS_SUPPORTED | ||
108 | + | ||
109 | + | ||
110 | +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], | ||
111 | +# [ACTION-IF-NOT-FOUND]) | ||
112 | +# | ||
113 | +# | ||
114 | +# Note that if there is a possibility the first call to | ||
115 | +# PKG_CHECK_MODULES might not happen, you should be sure to include an | ||
116 | +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac | ||
117 | +# | ||
118 | +# | ||
119 | +# -------------------------------------------------------------- | ||
120 | +AC_DEFUN([PKG_CHECK_MODULES], | ||
121 | +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl | ||
122 | +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl | ||
123 | +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl | ||
124 | + | ||
125 | +pkg_failed=no | ||
126 | +AC_MSG_CHECKING([for $1]) | ||
127 | + | ||
128 | +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) | ||
129 | +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) | ||
130 | + | ||
131 | +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS | ||
132 | +and $1[]_LIBS to avoid the need to call pkg-config. | ||
133 | +See the pkg-config man page for more details.]) | ||
134 | + | ||
135 | +if test $pkg_failed = yes; then | ||
136 | + _PKG_SHORT_ERRORS_SUPPORTED | ||
137 | + if test $_pkg_short_errors_supported = yes; then | ||
138 | + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"` | ||
139 | + else | ||
140 | + $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` | ||
141 | + fi | ||
142 | + # Put the nasty error message in config.log where it belongs | ||
143 | + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD | ||
144 | + | ||
145 | + ifelse([$4], , [AC_MSG_ERROR(dnl | ||
146 | +[Package requirements ($2) were not met: | ||
147 | + | ||
148 | +$$1_PKG_ERRORS | ||
149 | + | ||
150 | +Consider adjusting the PKG_CONFIG_PATH environment variable if you | ||
151 | +installed software in a non-standard prefix. | ||
152 | + | ||
153 | +_PKG_TEXT | ||
154 | +])], | ||
155 | + [$4]) | ||
156 | +elif test $pkg_failed = untried; then | ||
157 | + ifelse([$4], , [AC_MSG_FAILURE(dnl | ||
158 | +[The pkg-config script could not be found or is too old. Make sure it | ||
159 | +is in your PATH or set the PKG_CONFIG environment variable to the full | ||
160 | +path to pkg-config. | ||
161 | + | ||
162 | +_PKG_TEXT | ||
163 | + | ||
164 | +To get pkg-config, see <http://www.freedesktop.org/software/pkgconfig>.])], | ||
165 | + [$4]) | ||
166 | +else | ||
167 | + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS | ||
168 | + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS | ||
169 | + AC_MSG_RESULT([yes]) | ||
170 | + ifelse([$3], , :, [$3]) | ||
171 | +fi[]dnl | ||
172 | +])# PKG_CHECK_MODULES | ||
173 | + | ||
174 | +m4_include([acinclude.m4]) | ||
175 | --- upstream/Makefile.in 2005-11-18 16:15:40.000000000 +0100 | ||
176 | +++ lennart/Makefile.in 2005-11-18 01:14:43.000000000 +0100 | ||
177 | @@ -171,6 +171,7 @@ | ||
178 | src/ssh.o src/state.o src/strip.o \ | ||
179 | src/timefile.o src/traceenv.o \ | ||
180 | src/where.o \ | ||
181 | + @ZEROCONF_DISTCC_OBJS@ \ | ||
182 | $(common_obj) | ||
183 | |||
184 | distccd_obj = src/access.o \ | ||
185 | @@ -178,6 +179,7 @@ | ||
186 | src/ncpus.o \ | ||
187 | src/prefork.o \ | ||
188 | src/serve.o src/setuid.o src/srvnet.o src/srvrpc.o src/state.o \ | ||
189 | + @ZEROCONF_DISTCCD_OBJS@ \ | ||
190 | $(common_obj) @BUILD_POPT@ | ||
191 | |||
192 | # Objects that need to be linked in to build monitors | ||
193 | --- upstream/src/distcc.c 2005-11-18 16:15:40.000000000 +0100 | ||
194 | +++ lennart/src/distcc.c 2005-11-18 01:14:43.000000000 +0100 | ||
195 | @@ -83,6 +83,9 @@ | ||
196 | " COMPILER defaults to \"cc\"\n" | ||
197 | " --help explain usage and exit\n" | ||
198 | " --version show version and exit\n" | ||
199 | +" --show-hosts show host list and exit\n" | ||
200 | +" -j calculate the concurrency level from\n" | ||
201 | +" the host list.\n" | ||
202 | "\n" | ||
203 | "Environment variables:\n" | ||
204 | " See the manual page for a complete list.\n" | ||
205 | @@ -135,7 +138,46 @@ | ||
206 | signal(SIGHUP, &dcc_client_signalled); | ||
207 | } | ||
208 | |||
209 | +static void dcc_free_hostlist(struct dcc_hostdef *list) { | ||
210 | + while (list) { | ||
211 | + struct dcc_hostdef *l = list; | ||
212 | + list = list->next; | ||
213 | + dcc_free_hostdef(l); | ||
214 | + } | ||
215 | +} | ||
216 | + | ||
217 | +static void dcc_show_hosts(void) { | ||
218 | + struct dcc_hostdef *list, *l; | ||
219 | + int nhosts; | ||
220 | + | ||
221 | + if (dcc_get_hostlist(&list, &nhosts) != 0) { | ||
222 | + rs_log_crit("Failed to get host list"); | ||
223 | + return; | ||
224 | + } | ||
225 | + | ||
226 | + for (l = list; l; l = l->next) | ||
227 | + printf("%s\n", l->hostdef_string); | ||
228 | + | ||
229 | + dcc_free_hostlist(list); | ||
230 | +} | ||
231 | + | ||
232 | +static void dcc_concurrency_level(void) { | ||
233 | + struct dcc_hostdef *list, *l; | ||
234 | + int nhosts; | ||
235 | + int nslots = 0; | ||
236 | + | ||
237 | + if (dcc_get_hostlist(&list, &nhosts) != 0) { | ||
238 | + rs_log_crit("Failed to get host list"); | ||
239 | + return; | ||
240 | + } | ||
241 | + | ||
242 | + for (l = list; l; l = l->next) | ||
243 | + nslots += l->n_slots; | ||
244 | |||
245 | + dcc_free_hostlist(list); | ||
246 | + | ||
247 | + printf("%i\n", nslots); | ||
248 | +} | ||
249 | |||
250 | /** | ||
251 | * distcc client entry point. | ||
252 | @@ -182,6 +224,18 @@ | ||
253 | ret = 0; | ||
254 | goto out; | ||
255 | } | ||
256 | + | ||
257 | + if (!strcmp(argv[1], "--show-hosts")) { | ||
258 | + dcc_show_hosts(); | ||
259 | + ret = 0; | ||
260 | + goto out; | ||
261 | + } | ||
262 | + | ||
263 | + if (!strcmp(argv[1], "-j")) { | ||
264 | + dcc_concurrency_level(); | ||
265 | + ret = 0; | ||
266 | + goto out; | ||
267 | + } | ||
268 | |||
269 | dcc_find_compiler(argv, &compiler_args); | ||
270 | /* compiler_args is now respectively either "cc -c hello.c" or | ||
271 | --- upstream/src/distcc.h 2005-11-18 16:15:40.000000000 +0100 | ||
272 | +++ lennart/src/distcc.h 2005-11-18 01:14:43.000000000 +0100 | ||
273 | @@ -112,7 +112,7 @@ | ||
274 | int *ret_nhosts); | ||
275 | int dcc_parse_hosts(const char *where, const char *source_name, | ||
276 | struct dcc_hostdef **ret_list, | ||
277 | - int *ret_nhosts); | ||
278 | + int *ret_nhosts, struct dcc_hostdef **ret_prev); | ||
279 | |||
280 | /* ncpu.c */ | ||
281 | int dcc_ncpus(int *); | ||
282 | @@ -226,6 +226,7 @@ | ||
283 | int dcc_make_tmpnam(const char *, const char *suffix, char **); | ||
284 | |||
285 | int dcc_mkdir(const char *path) WARN_UNUSED; | ||
286 | +int dcc_get_subdir(const char *name, char **path_ret) WARN_UNUSED; | ||
287 | int dcc_get_lock_dir(char **path_ret) WARN_UNUSED; | ||
288 | int dcc_get_state_dir(char **path_ret) WARN_UNUSED; | ||
289 | int dcc_get_top_dir(char **path_ret) WARN_UNUSED; | ||
290 | --- upstream/src/dopt.c 2005-11-18 16:15:40.000000000 +0100 | ||
291 | +++ lennart/src/dopt.c 2005-11-18 04:14:26.000000000 +0100 | ||
292 | @@ -93,6 +93,10 @@ | ||
293 | opt_log_level | ||
294 | }; | ||
295 | |||
296 | +#ifdef HAVE_AVAHI | ||
297 | +/* Flag for enabling/disabling Zeroconf using Avahi */ | ||
298 | +int opt_zeroconf = 0; | ||
299 | +#endif | ||
300 | |||
301 | const struct poptOption options[] = { | ||
302 | { "allow", 'a', POPT_ARG_STRING, 0, 'a', 0, 0 }, | ||
303 | @@ -115,6 +119,9 @@ | ||
304 | { "verbose", 0, POPT_ARG_NONE, 0, 'v', 0, 0 }, | ||
305 | { "version", 0, POPT_ARG_NONE, 0, 'V', 0, 0 }, | ||
306 | { "wizard", 'W', POPT_ARG_NONE, 0, 'W', 0, 0 }, | ||
307 | +#ifdef HAVE_AVAHI | ||
308 | + { "zeroconf", 0, POPT_ARG_NONE, &opt_zeroconf, 0, 0, 0 }, | ||
309 | +#endif | ||
310 | { 0, 0, 0, 0, 0, 0, 0 } | ||
311 | }; | ||
312 | |||
313 | @@ -137,6 +144,9 @@ | ||
314 | " -p, --port PORT TCP port to listen on\n" | ||
315 | " --listen ADDRESS IP address to listen on\n" | ||
316 | " -a, --allow IP[/BITS] client address access control\n" | ||
317 | +#ifdef HAVE_AVAHI | ||
318 | +" --zeroconf register via mDNS/DNS-SD\n" | ||
319 | +#endif | ||
320 | " Debug and trace:\n" | ||
321 | " --log-level=LEVEL set detail level for log file\n" | ||
322 | " levels: critical, error, warning, notice, info, debug\n" | ||
323 | --- upstream/src/dopt.h 2005-11-18 16:15:40.000000000 +0100 | ||
324 | +++ lennart/src/dopt.h 2005-11-18 02:27:45.000000000 +0100 | ||
325 | @@ -38,3 +38,7 @@ | ||
326 | extern int opt_lifetime; | ||
327 | extern char *opt_listen_addr; | ||
328 | extern int opt_niceness; | ||
329 | + | ||
330 | +#ifdef HAVE_AVAHI | ||
331 | +extern int opt_zeroconf; | ||
332 | +#endif | ||
333 | --- upstream/src/dparent.c 2005-11-18 16:15:40.000000000 +0100 | ||
334 | +++ lennart/src/dparent.c 2005-11-18 04:13:23.000000000 +0100 | ||
335 | @@ -70,6 +70,7 @@ | ||
336 | #include "types.h" | ||
337 | #include "daemon.h" | ||
338 | #include "netutil.h" | ||
339 | +#include "zeroconf.h" | ||
340 | |||
341 | static void dcc_nofork_parent(int listen_fd) NORETURN; | ||
342 | static void dcc_detach(void); | ||
343 | @@ -94,6 +95,9 @@ | ||
344 | int listen_fd; | ||
345 | int n_cpus; | ||
346 | int ret; | ||
347 | +#ifdef HAVE_AVAHI | ||
348 | + void *avahi = NULL; | ||
349 | +#endif | ||
350 | |||
351 | if ((ret = dcc_socket_listen(arg_port, &listen_fd, opt_listen_addr)) != 0) | ||
352 | return ret; | ||
353 | @@ -131,6 +135,14 @@ | ||
354 | /* Don't catch signals until we've detached or created a process group. */ | ||
355 | dcc_daemon_catch_signals(); | ||
356 | |||
357 | +#ifdef HAVE_AVAHI | ||
358 | + /* Zeroconf registration */ | ||
359 | + if (opt_zeroconf) { | ||
360 | + if (!(avahi = dcc_zeroconf_register((uint16_t) arg_port, n_cpus))) | ||
361 | + return EXIT_CONNECT_FAILED; | ||
362 | + } | ||
363 | +#endif | ||
364 | + | ||
365 | /* This is called in the master daemon, whether that is detached or | ||
366 | * not. */ | ||
367 | dcc_master_pid = getpid(); | ||
368 | @@ -138,10 +150,21 @@ | ||
369 | if (opt_no_fork) { | ||
370 | dcc_log_daemon_started("non-forking daemon"); | ||
371 | dcc_nofork_parent(listen_fd); | ||
372 | + ret = 0; | ||
373 | } else { | ||
374 | dcc_log_daemon_started("preforking daemon"); | ||
375 | - return dcc_preforking_parent(listen_fd); | ||
376 | + ret = dcc_preforking_parent(listen_fd); | ||
377 | } | ||
378 | + | ||
379 | +#ifdef HAVE_AVAHI | ||
380 | + /* Remove zeroconf registration */ | ||
381 | + if (opt_zeroconf) { | ||
382 | + if (dcc_zeroconf_unregister(avahi) != 0) | ||
383 | + return EXIT_CONNECT_FAILED; | ||
384 | + } | ||
385 | +#endif | ||
386 | + | ||
387 | + return ret; | ||
388 | } | ||
389 | |||
390 | |||
391 | --- upstream/src/help.c 2005-11-18 16:15:40.000000000 +0100 | ||
392 | +++ lennart/src/help.c 2005-11-18 02:27:45.000000000 +0100 | ||
393 | @@ -62,6 +62,9 @@ | ||
394 | "distcc comes with ABSOLUTELY NO WARRANTY. distcc is free software, and\n" | ||
395 | "you may use, modify and redistribute it under the terms of the GNU \n" | ||
396 | "General Public License version 2 or later.\n" | ||
397 | +#ifdef HAVE_AVAHI | ||
398 | +"\nBuilt with Zeroconf support.\n" | ||
399 | +#endif | ||
400 | "\n" | ||
401 | , | ||
402 | prog, PACKAGE_VERSION, GNU_HOST, DISTCC_DEFAULT_PORT, | ||
403 | --- upstream/src/hostfile.c 2005-11-18 16:15:40.000000000 +0100 | ||
404 | +++ lennart/src/hostfile.c 2005-11-18 01:14:43.000000000 +0100 | ||
405 | @@ -59,7 +59,7 @@ | ||
406 | if ((ret = dcc_load_file_string(fname, &body)) != 0) | ||
407 | return ret; | ||
408 | |||
409 | - ret = dcc_parse_hosts(body, fname, ret_list, ret_nhosts); | ||
410 | + ret = dcc_parse_hosts(body, fname, ret_list, ret_nhosts, NULL); | ||
411 | |||
412 | free(body); | ||
413 | |||
414 | --- upstream/src/hosts.c 2005-11-18 16:15:40.000000000 +0100 | ||
415 | +++ lennart/src/hosts.c 2005-11-18 02:27:45.000000000 +0100 | ||
416 | @@ -96,6 +96,10 @@ | ||
417 | #include "hosts.h" | ||
418 | #include "exitcode.h" | ||
419 | #include "snprintf.h" | ||
420 | +#ifdef HAVE_AVAHI | ||
421 | +#include "zeroconf.h" | ||
422 | +#define ZEROCONF_MAGIC "+zeroconf" | ||
423 | +#endif | ||
424 | |||
425 | const int dcc_default_port = DISTCC_DEFAULT_PORT; | ||
426 | |||
427 | @@ -134,9 +138,12 @@ | ||
428 | char *path, *top; | ||
429 | int ret; | ||
430 | |||
431 | + *ret_list = NULL; | ||
432 | + *ret_nhosts = 0; | ||
433 | + | ||
434 | if ((env = getenv("DISTCC_HOSTS")) != NULL) { | ||
435 | rs_trace("read hosts from environment"); | ||
436 | - return dcc_parse_hosts(env, "$DISTCC_HOSTS", ret_list, ret_nhosts); | ||
437 | + return dcc_parse_hosts(env, "$DISTCC_HOSTS", ret_list, ret_nhosts, NULL); | ||
438 | } | ||
439 | |||
440 | /* $DISTCC_DIR or ~/.distcc */ | ||
441 | @@ -163,7 +170,7 @@ | ||
442 | rs_trace("not reading %s: %s", path, strerror(errno)); | ||
443 | free(path); | ||
444 | } | ||
445 | - | ||
446 | + | ||
447 | /* FIXME: Clearer message? */ | ||
448 | rs_log_warning("no hostlist is set; can't distribute work"); | ||
449 | |||
450 | @@ -346,17 +353,19 @@ | ||
451 | **/ | ||
452 | int dcc_parse_hosts(const char *where, const char *source_name, | ||
453 | struct dcc_hostdef **ret_list, | ||
454 | - int *ret_nhosts) | ||
455 | + int *ret_nhosts, struct dcc_hostdef **ret_prev) | ||
456 | { | ||
457 | int ret; | ||
458 | - struct dcc_hostdef *prev, *curr; | ||
459 | + struct dcc_hostdef *curr, *_prev; | ||
460 | + | ||
461 | + if (!ret_prev) { | ||
462 | + ret_prev = &_prev; | ||
463 | + _prev = NULL; | ||
464 | + } | ||
465 | |||
466 | /* TODO: Check for '/' in places where it might cause trouble with | ||
467 | * a lock file name. */ | ||
468 | |||
469 | - prev = NULL; | ||
470 | - *ret_list = NULL; | ||
471 | - *ret_nhosts = 0; | ||
472 | /* A simple, hardcoded scanner. Some of the GNU routines might be | ||
473 | * useful here, but they won't work on less capable systems. | ||
474 | * | ||
475 | @@ -390,6 +399,15 @@ | ||
476 | token_start = where; | ||
477 | token_len = strcspn(where, " #\t\n\f\r"); | ||
478 | |||
479 | +#ifdef HAVE_AVAHI | ||
480 | + if (token_len == sizeof(ZEROCONF_MAGIC)-1 && | ||
481 | + !strncmp(token_start, ZEROCONF_MAGIC, (unsigned) token_len)) { | ||
482 | + if ((ret = dcc_zeroconf_add_hosts(ret_list, ret_nhosts, 4, ret_prev) != 0)) | ||
483 | + return ret; | ||
484 | + goto skip; | ||
485 | + } | ||
486 | +#endif | ||
487 | + | ||
488 | /* Allocate new list item */ | ||
489 | curr = calloc(1, sizeof(struct dcc_hostdef)); | ||
490 | if (!curr) { | ||
491 | @@ -404,8 +422,8 @@ | ||
492 | } | ||
493 | |||
494 | /* Link into list */ | ||
495 | - if (prev) { | ||
496 | - prev->next = curr; | ||
497 | + if (*ret_prev) { | ||
498 | + (*ret_prev)->next = curr; | ||
499 | } else { | ||
500 | *ret_list = curr; /* first */ | ||
501 | } | ||
502 | @@ -434,10 +452,15 @@ | ||
503 | return ret; | ||
504 | } | ||
505 | |||
506 | + (*ret_nhosts)++; | ||
507 | + *ret_prev = curr; | ||
508 | + | ||
509 | +#ifdef HAVE_AVAHI | ||
510 | + skip: | ||
511 | +#endif | ||
512 | + | ||
513 | /* continue to next token if any */ | ||
514 | where = token_start + token_len; | ||
515 | - prev = curr; | ||
516 | - (*ret_nhosts)++; | ||
517 | } | ||
518 | |||
519 | if (*ret_nhosts) { | ||
520 | --- upstream/src/io.c 2005-11-18 16:15:40.000000000 +0100 | ||
521 | +++ lennart/src/io.c 2005-11-18 01:14:43.000000000 +0100 | ||
522 | @@ -163,7 +163,7 @@ | ||
523 | return ret; | ||
524 | else | ||
525 | continue; | ||
526 | - } else if (r == -1 && errno == EAGAIN) { | ||
527 | + } else if (r == -1 && errno == EINTR) { | ||
528 | continue; | ||
529 | } else if (r == -1) { | ||
530 | rs_log_error("failed to read: %s", strerror(errno)); | ||
531 | @@ -205,9 +205,6 @@ | ||
532 | } else if (r == -1) { | ||
533 | rs_log_error("failed to write: %s", strerror(errno)); | ||
534 | return EXIT_IO_ERROR; | ||
535 | - } else if (r == 0) { | ||
536 | - rs_log_error("unexpected eof on fd%d", fd); | ||
537 | - return EXIT_TRUNCATED; | ||
538 | } else { | ||
539 | buf = &((char *) buf)[r]; | ||
540 | len -= r; | ||
541 | --- upstream/src/tempfile.c 2005-11-18 16:15:40.000000000 +0100 | ||
542 | +++ lennart/src/tempfile.c 2005-11-18 01:14:43.000000000 +0100 | ||
543 | @@ -161,7 +161,7 @@ | ||
544 | * Return a subdirectory of the DISTCC_DIR of the given name, making | ||
545 | * sure that the directory exists. | ||
546 | **/ | ||
547 | -static int dcc_get_subdir(const char *name, | ||
548 | +int dcc_get_subdir(const char *name, | ||
549 | char **dir_ret) | ||
550 | { | ||
551 | int ret; | ||
552 | --- upstream/configure.ac 2005-11-18 16:15:40.000000000 +0100 | ||
553 | +++ lennart/configure.ac 2005-11-18 04:18:07.000000000 +0100 | ||
554 | @@ -388,6 +388,23 @@ | ||
555 | AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1, [define if you have struct sockaddr_storage]),, | ||
556 | [#include <sys/socket.h>]) | ||
557 | |||
558 | +dnl check for avahi | ||
559 | +PKG_CHECK_MODULES(AVAHI, [avahi-client >= 0.6], | ||
560 | +[AC_DEFINE(HAVE_AVAHI, 1, [defined if Avahi is available]) | ||
561 | +CFLAGS="$CFLAGS $AVAHI_CFLAGS" | ||
562 | +LIBS="$LIBS $AVAHI_LIBS" | ||
563 | +ZEROCONF_DISTCC_OBJS="src/zeroconf.o" | ||
564 | +ZEROCONF_DISTCCD_OBJS="src/zeroconf-reg.o"], | ||
565 | +[ZEROCONF_DISTCC_OBJS="" | ||
566 | +ZEROCONF_DISTCCD_OBJS=""]) | ||
567 | +AC_SUBST(ZEROCONF_DISTCC_OBJS) | ||
568 | +AC_SUBST(ZEROCONF_DISTCCD_OBJS) | ||
569 | + | ||
570 | +ACX_PTHREAD | ||
571 | +LIBS="$PTHREAD_LIBS $LIBS" | ||
572 | +CFLAGS="$CFLAGS $PTHREAD_CFLAGS" | ||
573 | +CC="$PTHREAD_CC" | ||
574 | + | ||
575 | dnl ##### Output | ||
576 | AC_SUBST(docdir) | ||
577 | AC_SUBST(CFLAGS) | ||
578 | --- upstream/acinclude.m4 1970-01-01 01:00:00.000000000 +0100 | ||
579 | +++ lennart/acinclude.m4 2005-11-18 04:17:08.000000000 +0100 | ||
580 | @@ -0,0 +1,235 @@ | ||
581 | +dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) | ||
582 | +dnl | ||
583 | +dnl This macro figures out how to build C programs using POSIX threads. | ||
584 | +dnl It sets the PTHREAD_LIBS output variable to the threads library and | ||
585 | +dnl linker flags, and the PTHREAD_CFLAGS output variable to any special | ||
586 | +dnl C compiler flags that are needed. (The user can also force certain | ||
587 | +dnl compiler flags/libs to be tested by setting these environment | ||
588 | +dnl variables.) | ||
589 | +dnl | ||
590 | +dnl Also sets PTHREAD_CC to any special C compiler that is needed for | ||
591 | +dnl multi-threaded programs (defaults to the value of CC otherwise). | ||
592 | +dnl (This is necessary on AIX to use the special cc_r compiler alias.) | ||
593 | +dnl | ||
594 | +dnl NOTE: You are assumed to not only compile your program with these | ||
595 | +dnl flags, but also link it with them as well. e.g. you should link | ||
596 | +dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS | ||
597 | +dnl $LIBS | ||
598 | +dnl | ||
599 | +dnl If you are only building threads programs, you may wish to use | ||
600 | +dnl these variables in your default LIBS, CFLAGS, and CC: | ||
601 | +dnl | ||
602 | +dnl LIBS="$PTHREAD_LIBS $LIBS" | ||
603 | +dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" | ||
604 | +dnl CC="$PTHREAD_CC" | ||
605 | +dnl | ||
606 | +dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute | ||
607 | +dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to | ||
608 | +dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). | ||
609 | +dnl | ||
610 | +dnl ACTION-IF-FOUND is a list of shell commands to run if a threads | ||
611 | +dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to | ||
612 | +dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the | ||
613 | +dnl default action will define HAVE_PTHREAD. | ||
614 | +dnl | ||
615 | +dnl Please let the authors know if this macro fails on any platform, or | ||
616 | +dnl if you have any other suggestions or comments. This macro was based | ||
617 | +dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with | ||
618 | +dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros | ||
619 | +dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. | ||
620 | +dnl We are also grateful for the helpful feedback of numerous users. | ||
621 | +dnl | ||
622 | +dnl @category InstalledPackages | ||
623 | +dnl @author Steven G. Johnson <stevenj@alum.mit.edu> | ||
624 | +dnl @version 2005-01-14 | ||
625 | +dnl @license GPLWithACException | ||
626 | + | ||
627 | +AC_DEFUN([ACX_PTHREAD], [ | ||
628 | +AC_REQUIRE([AC_CANONICAL_HOST]) | ||
629 | +AC_LANG_SAVE | ||
630 | +AC_LANG_C | ||
631 | +acx_pthread_ok=no | ||
632 | + | ||
633 | +# We used to check for pthread.h first, but this fails if pthread.h | ||
634 | +# requires special compiler flags (e.g. on True64 or Sequent). | ||
635 | +# It gets checked for in the link test anyway. | ||
636 | + | ||
637 | +# First of all, check if the user has set any of the PTHREAD_LIBS, | ||
638 | +# etcetera environment variables, and if threads linking works using | ||
639 | +# them: | ||
640 | +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then | ||
641 | + save_CFLAGS="$CFLAGS" | ||
642 | + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" | ||
643 | + save_LIBS="$LIBS" | ||
644 | + LIBS="$PTHREAD_LIBS $LIBS" | ||
645 | + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) | ||
646 | + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) | ||
647 | + AC_MSG_RESULT($acx_pthread_ok) | ||
648 | + if test x"$acx_pthread_ok" = xno; then | ||
649 | + PTHREAD_LIBS="" | ||
650 | + PTHREAD_CFLAGS="" | ||
651 | + fi | ||
652 | + LIBS="$save_LIBS" | ||
653 | + CFLAGS="$save_CFLAGS" | ||
654 | +fi | ||
655 | + | ||
656 | +# We must check for the threads library under a number of different | ||
657 | +# names; the ordering is very important because some systems | ||
658 | +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the | ||
659 | +# libraries is broken (non-POSIX). | ||
660 | + | ||
661 | +# Create a list of thread flags to try. Items starting with a "-" are | ||
662 | +# C compiler flags, and other items are library names, except for "none" | ||
663 | +# which indicates that we try without any flags at all, and "pthread-config" | ||
664 | +# which is a program returning the flags for the Pth emulation library. | ||
665 | + | ||
666 | +acx_pthread_flags="pthreads pthread none -Kthread -kthread lthread -pthread -pthreads -mthreads --thread-safe -mt pthread-config" | ||
667 | + | ||
668 | +# The ordering *is* (sometimes) important. Some notes on the | ||
669 | +# individual items follow: | ||
670 | + | ||
671 | +# pthreads: AIX (must check this before -lpthread) | ||
672 | +# none: in case threads are in libc; should be tried before -Kthread and | ||
673 | +# other compiler flags to prevent continual compiler warnings | ||
674 | +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) | ||
675 | +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) | ||
676 | +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) | ||
677 | +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) | ||
678 | +# -pthreads: Solaris/gcc | ||
679 | +# -mthreads: Mingw32/gcc, Lynx/gcc | ||
680 | +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it | ||
681 | +# doesn't hurt to check since this sometimes defines pthreads too; | ||
682 | +# also defines -D_REENTRANT) | ||
683 | +# pthread: Linux, etcetera | ||
684 | +# --thread-safe: KAI C++ | ||
685 | +# pthread-config: use pthread-config program (for GNU Pth library) | ||
686 | + | ||
687 | +case "${host_cpu}-${host_os}" in | ||
688 | + *solaris*) | ||
689 | + | ||
690 | + # On Solaris (at least, for some versions), libc contains stubbed | ||
691 | + # (non-functional) versions of the pthreads routines, so link-based | ||
692 | + # tests will erroneously succeed. (We need to link with -pthread or | ||
693 | + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather | ||
694 | + # a function called by this macro, so we could check for that, but | ||
695 | + # who knows whether they'll stub that too in a future libc.) So, | ||
696 | + # we'll just look for -pthreads and -lpthread first: | ||
697 | + | ||
698 | + acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" | ||
699 | + ;; | ||
700 | +esac | ||
701 | + | ||
702 | +if test x"$acx_pthread_ok" = xno; then | ||
703 | +for flag in $acx_pthread_flags; do | ||
704 | + | ||
705 | + case $flag in | ||
706 | + none) | ||
707 | + AC_MSG_CHECKING([whether pthreads work without any flags]) | ||
708 | + ;; | ||
709 | + | ||
710 | + -*) | ||
711 | + AC_MSG_CHECKING([whether pthreads work with $flag]) | ||
712 | + PTHREAD_CFLAGS="$flag" | ||
713 | + ;; | ||
714 | + | ||
715 | + pthread-config) | ||
716 | + AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) | ||
717 | + if test x"$acx_pthread_config" = xno; then continue; fi | ||
718 | + PTHREAD_CFLAGS="`pthread-config --cflags`" | ||
719 | + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" | ||
720 | + ;; | ||
721 | + | ||
722 | + *) | ||
723 | + AC_MSG_CHECKING([for the pthreads library -l$flag]) | ||
724 | + PTHREAD_LIBS="-l$flag" | ||
725 | + ;; | ||
726 | + esac | ||
727 | + | ||
728 | + save_LIBS="$LIBS" | ||
729 | + save_CFLAGS="$CFLAGS" | ||
730 | + LIBS="$PTHREAD_LIBS $LIBS" | ||
731 | + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" | ||
732 | + | ||
733 | + # Check for various functions. We must include pthread.h, | ||
734 | + # since some functions may be macros. (On the Sequent, we | ||
735 | + # need a special flag -Kthread to make this header compile.) | ||
736 | + # We check for pthread_join because it is in -lpthread on IRIX | ||
737 | + # while pthread_create is in libc. We check for pthread_attr_init | ||
738 | + # due to DEC craziness with -lpthreads. We check for | ||
739 | + # pthread_cleanup_push because it is one of the few pthread | ||
740 | + # functions on Solaris that doesn't have a non-functional libc stub. | ||
741 | + # We try pthread_create on general principles. | ||
742 | + AC_TRY_LINK([#include <pthread.h>], | ||
743 | + [pthread_t th; pthread_join(th, 0); | ||
744 | + pthread_attr_init(0); pthread_cleanup_push(0, 0); | ||
745 | + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], | ||
746 | + [acx_pthread_ok=yes]) | ||
747 | + | ||
748 | + LIBS="$save_LIBS" | ||
749 | + CFLAGS="$save_CFLAGS" | ||
750 | + | ||
751 | + AC_MSG_RESULT($acx_pthread_ok) | ||
752 | + if test "x$acx_pthread_ok" = xyes; then | ||
753 | + break; | ||
754 | + fi | ||
755 | + | ||
756 | + PTHREAD_LIBS="" | ||
757 | + PTHREAD_CFLAGS="" | ||
758 | +done | ||
759 | +fi | ||
760 | + | ||
761 | +# Various other checks: | ||
762 | +if test "x$acx_pthread_ok" = xyes; then | ||
763 | + save_LIBS="$LIBS" | ||
764 | + LIBS="$PTHREAD_LIBS $LIBS" | ||
765 | + save_CFLAGS="$CFLAGS" | ||
766 | + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" | ||
767 | + | ||
768 | + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. | ||
769 | + AC_MSG_CHECKING([for joinable pthread attribute]) | ||
770 | + attr_name=unknown | ||
771 | + for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do | ||
772 | + AC_TRY_LINK([#include <pthread.h>], [int attr=$attr;], | ||
773 | + [attr_name=$attr; break]) | ||
774 | + done | ||
775 | + AC_MSG_RESULT($attr_name) | ||
776 | + if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then | ||
777 | + AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, | ||
778 | + [Define to necessary symbol if this constant | ||
779 | + uses a non-standard name on your system.]) | ||
780 | + fi | ||
781 | + | ||
782 | + AC_MSG_CHECKING([if more special flags are required for pthreads]) | ||
783 | + flag=no | ||
784 | + case "${host_cpu}-${host_os}" in | ||
785 | + *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; | ||
786 | + *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; | ||
787 | + esac | ||
788 | + AC_MSG_RESULT(${flag}) | ||
789 | + if test "x$flag" != xno; then | ||
790 | + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" | ||
791 | + fi | ||
792 | + | ||
793 | + LIBS="$save_LIBS" | ||
794 | + CFLAGS="$save_CFLAGS" | ||
795 | + | ||
796 | + # More AIX lossage: must compile with cc_r | ||
797 | + AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) | ||
798 | +else | ||
799 | + PTHREAD_CC="$CC" | ||
800 | +fi | ||
801 | + | ||
802 | +AC_SUBST(PTHREAD_LIBS) | ||
803 | +AC_SUBST(PTHREAD_CFLAGS) | ||
804 | +AC_SUBST(PTHREAD_CC) | ||
805 | + | ||
806 | +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: | ||
807 | +if test x"$acx_pthread_ok" = xyes; then | ||
808 | + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) | ||
809 | + : | ||
810 | +else | ||
811 | + acx_pthread_ok=no | ||
812 | + $2 | ||
813 | +fi | ||
814 | +AC_LANG_RESTORE | ||
815 | +])dnl ACX_PTHREAD | ||
816 | --- upstream/src/zeroconf.h 1970-01-01 01:00:00.000000000 +0100 | ||
817 | +++ lennart/src/zeroconf.h 2005-11-18 04:06:29.000000000 +0100 | ||
818 | @@ -0,0 +1,13 @@ | ||
819 | +#ifndef foozeroconfhfoo | ||
820 | +#define foozeroconfhfoo | ||
821 | + | ||
822 | +#include <inttypes.h> | ||
823 | + | ||
824 | +int dcc_zeroconf_add_hosts(struct dcc_hostdef **re_list, int *ret_nhosts, int slots, struct dcc_hostdef **ret_prev); | ||
825 | + | ||
826 | +void * dcc_zeroconf_register(uint16_t port, int n_cpus); | ||
827 | +int dcc_zeroconf_unregister(void*); | ||
828 | + | ||
829 | +#define DCC_DNS_SERVICE_TYPE "_distcc._tcp" | ||
830 | + | ||
831 | +#endif | ||
832 | --- upstream/src/zeroconf.c 1970-01-01 01:00:00.000000000 +0100 | ||
833 | +++ lennart/src/zeroconf.c 2005-11-18 15:51:45.000000000 +0100 | ||
834 | @@ -0,0 +1,602 @@ | ||
835 | +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- */ | ||
836 | + | ||
837 | +#include "config.h" | ||
838 | + | ||
839 | +#include <assert.h> | ||
840 | +#include <stdio.h> | ||
841 | +#include <sys/select.h> | ||
842 | +#include <signal.h> | ||
843 | +#include <sys/file.h> | ||
844 | +#include <sys/time.h> | ||
845 | +#include <time.h> | ||
846 | +#include <sys/stat.h> | ||
847 | +#include <string.h> | ||
848 | +#include <errno.h> | ||
849 | +#include <unistd.h> | ||
850 | +#include <stdlib.h> | ||
851 | +#include <limits.h> | ||
852 | + | ||
853 | +#include <avahi-common/domain.h> | ||
854 | +#include <avahi-common/error.h> | ||
855 | +#include <avahi-common/malloc.h> | ||
856 | +#include <avahi-common/address.h> | ||
857 | +#include <avahi-common/simple-watch.h> | ||
858 | +#include <avahi-client/lookup.h> | ||
859 | + | ||
860 | +#include "distcc.h" | ||
861 | +#include "hosts.h" | ||
862 | +#include "zeroconf.h" | ||
863 | +#include "trace.h" | ||
864 | +#include "exitcode.h" | ||
865 | + | ||
866 | +/* How long shall the background daemon be idle before i terminates itself? */ | ||
867 | +#define MAX_IDLE_TIME 20 | ||
868 | + | ||
869 | +/* Maxium size of host file to load */ | ||
870 | +#define MAX_FILE_SIZE (1024*100) | ||
871 | + | ||
872 | +/* General daemon data */ | ||
873 | +struct daemon_data { | ||
874 | + struct host *hosts; | ||
875 | + int fd; | ||
876 | + int n_slots; | ||
877 | + | ||
878 | + AvahiClient *client; | ||
879 | + AvahiServiceBrowser *browser; | ||
880 | + AvahiSimplePoll *simple_poll; | ||
881 | +}; | ||
882 | + | ||
883 | +/* Zeroconf service wrapper */ | ||
884 | +struct host { | ||
885 | + struct daemon_data *daemon_data; | ||
886 | + struct host *next; | ||
887 | + | ||
888 | + AvahiIfIndex interface; | ||
889 | + AvahiProtocol protocol; | ||
890 | + char *service; | ||
891 | + char *domain; | ||
892 | + | ||
893 | + AvahiAddress address; | ||
894 | + uint16_t port; | ||
895 | + int n_cpus; | ||
896 | + | ||
897 | + AvahiServiceResolver *resolver; | ||
898 | +}; | ||
899 | + | ||
900 | +/* A generic, system independant lock routine, similar to sys_lock, | ||
901 | + * but more powerful: | ||
902 | + * rw: if non-zero: r/w lock instead of r/o lock | ||
903 | + * enable: lock or unlock | ||
904 | + * block: block when locking */ | ||
905 | +static int generic_lock(int fd, int rw, int enable, int block) { | ||
906 | +#if defined(F_SETLK) | ||
907 | + struct flock lockparam; | ||
908 | + | ||
909 | + lockparam.l_type = enable ? (rw ? F_WRLCK : F_RDLCK) : F_UNLCK; | ||
910 | + lockparam.l_whence = SEEK_SET; | ||
911 | + lockparam.l_start = 0; | ||
912 | + lockparam.l_len = 0; /* whole file */ | ||
913 | + | ||
914 | + return fcntl(fd, block ? F_SETLKW : F_SETLK, &lockparam); | ||
915 | +#elif defined(HAVE_FLOCK) | ||
916 | + return flock(fd, (enable ? (rw ? LOCK_EX : LOCK_SH) : LOCK_UN) | (block ? LOCK_NB : 0)); | ||
917 | +#elif defined(HAVE_LOCKF) | ||
918 | + return lockf(fd, (enable ? (block ? F_LOCK : F_TLOCK) : F_ULOCK)); | ||
919 | +#else | ||
920 | +# error "No supported lock method. Please port this code." | ||
921 | +#endif | ||
922 | +} | ||
923 | + | ||
924 | +/* Return the number of seconds, when the specified file was last | ||
925 | + * read. If the atime of that file is < clip_time, use clip_time | ||
926 | + * instead */ | ||
927 | +static time_t fd_last_used(int fd, time_t clip_time) { | ||
928 | + struct stat st; | ||
929 | + time_t now, ft; | ||
930 | + assert(fd >= 0); | ||
931 | + | ||
932 | + if (fstat(fd, &st) < 0) { | ||
933 | + rs_log_crit("fstat() failed: %s\n", strerror(errno)); | ||
934 | + return -1; | ||
935 | + } | ||
936 | + | ||
937 | + if ((now = time(NULL)) == (time_t) -1) { | ||
938 | + rs_log_crit("time() failed: %s\n", strerror(errno)); | ||
939 | + return -1; | ||
940 | + } | ||
941 | + | ||
942 | + ft = clip_time ? (st.st_atime < clip_time ? clip_time : st.st_atime) : st.st_atime; | ||
943 | + assert(ft <= now); | ||
944 | + | ||
945 | + return now - ft; | ||
946 | +} | ||
947 | + | ||
948 | +/* Write host data to host file */ | ||
949 | +static int write_hosts(struct daemon_data *d) { | ||
950 | + struct host *h; | ||
951 | + int r = 0; | ||
952 | + assert(d); | ||
953 | + | ||
954 | + rs_log_info("writing zeroconf data.\n"); | ||
955 | + | ||
956 | + if (generic_lock(d->fd, 1, 1, 1) < 0) { | ||
957 | + rs_log_crit("lock failed: %s\n", strerror(errno)); | ||
958 | + return -1; | ||
959 | + } | ||
960 | + | ||
961 | + if (lseek(d->fd, 0, SEEK_SET) < 0) { | ||
962 | + rs_log_crit("lseek() failed: %s\n", strerror(errno)); | ||
963 | + return -1; | ||
964 | + } | ||
965 | + | ||
966 | + if (ftruncate(d->fd, 0) < 0) { | ||
967 | + rs_log_crit("ftruncate() failed: %s\n", strerror(errno)); | ||
968 | + return -1; | ||
969 | + } | ||
970 | + | ||
971 | + for (h = d->hosts; h; h = h->next) { | ||
972 | + char t[256], a[AVAHI_ADDRESS_STR_MAX]; | ||
973 | + | ||
974 | + if (h->resolver) | ||
975 | + /* Not yet fully resolved */ | ||
976 | + continue; | ||
977 | + | ||
978 | + snprintf(t, sizeof(t), "%s:%u/%i\n", avahi_address_snprint(a, sizeof(a), &h->address), h->port, d->n_slots * h->n_cpus); | ||
979 | + | ||
980 | + if (dcc_writex(d->fd, t, strlen(t)) != 0) { | ||
981 | + rs_log_crit("write() failed: %s\n", strerror(errno)); | ||
982 | + goto finish; | ||
983 | + } | ||
984 | + } | ||
985 | + | ||
986 | + r = 0; | ||
987 | + | ||
988 | +finish: | ||
989 | + | ||
990 | + generic_lock(d->fd, 1, 0, 1); | ||
991 | + return r; | ||
992 | + | ||
993 | +}; | ||
994 | + | ||
995 | +/* Free host data */ | ||
996 | +static void free_host(struct host *h) { | ||
997 | + assert(h); | ||
998 | + | ||
999 | + if (h->resolver) | ||
1000 | + avahi_service_resolver_free(h->resolver); | ||
1001 | + | ||
1002 | + free(h->service); | ||
1003 | + free(h->domain); | ||
1004 | + free(h); | ||
1005 | +} | ||
1006 | + | ||
1007 | +/* Remove a service from the host list */ | ||
1008 | +static void remove_service(struct daemon_data *d, AvahiIfIndex interface, AvahiProtocol protocol, const char *name, const char *domain) { | ||
1009 | + struct host *h, *p = NULL; | ||
1010 | + assert(d); | ||
1011 | + | ||
1012 | + for (h = d->hosts; h; h = h->next) { | ||
1013 | + if (h->interface == interface && | ||
1014 | + h->protocol == protocol && | ||
1015 | + !strcmp(h->service, name) && | ||
1016 | + avahi_domain_equal(h->domain, domain)) { | ||
1017 | + | ||
1018 | + if (p) | ||
1019 | + p->next = h->next; | ||
1020 | + else | ||
1021 | + d->hosts = h->next; | ||
1022 | + | ||
1023 | + free_host(h); | ||
1024 | + | ||
1025 | + break; | ||
1026 | + } else | ||
1027 | + p = h; | ||
1028 | + } | ||
1029 | +} | ||
1030 | + | ||
1031 | +/* Called when a resolve call completes */ | ||
1032 | +static void resolve_reply(AvahiServiceResolver *UNUSED(r), | ||
1033 | + AvahiIfIndex UNUSED(interface), | ||
1034 | + AvahiProtocol UNUSED(protocol), | ||
1035 | + AvahiResolverEvent event, | ||
1036 | + const char *name, | ||
1037 | + const char *UNUSED(type), | ||
1038 | + const char *UNUSED(domain), | ||
1039 | + const char *UNUSED(host_name), | ||
1040 | + const AvahiAddress *a, | ||
1041 | + uint16_t port, | ||
1042 | + AvahiStringList *txt, | ||
1043 | + AvahiLookupResultFlags UNUSED(flags), | ||
1044 | + void *userdata) { | ||
1045 | + | ||
1046 | + struct host *h = userdata; | ||
1047 | + | ||
1048 | + switch (event) { | ||
1049 | + | ||
1050 | + case AVAHI_RESOLVER_FOUND: { | ||
1051 | + AvahiStringList *i; | ||
1052 | + | ||
1053 | + /* Look for the number of CPUs in TXT RRs */ | ||
1054 | + for (i = txt; i; i = i->next) { | ||
1055 | + char *key, *value; | ||
1056 | + | ||
1057 | + if (avahi_string_list_get_pair(i, &key, &value, NULL) < 0) | ||
1058 | + continue; | ||
1059 | + | ||
1060 | + if (!strcmp(key, "cpus")) | ||
1061 | + if ((h->n_cpus = atoi(value)) <= 0) | ||
1062 | + h->n_cpus = 1; | ||
1063 | + | ||
1064 | + avahi_free(key); | ||
1065 | + avahi_free(value); | ||
1066 | + } | ||
1067 | + | ||
1068 | + h->address = *a; | ||
1069 | + h->port = port; | ||
1070 | + | ||
1071 | + avahi_service_resolver_free(h->resolver); | ||
1072 | + h->resolver = NULL; | ||
1073 | + | ||
1074 | + /* Write modified hosts file */ | ||
1075 | + write_hosts(h->daemon_data); | ||
1076 | + | ||
1077 | + break; | ||
1078 | + } | ||
1079 | + | ||
1080 | + case AVAHI_RESOLVER_FAILURE: | ||
1081 | + | ||
1082 | + rs_log_warning("Failed to resolve service '%s': %s\n", name, | ||
1083 | + avahi_strerror(avahi_client_errno(h->daemon_data->client))); | ||
1084 | + | ||
1085 | + free_host(h); | ||
1086 | + break; | ||
1087 | + } | ||
1088 | + | ||
1089 | +} | ||
1090 | + | ||
1091 | +/* Called whenever a new service is found or removed */ | ||
1092 | +static void browse_reply(AvahiServiceBrowser *UNUSED(b), | ||
1093 | + AvahiIfIndex interface, | ||
1094 | + AvahiProtocol protocol, | ||
1095 | + AvahiBrowserEvent event, | ||
1096 | + const char *name, | ||
1097 | + const char *type, | ||
1098 | + const char *domain, | ||
1099 | + AvahiLookupResultFlags UNUSED(flags), | ||
1100 | + void *userdata) { | ||
1101 | + | ||
1102 | + struct daemon_data *d = userdata; | ||
1103 | + assert(d); | ||
1104 | + | ||
1105 | + switch (event) { | ||
1106 | + case AVAHI_BROWSER_NEW: { | ||
1107 | + struct host *h; | ||
1108 | + | ||
1109 | + h = malloc(sizeof(struct host)); | ||
1110 | + assert(h); | ||
1111 | + | ||
1112 | + rs_log_info("new service: %s\n", name); | ||
1113 | + | ||
1114 | + if (!(h->resolver = avahi_service_resolver_new(d->client, | ||
1115 | + interface, | ||
1116 | + protocol, | ||
1117 | + name, | ||
1118 | + type, | ||
1119 | + domain, | ||
1120 | + AVAHI_PROTO_UNSPEC, | ||
1121 | + 0, | ||
1122 | + resolve_reply, | ||
1123 | + h))) { | ||
1124 | + rs_log_warning("Failed to create service resolver for '%s': %s\n", name, | ||
1125 | + avahi_strerror(avahi_client_errno(d->client))); | ||
1126 | + | ||
1127 | + free(h); | ||
1128 | + | ||
1129 | + } else { | ||
1130 | + | ||
1131 | + /* Fill in missing data */ | ||
1132 | + h->service = strdup(name); | ||
1133 | + assert(h->service); | ||
1134 | + h->domain = strdup(domain); | ||
1135 | + assert(h->domain); | ||
1136 | + h->daemon_data = d; | ||
1137 | + h->interface = interface; | ||
1138 | + h->protocol = protocol; | ||
1139 | + h->next = d->hosts; | ||
1140 | + h->n_cpus = 1; | ||
1141 | + d->hosts = h; | ||
1142 | + } | ||
1143 | + | ||
1144 | + break; | ||
1145 | + } | ||
1146 | + | ||
1147 | + case AVAHI_BROWSER_REMOVE: | ||
1148 | + | ||
1149 | + rs_log_info("Removed service: %s\n", name); | ||
1150 | + | ||
1151 | + remove_service(d, interface, protocol, name, domain); | ||
1152 | + write_hosts(d); | ||
1153 | + break; | ||
1154 | + | ||
1155 | + case AVAHI_BROWSER_FAILURE: | ||
1156 | + rs_log_crit("Service Browser failure '%s': %s\n", name, | ||
1157 | + avahi_strerror(avahi_client_errno(d->client))); | ||
1158 | + | ||
1159 | + avahi_simple_poll_quit(d->simple_poll); | ||
1160 | + break; | ||
1161 | + | ||
1162 | + case AVAHI_BROWSER_CACHE_EXHAUSTED: | ||
1163 | + case AVAHI_BROWSER_ALL_FOR_NOW: | ||
1164 | + ; | ||
1165 | + | ||
1166 | + } | ||
1167 | +} | ||
1168 | + | ||
1169 | +static void client_callback(AvahiClient *client, AvahiClientState state, void *userdata) { | ||
1170 | + struct daemon_data *d = userdata; | ||
1171 | + | ||
1172 | + switch (state) { | ||
1173 | + | ||
1174 | + case AVAHI_CLIENT_FAILURE: | ||
1175 | + rs_log_crit("Client failure: %s\n", avahi_strerror(avahi_client_errno(client))); | ||
1176 | + avahi_simple_poll_quit(d->simple_poll); | ||
1177 | + break; | ||
1178 | + | ||
1179 | + case AVAHI_CLIENT_S_COLLISION: | ||
1180 | + case AVAHI_CLIENT_S_REGISTERING: | ||
1181 | + case AVAHI_CLIENT_S_RUNNING: | ||
1182 | + case AVAHI_CLIENT_CONNECTING: | ||
1183 | + ; | ||
1184 | + } | ||
1185 | +} | ||
1186 | + | ||
1187 | +/* The main function of the background daemon */ | ||
1188 | +static void daemon_proc(const char *host_file, const char *lock_file, int n_slots) { | ||
1189 | + int ret = 1; | ||
1190 | + int lock_fd = -1; | ||
1191 | + struct daemon_data d; | ||
1192 | + time_t clip_time; | ||
1193 | + int error; | ||
1194 | + | ||
1195 | + rs_add_logger(rs_logger_syslog, RS_LOG_DEBUG, NULL, 0); | ||
1196 | + | ||
1197 | + /* Prepare daemon data structure */ | ||
1198 | + d.fd = -1; | ||
1199 | + d.hosts = NULL; | ||
1200 | + d.n_slots = n_slots; | ||
1201 | + d.simple_poll = NULL; | ||
1202 | + d.browser = NULL; | ||
1203 | + d.client = NULL; | ||
1204 | + clip_time = time(NULL); | ||
1205 | + | ||
1206 | + rs_log_info("Zeroconf daemon running.\n"); | ||
1207 | + | ||
1208 | + /* Open daemon lock file and lock it */ | ||
1209 | + if ((lock_fd = open(lock_file, O_RDWR|O_CREAT, 0666)) < 0) { | ||
1210 | + rs_log_crit("open('%s') failed: %s\n", lock_file, strerror(errno)); | ||
1211 | + goto finish; | ||
1212 | + } | ||
1213 | + | ||
1214 | + if (generic_lock(lock_fd, 1, 1, 0) < 0) { | ||
1215 | + /* lock failed, there's probably already another daemon running */ | ||
1216 | + goto finish; | ||
1217 | + } | ||
1218 | + | ||
1219 | + /* Open host file */ | ||
1220 | + if ((d.fd = open(host_file, O_RDWR|O_CREAT, 0666)) < 0) { | ||
1221 | + rs_log_crit("open('%s') failed: %s\n", host_file, strerror(errno)); | ||
1222 | + goto finish; | ||
1223 | + } | ||
1224 | + | ||
1225 | + /* Clear host file */ | ||
1226 | + write_hosts(&d); | ||
1227 | + | ||
1228 | + if (!(d.simple_poll = avahi_simple_poll_new())) { | ||
1229 | + rs_log_crit("Failed to create simple poll object.\n"); | ||
1230 | + goto finish; | ||
1231 | + } | ||
1232 | + | ||
1233 | + if (!(d.client = avahi_client_new(avahi_simple_poll_get(d.simple_poll), | ||
1234 | + 0, | ||
1235 | + client_callback, | ||
1236 | + &d, | ||
1237 | + &error))) { | ||
1238 | + rs_log_crit("Failed to create Avahi client object: %s\n", avahi_strerror(error)); | ||
1239 | + goto finish; | ||
1240 | + } | ||
1241 | + | ||
1242 | + if (!(d.browser = avahi_service_browser_new(d.client, | ||
1243 | + AVAHI_IF_UNSPEC, | ||
1244 | + AVAHI_PROTO_UNSPEC, | ||
1245 | + DCC_DNS_SERVICE_TYPE, | ||
1246 | + NULL, | ||
1247 | + 0, | ||
1248 | + browse_reply, | ||
1249 | + &d))) { | ||
1250 | + rs_log_crit("Failed to create service browser object: %s\n", avahi_strerror(avahi_client_errno(d.client))); | ||
1251 | + goto finish; | ||
1252 | + } | ||
1253 | + | ||
1254 | + /* Check whether the host file has been used recently */ | ||
1255 | + while (fd_last_used(d.fd, clip_time) <= MAX_IDLE_TIME) { | ||
1256 | + | ||
1257 | + /* Iterate the main loop for 500ms */ | ||
1258 | + if (avahi_simple_poll_iterate(d.simple_poll, 500) != 0) { | ||
1259 | + rs_log_crit("Event loop exited abnormaly.\n"); | ||
1260 | + goto finish; | ||
1261 | + } | ||
1262 | + } | ||
1263 | + | ||
1264 | + /* Wer are idle */ | ||
1265 | + rs_log_info("Zeroconf daemon unused.\n"); | ||
1266 | + | ||
1267 | + ret = 0; | ||
1268 | + | ||
1269 | +finish: | ||
1270 | + | ||
1271 | + /* Cleanup */ | ||
1272 | + if (lock_fd >= 0) { | ||
1273 | + generic_lock(lock_fd, 1, 0, 0); | ||
1274 | + close(lock_fd); | ||
1275 | + } | ||
1276 | + | ||
1277 | + if (d.fd >= 0) | ||
1278 | + close(d.fd); | ||
1279 | + | ||
1280 | + while (d.hosts) { | ||
1281 | + struct host *h = d.hosts; | ||
1282 | + d.hosts = d.hosts->next; | ||
1283 | + free_host(h); | ||
1284 | + } | ||
1285 | + | ||
1286 | + if (d.client) | ||
1287 | + avahi_client_free(d.client); | ||
1288 | + | ||
1289 | + if (d.simple_poll) | ||
1290 | + avahi_simple_poll_free(d.simple_poll); | ||
1291 | + | ||
1292 | + rs_log_info("zeroconf daemon ended.\n"); | ||
1293 | + | ||
1294 | + _exit(ret); | ||
1295 | +} | ||
1296 | + | ||
1297 | +/* Return path to the zeroconf directory in ~/.distcc */ | ||
1298 | +static int get_zeroconf_dir(char **dir_ret) { | ||
1299 | + static char *cached; | ||
1300 | + int ret; | ||
1301 | + | ||
1302 | + if (cached) { | ||
1303 | + *dir_ret = cached; | ||
1304 | + return 0; | ||
1305 | + } else { | ||
1306 | + ret = dcc_get_subdir("zeroconf", dir_ret); | ||
1307 | + if (ret == 0) | ||
1308 | + cached = *dir_ret; | ||
1309 | + return ret; | ||
1310 | + } | ||
1311 | +} | ||
1312 | + | ||
1313 | +/* Get the host list from zeroconf */ | ||
1314 | +int dcc_zeroconf_add_hosts(struct dcc_hostdef **ret_list, int *ret_nhosts, int n_slots, struct dcc_hostdef **ret_prev) { | ||
1315 | + char host_file[PATH_MAX], lock_file[PATH_MAX], *s = NULL; | ||
1316 | + int lock_fd = -1, host_fd = -1; | ||
1317 | + int fork_daemon = 0; | ||
1318 | + int r = -1; | ||
1319 | + char *dir; | ||
1320 | + struct stat st; | ||
1321 | + | ||
1322 | + if (get_zeroconf_dir(&dir) != 0) { | ||
1323 | + rs_log_crit("failed to get zeroconf dir.\n"); | ||
1324 | + goto finish; | ||
1325 | + } | ||
1326 | + | ||
1327 | + snprintf(lock_file, sizeof(lock_file), "%s/lock", dir); | ||
1328 | + snprintf(host_file, sizeof(host_file), "%s/hosts", dir); | ||
1329 | + | ||
1330 | + /* Open lock file */ | ||
1331 | + if ((lock_fd = open(lock_file, O_RDWR|O_CREAT, 0666)) < 0) { | ||
1332 | + rs_log_crit("open('%s') failed: %s\n", lock_file, strerror(errno)); | ||
1333 | + goto finish; | ||
1334 | + } | ||
1335 | + | ||
1336 | + /* Try to lock the lock file */ | ||
1337 | + if (generic_lock(lock_fd, 1, 1, 0) >= 0) { | ||
1338 | + /* The lock succeeded => there's no daemon running yet! */ | ||
1339 | + fork_daemon = 1; | ||
1340 | + generic_lock(lock_fd, 1, 0, 0); | ||
1341 | + } | ||
1342 | + | ||
1343 | + close(lock_fd); | ||
1344 | + | ||
1345 | + /* Shall we fork a new daemon? */ | ||
1346 | + if (fork_daemon) { | ||
1347 | + pid_t pid; | ||
1348 | + | ||
1349 | + rs_log_info("Spawning zeroconf daemon.\n"); | ||
1350 | + | ||
1351 | + if ((pid = fork()) == -1) { | ||
1352 | + rs_log_crit("fork() failed: %s\n", strerror(errno)); | ||
1353 | + goto finish; | ||
1354 | + } else if (pid == 0) { | ||
1355 | + int fd; | ||
1356 | + /* Child */ | ||
1357 | + | ||
1358 | + /* Close file descriptors and replace them by /dev/null */ | ||
1359 | + close(0); | ||
1360 | + close(1); | ||
1361 | + close(2); | ||
1362 | + fd = open("/dev/null", O_RDWR); | ||
1363 | + assert(fd == 0); | ||
1364 | + fd = dup(0); | ||
1365 | + assert(fd == 1); | ||
1366 | + fd = dup(0); | ||
1367 | + assert(fd == 2); | ||
1368 | + | ||
1369 | +#ifdef HAVE_SETSID | ||
1370 | + setsid(); | ||
1371 | +#endif | ||
1372 | + | ||
1373 | + chdir("/"); | ||
1374 | + rs_add_logger(rs_logger_syslog, RS_LOG_DEBUG, NULL, 0); | ||
1375 | + daemon_proc(host_file, lock_file, n_slots); | ||
1376 | + } | ||
1377 | + | ||
1378 | + /* Parent */ | ||
1379 | + | ||
1380 | + /* Wait some time for initial host gathering */ | ||
1381 | + usleep(1000000); /* 1000 ms */ | ||
1382 | + | ||
1383 | + } | ||
1384 | + | ||
1385 | + /* Open host list read-only */ | ||
1386 | + if ((host_fd = open(host_file, O_RDONLY)) < 0) { | ||
1387 | + rs_log_crit("open('%s') failed: %s\n", host_file, strerror(errno)); | ||
1388 | + goto finish; | ||
1389 | + } | ||
1390 | + | ||
1391 | + /* A read lock */ | ||
1392 | + if (generic_lock(host_fd, 0, 1, 1) < 0) { | ||
1393 | + rs_log_crit("lock failed: %s\n", strerror(errno)); | ||
1394 | + goto finish; | ||
1395 | + } | ||
1396 | + | ||
1397 | + /* Get file size */ | ||
1398 | + if (fstat(host_fd, &st) < 0) { | ||
1399 | + rs_log_crit("stat() failed: %s\n", strerror(errno)); | ||
1400 | + goto finish; | ||
1401 | + } | ||
1402 | + | ||
1403 | + if (st.st_size >= MAX_FILE_SIZE) { | ||
1404 | + rs_log_crit("file too large.\n"); | ||
1405 | + goto finish; | ||
1406 | + } | ||
1407 | + | ||
1408 | + /* read file data */ | ||
1409 | + s = malloc((size_t) st.st_size+1); | ||
1410 | + assert(s); | ||
1411 | + | ||
1412 | + if (dcc_readx(host_fd, s, (size_t) st.st_size) != 0) { | ||
1413 | + rs_log_crit("failed to read from file.\n"); | ||
1414 | + goto finish; | ||
1415 | + } | ||
1416 | + s[st.st_size] = 0; | ||
1417 | + | ||
1418 | + /* Parse host data */ | ||
1419 | + if (dcc_parse_hosts(s, host_file, ret_list, ret_nhosts, ret_prev) != 0) { | ||
1420 | + rs_log_crit("failed to parse host file.\n"); | ||
1421 | + goto finish; | ||
1422 | + } | ||
1423 | + | ||
1424 | + r = 0; | ||
1425 | + | ||
1426 | +finish: | ||
1427 | + if (host_fd >= 0) { | ||
1428 | + generic_lock(host_fd, 0, 0, 1); | ||
1429 | + close(host_fd); | ||
1430 | + } | ||
1431 | + | ||
1432 | + free(s); | ||
1433 | + | ||
1434 | + return r; | ||
1435 | +} | ||
1436 | + | ||
1437 | --- upstream/src/zeroconf-reg.c 1970-01-01 01:00:00.000000000 +0100 | ||
1438 | +++ lennart/src/zeroconf-reg.c 2005-11-18 15:34:00.000000000 +0100 | ||
1439 | @@ -0,0 +1,297 @@ | ||
1440 | +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- */ | ||
1441 | + | ||
1442 | +#include "config.h" | ||
1443 | + | ||
1444 | +#include <assert.h> | ||
1445 | +#include <stdio.h> | ||
1446 | +#include <sys/select.h> | ||
1447 | +#include <signal.h> | ||
1448 | +#include <sys/file.h> | ||
1449 | +#include <sys/time.h> | ||
1450 | +#include <time.h> | ||
1451 | +#include <sys/stat.h> | ||
1452 | +#include <sys/poll.h> | ||
1453 | +#include <pthread.h> | ||
1454 | +#include <stdlib.h> | ||
1455 | +#include <unistd.h> | ||
1456 | +#include <string.h> | ||
1457 | +#include <errno.h> | ||
1458 | + | ||
1459 | +#include <avahi-common/simple-watch.h> | ||
1460 | +#include <avahi-common/error.h> | ||
1461 | +#include <avahi-common/alternative.h> | ||
1462 | +#include <avahi-common/malloc.h> | ||
1463 | +#include <avahi-client/publish.h> | ||
1464 | + | ||
1465 | +#include "distcc.h" | ||
1466 | +#include "zeroconf.h" | ||
1467 | +#include "trace.h" | ||
1468 | +#include "exitcode.h" | ||
1469 | + | ||
1470 | +struct context { | ||
1471 | + int thread_running; | ||
1472 | + pthread_t thread_id; | ||
1473 | + pthread_mutex_t mutex; | ||
1474 | + char *name; | ||
1475 | + AvahiSimplePoll *simple_poll; | ||
1476 | + AvahiClient *client; | ||
1477 | + AvahiEntryGroup *group; | ||
1478 | + uint16_t port; | ||
1479 | + int n_cpus; | ||
1480 | +}; | ||
1481 | + | ||
1482 | +static void publish_reply(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata); | ||
1483 | + | ||
1484 | +static void register_stuff(struct context *ctx) { | ||
1485 | + | ||
1486 | + if (!ctx->group) { | ||
1487 | + | ||
1488 | + if (!(ctx->group = avahi_entry_group_new(ctx->client, publish_reply, ctx))) { | ||
1489 | + rs_log_crit("Failed to create entry group: %s\n", avahi_strerror(avahi_client_errno(ctx->client))); | ||
1490 | + goto fail; | ||
1491 | + } | ||
1492 | + | ||
1493 | + } | ||
1494 | + | ||
1495 | + if (avahi_entry_group_is_empty(ctx->group)) { | ||
1496 | + char cpus[32]; | ||
1497 | + | ||
1498 | + snprintf(cpus, sizeof(cpus), "cpus=%i", ctx->n_cpus); | ||
1499 | + | ||
1500 | + /* Register our service */ | ||
1501 | + | ||
1502 | + if (avahi_entry_group_add_service(ctx->group, | ||
1503 | + AVAHI_IF_UNSPEC, | ||
1504 | + AVAHI_PROTO_UNSPEC, | ||
1505 | + 0, | ||
1506 | + ctx->name, | ||
1507 | + DCC_DNS_SERVICE_TYPE, | ||
1508 | + NULL, | ||
1509 | + NULL, | ||
1510 | + ctx->port, | ||
1511 | + "txtvers=1", | ||
1512 | + cpus, | ||
1513 | + "distcc="PACKAGE_VERSION, | ||
1514 | + "gnuhost="GNU_HOST, | ||
1515 | + NULL) < 0) { | ||
1516 | + rs_log_crit("Failed to add service: %s\n", avahi_strerror(avahi_client_errno(ctx->client))); | ||
1517 | + goto fail; | ||
1518 | + } | ||
1519 | + | ||
1520 | + if (avahi_entry_group_commit(ctx->group) < 0) { | ||
1521 | + rs_log_crit("Failed to commit entry group: %s\n", avahi_strerror(avahi_client_errno(ctx->client))); | ||
1522 | + goto fail; | ||
1523 | + } | ||
1524 | + } | ||
1525 | + | ||
1526 | + return; | ||
1527 | + | ||
1528 | + fail: | ||
1529 | + avahi_simple_poll_quit(ctx->simple_poll); | ||
1530 | +} | ||
1531 | + | ||
1532 | +/* Called when publishing of service data completes */ | ||
1533 | +static void publish_reply(AvahiEntryGroup *UNUSED(g), AvahiEntryGroupState state, void *userdata) { | ||
1534 | + struct context *ctx = userdata; | ||
1535 | + | ||
1536 | + switch (state) { | ||
1537 | + | ||
1538 | + case AVAHI_ENTRY_GROUP_COLLISION: { | ||
1539 | + char *n; | ||
1540 | + | ||
1541 | + /* Pick a new name for our service */ | ||
1542 | + | ||
1543 | + n = avahi_alternative_service_name(ctx->name); | ||
1544 | + assert(n); | ||
1545 | + | ||
1546 | + avahi_free(ctx->name); | ||
1547 | + ctx->name = n; | ||
1548 | + | ||
1549 | + register_stuff(ctx); | ||
1550 | + break; | ||
1551 | + } | ||
1552 | + | ||
1553 | + case AVAHI_ENTRY_GROUP_FAILURE: | ||
1554 | + rs_log_crit("Failed to register service: %s\n", avahi_strerror(avahi_client_errno(ctx->client))); | ||
1555 | + avahi_simple_poll_quit(ctx->simple_poll); | ||
1556 | + break; | ||
1557 | + | ||
1558 | + case AVAHI_ENTRY_GROUP_UNCOMMITED: | ||
1559 | + case AVAHI_ENTRY_GROUP_REGISTERING: | ||
1560 | + case AVAHI_ENTRY_GROUP_ESTABLISHED: | ||
1561 | + ; | ||
1562 | + } | ||
1563 | +} | ||
1564 | + | ||
1565 | +static void client_callback(AvahiClient *client, AvahiClientState state, void *userdata) { | ||
1566 | + struct context *ctx = userdata; | ||
1567 | + | ||
1568 | + ctx->client = client; | ||
1569 | + | ||
1570 | + switch (state) { | ||
1571 | + | ||
1572 | + case AVAHI_CLIENT_S_RUNNING: | ||
1573 | + | ||
1574 | + register_stuff(ctx); | ||
1575 | + break; | ||
1576 | + | ||
1577 | + case AVAHI_CLIENT_S_COLLISION: | ||
1578 | + | ||
1579 | + if (ctx->group) | ||
1580 | + avahi_entry_group_reset(ctx->group); | ||
1581 | + break; | ||
1582 | + | ||
1583 | + case AVAHI_CLIENT_FAILURE: | ||
1584 | + | ||
1585 | + if (avahi_client_errno(client) == AVAHI_ERR_DISCONNECTED) { | ||
1586 | + int error; | ||
1587 | + | ||
1588 | + avahi_client_free(ctx->client); | ||
1589 | + ctx->client = NULL; | ||
1590 | + ctx->group = NULL; | ||
1591 | + | ||
1592 | + /* Reconnect to the server */ | ||
1593 | + | ||
1594 | + if (!(ctx->client = avahi_client_new(avahi_simple_poll_get(ctx->simple_poll), | ||
1595 | + AVAHI_CLIENT_NO_FAIL, | ||
1596 | + client_callback, | ||
1597 | + ctx, | ||
1598 | + &error))) { | ||
1599 | + | ||
1600 | + rs_log_crit("Failed to contact server: %s\n", avahi_strerror(error)); | ||
1601 | + avahi_simple_poll_quit(ctx->simple_poll); | ||
1602 | + } | ||
1603 | + | ||
1604 | + } else { | ||
1605 | + rs_log_crit("Client failure: %s\n", avahi_strerror(avahi_client_errno(client))); | ||
1606 | + avahi_simple_poll_quit(ctx->simple_poll); | ||
1607 | + } | ||
1608 | + | ||
1609 | + break; | ||
1610 | + | ||
1611 | + case AVAHI_CLIENT_S_REGISTERING: | ||
1612 | + case AVAHI_CLIENT_CONNECTING: | ||
1613 | + ; | ||
1614 | + } | ||
1615 | +} | ||
1616 | + | ||
1617 | +static void* thread(void *userdata) { | ||
1618 | + struct context *ctx = userdata; | ||
1619 | + sigset_t mask; | ||
1620 | + int r; | ||
1621 | + | ||
1622 | + /* Make sure that signals are delivered to the main thread */ | ||
1623 | + sigfillset(&mask); | ||
1624 | + pthread_sigmask(SIG_BLOCK, &mask, NULL); | ||
1625 | + | ||
1626 | + pthread_mutex_lock(&ctx->mutex); | ||
1627 | + | ||
1628 | + /* Run the main loop */ | ||
1629 | + r = avahi_simple_poll_loop(ctx->simple_poll); | ||
1630 | + | ||
1631 | + /* Cleanup some stuff */ | ||
1632 | + if (ctx->client) | ||
1633 | + avahi_client_free(ctx->client); | ||
1634 | + ctx->client = NULL; | ||
1635 | + ctx->group = NULL; | ||
1636 | + | ||
1637 | + pthread_mutex_unlock(&ctx->mutex); | ||
1638 | + | ||
1639 | + return NULL; | ||
1640 | +} | ||
1641 | + | ||
1642 | +static int poll_func(struct pollfd *ufds, unsigned int nfds, int timeout, void *userdata) { | ||
1643 | + pthread_mutex_t *mutex = userdata; | ||
1644 | + int r; | ||
1645 | + | ||
1646 | + /* Before entering poll() we unlock the mutex, so that | ||
1647 | + * avahi_simple_poll_quit() can succeed from another thread. */ | ||
1648 | + | ||
1649 | + pthread_mutex_unlock(mutex); | ||
1650 | + r = poll(ufds, nfds, timeout); | ||
1651 | + pthread_mutex_lock(mutex); | ||
1652 | + | ||
1653 | + return r; | ||
1654 | +} | ||
1655 | + | ||
1656 | +/* register a distcc service in DNS-SD/mDNS with the given port and number of CPUs */ | ||
1657 | +void* dcc_zeroconf_register(uint16_t port, int n_cpus) { | ||
1658 | + struct context *ctx = NULL; | ||
1659 | + | ||
1660 | + char service[256] = "distcc@"; | ||
1661 | + int error, ret; | ||
1662 | + | ||
1663 | + ctx = malloc(sizeof(struct context)); | ||
1664 | + assert(ctx); | ||
1665 | + ctx->client = NULL; | ||
1666 | + ctx->group = NULL; | ||
1667 | + ctx->simple_poll = NULL; | ||
1668 | + ctx->thread_running = 0; | ||
1669 | + ctx->port = port; | ||
1670 | + ctx->n_cpus = n_cpus; | ||
1671 | + pthread_mutex_init(&ctx->mutex, NULL); | ||
1672 | + | ||
1673 | + /* Prepare service name */ | ||
1674 | + gethostname(service+7, sizeof(service)-8); | ||
1675 | + service[sizeof(service)-1] = 0; | ||
1676 | + | ||
1677 | + ctx->name = strdup(service); | ||
1678 | + assert(ctx->name); | ||
1679 | + | ||
1680 | + if (!(ctx->simple_poll = avahi_simple_poll_new())) { | ||
1681 | + rs_log_crit("Failed to create event loop object.\n"); | ||
1682 | + goto fail; | ||
1683 | + } | ||
1684 | + | ||
1685 | + avahi_simple_poll_set_func(ctx->simple_poll, poll_func, &ctx->mutex); | ||
1686 | + | ||
1687 | + if (!(ctx->client = avahi_client_new(avahi_simple_poll_get(ctx->simple_poll), AVAHI_CLIENT_NO_FAIL, client_callback, ctx, &error))) { | ||
1688 | + rs_log_crit("Failed to create client object: %s\n", avahi_strerror(avahi_client_errno(ctx->client))); | ||
1689 | + goto fail; | ||
1690 | + } | ||
1691 | + | ||
1692 | + /* Create the mDNS event handler */ | ||
1693 | + if ((ret = pthread_create(&ctx->thread_id, NULL, thread, ctx)) < 0) { | ||
1694 | + rs_log_crit("Failed to create thread: %s\n", strerror(ret)); | ||
1695 | + goto fail; | ||
1696 | + } | ||
1697 | + | ||
1698 | + ctx->thread_running = 1; | ||
1699 | + | ||
1700 | + return ctx; | ||
1701 | + | ||
1702 | + fail: | ||
1703 | + | ||
1704 | + if (ctx) | ||
1705 | + dcc_zeroconf_unregister(ctx); | ||
1706 | + | ||
1707 | + return NULL; | ||
1708 | +} | ||
1709 | + | ||
1710 | +/* Unregister this server from DNS-SD/mDNS */ | ||
1711 | +int dcc_zeroconf_unregister(void *u) { | ||
1712 | + struct context *ctx = u; | ||
1713 | + | ||
1714 | + if (ctx->thread_running) { | ||
1715 | + pthread_mutex_lock(&ctx->mutex); | ||
1716 | + avahi_simple_poll_quit(ctx->simple_poll); | ||
1717 | + pthread_mutex_unlock(&ctx->mutex); | ||
1718 | + | ||
1719 | + pthread_join(ctx->thread_id, NULL); | ||
1720 | + ctx->thread_running = 0; | ||
1721 | + } | ||
1722 | + | ||
1723 | + avahi_free(ctx->name); | ||
1724 | + | ||
1725 | + if (ctx->client) | ||
1726 | + avahi_client_free(ctx->client); | ||
1727 | + | ||
1728 | + if (ctx->simple_poll) | ||
1729 | + avahi_simple_poll_free(ctx->simple_poll); | ||
1730 | + | ||
1731 | + pthread_mutex_destroy(&ctx->mutex); | ||
1732 | + | ||
1733 | + free(ctx); | ||
1734 | + | ||
1735 | + return 0; | ||
1736 | +} | ||