--- +++ 2004/01/05 13:36:02 @@ -, +, @@ --- configure.ac @@ -57,7 +57,6 @@ AC_HELP_STRING([--enable-rfc2553], [use getaddrinfo, getnameinfo, etc]), AC_DEFINE(ENABLE_RFC2553,1,[Use getaddrinfo(), getnameinfo(), etc])) - AC_ARG_WITH(gnome, AC_HELP_STRING([--with-gnome], [build GNOME-based monitor]), [GNOME_BIN=distccmon-gnome @@ -262,13 +261,42 @@ AC_MSG_RESULT(no) fi +######################################################################## +# Check for OpenSLP +AC_ARG_ENABLE(slp, [ --enable-slp find hosts via slp], with_slp=$enableval, with_slp=no) +if test "$with_slp" = "yes"; then +AC_MSG_CHECKING(for SLP support) +save_slptest_LIBS="$LIBS" +save_slptest_LDFLAGS="$LDFLAGS" +save_slptest_CPPFLAGS="$CPPFLAGS" +LDFLAGS="$all_libraries $LDFLAGS" +CPPFLAGS="$CPPFLAGS $all_includes" +LIBS="-lslp" +AC_TRY_LINK( [ + #include + ],[ + SLPOpen(0, SLP_FALSE, (SLPHandle*) 0); + ],[ + AC_DEFINE(WITH_SLP,1,[Define if SLP is avaible and enabled]) + LIB_SLP="-lslp" + SLP_BIN=distccenv + BUILD_SLP='$(slp_OBJS)' + AC_MSG_RESULT(yes) + ],[ + AC_MSG_ERROR(no) +]) +CPPFLAGS=$save_slptest_CPPFLAGS +LDFLAGS=$save_slptest_LDFLAGS +LIBS=$save_slptest_LIBS +fi +AC_SUBST(LIB_SLP) + ######################################################################## # Check for types AC_TYPE_SIGNAL - ######################################################################## # Checks for library functions, using libraries discovered above CPPFLAGS="$CPPFLAGS -I$srcdir/src" @@ -353,6 +381,8 @@ AC_SUBST(CPPFLAGS) AC_SUBST(BUILD_POPT) AC_SUBST(GNOME_BIN) +AC_SUBST(SLP_BIN) +AC_SUBST(BUILD_SLP) dnl AC_DEFINE_UNQUOTED(PACKAGE, $PACKAGE, [Package name]) dnl AC_DEFINE_UNQUOTED(VERSION, $VERSION, [Package version]) AC_DEFINE_UNQUOTED(GNU_HOST, ["$host"], [Your gnu-style host triple]) --- Makefile.in @@ -62,7 +62,7 @@ GNOME_CFLAGS = @GNOME_CFLAGS@ GNOME_LIBS = @GNOME_LIBS@ -LIBS = @LIBS@ +LIBS = @LIBS@ @LIB_SLP@ DESTDIR = @@ -84,6 +84,7 @@ $(MEN) \ $(pkgdoc_DOCS) \ $(example_DOCS) \ + $(slp_EXTRA) $(slp_SRC) $(slp_HEADERS) \ $(popt_EXTRA) $(popt_SRC) $(popt_HEADERS) \ $(SRC) $(HEADERS) \ $(test_SOURCE) \ @@ -175,6 +176,8 @@ src/safeguard.o src/snprintf.o src/timeval.o \ lzo/minilzo.o +distccenv_obj = src/distccenv.o src/cc_version.o + distcc_obj = src/backoff.o \ src/climasq.o src/clinet.o src/clirpc.o \ src/compile.o src/cpp.o \ @@ -192,7 +195,7 @@ src/ncpus.o \ src/prefork.o \ src/serve.o src/setuid.o src/srvnet.o src/srvrpc.o \ - $(common_obj) @BUILD_POPT@ + $(common_obj) @BUILD_POPT@ @BUILD_SLP@ # Objects that need to be linked in to build monitors mon_obj = \ @@ -224,7 +227,7 @@ src/cleanup.c \ src/climasq.c src/clinet.c src/clirpc.c src/compile.c \ src/compress.c src/cpp.c \ - src/daemon.c src/distcc.c src/dsignal.c \ + src/daemon.c src/distcc.c src/dsignal.c src/register_slp.c \ src/dopt.c src/dparent.c src/exec.c src/filename.c \ src/h_argvtostr.c \ src/h_exten.c src/h_hosts.c src/h_issource.c src/h_parsemask.c \ @@ -265,6 +268,11 @@ gnome_data = gnome/distccmon-gnome-icon.png \ gnome/distccmon-gnome.desktop +slp_OBJS=src/register_slp.o src/cc_version.o +slp_SRC=src/register_slp.c src/cc_version.c +slp_HEADERS = src/register_slp.h src/cc_version.h +slp_EXTRA = README.slp + popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \ popt/popthelp.o popt/poptparse.o @@ -292,7 +300,8 @@ distcc@EXEEXT@ \ distccd@EXEEXT@ \ distccmon-text@EXEEXT@ \ - @GNOME_BIN@ + @GNOME_BIN@ \ + @SLP_BIN@ check_PROGRAMS = \ h_exten@EXEEXT@ \ @@ -333,6 +342,9 @@ distcc@EXEEXT@: $(distcc_obj) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(distcc_obj) $(LIBS) +distccenv@EXEEXT@: $(distccenv_obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(distccenv_obj) $(LIBS) + distccd@EXEEXT@: $(distccd_obj) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(distccd_obj) $(LIBS) --- README.slp @@ -0,0 +1,40 @@ +# +# SLP support in distcc +# + +It is enough to start the SLP server and distcc server, if you have +compiled distccd with SLP support. You can simply use distcc as compiler +afterwards. + +NOTE: SLP support is only used, when distccd runs as daemon, not when + running via inetd or xinetd ! + +The distcc frontend cache SLP results inside the $HOME/.distcc.slp.cache +file. This file gets update every 3 minutes (hardcoded for now). + +Alternative you can set the enviroment once via distccenv. A bash user +might simply do to set $DISTCC_HOSTS with + + eval `distccenv` + +A distcc service url looks like + + service:distccd.$IDENTITY + +The identity is usually set based on the used compiler at build time +of distcc and the used system architecture. +However there is no check which checks the installed compiler, since it +is not known how it is called at distccd startup time. + +You can set the IDENTIY during distccd startup via the --slp-identy=$IDENTIY +switch. You need to set the $DISTCC_IDENTITY enviroment variable to the +same value afterwards inside your enviroment (or during distccenv run). + +There is some very basic load balancing code. You can enable it via + + export DISTCC_LOAD_BALANCE=1 + +in your compile enviroment. It is not active, if $DISTCC_HOSTS is set. + +Have fun, adrian. + --- src/cc_version.c @@ -0,0 +1,93 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003 by Adrian Schroeter + * + * 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 + */ + +#include +#include +#include +#include +#include "cc_version.h" +#include "config.h" + +char *used_compiler_version(void) +{ + char *compiler = NULL; + char *architecture = NULL; + char *ret; + int len; + + /* The enviroment is always right ... */ + if ( getenv("DISTCC_IDENTIFY") ) + return getenv("DISTCC_IDENTIFY"); + + /* do we really want a runtime check here ? */ + /* it would be worse performance wise for the distcc frontend ... */ + + /* default compiler based on distcc build time */ +#ifdef __GNUC__ +#ifdef __GNUC_MINOR__ +#ifdef __GNUC_PATCHLEVEL__ + compiler = (char*) malloc( 33 ); + snprintf( compiler, 32, "gcc-%d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ ); +#endif +#endif +#endif + +#ifdef GNU_HOST + architecture = strdup(GNU_HOST); + { + char *p; + p = strstr( architecture, "-" ); + if (p){ + *p = '\0'; + /* unify all different ia32 systems */ + p = architecture; + if ( p[0] == 'i' && p[2] == '8' && p[3] == '6' && p[4] == '\0' ) + p[1] = '3'; + } + } +#endif + + if ( compiler == NULL ){ + /* we use the system release, this is unreleated to the compiler + version, but better than default ... */ + struct utsname t; + if ( !uname( &t ) ) + compiler = t.release; + } + if ( architecture == NULL ){ + struct utsname t; + if ( !uname( &t ) ) + architecture = t.machine; + } + + /* fallback values */ + if ( compiler == NULL ) + compiler = strdup("default"); + if ( architecture == NULL ) + architecture = strdup("default"); + + len = strlen(compiler) + 1 + strlen(architecture) + 1; + ret = (char*) malloc(len + 1); + snprintf( ret, len, "%s-%s", compiler, architecture ); + return ret; +} + --- src/cc_version.h @@ -0,0 +1,3 @@ + +char *used_compiler_version(void); + --- src/config.h.in @@ -260,6 +260,9 @@ /* Use GTK+ */ #undef WITH_GTK +/* Use SLP */ +#undef WITH_SLP + /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus --- src/distccenv.c @@ -0,0 +1,205 @@ + +#include "config.h" + +#ifndef WITH_SLP +#error distccenv needs SLP atm. +#endif + +#include +#include +#include + +#include "register_slp.h" + +#define BUFFER 1024 + +char compiler[BUFFER + 1]; +FILE *out; + +#define MAX_HOSTS 256 +struct dcc_host{ + char *url; + int jobs; + float speed; + float load; + long value; +}; +struct dcc_host hosts[MAX_HOSTS]; +int host_count = 0; + +int slp_calls = 0; +int load_balancing = 0; + +void dump_result(void); +SLPBoolean myAttrCallback(SLPHandle phslp, char* attrlist, + SLPError errcode, void* cookie ); +SLPBoolean MySLPSrvURLCallback( SLPHandle phslp, const char* srvurl, + unsigned short lifetime, SLPError errcode, + void* cookie ); + +void dump_result(void) +{ + int h, j, max_jobs = 0; + float avg_speed = 0, avg_load = 0; + + if ( host_count == 0 ) + exit(-1); + + if ( !out ) + printf( "DISTCC_HOSTS=\"" ); + + if ( load_balancing ) + { + for ( h = 0; h 2 && !strcmp(argv[1], "--file" ) ) + out = fopen( argv[2], "w" ); + + snprintf( compiler, BUFFER, "service:distccd.%s", used_compiler_version() ); + + result = SLPOpen( NULL, SLP_FALSE, &phslp); + if (result != SLP_OK) { + fprintf( stderr, "SLPOpen failed ! Aborting ... " ); + exit( -1 ); + } else { + result = SLPFindSrvs( phslp, + compiler, + "", // TODO: Scope selector + "", // all services + MySLPSrvURLCallback, + 0 ); + if (result != SLP_OK){ + fprintf( stderr, "unable to query for services ! Aborting .." ); + exit(-1); + } + + if ( load_balancing ) + { + for ( h = 0; h < host_count; h++ ) + { + char buf[BUFFER+1]; + snprintf( buf, BUFFER, "%s://%s", compiler, hosts[h].url ); + result = SLPFindAttrs(phslp, + buf, + "", + "maxjobs,bogomips,load", + myAttrCallback, + (void*)h); + if(result != SLP_OK) + { + printf("unable to request SLP attributes: %i\n",result); + exit(-1); + } + } + }else + dump_result(); + + SLPClose( phslp ); + } + + dump_result(); + return 0; +} --- src/dopt.c @@ -50,6 +50,10 @@ #include "setuid.h" #include "access.h" +#ifdef WITH_SLP +#include "register_slp.h" +#endif + int opt_niceness = 5; /* default */ /** @@ -92,6 +96,7 @@ const char *arg_pid_file = NULL; const char *arg_log_file = NULL; +const char *compiler_version = NULL; /* Enumeration values for options that don't have single-letter name. These * must be numerically above all the ascii letters. */ @@ -123,6 +128,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 WITH_SLP + { "slp-identy", 0, POPT_ARG_STRING, &compiler_version, 0, 0, 0 }, +#endif { 0, 0, 0, 0, 0, 0, 0 } }; @@ -157,6 +165,10 @@ " Mode of operation:\n" " --inetd serve client connected to stdin\n" " --daemon bind and listen on socket\n" +#ifdef WITH_SLP +" SLP Identification:\n" +" --slp-identy=STRING to identify the provided compiler\n" +#endif "\n" "distccd runs either from inetd or as a standalone daemon to compile\n" "files submitted by the distcc client.\n" @@ -253,6 +265,11 @@ } } +#ifdef WITH_SLP + if ( compiler_version == NULL ) + compiler_version = used_compiler_version(); +#endif + poptFreeContext(po); return 0; --- src/dopt.h @@ -20,6 +20,7 @@ * USA */ +#include "config.h" /* dopt.c */ extern struct dcc_allow_list *opt_allowed; @@ -38,3 +39,6 @@ extern int opt_lifetime; extern char *opt_listen_addr; extern int opt_niceness; +#ifdef WITH_SLP +extern const char *compiler_version; +#endif --- src/dparent.c @@ -71,6 +71,9 @@ #include "srvnet.h" #include "types.h" #include "daemon.h" +#if WITH_SLP +#include "register_slp.h" +#endif static int dcc_start_server_child(int listen_fd, int accept_fd, struct sockaddr *, int); @@ -137,6 +140,10 @@ * not. */ dcc_master_pid = getpid(); +#ifdef WITH_SLP + register_slp(); +#endif + if (opt_no_fork) { dcc_log_daemon_started("non-forking daemon"); dcc_nofork_parent(listen_fd); --- src/hosts.c @@ -85,6 +85,8 @@ #include #include #include +#include +#include #include #include #include @@ -162,7 +164,30 @@ rs_trace("not reading %s: %s", path, strerror(errno)); free(path); } - + +#ifdef WITH_SLP + if ((home = getenv("HOME")) != NULL) { + struct stat fst; + + asprintf(&path, "%s/.distcc.slp.cache", home); + /* the refresh rate of SLP cache is hardcoded to 5 minutes for now */ + if ( stat (path, &fst) || fst.st_mtime < time (0) - 60*5 ) { + unlink( path ); + /* sure, we could implement the SLP query also via a function + call, but we would need to wait here anyway ... */ + execlp("distccenv", "distccenv", "--file", path, 0 ); + } + if (access(path, R_OK) == 0) { + ret = dcc_parse_hosts_file(path, ret_list, ret_nhosts); + free(path); + return ret; + } else { + rs_trace("not reading %s: %s", path, strerror(errno)); + free(path); + } + } +#endif + /* FIXME: Clearer message? */ rs_log_warning("no hostlist is set; can't distribute work"); --- src/register_slp.c @@ -0,0 +1,127 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003 by Adrian Schroeter + * + * 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 + */ + +#include "register_slp.h" + +#ifdef WITH_SLP +#include +#include +#include +#include +#include +#include +#include "dopt.h" +#include "trace.h" +#include "cc_version.h" + +extern int dcc_max_kids; + +void mySLPRegReport(SLPHandle hslp, SLPError errcode, void *cookie) +{ + hslp = hslp; cookie = cookie; + if (errcode) + rs_log_warning( "SLP (de)registration error" ); +} + +void refresh_slp(void) +{ + register_slp(); +} + +void register_slp(void) +{ + SLPHandle phslp; + SLPError result; + struct sigaction act, oact; + /* TODO: make it a config option */ + /* hardcode it to 5 minutes now, because we use also the load + from last 5 minutes */ + int slp_timeout = 60 * 3; + + /* do not bomb the slp server with wrong configuration */ + if ( slp_timeout < 120 ) + slp_timeout = 120 ; + if ( slp_timeout > SLP_LIFETIME_MAXIMUM ) + slp_timeout = SLP_LIFETIME_MAXIMUM; + + result = SLPOpen( 0, SLP_FALSE, &phslp); + if (result != SLP_OK) + rs_log_warning( "SLPOpen failed" ); + else { + char hostname[1024]; + char SLPServiceUrl[2048]; + char SLPattributes[2048]; + long load = -1, bogomips = 0; + FILE *proc; + + gethostname( hostname, 1023 ); + /* Linux specific part, no idea how to do this in general */ + proc = fopen( "/proc/cpuinfo", "r" ); + if ( proc ){ + while( !feof(proc) ) { + long b = 0; + int ret; + ret = fscanf( proc, "bogomips : %ld", &b ); + if ( ret < 0 ) + break; + if ( ret ) + bogomips += b; + fseek( proc, 1L, SEEK_CUR ); + } + fclose( proc ); + } + + proc = fopen( "/proc/loadavg", "r" ); + if ( proc ){ + fscanf( proc, "%*d.%*d %ld.%*d %*s %*s %*s", &load ); + fclose( proc ); + } + if ( !bogomips ) bogomips = 1; + load += 1; + + snprintf( SLPServiceUrl, 1023, "service:distccd.%s://%s:%i", compiler_version, hostname, arg_port ); + snprintf( SLPattributes, 1023, "(maxjobs=%d),(bogomips=%ld),(load=%ld)", dcc_max_kids, bogomips, load ); + + result = SLPReg( phslp, + SLPServiceUrl, + slp_timeout, + 0, + SLPattributes, + SLP_TRUE, + mySLPRegReport, + 0 ); + + if (result != SLP_OK) + rs_log_warning( "unable to register SLP service" ); + SLPClose( phslp ); + + /* sigalarm is also used in inetd mode, but we should never + use SLP in inetd mode anyway ... */ + act.sa_handler = refresh_slp; + if (0 != sigaction(SIGALRM, &act, &oact)) + rs_log_warning("Error establishing signal handler for SLP"); + alarm(slp_timeout - 15); + } +} +#endif + + --- src/register_slp.h @@ -0,0 +1,15 @@ + +#include "config.h" + +#ifdef WITH_SLP + +#include + +void register_slp(void); +char* used_compiler_version(void); + +void refresh_slp(void); +void mySLPRegReport(SLPHandle hslp, SLPError errcode, void *cookie); + +#endif + --- src/setuid.c @@ -108,11 +108,6 @@ * permanently discard privileges: both the real and effective uid are * set. */ - if (setuid(uid)) { - rs_log_error("setuid(%d) failed: %s", (int) uid, strerror(errno)); - return EXIT_SETUID_FAILED; - } - if (setgid(gid)) { rs_log_error("setgid(%d) failed: %s", (int) gid, strerror(errno)); return EXIT_SETUID_FAILED; @@ -128,6 +123,11 @@ } #endif + if (setuid(uid)) { + rs_log_error("setuid(%d) failed: %s", (int) uid, strerror(errno)); + return EXIT_SETUID_FAILED; + } + if (getuid() == 0 || geteuid() == 0) { rs_log_crit("still have root privileges after trying to discard them!"); return EXIT_SETUID_FAILED;