├── tests ├── assembler.args ├── clangpluginextra.txt ├── plain.c ├── plain.cpp ├── macros.s ├── fsanitize-blacklist.txt ├── testfunc.cpp ├── true.cpp ├── clangplugintest.cpp ├── make10.cpp ├── make2.cpp ├── make3.cpp ├── make4.cpp ├── make5.cpp ├── make6.cpp ├── make7.cpp ├── make8.cpp ├── make9.cpp ├── debug-gdb.txt ├── testmainfunc.cpp ├── recursive_g++ ├── syntaxerror.cpp ├── recursive_clang++ ├── unusedmacro.cpp ├── unusedmacro1.txt ├── unusedmacro2.txt ├── includes.h ├── unusedmacro3.txt ├── plain ├── make1.cpp ├── messages.cpp ├── test-setup.sh.in ├── includes.cpp ├── messages.h ├── testdefine.cpp ├── warninginmacro.cpp ├── includes-without.cpp ├── debug.cpp ├── fsanitize.cpp ├── debug │ └── debug2.cpp ├── icerun-test.sh ├── valgrind_suppressions ├── Makefile.test ├── make.h ├── Makefile.am ├── args.cpp ├── README └── clangplugin.cpp ├── compilerwrapper ├── Makefile.am └── compilerwrapper.cpp ├── suse ├── iceccd.xml ├── icecc-scheduler.xml ├── logrotate ├── SuSEfirewall.iceccd ├── SuSEfirewall.scheduler ├── update_rpm ├── Makefile.am ├── sysconfig.icecream ├── init.icecream └── icecream.spec.in ├── scheduler ├── Makefile.am ├── scheduler.h ├── jobstat.h ├── jobstat.cpp ├── job.h ├── job.cpp └── compileserver.h ├── services ├── icecc.pc.in ├── Makefile.am ├── util.h ├── gcc.cpp ├── platform.h ├── tempfile.h ├── exitcode.cpp ├── exitcode.h ├── platform.cpp ├── job.cpp ├── getifaddrs.h ├── logging.h ├── tempfile.c ├── logging.cpp ├── job.h └── getifaddrs.cpp ├── Makefile.am ├── daemon ├── Makefile.am ├── ncpus.h ├── load.h ├── file_util.h ├── serve.h ├── workit.h ├── environment.h ├── ncpus.c └── file_util.cpp ├── .cirrus.yml ├── doc ├── Makefile.am ├── man-icecc.1.xml ├── man-icecc-create-env.1.xml ├── man-icecc-scheduler.1.xml └── man-iceccd.1.xml ├── .gitignore ├── README ├── client ├── argv.h ├── Makefile.am ├── util.h ├── safeguard.cpp ├── md5.h ├── client.h ├── icecc-test-env.in ├── cpp.cpp └── util.cpp ├── autogen.sh ├── m4 └── cap-ng.m4 ├── .travis.yml ├── TODO └── BENCH /tests/assembler.args: -------------------------------------------------------------------------------- 1 | -al=listing.txt 2 | -------------------------------------------------------------------------------- /tests/clangpluginextra.txt: -------------------------------------------------------------------------------- 1 | testfile 2 | -------------------------------------------------------------------------------- /tests/plain.c: -------------------------------------------------------------------------------- 1 | void f() 2 | { 3 | } 4 | -------------------------------------------------------------------------------- /tests/plain.cpp: -------------------------------------------------------------------------------- 1 | void f() 2 | { 3 | } 4 | -------------------------------------------------------------------------------- /tests/macros.s: -------------------------------------------------------------------------------- 1 | 2 | 3 | .macro asm_macro 4 | .endm 5 | -------------------------------------------------------------------------------- /tests/fsanitize-blacklist.txt: -------------------------------------------------------------------------------- 1 | fun:*test_fsanitize_function* 2 | -------------------------------------------------------------------------------- /tests/testfunc.cpp: -------------------------------------------------------------------------------- 1 | int f() 2 | { 3 | return 123; 4 | } 5 | -------------------------------------------------------------------------------- /tests/true.cpp: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | return 0; 4 | } 5 | -------------------------------------------------------------------------------- /tests/clangplugintest.cpp: -------------------------------------------------------------------------------- 1 | bool foo() 2 | { 3 | return false; 4 | } 5 | -------------------------------------------------------------------------------- /tests/make10.cpp: -------------------------------------------------------------------------------- 1 | #include "make.h" 2 | 3 | void make10() 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /tests/make2.cpp: -------------------------------------------------------------------------------- 1 | #include "make.h" 2 | 3 | void make2() 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /tests/make3.cpp: -------------------------------------------------------------------------------- 1 | #include "make.h" 2 | 3 | void make3() 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /tests/make4.cpp: -------------------------------------------------------------------------------- 1 | #include "make.h" 2 | 3 | void make4() 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /tests/make5.cpp: -------------------------------------------------------------------------------- 1 | #include "make.h" 2 | 3 | void make5() 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /tests/make6.cpp: -------------------------------------------------------------------------------- 1 | #include "make.h" 2 | 3 | void make6() 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /tests/make7.cpp: -------------------------------------------------------------------------------- 1 | #include "make.h" 2 | 3 | void make7() 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /tests/make8.cpp: -------------------------------------------------------------------------------- 1 | #include "make.h" 2 | 3 | void make8() 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /tests/make9.cpp: -------------------------------------------------------------------------------- 1 | #include "make.h" 2 | 3 | void make9() 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /tests/debug-gdb.txt: -------------------------------------------------------------------------------- 1 | start 2 | list main,main 3 | step 4 | print debugObject.debugMember 5 | -------------------------------------------------------------------------------- /tests/testmainfunc.cpp: -------------------------------------------------------------------------------- 1 | extern int f(); 2 | 3 | int main() 4 | { 5 | return f(); 6 | } 7 | -------------------------------------------------------------------------------- /tests/recursive_g++: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # Indirectly invoke icecc again. 4 | 5 | exec icecc g++ "$@" 6 | -------------------------------------------------------------------------------- /tests/syntaxerror.cpp: -------------------------------------------------------------------------------- 1 | void f() 2 | { 3 | catch throw break auto; 4 | nonsense; 5 | } 6 | -------------------------------------------------------------------------------- /tests/recursive_clang++: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # Indirectly invoke icecc again. 4 | 5 | exec icecc clang++ "$@" 6 | -------------------------------------------------------------------------------- /tests/unusedmacro.cpp: -------------------------------------------------------------------------------- 1 | #define FOO bar 2 | #define NUMBER 10 3 | int f() 4 | { 5 | return NUMBER; 6 | } 7 | -------------------------------------------------------------------------------- /compilerwrapper/Makefile.am: -------------------------------------------------------------------------------- 1 | pkglibexec_PROGRAMS = compilerwrapper 2 | compilerwrapper_SOURCES = compilerwrapper.cpp 3 | -------------------------------------------------------------------------------- /tests/unusedmacro1.txt: -------------------------------------------------------------------------------- 1 | unusedmacro.cpp:1:0: warning: macro "FOO" is not used [-Wunused-macros] 2 | #define FOO bar 3 | 4 | -------------------------------------------------------------------------------- /tests/unusedmacro2.txt: -------------------------------------------------------------------------------- 1 | unusedmacro.cpp:1:0: warning: macro "FOO" is not used [-Wunused-macros] 2 | #define FOO bar 3 | ^ 4 | -------------------------------------------------------------------------------- /tests/includes.h: -------------------------------------------------------------------------------- 1 | #ifndef INCLUDES_H 2 | #define INCLUDES_H 3 | 4 | #include 5 | #include 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /tests/unusedmacro3.txt: -------------------------------------------------------------------------------- 1 | unusedmacro.cpp:1: warning: macro "FOO" is not used [-Wunused-macros] 2 | 1 | #define FOO bar 3 | | 4 | -------------------------------------------------------------------------------- /tests/plain: -------------------------------------------------------------------------------- 1 | // C++ feature (so that C++ mode is required) 2 | template< typename T > T func( T ); 3 | 4 | void f() 5 | { 6 | } 7 | -------------------------------------------------------------------------------- /tests/make1.cpp: -------------------------------------------------------------------------------- 1 | #include "make.h" 2 | 3 | void make1() 4 | { 5 | } 6 | 7 | int main() 8 | { 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /tests/messages.cpp: -------------------------------------------------------------------------------- 1 | #include "messages.h" 2 | 3 | void f() 4 | { 5 | int unused; // this should give a warning about being unused 6 | } 7 | -------------------------------------------------------------------------------- /tests/test-setup.sh.in: -------------------------------------------------------------------------------- 1 | # Sourced by test.sh , not to be used directly. 2 | 3 | # Needed for locating our compiler wrapper symlinks. 4 | pkglibexecdir=@PKGLIBEXECDIR@ 5 | -------------------------------------------------------------------------------- /tests/includes.cpp: -------------------------------------------------------------------------------- 1 | #include "includes.h" 2 | #include 3 | 4 | void f() 5 | { 6 | std::cout << std::endl; // use something included only by includes.h 7 | } 8 | -------------------------------------------------------------------------------- /tests/messages.h: -------------------------------------------------------------------------------- 1 | #ifndef MESSAGES_H 2 | #define MESSAGES_H 3 | 4 | void g() 5 | { 6 | int unused; // this should also give a warning about being unused 7 | } 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /tests/testdefine.cpp: -------------------------------------------------------------------------------- 1 | #ifndef ICECREAM_TEST_DEFINE 2 | #error Failed. 3 | #endif 4 | 5 | // this should expand to test() 6 | void ICECREAM_TEST_DEFINE(); 7 | 8 | void test2() 9 | { 10 | test(); 11 | } 12 | -------------------------------------------------------------------------------- /tests/warninginmacro.cpp: -------------------------------------------------------------------------------- 1 | // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80369 2 | 3 | #define MACRO if( arg != arg ) return 1; 4 | 5 | int f( int arg ) 6 | { 7 | MACRO 8 | return 2; 9 | } 10 | -------------------------------------------------------------------------------- /tests/includes-without.cpp: -------------------------------------------------------------------------------- 1 | // #include "includes.h" - will be done using -include includes.h 2 | #include 3 | 4 | void f() 5 | { 6 | std::cout << std::endl; // use something included only by includes.h 7 | } 8 | -------------------------------------------------------------------------------- /suse/iceccd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | icecream daemon 4 | Icecream distributed compilation scheduler. 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/debug.cpp: -------------------------------------------------------------------------------- 1 | struct DebugStruct 2 | { 3 | int debugMember; 4 | }; 5 | 6 | int main() { // first line of main function 7 | static DebugStruct debugObject; 8 | debugObject.debugMember = 1243; 9 | return debugObject.debugMember; 10 | } 11 | -------------------------------------------------------------------------------- /tests/fsanitize.cpp: -------------------------------------------------------------------------------- 1 | void test_fsanitize_function() 2 | { 3 | int* arr = new int[10]; 4 | delete[] arr; 5 | int r = arr[ 0 ]; 6 | (void)r; 7 | } 8 | 9 | int main() 10 | { 11 | test_fsanitize_function(); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /tests/debug/debug2.cpp: -------------------------------------------------------------------------------- 1 | struct DebugStruct 2 | { 3 | int debugMember; 4 | }; 5 | 6 | int main() { // first line of main function 7 | static DebugStruct debugObject; 8 | debugObject.debugMember = 1423; 9 | return debugObject.debugMember; 10 | } 11 | -------------------------------------------------------------------------------- /scheduler/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | sbin_PROGRAMS = icecc-scheduler 3 | icecc_scheduler_SOURCES = compileserver.cpp job.cpp jobstat.cpp scheduler.cpp 4 | icecc_scheduler_LDADD = ../services/libicecc.la 5 | 6 | noinst_HEADERS = \ 7 | compileserver.h \ 8 | job.h \ 9 | jobstat.h \ 10 | scheduler.h 11 | -------------------------------------------------------------------------------- /tests/icerun-test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | dir="$1" 4 | num="$2" 5 | test -z "$dir" -o -z "$num" && exit 1 6 | 7 | touch "$dir"/running$num 8 | if test -z "$ICERUN_TEST_VALGRIND"; then 9 | sleep 0.2 10 | else 11 | sleep 1 12 | fi 13 | rm "$dir"/running$num 14 | touch "$dir"/done$num 15 | exit 0 16 | -------------------------------------------------------------------------------- /suse/icecc-scheduler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | icecream scheduler 4 | Icecream distributed compilation scheduler. 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /suse/logrotate: -------------------------------------------------------------------------------- 1 | /var/log/icecream/iceccd /var/log/icecream/scheduler { 2 | compress 3 | dateext 4 | maxage 30 5 | rotate 99 6 | missingok 7 | notifempty 8 | size +4096k 9 | create 644 icecream icecream 10 | su icecream icecream 11 | sharedscripts 12 | postrotate 13 | /etc/init.d/icecream reload 14 | endscript 15 | } 16 | 17 | -------------------------------------------------------------------------------- /services/icecc.pc.in: -------------------------------------------------------------------------------- 1 | # icecc pkg-config file 2 | 3 | prefix=@prefix@ 4 | exec_prefix=@exec_prefix@ 5 | libdir=@libdir@ 6 | includedir=@includedir@ 7 | 8 | Name: icecc 9 | Description: icecc is a library for connecting to icecc schedulers 10 | Version: @VERSION@ 11 | Requires: 12 | Conflicts: 13 | Libs: -L${libdir} -licecc 14 | Libs.private: @CAPNG_LDADD@ -llzo2 15 | Cflags: -I${includedir} 16 | -------------------------------------------------------------------------------- /tests/valgrind_suppressions: -------------------------------------------------------------------------------- 1 | # The error seems to be about the second argument to the capget syscall, 2 | # but that seems to be actually no problem (at least to me). Either way, 3 | # not icecream's problem. 4 | { 5 | capget 6 | Memcheck:Param 7 | capget(data) 8 | fun:capget 9 | fun:init 10 | fun:capng_get_caps_process 11 | fun:capng_have_capability 12 | fun:main 13 | } 14 | -------------------------------------------------------------------------------- /tests/Makefile.test: -------------------------------------------------------------------------------- 1 | all: maketest 2 | SOURCES = make1.cpp make2.cpp make3.cpp make4.cpp make5.cpp make6.cpp make7.cpp make8.cpp make9.cpp make10.cpp 3 | OBJS = $(patsubst %.cpp,$(OUTDIR)/%.o,$(SOURCES)) 4 | 5 | maketest: $(OUTDIR)/maketest 6 | 7 | $(OUTDIR)/maketest: $(OBJS) 8 | $(CXX) -o $@ $^ 9 | 10 | $(OUTDIR)/%.o: %.cpp 11 | $(CXX) -o $@ -c $^ 12 | 13 | clean: 14 | rm -f $(OBJS) $(OUTDIR)/maketest 15 | -------------------------------------------------------------------------------- /tests/make.h: -------------------------------------------------------------------------------- 1 | #ifndef MAKE_H 2 | #define MAKE_H 3 | 4 | // some includes that'll make the compile take at least a little time 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // This is to prevent scheduler from ignoring stats for the compile job, 12 | // as jobs with too small .o result are ignored in add_job_stats(). 13 | static volatile const int largedata[ 16384 ] = { 1, 2 }; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = README.md 2 | 3 | ACLOCAL_AMFLAGS = -I m4 4 | 5 | SUBDIRS = \ 6 | services \ 7 | daemon \ 8 | client \ 9 | doc \ 10 | suse \ 11 | compilerwrapper \ 12 | scheduler \ 13 | tests 14 | 15 | dist-hook: 16 | ( cd $(top_srcdir) && git log --date=short --pretty="format:@%cd %an <%ae> [%H]%n%n%s%n%n%e%b" | sed -e "s|^\([^@]\)|\t\1|" -e "s|^@||" ) >$(distdir)/ChangeLog 17 | 18 | test: install 19 | $(MAKE) -C tests $@ 20 | test-strict: install 21 | $(MAKE) -C tests $@ 22 | -------------------------------------------------------------------------------- /daemon/Makefile.am: -------------------------------------------------------------------------------- 1 | sbin_PROGRAMS = iceccd 2 | 3 | iceccd_SOURCES = \ 4 | ncpus.c \ 5 | main.cpp \ 6 | serve.cpp \ 7 | workit.cpp \ 8 | environment.cpp \ 9 | load.cpp \ 10 | file_util.cpp 11 | 12 | iceccd_LDADD = \ 13 | ../services/libicecc.la \ 14 | $(LIB_KINFO) \ 15 | $(CAPNG_LDADD) \ 16 | $(ARCHIVE_LDADD) 17 | 18 | AM_CPPFLAGS = \ 19 | -I$(top_srcdir)/services 20 | 21 | noinst_HEADERS = \ 22 | environment.h \ 23 | load.h \ 24 | ncpus.h \ 25 | serve.h \ 26 | workit.h \ 27 | file_util.h 28 | -------------------------------------------------------------------------------- /services/Makefile.am: -------------------------------------------------------------------------------- 1 | lib_LTLIBRARIES = libicecc.la 2 | libicecc_la_SOURCES = job.cpp comm.cpp exitcode.cpp getifaddrs.cpp logging.cpp tempfile.c platform.cpp gcc.cpp 3 | libicecc_la_LIBADD = \ 4 | $(LZO_LDADD) \ 5 | $(CAPNG_LDADD) \ 6 | $(DL_LDADD) 7 | 8 | libicecc_la_CFLAGS = -fPIC -DPIC 9 | libicecc_la_CXXFLAGS = -fPIC -DPIC 10 | 11 | icedir = $(includedir)/icecc 12 | ice_HEADERS = \ 13 | job.h \ 14 | comm.h \ 15 | logging.h 16 | 17 | noinst_HEADERS = \ 18 | exitcode.h \ 19 | getifaddrs.h \ 20 | logging.h \ 21 | tempfile.h \ 22 | platform.h \ 23 | util.h 24 | 25 | pkgconfigdir = $(libdir)/pkgconfig 26 | pkgconfig_DATA = icecc.pc 27 | -------------------------------------------------------------------------------- /.cirrus.yml: -------------------------------------------------------------------------------- 1 | env: 2 | CIRRUS_CLONE_DEPTH: 1 3 | 4 | task: 5 | env: 6 | CFLAGS: -I /usr/local/include 7 | CXXFLAGS: -I/usr/local/include 8 | LDFLAGS: -L/usr/local/lib 9 | freebsd_instance: 10 | matrix: 11 | image: freebsd-12-0-release-amd64 12 | image: freebsd-11-2-release-amd64 13 | install_script: 14 | - sed -i.bak -e 's,pkg+http://pkg.FreeBSD.org/\${ABI}/quarterly,pkg+http://pkg.FreeBSD.org/\${ABI}/latest,' /etc/pkg/FreeBSD.conf 15 | - pkg upgrade -y 16 | - pkg install -y autoconf automake docbook2X gmake libtool lzo2 17 | script: 18 | - ./autogen.sh 19 | - ./configure --prefix=/usr/local 20 | - gmake -j`sysctl -n kern.smp.cpus` 21 | - gmake dist 22 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | if WITH_ICECREAM_MAN 2 | 3 | icecc.1: $(srcdir)/man-icecc.1.xml 4 | $(DOCBOOK2X) $< 5 | 6 | icecc-create-env.1: $(srcdir)/man-icecc-create-env.1.xml 7 | $(DOCBOOK2X) $< 8 | 9 | icecc-scheduler.1: $(srcdir)/man-icecc-scheduler.1.xml 10 | $(DOCBOOK2X) $< 11 | 12 | iceccd.1: $(srcdir)/man-iceccd.1.xml 13 | $(DOCBOOK2X) $< 14 | 15 | icecream.7: $(srcdir)/man-icecream.7.xml 16 | $(DOCBOOK2X) $< 17 | 18 | dist_man_MANS = \ 19 | icecc.1 \ 20 | iceccd.1 \ 21 | icecc-scheduler.1 \ 22 | icecc-create-env.1 \ 23 | icecream.7 24 | 25 | endif 26 | 27 | EXTRA_DIST = \ 28 | man-icecc.1.xml \ 29 | man-iceccd.1.xml \ 30 | man-icecc-scheduler.1.xml \ 31 | man-icecc-create-env.1.xml \ 32 | man-icecream.7.xml 33 | -------------------------------------------------------------------------------- /suse/SuSEfirewall.iceccd: -------------------------------------------------------------------------------- 1 | # Only the variables TCP, UDP, RPC, IP and BROADCAST are allowed. 2 | # More may be supported in the future. 3 | # 4 | # For a more detailed description of the individual variables see 5 | # the comments for FW_SERVICES_*_EXT in /etc/sysconfig/SuSEfirewall2 6 | # 7 | 8 | ## Name: icecream daemon 9 | ## Description: opens socket for the icecream compilation daemon 10 | 11 | # space separated list of allowed TCP ports 12 | TCP="10245" 13 | 14 | # space separated list of allowed UDP ports 15 | UDP="" 16 | 17 | # space separated list of allowed RPC services 18 | RPC="" 19 | 20 | # space separated list of allowed IP protocols 21 | IP="" 22 | 23 | # space separated list of allowed UDP broadcast ports 24 | BROADCAST="" 25 | -------------------------------------------------------------------------------- /suse/SuSEfirewall.scheduler: -------------------------------------------------------------------------------- 1 | # Only the variables TCP, UDP, RPC, IP and BROADCAST are allowed. 2 | # More may be supported in the future. 3 | # 4 | # For a more detailed description of the individual variables see 5 | # the comments for FW_SERVICES_*_EXT in /etc/sysconfig/SuSEfirewall2 6 | # 7 | 8 | ## Name: icecream scheduler 9 | ## Description: Opens ports for the icecream scheduler 10 | 11 | # space separated list of allowed TCP ports 12 | TCP="8765 8766" 13 | 14 | # space separated list of allowed UDP ports 15 | UDP="" 16 | 17 | # space separated list of allowed RPC services 18 | RPC="" 19 | 20 | # space separated list of allowed IP protocols 21 | IP="" 22 | 23 | # space separated list of allowed UDP broadcast ports 24 | BROADCAST="8765" 25 | -------------------------------------------------------------------------------- /suse/update_rpm: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | export PATH=/opt/kde3/bin:$PATH 4 | opwd=$PWD 5 | tdir=`mktemp -d` 6 | cd $tdir || exit 1 7 | svn export svn+ssh://svn.kde.org/home/kde/trunk/icecream 8 | rm icecream/suse/update_rpm 9 | version=`grep INIT_AUTOMAKE icecream/configure.in | cut -d, -f2 | sed -e 's,[^"]*",,; s,".*,,'` 10 | tar -cvj -f $opwd/icecc-$version.tar.bz2 icecream 11 | sed -e "s,Version:.*,Version:$version," icecream/suse/icecream.spec.in > $opwd/icecream.spec 12 | mkdir mans 13 | omans=$PWD/mans 14 | cd icecream/doc 15 | for i in *.docbook; do 16 | output=${i/man-/} 17 | output=${output/.docbook/} 18 | meinproc4 --stylesheet /opt/kde3/share/apps/ksgmltools2/customization/kde-man.xsl $i && mv manpage.troff $omans/$output 19 | done 20 | cd ../.. 21 | tar cvjf $opwd/icecream-manpages.tar.bz2 mans 22 | cd / 23 | rm -rf $tdir 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # out-of-tree build 2 | compile 3 | build/ 4 | # autoconf 5 | m4/libtool.m4 6 | m4/ltoptions.m4 7 | m4/ltsugar.m4 8 | m4/ltversion.m4 9 | m4/lt~obsolete.m4 10 | Makefile.in 11 | aclocal.m4 12 | autom4te.cache 13 | config.guess 14 | config.h.in 15 | config.sub 16 | configure 17 | depcomp 18 | install-sh 19 | ltmain.sh 20 | missing 21 | *.o 22 | *.lo 23 | .deps 24 | .libs 25 | Makefile 26 | stamp-h1 27 | client/icecc 28 | client/icecc-create-env 29 | client/icecc-test-env 30 | client/libclient.a 31 | compilerwrapper/compilerwrapper 32 | config.h 33 | config.log 34 | config.status 35 | daemon/iceccd 36 | libtool 37 | test-driver 38 | minilzo/libminilzo.la 39 | scheduler/icecc-scheduler 40 | services/icecc.pc 41 | services/libicecc.la 42 | suse/icecream.spec 43 | doc/*.1 44 | doc/*.7 45 | doc/index.html 46 | tests/results 47 | tests/test-suite.log 48 | tests/testargs 49 | tests/testargs.log 50 | tests/testargs.trs 51 | tests/test-setup.sh 52 | tests/listing.txt 53 | -------------------------------------------------------------------------------- /services/util.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License along 17 | with this program; if not, write to the Free Software Foundation, Inc., 18 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | */ 20 | 21 | #ifndef UTIL_H 22 | #define UTIL_H 23 | 24 | template 25 | inline T ignore_result(T x __attribute__((unused))) 26 | { 27 | return x; 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /daemon/ncpus.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (C) 2002, 2003 by Martin Pool 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | int dcc_ncpus(int *); 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | -------------------------------------------------------------------------------- /services/gcc.cpp: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | // code based on gcc - Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. 4 | 5 | #include 6 | 7 | /* Heuristic to set a default for GGC_MIN_EXPAND. */ 8 | int ggc_min_expand_heuristic(unsigned int mem_limit) 9 | { 10 | double min_expand = mem_limit; 11 | 12 | /* The heuristic is a percentage equal to 30% + 70%*(RAM/1GB), yielding 13 | a lower bound of 30% and an upper bound of 100% (when RAM >= 1GB). */ 14 | min_expand /= 1024; 15 | min_expand *= 70; 16 | min_expand = std::min(min_expand, 70.); 17 | min_expand += 30; 18 | 19 | return int(min_expand); 20 | } 21 | 22 | /* Heuristic to set a default for GGC_MIN_HEAPSIZE. */ 23 | unsigned int ggc_min_heapsize_heuristic(unsigned int mem_limit) 24 | { 25 | /* The heuristic is RAM/8, with a lower bound of 4M and an upper 26 | bound of 128M (when RAM >= 1GB). */ 27 | mem_limit /= 8; 28 | mem_limit = std::max(mem_limit, 4U); 29 | mem_limit = std::min(mem_limit, 128U); 30 | 31 | return mem_limit * 1024; 32 | } 33 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | NOTE: Although icecream will compile on some non-Linux systems, 2 | it depends critically on Linux' /proc/ structures and will fail 3 | at runtime until somebody figures out how to emulate the "ticks" 4 | form of process accounting in there. 5 | 6 | Required Libraries 7 | ================== 8 | Note: The package name may vary by distro 9 | * libcap-ng-devel 10 | * libarchive-devel 11 | 12 | How to install icecream 13 | ======================= 14 | 15 | cd icecream 16 | ./autogen.sh 17 | ./configure --prefix=/opt/icecream 18 | make 19 | make install 20 | 21 | WARNING: Make sure you specify a prefix, otherwise icecream 22 | might override your gcc installation! You will need to use this 23 | prefix instead of /usr when referring to icecream (for example 24 | when extending the $PATH variable). 25 | 26 | The documentation is maintained in README.md for the time being. 27 | 28 | How to contribute 29 | ================= 30 | 31 | Fork on github.com and send a pull request: 32 | https://github.com/icecc/icecream 33 | 34 | There is a testsuite in the tests/ directory, see the README file there. 35 | 36 | Mailing list: 37 | icecream-users@googlegroups.com (icecream-users+subscribe@googlegroups.com) 38 | -------------------------------------------------------------------------------- /scheduler/scheduler.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2004 Michael Matz 7 | 2004 Stephan Kulow 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #ifndef SCHEDULER_H 25 | #define SCHEDULER_H 26 | 27 | // Values 0 to 3. 28 | #define DEBUG_SCHEDULER 0 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | # By default be lenient and don't fail if some tests are skipped. 2 | # Strict mode will fail in such case. 3 | 4 | test: test-full 5 | test-strict: 6 | $(MAKE) test STRICT=1 7 | 8 | test-prepare: 9 | if test -n "$(VALGRIND)"; then \ 10 | true; \ 11 | elif test -x /sbin/setcap; then \ 12 | sudo /sbin/setcap cap_sys_chroot+ep ${sbindir}/iceccd ; \ 13 | elif test -x /usr/sbin/setcap; then \ 14 | sudo /usr/sbin/setcap cap_sys_chroot+ep ${sbindir}/iceccd ; \ 15 | elif command -v filecap >/dev/null 2>/dev/null; then \ 16 | sudo filecap ${sbindir}/iceccd sys_chroot ; \ 17 | else \ 18 | true ; \ 19 | fi 20 | 21 | test-full: test-prepare 22 | $(MAKE) test-run 23 | 24 | test-run: test-setup.sh 25 | results=`realpath -s ${builddir}/results` && builddir2=`realpath -s ${builddir}` && cd ${srcdir} && /bin/bash test.sh ${prefix} $$results --builddir=$$builddir2 --strict=$(STRICT) --valgrind=$(VALGRIND) 26 | 27 | TESTS = testargs 28 | 29 | AM_CPPFLAGS = -I$(top_srcdir)/client -I$(top_srcdir)/services 30 | testargs_LDADD = ../client/libclient.a ../services/libicecc.la $(LIBRSYNC) 31 | 32 | check_PROGRAMS = testargs 33 | testargs_SOURCES = args.cpp 34 | 35 | check_SCRIPTS = test.sh test-setup.sh 36 | -------------------------------------------------------------------------------- /client/argv.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | * icecc -- A simple distributed compiler system 5 | * 6 | * Copyright (C) 2003, 2004 by the Icecream Authors 7 | * 8 | * based on distcc 9 | * Copyright (C) 2002, 2003 by Martin Pool 10 | * 11 | * This program is free software; you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation; either version 2 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along 22 | * with this program; if not, write to the Free Software Foundation, Inc., 23 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 24 | */ 25 | 26 | #ifdef __cplusplus 27 | extern "C" 28 | { 29 | #endif 30 | 31 | void expandargv (int *argcp, char ***argvp); 32 | void freeargv(char **vector); 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | -------------------------------------------------------------------------------- /services/platform.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2006 Mirko Boehm 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #ifndef PLATFORM_H 24 | #define PLATFORM_H 25 | 26 | #include 27 | 28 | extern const std::string &determine_platform(); 29 | 30 | extern int ggc_min_expand_heuristic(unsigned int mem_limit); 31 | extern unsigned int ggc_min_heapsize_heuristic(unsigned int mem_limit); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /daemon/load.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2004 Stephan Kulow 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #ifndef ICECREAM_LOAD_H 24 | #define ICECREAM_LOAD_H 25 | 26 | #include 27 | 28 | // 'hint' is used to approximate the load, whenever getloadavg() is unavailable. 29 | void fill_stats(unsigned long &myidleload, unsigned long &myniceload, unsigned int &memory_fillgrade, StatsMsg *msg, unsigned int hint); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /services/tempfile.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | * distcc -- A simple distributed compiler system 5 | * 6 | * Copyright (C) 2002, 2003 by Martin Pool 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License along 19 | * with this program; if not, write to the Free Software Foundation, Inc., 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | int dcc_make_tmpnam(const char *prefix, 28 | const char *suffix, 29 | char **name_ret, int relative); 30 | int dcc_make_tmpdir(char **name_ret); 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | -------------------------------------------------------------------------------- /daemon/file_util.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License along 17 | with this program; if not, write to the Free Software Foundation, Inc., 18 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | */ 20 | 21 | #ifndef ICECREAM_FILE_UTIL_H 22 | #define ICECREAM_FILE_UTIL_H 23 | 24 | #include 25 | #include 26 | 27 | std::vector split(const std::string &s, char delim); 28 | std::string get_relative_path(const std::string &to, const std::string &from); 29 | std::string get_canonicalized_path(const std::string &path); 30 | bool mkpath(const std::string &path); 31 | bool rmpath(const char* path); 32 | 33 | #endif 34 | 35 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | TESTLIBTOOLIZE="glibtoolize libtoolize" 3 | 4 | LIBTOOLIZEFOUND="0" 5 | 6 | srcdir=$(dirname $0) 7 | test -z "$srcdir" && srcdir=. 8 | 9 | cd $srcdir 10 | 11 | aclocal --version > /dev/null 2> /dev/null || { 12 | echo "error: aclocal not found" 13 | exit 1 14 | } 15 | automake --version > /dev/null 2> /dev/null || { 16 | echo "error: automake not found" 17 | exit 1 18 | } 19 | 20 | for i in $TESTLIBTOOLIZE; do 21 | if which $i > /dev/null 2>&1; then 22 | LIBTOOLIZE=$i 23 | LIBTOOLIZEFOUND="1" 24 | break 25 | fi 26 | done 27 | 28 | if [ "$LIBTOOLIZEFOUND" = "0" ]; then 29 | echo "$0: need libtoolize tool to build icecream" >&2 30 | exit 1 31 | fi 32 | 33 | if automake --version | grep -F 'automake (GNU automake) 1.5' > /dev/null; then # grep -q is non-portable 34 | echo "warning: you appear to be using automake 1.5" 35 | echo " this version has a bug - GNUmakefile.am dependencies are not generated" 36 | fi 37 | 38 | rm -rf autom4te*.cache 39 | 40 | $LIBTOOLIZE --force --copy || { 41 | echo "error: libtoolize failed" 42 | exit 1 43 | } 44 | aclocal -I m4 $ACLOCAL_FLAGS || { 45 | echo "error: aclocal -I m4 $ACLOCAL_FLAGS failed" 46 | exit 1 47 | } 48 | autoheader || { 49 | echo "error: autoheader failed" 50 | exit 1 51 | } 52 | automake -a -c --foreign || { 53 | echo "warning: automake failed" 54 | } 55 | autoconf || { 56 | echo "error: autoconf failed" 57 | exit 1 58 | } 59 | -------------------------------------------------------------------------------- /daemon/serve.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2004 Stephan Kulow 7 | 2002, 2003 by Martin Pool 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #ifndef ICECREAM_SERVE_H 25 | #define ICECREAM_SERVE_H 26 | 27 | #include 28 | 29 | class CompileJob; 30 | class MsgChannel; 31 | 32 | extern int nice_level; 33 | 34 | int handle_connection(const std::string &basedir, CompileJob *job, 35 | MsgChannel *serv, int & out_fd, 36 | unsigned int mem_limit, uid_t user_uid, gid_t user_gid); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /services/exitcode.cpp: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | * distcc -- A simple distributed compiler system 5 | * 6 | * Copyright (C) 2002, 2003 by Martin Pool 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License along 19 | * with this program; if not, write to the Free Software Foundation, Inc., 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "exitcode.h" 24 | 25 | #include 26 | #include 27 | 28 | /* 29 | Converts exit status from waitpid() to exit status to be returned by the process. 30 | */ 31 | int shell_exit_status(int status) 32 | { 33 | if (WIFEXITED(status)) { 34 | return WEXITSTATUS(status); 35 | } else if (WIFSIGNALED(status)) { 36 | return WTERMSIG(status) + 128; // shell does this 37 | } else { 38 | return -1; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /client/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = icecc 2 | bin_SCRIPTS = icecc-create-env icecc-test-env 3 | 4 | noinst_LIBRARIES = libclient.a 5 | libclient_a_SOURCES = \ 6 | arg.cpp \ 7 | argv.c \ 8 | cpp.cpp \ 9 | local.cpp \ 10 | remote.cpp \ 11 | util.cpp \ 12 | md5.c \ 13 | safeguard.cpp 14 | 15 | icecc_SOURCES = \ 16 | main.cpp 17 | icecc_LDADD = \ 18 | libclient.a \ 19 | ../services/libicecc.la \ 20 | $(LIBRSYNC) 21 | 22 | noinst_HEADERS = \ 23 | argv.h \ 24 | client.h \ 25 | md5.h \ 26 | util.h 27 | AM_CPPFLAGS = \ 28 | -DPLIBDIR=\"$(pkglibexecdir)\" \ 29 | -I$(top_srcdir)/services \ 30 | -I$(top_srcdir)/ 31 | 32 | EXTRA_DIST = icecc-create-env 33 | 34 | install-exec-local: 35 | $(mkinstalldirs) $(DESTDIR)$(bindir) 36 | rm -f $(DESTDIR)$(bindir)/icerun 37 | $(LN_S) $(bindir)/icecc $(DESTDIR)$(bindir)/icerun 38 | $(mkinstalldirs) $(DESTDIR)$(pkglibexecdir) 39 | rm -f $(DESTDIR)$(pkglibexecdir)/icecc-create-env 40 | $(LN_S) $(bindir)/icecc-create-env $(DESTDIR)$(pkglibexecdir)/icecc-create-env 41 | 42 | $(mkinstalldirs) $(DESTDIR)$(pkglibexecdir)/bin 43 | for link in g++ gcc c++ cc $(CLANG_SYMLINK_WRAPPERS); do \ 44 | rm -f $(DESTDIR)$(pkglibexecdir)/bin/$$link ;\ 45 | $(LN_S) $(bindir)/icecc $(DESTDIR)$(pkglibexecdir)/bin/$$link ;\ 46 | done 47 | 48 | uninstall-local: 49 | rm $(DESTDIR)$(bindir)/icerun 50 | rm $(DESTDIR)$(pkglibexecdir)/icecc-create-env 51 | 52 | for link in g++ gcc c++ cc $(CLANG_SYMLINK_WRAPPERS); do \ 53 | rm $(DESTDIR)$(pkglibexecdir)/bin/$$link ;\ 54 | done 55 | -------------------------------------------------------------------------------- /m4/cap-ng.m4: -------------------------------------------------------------------------------- 1 | # libcap-ng.m4 - Checks for the libcap-ng support 2 | # Copyright (c) 2009 Steve Grubb sgrubb@redhat.com 3 | # 4 | AC_DEFUN([ICECC_LIBCAP_NG_PATH], 5 | [ 6 | case $host in 7 | *linux*) capng_auto=no ;; 8 | *) capng_auto=yes ;; 9 | esac 10 | 11 | AC_ARG_WITH(libcap-ng, 12 | [ --with-libcap-ng=[auto/yes/no] Add Libcap-ng support],, 13 | with_libcap_ng=auto) 14 | 15 | # Check for Libcap-ng API 16 | # 17 | # libcap-ng detection 18 | 19 | if test x$with_libcap_ng = xno ; then 20 | have_libcap_ng=no; 21 | else 22 | # Start by checking for header file 23 | AC_CHECK_HEADER(cap-ng.h, capng_headers=yes, capng_headers=no) 24 | 25 | # See if we have libcap-ng library 26 | AC_CHECK_LIB(cap-ng, capng_clear, 27 | CAPNG_LDADD=-lcap-ng,) 28 | 29 | # Check results are usable 30 | if test x$with_libcap_ng = xyes -a x$CAPNG_LDADD = x ; then 31 | AC_MSG_ERROR(libcap-ng support was requested and the library was not found) 32 | fi 33 | if test x$capng_auto = xno -a x$CAPNG_LDADD = x ; then 34 | AC_MSG_ERROR(libcap-ng library was not found) 35 | fi 36 | if test x$CAPNG_LDADD != x -a $capng_headers = no ; then 37 | AC_MSG_ERROR(libcap-ng libraries found but headers are missing) 38 | fi 39 | fi 40 | AC_SUBST(CAPNG_LDADD) 41 | AC_MSG_CHECKING(whether to use libcap-ng) 42 | if test x$CAPNG_LDADD != x ; then 43 | AC_DEFINE(HAVE_LIBCAP_NG,1,[libcap-ng support]) 44 | AC_MSG_RESULT(yes) 45 | else 46 | AC_MSG_RESULT(no) 47 | fi 48 | ]) 49 | -------------------------------------------------------------------------------- /doc/man-icecc.1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | icecc"> 6 | ]> 7 | 8 | 9 | 10 | 11 | Icecream User's Manual 12 | 13 | 14 | Cornelius 15 | Schumacher 16 | 17 | 18 | April 21th, 2005 19 | Icecream 20 | 21 | 22 | 23 | icecc 24 | 1 25 | 26 | 27 | 28 | icecc 29 | Icecream compiler stub 30 | 31 | 32 | 33 | 34 | icecc 35 | compiler 36 | compile options 37 | -o OBJECT 38 | -c SOURCE 39 | 40 | 41 | 42 | 43 | Description 44 | &icecc; is the Icecream compiler stub. It gets called in place of the actual 45 | compiler and transparently routes the compile requests to the Icecream 46 | network. You should not call &icecc; directly, but place the specific compiler 47 | stubs in your path: 48 | export PATH=/usr/lib/icecc/bin:$PATH. 49 | 50 | 51 | 52 | See Also 53 | icecream(7), icecc-scheduler(1), iceccd(1), icemon(1) 54 | 55 | 56 | 57 | Author 58 | Cornelius Schumacher 59 | 60 | 61 | -------------------------------------------------------------------------------- /client/util.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | * distcc -- A simple distributed compiler system 5 | * 6 | * Copyright (C) 2002, 2003 by Martin Pool 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License along 19 | * with this program; if not, write to the Free Software Foundation, Inc., 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include 24 | 25 | class CompileJob; 26 | 27 | /* util.c */ 28 | extern int set_cloexec_flag(int desc, int value); 29 | extern int dcc_ignore_sigpipe(int val); 30 | 31 | extern std::string find_basename(const std::string &sfile); 32 | extern std::string find_prefix(const std::string &basename); 33 | extern void colorify_output(const std::string &s_ccout); 34 | extern bool colorify_wanted(const CompileJob &job); 35 | extern bool compiler_has_color_output(const CompileJob &job); 36 | extern bool output_needs_workaround(const CompileJob &job); 37 | extern bool ignore_unverified(); 38 | extern int resolve_link(const std::string &file, std::string &resolved); 39 | extern std::string get_cwd(); 40 | extern std::string read_command_output(const std::string& command); 41 | 42 | extern bool dcc_unlock(int lock_fd); 43 | extern bool dcc_lock_host(int &lock_fd); 44 | -------------------------------------------------------------------------------- /suse/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = icecream.spec.in \ 2 | init.icecream \ 3 | logrotate \ 4 | SuSEfirewall.iceccd \ 5 | SuSEfirewall.scheduler \ 6 | sysconfig.icecream 7 | 8 | initdir=$(sysconfdir)/init.d 9 | templatesdir=$(localstatedir)/adm/fillup-templates 10 | icecreamcachedir=$(localstatedir)/cache/icecream 11 | logdir=$(localstatedir)/log/icecream 12 | logrotatedir=$(sysconfdir)/logrotate.d 13 | susefirewallservicesdir=$(sysconfdir)/sysconfig/SuSEfirewall2.d/services 14 | 15 | install: init.icecream logrotate SuSEfirewall.iceccd SuSEfirewall.scheduler sysconfig.icecream 16 | if test $(host_vendor) = "suse" -o $(host_vendor) = "ibm" ; then \ 17 | mkdir -p $(DESTDIR)/$(initdir) ;\ 18 | $(INSTALL) -m 755 $(srcdir)/init.icecream $(DESTDIR)$(initdir)/icecream ;\ 19 | ln -sf $(initdir)/icecream $(DESTDIR)$(sbindir)/rcicecream ;\ 20 | mkdir -p $(DESTDIR)$(templatesdir) ;\ 21 | $(INSTALL) -m 644 $(srcdir)/sysconfig.icecream $(DESTDIR)$(templatesdir)/sysconfig.icecream ;\ 22 | mkdir -p $(DESTDIR)$(icecreamcachedir) ;\ 23 | mkdir -p $(DESTDIR)$(logdir) ;\ 24 | $(INSTALL) -m 644 -D $(srcdir)/logrotate $(DESTDIR)$(logrotatedir)/icecream ;\ 25 | mkdir -p $(DESTDIR)$(susefirewallservicesdir) ;\ 26 | $(INSTALL) -m 644 $(srcdir)/SuSEfirewall.iceccd $(DESTDIR)$(susefirewallservicesdir)/iceccd ;\ 27 | $(INSTALL) -m 644 $(srcdir)/SuSEfirewall.scheduler $(DESTDIR)$(susefirewallservicesdir)/icecream-scheduler ;\ 28 | fi 29 | 30 | uninstall: 31 | if test $(host_vendor) = "suse"; then \ 32 | rm $(DESTDIR)$(initdir)/icecream ;\ 33 | rmdir $(DESTDIR)/$(initdir) ;\ 34 | rm $(DESTDIR)$(sbindir)/rcicecream ;\ 35 | rm $(DESTDIR)$(templatesdir)/sysconfig.icecream ;\ 36 | rmdir $(DESTDIR)$(templatesdir) ;\ 37 | rmdir $(DESTDIR)$(icecreamcachedir) ;\ 38 | rmdir $(DESTDIR)$(logdir) ;\ 39 | rm $(DESTDIR)$(logrotatedir)/icecream ;\ 40 | rm $(DESTDIR)$(susefirewallservicesdir)/iceccd ;\ 41 | rm $(DESTDIR)$(susefirewallservicesdir)/icecream-scheduler ;\ 42 | rmdir $(DESTDIR)$(susefirewallservicesdir) ;\ 43 | fi 44 | 45 | -------------------------------------------------------------------------------- /daemon/workit.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2004 Stephan Kulow 7 | 2002, 2003 by Martin Pool 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #ifndef ICECREAM_WORKIT_H 25 | #define ICECREAM_WORKIT_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | class MsgChannel; 34 | class CompileResultMsg; 35 | 36 | // No icecream ;( 37 | class myexception : public std::exception 38 | { 39 | int code; 40 | public: 41 | myexception(int _exitcode) : exception(), code(_exitcode) {} 42 | int exitcode() const { 43 | return code; 44 | } 45 | }; 46 | 47 | namespace JobStatistics 48 | { 49 | enum job_stat_fields { in_compressed, in_uncompressed, out_uncompressed, exit_code, 50 | real_msec, user_msec, sys_msec, sys_pfaults 51 | }; 52 | } 53 | 54 | extern int work_it(CompileJob &j, unsigned int job_stats[], MsgChannel *client, CompileResultMsg &msg, 55 | const std::string &tmp_root, const std::string &build_path, const std::string &file_name, 56 | unsigned long int mem_limit, int client_fd); 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /scheduler/jobstat.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2004 Michael Matz 7 | 2004 Stephan Kulow 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #ifndef JOBSTAT_H 25 | #define JOBSTAT_H 26 | 27 | struct JobStat { 28 | public: 29 | JobStat(); 30 | 31 | unsigned long outputSize() const; 32 | void setOutputSize(unsigned long size); 33 | 34 | unsigned long compileTimeReal() const; 35 | void setCompileTimeReal(unsigned long time); 36 | 37 | unsigned long compileTimeUser() const; 38 | void setCompileTimeUser(unsigned long time); 39 | 40 | unsigned long compileTimeSys() const; 41 | void setCompileTimeSys(unsigned long time); 42 | 43 | unsigned int jobId() const; 44 | void setJobId(unsigned int id); 45 | 46 | JobStat &operator+(const JobStat &st); 47 | 48 | JobStat &operator+=(const JobStat &st); 49 | 50 | JobStat &operator-(const JobStat &st); 51 | 52 | JobStat &operator-=(const JobStat &st); 53 | 54 | JobStat operator/(int d) const; 55 | 56 | JobStat &operator/=(int d); 57 | 58 | private: 59 | unsigned long m_outputSize; // output size (uncompressed) 60 | unsigned long m_compileTimeReal; // in milliseconds 61 | unsigned long m_compileTimeUser; 62 | unsigned long m_compileTimeSys; 63 | unsigned int m_jobId; 64 | }; 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /services/exitcode.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | * distcc -- A simple distributed compiler system 5 | * 6 | * Copyright (C) 2002, 2003 by Martin Pool 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License along 19 | * with this program; if not, write to the Free Software Foundation, Inc., 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #ifndef DISTCC_EXITCODE_H 24 | #define DISTCC_EXITCODE_H 25 | 26 | /** 27 | * @file 28 | * 29 | * Common exit codes. 30 | **/ 31 | 32 | /** 33 | * Common exit codes for both client and server. 34 | * 35 | * These need to be in [1,255] so that they can be used as exit() 36 | * codes. 37 | **/ 38 | enum dcc_exitcode { 39 | EXIT_DISTCC_FAILED = 100, /**< General failure */ 40 | EXIT_BAD_ARGUMENTS = 101, 41 | EXIT_BIND_FAILED = 102, 42 | EXIT_CONNECT_FAILED = 103, 43 | EXIT_COMPILER_CRASHED = 104, 44 | EXIT_OUT_OF_MEMORY = 105, 45 | EXIT_BAD_HOSTSPEC = 106, 46 | EXIT_IO_ERROR = 107, 47 | EXIT_TRUNCATED = 108, 48 | EXIT_PROTOCOL_ERROR = 109, 49 | EXIT_COMPILER_MISSING = 110, /**< Compiler executable not found */ 50 | EXIT_RECURSION = 111, /**< icecc called itself */ 51 | EXIT_SETUID_FAILED = 112, /**< Failed to discard privileges */ 52 | EXIT_ACCESS_DENIED = 113, /**< Network access denied */ 53 | EXIT_BUSY = 114, /**< In use by another process. */ 54 | EXIT_NO_SUCH_FILE = 115, 55 | EXIT_NO_HOSTS = 116, 56 | EXIT_GONE = 117, /**< No longer relevant */ 57 | EXIT_CLIENT_KILLED = 118, 58 | EXIT_TEST_SOCKET_ERROR = 119 59 | }; 60 | 61 | extern int shell_exit_status(int status); 62 | 63 | #endif /* _DISTCC_EXITCODE_H */ 64 | -------------------------------------------------------------------------------- /suse/sysconfig.icecream: -------------------------------------------------------------------------------- 1 | # 2 | ## Type: integer(0:19) 3 | ## Path: Applications/icecream 4 | ## Description: Icecream settings 5 | ## ServiceRestart: icecream 6 | ## Default: 5 7 | # 8 | # Nice level of running compilers 9 | # 10 | ICECREAM_NICE_LEVEL="5" 11 | 12 | # 13 | ## Type: string 14 | ## Path: Applications/icecream 15 | ## Default: /var/log/icecream/iceccd 16 | # 17 | # icecream daemon log file 18 | # 19 | ICECREAM_LOG_FILE="/var/log/icecream/iceccd" 20 | 21 | # 22 | ## Type: string 23 | ## Path: Applications/icecream 24 | ## Default: no 25 | # 26 | # Start also the scheduler? 27 | # 28 | ICECREAM_RUN_SCHEDULER="no" 29 | 30 | # 31 | ## Type: string 32 | ## Path: Applications/icecream 33 | ## Default: /var/log/icecream/scheduler 34 | # 35 | # icecream scheduler log file 36 | # 37 | ICECREAM_SCHEDULER_LOG_FILE="/var/log/icecream/scheduler" 38 | 39 | # 40 | ## Type: string 41 | ## Path: Applications/icecream 42 | ## Default: "" 43 | # 44 | # Identification for the network the scheduler and daemon run on. 45 | # You can have several distinct icecream networks in the same LAN 46 | # for whatever reason. 47 | # 48 | ICECREAM_NETNAME="" 49 | 50 | # 51 | ## Type: string 52 | ## Path: Applications/icecream 53 | ## Default: "" 54 | # 55 | # If the daemon can't find the scheduler by broadcast (e.g. because 56 | # of a firewall) you can specify it. 57 | # 58 | ICECREAM_SCHEDULER_HOST="" 59 | 60 | # 61 | ## Type: integer 62 | ## Path: Applications/icecream 63 | ## Default: "" 64 | # 65 | # You can overwrite here the number of jobs to run in parallel. Per 66 | # default this depends on the number of (virtual) CPUs installed. 67 | # 68 | # Note: a value of "0" is actually interpreted as "1", however it 69 | # also sets ICECREAM_ALLOW_REMOTE="no". 70 | # 71 | ICECREAM_MAX_JOBS="" 72 | 73 | # 74 | ## Type: yesno 75 | ## Path: Applications/icecream 76 | ## Default: "yes" 77 | # 78 | # Specifies whether jobs submitted by other nodes are allowed to run on 79 | # this one. 80 | # 81 | ICECREAM_ALLOW_REMOTE="yes" 82 | 83 | # 84 | ## Type: string 85 | ## Path: Applications/icecream 86 | ## Default: "/var/cache/icecream" 87 | # 88 | # This is the directory where the icecream daemon stores the environments 89 | # it compiles in. In a big network this can grow quite a bit, so use some 90 | # path if your /tmp is small - but the user icecream has to write to it. 91 | # 92 | ICECREAM_BASEDIR="/var/cache/icecream" 93 | -------------------------------------------------------------------------------- /tests/args.cpp: -------------------------------------------------------------------------------- 1 | #include "client.h" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | static const char *ICECC_COLOR_DIAGNOSTICS = NULL; 9 | void backup_icecc_color_diagnostics() { 10 | ICECC_COLOR_DIAGNOSTICS = getenv("ICECC_COLOR_DIAGNOSTICS"); 11 | setenv("ICECC_COLOR_DIAGNOSTICS", "0", 1); 12 | } 13 | 14 | void restore_icecc_color_diagnostics() { 15 | if (ICECC_COLOR_DIAGNOSTICS) 16 | setenv("ICECC_COLOR_DIAGNOSTICS", ICECC_COLOR_DIAGNOSTICS, 1); 17 | else 18 | unsetenv("ICECC_COLOR_DIAGNOSTICS"); 19 | } 20 | 21 | void test_run(const string &prefix, const char * const *argv, bool icerun, const string& expected) { 22 | list extrafiles; 23 | CompileJob job; 24 | bool local = analyse_argv(argv, job, icerun, &extrafiles); 25 | std::stringstream str; 26 | str << "local:" << local; 27 | str << " language:" << job.language(); 28 | str << " compiler:" << job.compilerName(); 29 | str << " local:" << concat_args(job.localFlags()); 30 | str << " remote:" << concat_args(job.remoteFlags()); 31 | str << " rest:" << concat_args(job.restFlags()); 32 | if (str.str() != expected) { 33 | cerr << prefix << " failed\n"; 34 | cerr << " got: \"" << str.str() << "\"\nexpected: \"" << expected << "\"\n"; 35 | exit(1); 36 | } 37 | } 38 | 39 | static void test_1() { 40 | const char * argv[] = { "gcc", "-D", "TEST=1", "-c", "main.cpp", "-o", "main.o", 0 }; 41 | backup_icecc_color_diagnostics(); 42 | test_run("1", argv, false, "local:0 language:C++ compiler:gcc local:'-D, TEST=1' remote:'-c' rest:''"); 43 | restore_icecc_color_diagnostics(); 44 | } 45 | 46 | static void test_2() { 47 | const char * argv[] = { "gcc", "-DTEST=1", "-c", "main.cpp", "-o", "main.o", 0 }; 48 | backup_icecc_color_diagnostics(); 49 | test_run("2", argv, false, "local:0 language:C++ compiler:gcc local:'-DTEST=1' remote:'-c' rest:''"); 50 | restore_icecc_color_diagnostics(); 51 | } 52 | 53 | static void test_3() { 54 | const char * argv[] = { "clang", "-D", "TEST1=1", "-I.", "-c", "make1.cpp", "-o", "make.o", 0}; 55 | backup_icecc_color_diagnostics(); 56 | test_run("3", argv, false, "local:0 language:C++ compiler:clang local:'-D, TEST1=1, -I.' remote:'-c' rest:''"); 57 | restore_icecc_color_diagnostics(); 58 | } 59 | 60 | int main() { 61 | test_1(); 62 | test_2(); 63 | test_3(); 64 | exit(0); 65 | } 66 | -------------------------------------------------------------------------------- /services/platform.cpp: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2006 Mirko Boehm 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | extern "C" { 24 | #include 25 | } 26 | 27 | #include "logging.h" 28 | #include "platform.h" 29 | 30 | std::string determine_platform_once() 31 | { 32 | using namespace std; 33 | string platform; 34 | 35 | struct utsname uname_buf; 36 | 37 | if (uname(&uname_buf)) { 38 | log_perror("uname call failed"); 39 | throw("determine_platform: cannot determine OS version and machine architecture"); 40 | // return platform; 41 | } 42 | 43 | string os = uname_buf.sysname; 44 | 45 | if (os == "Darwin") { 46 | const std::string release = uname_buf.release; 47 | const string::size_type pos = release.find('.'); 48 | 49 | if (pos == string::npos) { 50 | throw(std::string("determine_platform: Cannot determine Darwin release from release string \"") + release + "\""); 51 | } 52 | 53 | os += release.substr(0, pos); 54 | } 55 | 56 | if (os != "Linux") { 57 | platform = os + '_' + uname_buf.machine; 58 | } else { // Linux 59 | platform = uname_buf.machine; 60 | } 61 | 62 | while (true) { 63 | string::size_type pos = platform.find(" "); 64 | 65 | if (pos == string::npos) { 66 | break; 67 | } 68 | 69 | platform.erase(pos, 1); 70 | } 71 | 72 | return platform; 73 | } 74 | 75 | const std::string &determine_platform() 76 | { 77 | const static std::string platform(determine_platform_once()); 78 | return platform; 79 | } 80 | -------------------------------------------------------------------------------- /client/safeguard.cpp: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | * distcc -- A simple distributed compiler system 5 | * 6 | * Copyright (C) 2002, 2003 by Martin Pool 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License along 19 | * with this program; if not, write to the Free Software Foundation, Inc., 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "client.h" 24 | 25 | #include "logging.h" 26 | 27 | using namespace std; 28 | 29 | /** 30 | * @file 31 | * @brief Protect against unbounded recursion. 32 | * 33 | * It would be fairly easy for somebody to get confused in masquerade mode and 34 | * try to get distcc to invoke itself in a loop. We can't always work out the 35 | * right thing to do but we can at least flag an error. 36 | * 37 | * This environment variable is set to guard against distcc accidentally 38 | * recursively invoking itself, thinking it's the real compiler. 39 | **/ 40 | 41 | static const char dcc_safeguard_name[] = "_ICECC_SAFEGUARD"; 42 | static int dcc_safeguard_level; 43 | 44 | int dcc_recursion_safeguard(void) 45 | { 46 | const char *env = getenv(dcc_safeguard_name); 47 | 48 | if (env) { 49 | //trace() << "safeguard: " << env << endl; 50 | if (!(dcc_safeguard_level = atoi(env))) { 51 | dcc_safeguard_level = 1; 52 | } 53 | } else { 54 | dcc_safeguard_level = 0; 55 | } 56 | 57 | //trace() << "safeguard level=" << dcc_safeguard_level << endl; 58 | 59 | return dcc_safeguard_level; 60 | } 61 | 62 | 63 | void dcc_increment_safeguard(SafeguardStep step) 64 | { 65 | char value[2] = { (char)(dcc_safeguard_level + step + '0'), '\0' }; 66 | //trace() << "setting safeguard: " << dcc_safeguard_set << endl; 67 | if (setenv(dcc_safeguard_name, value, 1) == -1) { 68 | log_error() << "putenv failed" << endl; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /doc/man-icecc-create-env.1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Clang"> 6 | GCC"> 7 | icecc-create-env"> 8 | ]> 9 | 10 | 11 | 12 | 13 | Icecream User's Manual 14 | 15 | 16 | Pino 17 | Toscano 18 | 19 | 20 | June 5rd, 2013 21 | Icecream 22 | 23 | 24 | 25 | icecc-create-env 26 | 1 27 | 28 | 29 | 30 | icecc-create-env 31 | Create an Icrecream environment tarball 32 | 33 | 34 | 35 | 36 | icecc-create-env 37 | compiler-binary 38 | --addfile file 39 | 40 | 41 | 42 | 43 | Description 44 | &icecc-create-env; is an Icecream helper that creates a new .tar.gz 45 | archive with all the files (compiler, tools and libraries) needed to setup a 46 | build environment. 47 | The resulting archive has a random file name like 48 | ddaea39ca1a7c88522b185eca04da2d8.tar.gz, which can 49 | then be renamed. See icecream(7) for more information on using the environment 50 | tarballs. 51 | Note that in the usual case it is not necessary to invoke icecc-create-env manually, as it will be 52 | called automatically for the native compiler used whenever necessary. 53 | 54 | 55 | 56 | Options 57 | 58 | 59 | 60 | 61 | 62 | file 63 | Add file to the environment 64 | archive; can be specified multiple times. 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | See Also 74 | icecream(7), icecc-scheduler(1), iceccd(1) 75 | 76 | 77 | 78 | Author 79 | Pino Toscano 80 | 81 | 82 | -------------------------------------------------------------------------------- /client/md5.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | Copyright (C) 1999 Aladdin Enterprises. All rights reserved. 5 | 6 | This software is provided 'as-is', without any express or implied 7 | warranty. In no event will the authors be held liable for any damages 8 | arising from the use of this software. 9 | 10 | Permission is granted to anyone to use this software for any purpose, 11 | including commercial applications, and to alter it and redistribute it 12 | freely, subject to the following restrictions: 13 | 14 | 1. The origin of this software must not be misrepresented; you must not 15 | claim that you wrote the original software. If you use this software 16 | in a product, an acknowledgment in the product documentation would be 17 | appreciated but is not required. 18 | 2. Altered source versions must be plainly marked as such, and must not be 19 | misrepresented as being the original software. 20 | 3. This notice may not be removed or altered from any source distribution. 21 | 22 | L. Peter Deutsch 23 | ghost@aladdin.com 24 | 25 | */ 26 | /* 27 | Independent implementation of MD5 (RFC 1321). 28 | 29 | This code implements the MD5 Algorithm defined in RFC 1321. 30 | It is derived directly from the text of the RFC and not from the 31 | reference implementation. 32 | 33 | The original and principal author of md5.h is L. Peter Deutsch 34 | . Other authors are noted in the change history 35 | that follows (in reverse chronological order): 36 | 37 | 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 38 | 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); 39 | added conditionalization for C++ compilation from Martin 40 | Purschke . 41 | 1999-05-03 lpd Original version. 42 | */ 43 | 44 | #ifndef md5_INCLUDED 45 | # define md5_INCLUDED 46 | 47 | typedef unsigned char md5_byte_t; /* 8-bit byte */ 48 | typedef unsigned int md5_word_t; /* 32-bit word */ 49 | 50 | /* Define the state of the MD5 Algorithm. */ 51 | typedef struct md5_state_s { 52 | md5_word_t count[2]; /* message length in bits, lsw first */ 53 | md5_word_t abcd[4]; /* digest buffer */ 54 | md5_byte_t buf[64]; /* accumulate block */ 55 | } md5_state_t; 56 | 57 | #ifdef __cplusplus 58 | extern "C" 59 | { 60 | #endif 61 | 62 | /* Initialize the algorithm. */ 63 | void md5_init(md5_state_t *pms); 64 | 65 | /* Append a string to the message. */ 66 | void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); 67 | 68 | /* Finish the message and return the digest. */ 69 | void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); 70 | 71 | #ifdef __cplusplus 72 | } /* end extern "C" */ 73 | #endif 74 | 75 | #endif /* md5_INCLUDED */ 76 | -------------------------------------------------------------------------------- /daemon/environment.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2004 Stephan Kulow 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #ifndef ICECREAM_ENVIRONMENT_H 24 | #define ICECREAM_ENVIRONMENT_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | class MsgChannel; 32 | extern bool cleanup_cache(const std::string &basedir, uid_t user_uid, gid_t user_gid); 33 | extern int start_create_env(const std::string &basedir, 34 | uid_t user_uid, gid_t user_gid, 35 | const std::string &compiler, const std::list &extrafiles); 36 | extern size_t finish_create_env(int pipe, const std::string &basedir, std::string &native_environment); 37 | Environments available_environmnents(const std::string &basename); 38 | extern void save_compiler_timestamps(time_t &gcc_bin_timestamp, time_t &gpp_bin_timestamp, time_t &clang_bin_timestamp); 39 | bool compilers_uptodate(time_t gcc_bin_timestamp, time_t gpp_bin_timestamp, time_t clang_bin_timestamp); 40 | extern pid_t start_install_environment(const std::string &basename, 41 | const std::string &target, 42 | const std::string &name, 43 | MsgChannel *c, int& pipe_to_child, 44 | FileChunkMsg*& fmsg, 45 | uid_t user_uid, gid_t user_gid, int extract_priority); 46 | extern size_t finalize_install_environment(const std::string &basename, const std::string &target, 47 | pid_t pid, uid_t user_uid, gid_t user_gid); 48 | extern size_t remove_environment(const std::string &basedir, const std::string &env); 49 | extern size_t remove_native_environment(const std::string &env); 50 | extern void chdir_to_environment(MsgChannel *c, const std::string &dirname, uid_t user_uid, gid_t user_gid); 51 | extern bool verify_env(MsgChannel *c, const std::string &basedir, const std::string &target, 52 | const std::string &env, uid_t user_uid, gid_t user_gid); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /scheduler/jobstat.cpp: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2004 Michael Matz 7 | 2004 Stephan Kulow 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #include "jobstat.h" 25 | 26 | JobStat::JobStat() 27 | : m_outputSize(0) 28 | , m_compileTimeReal(0) 29 | , m_compileTimeUser(0) 30 | , m_compileTimeSys(0) 31 | , m_jobId(0) 32 | { 33 | } 34 | 35 | unsigned long JobStat::outputSize() const 36 | { 37 | return m_outputSize; 38 | } 39 | 40 | void JobStat::setOutputSize(unsigned long size) 41 | { 42 | m_outputSize = size; 43 | } 44 | 45 | unsigned long JobStat::compileTimeReal() const 46 | { 47 | return m_compileTimeReal; 48 | } 49 | 50 | void JobStat::setCompileTimeReal(unsigned long time) 51 | { 52 | m_compileTimeReal = time; 53 | } 54 | 55 | unsigned long JobStat::compileTimeUser() const 56 | { 57 | return m_compileTimeUser; 58 | } 59 | 60 | void JobStat::setCompileTimeUser(unsigned long time) 61 | { 62 | m_compileTimeUser = time; 63 | } 64 | 65 | unsigned long JobStat::compileTimeSys() const 66 | { 67 | return m_compileTimeSys; 68 | } 69 | 70 | void JobStat::setCompileTimeSys(unsigned long time) 71 | { 72 | m_compileTimeSys = time; 73 | } 74 | 75 | unsigned int JobStat::jobId() const 76 | { 77 | return m_jobId; 78 | } 79 | 80 | void JobStat::setJobId(unsigned int id) 81 | { 82 | m_jobId = id; 83 | } 84 | 85 | JobStat &JobStat::operator+(const JobStat &st) 86 | { 87 | m_outputSize += st.m_outputSize; 88 | m_compileTimeReal += st.m_compileTimeReal; 89 | m_compileTimeUser += st.m_compileTimeUser; 90 | m_compileTimeSys += st.m_compileTimeSys; 91 | m_jobId = 0; 92 | return *this; 93 | } 94 | 95 | JobStat &JobStat::operator+=(const JobStat &st) 96 | { 97 | return *this + st; 98 | } 99 | 100 | JobStat &JobStat::operator-(const JobStat &st) 101 | { 102 | m_outputSize -= st.m_outputSize; 103 | m_compileTimeReal -= st.m_compileTimeReal; 104 | m_compileTimeUser -= st.m_compileTimeUser; 105 | m_compileTimeSys -= st.m_compileTimeSys; 106 | m_jobId = 0; 107 | return *this; 108 | } 109 | 110 | JobStat &JobStat::operator-=(const JobStat &st) 111 | { 112 | return *this - st; 113 | } 114 | 115 | JobStat JobStat::operator/(int d) const 116 | { 117 | JobStat r = *this; 118 | r /= d; 119 | return r; 120 | } 121 | 122 | JobStat &JobStat::operator/=(int d) 123 | { 124 | m_outputSize /= d; 125 | m_compileTimeReal /= d; 126 | m_compileTimeUser /= d; 127 | m_compileTimeSys /= d; 128 | m_jobId = 0; 129 | return *this; 130 | } 131 | -------------------------------------------------------------------------------- /services/job.cpp: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2004 Stephan Kulow 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "job.h" 24 | #include "logging.h" 25 | #include "exitcode.h" 26 | #include "platform.h" 27 | #include 28 | 29 | using namespace std; 30 | 31 | list CompileJob::flags(Argument_Type argumentType) const 32 | { 33 | list args; 34 | 35 | for (ArgumentsList::const_iterator it = m_flags.begin(); it != m_flags.end(); ++it) { 36 | if (it->second == argumentType) { 37 | args.push_back(it->first); 38 | } 39 | } 40 | 41 | return args; 42 | } 43 | 44 | list CompileJob::localFlags() const 45 | { 46 | return flags(Arg_Local); 47 | } 48 | 49 | list CompileJob::remoteFlags() const 50 | { 51 | return flags(Arg_Remote); 52 | } 53 | 54 | list CompileJob::restFlags() const 55 | { 56 | return flags(Arg_Rest); 57 | } 58 | 59 | list CompileJob::allFlags() const 60 | { 61 | list args; 62 | 63 | for (ArgumentsList::const_iterator it = m_flags.begin(); it != m_flags.end(); ++it) { 64 | args.push_back(it->first); 65 | } 66 | 67 | return args; 68 | } 69 | 70 | void CompileJob::setTargetPlatform() 71 | { 72 | m_target_platform = determine_platform(); 73 | } 74 | 75 | unsigned int CompileJob::argumentFlags() const 76 | { 77 | unsigned int result = Flag_None; 78 | 79 | for (ArgumentsList::const_iterator it = m_flags.begin(); it != m_flags.end(); ++it) { 80 | const string arg = it->first; 81 | 82 | if (arg.at(0) == '-') { 83 | if (arg.length() == 1) { 84 | continue; 85 | } 86 | 87 | if (arg.at(1) == 'g') { 88 | if (arg.length() > 2 && arg.at(2) == '3') { 89 | result &= ~Flag_g; 90 | result |= Flag_g3; 91 | } else { 92 | result &= ~Flag_g3; 93 | result |= Flag_g; 94 | } 95 | } else if (arg.at(1) == 'O') { 96 | result &= ~(Flag_O | Flag_O2 | Flag_Ol2); 97 | 98 | if (arg.length() == 2) { 99 | result |= Flag_O; 100 | } else { 101 | assert(arg.length() > 2); 102 | 103 | if (arg.at(2) == '2') { 104 | result |= Flag_O2; 105 | } else if (arg.at(2) == '1') { 106 | result |= Flag_O; 107 | } else if (arg.at(2) != '0') { 108 | result |= Flag_Ol2; 109 | } 110 | } 111 | } 112 | } 113 | } 114 | 115 | return result; 116 | } 117 | -------------------------------------------------------------------------------- /client/client.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of icecc. 5 | 6 | Copyright (C) 2002, 2003 by Martin Pool 7 | 2004 Stephan Kulow 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #ifndef _CLIENT_H_ 25 | #define _CLIENT_H_ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | #include "exitcode.h" 36 | #include "logging.h" 37 | #include "util.h" 38 | 39 | class MsgChannel; 40 | 41 | extern std::string remote_daemon; 42 | 43 | /* in remote.cpp */ 44 | extern std::string get_absfilename(const std::string &_file); 45 | 46 | /* In arg.cpp. */ 47 | extern bool analyse_argv(const char * const *argv, CompileJob &job, bool icerun, 48 | std::list *extrafiles); 49 | 50 | /* In cpp.cpp. */ 51 | extern pid_t call_cpp(CompileJob &job, int fdwrite, int fdread = -1); 52 | 53 | /* In local.cpp. */ 54 | extern int build_local(CompileJob &job, MsgChannel *daemon, struct rusage *usage = 0); 55 | extern std::string find_compiler(const CompileJob &job); 56 | extern bool compiler_is_clang(const CompileJob &job); 57 | extern bool compiler_only_rewrite_includes(const CompileJob &job); 58 | extern std::string compiler_path_lookup(const std::string &compiler); 59 | extern std::string clang_get_default_target(const CompileJob &job); 60 | 61 | /* In remote.cpp - permill is the probability it will be compiled three times */ 62 | extern int build_remote(CompileJob &job, MsgChannel *scheduler, const Environments &envs, int permill); 63 | 64 | /* safeguard.cpp */ 65 | // We allow several recursions if icerun is involved, just in case icerun is e.g. used to invoke a script 66 | // that calls make that invokes compilations. In this case, it is allowed to have icerun->icecc->compiler. 67 | // However, icecc->icecc recursion is a problem, so just one recursion exceeds the limit. 68 | // Also note that if the total number of such recursive invocations exceedds the number of allowed local 69 | // jobs, iceccd will not assign another local job and the whole build will get stuck. 70 | static const int SafeguardMaxLevel = 2; 71 | enum SafeguardStep 72 | { 73 | SafeguardStepCompiler = SafeguardMaxLevel, 74 | SafeguardStepCustom = 1 75 | }; 76 | extern void dcc_increment_safeguard(SafeguardStep step); 77 | extern int dcc_recursion_safeguard(void); 78 | 79 | extern Environments parse_icecc_version(const std::string &target, const std::string &prefix); 80 | 81 | class client_error : public std::runtime_error 82 | { 83 | public: 84 | client_error(int code, const std::string& what) 85 | : std::runtime_error(what) 86 | , errorCode(code) 87 | {} 88 | 89 | const int errorCode; 90 | }; 91 | 92 | class remote_error : public client_error 93 | { 94 | public: 95 | remote_error(int code, const std::string& what) 96 | : client_error(code, what) 97 | {} 98 | }; 99 | 100 | 101 | #endif 102 | -------------------------------------------------------------------------------- /services/getifaddrs.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* ifaddrs.h -- declarations for getting network interface addresses 4 | Copyright (C) 2002 Free Software Foundation, Inc. 5 | This file is part of the GNU C Library. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | /** 23 | * 02-12-26, tim@tjansen.de: added kde_ prefix, fallback-code, 24 | * removed glibs dependencies 25 | */ 26 | 27 | #include "config.h" 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | #ifndef IFF_POINTOPOINT 35 | # define IFF_POINTOPOINT 0x10 36 | #endif 37 | 38 | #ifdef HAVE_IFADDRS_H 39 | #include 40 | 41 | #define kde_getifaddrs(a) getifaddrs(a) 42 | #define kde_freeifaddrs(a) freeifaddrs(a) 43 | #define kde_ifaddrs ifaddrs 44 | 45 | #else 46 | 47 | #ifndef GETIFADDRS_H 48 | #define GETIFADDRS_H 49 | 50 | 51 | #include 52 | 53 | /* The `getifaddrs' function generates a linked list of these structures. 54 | Each element of the list describes one network interface. */ 55 | struct kde_ifaddrs { 56 | struct kde_ifaddrs *ifa_next; /* Pointer to the next structure. */ 57 | 58 | char *ifa_name; /* Name of this network interface. */ 59 | unsigned int ifa_flags; /* Flags as from SIOCGIFFLAGS ioctl. */ 60 | 61 | struct sockaddr *ifa_addr; /* Network address of this interface. */ 62 | struct sockaddr *ifa_netmask; /* Netmask of this interface. */ 63 | 64 | union { 65 | /* At most one of the following two is valid. If the IFF_BROADCAST 66 | bit is set in `ifa_flags', then `ifa_broadaddr' is valid. If the 67 | IFF_POINTOPOINT bit is set, then `ifa_dstaddr' is valid. 68 | It is never the case that both these bits are set at once. */ 69 | struct sockaddr *ifu_broadaddr; /* Broadcast address of this interface. */ 70 | struct sockaddr *ifu_dstaddr; /* Point-to-point destination address. */ 71 | } ifa_ifu; 72 | 73 | /* These very same macros are defined by for `struct ifaddr'. 74 | So if they are defined already, the existing definitions will be fine. */ 75 | # ifndef ifa_broadaddr 76 | # define ifa_broadaddr ifa_ifu.ifu_broadaddr 77 | # endif 78 | # ifndef ifa_dstaddr 79 | # define ifa_dstaddr ifa_ifu.ifu_dstaddr 80 | # endif 81 | 82 | void *ifa_data; /* Address-specific data (may be unused). */ 83 | }; 84 | 85 | 86 | /* Create a linked list of `struct kde_ifaddrs' structures, one for each 87 | network interface on the host machine. If successful, store the 88 | list in *IFAP and return 0. On errors, return -1 and set `errno'. 89 | 90 | The storage returned in *IFAP is allocated dynamically and can 91 | only be properly freed by passing it to `freeifaddrs'. */ 92 | extern int kde_getifaddrs(struct kde_ifaddrs **__ifap); 93 | 94 | /* Reclaim the storage allocated by a previous `getifaddrs' call. */ 95 | extern void kde_freeifaddrs(struct kde_ifaddrs *__ifa); 96 | 97 | #endif 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /doc/man-icecc-scheduler.1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | icecc-scheduler"> 6 | ]> 7 | 8 | 9 | 10 | 11 | Icecream User's Manual 12 | 13 | 14 | Cornelius 15 | Schumacher 16 | 17 | 18 | April 21th, 2005 19 | Icecream 20 | 21 | 22 | 23 | icecc-scheduler 24 | 1 25 | 26 | 27 | 28 | icecc-scheduler 29 | Icecream scheduler 30 | 31 | 32 | 33 | 34 | icecc-scheduler 35 | -d 36 | -r 37 | -l log-file 38 | -n net-name 39 | -p port 40 | -u user 41 | -vvv 42 | 43 | 44 | 45 | 46 | Description 47 | The Icecream scheduler is the central instance of an Icecream compile 48 | network. It distributes the compile jobs and provides the data for the 49 | monitors. 50 | 51 | 52 | 53 | Options 54 | 55 | 56 | 57 | 58 | , 59 | Detach daemon from shell. 60 | 61 | 62 | 63 | , 64 | Client connections are not disconnected from the scheduler even if there is a better scheduler available. 65 | 66 | 67 | 68 | , 69 | Print help message and exit. 70 | 71 | 72 | 73 | , 74 | log-file 75 | Name of file where log output is written to. 76 | 77 | 78 | 79 | , 80 | net-name 81 | The name of the Icecream network the scheduler 82 | controls. 83 | 84 | 85 | 86 | , 87 | port 88 | IP port the scheduler uses. 89 | 90 | 91 | 92 | , 93 | user 94 | Specify the system user used by the daemon, which must be 95 | different than root. If not specified, the daemon defaults 96 | to the icecc system user if available, or nobody 97 | if not. 98 | 99 | 100 | 101 | , , 102 | Control verbosity of daemon. The more v the more 103 | verbose. 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | See Also 113 | icecream(7), iceccd(1), icemon(1) 114 | 115 | 116 | 117 | Author 118 | Cornelius Schumacher 119 | 120 | 121 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | script: 4 | - ./autogen.sh 5 | - ./configure --prefix=$PWD/_inst 6 | - make -s -j $(getconf _NPROCESSORS_ONLN) 7 | - | 8 | if test "$TRAVIS_OS_NAME" = "linux"; then 9 | strict="-strict" 10 | if test -n "$VALGRIND"; then 11 | # See tests/README. 12 | sudo /sbin/setcap cap_sys_chroot+ep /usr/lib/valgrind/memcheck-amd64-linux 13 | fi 14 | make -s test${strict} VALGRIND=$VALGRIND TESTCC=/usr/bin/gcc TESTCXX=/usr/bin/g++ 15 | if test $? -ne 0; then 16 | exit 1 17 | fi 18 | # Only the clang(-3.4) package provides /usr/bin/clang, but this path is hardcoded in icecream. 19 | # So for now make icecream use the newer version provided by Travis. 20 | sudo ln -s `which clang` /usr/bin/clang 21 | sudo ln -s `which clang++` /usr/bin/clang++ 22 | make -s test${strict} VALGRIND=$VALGRIND TESTCC=/usr/bin/clang TESTCXX=/usr/bin/clang++ 23 | if test $? -ne 0; then 24 | exit 1 25 | fi 26 | elif test "$TRAVIS_OS_NAME" = "osx"; then 27 | if test -n "$STRICTTESTS"; then 28 | strict="-strict" 29 | fi 30 | make -s test${strict} TESTCC=clang TESTCXX=clang++ 31 | if test $? -ne 0; then 32 | exit 1 33 | fi 34 | fi 35 | make -s dist 36 | if test $? -ne 0; then 37 | exit 1 38 | fi 39 | 40 | matrix: 41 | include: 42 | - os: linux 43 | sudo: true # for setcap so we can run the tests in chroot. 44 | compiler: gcc 45 | dist: trusty 46 | - os: linux 47 | sudo: true # for setcap so we can run the tests in chroot. 48 | compiler: clang 49 | dist: trusty 50 | - os: osx 51 | before_install: 52 | - brew update 53 | - brew install lzo docbook2x gdb ccache libarchive 54 | - os: linux 55 | sudo: true # for setcap so we can run the tests in chroot. 56 | compiler: clang 57 | env: VALGRIND=1 58 | dist: trusty 59 | - os: linux 60 | sudo: true # for setcap so we can run the tests in chroot. 61 | compiler: clang 62 | env: BUILD_TYPE=asan 63 | dist: trusty 64 | # Sanitizer builds with newer travis fail for unknown reason without giving any message. 65 | group: deprecated-2017Q4 66 | - os: linux 67 | sudo: true # for setcap so we can run the tests in chroot. 68 | compiler: clang 69 | env: BUILD_TYPE=lsan 70 | dist: trusty 71 | group: deprecated-2017Q4 72 | - os: linux 73 | sudo: true # for setcap so we can run the tests in chroot. 74 | compiler: clang 75 | env: BUILD_TYPE=ubsan 76 | dist: trusty 77 | allow_failures: 78 | 79 | before_script: 80 | - | 81 | if [ "$BUILD_TYPE" == "asan" ]; then 82 | export SAN_FLAGS="-fsanitize=address -fsanitize-address-use-after-scope -fno-omit-frame-pointer" 83 | fi 84 | - | 85 | if [ "$BUILD_TYPE" == "lsan" ]; then 86 | export SAN_FLAGS="-fsanitize=leak -fno-omit-frame-pointer" 87 | fi 88 | - | 89 | if [ "$BUILD_TYPE" == "msan" ]; then 90 | export SAN_FLAGS="-fsanitize=memory-fno-omit-frame-pointer" 91 | fi 92 | - | 93 | if [ "$BUILD_TYPE" == "ubsan" ]; then 94 | export SAN_FLAGS="-fsanitize=undefined -fno-omit-frame-pointer" 95 | export LDFLAGS="$UBSAN_FLAGS ${LDFLAGS}" 96 | export UBSAN_OPTIONS=print_stacktrace=1 97 | fi 98 | - | 99 | if [ "$TRAVIS_OS_NAME" == "osx" ]; then 100 | export LDFLAGS="${LDFLAGS} -L/usr/local/opt/libarchive/lib" 101 | export CPPFLAGS="${CPPFLAGS} -I/usr/local/opt/libarchive/include" 102 | export PKG_CONFIG_PATH="/usr/local/opt/libarchive/lib/pkgconfig" 103 | fi 104 | - | 105 | export CFLAGS="${SAN_FLAGS} ${CFLAGS} -Wall -Wextra" 106 | export CXXFLAGS="${SAN_FLAGS} ${CXXFLAGS} -Wall -Wextra" 107 | export LDFLAGS="${SAN_FLAGS} ${LDFLAGS}" 108 | 109 | 110 | addons: 111 | apt: 112 | packages: 113 | - gcc 114 | - libcap-ng-dev 115 | - libcap-ng-utils 116 | - liblzo2-dev 117 | - docbook2x 118 | - realpath 119 | - gdb 120 | - valgrind 121 | - libarchive-dev 122 | -------------------------------------------------------------------------------- /scheduler/job.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2004 Michael Matz 7 | 2004 Stephan Kulow 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #ifndef JOB_H 25 | #define JOB_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "../services/comm.h" 32 | 33 | class CompileServer; 34 | 35 | class Job 36 | { 37 | public: 38 | enum State { 39 | PENDING, 40 | WAITINGFORCS, 41 | COMPILING 42 | }; 43 | 44 | Job(const unsigned int _id, CompileServer *subm); 45 | ~Job(); 46 | 47 | unsigned int id() const; 48 | 49 | unsigned int localClientId() const; 50 | void setLocalClientId(const unsigned int id); 51 | 52 | State state() const; 53 | void setState(const State state); 54 | 55 | CompileServer *server() const; 56 | void setServer(CompileServer *server); 57 | 58 | CompileServer *submitter() const; 59 | void setSubmitter(CompileServer *submitter); 60 | 61 | Environments environments() const; 62 | void setEnvironments(const Environments &environments); 63 | void appendEnvironment(const std::pair &env); 64 | void clearEnvironments(); 65 | 66 | time_t startTime() const; 67 | void setStartTime(const time_t time); 68 | 69 | time_t startOnScheduler() const; 70 | void setStartOnScheduler(const time_t time); 71 | 72 | time_t doneTime() const; 73 | void setDoneTime(const time_t time); 74 | 75 | std::string targetPlatform() const; 76 | void setTargetPlatform(const std::string &platform); 77 | 78 | std::string fileName() const; 79 | void setFileName(const std::string &fileName); 80 | 81 | std::list masterJobFor() const; 82 | void appendJob(Job *job); 83 | 84 | unsigned int argFlags() const; 85 | void setArgFlags(const unsigned int argFlags); 86 | 87 | std::string language() const; 88 | void setLanguage(const std::string &language); 89 | 90 | std::string preferredHost() const; 91 | void setPreferredHost(const std::string &host); 92 | 93 | int minimalHostVersion() const; 94 | void setMinimalHostVersion( int version ); 95 | 96 | private: 97 | const unsigned int m_id; 98 | unsigned int m_localClientId; 99 | State m_state; 100 | CompileServer *m_server; // on which server we build 101 | CompileServer *m_submitter; // who submitted us 102 | Environments m_environments; 103 | time_t m_startTime; // _local_ to the compiler server 104 | time_t m_startOnScheduler; // starttime local to scheduler 105 | /** 106 | * the end signal from client and daemon is a bit of a race and 107 | * in 99.9% of all cases it's catched correctly. But for the remaining 108 | * 0.1% we need a solution too - otherwise these jobs are eating up slots. 109 | * So the solution is to track done jobs (client exited, daemon didn't signal) 110 | * and after 10s no signal, kill the daemon (and let it rehup) **/ 111 | time_t m_doneTime; 112 | 113 | std::string m_targetPlatform; 114 | std::string m_fileName; 115 | std::list m_masterJobFor; 116 | unsigned int m_argFlags; 117 | std::string m_language; // for debugging 118 | std::string m_preferredHost; // for debugging daemons 119 | int m_minimalHostVersion; // minimal version required for the the remote server 120 | }; 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /suse/init.icecream: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Copyright (c) 2003 SuSE Linux AG Nuernberg, Germany. 3 | # 4 | # Author: Stephan Kulow 5 | # 6 | # /etc/init.d/icecream 7 | # and its symbolic link 8 | # /usr/sbin/rcicecream 9 | # 10 | ### BEGIN INIT INFO 11 | # Provides: icecream 12 | # Required-Start: $network $syslog $remote_fs 13 | # Required-Stop: $network $remote_fs 14 | # Default-Start: 3 5 15 | # Default-Stop: 16 | # Description: distributed compiler daemon 17 | # Short-Description: icecc 18 | ### END INIT INFO 19 | 20 | # Determine the base and follow a runlevel link name. 21 | base=${0##*/} 22 | link=${base#*[SK][0-9][0-9]} 23 | 24 | # Force execution if not called by a runlevel directory. 25 | test -x /usr/sbin/iceccd || exit 0 26 | 27 | . /etc/rc.status 28 | . /etc/sysconfig/icecream 29 | 30 | rc_reset 31 | case "$1" in 32 | start) 33 | echo -n "Starting Distributed Compiler Daemon" 34 | netname= 35 | if test -n "$ICECREAM_NETNAME"; then 36 | netname="-n $ICECREAM_NETNAME" 37 | fi 38 | if test "$ICECREAM_RUN_SCHEDULER" == "yes"; then 39 | logfile="" 40 | if test -z "$ICECREAM_SCHEDULER_LOG_FILE"; then 41 | ICECREAM_SCHEDULER_LOG_FILE="/var/log/icecream/scheduler" 42 | fi 43 | logfile="-l $ICECREAM_SCHEDULER_LOG_FILE" 44 | : > $ICECREAM_SCHEDULER_LOG_FILE 45 | chown icecream:icecream $ICECREAM_SCHEDULER_LOG_FILE 46 | startproc -u icecream /usr/sbin/icecc-scheduler -d $logfile $netname 47 | fi 48 | logfile="" 49 | if test -n "$ICECREAM_LOG_FILE"; then 50 | touch $ICECREAM_LOG_FILE 51 | chown icecream:icecream $ICECREAM_LOG_FILE 52 | logfile="-l $ICECREAM_LOG_FILE" 53 | else 54 | touch /var/log/icecream/iceccd 55 | chown icecream:icecream /var/log/icecream/iceccd 56 | fi 57 | nice= 58 | if test -n "$ICECREAM_NICE_LEVEL"; then 59 | nice="--nice $ICECREAM_NICE_LEVEL" 60 | fi 61 | scheduler= 62 | if test -n "$ICECREAM_SCHEDULER_HOST"; then 63 | scheduler="-s $ICECREAM_SCHEDULER_HOST" 64 | fi 65 | noremote= 66 | if test "$ICECREAM_ALLOW_REMOTE" = "no" 2> /dev/null; then 67 | noremote="--no-remote" 68 | fi 69 | maxjobs= 70 | if test -n "$ICECREAM_MAX_JOBS"; then 71 | if test "$ICECREAM_MAX_JOBS" -eq 0 2> /dev/null; then 72 | maxjobs="-m 1" 73 | noremote="--no-remote" 74 | else 75 | maxjobs="-m $ICECREAM_MAX_JOBS" 76 | fi 77 | fi 78 | startproc /usr/sbin/iceccd -d $logfile $nice $scheduler $netname -u icecream -b "$ICECREAM_BASEDIR" $maxjobs $noremote 79 | rc_status -v 80 | ;; 81 | stop) 82 | echo -n "Shutting down Distributed Compiler Daemon" 83 | killproc -TERM /usr/sbin/iceccd 84 | if test "$ICECREAM_RUN_SCHEDULER" == "yes"; then 85 | killproc -TERM /usr/sbin/icecc-scheduler 86 | fi 87 | rc_status -v 88 | ;; 89 | restart) 90 | ## If first returns OK call the second, if first or 91 | ## second command fails, set echo return value. 92 | $0 stop; sleep 1 && $0 start 93 | rc_status 94 | ;; 95 | try-restart|condrestart) 96 | ## Do a restart only if the service was active before. 97 | ## Note: try-restart is now part of LSB (as of 1.9). 98 | ## RH has a similar command named condrestart. 99 | if test "$1" = "condrestart"; then 100 | echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}" 101 | fi 102 | $0 status 103 | if test $? = 0; then 104 | $0 restart 105 | else 106 | rc_reset # Not running is not a failure. 107 | fi 108 | # Remember status and be quiet 109 | rc_status 110 | ;; 111 | reload|force-reload) 112 | if test "$ICECREAM_RUN_SCHEDULER" == "yes"; then 113 | killproc -HUP /usr/sbin/icecc-scheduler 114 | fi 115 | killproc -HUP /usr/sbin/iceccd 116 | rc_status 117 | ;; 118 | status) 119 | echo -n "Checking for Distributed Compiler Daemon: " 120 | checkproc /usr/sbin/iceccd 121 | rc_status -v 122 | ;; 123 | *) 124 | echo "Usage: $0 {start|stop|status|restart|try-restart|reload}" 125 | exit 1 126 | ;; 127 | esac 128 | rc_exit 129 | -------------------------------------------------------------------------------- /daemon/ncpus.c: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | * distcc -- A simple distributed compiler system 5 | * 6 | * Copyright (C) 2003 by Martin Pool 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License along 19 | * with this program; if not, write to the Free Software Foundation, Inc., 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | /* Thanks to Dimitri PAPADOPOULOS-ORFANOS for researching many of the methods 24 | * in this file. */ 25 | 26 | #include "config.h" 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "ncpus.h" 36 | #include "exitcode.h" 37 | 38 | /** 39 | * Determine number of processors online. 40 | * 41 | * We will in the future use this to gauge how many concurrent tasks 42 | * should run on this machine. Obviously this is only very rough: the 43 | * correct number needs to take into account disk buffers, IO 44 | * bandwidth, other tasks, etc. 45 | **/ 46 | 47 | #if defined(__hpux__) || defined(__hpux) 48 | 49 | #include 50 | #include 51 | 52 | int dcc_ncpus(int *ncpus) 53 | { 54 | struct pst_dynamic psd; 55 | 56 | if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) != -1) { 57 | *ncpus = psd.psd_proc_cnt; 58 | return 0; 59 | } 60 | 61 | rs_log_error("pstat_getdynamic failed: %s", strerror(errno)); 62 | *ncpus = 1; 63 | return EXIT_DISTCC_FAILED; 64 | } 65 | 66 | 67 | #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined(__bsdi__) || defined(__DragonFly__) 68 | 69 | /* http://www.FreeBSD.org/cgi/man.cgi?query=sysctl&sektion=3&manpath=FreeBSD+4.6-stable 70 | http://www.openbsd.org/cgi-bin/man.cgi?query=sysctl&sektion=3&manpath=OpenBSD+Current 71 | http://www.tac.eu.org/cgi-bin/man-cgi?sysctl+3+NetBSD-current 72 | */ 73 | 74 | #include 75 | #include 76 | #include 77 | 78 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 79 | #undef HAVE_RS_LOG_ERROR 80 | #else 81 | #define HAVE_RS_LOG_ERROR 82 | #endif 83 | 84 | int dcc_ncpus(int *ncpus) 85 | { 86 | int mib[2]; 87 | size_t len = sizeof(*ncpus); 88 | mib[0] = CTL_HW; 89 | mib[1] = HW_NCPU; 90 | 91 | if (sysctl(mib, 2, ncpus, &len, NULL, 0) == 0) { 92 | return 0; 93 | } 94 | 95 | #ifdef have_rs_log_error 96 | rs_log_error("sysctl(CTL_HW:HW_NCPU) failed: %s", 97 | strerror(errno)); 98 | #else 99 | fprintf(stderr, "sysctl(CTL_HW:HW_NCPU) failed: %s", strerror(errno)); 100 | #endif 101 | *ncpus = 1; 102 | return EXIT_DISTCC_FAILED; 103 | } 104 | 105 | #else /* every other system */ 106 | 107 | /* 108 | http://www.opengroup.org/onlinepubs/007904975/functions/sysconf.html 109 | http://docs.sun.com/?p=/doc/816-0213/6m6ne38dd&a=view 110 | http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V40G_HTML/MAN/MAN3/0629____.HTM 111 | http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=0650&db=man&fname=/usr/share/catman/p_man/cat3c/sysconf.z 112 | */ 113 | 114 | int dcc_ncpus(int *ncpus) 115 | { 116 | #if defined(_SC_NPROCESSORS_ONLN) 117 | /* Linux, Solaris, Tru64, UnixWare 7, and Open UNIX 8 */ 118 | *ncpus = sysconf(_SC_NPROCESSORS_ONLN); 119 | #elif defined(_SC_NPROC_ONLN) 120 | /* IRIX */ 121 | *ncpus = sysconf(_SC_NPROC_ONLN); 122 | #else 123 | #warning "Please port this function" 124 | *ncpus = -1; /* unknown */ 125 | #endif 126 | 127 | if (*ncpus == -1) { 128 | *ncpus = 1; 129 | return EXIT_DISTCC_FAILED; 130 | } 131 | 132 | if (*ncpus == 0) { 133 | /* if there are no cpus, what are we running on? But it has 134 | * apparently been observed to happen on ARM Linux 135 | */ 136 | *ncpus = 1; 137 | } 138 | 139 | return 0; 140 | } 141 | #endif 142 | -------------------------------------------------------------------------------- /tests/README: -------------------------------------------------------------------------------- 1 | Testuite for Icecream 2 | ===================== 3 | 4 | In this directory are tests for Icecream. 5 | 6 | How to run the tests: 7 | ===================== 8 | 9 | The tests do not conflict with system Icecream, so it is possible to compile 10 | and test while system Icecream is active. 11 | 12 | Since Icecream hardcodes locations of some binaries, it is necessary to 13 | install Icecream for the tests (really install, no $DESTDIR). It is however 14 | not necessary to do a system install, simply install somewhere. If you want 15 | to test also remote builds (recommended), it is necessary for the install to have 16 | the capability to chroot. This is most easily done by giving the CAP_SYS_CHROOT 17 | Linux capability to the iceccd binary (which is done is triggered to be done 18 | automatically by "make test" using sudo). 19 | 20 | An example of building Icecream and testing it: 21 | 22 | ./configure --prefix=$HOME/iceinstall 23 | make test 24 | 25 | The 'make test' step roughly performs: 26 | 27 | make 28 | make install 29 | sudo /sbin/setcap cap_sys_chroot+ep ${prefix}/sbin/iceccd 30 | cd tests 31 | ./test.sh ${prefix} ${builddir}/tests/results --builddir=${builddir}/tests 32 | 33 | This will build and install Icecream into $HOME/iceinstall prefix and all 34 | logs and temporary files will be in ${builddir}/tests/results. It is also possible to use 35 | 'filecap' from cap-ng instead of 'setcap', but 'filecap' does not report failures. 36 | 37 | Note that the limitations (real install needed in a helper location, chroot capability) 38 | mean that these tests are not suitable to be run as a part of building binary 39 | packages, they are meant to be run by developers. 40 | 41 | If a test fails, all relevant files should be in the log and temporary directory 42 | passed to test.sh . The {daemon}.log files contain logs relevant only to the last run test, 43 | files {daemon}_all.log include complete logs (up to but not including the failed test, if any). 44 | 45 | Exit status of test.sh is 0 for all tests passing, 1 for all tests passing but some being 46 | skipped and 2 for errors. 47 | 48 | If you want to use icemon for the tests, use 'ICECC_SCHEDULER=localhost:8767 icemon'. Note that 49 | icemon needs to be built with recent (Feb 2014) libicecc library for this to work. 50 | 51 | 52 | Valgrind: 53 | ========= 54 | 55 | It is possible to pass --valgrind to test.sh in order to test (almost) everything with Valgrind. 56 | Valgrind may be also automatically invoked using: 57 | 58 | make test VALGRIND=1 59 | 60 | Note that in order to be able to chroot, it is necessary to give the capability to the actual 61 | Valgrind binary instead of iceccd (this is because this binary is what actually runs as 62 | the process): 63 | 64 | sudo /sbin/setcap cap_sys_chroot+ep /usr/lib/valgrind/memcheck-x86-linux 65 | 66 | Do not forget to reset it back when done: 67 | 68 | sudo /sbin/setcap -r /usr/lib/valgrind/memcheck-x86-linux 69 | 70 | 71 | Adding new tests: 72 | ================= 73 | 74 | The test.sh script is hopefully straightforward and commented enough. 75 | If you want to test handling of specific flags, see the run_ice function. 76 | If you want more complex/specific tests, you can also check logs using 77 | the various check_log_* functions. 78 | 79 | Common log messages: 80 | (icecc.log) "Have to use host 127.0.0.1:" - will be built remotely (one one of the remote hosts) 81 | (icecc.log) "Have to use host 127.0.0.1:10246" - will be built remotely on remoteice1 82 | (icecc.log) "Have to use host 127.0.0.1:10247" - will be built remotely on remoteice1 83 | (icecc.log) "building myself, but telling localhost" - job could be built remotely, but 84 | the scheduler selected the local daemon for the build 85 | (icecc.log) "" - the job is forced to be built locally (cannot be built remotely) 86 | 87 | 88 | Internals: 89 | ========== 90 | 91 | For most tests, there is a new scheduler run and three daemons, one (localice) 92 | that serves as the "local" daemon that icecc uses, and two more (remoteice1/2) 93 | that serve as "remote" daemons that which remote jobs will be distributed. 94 | 95 | In order not to interfere with system Icecream, they all use different ports 96 | and a special socket is used for communication with localice daemon. 97 | All daemons are set with 2 jobs max, in order to have reliable results 98 | when testing paralellism. 99 | 100 | ICECC_PREFERRED_HOST is used when forcing whether a job should be built 101 | locally or remotely. The localice daemon also has ICECC_TEST_REMOTEBUILD=1 102 | to avoid building locally when it in fact should forward to "remote" daemons 103 | even though they are technically local. 104 | -------------------------------------------------------------------------------- /client/icecc-test-env.in: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # 3 | # A simple script that can be used to see if an environment was built 4 | # successfully. Note that passing these test doesn't guarantee the environment 5 | # will work, but failing them means it certainly won't. Note that this script 6 | # may need to be executed with sudo if the current user doesn't have chroot 7 | # permissions 8 | # 9 | # This program always exits with an error code of 2 so that it can be 10 | # distinguished from a sudo error (with an exit code of 1) 11 | # 12 | # Copyright (C) 2018 Joshua Watt 13 | # 14 | # This program is free software; you can redistribute it and/or modify 15 | # it under the terms of the GNU General Public License as published by 16 | # the Free Software Foundation; either version 2 of the License, or 17 | # (at your option) any later version. 18 | # 19 | # This program is distributed in the hope that it will be useful, 20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | # GNU General Public License for more details. 23 | # 24 | # You should have received a copy of the GNU General Public License along 25 | # with this program; if not, write to the Free Software Foundation, Inc., 26 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 27 | 28 | # Exit on any unexpected failure 29 | set -e 30 | 31 | TEST_DIR= 32 | QUIET=false 33 | REALPATH=$(which realpath 2> /dev/null || true) 34 | 35 | # Cleanup the temp directory on exit 36 | cleanup() { 37 | if [ -n "$TEST_DIR" ]; then 38 | rm -rf "$TEST_DIR" 39 | fi 40 | } 41 | trap cleanup EXIT 42 | 43 | print_info() { 44 | if ! $QUIET; then 45 | echo "$@" 46 | fi 47 | } 48 | 49 | usage() { 50 | echo "Usage: $(basename $0) [-h] TOOLCHAIN" 51 | echo " -h --help Show Help" 52 | echo " -q --quiet Only print errors" 53 | echo " TOOLCHAIN Toolchain archive to test" 54 | echo "" 55 | echo "Tests a toolchain environment to see if it is correctly constructed" 56 | } 57 | 58 | OPTIONS=`getopt -o hqf --long help,quiet -n $(basename $0) -- "$@"` 59 | eval set -- "$OPTIONS" 60 | 61 | while true; do 62 | case "$1" in 63 | -h|--help) 64 | usage 65 | exit 0 66 | ;; 67 | -q|--quiet) 68 | QUIET=true 69 | shift 70 | ;; 71 | --) 72 | shift 73 | break 74 | ;; 75 | *) 76 | echo "Unknown option '$1'" 77 | exit 2 78 | ;; 79 | esac 80 | done 81 | 82 | if [ -z "$1" ]; then 83 | echo "Toolchain argument is required" 84 | usage 85 | exit 2 86 | fi 87 | TEST_DIR=$(mktemp -d) 88 | 89 | if [ -z "$REALPATH" ]; then 90 | echo "WARNING: realpath not found, symlink tests will be disabled" 91 | fi 92 | 93 | # Extract the toolchain 94 | tar -xf "$1" -C "$TEST_DIR" 95 | 96 | # Determine the compiler 97 | if [ -e $TEST_DIR/usr/bin/clang ]; then 98 | print_info "Compiler is clang" 99 | IS_CLANG=true 100 | else 101 | print_info "Compiler is gcc" 102 | IS_CLANG=false 103 | fi 104 | 105 | check_program() { 106 | local prog="$1" 107 | shift 108 | 109 | cd $TEST_DIR 110 | print_info "Checking $prog..." 111 | if [ ! -x "${TEST_DIR}${prog}" ]; then 112 | echo "$prog is missing or not executable" 113 | exit 2 114 | fi 115 | if [ -n "$REALPATH" ]; then 116 | local target="$($REALPATH "${TEST_DIR}${prog}")" 117 | case $target in 118 | "$($REALPATH "${TEST_DIR}")"/*) 119 | ;; 120 | *) 121 | echo "$prog is a symbolic link that points to '$target' outside the environment" 122 | exit 2 123 | ;; 124 | esac 125 | fi 126 | if ! chroot . $prog $@ < /dev/null; then 127 | echo "$prog failed to execute" 128 | exit 2 129 | fi 130 | print_info "OK" 131 | } 132 | 133 | check_program /bin/true 134 | if $IS_CLANG; then 135 | check_program /usr/bin/clang -xc -c -o test.o - 136 | check_program /usr/bin/as 137 | # NOTE: The compilerwrapper programs /usr/bin/gcc and /usr/bin/g++ are not 138 | # tested because they interfer with the automated testing when the 139 | # address sanitizer is enabled 140 | else 141 | ARGS="-fpreprocessed" 142 | check_program /usr/bin/gcc $ARGS -xc -c -o test.o - 143 | check_program /usr/bin/g++ $ARGS -xc++ -c -o test.o - 144 | check_program /usr/bin/cc1 $ARGS -o test.o -quiet 145 | check_program /usr/bin/cc1plus $ARGS -o test.o -quiet 146 | check_program /usr/bin/as 147 | fi 148 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Release Critical: 2 | * chmod TMPDIR/native, as otherwise set umask prevent it from being readable by the client 3 | I'm wondering if it doesn't make sense to leave the daemon out of the game and let the 4 | client package the environment - it could either cache it in /tmp and leave a note in 5 | ~/.icecream or it packages it right into ~/.icecream and use e.g. the inode numbers of 6 | the compilers to verify it's the right environment - think NFS users changing machines. 7 | This would simplify some things and avoid the above bugs (and it would make it more 8 | convenient for users of /opt/gcc-cvs/bin too) 9 | This would also help users who are running in a chroot enviornment where the local 10 | daemon cannot even find the path to the compiler 11 | 12 | * Improve Documentation (cschum) 13 | * make the protocol version an uint32, not a hand-build array. 14 | * let the client specify it was compiled with recent compiler (supporting -param). If so, 15 | let the daemon compile with the options, otherwise leave them out. 16 | 17 | Akademy must have's: 18 | * daemon: only accept connections from a sane net prefix (scheduler can determine 19 | this and send it out via confMsg) to avoid being exposed to the internet 20 | * benchmark/testing jobs (broken machines with broken ram and broken network card on the 21 | icecream network destroy the fun and are not easy to find manually) 22 | 23 | Random: 24 | * Option -iiface to specify the interface[s] to listen on for the scheduler, or 25 | to use for the daemon. 26 | * Don't explicitly forbid tunnels because it could be useful for things like 27 | vmware 28 | * If someone calls a amd64 client on a host that runs a ia32 daemon and there are 29 | no other amd64 daemons in the farm, he will get no answer, but a timeout from 30 | scheduler (quite a corner case, but neat) 31 | * use syslog 32 | * Log problems found at some scheduler log - or even in the monitor. E.g. if a client 33 | can't reach a given daemon, it should be able to tell. Perhaps the scheduler can even 34 | disable that very host for some penalty time 35 | * Reduce amount of force-waits, especially if they involve network latency (scheduler queries) 36 | and daemon context switches: 37 | - remove the need for EndMsg 38 | - do not ask the daemon about the first job (WIP dirk) 39 | * if a compile job SIGSEGV's or SIGABORTs, make sure to recompile locally because it could 40 | be just a glibc/kernel incompatibility on the remote site 41 | * Add heuristic which optimises for overhead-reduction. Statistics prove ( ;) ), that for 42 | e.g. linux kernel the file size varies a lot, and small jobs should be preferably compiled 43 | locally and bigger ones preferably remote. 44 | * Split number of jobs into number of compile jobs (cheap) and number of non compile jobs (can 45 | be expensive, e.g. ld or meinproc). The reason is that multicore chips become more and more 46 | common. Today you can get quad cores easily and in some month we've 8 cores and several link 47 | jobs at the same time can pull down your whole system. 48 | (I can life with a hard coded number of one non compile job but others probably prefer a 49 | configurable number) 50 | * Consider launching a scheduler on-demand if there is none available or if a daemon knows 51 | it has a better version than the scheduler that is available (https://github.com/icecc/icecream/issues/84). 52 | 53 | Suggestions from "Wilson Snyder" sicortex.com: 54 | - Add ICECREAM_RUN_ICECCD to make the scheduler machine not run iceccd 55 | 56 | Christoph Thielecke writes: 57 | > 1) Problem von icecream: icecc hat /usr/bin/gcc-4.2 kopiert (ist aber ein 58 | > Symlink auf den Hardening-Wrapper, der installiert war, siehe Listing 59 | > unten). Kannst Du vieleicht eine Prüfung einbauen, ob gcc-x.y mit .real 60 | > endet bzw der Wrapper ist? 61 | 62 | Andi Kleen writes to protect against misconfiguration: 63 | >generate somefile.h on the client with 64 | >#if __GNUC__ != expected_major || __GNU_MINOR__ != expected_minor 65 | >#warning blabla 66 | >#endif 67 | >and then run with 68 | >-include somefile.h 69 | > (this file needs to be in the environment created by create_env) 70 | 71 | From thedrow (distcc maintainer) 72 | >Merging this back might just mean feature parity with what icecream currently 73 | >provides or merging some of the code directly to distcc. 74 | >I think that the entire Linux community will gain from one tool that is able to 75 | >distribute compilation of large C/C++ components that provides more flexibility 76 | >and allows you to grow from the easy to setup distcc type of deployment to the 100 77 | >machines build farm that icecc provides. 78 | >Are there more features that diverged from distcc except for the server/client 79 | >architecture? 80 | We think the the only other feature is better support for automatic chroot. 81 | 82 | -------------------------------------------------------------------------------- /services/logging.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2004 Stephan Kulow 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #ifndef ICECREAM_LOGGING_H 24 | #define ICECREAM_LOGGING_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | // Verbosity level, from least to most. 36 | enum VerbosityLevel { 37 | Error = 0, 38 | Warning = 1, 39 | Info = 2, 40 | Debug = 3, 41 | 42 | MaxVerboseLevel = Debug 43 | }; 44 | 45 | extern std::ostream *logfile_info; 46 | extern std::ostream *logfile_warning; 47 | extern std::ostream *logfile_error; 48 | extern std::ostream *logfile_trace; 49 | extern std::string logfile_prefix; 50 | 51 | void setup_debug(int level, const std::string &logfile = "", const std::string &prefix = ""); 52 | void reset_debug_if_needed(); // if we get SIGHUP, this will handle the reset 53 | void reset_debug(); 54 | void close_debug(); 55 | void flush_debug(); 56 | 57 | static inline std::ostream &output_date(std::ostream &os) 58 | { 59 | time_t t = time(0); 60 | struct tm *tmp = localtime(&t); 61 | char buf[64]; 62 | strftime(buf, sizeof(buf), "%Y-%m-%d %T: ", tmp); 63 | 64 | if (logfile_prefix.size()) { 65 | os << logfile_prefix; 66 | } 67 | 68 | os << "[" << getpid() << "] "; 69 | 70 | os << buf; 71 | return os; 72 | } 73 | 74 | static inline std::ostream &log_info() 75 | { 76 | if (!logfile_info) { 77 | return std::cerr; 78 | } 79 | 80 | return output_date(*logfile_info); 81 | } 82 | 83 | static inline std::ostream &log_warning() 84 | { 85 | if (!logfile_warning) { 86 | return std::cerr; 87 | } 88 | 89 | return output_date(*logfile_warning); 90 | } 91 | 92 | 93 | static inline std::ostream &log_error() 94 | { 95 | if (!logfile_error) { 96 | return std::cerr; 97 | } 98 | 99 | return output_date(*logfile_error); 100 | } 101 | 102 | static inline std::ostream &trace() 103 | { 104 | if (!logfile_trace) { 105 | return std::cerr; 106 | } 107 | 108 | return output_date(*logfile_trace); 109 | } 110 | 111 | static inline std::ostream & log_errno(const char *prefix, int tmp_errno) 112 | { 113 | return log_error() << prefix << "(Error: " << strerror(tmp_errno) << ")" << std::endl; 114 | } 115 | 116 | static inline std::ostream & log_perror(const char *prefix) 117 | { 118 | return log_errno(prefix, errno); 119 | } 120 | 121 | static inline std::ostream & log_errno_trace(const char *prefix, int tmp_errno) 122 | { 123 | return trace() << prefix << "(Error: " << strerror(tmp_errno) << ")" << std::endl; 124 | } 125 | 126 | static inline std::ostream & log_perror_trace(const char *prefix) 127 | { 128 | return log_errno_trace(prefix, errno); 129 | } 130 | 131 | class log_block 132 | { 133 | static unsigned nesting; 134 | timeval m_start; 135 | char *m_label; 136 | 137 | public: 138 | log_block(const char *label = 0) 139 | { 140 | #ifndef NDEBUG 141 | 142 | for (unsigned i = 0; i < nesting; ++i) { 143 | log_info() << " "; 144 | } 145 | 146 | log_info() << "<" << (label ? label : "") << ">\n"; 147 | 148 | m_label = strdup(label ? label : ""); 149 | ++nesting; 150 | gettimeofday(&m_start, 0); 151 | #endif 152 | } 153 | 154 | ~log_block() 155 | { 156 | #ifndef NDEBUG 157 | timeval end; 158 | gettimeofday(&end, 0); 159 | 160 | --nesting; 161 | 162 | for (unsigned i = 0; i < nesting; ++i) { 163 | log_info() << " "; 164 | } 165 | 166 | log_info() << "\n"; 169 | 170 | free(m_label); 171 | #endif 172 | } 173 | }; 174 | 175 | #include 176 | #include 177 | 178 | template std::string toString(const T &val) 179 | { 180 | std::ostringstream os; 181 | os << val; 182 | return os.str(); 183 | } 184 | 185 | #endif 186 | -------------------------------------------------------------------------------- /suse/icecream.spec.in: -------------------------------------------------------------------------------- 1 | # 2 | # spec file for package icecream 3 | # 4 | # Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. 5 | # 6 | # All modifications and additions to the file contributed by third parties 7 | # remain the property of their copyright owners, unless otherwise agreed 8 | # upon. The license for this file, and modifications and additions to the 9 | # file, is the same license as for the pristine package itself (unless the 10 | # license for the pristine package is not an Open Source License, in which 11 | # case the license is the MIT License). An "Open Source License" is a 12 | # license that conforms to the Open Source Definition (Version 1.9) 13 | # published by the Open Source Initiative. 14 | 15 | # Please submit bugfixes or comments via http://bugs.opensuse.org/ 16 | # 17 | # icecream 0 18 | 19 | 20 | Name: icecream 21 | BuildRequires: gcc-c++ 22 | BuildRequires: lzo-devel 23 | %if 0%{?suse_version} > 1110 24 | BuildRequires: libcap-ng-devel 25 | %endif 26 | Summary: For Distributed Compile in the Network 27 | License: GPL-2.0+ and LGPL-2.1+ 28 | Group: Development/Tools/Building 29 | Url: https://github.com/icecc/icecream 30 | Requires: /bin/tar 31 | Requires: /usr/bin/bzip2 32 | %if 0%{?suse_version} 33 | PreReq: %fillup_prereq 34 | PreReq: %insserv_prereq 35 | %endif 36 | PreReq: /usr/sbin/useradd 37 | PreReq: /usr/sbin/groupadd 38 | Recommends: gcc-c++ 39 | Requires: logrotate 40 | Version: @VERSION@ 41 | Release: 0 42 | Source0: ftp://ftp.suse.com/pub/projects/icecream/icecc-%{version}.tar.bz2 43 | BuildRoot: %{_tmppath}/%{name}-%{version}-build 44 | 45 | %description 46 | Distributed compiler with a central scheduler to share build load 47 | 48 | %package -n libicecream-devel 49 | Summary: For Distributed Compile in the Network 50 | Group: Development/Tools/Building 51 | Requires: libstdc++-devel 52 | %if 0%{?suse_version} > 1110 53 | Requires: libcap-ng-devel 54 | %endif 55 | 56 | %description -n libicecream-devel 57 | icecream is the next generation distcc. 58 | 59 | %package -n icecream-clang-wrappers 60 | Summary: Distributed Compile Wrappers for Clang 61 | Group: Development/Tools/Building 62 | Requires: clang 63 | Requires: icecream 64 | Supplements: packageand(icecream:clang) 65 | 66 | %description -n icecream-clang-wrappers 67 | Wrapper symlinks for clang/clang++ for icecream distributed building. 68 | 69 | %prep 70 | %setup -q -n icecc-%{version} 71 | # DO NOT ADD PATCHES without github reference 72 | 73 | %build 74 | export CFLAGS="$RPM_OPT_FLAGS" 75 | export CXXFLAGS="$RPM_OPT_FLAGS" 76 | %configure \ 77 | %if 0%{?suse_version} >= 1230 78 | --enable-clang-rewrite-includes \ 79 | %endif 80 | --enable-clang-wrappers \ 81 | --libexecdir %_libexecdir 82 | make %{?jobs:-j %jobs} 83 | 84 | %install 85 | make DESTDIR=$RPM_BUILD_ROOT install 86 | 87 | # Create symlinks in /opt/icecream/bin on openSUSE <= 1220 88 | %if 0%{?suse_version} <= 1220 89 | mkdir -p $RPM_BUILD_ROOT/opt/icecream/bin 90 | for i in g++ gcc cc c++ clang++ clang; do 91 | ln -sf %_bindir/icecc $RPM_BUILD_ROOT/opt/icecream/bin/$i 92 | done 93 | %endif 94 | 95 | %preun 96 | %stop_on_removal icecream 97 | 98 | %pre 99 | /usr/sbin/groupadd -r icecream 2> /dev/null || : 100 | /usr/sbin/useradd -r -g icecream -s /bin/false -c "Icecream Daemon" -d /var/cache/icecream icecream 2> /dev/null || : 101 | 102 | %post 103 | # older icecream versions may have left some files owned by root:root in the cache 104 | rm -rf -- %_localstatedir/cache/icecream/* 105 | %if 0%{?suse_version} 106 | %{fillup_and_insserv -n icecream icecream} 107 | %endif 108 | 109 | %postun 110 | %restart_on_update icecream 111 | %{insserv_cleanup} 112 | 113 | %files 114 | %defattr(-,root,root) 115 | %doc COPYING README.md NEWS 116 | %config %_sysconfdir/logrotate.d/icecream 117 | %config %_sysconfdir/init.d/icecream 118 | %_bindir/icecc-create-env 119 | %_bindir/icecc 120 | %_bindir/icerun 121 | %_sbindir/icecc-scheduler 122 | %_sbindir/iceccd 123 | %_sbindir/rcicecream 124 | %_mandir/man*/* 125 | %_libexecdir/icecc 126 | %exclude %_libexecdir/icecc/bin/clang 127 | %exclude %_libexecdir/icecc/bin/clang++ 128 | %if 0%{?suse_version} 129 | %config %_sysconfdir/sysconfig/SuSEfirewall2.d/services/* 130 | %_localstatedir/adm/fillup-templates/sysconfig.icecream 131 | %if 0%{?suse_version} <= 1220 132 | /opt/icecream 133 | %exclude /opt/icecream/bin/clang 134 | %exclude /opt/icecream/bin/clang++ 135 | %endif 136 | %endif 137 | %attr(-,icecream,icecream) %_localstatedir/cache/icecream 138 | %attr(-,icecream,icecream) %_localstatedir/log/icecream 139 | 140 | %files -n libicecream-devel 141 | %defattr(-,root,root) 142 | %_includedir/icecc 143 | %_libdir/libicecc.* 144 | %_libdir/pkgconfig/icecc.pc 145 | 146 | %files -n icecream-clang-wrappers 147 | %defattr(-,root,root) 148 | %_libexecdir/icecc/bin/clang 149 | %_libexecdir/icecc/bin/clang++ 150 | %if 0%{?suse_version} <= 1220 151 | /opt/icecream/bin/clang 152 | /opt/icecream/bin/clang++ 153 | %endif 154 | 155 | %changelog 156 | -------------------------------------------------------------------------------- /scheduler/job.cpp: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2004 Michael Matz 7 | 2004 Stephan Kulow 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #include "job.h" 25 | 26 | #include "compileserver.h" 27 | 28 | Job::Job(const unsigned int _id, CompileServer *subm) 29 | : m_id(_id) 30 | , m_localClientId(0) 31 | , m_state(PENDING) 32 | , m_server(0) 33 | , m_submitter(subm) 34 | , m_startTime(0) 35 | , m_startOnScheduler(0) 36 | , m_doneTime(0) 37 | , m_targetPlatform() 38 | , m_fileName() 39 | , m_masterJobFor() 40 | , m_argFlags(0) 41 | , m_language() 42 | , m_preferredHost() 43 | , m_minimalHostVersion(0) 44 | { 45 | m_submitter->submittedJobsIncrement(); 46 | } 47 | 48 | Job::~Job() 49 | { 50 | // XXX is this really deleted on all other paths? 51 | /* fd2chan.erase (channel->fd); 52 | delete channel;*/ 53 | m_submitter->submittedJobsDecrement(); 54 | } 55 | 56 | unsigned int Job::id() const 57 | { 58 | return m_id; 59 | } 60 | 61 | unsigned int Job::localClientId() const 62 | { 63 | return m_localClientId; 64 | } 65 | 66 | void Job::setLocalClientId(const unsigned int id) 67 | { 68 | m_localClientId = id; 69 | } 70 | 71 | Job::State Job::state() const 72 | { 73 | return m_state; 74 | } 75 | 76 | void Job::setState(const Job::State state) 77 | { 78 | m_state = state; 79 | } 80 | 81 | CompileServer *Job::server() const 82 | { 83 | return m_server; 84 | } 85 | 86 | void Job::setServer(CompileServer *server) 87 | { 88 | m_server = server; 89 | } 90 | 91 | CompileServer *Job::submitter() const 92 | { 93 | return m_submitter; 94 | } 95 | 96 | void Job::setSubmitter(CompileServer *submitter) 97 | { 98 | m_submitter = submitter; 99 | } 100 | 101 | Environments Job::environments() const 102 | { 103 | return m_environments; 104 | } 105 | 106 | void Job::setEnvironments(const Environments &environments) 107 | { 108 | m_environments = environments; 109 | } 110 | 111 | void Job::appendEnvironment(const std::pair &env) 112 | { 113 | m_environments.push_back(env); 114 | } 115 | 116 | void Job::clearEnvironments() 117 | { 118 | m_environments.clear(); 119 | } 120 | 121 | time_t Job::startTime() const 122 | { 123 | return m_startTime; 124 | } 125 | 126 | void Job::setStartTime(const time_t time) 127 | { 128 | m_startTime = time; 129 | } 130 | 131 | time_t Job::startOnScheduler() const 132 | { 133 | return m_startOnScheduler; 134 | } 135 | 136 | void Job::setStartOnScheduler(const time_t time) 137 | { 138 | m_startOnScheduler = time; 139 | } 140 | 141 | time_t Job::doneTime() const 142 | { 143 | return m_doneTime; 144 | } 145 | 146 | void Job::setDoneTime(const time_t time) 147 | { 148 | m_doneTime = time; 149 | } 150 | 151 | std::string Job::targetPlatform() const 152 | { 153 | return m_targetPlatform; 154 | } 155 | 156 | void Job::setTargetPlatform(const std::string &platform) 157 | { 158 | m_targetPlatform = platform; 159 | } 160 | 161 | std::string Job::fileName() const 162 | { 163 | return m_fileName; 164 | } 165 | 166 | void Job::setFileName(const std::string &fileName) 167 | { 168 | m_fileName = fileName; 169 | } 170 | 171 | std::list Job::masterJobFor() const 172 | { 173 | return m_masterJobFor; 174 | } 175 | 176 | void Job::appendJob(Job *job) 177 | { 178 | m_masterJobFor.push_back(job); 179 | } 180 | 181 | unsigned int Job::argFlags() const 182 | { 183 | return m_argFlags; 184 | } 185 | 186 | void Job::setArgFlags(const unsigned int argFlags) 187 | { 188 | m_argFlags = argFlags; 189 | } 190 | 191 | std::string Job::language() const 192 | { 193 | return m_language; 194 | } 195 | 196 | void Job::setLanguage(const std::string &language) 197 | { 198 | m_language = language; 199 | } 200 | 201 | std::string Job::preferredHost() const 202 | { 203 | return m_preferredHost; 204 | } 205 | 206 | void Job::setPreferredHost(const std::string &host) 207 | { 208 | m_preferredHost = host; 209 | } 210 | 211 | int Job::minimalHostVersion() const 212 | { 213 | return m_minimalHostVersion; 214 | } 215 | 216 | void Job::setMinimalHostVersion(int version) 217 | { 218 | m_minimalHostVersion = version; 219 | } 220 | -------------------------------------------------------------------------------- /tests/clangplugin.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Icecream. 3 | * 4 | * Based on LLVM/Clang. 5 | * 6 | * This file is distributed under the University of Illinois Open Source 7 | * License. 8 | * 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | using namespace clang; 22 | using namespace std; 23 | 24 | namespace IcecreamTest 25 | { 26 | 27 | void report( const CompilerInstance& compiler, DiagnosticsEngine::Level level, const char* txt, SourceLocation loc = SourceLocation()); 28 | 29 | class Action 30 | : public PluginASTAction 31 | { 32 | public: 33 | #if (CLANG_VERSION_MAJOR == 3 && CLANG_VERSION_MINOR >= 6) || CLANG_VERSION_MAJOR > 3 34 | virtual std::unique_ptr CreateASTConsumer( CompilerInstance& compiler, StringRef infile ); 35 | #else 36 | virtual ASTConsumer* CreateASTConsumer( CompilerInstance& compiler, StringRef infile ); 37 | #endif 38 | virtual bool ParseArgs( const CompilerInstance& compiler, const vector< string >& args ); 39 | private: 40 | vector< string > _args; 41 | }; 42 | 43 | class Consumer 44 | : public RecursiveASTVisitor< Consumer >, public ASTConsumer 45 | { 46 | public: 47 | Consumer( CompilerInstance& compiler, const vector< string >& args ); 48 | bool VisitReturnStmt( const ReturnStmt* returnstmt ); 49 | virtual void HandleTranslationUnit( ASTContext& context ); 50 | private: 51 | CompilerInstance& compiler; 52 | }; 53 | 54 | 55 | #if (CLANG_VERSION_MAJOR == 3 && CLANG_VERSION_MINOR >= 6) || CLANG_VERSION_MAJOR > 3 56 | std::unique_ptr Action::CreateASTConsumer( CompilerInstance& compiler, StringRef ) 57 | { 58 | return unique_ptr( new Consumer( compiler, _args )); 59 | } 60 | #else 61 | ASTConsumer* Action::CreateASTConsumer( CompilerInstance& compiler, StringRef ) 62 | { 63 | return new Consumer( compiler, _args ); 64 | } 65 | #endif 66 | 67 | bool Action::ParseArgs( const CompilerInstance& /*compiler*/, const vector< string >& args ) 68 | { 69 | _args = args; 70 | return true; 71 | } 72 | 73 | Consumer::Consumer( CompilerInstance& compiler, const vector< string >& args ) 74 | : compiler( compiler ) 75 | { 76 | // Check that the file passed as argument really exists (was included in ICECC_EXTRAFILES). 77 | if( args.size() != 1 ) 78 | { 79 | report( compiler, DiagnosticsEngine::Error, "Incorrect number of arguments" ); 80 | return; 81 | } 82 | ifstream is( args[ 0 ].c_str()); 83 | if( !is.good()) 84 | report( compiler, DiagnosticsEngine::Error, "Extra file open error" ); 85 | else 86 | { 87 | char buf[ 20 ]; 88 | is.getline( buf, 20 ); 89 | if( strcmp( buf, "testfile" ) != 0 ) 90 | report( compiler, DiagnosticsEngine::Error, "File contents do not match" ); 91 | else 92 | report( compiler, DiagnosticsEngine::Warning, "Extra file check successful" ); 93 | } 94 | } 95 | 96 | void Consumer::HandleTranslationUnit( ASTContext& context ) 97 | { 98 | if( context.getDiagnostics().hasErrorOccurred()) 99 | return; 100 | TraverseDecl( compiler.getASTContext().getTranslationUnitDecl()); 101 | } 102 | 103 | bool Consumer::VisitReturnStmt( const ReturnStmt* returnstmt ) 104 | { 105 | // Get the expression in the return statement (see ReturnStmt API docs). 106 | const Expr* expression = returnstmt->getRetValue(); 107 | if( expression == NULL ) 108 | return true; // plain 'return;' without expression 109 | // Check if the expression is a bool literal (Clang uses dyn_cast<> instead of dynamic_cast<>). 110 | if( const CXXBoolLiteralExpr* boolliteral = dyn_cast< CXXBoolLiteralExpr >( expression )) 111 | { // It is. 112 | if( boolliteral->getValue() == false ) 113 | report( compiler, DiagnosticsEngine::Warning, "Icecream plugin found return false", 114 | #if CLANG_VERSION_MAJOR >= 8 115 | returnstmt->getBeginLoc()); 116 | #else 117 | returnstmt->getLocStart()); 118 | #endif 119 | } 120 | return true; 121 | } 122 | 123 | void report( const CompilerInstance& compiler, DiagnosticsEngine::Level level, const char* txt, SourceLocation loc ) 124 | { 125 | DiagnosticsEngine& engine = compiler.getDiagnostics(); 126 | #if (CLANG_VERSION_MAJOR == 3 && CLANG_VERSION_MINOR >= 5) || CLANG_VERSION_MAJOR > 3 127 | if( loc.isValid()) 128 | engine.Report( loc, engine.getDiagnosticIDs()->getCustomDiagID( 129 | static_cast< DiagnosticIDs::Level >( level ), txt )); 130 | else 131 | engine.Report( engine.getDiagnosticIDs()->getCustomDiagID( 132 | static_cast< DiagnosticIDs::Level >( level ), txt )); 133 | #else 134 | if( loc.isValid()) 135 | engine.Report( loc, engine.getCustomDiagID( level, txt )); 136 | else 137 | engine.Report( engine.getCustomDiagID( level, txt )); 138 | #endif 139 | } 140 | 141 | } // namespace 142 | 143 | static FrontendPluginRegistry::Add< IcecreamTest::Action > X( "icecreamtest", "Icecream test plugin" ); 144 | -------------------------------------------------------------------------------- /compilerwrapper/compilerwrapper.cpp: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | Copyright (C) 2012 Lubos Lunak 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions 8 | are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | 29 | /* 30 | Older icecream versions assume the compiler is always GCC. This can 31 | be fixed on the local side, but remote nodes would need icecream upgrade. 32 | As a workaround icecc-create-env includes this wrapper binary in the environment 33 | if clang is to be used as well, that will either call clang or the real gcc. 34 | Which one depends on an extra argument added by icecream. 35 | */ 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | //#define DEBUG 44 | 45 | int main(int argc, char *argv[]) 46 | { 47 | bool iscxx = false; 48 | int argv0len = strlen(argv[0]); 49 | 50 | if (argv0len > 2 && argv[0][argv0len - 1] == '+' && argv[0][argv0len - 2] == '+') { 51 | iscxx = true; 52 | } 53 | 54 | #ifdef DEBUG 55 | fprintf(stderr, "Args1:\n"); 56 | 57 | for (int i = 0; i < argc; ++i) { 58 | fprintf(stderr, "%s\n", argv[i]); 59 | } 60 | 61 | fprintf(stderr, "\n"); 62 | #endif 63 | bool isclang = argc >= 2 && strcmp(argv[1], "clang") == 0; // the extra argument from icecream 64 | // 1 extra for -no-canonical-prefixes 65 | char **args = new char*[argc + 2]; 66 | args[0] = new char[strlen(argv[0]) + 20]; 67 | strcpy(args[0], argv[0]); 68 | char *separator = strrchr(args[0], '/'); 69 | 70 | if (separator == NULL) { 71 | args[0][0] = '\0'; 72 | } else { 73 | separator[1] = '\0'; // after the separator 74 | } 75 | 76 | if (isclang) { 77 | strcat(args[0], "clang"); 78 | } else if (iscxx) { 79 | strcat(args[0], "g++.bin"); 80 | } else { 81 | strcat(args[0], "gcc.bin"); 82 | } 83 | 84 | int pos = 1; 85 | 86 | if (isclang) { 87 | args[pos++] = strdup("-no-canonical-prefixes"); // otherwise clang tries to access /proc/self/exe 88 | // clang wants the -x argument early, otherwise it seems to ignore it 89 | // (and treats the file as already preprocessed) 90 | int x_arg_pos = -1; 91 | 92 | for (int i = 2; // 2 - skip the extra "clang" argument 93 | i < argc; 94 | ++i) { 95 | if (strcmp(argv[i], "-x") == 0 && i + 1 < argc 96 | && (strcmp(argv[i + 1], "c") == 0 || strcmp(argv[i + 1], "c++") == 0)) { 97 | x_arg_pos = i; 98 | args[pos++] = strdup("-x"); 99 | args[pos++] = strdup(argv[i + 1]); 100 | break; 101 | } 102 | } 103 | 104 | for (int i = 2; // 2 - skip the extra "clang" argument 105 | i < argc; 106 | ++i) { 107 | // strip options that icecream adds but clang doesn't know or need 108 | if (strcmp(argv[i], "-fpreprocessed") == 0) { 109 | continue; // clang doesn't know this (it presumably needs to always preprocess anyway) 110 | } 111 | 112 | if (strcmp(argv[i], "--param") == 0 && i + 1 < argc) { 113 | if (strncmp(argv[i + 1], "ggc-min-expand=", strlen("ggc-min-expand=")) == 0 114 | || strncmp(argv[i + 1], "ggc-min-heapsize=", strlen("ggc-min-heapsize=")) == 0) { 115 | // drop --param and the parameter itself 116 | ++i; 117 | continue; 118 | } 119 | } 120 | 121 | if (i == x_arg_pos) { 122 | ++i; // skip following 123 | continue; // and skip this one 124 | } 125 | 126 | args[pos++] = strdup(argv[i]); 127 | } 128 | } else { // !isclang , just copy the arguments 129 | for (int i = 1; i < argc; ++i) { 130 | args[pos++] = strdup(argv[i]); 131 | } 132 | } 133 | 134 | args[pos++] = NULL; 135 | assert(pos <= argc + 2); 136 | #ifdef DEBUG 137 | fprintf(stderr, "Args2:\n"); 138 | 139 | for (int i = 0; i < pos; ++i) { 140 | fprintf(stderr, "%s\n", args[i]); 141 | } 142 | 143 | fprintf(stderr, "\n"); 144 | #endif 145 | execv(args[0], args); 146 | fprintf(stderr, "execv failed\n"); 147 | exit(1); 148 | } 149 | -------------------------------------------------------------------------------- /services/tempfile.c: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | * distcc -- A simple distributed compiler system 5 | * 6 | * Copyright (C) 2002, 2003 by Martin Pool 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License along 19 | * with this program; if not, write to the Free Software Foundation, Inc., 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | 24 | /* "More computing sins are committed in the name of 25 | * efficiency (without necessarily achieving it) than 26 | * for any other single reason - including blind 27 | * stupidity." -- W.A. Wulf 28 | */ 29 | 30 | 31 | 32 | #include "config.h" 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include "tempfile.h" 48 | #include "exitcode.h" 49 | 50 | #ifndef _PATH_TMP 51 | #define _PATH_TMP "/tmp" 52 | #endif 53 | 54 | 55 | 56 | /** 57 | * Create a file inside the temporary directory and register it for 58 | * later cleanup, and return its name. 59 | * 60 | * The file will be reopened later, possibly in a child. But we know 61 | * that it exists with appropriately tight permissions. 62 | **/ 63 | int dcc_make_tmpnam(const char *prefix, const char *suffix, char **name_ret, int relative) 64 | { 65 | unsigned long random_bits; 66 | unsigned long tries = 0; 67 | size_t tmpname_length; 68 | char *tmpname; 69 | 70 | tmpname_length = strlen(_PATH_TMP) + 1 + strlen(prefix) + 1 + 8 + strlen(suffix) + 1; 71 | tmpname = malloc(tmpname_length); 72 | 73 | if (!tmpname) { 74 | return EXIT_OUT_OF_MEMORY; 75 | } 76 | 77 | random_bits = (unsigned long) getpid() << 16; 78 | 79 | { 80 | struct timeval tv; 81 | gettimeofday(&tv, NULL); 82 | random_bits ^= tv.tv_usec << 16; 83 | random_bits ^= tv.tv_sec; 84 | } 85 | 86 | #if 0 87 | random_bits = 0; /* FOR TESTING */ 88 | #endif 89 | 90 | do { 91 | if (snprintf(tmpname, tmpname_length, "%s/%s_%08lx%s", 92 | (relative ? _PATH_TMP + 1 : _PATH_TMP), 93 | prefix, 94 | random_bits & 0xffffffffUL, 95 | suffix) == -1) { 96 | free(tmpname); 97 | return EXIT_OUT_OF_MEMORY; 98 | } 99 | 100 | /* Note that if the name already exists as a symlink, this 101 | * open call will fail. 102 | * 103 | * The permissions are tight because nobody but this process 104 | * and our children should do anything with it. */ 105 | int fd = open(tmpname, O_WRONLY | O_CREAT | O_EXCL, 0600); 106 | 107 | if (fd == -1) { 108 | /* Don't try getting a file too often. Safety net against 109 | endless loops. Probably just paranoia. */ 110 | if (++tries > 1000000) { 111 | free(tmpname); 112 | return EXIT_IO_ERROR; 113 | } 114 | 115 | /* Some errors won't change by changing the filename, 116 | e.g. ENOENT means that the directory where we try to create 117 | the file was removed from under us. Don't endlessly loop 118 | in that case. */ 119 | switch (errno) { 120 | case EACCES: 121 | case EEXIST: 122 | case EISDIR: 123 | case ELOOP: 124 | /* try again */ 125 | random_bits += 7777; /* fairly prime */ 126 | continue; 127 | } 128 | 129 | free(tmpname); 130 | return EXIT_IO_ERROR; 131 | } 132 | 133 | if (close(fd) == -1) { /* huh? */ 134 | free(tmpname); 135 | return EXIT_IO_ERROR; 136 | } 137 | 138 | break; 139 | } while (1); 140 | 141 | *name_ret = tmpname; 142 | 143 | return 0; 144 | } 145 | 146 | int dcc_make_tmpdir(char **name_ret) { 147 | unsigned long tries = 0; 148 | char template[] = "icecc-XXXXXX"; 149 | size_t tmpname_length = strlen(_PATH_TMP) + 1 + strlen(template) + 1; 150 | char *tmpname = malloc(tmpname_length); 151 | 152 | if (!tmpname) { 153 | return EXIT_OUT_OF_MEMORY; 154 | } 155 | 156 | if (snprintf(tmpname, tmpname_length, "%s/%s", _PATH_TMP, template) == -1) { 157 | free(tmpname); 158 | return EXIT_OUT_OF_MEMORY; 159 | } 160 | 161 | do { 162 | if (!mkdtemp(tmpname)) { 163 | if (++tries > 1000000) { 164 | free(tmpname); 165 | return EXIT_IO_ERROR; 166 | } 167 | 168 | switch (errno) { 169 | case EACCES: 170 | case EEXIST: 171 | case EISDIR: 172 | case ELOOP: 173 | continue; 174 | } 175 | 176 | free(tmpname); 177 | return EXIT_IO_ERROR; 178 | } 179 | 180 | break; 181 | } while (1); 182 | 183 | *name_ret = tmpname; 184 | 185 | return 0; 186 | } 187 | -------------------------------------------------------------------------------- /daemon/file_util.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "file_util.h" 13 | 14 | 15 | using namespace std; 16 | 17 | /** 18 | * Adapted from an answer by "Evan Teran" from this stack overflow question: 19 | * http://stackoverflow.com/questions/236129/split-a-string-in-c 20 | */ 21 | vector split(const string &s, char delim) { 22 | vector elems; 23 | stringstream ss(s); 24 | string item; 25 | while (getline(ss, item, delim)) { 26 | if (!item.empty()) { 27 | elems.push_back(item); 28 | } 29 | } 30 | return elems; 31 | } 32 | 33 | /** 34 | * Adapted from an answer by "dash-tom-bang" from this stack overflow question: 35 | * http://stackoverflow.com/questions/5772992/get-relative-path-from-two-absolute-paths 36 | */ 37 | string get_relative_path(const string &to, const string &from) { 38 | vector to_dirs = split(to, '/'); 39 | vector from_dirs = split(from, '/'); 40 | 41 | string output; 42 | output.reserve(to.size()); 43 | 44 | vector::const_iterator to_it = to_dirs.begin(), 45 | to_end = to_dirs.end(), 46 | from_it = from_dirs.begin(), 47 | from_end = from_dirs.end(); 48 | 49 | while ((to_it != to_end) && (from_it != from_end) && *to_it == *from_it) { 50 | ++to_it; 51 | ++from_it; 52 | } 53 | 54 | while (from_it != from_end) { 55 | output += "../"; 56 | ++from_it; 57 | } 58 | 59 | while (to_it != to_end) { 60 | output += *to_it; 61 | ++to_it; 62 | 63 | if (to_it != to_end) { 64 | output += "/"; 65 | } 66 | } 67 | 68 | return output; 69 | } 70 | 71 | /** 72 | * Returns a string without '..' and '.' 73 | * 74 | * Preconditions: path must be an absolute path 75 | * Postconditions: if path is empty or not an absolute path, return original 76 | * path, otherwise, return path after resolving '..' and '.' 77 | */ 78 | string get_canonicalized_path(const string &path) { 79 | if (path.empty() || path[0] != '/') { 80 | return path; 81 | } 82 | 83 | vector parts = split(path, '/'); 84 | vector canonicalized_path; 85 | 86 | vector::const_iterator parts_it = parts.begin(), 87 | parts_end = parts.end(); 88 | 89 | while (parts_it != parts_end) { 90 | if (*parts_it == ".." && !canonicalized_path.empty()) { 91 | canonicalized_path.pop_back(); 92 | } 93 | else if (*parts_it != "." && *parts_it != "..") { 94 | canonicalized_path.push_back(*parts_it); 95 | } 96 | 97 | ++parts_it; 98 | } 99 | 100 | vector::const_iterator path_it = canonicalized_path.begin(), 101 | path_end = canonicalized_path.end(); 102 | 103 | string output; 104 | output.reserve(path.size()); 105 | output += "/"; 106 | while (path_it != path_end) { 107 | output += *path_it; 108 | 109 | ++path_it; 110 | if (path_it != path_end) { 111 | output += "/"; 112 | } 113 | } 114 | 115 | return output; 116 | } 117 | 118 | /** 119 | * Adapted from an answer by "Mark" from this stack overflow question: 120 | * http://stackoverflow.com/questions/675039/how-can-i-create-directory-tree-in-c-linux 121 | */ 122 | bool mkpath(const string &path) { 123 | bool success = false; 124 | int ret = mkdir(path.c_str(), 0775); 125 | if(ret == -1) { 126 | switch(errno) { 127 | case ENOENT: 128 | if(mkpath(path.substr(0, path.find_last_of('/')))) 129 | success = 0 == mkdir(path.c_str(), 0775); 130 | else 131 | success = false; 132 | break; 133 | case EEXIST: 134 | success = true; 135 | break; 136 | default: 137 | success = false; 138 | break; 139 | } 140 | } 141 | else { 142 | success = true; 143 | } 144 | 145 | return success; 146 | } 147 | 148 | /** 149 | * Adapted from an answer by "asveikau" from this stack overflow question: 150 | * http://stackoverflow.com/questions/2256945/removing-a-non-empty-directory-programmatically-in-c-or-c 151 | */ 152 | bool rmpath(const char* path) { 153 | DIR *d = opendir(path); 154 | size_t path_len = strlen(path); 155 | int r = -1; 156 | 157 | if (d) { 158 | struct dirent *p; 159 | 160 | r = 0; 161 | 162 | while (!r && (p=readdir(d))) { 163 | int r2 = -1; 164 | char *buf; 165 | size_t len; 166 | 167 | /* Skip the names "." and ".." as we don't want to recurse on them. */ 168 | if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) { 169 | continue; 170 | } 171 | 172 | len = path_len + strlen(p->d_name) + 2; 173 | buf = (char*)malloc(len); 174 | 175 | if (buf) { 176 | struct stat statbuf; 177 | 178 | snprintf(buf, len, "%s/%s", path, p->d_name); 179 | 180 | if (!stat(buf, &statbuf)) { 181 | if (S_ISDIR(statbuf.st_mode)) { 182 | r2 = rmpath(buf); 183 | } 184 | else { 185 | r2 = unlink(buf); 186 | } 187 | } 188 | 189 | free(buf); 190 | } 191 | 192 | r = r2; 193 | } 194 | 195 | closedir(d); 196 | } 197 | 198 | if (!r) { 199 | r = rmdir(path); 200 | } 201 | 202 | return r; 203 | } 204 | -------------------------------------------------------------------------------- /scheduler/compileserver.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2004 Michael Matz 7 | 2004 Stephan Kulow 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License along 20 | with this program; if not, write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #ifndef COMPILESERVER_H 25 | #define COMPILESERVER_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "../services/comm.h" 32 | #include "jobstat.h" 33 | 34 | class Job; 35 | 36 | using namespace std; 37 | 38 | /* One compile server (receiver, compile daemon) */ 39 | class CompileServer : public MsgChannel 40 | { 41 | public: 42 | enum State { 43 | CONNECTED, 44 | LOGGEDIN 45 | }; 46 | 47 | enum Type { 48 | UNKNOWN, 49 | DAEMON, 50 | MONITOR, 51 | LINE 52 | }; 53 | 54 | CompileServer(const int fd, struct sockaddr *_addr, const socklen_t _len, const bool text_based); 55 | 56 | void pick_new_id(); 57 | 58 | bool check_remote(const Job *job) const; 59 | bool platforms_compatible(const string &target) const; 60 | string can_install(const Job *job); 61 | bool is_eligible(const Job *job); 62 | 63 | unsigned int remotePort() const; 64 | void setRemotePort(const unsigned int port); 65 | 66 | unsigned int hostId() const; 67 | void setHostId(const unsigned int id); 68 | 69 | string nodeName() const; 70 | void setNodeName(const string &name); 71 | 72 | bool matches(const string& nm) const; 73 | 74 | time_t busyInstalling() const; 75 | void setBusyInstalling(const time_t time); 76 | 77 | string hostPlatform() const; 78 | void setHostPlatform(const string &platform); 79 | 80 | unsigned int load() const; 81 | void setLoad(const unsigned int load); 82 | 83 | int maxJobs() const; 84 | void setMaxJobs(const int jobs); 85 | 86 | bool noRemote() const; 87 | void setNoRemote(const bool value); 88 | 89 | list jobList() const; 90 | void appendJob(Job *job); 91 | void removeJob(Job *job); 92 | unsigned int lastPickedId(); 93 | 94 | State state() const; 95 | void setState(const State state); 96 | 97 | Type type() const; 98 | void setType(const Type type); 99 | 100 | bool chrootPossible() const; 101 | void setChrootPossible(const bool possible); 102 | 103 | int clientCount() const; 104 | void setClientCount( int clientCount ); 105 | int submittedJobsCount() const; 106 | void submittedJobsIncrement(); 107 | void submittedJobsDecrement(); 108 | 109 | Environments compilerVersions() const; 110 | void setCompilerVersions(const Environments &environments); 111 | 112 | list lastCompiledJobs() const; 113 | void appendCompiledJob(const JobStat &stats); 114 | void popCompiledJob(); 115 | 116 | list lastRequestedJobs() const; 117 | void appendRequestedJobs(const JobStat &stats); 118 | void popRequestedJobs(); 119 | 120 | JobStat cumCompiled() const; 121 | void setCumCompiled(const JobStat &stats); 122 | 123 | JobStat cumRequested() const; 124 | void setCumRequested(const JobStat &stats); 125 | 126 | 127 | unsigned int hostidCounter() const; 128 | 129 | int getClientJobId(const int localJobId); 130 | void insertClientJobId(const int localJobId, const int newJobId); 131 | void eraseClientJobId(const int localJobId); 132 | 133 | map blacklist() const; 134 | Environments getEnvsForBlacklistedCS(CompileServer *cs); 135 | void blacklistCompileServer(CompileServer *cs, const std::pair &env); 136 | void eraseCSFromBlacklist(CompileServer *cs); 137 | 138 | int getInFd() const; 139 | void startInConnectionTest(); 140 | time_t getConnectionTimeout(); 141 | time_t getNextTimeout(); 142 | bool getConnectionInProgress(); 143 | bool isConnected(); 144 | void updateInConnectivity(bool acceptingIn); 145 | 146 | private: 147 | bool blacklisted(const Job *job, const pair &environment); 148 | 149 | /* The listener port, on which it takes compile requests. */ 150 | unsigned int m_remotePort; 151 | unsigned int m_hostId; 152 | string m_nodeName; 153 | time_t m_busyInstalling; 154 | string m_hostPlatform; 155 | 156 | // LOAD is load * 1000 157 | unsigned int m_load; 158 | int m_maxJobs; 159 | bool m_noRemote; 160 | list m_jobList; 161 | State m_state; 162 | Type m_type; 163 | bool m_chrootPossible; 164 | int m_clientCount; // number of client connections the daemon has 165 | int m_submittedJobsCount; 166 | unsigned int m_lastPickId; 167 | 168 | Environments m_compilerVersions; // Available compilers 169 | 170 | list m_lastCompiledJobs; 171 | list m_lastRequestedJobs; 172 | JobStat m_cumCompiled; // cumulated 173 | JobStat m_cumRequested; 174 | 175 | static unsigned int s_hostIdCounter; 176 | map m_clientMap; // map client ID for daemon to our IDs 177 | map m_blacklist; 178 | 179 | int m_inFd; 180 | unsigned int m_inConnAttempt; 181 | time_t m_nextConnTime; 182 | time_t m_lastConnStartTime; 183 | bool m_acceptingInConnection; 184 | }; 185 | 186 | #endif 187 | -------------------------------------------------------------------------------- /doc/man-iceccd.1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | iceccd"> 6 | ]> 7 | 8 | 9 | 10 | 11 | Icecream User's Manual 12 | 13 | 14 | Cornelius 15 | Schumacher 16 | 17 | 18 | April 21th, 2005 19 | Icecream 20 | 21 | 22 | 23 | iceccd 24 | 1 25 | 26 | 27 | 28 | iceccd 29 | Icecream daemon 30 | 31 | 32 | 33 | 34 | iceccd 35 | -b env-basedir 36 | --cache-limit MB 37 | -d 38 | -l log-file 39 | -m max-processes 40 | -N hostname 41 | -n node-name 42 | --nice level 43 | --no-remote 44 | -s scheduler-host 45 | -u user 46 | -vvv 47 | 48 | 49 | 50 | 51 | Description 52 | The Icecream daemon has to run on all nodes being part of the Icecream 53 | compile cluster. It receives compile jobs and executes them in a chroot 54 | environment. The compile clients send their compile environment the first time 55 | they send a job to a particular daemon, so that the environment of the daemon 56 | does not have to match the one of the client. 57 | 58 | The daemon also has to run on clients sending compile jobs to the Icecream 59 | network. If a node should be able to send compile jobs, but never receive any, 60 | start the daemon with the option . 61 | 62 | All Icecream daemons need to have contact to the Icecream scheduler which 63 | controls the distribution of data between compile nodes. Normally the daemon 64 | will automatically find the right scheduler. If this is not the case you can 65 | explicitly specify the name of the Icecream network and the host running the 66 | scheduler. 67 | 68 | 69 | 70 | 71 | Options 72 | 73 | 74 | 75 | 76 | , 77 | env-basedir 78 | Base directory for storing compile environments sent to the 79 | daemon by the compile clients. 80 | 81 | 82 | 83 | MB 84 | Maximum size in Mega Bytes of cache used to store compile 85 | environments of compile clients. 86 | 87 | 88 | 89 | , 90 | Detach daemon from shell. 91 | 92 | 93 | 94 | , 95 | Print help message and exit. 96 | 97 | 98 | 99 | , 100 | log-file 101 | Name of file where log output is written to. 102 | 103 | 104 | 105 | , 106 | max-processes 107 | Maximum number of compile jobs started in parallel on machine 108 | running the daemon. 109 | 110 | 111 | 112 | hostname 113 | The name of the icecream host on the network. 114 | 115 | 116 | 117 | , , 118 | net-name 119 | The name of the icecream network the daemon should connect to. 120 | There has to be a scheduler running for the network under the same network 121 | name. 122 | 123 | 124 | 125 | level 126 | The level of niceness to use. Default is 5. 127 | 128 | 129 | 130 | 131 | Prevents jobs from other nodes being scheduled on this one. 132 | 133 | 134 | 135 | , 136 | scheduler-host 137 | Name of host running the scheduler for the network the daemon 138 | should connect to. This option might help if the scheduler cannot broadcast its 139 | presence to the clients due to firewall settings or similar 140 | reasons, when this is enabled scheduler should use --persistent-client-connection. 141 | 142 | 143 | 144 | , 145 | user 146 | Specify the system user used by the daemon, which must be 147 | different than root. If not specified, the daemon defaults 148 | to the icecc system user if available, or nobody 149 | if not. 150 | 151 | 152 | 153 | , , 154 | Control verbosity of daemon. The more v the more 155 | verbose. 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | See Also 164 | icecream(7), icecc-scheduler(1), icemon(1) 165 | 166 | 167 | 168 | Author 169 | Cornelius Schumacher 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /services/logging.cpp: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2004 Stephan Kulow 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include 24 | #include 25 | #include "logging.h" 26 | #include 27 | #include 28 | #include 29 | #include 30 | #ifdef __linux__ 31 | #include 32 | #endif 33 | 34 | using namespace std; 35 | 36 | int debug_level = Error; 37 | ostream *logfile_trace = 0; 38 | ostream *logfile_info = 0; 39 | ostream *logfile_warning = 0; 40 | ostream *logfile_error = 0; 41 | string logfile_prefix; 42 | volatile sig_atomic_t reset_debug_needed = 0; 43 | 44 | static ofstream logfile_null("/dev/null"); 45 | static ofstream logfile_file; 46 | static string logfile_filename; 47 | 48 | static void reset_debug_signal_handler(int); 49 | 50 | // Implementation of an iostream helper that allows redirecting output to a given file descriptor. 51 | // This seems to be the only portable way to do it. 52 | namespace 53 | { 54 | class ofdbuf : public streambuf 55 | { 56 | public: 57 | explicit ofdbuf( int fd ) : fd( fd ) {} 58 | virtual int_type overflow( int_type c ); 59 | virtual streamsize xsputn( const char* c, streamsize n ); 60 | private: 61 | int fd; 62 | }; 63 | 64 | ofdbuf::int_type ofdbuf::overflow( int_type c ) 65 | { 66 | if( c != EOF ) { 67 | char cc = c; 68 | if( write( fd, &cc, 1 ) != 1 ) 69 | return EOF; 70 | } 71 | return c; 72 | } 73 | 74 | streamsize ofdbuf::xsputn( const char* c, streamsize n ) 75 | { 76 | return write( fd, c, n ); 77 | } 78 | 79 | ostream* ccache_stream( int fd ) 80 | { 81 | int status = fcntl( fd, F_GETFL ); 82 | if( status < 0 || ( status & ( O_WRONLY | O_RDWR )) == 0 ) { 83 | // As logging is not set up yet, this will log to stderr. 84 | log_warning() << "UNCACHED_ERR_FD provides an invalid file descriptor, using stderr" << endl; 85 | return &cerr; // fd is not valid fd for writting 86 | } 87 | static ofdbuf buf( fd ); 88 | static ostream stream( &buf ); 89 | return &stream; 90 | } 91 | } // namespace 92 | 93 | void setup_debug(int level, const string &filename, const string &prefix) 94 | { 95 | debug_level = level; 96 | logfile_prefix = prefix; 97 | logfile_filename = filename; 98 | 99 | if (logfile_file.is_open()) { 100 | logfile_file.close(); 101 | } 102 | 103 | ostream *output = 0; 104 | 105 | if (filename.length()) { 106 | logfile_file.clear(); 107 | logfile_file.open(filename.c_str(), fstream::out | fstream::app); 108 | #ifdef __linux__ 109 | 110 | string fname = filename; 111 | if (fname[0] != '/') { 112 | char buf[PATH_MAX]; 113 | 114 | if (getcwd(buf, sizeof(buf))) { 115 | fname.insert(0, "/"); 116 | fname.insert(0, buf); 117 | } 118 | } 119 | 120 | setenv("SEGFAULT_OUTPUT_NAME", fname.c_str(), false); 121 | #endif 122 | output = &logfile_file; 123 | } else if( const char* ccache_err_fd = getenv( "UNCACHED_ERR_FD" )) { 124 | output = ccache_stream( atoi( ccache_err_fd )); 125 | } else { 126 | output = &cerr; 127 | } 128 | 129 | #ifdef __linux__ 130 | (void) dlopen("libSegFault.so", RTLD_NOW | RTLD_LOCAL); 131 | #endif 132 | 133 | if (debug_level >= Debug) { 134 | logfile_trace = output; 135 | } else { 136 | logfile_trace = &logfile_null; 137 | } 138 | 139 | if (debug_level >= Info) { 140 | logfile_info = output; 141 | } else { 142 | logfile_info = &logfile_null; 143 | } 144 | 145 | if (debug_level >= Warning) { 146 | logfile_warning = output; 147 | } else { 148 | logfile_warning = &logfile_null; 149 | } 150 | 151 | if (debug_level >= Error) { 152 | logfile_error = output; 153 | } else { 154 | logfile_error = &logfile_null; 155 | } 156 | 157 | signal(SIGHUP, reset_debug_signal_handler); 158 | } 159 | 160 | void reset_debug() 161 | { 162 | setup_debug(debug_level, logfile_filename); 163 | } 164 | 165 | void reset_debug_signal_handler(int) 166 | { 167 | reset_debug_needed = 1; 168 | } 169 | 170 | void reset_debug_if_needed() 171 | { 172 | if( reset_debug_needed ) { 173 | reset_debug_needed = 0; 174 | reset_debug(); 175 | if( const char* env = getenv( "ICECC_TEST_FLUSH_LOG_MARK" )) { 176 | ifstream markfile( env ); 177 | string mark; 178 | getline( markfile, mark ); 179 | if( !mark.empty()) { 180 | assert( logfile_trace != NULL ); 181 | *logfile_trace << "flush log mark: " << mark << endl; 182 | } 183 | } 184 | if( const char* env = getenv( "ICECC_TEST_LOG_HEADER" )) { 185 | ifstream markfile( env ); 186 | string header1, header2, header3; 187 | getline( markfile, header1 ); 188 | getline( markfile, header2 ); 189 | getline( markfile, header3 ); 190 | if( !header1.empty()) { 191 | assert( logfile_trace != NULL ); 192 | *logfile_trace << header1 << endl; 193 | *logfile_trace << header2 << endl; 194 | *logfile_trace << header3 << endl; 195 | } 196 | } 197 | } 198 | } 199 | 200 | void close_debug() 201 | { 202 | if (logfile_null.is_open()) { 203 | logfile_null.close(); 204 | } 205 | 206 | if (logfile_file.is_open()) { 207 | logfile_file.close(); 208 | } 209 | 210 | logfile_trace = logfile_info = logfile_warning = logfile_error = 0; 211 | } 212 | 213 | /* Flushes all ostreams used for debug messages. You need to call 214 | this before forking. */ 215 | void flush_debug() 216 | { 217 | if (logfile_null.is_open()) { 218 | logfile_null.flush(); 219 | } 220 | 221 | if (logfile_file.is_open()) { 222 | logfile_file.flush(); 223 | } 224 | } 225 | 226 | unsigned log_block::nesting; 227 | -------------------------------------------------------------------------------- /services/job.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | This file is part of Icecream. 5 | 6 | Copyright (c) 2004-2014 Stephan Kulow 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #ifndef ICECREAM_COMPILE_JOB_H 24 | #define ICECREAM_COMPILE_JOB_H 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | typedef enum { 32 | Arg_Local, // Local-only args. 33 | Arg_Remote, // Remote-only args. 34 | Arg_Rest // Args to use both locally and remotely. 35 | } Argument_Type; 36 | 37 | class ArgumentsList : public std::list > 38 | { 39 | public: 40 | void append(std::string s, Argument_Type t) { 41 | push_back(make_pair(s, t)); 42 | } 43 | }; 44 | 45 | class CompileJob 46 | { 47 | public: 48 | typedef enum { 49 | Lang_C, 50 | Lang_CXX, 51 | Lang_OBJC, 52 | Lang_OBJCXX, 53 | Lang_Custom 54 | } Language; 55 | 56 | typedef enum { 57 | Flag_None = 0, 58 | Flag_g = 0x1, 59 | Flag_g3 = 0x2, 60 | Flag_O = 0x4, 61 | Flag_O2 = 0x8, 62 | Flag_Ol2 = 0x10 63 | } Flag; 64 | 65 | CompileJob() 66 | : m_id(0) 67 | , m_dwarf_fission(false) 68 | , m_block_rewrite_includes(false) 69 | { 70 | setTargetPlatform(); 71 | } 72 | 73 | void setCompilerName(const std::string &name) 74 | { 75 | m_compiler_name = name; 76 | } 77 | 78 | std::string compilerName() const 79 | { 80 | return m_compiler_name; 81 | } 82 | 83 | void setLanguage(Language lg) 84 | { 85 | m_language = lg; 86 | } 87 | 88 | Language language() const 89 | { 90 | return m_language; 91 | } 92 | 93 | // Not used remotely. 94 | void setCompilerPathname(const std::string& pathname) 95 | { 96 | m_compiler_pathname = pathname; 97 | } 98 | 99 | // Not used remotely. 100 | // Use find_compiler(), as this may be empty. 101 | std::string compilerPathname() const 102 | { 103 | return m_compiler_pathname; 104 | } 105 | 106 | void setEnvironmentVersion(const std::string &ver) 107 | { 108 | m_environment_version = ver; 109 | } 110 | 111 | std::string environmentVersion() const 112 | { 113 | return m_environment_version; 114 | } 115 | 116 | unsigned int argumentFlags() const; 117 | 118 | void setFlags(const ArgumentsList &flags) 119 | { 120 | m_flags = flags; 121 | } 122 | std::list localFlags() const; 123 | std::list remoteFlags() const; 124 | std::list restFlags() const; 125 | std::list allFlags() const; 126 | 127 | void setInputFile(const std::string &file) 128 | { 129 | m_input_file = file; 130 | } 131 | 132 | std::string inputFile() const 133 | { 134 | return m_input_file; 135 | } 136 | 137 | void setOutputFile(const std::string &file) 138 | { 139 | m_output_file = file; 140 | } 141 | 142 | std::string outputFile() const 143 | { 144 | return m_output_file; 145 | } 146 | 147 | void setDwarfFissionEnabled(bool flag) 148 | { 149 | m_dwarf_fission = flag; 150 | } 151 | 152 | bool dwarfFissionEnabled() const 153 | { 154 | return m_dwarf_fission; 155 | } 156 | 157 | void setWorkingDirectory(const std::string& dir) 158 | { 159 | m_working_directory = dir; 160 | } 161 | 162 | std::string workingDirectory() const 163 | { 164 | return m_working_directory; 165 | } 166 | 167 | void setJobID(unsigned int id) 168 | { 169 | m_id = id; 170 | } 171 | 172 | unsigned int jobID() const 173 | { 174 | return m_id; 175 | } 176 | 177 | void appendFlag(std::string arg, Argument_Type argumentType) 178 | { 179 | m_flags.append(arg, argumentType); 180 | } 181 | 182 | std::string targetPlatform() const 183 | { 184 | return m_target_platform; 185 | } 186 | 187 | void setTargetPlatform(const std::string &_target) 188 | { 189 | m_target_platform = _target; 190 | } 191 | 192 | // Not used remotely. 193 | void setBlockRewriteIncludes(bool flag) 194 | { 195 | m_block_rewrite_includes = flag; 196 | } 197 | 198 | // Not used remotely. 199 | bool blockRewriteIncludes() const 200 | { 201 | return m_block_rewrite_includes; 202 | } 203 | 204 | private: 205 | std::list flags(Argument_Type argumentType) const; 206 | void setTargetPlatform(); 207 | 208 | unsigned int m_id; 209 | Language m_language; 210 | std::string m_compiler_pathname; 211 | std::string m_compiler_name; 212 | std::string m_environment_version; 213 | ArgumentsList m_flags; 214 | std::string m_input_file, m_output_file; 215 | std::string m_working_directory; 216 | std::string m_target_platform; 217 | bool m_dwarf_fission; 218 | bool m_block_rewrite_includes; 219 | }; 220 | 221 | inline void appendList(std::list &list, const std::list &toadd) 222 | { 223 | // Cannot splice since toadd is a reference-to-const 224 | list.insert(list.end(), toadd.begin(), toadd.end()); 225 | } 226 | 227 | inline std::ostream &operator<<( std::ostream &output, 228 | const CompileJob::Language &l ) 229 | { 230 | switch (l) { 231 | case CompileJob::Lang_CXX: 232 | output << "C++"; 233 | break; 234 | case CompileJob::Lang_C: 235 | output << "C"; 236 | break; 237 | case CompileJob::Lang_Custom: 238 | output << ""; 239 | break; 240 | case CompileJob::Lang_OBJC: 241 | output << "ObjC"; 242 | break; 243 | case CompileJob::Lang_OBJCXX: 244 | output << "ObjC++"; 245 | break; 246 | } 247 | return output; 248 | } 249 | 250 | inline std::string concat_args(const std::list &args) 251 | { 252 | std::stringstream str; 253 | str << "'"; 254 | 255 | for (std::list::const_iterator it = args.begin(); it != args.end();) { 256 | str << *it++; 257 | if (it != args.end()) 258 | str << ", "; 259 | } 260 | return str.str() + "'"; 261 | } 262 | 263 | #endif 264 | -------------------------------------------------------------------------------- /client/cpp.cpp: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | * distcc -- A simple distributed compiler system 5 | * 6 | * Copyright (C) 2002, 2003 by Martin Pool 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License along 19 | * with this program; if not, write to the Free Software Foundation, Inc., 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | /** 24 | * @file 25 | * 26 | * Run the preprocessor. Client-side only. 27 | **/ 28 | 29 | #include "config.h" 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "client.h" 39 | 40 | using namespace std; 41 | 42 | bool dcc_is_preprocessed(const string &sfile) 43 | { 44 | if (sfile.size() < 3) { 45 | return false; 46 | } 47 | 48 | int last = sfile.size() - 1; 49 | 50 | if ((sfile[last - 1] == '.') && (sfile[last] == 'i')) { 51 | return true; // .i 52 | } 53 | 54 | if ((sfile[last - 2] == '.') && (sfile[last - 1] == 'i') && (sfile[last] == 'i')) { 55 | return true; // .ii 56 | } 57 | 58 | return false; 59 | } 60 | 61 | /** 62 | * If the input filename is a plain source file rather than a 63 | * preprocessed source file, then preprocess it to a temporary file 64 | * and return the name in @p cpp_fname. 65 | * 66 | * The preprocessor may still be running when we return; you have to 67 | * wait for @p cpp_fid to exit before the output is complete. This 68 | * allows us to overlap opening the TCP socket, which probably doesn't 69 | * use many cycles, with running the preprocessor. 70 | **/ 71 | pid_t call_cpp(CompileJob &job, int fdwrite, int fdread) 72 | { 73 | flush_debug(); 74 | pid_t pid = fork(); 75 | 76 | if (pid == -1) { 77 | log_perror("failed to fork:"); 78 | return -1; /* probably */ 79 | } 80 | 81 | if (pid != 0) { 82 | /* Parent. Close the write fd. */ 83 | if (fdwrite > -1) { 84 | if ((-1 == close(fdwrite)) && (errno != EBADF)){ 85 | log_perror("close() failed"); 86 | } 87 | } 88 | 89 | return pid; 90 | } 91 | 92 | /* Child. Close the read fd, in case we have one. */ 93 | if (fdread > -1) { 94 | if ((-1 == close(fdread)) && (errno != EBADF)){ 95 | log_perror("close failed"); 96 | } 97 | } 98 | 99 | int ret = dcc_ignore_sigpipe(0); 100 | 101 | if (ret) { /* set handler back to default */ 102 | _exit(ret); 103 | } 104 | 105 | char **argv; 106 | 107 | if (dcc_is_preprocessed(job.inputFile())) { 108 | /* already preprocessed, great. 109 | write the file to the fdwrite (using cat) */ 110 | argv = new char*[2 + 1]; 111 | argv[0] = strdup("/bin/cat"); 112 | argv[1] = strdup(job.inputFile().c_str()); 113 | argv[2] = 0; 114 | } else { 115 | list flags = job.localFlags(); 116 | appendList(flags, job.restFlags()); 117 | 118 | for (list::iterator it = flags.begin(); it != flags.end();) { 119 | /* This has a duplicate meaning. it can either include a file 120 | for preprocessing or a precompiled header. decide which one. */ 121 | if ((*it) == "-include") { 122 | ++it; 123 | 124 | if (it != flags.end()) { 125 | std::string p = (*it); 126 | 127 | if (access(p.c_str(), R_OK) < 0 && access((p + ".gch").c_str(), R_OK) == 0) { 128 | // PCH is useless for preprocessing, ignore the flag. 129 | list::iterator o = --it; 130 | it++; 131 | flags.erase(o); 132 | o = it++; 133 | flags.erase(o); 134 | } 135 | } 136 | } else if ((*it) == "-include-pch") { 137 | list::iterator o = it; 138 | ++it; 139 | if (it != flags.end()) { 140 | std::string p = (*it); 141 | if (access(p.c_str(), R_OK) == 0) { 142 | // PCH is useless for preprocessing (and probably slows things down), ignore the flag. 143 | flags.erase(o); 144 | o = it++; 145 | flags.erase(o); 146 | } 147 | } 148 | } else if ((*it) == "-fpch-preprocess") { 149 | // This would add #pragma GCC pch_preprocess to the preprocessed output, which would make 150 | // the remote GCC try to load the PCH directly and fail. Just drop it. This may cause a build 151 | // failure if the -include check above failed to detect usage of a PCH file (e.g. because 152 | // it needs to be found in one of the -I paths, which we don't check) and the header file 153 | // itself doesn't exist. 154 | flags.erase(it++); 155 | } else { 156 | ++it; 157 | } 158 | } 159 | 160 | int argc = flags.size(); 161 | argc++; // the program 162 | argc += 2; // -E file.i 163 | argc += 1; // -frewrite-includes / -fdirectives-only 164 | argv = new char*[argc + 1]; 165 | argv[0] = strdup(find_compiler(job).c_str()); 166 | int i = 1; 167 | 168 | for (list::const_iterator it = flags.begin(); it != flags.end(); ++it) { 169 | argv[i++] = strdup(it->c_str()); 170 | } 171 | 172 | argv[i++] = strdup("-E"); 173 | argv[i++] = strdup(job.inputFile().c_str()); 174 | 175 | if (compiler_only_rewrite_includes(job)) { 176 | if( compiler_is_clang(job)) { 177 | argv[i++] = strdup("-frewrite-includes"); 178 | } else { // gcc 179 | argv[i++] = strdup("-fdirectives-only"); 180 | } 181 | } 182 | 183 | argv[i++] = 0; 184 | } 185 | 186 | string argstxt = argv[ 0 ]; 187 | for( int i = 1; argv[ i ] != NULL; ++i ) { 188 | argstxt += ' '; 189 | argstxt += argv[ i ]; 190 | } 191 | trace() << "preparing source to send: " << argstxt << endl; 192 | 193 | if (fdwrite != STDOUT_FILENO) { 194 | /* Ignore failure */ 195 | close(STDOUT_FILENO); 196 | dup2(fdwrite, STDOUT_FILENO); 197 | close(fdwrite); 198 | } 199 | 200 | dcc_increment_safeguard(SafeguardStepCompiler); 201 | execv(argv[0], argv); 202 | int exitcode = ( errno == ENOENT ? 127 : 126 ); 203 | log_perror("execv failed"); 204 | _exit(exitcode); 205 | } 206 | -------------------------------------------------------------------------------- /BENCH: -------------------------------------------------------------------------------- 1 | 2 | There were no structured benchmarks of icecream, so I started some. I'm benchmarking 5 runs 3 | each, throwing away the worst and the best run, and then averaging the rest of the 3. 4 | There are two machines in the cluster, both single cpu and both about the same speed (1.7GHz 5 | Pentium M). Normally the tests are done via otherwise idle WLAN (54MBit). WLAN has a bad 6 | latency and very bad throughput, which gives icecream a hard time, and should be compareable 7 | to a loaded cabled network environment. For comparison, I repeated some tests via 100MBit 8 | cabled LAN. 9 | 10 | I'm testing linux 2.6.16 (defconfig), which is a set of small C files with sometimes larger 11 | C files inbetween. its a tough benchmark because compiling C is rather quick, so remote 12 | overhead has to be low. 13 | 14 | No icecream: 15 | 16 | make -j1: 315s 17 | make -j2: 322s 18 | make -j3: 324s 19 | make -j10: 334s 20 | 21 | result: without icecream, starting more compilers than CPUs available is a bad idea. 22 | 23 | 24 | icecream wrapper, no scheduler. 25 | 26 | make -j1: 323s 27 | make -j10: 340s 28 | 29 | result: Overhead of just using icecream without cluster is neglectible (2%) in all cases. 30 | 31 | dirk's no-latency icecream: remote daemon with -m 1: 32 | 33 | make -j1: 418s 34 | make -j2: 397s 35 | make -j3: 263s 36 | make -j10: 230s 37 | make -j10/100: 203s 38 | make -j100: 231s 39 | make -j10/100: 202s 40 | 41 | result: Enabling icecream without parallel compilation is a horrible mistake. icecream 42 | must be tuned to detect and compensate this situation better. Maximum performance 43 | improvement of icecream is 27% (LAN: 36%) out of the theoretical 50%. 44 | 45 | ====================================================================== 46 | 47 | Qt 3.3.6's src/ subdirectory. This is a bunch of medium and large C++ files. It 48 | gives icecream good opportunities because compilation time is comparatively low 49 | and the preprocessed files are not too large (low STL usage). 50 | 51 | 52 | No icecream: 53 | 54 | make -j1: 368s 55 | make -j3: 363s 56 | 57 | result: apparently there is a small win by starting more compilers than CPUs in parallel. 58 | Perhaps the I/O overhead is not neglectible like in the linux kernel case. 59 | 60 | dirk's no-latency icecream, remote daemon with -m 2: 61 | 62 | make -j1: 572s 63 | make -j3: 273s 64 | make -j10: 269s 65 | make -j10/100: 239s 66 | make -j100: 282s 67 | 68 | result: again, not compiling in parallel is a deadly sin. trying to overload the cluster 69 | with very high parallelism as well. Maximum performance improvement is again 27% and 70 | 36% for LAN. That these numbers compare equally with the Linux kernel case is astonishing 71 | and needs explanation. 72 | 73 | Now, to make sure that the no-latency patch hasn't regressed anything, we're comparing with 74 | stock 0.7 (which already has some performance improvements over 0.6): 75 | 76 | 77 | make -j1: 569s 78 | make -j10: 349s 79 | make -j10/100: 253s 80 | make -j100/100: 278s 81 | 82 | It is remarkable, that 0.7 does not provide much advantage over compiling locally (6% speedup) 83 | in a WLAN, while providing the expected 36% speedup for LAN. This proves that no-latency 84 | provides significant wins for unstable/bad network connections and does not regress 85 | performance for good networking setups. The overall 20% improvement is not bad at all. 86 | 87 | 2006-06-16 make-it-cool-branch: 88 | 89 | make -j10/100: 244s 90 | make -j1: 376s 91 | 92 | result: correcting process accounting for local jobs makes -j1 fast again (just 2% overhead) 93 | 94 | icecream, always compile remote even though host is not faster: 95 | 96 | make -j10: 538s 97 | make -j10/sched: 389s 98 | 99 | As we can see, the scheduler improves performance by 38%. 100 | 101 | 102 | ====================================================================== 103 | 104 | New performance experiments. 105 | 106 | New baseline: 107 | 108 | make-it-cool, both with -m 1, make -j5 109 | 110 | make -j5 : 382s 111 | make -j5 : 354s 112 | make -j5 : 336s 113 | make -j5 : 355s 114 | 115 | remote with -m 2 116 | 117 | make -j5 : 333s 118 | make -j5 : 299s 119 | make -j5 : 307s 120 | 121 | remote with -m 2, preload scheduler: 122 | 123 | make -j5 : 303s 124 | make -j5 : 287s 125 | make -j5 : 291s 126 | 127 | remote with -m 1, preload scheduler: 128 | 129 | make -j5 : 287s 130 | make -j5 : 288s 131 | make -j5 : 289s 132 | 133 | remote with -m 1, preload scheduler, optimized return: 134 | make -j5 : 288s 135 | make -j5 : 289s 136 | make -j5 : 288s 137 | 138 | remote with -m 2, preload scheduler, optimized return: 139 | make -j5 : 279s 140 | make -j5 : 281s 141 | make -j5 : 278s 142 | 143 | As we can see, over-booking the remote slave improves performance by 13%. 144 | As the CPU hardly gets faster, it means that we're reducing idle wait time 145 | this way. 146 | 147 | One experiment was to pre-load jobs on the remote slave. This means even 148 | though all compile slots are filled, it gets one (exactly one) job assigned. 149 | The daemon itself will start compilation as soon as it gets a free slot, 150 | reducing both client<->CS and CS<->scheduler roundtrip. Overall, it gave an 151 | impressive 4% speedup. 152 | 153 | A lot of time is however spent on writing back the compiled object file 154 | to the client, and this is dominated by network saturation and latency 155 | and not by CPU usage. The obvious solution is to notify the scheduler 156 | about a free slot as soon as compilation (but not write-back) has 157 | finished. With remote over-booking this resulted in another 3% speedup, 158 | while no improvements could be measured in the -m 1 case. Given that 159 | it significantly reduced code complexity in the daemon, it should still be 160 | an improvement (reduced code size by almost 8%!). 161 | 162 | ====================================================================== 163 | 164 | Load detection tunings. 165 | 166 | The biggest problem with accurate load detection is that it is impossible 167 | to find out how much cpu time a iceccd child is currently using. All you 168 | can get is how much time it used overall, but only when it exited. 169 | Which gives you a lot of cpu-usage peaks sprinkled over time, and you have 170 | to somehow average that out in a meaningful way. 171 | 172 | Actually, the Linux kernel tracks cpu time, and you can read it in 173 | /proc//stat for any child. unfortunately it is converted to seconds 174 | in there, so resolution isn't much more accurate. 175 | 176 | Watching the old load detector, it became obvious that it once in a 177 | while jumps to 1000 because of own jobs eating 100% cpu, but not finishing 178 | within the measure timeframe, which causes the host to be blacklisted 179 | by the scheduler, even though nothing is wrong with it. 180 | 181 | There are two solutions: 182 | 183 | - trying to get a more accurate usage over time 184 | 185 | - only track usage whenever it is accurate, e.g. a child exited. 186 | 187 | As the second possibility has problems with multi-cpu environments (you'd 188 | have to wait for all jobs to finish before doing another idleness sample, 189 | which probably reduces throughput considerably), first one was chosen. 190 | 191 | Simplest idea: assume that overall system nice load is at least partially 192 | caused by our own childs. 193 | 194 | remote with -m 2: 195 | make -j5 : 272s 196 | make -j5 : 274s 197 | make -j5 : 271s 198 | 199 | Hmm.. 2% win. 200 | 201 | ============================================================================ 202 | 203 | New baseline: 0.8.0: 204 | 205 | remote with -m 1: 206 | make -j5 : 257s 207 | 208 | without compression: 209 | 210 | make -j5: 442s 211 | 212 | -------------------------------------------------------------------------------- /services/getifaddrs.cpp: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* getifaddrs -- get names and addresses of all network interfaces 4 | Copyright (C) 1999,2002 Free Software Foundation, Inc. 5 | This file is part of the GNU C Library. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | 22 | /** 23 | * 02-12-26, tim@tjansen.de: put in kde_ namespace, C++ fixes, 24 | * included ifreq.h 25 | * removed glibc dependencies 26 | */ 27 | 28 | #include "config.h" 29 | 30 | #ifndef HAVE_IFADDRS_H 31 | 32 | #include "getifaddrs.h" 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #ifndef IF_NAMESIZE 44 | #define IF_NAMESIZE IFNAMSIZ 45 | #endif 46 | 47 | #ifdef SIOCGIFCONF 48 | 49 | #define old_siocgifconf 0 50 | 51 | static inline void __ifreq(struct ifreq **ifreqs, int *num_ifs, int sockfd) 52 | { 53 | int fd = sockfd; 54 | struct ifconf ifc; 55 | int rq_len; 56 | int nifs; 57 | # define RQ_IFS 4 58 | 59 | if (fd < 0) { 60 | fd = socket(AF_INET, SOCK_DGRAM, 0); 61 | } 62 | 63 | if (fd < 0) { 64 | *num_ifs = 0; 65 | *ifreqs = NULL; 66 | return; 67 | } 68 | 69 | ifc.ifc_buf = NULL; 70 | 71 | /* We may be able to get the needed buffer size directly, rather than 72 | guessing. */ 73 | if (! old_siocgifconf) { 74 | ifc.ifc_buf = NULL; 75 | ifc.ifc_len = 0; 76 | 77 | if (ioctl(fd, SIOCGIFCONF, &ifc) < 0 || ifc.ifc_len == 0) { 78 | rq_len = RQ_IFS * sizeof(struct ifreq); 79 | } else { 80 | rq_len = ifc.ifc_len; 81 | } 82 | } else { 83 | rq_len = RQ_IFS * sizeof(struct ifreq); 84 | } 85 | 86 | /* Read all the interfaces out of the kernel. */ 87 | while (1) { 88 | ifc.ifc_len = rq_len; 89 | ifc.ifc_buf = (char *) realloc(ifc.ifc_buf, ifc.ifc_len); 90 | 91 | if (ifc.ifc_buf == NULL || ioctl(fd, SIOCGIFCONF, &ifc) < 0) { 92 | if (ifc.ifc_buf) { 93 | free(ifc.ifc_buf); 94 | } 95 | 96 | if (fd != sockfd) { 97 | if ((-1 == close(fd)) && (errno != EBADF)){ 98 | log_perror("close failed"); 99 | } 100 | } 101 | 102 | *num_ifs = 0; 103 | *ifreqs = NULL; 104 | return; 105 | } 106 | 107 | if (!old_siocgifconf || ifc.ifc_len < rq_len) { 108 | break; 109 | } 110 | 111 | rq_len *= 2; 112 | } 113 | 114 | nifs = ifc.ifc_len / sizeof(struct ifreq); 115 | 116 | if (fd != sockfd) { 117 | if ((-1 == close(fd)) && (errno != EBADF)){ 118 | log_perror("close failed"); 119 | } 120 | } 121 | 122 | *num_ifs = nifs; 123 | *ifreqs = (ifreq *)realloc(ifc.ifc_buf, nifs * sizeof(struct ifreq)); 124 | } 125 | 126 | static inline struct ifreq *__if_nextreq(struct ifreq *ifr) { 127 | return ifr + 1; 128 | } 129 | 130 | static inline void __if_freereq(struct ifreq *ifreqs, int num_ifs) 131 | { 132 | free(ifreqs); 133 | } 134 | 135 | /* Create a linked list of `struct kde_ifaddrs' structures, one for each 136 | network interface on the host machine. If successful, store the 137 | list in *IFAP and return 0. On errors, return -1 and set `errno'. */ 138 | int kde_getifaddrs(struct kde_ifaddrs **ifap) 139 | { 140 | /* This implementation handles only IPv4 interfaces. 141 | The various ioctls below will only work on an AF_INET socket. 142 | Some different mechanism entirely must be used for IPv6. */ 143 | int fd = socket(AF_INET, SOCK_DGRAM, 0); 144 | struct ifreq *ifreqs; 145 | int nifs; 146 | 147 | if (fd < 0) { 148 | return -1; 149 | } 150 | 151 | __ifreq(&ifreqs, &nifs, fd); 152 | 153 | if (ifreqs == NULL) { /* XXX doesn't distinguish error vs none */ 154 | if (-1 == close(fd)){ 155 | log_perror("close failed"); 156 | } 157 | return -1; 158 | } 159 | 160 | /* Now we have the list of interfaces and each one's address. 161 | Put it into the expected format and fill in the remaining details. */ 162 | if (nifs == 0) { 163 | *ifap = NULL; 164 | } else { 165 | struct Storage { 166 | struct kde_ifaddrs ia; 167 | struct sockaddr addr, netmask, broadaddr; 168 | char name[IF_NAMESIZE]; 169 | } *storage; 170 | struct ifreq *ifr; 171 | int i; 172 | 173 | storage = (Storage *) malloc(nifs * sizeof storage[0]); 174 | 175 | if (storage == NULL) { 176 | if (-1 == close(fd)){ 177 | log_perror("close failed"); 178 | } 179 | __if_freereq(ifreqs, nifs); 180 | return -1; 181 | } 182 | 183 | i = 0; 184 | ifr = ifreqs; 185 | 186 | do { 187 | /* Fill in all pointers to the storage we've already allocated. */ 188 | storage[i].ia.ifa_next = &storage[i + 1].ia; 189 | storage[i].ia.ifa_addr = &storage[i].addr; 190 | storage[i].ia.ifa_netmask = &storage[i].netmask; 191 | storage[i].ia.ifa_broadaddr = &storage[i].broadaddr; /* & dstaddr */ 192 | 193 | /* Now copy the information we already have from SIOCGIFCONF. */ 194 | storage[i].ia.ifa_name = strncpy(storage[i].name, ifr->ifr_name, 195 | sizeof storage[i].name); 196 | storage[i].addr = ifr->ifr_addr; 197 | 198 | /* The SIOCGIFCONF call filled in only the name and address. 199 | Now we must also ask for the other information we need. */ 200 | 201 | if (ioctl(fd, SIOCGIFFLAGS, ifr) < 0) { 202 | break; 203 | } 204 | 205 | storage[i].ia.ifa_flags = ifr->ifr_flags; 206 | 207 | ifr->ifr_addr = storage[i].addr; 208 | 209 | if (ioctl(fd, SIOCGIFNETMASK, ifr) < 0) { 210 | break; 211 | } 212 | 213 | storage[i].netmask = ifr->ifr_netmask; 214 | 215 | if (ifr->ifr_flags & IFF_BROADCAST) { 216 | ifr->ifr_addr = storage[i].addr; 217 | 218 | if (ioctl(fd, SIOCGIFBRDADDR, ifr) < 0) { 219 | break; 220 | } 221 | 222 | storage[i].broadaddr = ifr->ifr_broadaddr; 223 | } else if (ifr->ifr_flags & IFF_POINTOPOINT) { 224 | ifr->ifr_addr = storage[i].addr; 225 | // Needed on Cygwin 226 | #ifndef SIOCGIFDSTADDR 227 | #define SIOCGIFDSTADDR 0x8917 228 | #endif 229 | 230 | if (ioctl(fd, SIOCGIFDSTADDR, ifr) < 0) { 231 | break; 232 | } 233 | 234 | #if HAVE_IFR_DSTADDR 235 | storage[i].broadaddr = ifr->ifr_dstaddr; 236 | #else 237 | // Fix for Cygwin 238 | storage[i].broadaddr = ifr->ifr_broadaddr; 239 | #endif 240 | } else 241 | /* Just 'cause. */ 242 | { 243 | memset(&storage[i].broadaddr, 0, sizeof storage[i].broadaddr); 244 | } 245 | 246 | storage[i].ia.ifa_data = NULL; /* Nothing here for now. */ 247 | 248 | ifr = __if_nextreq(ifr); 249 | } while (++i < nifs); 250 | 251 | if (i < nifs) { /* Broke out early on error. */ 252 | if (-1 == close(fd)){ 253 | log_perror("close failed"); 254 | } 255 | free(storage); 256 | __if_freereq(ifreqs, nifs); 257 | return -1; 258 | } 259 | 260 | storage[i - 1].ia.ifa_next = NULL; 261 | 262 | *ifap = &storage[0].ia; 263 | 264 | if (-1 == close(fd)){ 265 | log_perror("close failed"); 266 | } 267 | __if_freereq(ifreqs, nifs); 268 | } 269 | 270 | return 0; 271 | } 272 | 273 | void kde_freeifaddrs(struct kde_ifaddrs *ifa) 274 | { 275 | free(ifa); 276 | } 277 | 278 | #else 279 | int kde_getifaddrs(struct kde_ifaddrs **) 280 | { 281 | return 1; 282 | } 283 | void kde_freeifaddrs(struct kde_ifaddrs *) 284 | { 285 | } 286 | struct { } kde_ifaddrs; 287 | 288 | #endif 289 | 290 | #endif 291 | -------------------------------------------------------------------------------- /client/util.cpp: -------------------------------------------------------------------------------- 1 | /* -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 99; -*- */ 2 | /* vim: set ts=4 sw=4 et tw=99: */ 3 | /* 4 | * distcc -- A simple distributed compiler system 5 | * 6 | * Copyright (C) 2002, 2003 by Martin Pool 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License along 19 | * with this program; if not, write to the Free Software Foundation, Inc., 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "config.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | 41 | #include 42 | 43 | #include "client.h" 44 | #include "exitcode.h" 45 | #include "job.h" 46 | #include "logging.h" 47 | #include "util.h" 48 | 49 | using namespace std; 50 | 51 | extern bool explicit_color_diagnostics; 52 | extern bool explicit_no_show_caret; 53 | 54 | /** 55 | * Set the `FD_CLOEXEC' flag of DESC if VALUE is nonzero, 56 | * or clear the flag if VALUE is 0. 57 | * 58 | * From the GNU C Library examples. 59 | * 60 | * @returns 0 on success, or -1 on error with `errno' set. 61 | **/ 62 | int set_cloexec_flag(int desc, int value) 63 | { 64 | int oldflags = fcntl(desc, F_GETFD, 0); 65 | 66 | /* If reading the flags failed, return error indication now. */ 67 | if (oldflags < 0) { 68 | return oldflags; 69 | } 70 | 71 | /* Set just the flag we want to set. */ 72 | if (value != 0) { 73 | oldflags |= FD_CLOEXEC; 74 | } else { 75 | oldflags &= ~FD_CLOEXEC; 76 | } 77 | 78 | /* Store modified flag word in the descriptor. */ 79 | return fcntl(desc, F_SETFD, oldflags); 80 | } 81 | 82 | /** 83 | * Ignore or unignore SIGPIPE. 84 | * 85 | * The server and child ignore it, because distcc code wants to see 86 | * EPIPE errors if something goes wrong. However, for invoked 87 | * children it is set back to the default value, because they may not 88 | * handle the error properly. 89 | **/ 90 | int dcc_ignore_sigpipe(int val) 91 | { 92 | if (signal(SIGPIPE, val ? SIG_IGN : SIG_DFL) == SIG_ERR) { 93 | log_warning() << "signal(SIGPIPE, " << (val ? "ignore" : "default") << ") failed: " 94 | << strerror(errno) << endl; 95 | return EXIT_DISTCC_FAILED; 96 | } 97 | 98 | return 0; 99 | } 100 | 101 | /** 102 | * Return a pointer to the basename of the file (everything after the 103 | * last slash.) If there is no slash, return the whole filename, 104 | * which is presumably in the current directory. 105 | **/ 106 | string find_basename(const string &sfile) 107 | { 108 | size_t index = sfile.find_last_of('/'); 109 | 110 | if (index == string::npos) { 111 | return sfile; 112 | } 113 | 114 | return sfile.substr(index + 1); 115 | } 116 | 117 | string find_prefix(const string &basename) 118 | { 119 | size_t index = basename.find_last_of('-'); 120 | 121 | if (index == string::npos) { 122 | return ""; 123 | } 124 | 125 | return basename.substr(0, index); 126 | } 127 | 128 | /** 129 | * Get an exclusive, non-blocking lock on a file using whatever method 130 | * is available on this system. 131 | * 132 | * @retval 0 if we got the lock 133 | * @retval -1 with errno set if the file is already locked. 134 | **/ 135 | static int sys_lock(int fd, bool block) 136 | { 137 | #if defined(F_SETLK) 138 | struct flock lockparam; 139 | 140 | lockparam.l_type = F_WRLCK; 141 | lockparam.l_whence = SEEK_SET; 142 | lockparam.l_start = 0; 143 | lockparam.l_len = 0; /* whole file */ 144 | 145 | return fcntl(fd, block ? F_SETLKW : F_SETLK, &lockparam); 146 | #elif defined(HAVE_FLOCK) 147 | return flock(fd, LOCK_EX | (block ? 0 : LOCK_NB)); 148 | #elif defined(HAVE_LOCKF) 149 | return lockf(fd, block ? F_LOCK : F_TLOCK, 0); 150 | #else 151 | # error "No supported lock method. Please port this code." 152 | #endif 153 | } 154 | 155 | 156 | bool dcc_unlock(int lock_fd) 157 | { 158 | /* All our current locks can just be closed */ 159 | if (close(lock_fd)) { 160 | log_perror("close failed:"); 161 | return false; 162 | } 163 | 164 | return true; 165 | } 166 | 167 | 168 | /** 169 | * Open a lockfile, creating if it does not exist. 170 | **/ 171 | static bool dcc_open_lockfile(const string &fname, int &plockfd) 172 | { 173 | /* Create if it doesn't exist. We don't actually do anything with 174 | * the file except lock it. 175 | * 176 | * The file is created with the loosest permissions allowed by the user's 177 | * umask, to give the best chance of avoiding problems if they should 178 | * happen to use a shared lock dir. */ 179 | plockfd = open(fname.c_str(), O_WRONLY | O_CREAT, 0666); 180 | 181 | if (plockfd == -1 && errno != EEXIST) { 182 | log_error() << "failed to creat " << fname << ": " << strerror(errno) << endl; 183 | return false; 184 | } 185 | 186 | return true; 187 | } 188 | 189 | bool dcc_lock_host(int &lock_fd) 190 | { 191 | string fname = "/tmp/.icecream-"; 192 | struct passwd *pwd = getpwuid(getuid()); 193 | 194 | if (pwd) { 195 | fname += pwd->pw_name; 196 | } else { 197 | char buffer[12]; 198 | sprintf(buffer, "%ld", (long)getuid()); 199 | fname += buffer; 200 | } 201 | 202 | if (mkdir(fname.c_str(), 0700) && errno != EEXIST) { 203 | log_perror("mkdir") << "\t" << fname << endl; 204 | return false; 205 | } 206 | 207 | fname += "/local_lock"; 208 | 209 | lock_fd = 0; 210 | 211 | if (!dcc_open_lockfile(fname, lock_fd)) { 212 | return false; 213 | } 214 | 215 | if (sys_lock(lock_fd, true) == 0) { 216 | return true; 217 | } 218 | 219 | switch (errno) { 220 | #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN 221 | case EWOULDBLOCK: 222 | #endif 223 | case EAGAIN: 224 | case EACCES: /* HP-UX and Cygwin give this for exclusion */ 225 | trace() << fname << " is busy" << endl; 226 | break; 227 | default: 228 | log_error() << "lock " << fname << " failed: " << strerror(errno) << endl; 229 | break; 230 | } 231 | 232 | if ((-1 == ::close(lock_fd)) && (errno != EBADF)){ 233 | log_perror("close failed"); 234 | } 235 | return false; 236 | } 237 | 238 | bool color_output_possible() 239 | { 240 | const char* term_env = getenv("TERM"); 241 | 242 | return isatty(2) && term_env && strcasecmp(term_env, "DUMB"); 243 | } 244 | 245 | bool compiler_has_color_output(const CompileJob &job) 246 | { 247 | if (!color_output_possible()) 248 | return false; 249 | 250 | // Clang has coloring. 251 | if (compiler_is_clang(job)) { 252 | return true; 253 | } 254 | if (const char* icecc_color_diagnostics = getenv("ICECC_COLOR_DIAGNOSTICS")) { 255 | return *icecc_color_diagnostics == '1'; 256 | } 257 | #ifdef HAVE_GCC_COLOR_DIAGNOSTICS 258 | return true; 259 | #endif 260 | // GCC has it since 4.9, but that'd require detecting what GCC 261 | // version is used for the actual compile. However it requires 262 | // also GCC_COLORS to be set (and not empty), so use that 263 | // for detecting if GCC would use colors. 264 | if (const char *gcc_colors = getenv("GCC_COLORS")) { 265 | return (*gcc_colors != '\0'); 266 | } 267 | return false; 268 | } 269 | 270 | // Whether icecream should add colors to the compiler output. 271 | bool colorify_wanted(const CompileJob &job) 272 | { 273 | if (compiler_has_color_output(job)) { 274 | return false; // -fcolor-diagnostics handling lets the compiler do it itself 275 | } 276 | if (explicit_color_diagnostics) { // colors explicitly enabled/disabled by an option 277 | return false; 278 | } 279 | if (getenv("ICECC_COLOR_DIAGNOSTICS") != NULL) 280 | return false; // if set explicitly, assume icecream's colorify is not wanted 281 | 282 | if (getenv("EMACS")) { 283 | return false; 284 | } 285 | 286 | return color_output_possible(); 287 | } 288 | 289 | void colorify_output(const string &_s_ccout) 290 | { 291 | string s_ccout(_s_ccout); 292 | string::size_type end; 293 | 294 | while ((end = s_ccout.find('\n')) != string::npos) { 295 | 296 | string cline = s_ccout.substr(string::size_type(0), end); 297 | s_ccout = s_ccout.substr(end + 1); 298 | 299 | if (cline.find(": error:") != string::npos) { 300 | fprintf(stderr, "\x1b[1;31m%s\x1b[0m\n", cline.c_str()); 301 | } else if (cline.find(": warning:") != string::npos) { 302 | fprintf(stderr, "\x1b[36m%s\x1b[0m\n", cline.c_str()); 303 | } else { 304 | fprintf(stderr, "%s\n", cline.c_str()); 305 | } 306 | } 307 | 308 | fprintf(stderr, "%s", s_ccout.c_str()); 309 | } 310 | 311 | 312 | bool ignore_unverified() 313 | { 314 | return getenv("ICECC_IGNORE_UNVERIFIED"); 315 | } 316 | 317 | // GCC4.8+ has -fdiagnostics-show-caret, but when it prints the source code, 318 | // it tries to find the source file on the disk, rather than printing the input 319 | // it got like Clang does. This means that when compiling remotely, it of course 320 | // won't find the source file in the remote chroot, and will disable the caret 321 | // silently. As a workaround, make it possible to recompile locally if there's 322 | // any stdout/stderr. 323 | // Another way of handling this might be to send all the headers to the remote 324 | // host, but this has been already tried in the sendheaders branch (for 325 | // preprocessing remotely too) and performance-wise it just doesn't seem to 326 | // be worth it. 327 | bool output_needs_workaround(const CompileJob &job) 328 | { 329 | if (compiler_is_clang(job)) 330 | return false; 331 | if (explicit_no_show_caret) 332 | return false; 333 | if (const char* caret_workaround = getenv("ICECC_CARET_WORKAROUND")) 334 | return *caret_workaround == '1'; 335 | #ifdef HAVE_GCC_SHOW_CARET 336 | return true; 337 | #endif 338 | return false; 339 | } 340 | 341 | int resolve_link(const std::string &file, std::string &resolved) 342 | { 343 | char buf[PATH_MAX]; 344 | buf[PATH_MAX - 1] = '\0'; 345 | const int ret = readlink(file.c_str(), buf, sizeof(buf) - 1); 346 | const int errno_save = errno; 347 | 348 | if (ret <= 0) { 349 | return errno_save; 350 | } 351 | 352 | buf[ret] = 0; 353 | resolved = std::string(buf); 354 | return 0; 355 | } 356 | 357 | std::string get_cwd() 358 | { 359 | static std::vector buffer(1024); 360 | 361 | errno = 0; 362 | while (getcwd(&buffer[0], buffer.size() - 1) == 0 && errno == ERANGE) { 363 | buffer.resize(buffer.size() + 1024); 364 | errno = 0; 365 | } 366 | if (errno != 0) 367 | return std::string(); 368 | 369 | return string(&buffer[0]); 370 | } 371 | 372 | std::string read_command_output(const std::string& command) 373 | { 374 | FILE *f = popen(command.c_str(), "r"); 375 | string output; 376 | 377 | if (!f) { 378 | log_error() << "no pipe " << strerror(errno) << endl; 379 | return output; 380 | } 381 | 382 | char buffer[1024]; 383 | 384 | while (!feof(f)) { 385 | size_t bytes = fread(buffer, 1, sizeof(buffer) - 1, f); 386 | buffer[bytes] = 0; 387 | output += buffer; 388 | } 389 | 390 | pclose(f); 391 | // get rid of the endline 392 | return output.substr(0, output.length() - 1); 393 | } 394 | --------------------------------------------------------------------------------