diff options
author | klarlund <klarlund@gmail.com> | 2008-03-28 02:48:48 +0000 |
---|---|---|
committer | klarlund <klarlund@gmail.com> | 2008-03-28 02:48:48 +0000 |
commit | d6532ae1d997a31884a67c51ec2bc75756242eed (patch) | |
tree | 995faab42744ddcb755996469397b865b88cc048 | |
download | distcc-git-d6532ae1d997a31884a67c51ec2bc75756242eed.tar.gz |
Initial submission @6805748, not fully baked yet.
278 files changed, 70099 insertions, 0 deletions
@@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. @@ -0,0 +1,39 @@ + +To build: the simple way is to just do + + run_all_autoconf.sh # invokes autoconf and autoheader using + # version info in the file version.sh + configure # creates distcc/config.h and makefiles + make # build + +but the recommended way is to build in a different directory tree +than the source tree: + + run_all_autoconf.sh + mkdir obj + cd obj + ../configure + make + +Either of these methods will: + + - compile distcc + - compile Python C extensions + +To test: + + make check + +To test installation using your own machine as a distcc compilation server: + + - start daemon (in one window): + + distcc/distccd --wizard --allow 127.0.0.1 + + - compile (in another): + + DISTCC_POTENTIAL_HOSTS=127.0.0.1 pump BUILDCOMMAND + +See the shell script pump in this directory. + + diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..a0a7b78 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,111 @@ +# This Makefile just delegates all the work to the Makefiles +# in the subdirectories. +# +SUBDIRS = distcc include_server +INSTALL_TARGETS = $(SUBDIRS:%=install-%) +CHECK_TARGETS = $(SUBDIRS:%=check-%) +CLEAN_TARGETS = $(SUBDIRS:%=clean-%) +MAINTAINER_CHECK_TARGETS = $(SUBDIRS:%=maintainer-check-%) + +# A timestamp file to reliably tell us when autoreconf was last run. +AUTOCONF_STAMP = @srcdir@/autoconf_stamp + +# A stamp file AUTOCONF_SANITY that tells us the last time either: +# +# - autoreconf was run, or +# +# - configure was run. +# +# AUTORECONF cannot be a phony target. Below we make the Makefile itself +# dependent on AUTOCONF_SANITY. After the Makefile is regenerated, as part of +# GNU make's feature of remaking the current Makefile if it is out of date, a +# dependency on a phony target would make 'make' make the Makefile again. An +# infinite regression would result. So, we must record the time of +# AUTOCONF_SANITY in a file. +AUTOCONF_SANITY = autoconf_sanity +# TODO(klarlund): substitute autoconf_sanity for AUTOCONF_SANITY? Same for +# AUTOCONF_STAMP. + +# Autoconf configuration variables. +# DESTDIR is for building rpm's. It's a temporary filesystem root +# where the rpm bulding process puts all its files. +DESTDIR = +prefix = $(DESTDIR)@prefix@ +exec_prefix = $(DESTDIR)@exec_prefix@ +bindir = $(DESTDIR)@bindir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +INSTALL = @INSTALL@ +PYTHON = @PYTHON@ + +# I swear, this is the code that Python's distutils uses. +PYTHON_VERSION = $(shell $(PYTHON) -c \ + 'import sys; import string; print string.split(sys.version)[0][:3]') + +# TODO(klarlund,fergus): +# - invoke distcc/configure before make in distcc/ + +.PHONY: all $(SUBDIRS) +all: $(AUTOCONF_SANITY) $(SUBDIRS) pump +$(SUBDIRS): %: + $(MAKE) --directory=$@ + +.PHONY: install $(INSTALL_TARGETS) +install: $(AUTOCONF_SANITY) $(INSTALL_TARGETS) install-local +$(INSTALL_TARGETS): install-%: + $(MAKE) --directory=$* install + +.PHONY: check $(CHECK_TARGETS) +check: $(AUTOCONF_SANITY) $(CHECK_TARGETS) +$(CHECK_TARGETS): check-%: + $(MAKE) --directory=$* check + +.PHONY: maintainer-check $(MAINTAINER_CHECK_TARGETS) +maintainer-check: $(AUTOCONF_SANITY) $(MAINTAINER_CHECK_TARGETS) +$(MAINTAINER_CHECK_TARGETS): maintainer-check-%: + $(MAKE) --directory=$* maintainer-check + +.PHONY: clean $(CLEAN_TARGETS) +clean: $(CLEAN_TARGETS) +$(CLEAN_TARGETS): clean-%: + $(MAKE) --directory=$* clean + +.PHONY: install-local +install-local: pump + $(INSTALL) -d $(bindir) + $(INSTALL) pump $(bindir) + +pump: $(AUTOCONF_SANITY) pump.in + ./config.status + +Makefile: $(AUTOCONF_SANITY) Makefile.in + ./config.status + +# SANITY CHECKS + +# Here we set up AUTOCONF_SANITY so that it works as described. It verifies +# that +# +# - autoconf has been run after its dependencies have changed (see rule for +# $(AUTOCONF_STAMP)) below, and +# +# - the time of this event, recorded by AUTOCONF_STAMP, is before that of +# config.status (see rule for config.status below). +# +# We need the touch: without it 'make' will invoke itself in an infinite loop, +# because the Makefile is dependent on AUTOCONF_SANITY. + +$(AUTOCONF_SANITY): $(AUTOCONF_STAMP) config.status + touch $(AUTOCONF_SANITY) + +# Check that autoreconf was run after changes to version.sh or +# config.status. This regenerates distcc/src/config.h.in. +$(AUTOCONF_STAMP): version.sh configure.ac + @echo "Please run ./run_all_autoconf.sh now." + @exit 1 + +# Check that the generated configure was run after autoreconf. The modification +# time of the configure.status file is updated by configure. +config.status: $(AUTOCONF_STAMP) + @echo "Please run ./configure now." + @exit 1 @@ -0,0 +1,55 @@ + + distcc-pump -- a free distributed C/C++ compiler system + + originally by Martin Pool <mbp@samba.org> + + extended at Google Inc. + + by Fergus Henderson, Nils Klarlund, Manos Renieris, and Craig Silverstein + + +distcc-pump improves on distcc by distributing not only compilation but also +preprocessing to distcc servers. For an introduction to distcc, see +distcc/README. + +The distcc-pump contributes an include server process that exists during the +build. The include server parses and analyzes source and header files. It runs +on the workstation that initiates the build. The include server analyzes each +header file only a few times, sometimes just once. In contrast, ordinary distcc +invokes the preprocessor hundreds of times on average for each header file of a +large build. + +With the distcc-pump, a static analysis algorithm inspects includes and computes +their possible values according to an overapproximation semantics. The resulting +dependency graph among header files is stored in the include server, which then +acts as a cache for include analysis. + +The include server compresses source files into a temporary directory as they +are encountered. In this way, a given source file is compressed only once during +the build. + +It may happen that a header file is included via an absolutely specified include +directory such as -I/absolute/path. But on the compilation server the path +-I/absolute/path does not exist; instead the server places foo.h under +/server_temporary_path/absolute/path for some /server_temporary_path root +directory. This directory has no meaning on the workstation. Before compressing +foo.h, the include server therefore inserts a #line directive in foo.h in such +cases to inform the preprocessor that the real location is /absolute/path. + +The distcc-pump client asks the include server for the list of compressed files +that constitute the transitive closure of the source file to be compiled. It +then spools these files to a distcc-pump server. The distcc-pump server unpacks +these files in the /server_temporary_path directory before preprocessing and +compiling. The server also rewrites include options, such as -I's, to reflect +the new locations of the files on the server. The .d and the .o files are both +returned to the distcc-pump client. + +The distcc-pump is able to distribute compilations up to 10X faster than distcc. +But because building also involves linking and perhaps generation of source +files the overall speed-up of the build time is variable. + +The distcc-pump was developed to be used with large clusters of distcc servers, +providing hundreds of CPUs. With versions of gcc >= 4.1.1, the distcc-pump will +probably not show performance gains using clusters of say only ten CPUs. The +preprocessor running on the workstation is fast enough to keep that many +machines busy. diff --git a/build-distcc.sh b/build-distcc.sh new file mode 100755 index 0000000..0002b09 --- /dev/null +++ b/build-distcc.sh @@ -0,0 +1,92 @@ +#!/bin/sh +# Simple shell script to build distcc SRPM and RPM from sources + +# When releasing a new version, you need to do four things: +# 1. edit the 'Release' field of the spec file +# 2. add a comment to the %changelog section of the spec file +# 3. edit the 'DISTCC_VERSION' and 'PUMP_SUBVERSION' variables in version.sh. +# It would be better if this was easier, but that's how it is right now. + +source version.sh + +PKG=distcc +TOP=`pwd` + +# Check if we have a bad kernel + RPM combination. +# Background: +# Versions of RPM prior to 4.4.1 incorrectly add a dependency on +# 'linux-gate.so.1', which is a virtual dso in 2.6+ Linux kernels. Since this +# is not a real lib provided by any package, the resulting RPMs won't install +# due to failed dependency checks. +# For the curious, more linux-gate details are documented at: +# http://www.trilithium.com/johan/2005/08/linux-gate/ +# +# See if running on a kernel with the virtual dso. +HAS_VSDO=0 +cat /proc/self/maps | grep -q vdso +if [ $? -eq 0 ]; then + HAS_VSDO=1 +fi +# See if we have incompatible RPM tools. +if [ $HAS_VSDO -eq 0 ]; then + grep -q 'linux-gate' /usr/lib/rpm/find-requires + if [ $? -ne 0 ]; then + echo 'ERROR: Your combination of RPM and kernel is buggy.' + echo 'Upgrade to RPM 4.4.1-5 or later, or patch /usr/lib/rpm/find-requires' + echo 'to special-case the "linux-gate" dependency.' + echo 'see also http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=338515' + exit 1 + fi +fi + +set -xe + +rm -rf tmp +mkdir tmp +cd tmp + +# Set up rpm build environment +RPM_SOURCE_DIR=$TOP +RPM_BUILD_DIR=$TOP +RPM_RPM_DIR=$TOP/tmp/rpms +RPM_SRPM_DIR=$TOP/tmp/srpms +# lifted from gboilerplate +USERNAME="$(whoami)" +PACKAGER="$(ldapsearch -x -LLL -b 'ou=People,dc=google,dc=com' "uid=$USERNAME" cn|grep '^cn'|colrm 1 4) <$USERNAME@google.com>" + +# Temporary directories +rm -rf $RPM_RPM_DIR +mkdir $RPM_RPM_DIR +rm -rf $RPM_SRPM_DIR +mkdir $RPM_SRPM_DIR +rm -rf /tmp/$PKG-$DISTCC_VERSION-root +mkdir /tmp/$PKG-$DISTCC_VERSION-root + + +CROSS=${CROSS-} +CC=${CROSS}gcc \ +CXX=${CROSS}g++ \ +AR=${CROSS}ar \ +RANLIB=${CROSS}ranlib \ +rpmbuild -bb $TOP/$PKG.spec \ + --define "_sourcedir $RPM_SOURCE_DIR" \ + --define "_builddir $RPM_BUILD_DIR" \ + --define "_rpmdir $RPM_RPM_DIR" \ + --define "_srcrpmdir $RPM_SRPM_DIR" \ + --define "name $PKG" \ + --define "version $DISTCC_VERSION" \ + --define "release $PUMP_SUBVERSION" \ + --define "packager $PACKAGER" \ + --define "bundle_dir $TOP" +# Determine the name of the directory where the package went +RPMARCH=`rpmbuild --showrc $TOP/$PKG.spec | grep "^build arch.*:" | sed -e 's/^build arch[[:space:]]*:[[:space:]]*//'` + +find . -type f | xargs chmod 644 +find . -type d | xargs chmod 755 + +echo Results in $RPM_SRPM_DIR and $RPM_RPM_DIR/${RPMARCH} : +ls -l $RPM_SRPM_DIR $RPM_RPM_DIR/$RPMARCH + +# Convert RPMs to DEBs for goobuntu. +fakeroot alien -c -k -v $RPM_RPM_DIR/$RPMARCH/*.rpm + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..367e336 --- /dev/null +++ b/configure.ac @@ -0,0 +1,11 @@ +AC_INIT(distcc_pump, + esyscmd(source version.sh && echo -n $DISTCC_PUMP_VERSION), + distcc-pump@google.com) +AC_CHECK_PROGS(PYTHON, [python2.4 python2.3 python-2.3 python2.2 python-2.2 python]) +AC_ARG_VAR(PYTHON, [Python interpreter]) +AC_CONFIG_AUX_DIR(distcc) +AC_CONFIG_SUBDIRS(include_server distcc) +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([pump], [chmod +x pump]) +AC_PROG_INSTALL +AC_OUTPUT diff --git a/distcc.spec b/distcc.spec new file mode 100644 index 0000000..5ac5647 --- /dev/null +++ b/distcc.spec @@ -0,0 +1,398 @@ +Summary: Client side program for distributed C/C++ compilations. +Name: %{name} +Version: %{version} +Release: %{release} +License: GPL + Google Internal +Group: Development/Languages +BuildRoot: %{_tmppath}/%{name}-buildroot +Provides: distcc +Url: https://www.corp.google.com/eng/designdocs/google3/distcc-intra-build.html +Obsoletes: crosstool-distcc + +%define _prefix /usr +%define _bindir %{_prefix}/bin +%define _datadir %{_prefix}/share +%define _docdir %{_datadir}/doc/%{name} +%define _libdir %{_prefix}/lib +# TODO grhat wants versioned doc dirs, but goobuntu apparently doesn't. Which +# should we use? +# %define _docdir %{_datadir}/doc/%{name}-%{version} +%define _mandir %{_datadir}/man +%define _sysconfdir /etc + +%description +distcc is a program to distribute compilation of C or C++ code across several +machines on a network. distcc should always generate the same results as a +local compile, is simple to install and use, and is often two or more times +faster than a local compile. + +%prep + +%build +./run_all_autoconf.sh +# Work around broken sendfile in 32 bit apps on some x86_64 systems +ac_cv_func_sendfile=no ac_cv_header_sys_sendfile_h=no ./configure \ + --prefix=%{_prefix} \ + --bindir=%{_bindir} \ + --sysconfdir=%{_sysconfdir} \ + --datadir=%{_datadir} \ + --with-docdir=%{_docdir} \ + --mandir=%{_mandir} \ + --enable-rfc2553 --with-included-popt +# Get the list of files installed by the python install process +# by asking make to tell setup.py to put it in python_install_record +make RPM_OPT_FLAGS="$RPM_OPT_FLAGS" \ + PYTHON_INSTALL_RECORD=python_install_record + +%install +rm -rf $RPM_BUILD_ROOT +make DESTDIR=${RPM_BUILD_ROOT} PYTHON_INSTALL_RECORD=python_install_record install +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d +install -m 644 distcc/packaging/RedHat/logrotate.d/distcc $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/distcc +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/xinetd.d +install -m 644 distcc/packaging/RedHat/xinetd.d/distcc $RPM_BUILD_ROOT%{_sysconfdir}/xinetd.d/distcc +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/init.d +install -m 755 distcc/packaging/RedHat/init.d/distcc $RPM_BUILD_ROOT%{_sysconfdir}/init.d/distcc +# TODO(mtm) Does grhat really need these links for something? +mkdir -p $RPM_BUILD_ROOT/%{_libdir}/distcc +ln -s %{_bindir}/distcc $RPM_BUILD_ROOT/%{_libdir}/distcc/cc +ln -s %{_bindir}/distcc $RPM_BUILD_ROOT/%{_libdir}/distcc/c++ +ln -s %{_bindir}/distcc $RPM_BUILD_ROOT/%{_libdir}/distcc/gcc +ln -s %{_bindir}/distcc $RPM_BUILD_ROOT/%{_libdir}/distcc/g++ + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-, root, root, 0755) +%{_bindir}/distcc +%{_bindir}/distccmon-text +%{_bindir}/lsdistcc +# TODO(mtm) Do we need the libdir stuff for grhat (see %install TODO above)? +%{_libdir}/distcc +%doc %{_mandir}/man1/distcc.1.gz +%doc %{_mandir}/man1/distccmon-text.1.gz +%doc %{_docdir} + + +%package server +Summary: Server side program for distributed C/C++ compilations. +Group: Development/Languages +Provides: distccd +Obsoletes: crosstool-distcc-server + +%description server +distcc is a program to distribute compilation of C or C++ code across several +machines on a network. distcc should always generate the same results as a +local compile, is simple to install and use, and is often two or more times +faster than a local compile. + +%files server +%defattr(-, root, root, 0755) +%{_bindir}/distccd +%dir %{_sysconfdir}/logrotate.d +%config %{_sysconfdir}/logrotate.d/distcc +# Don't list init.d dir because on Red Hat it's a symlink owned by +# chkconfig, so it causes a conflict on install. +#%dir %{_sysconfdir}/init.d +%config %{_sysconfdir}/init.d/distcc +%dir %{_sysconfdir}/xinetd.d/ +%config %{_sysconfdir}/xinetd.d/distcc +%doc %{_mandir}/man1/distccd.1.gz + +%pre server + +%post server +DISTCC_USER=distcc +if [ -s /etc/redhat-release ]; then + # sadly, can't useradd -s /sbin/nologin on rh71, since + # then starting the service as user distcc fails, + # since it uses su - without overriding the shell :-( + # See https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=26894 + /sbin/service distcc stop &>/dev/null || : + if fgrep 'nice initlog $INITLOG_ARGS -c "su - $user' /etc/init.d/functions | fgrep -v '.-s ' > /dev/null 2>&1 ; then + # Kludge: for Red Hat 6.2, don't use -s /sbin/nologin + /usr/sbin/useradd -d /var/run/distcc -m -r $DISTCC_USER &>/dev/null || : + else + # but do for everyone else + /usr/sbin/useradd -d /var/run/distcc -m -r -s /sbin/nologin $DISTCC_USER &>/dev/null || : + fi +else + echo Creating $DISTCC_USER user... + if ! id $DISTCC_USER > /dev/null 2>&1 ; then + if ! id -g $DISTCC_USER > /dev/null 2>&1 ; then + addgroup --system --gid 11 $DISTCC_USER + fi + adduser --quiet --system --gid 11 \ + --home / --no-create-home --uid 15 $DISTCC_USER + fi +fi + +DISTCC_LOGFILE=/var/log/distccd.log +if [ ! -s $DISTCC_LOGFILE ]; then + touch $DISTCC_LOGFILE + chown ${DISTCC_USER}:adm $DISTCC_LOGFILE + chmod 640 $DISTCC_LOGFILE +fi + +if ! grep -q "3632/tcp" /etc/services; then + echo -e "distcc\t\t3632/tcp\t\t\t# Distcc Distributed Compiler" >> /etc/services +fi + +if ! grep -q "^distcc:" /etc/hosts.allow; then + echo -e "distcc:\t127.0.0.1" >> /etc/hosts.allow +fi + +# Update runlevel settings and start daemon. +if [ -s /etc/redhat-release ]; then + /sbin/chkconfig --add distcc + /etc/init.d/distcc start || exit 0 +else + if [ -x "/etc/init.d/distcc" ]; then + update-rc.d -f distcc remove + update-rc.d distcc defaults 95 05 >/dev/null + if [ -x /usr/sbin/invoke-rc.d ]; then + invoke-rc.d distcc start || exit 0 + else + /etc/init.d/distcc start || exit 0 + fi + fi +fi + +%preun server +# Remove hosts.allow entry. +if grep -q "^distcc:" /etc/hosts.allow; then + sed -e "/^distcc/d" /etc/hosts.allow > /etc/hosts.allow.new + mv /etc/hosts.allow.new /etc/hosts.allow +fi + +# Stop daemon and clear runlevel settings. +if [ -s /etc/redhat-release ]; then + if [ $1 -eq 0 ]; then + /sbin/service distcc stop &>/dev/null || : + fi + # chkconfig --del must run before deleting init script. + /sbin/chkconfig --del distcc +else + if [ -x "/etc/init.d/distcc" ]; then + if [ -x /usr/sbin/invoke-rc.d ] ; then + invoke-rc.d distcc stop || exit 0 + else + /etc/init.d/distcc stop || exit 0 + fi + fi +fi + +%postun server +# TODO(mtm) Should Red Hat also remove user/group? +if [ -s /etc/debian_version ]; then + case "$1" in + purge) + deluser --quiet --system distcc + delgroup --quiet --system distcc + ;; + remove) + ;; + upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + ;; + esac + + if [ "$1" = "purge" ] ; then + # update-rc.d must run after deleting init script. + update-rc.d distcc remove >/dev/null || exit 0 + fi +fi + + +%package include_server +Summary: Include server for distcc-pump +Group: Development/Languages + +%description include_server +The include server is part of the distcc-pump project, as described in +<https://www.corp.google.com/eng/designdocs/google3/distcc-intra-build.html>. + +# The python_record_install file contains a list of the files installed +# by the python install process. +%files include_server -f include_server/python_install_record +%{_bindir}/pump +%defattr(-,root,root) + + +%changelog +* Thu Jun 14 2007 Manos Renieris <manos@google.com> 2.18.3-17gg1-pump1 +- Added all the distcc-pump related parts. +- Changed the way the package is built. +- Remove source package generation. +- Man pages are now unzipped. + +* Mon May 29 2007 Dongmin Zhang <zhangdm@google.com> 2.18.3-17gg1 +- Integrate changes and bug fix from Fergus's changes. Quote from his description: + Add -r<PORT> option to lsdistcc to specify which port to connect to. + ("-p", "-o", and "-t" were already taken.) + Fix a bug where "lsdistcc distcc%d" was only returning the first host. + Add some unit tests for lsdistcc. + Also tidy up the usage message a little. + +* Mon May 21 2007 Dongmin Zhang <zhangdm@google.com> 2.18.3-16gg1 +- Change the package name to 2.18.3-16gg1 to make the goobuntu and grhat be + able to pick up the newest version of distcc. + +* Mon Feb 8 2007 Dongmin Zhang <zhangdm@google.com> 2.18.3-16gg +- Added hosts list option to lsdistcc, such that lsdistcc can check only the + hosts listed on the given list. The host list is given in command line. + +* Wed Jan 31 2007 Dongmin Zhang <zhangdm@google.com> 2.18.3-15gg +- Added _libdir definition. +- Changed Name, Version, and Release to the ones passed by --define. +- Updated the server init script to give different path of ACL files for grhat + and goobuntu as suggested by Arthur Hyun <ahyun@google.com>. + +* Mon Jan 22 2007 Dongmin Zhang <zhangdm@google.com> 2.18.3-14gg +- Fixed a bug in timeout patch. Added sigaction to catch SIGCHLD such that the + select() in dcc_collect_child() could break out when the file is finished to + compile. + +%changelog +* Fri Dec 1 2006 Ollie Wild <aaw@google.com> 2.18.3-13gg +- Removed the 01-distcc-gdb-20051210.patch patch. The parser in this was too + naive to deal with output generate with the -directives-only flag. Also, it + should no longer be needed with recent versions of gcc. +- Removed the 10-distcc-before-cpp_locking-sub-gdb.patch and + 12-distcc-after-cpp_locking-add-gdb.patch patches. These were just modifying + the former patch. + +%changelog +* Fri Sep 8 2006 Michael Moss <mmoss@google.com> 2.18.3-12gg +- Update install and init scripts to work on Debian and Red Hat (allowing the + .rpm to be converted to .deb with alien, and then installed on Debian). + Some noteworthy changes: + - Deb - Remove unused defaults file /etc/default/distcc. + - Deb - No longer uses debconf. + - RH - useradd is run in post- rather than pre- install. + - RH - distcc server is automatically started. +- Added enable/disable commands to init scripts so the daemon can be + "permanently" disabled on misbehaving hosts. +- Added patches to allow building LSB-compliant binaries. +- Reorganized some existing patches to better partition functionality. + +* Tue Feb 28 2006 Dan Kegel <dank@kegel.com> 2.18.3-11 +- removed cache again + +* Mon Feb 20 2006 Dan Kegel <dank@kegel.com> 2.18.3-10 +- added cache + +* Mon Feb 6 2006 Dan Kegel <dank@kegel.com> 2.18.3-9 +- use Josh's randomize patch instead of Michael's, + since Josh's seems to perform better in our tests +- added disk space statistic on http interface +- lsdistcc now has -x option to output info even on down hosts (will be useful for server side caching) + +* Tue Jan 2 2006 Dan Kegel <dank@kegel.com> 2.18.3-8 +- removed load shedding patch (we have swap turned on, so overload isn't as bad) +- added stats for timeout + +* Wed Dec 8 2005 Dan Kegel <dank@kegel.com> 2.18.3-7 +- lsdistcc now has -l option, better -v output +- distccd now has nicer logging, --limit-load option, bugfixes in load shedding + +* Tue Nov 22 2005 Dan Kegel <dank@kegel.com> 2.18.3-6 +- rejects jobs if load too high +- serves up stats via http on port 3633 +- lsdistcc now has new -p and -c0 options + +* Wed Nov 2 2005 Dan Kegel <dank@kegel.com> 2.18.3-5 +- updated lsdistcc to use the longer of the two of HOST and HOSTNAME + to handle shells that set HOST to the nonqualified hostname, + but HOSTNAME to the FQDN +- Changes copyright 2005 Google. GPL. + +* Thu Oct 13 2005 Dan Kegel <dank@kegel.com> 2.18.3-4 +- updated lsdistcc patch +- removed gcc as a dependency, since we want to use it with + a wide range of other compilers (and in our case, not the + standard gcc), and it's impractical to list them all as dependencies +- Changes copyright 2005 Google. GPL. + +* Fri Sep 16 2005 Dan Kegel <dank@kegel.com> 2.18.3-3 +- now reads /etc/distcc/hosts instead of /usr/etc/distcc/hosts +- replaced distcc-2.18.3-rhl.patch with distcc-2.18.3-stringmap.patch + The stringmap patch updates the rhl init.d script to know about + all installed crosstool toolchains, and enables fuzzy path matching + This is useful if the toolchains are not installed at the same + prefix on all systems +- removed distcc-domain.patch +- added distcc-2.18.3-lsdistcc.patch +- Changes copyright 2005 Google. GPL. + +* Sat Sep 3 2005 Dan Kegel <dank@kegel.com> 2.18.3-2 +- now reads /etc/distcc/hosts instead of /usr/etc/distcc/hosts +- applied distcc-domain-2.patch +- Changes copyright 2005 Google. GPL. + +* Thu Jun 15 2005 Dan Kegel <dank@kegel.com> 2.18.3-1 +- Updated to 2.18.3 +- applied --randomize patch and cpp_locking patch +- redhat init.d script reads /etc/distccd.allow to construct --allow arguments +- added scriptlets from dag's package, but don't start service on install, + and call it distcc rather than distccd (to match the current + packaging's old practice) +- Changes copyright 2005 Google. GPL. + +* Sat May 31 2003 Terry Griffin <terryg@axian.com> 2.5-2 +- Updated to 2.5 + +* Sat May 24 2003 Terry Griffin <terryg@axian.com> 2.4.2-2 +- Updated to 2.4.2 + +* Sat May 17 2003 Terry Griffin <terryg@axian.com> 2.3-2 +- Updated to 2.3 + +* Sun May 04 2003 Terry Griffin <terryg@axian.com> 2.1-2 +- Updated to 2.1 +- Added symbolic links for masquerade mode + +* Fri Mar 28 2003 Terry Griffin <terryg@axian.com> 2.0.1-2 +- Updated to 2.0.1 +- Removed info file from document list. + +* Tue Feb 25 2003 Terry Griffin <terryg@axian.com> 1.2.1-2 +- Updated to 1.2.1 + +* Mon Jan 27 2003 Terry Griffin <terryg@axian.com> 1.1-2 +- Updated to 1.1 +- Minor improvements to the RPM spec file + +* Mon Dec 16 2002 Terry Griffin <terryg@axian.com> 0.15-2 +- Changed server user back to 'nobody' + +* Fri Dec 13 2002 Terry Griffin <terryg@axian.com> 0.15-2 +- Updated to 0.15 +- Changed port number in server configs to 3632 + +* Sat Nov 23 2002 Terry Griffin <terryg@axian.com> 0.14-2 +- Updated to 0.14 +- Major rework of the RPM spec file +- Added Red Hat server config files for both xinetd and SysV init. +- Change server user to daemon. + +* Sat Nov 09 2002 Terry Griffin <terryg@axian.com> 0.12-1 +- Updated to 0.12 + +* Thu Oct 10 2002 Terry Griffin <terryg@axian.com> 0.11-3 +- First binary packages for Red Hat 8.x +- Fixed xinetd config file for location of distccd. + +* Mon Sep 30 2002 Terry Griffin <terryg@axian.com> 0.11-2 +- Moved distccd back to /usr/bin from /usr/sbin. + +* Sat Sep 28 2002 Terry Griffin <terryg@axian.com> 0.11-1 +- Initial build (Red Hat 7.x) +- Client and server in separate binary packages +- Added xinetd config file +- Moved distccd to /usr/sbin +- Added version number suffix to the documentation directory diff --git a/distcc/AUTHORS b/distcc/AUTHORS new file mode 100644 index 0000000..3b2edab --- /dev/null +++ b/distcc/AUTHORS @@ -0,0 +1,6 @@ +Author and maintainer of distcc: + + Martin Pool <mbp@sourcefrog.net> + + +See NEWS for credits of other contributors. diff --git a/distcc/COPYING b/distcc/COPYING new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/distcc/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/distcc/ChangeLog b/distcc/ChangeLog new file mode 100644 index 0000000..4c26684 --- /dev/null +++ b/distcc/ChangeLog @@ -0,0 +1,2428 @@ +# do not edit -- automatically generated by arch changelog +# arch-tag: automatic-ChangeLog--mbp@sourcefrog.net--2004/distcc--devel--2 +# + +2004-12-15 00:11:05 GMT Martin Pool <mbp@sourcefrog.net> patch-159 + + Summary: + remove obsolete web targets from makefile + Revision: + distcc--devel--2--patch-159 + + + modified files: + ChangeLog Makefile.in + + +2004-12-14 07:07:01 GMT Martin Pool <mbp@sourcefrog.net> patch-158 + + Summary: + add pending Howl mDNS patch from Lennart Poettering + Revision: + distcc--devel--2--patch-158 + + + new files: + patches/.arch-ids/howl-mdns.diff.id patches/howl-mdns.diff + + modified files: + ChangeLog + + +2004-11-30 19:05:36 GMT Martin Pool <mbp@sourcefrog.net> patch-157 + + Summary: + Add freshmeat submission data + Revision: + distcc--devel--2--patch-157 + + + new files: + freshmeat/.arch-ids/2.18.3.id freshmeat/.arch-ids/=id + freshmeat/2.18.3 + + modified files: + ChangeLog + + new directories: + freshmeat freshmeat/.arch-ids + + +2004-11-30 12:25:10 GMT Martin Pool <mbp@sourcefrog.net> patch-156 + + Summary: + Fix for -x and -specs bug + Revision: + distcc--devel--2--patch-156 + + + modified files: + ChangeLog NEWS src/arg.c + + +2004-11-30 12:11:30 GMT Martin Pool <mbp@sourcefrog.net> patch-155 + + Summary: + Better text for -x and -specs + Revision: + distcc--devel--2--patch-155 + + + modified files: + ChangeLog NEWS TODO configure.ac test/testdistcc.py + + +2004-11-12 03:33:34 GMT Martin Pool <mbp@sourcefrog.net> patch-154 + + Summary: + Prepare for 2.18.2 release + Revision: + distcc--devel--2--patch-154 + + + modified files: + ChangeLog NEWS configure.ac + + +2004-11-12 03:32:54 GMT Martin Pool <mbp@sourcefrog.net> patch-153 + + Summary: + Notes on performance influence of mmap + Revision: + distcc--devel--2--patch-153 + + + new files: + doc/.arch-ids/mmap-influence.txt.id doc/mmap-influence.txt + + modified files: + ChangeLog + + +2004-11-12 03:31:51 GMT Martin Pool <mbp@sourcefrog.net> patch-152 + + Summary: + fix size_t/unsigned mismatch + Revision: + distcc--devel--2--patch-152 + + + modified files: + ChangeLog NEWS src/distcc.h + + +2004-11-12 03:23:15 GMT Martin Pool <mbp@sourcefrog.net> patch-151 + + Summary: + fix for checking uninitialized errno + Revision: + distcc--devel--2--patch-151 + + + modified files: + ChangeLog NEWS src/clinet.c + + +2004-11-03 02:20:56 GMT Martin Pool <mbp@sourcefrog.net> patch-150 + + Summary: + gcc -specs must also be run locally + Revision: + distcc--devel--2--patch-150 + + + modified files: + ChangeLog NEWS src/arg.c test/testdistcc.py + + +2004-11-02 07:12:57 GMT Martin Pool <mbp@sourcefrog.net> patch-149 + + Summary: + mon-gnome: fix tree_model warning + Revision: + distcc--devel--2--patch-149 + + + modified files: + ChangeLog NEWS src/mon-gnome.c + + +2004-10-23 08:42:53 GMT Martin Pool <mbp@sourcefrog.net> patch-148 + + Summary: + fold io.h into distcc.h + Revision: + distcc--devel--2--patch-148 + + + removed files: + src/.arch-ids/io.h.id src/io.h + + modified files: + ChangeLog Makefile.in src/arg.c src/argutil.c src/backoff.c + src/bulk.c src/clinet.c src/clirpc.c src/compress.c + src/daemon.c src/distcc.h src/dopt.c src/dparent.c src/exec.c + src/h_exten.c src/h_issource.c src/h_scanargs.c src/h_strip.c + src/hostfile.c src/io.c src/loadfile.c src/lock.c + src/mon-gnome.c src/mon-notify.c src/mon-text.c src/mon.c + src/prefork.c src/pump.c src/remote.c src/renderer.c src/rpc.c + src/safeguard.c src/sendfile.c src/serve.c src/srvnet.c + src/srvrpc.c src/ssh.c src/state.c src/strip.c src/timefile.c + src/util.c + + +2004-10-23 08:23:22 GMT Martin Pool <mbp@sourcefrog.net> patch-147 + + Summary: + fix some signedness/type warnings + Revision: + distcc--devel--2--patch-147 + + + modified files: + ChangeLog src/bulk.c src/climasq.c src/clirpc.c src/distcc.h + src/hosts.c src/io.h src/mon-gnome.c src/netutil.c + src/netutil.h src/rpc.c src/trace.c src/util.c src/where.c + + +2004-10-23 08:11:25 GMT Martin Pool <mbp@sourcefrog.net> patch-146 + + Summary: + Turn off -Wunreachable-code + Revision: + distcc--devel--2--patch-146 + + + modified files: + ChangeLog configure.ac + + +2004-10-23 08:00:12 GMT Martin Pool <mbp@sourcefrog.net> patch-145 + + Summary: + turn on more warnings + Revision: + distcc--devel--2--patch-145 + + + modified files: + ChangeLog configure.ac + + +2004-10-21 23:06:54 GMT Martin Pool <mbp@sourcefrog.net> patch-144 + + Summary: + Allow for host files containing \r + Revision: + distcc--devel--2--patch-144 + + + modified files: + ChangeLog NEWS src/hosts.c test/testdistcc.py + + +2004-10-13 02:37:50 GMT Martin Pool <mbp@sourcefrog.net> patch-143 + + Summary: + Return errors, rather than aborting. + Revision: + distcc--devel--2--patch-143 + + Don't call rs_fatal; instead return an error. It was giving warnings on + non-gcc compilers because it wasn't seen as noreturn, and anyhow aborting + is a bit untidy. + + modified files: + ChangeLog src/arg.c src/bulk.c src/cleanup.c src/cpp.c + src/dopt.c src/h_ccvers.c src/history.c src/hosts.c src/io.c + src/lock.c src/mon.c src/pump.c src/remote.c src/rpc.c + src/serve.c src/ssh.c src/trace.h src/util.c + + +2004-10-13 02:23:11 GMT Martin Pool <mbp@sourcefrog.net> patch-142 + + Summary: + fix header problem for Solaris + Revision: + distcc--devel--2--patch-142 + + * src/distcc.h: Need sys/types.h for pid_t. + + + + modified files: + ChangeLog NEWS bench/Build.py bench/Project.py + bench/ProjectDefs.py src/distcc.h + + +2004-10-12 06:28:10 GMT Martin Pool <mbp@sourcefrog.net> patch-141 + + Summary: + Add samba 3.0.7 as benchmark project + Revision: + distcc--devel--2--patch-141 + + + modified files: + ChangeLog bench/ProjectDefs.py + + +2004-10-12 05:41:38 GMT Martin Pool <mbp@sourcefrog.net> patch-140 + + Summary: + benchmark: scrub results on completion by default + Revision: + distcc--devel--2--patch-140 + + + modified files: + ChangeLog bench/actions.py + + +2004-10-12 05:37:21 GMT Martin Pool <mbp@sourcefrog.net> patch-139 + + Summary: + advance version to 2.19pre + Revision: + distcc--devel--2--patch-139 + + + modified files: + ChangeLog configure.ac + + +2004-10-12 05:13:54 GMT Martin Pool <mbp@sourcefrog.net> patch-138 + + Summary: + Prepare for release + Revision: + distcc--devel--2--patch-138 + + + modified files: + ChangeLog NEWS configure.ac + + +2004-10-12 05:10:31 GMT Martin Pool <mbp@sourcefrog.net> patch-137 + + Summary: + Always build conftest.c locally + Revision: + distcc--devel--2--patch-137 + + Problem: configure tests are typically very quick to build; also + configure can be very sensitive to stderr warnings or other small + variations between machines. + + Fix: To make things faster and safer, build conftest.* locally; also + tmp.conftest.* used by ccache. + + * src/filename.c (dcc_source_needs_local): New function. + + * src/arg.c (dcc_scan_args): Check. + + * cases/conftest.c: Manual test case. + + + new files: + cases/conftest.c + + modified files: + ChangeLog NEWS TODO src/arg.c src/distcc.h src/filename.c + + +2004-10-12 04:50:41 GMT Martin Pool <mbp@sourcefrog.net> patch-136 + + Summary: + Reset PATH when running maintainer-check + Revision: + distcc--devel--2--patch-136 + + Problem: Installed copies of distcc and/or ccache were getting invoked + from inside the test suite in a confusing way. + + Fix: Force the path to just /bin:/usr/bin:`pwd` + + + modified files: + ChangeLog Makefile.in + + +2004-10-12 04:43:39 GMT Martin Pool <mbp@sourcefrog.net> patch-135 + + Summary: + Remove mmap when receiving uncompressed data + Revision: + distcc--devel--2--patch-135 + + Problem: Calling msync seems likely to force disk IO, but not calling it + is unsafe. + + Fix: In fact, we can probably do fine by just using plain IO to receive + data. This is already done for compressed data. + + * src/pump.c (dcc_r_bulk_plain): Remove. + + * src/pump.c (dcc_r_bulk): Just pump bytes through when receiving data; + don't worry about mmap. Doc. + + * src/bulk.c (dcc_r_file): Output files can be WRONLY if we're not using + mmap. + + * src/io.c (dcc_want_mmap): Remove. + + * man/distcc.1, man/distccd.1: No more mmap! + + + modified files: + ChangeLog NEWS man/distcc.1 man/distccd.1 src/bulk.c src/io.c + src/pump.c src/sendfile.c + + +2004-10-12 04:38:27 GMT Martin Pool <mbp@sourcefrog.net> patch-134 + + Summary: + fix headers + Revision: + distcc--devel--2--patch-134 + + + modified files: + ChangeLog src/history.c + + +2004-10-12 04:27:45 GMT Martin Pool <mbp@sourcefrog.net> patch-133 + + Summary: + todo: conftest.c + Revision: + distcc--devel--2--patch-133 + + + modified files: + ChangeLog TODO + + +2004-10-12 04:20:05 GMT Martin Pool <mbp@sourcefrog.net> patch-132 + + Summary: + doc + Revision: + distcc--devel--2--patch-132 + + + modified files: + ChangeLog src/pump.c + + +2004-10-12 04:10:49 GMT Martin Pool <mbp@sourcefrog.net> patch-131 + + Summary: + Select-based non-blocking connect() + Revision: + distcc--devel--2--patch-131 + + * src/clinet.c (dcc_connect_by_addr): Make socket non-blocking at connect + time and impose a timeout on connection attempts; currently hardcoded + to 5s. + + + modified files: + ChangeLog NEWS src/clinet.c src/io.c + + +2004-10-12 03:10:31 GMT Martin Pool <mbp@sourcefrog.net> patch-130 + + Summary: + ssh: doc + Revision: + distcc--devel--2--patch-130 + + + modified files: + ChangeLog src/ssh.c + + +2004-10-12 03:02:18 GMT Martin Pool <mbp@sourcefrog.net> patch-129 + + Summary: + Ignore HTML manpages + Revision: + distcc--devel--2--patch-129 + + + new files: + man/.arch-inventory + + modified files: + ChangeLog + + +2004-10-12 02:59:16 GMT Martin Pool <mbp@sourcefrog.net> patch-128 + + Summary: + ssh: doc + Revision: + distcc--devel--2--patch-128 + + + modified files: + ChangeLog src/ssh.c + + +2004-10-12 02:15:39 GMT Martin Pool <mbp@sourcefrog.net> patch-127 + + Summary: + remove signal-based timeouts + Revision: + distcc--devel--2--patch-127 + + Problem: Using alarms to enforce timeouts is inherently unsafe, because + it might leave e.g. the resolver or C library in an inconsistent state. + + Fix: Don't use signals. We can do something simpler and safer using + select() in a future commit. + + We no longer have a timeout on name resolution; the best fix for this is + to set an appropriate timeout in resolv.conf. + + removed files: + src/.arch-ids/timeout.c.id src/timeout.c + + modified files: + ChangeLog Makefile.in man/distcc.1 src/distcc.h src/remote.c + src/serve.c + + +2004-10-11 09:09:47 GMT Martin Pool <mbp@sourcefrog.net> patch-126 + + Summary: + distcc(1): mention timeouts + Revision: + distcc--devel--2--patch-126 + + + modified files: + ChangeLog man/distcc.1 + + +2004-10-11 08:15:05 GMT Martin Pool <mbp@sourcefrog.net> patch-125 + + Summary: + no timeout on cpp + Revision: + distcc--devel--2--patch-125 + + Refactor code that waits for cpp to finish, and disarm the timeout during + this phase. + + + modified files: + ChangeLog NEWS src/remote.c + + +2004-10-11 07:28:00 GMT Martin Pool <mbp@sourcefrog.net> patch-124 + + Summary: + Adjust timeouts + Revision: + distcc--devel--2--patch-124 + + Short 5s CONNECT timeout covers only name resolution and TCP + connection. + + SEND phase and timeout should include sending the header, and waiting + for cpp to complete. 60s to send. + + Allow up to 20mins for compilation. + + + modified files: + ChangeLog src/remote.c src/serve.c + + +2004-10-11 07:17:31 GMT Martin Pool <mbp@sourcefrog.net> patch-123 + + Summary: + fix timeout crash bug + Revision: + distcc--devel--2--patch-123 + + Problem: Was using longjmp() from the SIGALRM handler to return an + error. This is not safe. + + Fix: Use siglongjmp() instead. That may not be completely safe + either, but it might fix the problem. + + modified files: + ChangeLog NEWS src/timeout.c + + +2004-10-11 06:24:35 GMT Martin Pool <mbp@sourcefrog.net> patch-122 + + Summary: + Add test case for siglongjmp + Revision: + distcc--devel--2--patch-122 + + + new files: + cases/.arch-ids/.arch-inventory.id + cases/.arch-ids/tryjump.c.id cases/.arch-inventory + cases/tryjump.c + + modified files: + ChangeLog NEWS + + +2004-10-11 06:21:43 GMT Martin Pool <mbp@sourcefrog.net> patch-121 + + Summary: + todo: problems with state file sharing + Revision: + distcc--devel--2--patch-121 + + + modified files: + ChangeLog TODO + + +2004-10-09 13:26:15 GMT Martin Pool <mbp@sourcefrog.net> patch-120 + + Summary: + distccmon-text(1): Clarify client requirements + Revision: + distcc--devel--2--patch-120 + + + modified files: + ChangeLog man/distccmon-text.1 + + +2004-09-25 10:01:05 GMT Martin Pool <mbp@sourcefrog.net> patch-119 + + Summary: + doc + Revision: + distcc--devel--2--patch-119 + + + modified files: + ChangeLog TODO + + +2004-09-25 09:57:52 GMT Martin Pool <mbp@sourcefrog.net> patch-118 + + Summary: + distcc.1: make it clearer this is a client-side monitor + Revision: + distcc--devel--2--patch-118 + + + modified files: + ChangeLog man/distccmon-text.1 + + +2004-09-17 00:41:14 GMT Martin Pool <mbp@sourcefrog.net> patch-117 + + Summary: + --allow is now mandatory + Revision: + distcc--devel--2--patch-117 + + + modified files: + ChangeLog NEWS src/daemon.c src/dopt.c + + +2004-09-16 05:58:09 GMT Martin Pool <mbp@sourcefrog.net> patch-116 + + Summary: + sa_family_t Tru64 portability cleanup -- just remove test + Revision: + distcc--devel--2--patch-116 + + + modified files: + ChangeLog NEWS configure.ac src/distcc.h + + +2004-09-16 05:20:08 GMT Martin Pool <mbp@sourcefrog.net> patch-115 + + Summary: + include state.h from within distcc.h + Revision: + distcc--devel--2--patch-115 + + + modified files: + ChangeLog src/compile.c src/distcc.c src/distcc.h + src/history.c src/mon-gnome.c src/mon-notify.c src/mon-text.c + src/mon.c src/remote.c src/renderer.c src/serve.c src/state.c + src/timeout.c src/where.c + + +2004-09-16 05:12:42 GMT Martin Pool <mbp@sourcefrog.net> patch-114 + + Summary: + doc + Revision: + distcc--devel--2--patch-114 + + + modified files: + ChangeLog src/distcc.h + + +2004-09-16 05:08:07 GMT Martin Pool <mbp@sourcefrog.net> patch-113 + + Summary: + Improved check for gcc>=3.4 for warn_unused_result + Revision: + distcc--devel--2--patch-113 + + + modified files: + ChangeLog src/distcc.h + + +2004-09-16 04:55:26 GMT Martin Pool <mbp@sourcefrog.net> patch-112 + + Summary: + fix enum type warning from Dmitri + Revision: + distcc--devel--2--patch-112 + + + modified files: + ChangeLog src/distcc.h src/timeout.c + + +2004-09-16 04:46:42 GMT Martin Pool <mbp@sourcefrog.net> patch-111 + + Summary: + fix unused var warning + Revision: + distcc--devel--2--patch-111 + + + modified files: + ChangeLog src/state.c + + +2004-09-16 04:46:26 GMT Martin Pool <mbp@sourcefrog.net> patch-110 + + Summary: + bump version + Revision: + distcc--devel--2--patch-110 + + + modified files: + ChangeLog configure.ac + + +2004-08-24 12:12:50 GMT Martin Pool <mbp@sourcefrog.net> patch-109 + + Summary: + Prepare for 2.17.1 release + Revision: + distcc--devel--2--patch-109 + + + modified files: + ChangeLog NEWS + + +2004-08-24 12:10:43 GMT Martin Pool <mbp@sourcefrog.net> patch-108 + + Summary: + Update version to 2.17.1 + Revision: + distcc--devel--2--patch-108 + + + modified files: + ChangeLog configure.ac + + +2004-08-24 12:07:55 GMT Martin Pool <mbp@sourcefrog.net> patch-107 + + Summary: + Don't use warn_unused_result on old gcc + Revision: + distcc--devel--2--patch-107 + + + modified files: + ChangeLog src/distcc.h + + +2004-08-13 22:06:05 GMT Martin Pool <mbp@sourcefrog.net> patch-106 + + Summary: + distcc.1: better explanation of using distcc with ccache + Revision: + distcc--devel--2--patch-106 + + + modified files: + ChangeLog Makefile.in man/distcc.1 + + +2004-08-06 00:34:21 GMT Martin Pool <mbp@sourcefrog.net> patch-105 + + Summary: + doc + Revision: + distcc--devel--2--patch-105 + + + modified files: + ChangeLog src/compile.c + + +2004-08-05 23:29:15 GMT Martin Pool <mbp@sourcefrog.net> patch-104 + + Summary: + Fix dcc_trace bug + Revision: + distcc--devel--2--patch-104 + + + modified files: + ChangeLog NEWS src/clinet.c + + +2004-08-02 18:41:07 GMT Martin Pool <mbp@sourcefrog.net> patch-103 + + Summary: + doc + Revision: + distcc--devel--2--patch-103 + + + modified files: + ChangeLog src/distcc.h + + +2004-08-01 05:52:01 GMT Martin Pool <mbp@sourcefrog.net> patch-102 + + Summary: + fix usage of dcc_timeout_arm + Revision: + distcc--devel--2--patch-102 + + + modified files: + ChangeLog src/serve.c + + +2004-08-01 05:50:45 GMT Martin Pool <mbp@sourcefrog.net> patch-101 + + Summary: + prepare for 2.17 release + Revision: + distcc--devel--2--patch-101 + + + modified files: + ChangeLog + + +2004-08-01 05:49:42 GMT Martin Pool <mbp@sourcefrog.net> patch-100 + + Summary: + add server-side timeouts + Revision: + distcc--devel--2--patch-100 + + + modified files: + ChangeLog Makefile.in NEWS src/serve.c + + +2004-08-01 05:45:46 GMT Martin Pool <mbp@sourcefrog.net> patch-99 + + Summary: + fix usage of dcc_timeout_arm + Revision: + distcc--devel--2--patch-99 + + + modified files: + ChangeLog src/remote.c + + +2004-08-01 05:43:10 GMT Martin Pool <mbp@sourcefrog.net> patch-98 + + Summary: + merge from happy + Revision: + distcc--devel--2--patch-98 + + Patches applied: + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-26 + dcc_timeout_arm: add WARN_UNUSED + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-27 + merge to devel + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-28 + add WARN_UNUSED to some functions + + + modified files: + ChangeLog src/distcc.h + + new patches: + mbp@sourcefrog.net--happy/distcc--devel--2--patch-26 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-27 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-28 + + +2004-08-01 05:39:19 GMT Martin Pool <mbp@sourcefrog.net> patch-97 + + Summary: + add WARN_UNUSED to some functions + Revision: + distcc--devel--2--patch-97 + + Patches applied: + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-26 + dcc_timeout_arm: add WARN_UNUSED + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-27 + merge to devel + + + modified files: + ChangeLog src/distcc.h + + +2004-07-29 21:38:23 GMT Martin Pool <mbp@sourcefrog.net> patch-96 + + Summary: + cleanups + Revision: + distcc--devel--2--patch-96 + + Patches applied: + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-23 + check return codes from dcc_timeout_arm + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-24 + ifdef __attribute__ on GNUC + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-25 + dcc_build_somewhere: cleanup + + + modified files: + ChangeLog src/compile.c src/distcc.h + + new patches: + mbp@sourcefrog.net--happy/distcc--devel--2--patch-23 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-24 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-25 + + +2004-07-29 21:32:11 GMT Martin Pool <mbp@sourcefrog.net> patch-95 + + Summary: + doc + Revision: + distcc--devel--2--patch-95 + + Patches applied: + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-16 + update todo items + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-17 + merged to devel + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-18 + doc + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-19 + notes on timeouts + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-20 + timeouts are done + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-21 + correct version number + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-22 + treat emacs temporary files as backups + + + modified files: + ChangeLog NEWS TODO configure.ac doc/roadmap.txt src/remote.c + {arch}/=tagging-method + + new patches: + mbp@sourcefrog.net--happy/distcc--devel--2--patch-16 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-17 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-18 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-19 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-20 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-21 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-22 + + +2004-07-29 19:35:33 GMT Martin Pool <mbp@sourcefrog.net> patch-94 + + Summary: + more timeouts and cleanups + Revision: + distcc--devel--2--patch-94 + + Patches applied: + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-11 + portability fix for WCOREDUMP + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-12 + remove obsolete patch + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-13 + dcc_compile_remote: add more client-side timeouts + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-14 + dcc_connect_by_addr: handle EINTR from connect() + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-15 + bump version number + + + removed files: + patches/.arch-ids/resolver-timeout.diff.id + patches/resolver-timeout.diff + + modified files: + ChangeLog NEWS configure.ac src/clinet.c src/distcc.h + src/exec.c src/remote.c + + new patches: + mbp@sourcefrog.net--happy/distcc--devel--2--patch-11 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-12 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-13 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-14 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-15 + + +2004-07-29 19:12:49 GMT Martin Pool <mbp@sourcefrog.net> patch-93 + + Summary: + alarm-based connection timeout + Revision: + distcc--devel--2--patch-93 + + Patches applied: + + * mbp@sourcefrog.net--happy/distcc--devel--2--base-0 + import from ozlabs + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-1 + tweak version output more + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-2 + Add EXIT_TIMEOUT + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-3 + Add overall connection timeout + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-4 + remove docs for deleted DISTCC_CONNECT_TIMEOUT + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-5 + fold in backoff.h + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-6 + remove select-based timeout in client connect + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-7 + dcc_connect_by_addr: remove host and port params + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-8 + dcc_connect_by_addr: cleanup trace + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-9 + dcc_build_somewhere: better message on fallback + + * mbp@sourcefrog.net--happy/distcc--devel--2--patch-10 + dcc_timeout_arm: doc + + + new files: + src/.arch-ids/timeout.c.id src/timeout.c + + removed files: + src/.arch-ids/backoff.h.id src/backoff.h + + modified files: + ChangeLog Makefile.in NEWS man/distcc.1 src/backoff.c + src/clinet.c src/compile.c src/distcc.h src/exitcode.h + src/help.c src/remote.c src/ssh.c src/util.c src/util.h + src/where.c + + new patches: + mbp@sourcefrog.net--happy/distcc--devel--2--base-0 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-1 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-2 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-3 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-4 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-5 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-6 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-7 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-8 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-9 + mbp@sourcefrog.net--happy/distcc--devel--2--patch-10 + + +2004-07-28 18:38:20 GMT Martin Pool <mbp@sourcefrog.net> patch-92 + + Summary: + mention miniLZO in --version + Revision: + distcc--devel--2--patch-92 + + + modified files: + ChangeLog src/help.c + + +2004-07-23 13:47:05 GMT Martin Pool <mbp@sourcefrog.net> patch-91 + + Summary: + Manpage fix from Jean Delvare. + Revision: + distcc--devel--2--patch-91 + + + modified files: + ChangeLog NEWS man/distcc.1 + + +2004-07-15 08:27:57 GMT Martin Pool <mbp@sourcefrog.net> patch-90 + + Summary: + Add CVE number for netmask problem + Revision: + distcc--devel--2--patch-90 + + + modified files: + ChangeLog NEWS + + +2004-07-14 05:32:41 GMT Martin Pool <mbp@sourcefrog.net> patch-89 + + Summary: + notes on mod_backhand load balancing + Revision: + distcc--devel--2--patch-89 + + + new files: + doc/todo/.arch-ids/backhand.txt.id doc/todo/backhand.txt + + modified files: + ChangeLog + + +2004-07-14 05:32:16 GMT Martin Pool <mbp@sourcefrog.net> patch-88 + + Summary: + dcc_set_row_idle: reduce unnecessary tree model updates + Revision: + distcc--devel--2--patch-88 + + + modified files: + ChangeLog src/mon-gnome.c + + +2004-07-14 05:27:54 GMT Martin Pool <mbp@sourcefrog.net> patch-87 + + Summary: + dcc_build_somewhere: don't retry if remote compiler crashed + Revision: + distcc--devel--2--patch-87 + + + modified files: + ChangeLog NEWS src/compile.c + + +2004-07-12 07:39:35 GMT Martin Pool <mbp@sourcefrog.net> patch-86 + + Summary: + Cleanup + Revision: + distcc--devel--2--patch-86 + + + modified files: + ChangeLog src/mon-gnome.c + + +2004-07-12 07:23:46 GMT Martin Pool <mbp@sourcefrog.net> patch-85 + + Summary: + make sure idle periods get drawn in history + Revision: + distcc--devel--2--patch-85 + + + modified files: + ChangeLog src/renderer.c + + +2004-07-12 07:21:41 GMT Martin Pool <mbp@sourcefrog.net> patch-84 + + Summary: + mon-gnome: Use circular array not GQueue for history + Revision: + distcc--devel--2--patch-84 + + Using a doubly-linked list to hold integers uses a lot of time and + memory. Instead we use just a simple circular array. + + history.c: New file holding this. + + + new files: + src/.arch-ids/history.c.id src/history.c + + modified files: + ChangeLog Makefile.in NEWS src/mon-gnome.c src/mon.h + src/renderer.c + + +2004-07-12 06:53:56 GMT Martin Pool <mbp@sourcefrog.net> patch-83 + + Summary: + s/dcc_history/dcc_task_state/ + Revision: + distcc--devel--2--patch-83 + + + modified files: + ChangeLog src/mon-fake.c src/mon-gnome.c src/mon-text.c + src/mon.c src/mon.h src/state.c src/state.h + + +2004-07-12 06:49:54 GMT Martin Pool <mbp@sourcefrog.net> patch-82 + + Summary: + s/dcc_state/dcc_phase/ + Revision: + distcc--devel--2--patch-82 + + + modified files: + ChangeLog src/mon-fake.c src/mon-gnome.c src/mon-text.c + src/mon.c src/mon.h src/renderer.c src/renderer.h src/state.c + src/state.h + + +2004-07-12 06:46:16 GMT Martin Pool <mbp@sourcefrog.net> patch-81 + + Summary: + Rename DCC_STATE_* to DCC_PHASE_* + Revision: + distcc--devel--2--patch-81 + + + modified files: + ChangeLog src/clirpc.c src/compile.c src/mon-fake.c + src/mon-gnome.c src/mon-text.c src/mon.c src/remote.c + src/renderer.c src/renderer.h src/state.c src/state.h + src/where.c + + +2004-07-12 06:45:29 GMT Martin Pool <mbp@sourcefrog.net> patch-80 + + Summary: + Fix warning + Revision: + distcc--devel--2--patch-80 + + + modified files: + ChangeLog src/daemon.h + + +2004-07-12 06:39:40 GMT Martin Pool <mbp@sourcefrog.net> patch-79 + + Summary: + Doc + Revision: + distcc--devel--2--patch-79 + + + modified files: + ChangeLog src/mon-gnome.c + + +2004-07-12 06:20:10 GMT Martin Pool <mbp@sourcefrog.net> patch-78 + + Summary: + dcc_draw_state_stripe: inline into the only caller + Revision: + distcc--devel--2--patch-78 + + + modified files: + ChangeLog src/renderer.c + + +2004-07-12 05:24:32 GMT Martin Pool <mbp@sourcefrog.net> patch-77 + + Summary: + Doc + Revision: + distcc--devel--2--patch-77 + + + modified files: + ChangeLog src/renderer.c + + +2004-07-09 05:16:20 GMT Martin Pool <mbp@sourcefrog.net> patch-76 + + Summary: + todo: monitor ideas + Revision: + distcc--devel--2--patch-76 + + + new files: + doc/todo/.arch-ids/monitor-clear.txt.id + doc/todo/.arch-ids/monitor-count.txt.id + doc/todo/monitor-clear.txt doc/todo/monitor-count.txt + + modified files: + ChangeLog + + +2004-07-09 04:56:11 GMT Martin Pool <mbp@sourcefrog.net> patch-75 + + Summary: + benchmark: notes on building glibc + Revision: + distcc--devel--2--patch-75 + + + modified files: + ChangeLog bench/ProjectDefs.py + + +2004-07-08 07:40:50 GMT Martin Pool <mbp@sourcefrog.net> patch-74 + + Summary: + fix warnings about sockaddr + Revision: + distcc--devel--2--patch-74 + + + modified files: + ChangeLog src/netutil.h + + +2004-07-08 07:39:35 GMT Martin Pool <mbp@sourcefrog.net> patch-73 + + Summary: + setuid.h: remove + Revision: + distcc--devel--2--patch-73 + + + removed files: + src/.arch-ids/setuid.h.id src/setuid.h + + modified files: + ChangeLog Makefile.in src/daemon.c src/daemon.h src/dopt.c + src/setuid.c + + +2004-07-08 07:36:08 GMT Martin Pool <mbp@sourcefrog.net> patch-72 + + Summary: + filename.h: remove + Revision: + distcc--devel--2--patch-72 + + + removed files: + src/.arch-ids/filename.h.id src/filename.h + + modified files: + ChangeLog Makefile.in src/arg.c src/argutil.c src/cpp.c + src/distcc.c src/distcc.h src/filename.c src/h_exten.c + src/h_issource.c src/implicit.c src/mon-notify.c + src/mon-text.c src/mon.c src/serve.c src/srvrpc.c src/state.c + + +2004-07-08 07:32:43 GMT Martin Pool <mbp@sourcefrog.net> patch-71 + + Summary: + cpp.h: removed + Revision: + distcc--devel--2--patch-71 + + + removed files: + src/.arch-ids/cpp.h.id src/cpp.h + + modified files: + ChangeLog Makefile.in src/compile.c src/cpp.c src/distcc.h + + +2004-07-08 07:31:15 GMT Martin Pool <mbp@sourcefrog.net> patch-70 + + Summary: + strip.h: removed + Revision: + distcc--devel--2--patch-70 + + + removed files: + src/.arch-ids/strip.h.id src/strip.h + + modified files: + ChangeLog doc/roadmap.txt src/compile.c src/cpp.c src/distcc.h + src/h_strip.c src/strip.c + + +2004-07-08 06:02:34 GMT Martin Pool <mbp@sourcefrog.net> patch-69 + + Summary: + doc + Revision: + distcc--devel--2--patch-69 + + + modified files: + ChangeLog src/mon-text.c + + +2004-07-08 05:57:05 GMT Martin Pool <mbp@sourcefrog.net> patch-68 + + Summary: + note leak fixes + Revision: + distcc--devel--2--patch-68 + + + modified files: + ChangeLog + + +2004-07-08 05:56:54 GMT Martin Pool <mbp@sourcefrog.net> patch-67 + + Summary: + distccmon-text: fix memory leak + Revision: + distcc--devel--2--patch-67 + + + modified files: + ChangeLog src/mon-text.c + + +2004-07-08 05:52:06 GMT Martin Pool <mbp@sourcefrog.net> patch-66 + + Summary: + dcc_history_free: Fix memory leak + Revision: + distcc--devel--2--patch-66 + + + modified files: + ChangeLog src/mon.c + + +2004-07-08 05:48:31 GMT Martin Pool <mbp@sourcefrog.net> patch-65 + + Summary: + mon-gnome: fix leak in setting title; don't set title twice + Revision: + distcc--devel--2--patch-65 + + + modified files: + ChangeLog src/mon-gnome.c + + +2004-07-08 05:10:10 GMT Martin Pool <mbp@sourcefrog.net> patch-64 + + Summary: + dcc_mon_load_state: fix leak on error path + Revision: + distcc--devel--2--patch-64 + + + modified files: + ChangeLog NEWS src/mon.c + + +2004-07-08 04:56:58 GMT Martin Pool <mbp@sourcefrog.net> patch-63 + + Summary: + Prepare for 2.16 release + Revision: + distcc--devel--2--patch-63 + + + modified files: + ChangeLog NEWS configure.ac + + +2004-07-08 04:52:43 GMT Martin Pool <mbp@sourcefrog.net> patch-62 + + Summary: + distccmon-gnome: use a GNOME status bar with a grab handle + Revision: + distcc--devel--2--patch-62 + + Patch from Nathan Fredrickson. + + + modified files: + ChangeLog NEWS src/mon-gnome.c + + +2004-07-08 04:32:35 GMT Martin Pool <mbp@sourcefrog.net> patch-61 + + Summary: + testdistcc.py: update to work on ia64 linux + Revision: + distcc--devel--2--patch-61 + + + modified files: + ChangeLog NEWS test/testdistcc.py + + +2004-07-08 04:31:44 GMT Martin Pool <mbp@sourcefrog.net> patch-60 + + Summary: + Rephrase news + Revision: + distcc--devel--2--patch-60 + + + modified files: + ChangeLog NEWS + + +2004-07-07 05:49:15 GMT Martin Pool <mbp@sourcefrog.net> patch-59 + + Summary: + testdistcc: allow for --version output to have more than two lines + Revision: + distcc--devel--2--patch-59 + + + modified files: + ChangeLog test/testdistcc.py + + +2004-07-07 05:44:23 GMT Martin Pool <mbp@sourcefrog.net> patch-58 + + Summary: + dcc_parse_mask: fix 64-bit bugs + Revision: + distcc--devel--2--patch-58 + + + modified files: + ChangeLog NEWS src/access.c + + +2004-07-07 05:21:02 GMT Martin Pool <mbp@sourcefrog.net> patch-57 + + Summary: + h_parsemask: stub for trace + Revision: + distcc--devel--2--patch-57 + + + modified files: + ChangeLog src/h_parsemask.c + + +2004-07-07 04:47:00 GMT Martin Pool <mbp@sourcefrog.net> patch-56 + + Summary: + dcc_show_version: Include copyright and licence + Revision: + distcc--devel--2--patch-56 + + + modified files: + ChangeLog NEWS src/distcc.c src/distcc.h src/dopt.c src/help.c + + +2004-07-07 04:38:53 GMT Martin Pool <mbp@sourcefrog.net> patch-55 + + Summary: + configure: if using system popt, need to use -lpopt + Revision: + distcc--devel--2--patch-55 + + + modified files: + ChangeLog configure.ac + + +2004-07-07 02:14:54 GMT Martin Pool <mbp@sourcefrog.net> patch-54 + + Summary: + dcc_log_child_exited: Fix bizarre syntax bug, remove #ifdef + Revision: + distcc--devel--2--patch-54 + + + modified files: + ChangeLog NEWS src/dparent.c + + +2004-07-07 02:07:47 GMT Martin Pool <mbp@sourcefrog.net> patch-53 + + Summary: + draft patch for faster polling when blocked + Revision: + distcc--devel--2--patch-53 + + + new files: + patches/.arch-ids/shorter-boredom-poll.diff.id + patches/shorter-boredom-poll.diff + + modified files: + ChangeLog + + +2004-07-07 02:06:53 GMT Martin Pool <mbp@sourcefrog.net> patch-52 + + Summary: + doc: note popt fix + Revision: + distcc--devel--2--patch-52 + + + modified files: + ChangeLog NEWS + + +2004-07-07 01:59:58 GMT Martin Pool <mbp@sourcefrog.net> patch-51 + + Summary: + doc: benchmarks + Revision: + distcc--devel--2--patch-51 + + + modified files: + ChangeLog doc/results.txt + + +2004-07-07 01:59:39 GMT Martin Pool <mbp@sourcefrog.net> patch-50 + + Summary: + configure.ac: fix problem detecting popt.h + Revision: + distcc--devel--2--patch-50 + + Problem: Some people might have libpopt, but no popt.h, in which case + we tried to use the system copy and failed. + + Fix: Check for popt.h. If not present, use ./popt. + + modified files: + ChangeLog configure.ac + + +2004-07-06 13:05:12 GMT Martin Pool <mbp@sourcefrog.net> patch-49 + + Summary: + Prepare for 2.15 release + Revision: + distcc--devel--2--patch-49 + + + modified files: + ChangeLog NEWS configure.ac + + +2004-07-06 13:00:16 GMT Martin Pool <mbp@sourcefrog.net> patch-48 + + Summary: + Notes on version checking + Revision: + distcc--devel--2--patch-48 + + + modified files: + ChangeLog doc/todo/version-check.txt + + +2004-07-06 12:47:38 GMT Martin Pool <mbp@sourcefrog.net> patch-47 + + Summary: + Doc + Revision: + distcc--devel--2--patch-47 + + + new files: + doc/todo/.arch-ids/monitor-legend.txt.id + doc/todo/monitor-legend.txt + + modified files: + ChangeLog + + +2004-07-06 09:03:44 GMT Martin Pool <mbp@sourcefrog.net> patch-46 + + Summary: + compress: assume a larger decompression buffer by default so less likely to retry + Revision: + distcc--devel--2--patch-46 + + + modified files: + ChangeLog src/compress.c + + +2004-07-06 08:50:24 GMT Martin Pool <mbp@sourcefrog.net> patch-45 + + Summary: + remove mmap/lzo support + Revision: + distcc--devel--2--patch-45 + + + modified files: + ChangeLog NEWS doc/results.txt src/compress.c + + +2004-07-06 08:27:44 GMT Martin Pool <mbp@sourcefrog.net> patch-44 + + Summary: + dcc_r_bulk_lzo1x: fix nasty bug in mmap recv lzo + Revision: + distcc--devel--2--patch-44 + + When reading in compressed data, our initial buffer might not be large + enough for the actual compressed data, so we need to free it and make + a larger one. When freeing the mmapped buffer, we need to pass both + address and length of the mapping. + + The bug was that we increased the length before unmapping and + therefore randomly unmapped some block of memory, causing a crash + later on. + + Fix: don't increase the length until we're done with the old value. + + This code is really too complex to be safe. + + modified files: + ChangeLog src/compress.c + + +2004-07-06 08:09:27 GMT Martin Pool <mbp@sourcefrog.net> patch-43 + + Summary: + fix warning + Revision: + distcc--devel--2--patch-43 + + + modified files: + ChangeLog src/daemon.c + + +2004-07-06 08:09:03 GMT Martin Pool <mbp@sourcefrog.net> patch-42 + + Summary: + tempfile.h: remove + Revision: + distcc--devel--2--patch-42 + + + removed files: + src/.arch-ids/tempfile.h.id src/tempfile.h + + modified files: + ChangeLog Makefile.in src/backoff.c src/cleanup.c src/cpp.c + src/daemon.c src/distcc.c src/distcc.h src/dparent.c + src/dsignal.c src/hosts.c src/lock.c src/mon-notify.c + src/mon-text.c src/mon.c src/prefork.c src/remote.c + src/serve.c src/state.c src/tempfile.c src/timefile.c + src/where.c + + +2004-07-06 08:06:57 GMT Martin Pool <mbp@sourcefrog.net> patch-41 + + Summary: + distccd: chdir to $TMPDIR not / at startup + Revision: + distcc--devel--2--patch-41 + + + modified files: + ChangeLog NEWS src/daemon.c + + +2004-07-06 08:05:30 GMT Martin Pool <mbp@sourcefrog.net> patch-40 + + Summary: + dcc_get_tmp_top: make public + Revision: + distcc--devel--2--patch-40 + + + modified files: + ChangeLog src/tempfile.c src/tempfile.h + + +2004-07-06 08:00:29 GMT Martin Pool <mbp@sourcefrog.net> patch-39 + + Summary: + dcc_log_child_exited: indicate if core was produced + Revision: + distcc--devel--2--patch-39 + + + modified files: + ChangeLog src/dparent.c + + +2004-07-06 05:10:05 GMT Martin Pool <mbp@sourcefrog.net> patch-38 + + Summary: + + Revision: + distcc--devel--2--patch-38 + + + + + modified files: + ChangeLog src/arg.c src/argutil.c src/distcc.c src/distcc.h + src/implicit.c + + +2004-07-06 05:03:25 GMT Martin Pool <mbp@sourcefrog.net> patch-37 + + Summary: + argutil.c: Doc + Revision: + distcc--devel--2--patch-37 + + + modified files: + ChangeLog src/argutil.c + + +2004-07-06 05:00:57 GMT Martin Pool <mbp@sourcefrog.net> patch-36 + + Summary: + arg.h: fold into distcc.h + Revision: + distcc--devel--2--patch-36 + + + removed files: + src/.arch-ids/arg.h.id src/arg.h + + modified files: + ChangeLog Makefile.in src/arg.c src/argutil.c src/clirpc.c + src/compile.c src/cpp.c src/distcc.c src/distcc.h src/exec.c + src/h_argvtostr.c src/h_ccvers.c src/h_scanargs.c + src/h_strip.c src/implicit.c src/serve.c src/srvrpc.c + src/ssh.c src/strip.c + + +2004-07-06 04:54:15 GMT Martin Pool <mbp@sourcefrog.net> patch-35 + + Summary: + dcc_free_argv: new function + Revision: + distcc--devel--2--patch-35 + + + modified files: + ChangeLog src/arg.h src/argutil.c + + +2004-07-06 04:47:46 GMT Martin Pool <mbp@sourcefrog.net> patch-34 + + Summary: + Remove redundant temporary file cleanup in non-forking mode. + Revision: + distcc--devel--2--patch-34 + + + modified files: + ChangeLog NEWS src/dparent.c src/serve.c + + +2004-06-18 23:47:56 GMT Martin Pool <mbp@sourcefrog.net> patch-33 + + Summary: + roadmap update + Revision: + distcc--devel--2--patch-33 + + + modified files: + ChangeLog doc/roadmap.txt + + +2004-06-17 04:15:48 GMT Martin Pool <mbp@sourcefrog.net> patch-32 + + Summary: + Doc + Revision: + distcc--devel--2--patch-32 + + + modified files: + ChangeLog src/lock.c + + +2004-06-12 08:47:59 GMT Martin Pool <mbp@sourcefrog.net> patch-31 + + Summary: + dcc_service_job: Doc + Revision: + distcc--devel--2--patch-31 + + + modified files: + ChangeLog src/serve.c + + +2004-06-11 08:31:22 GMT Martin Pool <mbp@sourcefrog.net> patch-30 + + Summary: + protocol-3: I think there's no need for hash after all + Revision: + distcc--devel--2--patch-30 + + + modified files: + ChangeLog doc/protocol-3.txt + + +2004-06-11 08:19:20 GMT Martin Pool <mbp@sourcefrog.net> patch-29 + + Summary: + protocol-3: describe request format; propose adding CRC + Revision: + distcc--devel--2--patch-29 + + + modified files: + ChangeLog doc/protocol-3.txt + + +2004-06-10 04:55:25 GMT Martin Pool <mbp@sourcefrog.net> patch-28 + + Summary: + protocol-3 design development + Revision: + distcc--devel--2--patch-28 + + + modified files: + ChangeLog doc/protocol-3.txt + + +2004-06-10 03:18:55 GMT Martin Pool <mbp@hp.com> patch-27 + + Summary: + todo: notes on file permissions + Revision: + distcc--devel--2--patch-27 + + + new files: + doc/todo/.arch-ids/permissions.txt.id doc/todo/permissions.txt + + modified files: + ChangeLog TODO + + +2004-06-10 02:47:13 GMT Martin Pool <mbp@hp.com> patch-26 + + Summary: + cases/hello.c: Include more headers to trigger compression + Revision: + distcc--devel--2--patch-26 + + + modified files: + ChangeLog cases/hello.c + + +2004-06-01 06:52:14 GMT Martin Pool <mbp@hp.com> patch-25 + + Summary: + distccmon-text(1) typo fix from Lisa + Revision: + distcc--devel--2--patch-25 + + + modified files: + ChangeLog man/distccmon-text.1 + + +2004-05-30 05:54:37 GMT Martin Pool <mbp@sourcefrog.net> patch-24 + + Summary: + Add fixme comments for places where memory is probably leaked + Revision: + distcc--devel--2--patch-24 + + + modified files: + ChangeLog src/arg.c src/compile.c src/cpp.c src/where.c + + +2004-05-30 05:48:09 GMT Martin Pool <mbp@sourcefrog.net> patch-23 + + Summary: + Doc + Revision: + distcc--devel--2--patch-23 + + + new files: + doc/todo/.arch-ids/gnome-leak.txt.id doc/todo/gnome-leak.txt + + modified files: + ChangeLog + + +2004-05-29 05:10:27 GMT Martin Pool <mbp@sourcefrog.net> patch-22 + + Summary: + More TODO notes on scheduling + Revision: + distcc--devel--2--patch-22 + + + + new files: + doc/todo/.arch-ids/host-selection.txt.id + doc/todo/.arch-ids/randomize-order.txt.id + doc/todo/host-selection.txt doc/todo/randomize-order.txt + + modified files: + ChangeLog + + +2004-05-28 23:42:32 GMT Martin Pool <mbp@sourcefrog.net> patch-21 + + Summary: + patch from joshh to randomize host list + Revision: + distcc--devel--2--patch-21 + + In http://lists.samba.org/archive/distcc/2004q2/002250.html, Dan + proposed randomizing the hosts list. Here's a patch to add that + feature, controlled by a special --randomize option in the hosts list. + On a large shared build cluster, this helps spread the load + without requiring separate hosts lists for each user. + Martin, what do you think? + + + + + new files: + patches/.arch-ids/joshh-random.diff.id + patches/joshh-random.diff + + modified files: + ChangeLog + + +2004-05-08 12:16:47 GMT Martin Pool <mbp@sourcefrog.net> patch-20 + + Summary: + Update plans + Revision: + distcc--devel--2--patch-20 + + + new files: + doc/todo/.arch-ids/window-geometry.txt.id + doc/todo/window-geometry.txt + + modified files: + ChangeLog doc/roadmap.txt + + +2004-05-06 03:20:08 GMT Martin Pool <mbp@sourcefrog.net> patch-19 + + Summary: + 'make uninstall' note + Revision: + distcc--devel--2--patch-19 + + + new files: + doc/todo/.arch-ids/make-uninstall.txt.id + doc/todo/make-uninstall.txt + + modified files: + ChangeLog + + +2004-05-05 06:34:07 GMT Martin Pool <mbp@sourcefrog.net> patch-18 + + Summary: + Doc + Revision: + distcc--devel--2--patch-18 + + + modified files: + ChangeLog NEWS src/remote.c + + +2004-05-03 00:41:02 GMT Martin Pool <mbp@sourcefrog.net> patch-17 + + Summary: + Red Hat fix from Colin + Revision: + distcc--devel--2--patch-17 + + Patches applied: + + * walters@verbum.org--2003/distcc--devel--2.14--patch-5 + merge from mbp + + * walters@verbum.org--2003/distcc--devel--2.14--patch-6 + actually expand variables + + + modified files: + ChangeLog contrib/redhat/init contrib/redhat/logrotate + contrib/redhat/xinetd + + new patches: + walters@verbum.org--2003/distcc--devel--2.14--patch-5 + walters@verbum.org--2003/distcc--devel--2.14--patch-6 + + +2004-05-02 10:42:57 GMT Martin Pool <mbp@sourcefrog.net> patch-16 + + Summary: + Note rate calculation + Revision: + distcc--devel--2--patch-16 + + + modified files: + ChangeLog NEWS + + +2004-05-02 10:40:35 GMT Martin Pool <mbp@sourcefrog.net> patch-15 + + Summary: + Client calculates overall compilation rate for remote jobs + Revision: + distcc--devel--2--patch-15 + + + modified files: + ChangeLog src/bulk.c src/distcc.h src/remote.c + + +2004-05-02 10:30:00 GMT Martin Pool <mbp@sourcefrog.net> patch-14 + + Summary: + Collect SSH child even when it fails + Revision: + distcc--devel--2--patch-14 + + + modified files: + ChangeLog src/remote.c + + +2004-05-02 10:22:22 GMT Martin Pool <mbp@sourcefrog.net> patch-13 + + Summary: + Remove unnecessary check that cpp produced output + Revision: + distcc--devel--2--patch-13 + + + modified files: + ChangeLog src/remote.c + + +2004-05-02 10:20:01 GMT Martin Pool <mbp@sourcefrog.net> patch-12 + + Summary: + Pass back size of transmitted files + Revision: + distcc--devel--2--patch-12 + + Also fix printf formats for file sizes. + + Remove old prototype for dcc_x_file_timed. + + modified files: + ChangeLog src/bulk.c src/bulk.h src/remote.c src/serve.c + + +2004-05-02 10:06:11 GMT Martin Pool <mbp@sourcefrog.net> patch-11 + + Summary: + Ignore gtags temporaries + Revision: + distcc--devel--2--patch-11 + + + modified files: + ChangeLog src/.arch-inventory + + +2004-05-02 10:05:11 GMT Martin Pool <mbp@sourcefrog.net> patch-10 + + Summary: + Remove dcc_send_job_corked wrapper + Revision: + distcc--devel--2--patch-10 + + Just insert/remove corks at the right places. + + modified files: + ChangeLog src/remote.c + + +2004-05-02 10:00:52 GMT Martin Pool <mbp@sourcefrog.net> patch-9 + + Summary: + Split out code to wait for cpp + Revision: + distcc--devel--2--patch-9 + + + modified files: + ChangeLog src/remote.c + + +2004-05-02 09:58:22 GMT Martin Pool <mbp@sourcefrog.net> patch-8 + + Summary: + Refactor code to send requests into remote.c + Revision: + distcc--devel--2--patch-8 + + + modified files: + ChangeLog src/clirpc.c src/distcc.h src/remote.c + + +2004-05-02 09:49:23 GMT Martin Pool <mbp@sourcefrog.net> patch-7 + + Summary: + Plan for calculating rate + Revision: + distcc--devel--2--patch-7 + + + new files: + doc/todo/.arch-ids/show-rate.txt.id doc/todo/show-rate.txt + + modified files: + ChangeLog + + +2004-05-02 09:38:40 GMT Martin Pool <mbp@sourcefrog.net> patch-6 + + Summary: + Remove relic zip.c + Revision: + distcc--devel--2--patch-6 + + + removed files: + src/.arch-ids/zip.c.id src/zip.c + + modified files: + ChangeLog Makefile.in + + +2004-05-02 09:35:26 GMT Martin Pool <mbp@sourcefrog.net> patch-5 + + Summary: + Remove old prototypes + Revision: + distcc--devel--2--patch-5 + + + modified files: + ChangeLog src/daemon.h src/dparent.c + + +2004-05-02 08:46:14 GMT Martin Pool <mbp@sourcefrog.net> patch-4 + + Summary: + Remove non-prefork mode + Revision: + distcc--devel--2--patch-4 + + Only choices now are preforking, or not forking at all. + + modified files: + ChangeLog NEWS src/dopt.c src/dparent.c + + +2004-05-02 08:35:51 GMT Martin Pool <mbp@sourcefrog.net> patch-3 + + Summary: + Set version to 2.15pre + Revision: + distcc--devel--2--patch-3 + + + modified files: + ChangeLog NEWS configure.ac + + +2004-05-02 08:34:49 GMT Martin Pool <mbp@sourcefrog.net> patch-2 + + Summary: + Plans for upcoming releases + Revision: + distcc--devel--2--patch-2 + + + modified files: + ChangeLog doc/roadmap.txt + + +2004-05-02 08:25:17 GMT Martin Pool <mbp@sourcefrog.net> patch-1 + + Summary: + New ChangeLog for new revision + Revision: + distcc--devel--2--patch-1 + + + new files: + ChangeLog + + renamed files: + ChangeLog + ==> ChangeLog-2.14 + + +2004-05-02 05:07:46 GMT Martin Pool <mbp@sourcefrog.net> base-0 + + Summary: + tag of mbp@sourcefrog.net--2004/distcc--devel--2.14--version-0 + Revision: + distcc--devel--2--base-0 + + (automatically generated log message) + + new patches: + mbp@sourcefrog.net--2004-happy/distcc--devel--2.14--base-0 + mbp@sourcefrog.net--2004-happy/distcc--devel--2.14--patch-1 + mbp@sourcefrog.net--2004-happy/distcc--devel--2.14--patch-2 + mbp@sourcefrog.net--2004-happy/distcc--devel--2.14--patch-3 + mbp@sourcefrog.net--2004-happy/distcc--devel--2.14--patch-4 + mbp@sourcefrog.net--2004-happy/distcc--devel--2.14--patch-5 + mbp@sourcefrog.net--2004-happy/distcc--devel--2.14--patch-6 + mbp@sourcefrog.net--2004-happy/distcc--devel--2.14--patch-7 + mbp@sourcefrog.net--2004-happy/distcc--devel--2.14--patch-8 + mbp@sourcefrog.net--2004-happy/distcc--devel--2.14--patch-9 + mbp@sourcefrog.net--2004-happy/distcc--devel--2.14--patch-10 + mbp@sourcefrog.net--2004-happy/distcc--devel--2.14--patch-11 + mbp@sourcefrog.net--2004-happy/distcc--devel--2.14--patch-12 + mbp@sourcefrog.net--2004/distcc--cvs--0--base-0 + mbp@sourcefrog.net--2004/distcc--cvs--0--patch-1 + mbp@sourcefrog.net--2004/distcc--cvs--0--patch-2 + mbp@sourcefrog.net--2004/distcc--cvs--0--patch-3 + mbp@sourcefrog.net--2004/distcc--cvs--0--patch-4 + mbp@sourcefrog.net--2004/distcc--cvs--0--patch-5 + mbp@sourcefrog.net--2004/distcc--cvs--0--patch-6 + mbp@sourcefrog.net--2004/distcc--cvs--0--patch-7 + mbp@sourcefrog.net--2004/distcc--cvs--0--patch-8 + mbp@sourcefrog.net--2004/distcc--cvs--0--patch-9 + mbp@sourcefrog.net--2004/distcc--cvs--0--patch-10 + mbp@sourcefrog.net--2004/distcc--cvs--0--patch-11 + mbp@sourcefrog.net--2004/distcc--devel--2.14--base-0 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-1 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-2 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-3 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-4 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-5 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-6 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-7 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-8 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-9 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-10 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-11 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-12 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-13 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-14 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-15 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-16 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-17 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-18 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-19 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-20 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-21 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-22 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-23 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-24 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-25 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-26 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-27 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-28 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-29 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-30 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-31 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-32 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-33 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-34 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-35 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-36 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-37 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-38 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-39 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-40 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-41 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-42 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-43 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-44 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-45 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-46 + mbp@sourcefrog.net--2004/distcc--devel--2.14--patch-47 + mbp@sourcefrog.net--2004/distcc--devel--2.14--version-0 + mbp@sourcefrog.net--2004/distcc--release--2.13--base-0 + walters@verbum.org--2003/distcc--devel--2.14--base-0 + walters@verbum.org--2003/distcc--devel--2.14--patch-1 + walters@verbum.org--2003/distcc--devel--2.14--patch-2 + walters@verbum.org--2003/distcc--devel--2.14--patch-3 + walters@verbum.org--2003/distcc--devel--2.14--patch-4 + + diff --git a/distcc/ChangeLog.old b/distcc/ChangeLog.old new file mode 100644 index 0000000..90580f1 --- /dev/null +++ b/distcc/ChangeLog.old @@ -0,0 +1,16140 @@ +2004-04-10 Martin Pool <mbp@sourcefrog.net> + + * src/mon-gnome.c (dcc_gnome_make_mainwin): Check gtk version and + don't use gtk_window_set_icon_from_file before 2.2.0. Reported by + Dag Wieers. + +2004-03-21 Martin Pool <mbp@sourcefrog.net> + + * src/exec.c (dcc_critique_status): Log input filename. + + * src/clirpc.c (dcc_send_job): Log input filename, + + * src/remote.c (dcc_compile_remote): Log input filename. + + * src/serve.c (dcc_run_job): Log input filename. + + * src/compile.c (dcc_compile_local): Log input filename. + +2004-03-03 Martin Pool <mbp@sourcefrog.net> + + * src/mon-gnome.c: Quieten g_messages. + + * src/distcc.c (dcc_show_usage): Describe DISTCC_DIR and other + things. + + * man/distcc.1: Document DISTCC_DIR and fix some spelling errors. + Patch from Thomas Schwinge. + + * src/hosts.c (dcc_get_hostlist): Get hosts from + $DISTCC_DIR/hosts, rather than hardcoding to ~/.distcc. + + * src/tempfile.c (dcc_get_top_dir): Make this public. Just log a + warning if $HOME is not set. + +2004-03-02 Martin Pool <mbp@sourcefrog.net> + + * src/srvnet.c (dcc_listen_by_addr): Don't create the socket, just + listen() on it. + (dcc_check_client): Do access control checks on ipv4-mapped or + ipv4-compat IPv6 addresses. + + * src/srvnet.c (dcc_socket_listen) [ENABLE_RFC2553]: Try creating + sockets in every returned address family until we get one that + works. Fix leak of addrinfo list. + + * src/srvnet.c (dcc_socket_listen) [!ENABLE_RFC2553]: Create + socket here. + +2004-03-01 Martin Pool <mbp@sourcefrog.net> + + * src/cleanup.c (dcc_cleanup_tempfiles): If DISTCC_SAVE_TEMPS is + set, then we still need to remove temp files from the list or it + will overflow. + + * src/mon-gnome.c, src/mon.c: Don't include netutil. + + * src/dparent.c (dcc_standalone_server): Set defer-accept bit. + + * man/distccd.1: Document DISTCC_TCP_DEFER_ACCEPT. + + * src/netutil.c (dcc_defer_accept): New function. + +2004-02-29 Martin Pool <mbp@sourcefrog.net> + + * test/testdistcc.py (ScanArgs_Case): Test -Wa,-xarch=v8. + + * src/arg.c (dcc_scan_args): Allow "-Wa,-xarch=v8" to be remote. + Reported by Ben Scarlet. + + * test/testdistcc.py (ScanArgs_Case): Add test cases for -x + handling. + + * src/arg.c (dcc_scan_args): Handle invocations like "-xcpp" with + no space after -x. Suggested by Ben Scarlet. + + * test/testdistcc.py (CompressedCompile_Case): Add a test of + compression. + + * src/mon-gnome.c: Include sys/loadavg.h if available. + + * configure.ac: Check for sys/loadavg.h. Suggested by Dimitri + Papadopoulos. + + * man/distcc.1: Document comments in host files. + + * test/testdistcc.py (ParseHostSpec_Case): Add test for + "localhostbutnotreally". + + * src/hosts.c (dcc_parse_hosts): Fix matching of hosts with names + like "localhost2". + +2004-02-20 Martin Pool <mbp@sourcefrog.net> + + * src/compress.c (dcc_r_bulk_lzo1x): ftruncate the file after + munmapping, rather than before. Might be better on HP-UX which + has problems with IO on mapped files. + + * README.packaging: Update description of why packagers should + change version numbers. + +2004-02-19 Martin Pool <mbp@sourcefrog.net> + + * src/netutil.c (dcc_sockaddr_to_string): Handle null sockaddr. + + * src/srvnet.c (dcc_check_client): Handle null sockaddr. + + * src/daemon.c (dcc_inetd_server): If there is no sockaddr, pass + it as NULL. + + * src/netutil.c (dcc_sockaddr_to_string) [ENABLE_RFC2553]: + Failure to convert the address to a string should be just a + warning, not an error. Add special cases for unix-domain sockets + and unknown address families. Possibly fixes SSH connections with + ENABLE_RFC2553. + + * src/daemon.c (dcc_inetd_server): Downgrade warning on + getpeername failure to just a notice message. + +2004-02-19 Albert China <china@thewrittenword.com> + + * test/testdistcc.py: Get test suite working on most of the + platforms we support: + + 1. Not much use in testing with the native compiler so we + *force* the test suite to use gcc. + + 2. Rather than picking up gcc from $PATH, we pass the full path + to GCC. This avoids problems when distccd is running. + + 3. I've added known failures on some platforms. For example, the + assembler test should only run on Linux x86. Where we know + the test will fail, we print: + + DashONoSpace_Case NOTRUN, GCC mips-tfile wants space after -o + ... + RemoteAssemble_Case NOTRUN, Linux x86 only + PreprocessAsm_Case NOTRUN, Linux x86 only + ... + + The tests pass on: HP-UX 10.20, 11.00, 11i; IRIX 6.5; Redhat Linux + 7.1, 9; Solaris 7, 8, 9; Tru64 UNIX 4.0d, 5.1 + +2004-02-18 Albert China <china@thewrittenword.com> + + These patches were tested on: AIX 4.3.2, 5.1; HP-UX 10.20, 11.00, + 11i; IRIX 6.5; Redhat Linux 7.1, 9; Solaris 2.5.1, 2.6, 7, 8, 9; + Tru64 UNIX 4.0D, 5.1: + + * src/exitcode.h: IBM C compiler doesn't like trailing commas + after last enum constant. + + * src/clinet.c: Define h_errno for HP-UX 10.20. + + * src/distcc.h: Forward declaration of 'struct sockaddr' gives + problems with IBM C compiler. And, it's not needed. + + * src/serve.c: Forgot to include <sys/socket.h> Needed on HP-UX + 10.20, 11.00, 11i. + + * src/types.h: Remove definition of socklen_t if unavailable. We + not declare it correctly via autoconf. + + * configure.ac: + a) Better detection for socklen_t. This code is taken from curl but + we submitted it so we own the copyright. Feel free to use as you + please. + b) Existence of mmap() doesn't imply MAP_FAILED exists. So, test + and define it if unavailable. + c) Replace the AC_CHECK_FUNCS(connect) mess. + +2004-01-30 Martin Pool <mbp@sourcefrog.net> + + * src/hosts.c (dcc_parse_hosts): Fix problem where we accidentally + detected localhost at end of string. + + * src/h_hosts.c (main): Fix up verbose mode. + + * test/testdistcc.py (ParseHostSpec_Case.runtest): Test parsing of + comments in host specifications. + + * src/hosts.c (dcc_parse_hosts): Skip over hash comments in host + specifications. + +2004-01-11 Martin Pool <mbp@sourcefrog.net> + + * src/srvnet.c (dcc_check_client): Take list of allowed addresses + as a new parameter so that this file doesn't depend on opt.c. + + * src/h_sa2str.c: New test harness. + + * Makefile.in (h_sa2str): new test. + +2004-01-09 Martin Pool <mbp@sourcefrog.net> + + * configure.ac: Make --without-gnome, --without-gtk, + --disable-profile all turn the relevant options off rather than + on. + + * Makefile.in: Add man/distccmon-text.1, and clean up manpage + handling. + + * man/distccmon-text.1: Fix some typos. + + * src/dopt.c (distccd_parse_options): Option arguments should be + held in (const char *). + + * src/setuid.c (dcc_discard_root): Must setuid after setgid, not + before. Fix from Wayne Davison. + + * src/mon.c (dcc_mon_check_orphans): When checking if a process + exists, accept EPERM as indicating it exists but isn't ours. This + allows watching the directory of a different user. Reported by + Ernst Bachmann. + +2003-12-21 Shri Shrikumar <shri@urbyte.com> + + * man/distccmon-text.1: New manpage. + +2003-12-15 Martin Pool <mbp@sourcefrog.net> + + * man/distccd.1: Mention TMPDIR. + + * man/distcc.1: We don't use a subdirectory of TMPDIR anymore. + +2003-11-28 Harold L Hunt II <huntharo@msu.edu> + + * configure.ac, Makefile.in: Add --with-docdir=PATH option to set + install location for documents. The default is the same as + previously: ${datadir}/doc/distcc. + +2003-11-28 Martin Pool <mbp@sourcefrog.net> + + * src/distcc.h (dcc_sockaddr_storage): Different method for + choosing the type for dcc_sockaddr_storage. We now use a plain + sockaddr unless RFC2553 was requested, in which case we use + sockaddr_storage. HAVE_SOCKADDR_STORAGE is only used as a check + that the RFC2553 implementation is reasonable. + + * src/distcc.h (dcc_sockaddr_storage): Use a new type name for our + replacement of sockaddr_storage, rather than calling it + sockaddr_storage, to make it more clear that it's determined by + autoconf. + + * src/prefork.c (dcc_preforked_child): Use dcc_sockaddr_storage. + + * src/dparent.c (dcc_forking_parent): Likewise. + + * src/daemon.c (dcc_inetd_server): Likewise. + +2003-11-23 Martin Pool <mbp@sourcefrog.net> + + * src/netutil.c (dcc_sockaddr_to_string) [ENABLE_RFC2553]: Include + the port number in the returned string, as for !ENABLE_RFC2553. + This looks a bit wierd for IPv6 but is legible and unambiguous at + least for output. Increase static buffer size. + + * src/clinet.c (dcc_connect_timed): Check SO_ERROR to see if the + connection failed so that we can trap it at this point rather than + waiting until we start doing IO. + + * src/distcc.h [ENABLE_RFC2553]: sockaddr_storage is required for + RFC2553. + + * src/dparent.c (dcc_nofork_parent, dcc_forking_parent): Socket + addresses should be stored on the stack in sockaddr_storage so + that IPv6 addresses will fit. We always have this type, or can + simulate it. + + * src/prefork.c (dcc_preforked_child): Likewise. + + * src/srvnet.c (dcc_socket_listen) [ENABLE_RFC2553]: Don't prefer + to listen on IPv4 addresses, just use whatever the operating + system thinks is best. + + * INSTALL: Suggest using --with-gnome and --enable-rfc2553. + + * man/distccd.1: Add description of --log-level. + + * src/dopt.c: New --log-level option to accomodate people who only + want to log errors. + + * src/trace.c, src/trace.h (rs_loglevel_from_name): New function. + + * configure.ac, Makefile.in: Check pkg-config information for + GNOME/GTK+ at configure time, not build time. This is a bit + quicker than running the script for every file we build, and means + that PKG_CONFIG_PATH only needs to be set for configure. + + * src/lock.c: Doc. + +2003-11-17 Lionel Sausin <lionel.sausin@free.fr> + + * man/fr/distcc.1, man/fr/distccd.1: French translations of the + manual pages. + +2003-11-17 Martin Pool <mbp@sourcefrog.net> + + * distcc.h: MAXPATHLEN is not defined on GNU/Hurd, so supply a + reasonable default value of 4096. Reported by Santiago Vila. + +2003-11-17 Martin Pool <mbp@sourcefrog.net> + + * sendfile.c: Documentation updates. + +2003-11-17 Allan Saddi <allan@saddi.com> + + * sendfile.c (sys_sendfile): BSD implementation of this function + needs to return -1 when transmission fails with EAGAIN and no + bytes were sent. + +2003-11-17 Martin Pool <mbp@sourcefrog.net> + + * setuid.c (dcc_discard_root): Wayne suggests calling + setgid()/setuid() before doing setgroups(). setgroups() on Mac OS + X Jaguar can't seem to handle setting to 0 groups, so just set it + to the same as the regular group. + +2003-10-30 19:02 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-10-28 11:38 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version. + +2003-10-23 13:36 Martin Pool <mbp@samba.org> + + * autogen.sh: Remove check on autoconf version because it breaks + on non-numeric versions like "2.57a". + +2003-10-23 10:50 Martin Pool <mbp@samba.org> + + * man/distccd.1: Add some description of search paths. + +2003-10-23 10:44 Martin Pool <mbp@samba.org> + + * man/distcc.1: Add some description of search paths. + +2003-10-23 10:14 Martin Pool <mbp@samba.org> + + * TODO: More tasks to do. + +2003-10-23 09:56 Martin Pool <mbp@samba.org> + + * NEWS, configure.ac: Prepare for 2.11.2 release + +2003-10-14 14:23 Martin Pool <mbp@samba.org> + + * gnome/distccmon-gnome.desktop, NEWS: Desktop file corrections + from Dag Wieers. + +2003-10-13 23:57 Martin Pool <mbp@samba.org> + + * TODO: Notes on current bugs. + +2003-10-13 20:05 Martin Pool <mbp@samba.org> + + * src/distcc.c: Don't trim the path at all when our invocation + name is "distcc". + +2003-10-13 19:52 Martin Pool <mbp@samba.org> + + * src/util.c: dcc_trim_path: Trace the compiler name. + +2003-10-13 19:51 Martin Pool <mbp@samba.org> + + * src/util.c: dcc_trim_path: Doc. + +2003-10-13 19:39 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc. + +2003-10-13 19:24 Martin Pool <mbp@samba.org> + + * src/climasq.c: Doc. + +2003-10-13 19:03 Martin Pool <mbp@samba.org> + + * NEWS, src/distcc.c, src/dsignal.c: Fatal signal handlers for + client and daemon should reset the signal vector before doing + anything else, to protect against an (unlikely) spin if the + signal is re-sent. + +2003-10-13 19:00 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc typo + +2003-10-13 18:39 Martin Pool <mbp@samba.org> + + * src/: distcc.c, dsignal.c: Use AC_TYPE_SIGNAL to set signal + handler return type for portability. + +2003-10-13 18:38 Martin Pool <mbp@samba.org> + + * doc/example/xinetd, NEWS: Add type = UNLISTED to cope without + an /etc/services entry. + +2003-10-13 18:34 Martin Pool <mbp@samba.org> + + * configure.ac: Doc + + * Add check for signal return type. + +2003-10-13 17:56 Martin Pool <mbp@samba.org> + + * man/distcc.1: Bump date. + +2003-10-13 17:56 Martin Pool <mbp@samba.org> + + * man/distcc.1, NEWS: Clear up meaning of UNCACHED_ERR_FD. + +2003-10-13 17:37 Martin Pool <mbp@samba.org> + + * README.packaging: Suggest adding to /etc/services. + +2003-10-13 17:06 Martin Pool <mbp@samba.org> + + * man/distccd.1: Clarifications/corrections to --allow + description. + +2003-10-13 16:52 Martin Pool <mbp@samba.org> + + * NEWS: IRIX fixes. + +2003-10-13 16:42 Martin Pool <mbp@samba.org> + + * src/serve.c: dcc_check_compiler_masq: Remove dead variable. + +2003-10-13 16:40 Martin Pool <mbp@samba.org> + + * src/dparent.c: dcc_log_child_exited: Use appropriate log + severity to match the signal severity, even on machines that + don't have strsignal(). + +2003-10-13 16:37 Martin Pool <mbp@samba.org> + + * TODO: Notes on better scheduling. + +2003-10-13 16:26 Martin Pool <mbp@samba.org> + + * NEWS: Remove dependency on libglade. + + * Fix --without-gnome. + +2003-10-13 16:24 Martin Pool <mbp@samba.org> + + * gnome/: distccmon-gnome.glade, distccmon-gnome.gladep: Remove + Glade packages. + +2003-10-13 16:20 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Set icon on monitor window from png file. + +2003-10-13 16:15 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Remove dependency on Glade by rolling back to + by-hand construction of window components, based on the code in + 2.10. + +2003-10-13 16:10 Martin Pool <mbp@samba.org> + + * Makefile.in: Don't require libglade. + +2003-10-13 16:09 Martin Pool <mbp@samba.org> + + * configure.ac: Correct the handling of --without-gnome, etc. + Previously this was treated the same as --with-gnome. + + * Don't require libglade. + +2003-10-13 15:31 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version + +2003-10-08 15:47 Martin Pool <mbp@samba.org> + + * NEWS, configure.ac: Prepare for 2.11.1 release. + +2003-10-08 15:45 Martin Pool <mbp@samba.org> + + * NEWS, src/arg.c, test/testdistcc.py: C++ compilation with + -frepo must be local, because it emits .rpo files. + +2003-10-07 16:12 Martin Pool <mbp@samba.org> + + * src/bulk.c: dcc_x_file_lzo1x should return any errors that + occur. + +2003-10-07 16:07 Martin Pool <mbp@samba.org> + + * src/exec.c: dcc_inside_child should be void and should never + return. + +2003-10-07 16:01 Martin Pool <mbp@samba.org> + + * src/: util.c, util.h: dcc_exit can be void. + +2003-10-07 15:52 Martin Pool <mbp@samba.org> + + * man/distcc.1: Typo fix from Lionel Sausin. + +2003-10-01 13:56 Martin Pool <mbp@samba.org> + + * src/mon.h, NEWS: Description from Frerich of how to write + monitor programs, with some edits by me. + +2003-09-30 12:54 Martin Pool <mbp@samba.org> + + * NEWS: Put Gnome data files into PKGDATADIR, e.g. + /usr/local/share/distcc/, rather than the top-level datadir. + +2003-09-30 12:49 Martin Pool <mbp@samba.org> + + * Makefile.in, src/mon-gnome.c: Put Gnome data files into + PKGDATADIR, e.g. /usr/local/share/distcc/, rather than the + top-level datadir. + +2003-09-30 12:42 Martin Pool <mbp@samba.org> + + * configure.ac, Makefile.in: New @INSTALL_GNOME@ substitution so + that Gnome/GTK data files are only installed when necessary. + +2003-09-30 12:40 Martin Pool <mbp@samba.org> + + * INSTALL: Give dependencies for --with-gtk. + +2003-09-30 09:54 Martin Pool <mbp@samba.org> + + * src/state.h: Remove stdint.h. We don't use it, and it does not + exist on FreeBSD 4-STABLE, according to Frerich Raabe. + +2003-09-29 22:23 Martin Pool <mbp@samba.org> + + * man/distcc.1: Set datestamp. + +2003-09-29 22:21 Martin Pool <mbp@samba.org> + + * NEWS: Fix for state.h + +2003-09-29 22:19 Martin Pool <mbp@samba.org> + + * man/distcc.1: Documentation corrections from Lionel Sausin. + +2003-09-29 16:57 Martin Pool <mbp@samba.org> + + * src/tempfile.c, NEWS: Check that we have permission to write to + the specified TMPDIR, or otherwise fail. + +2003-09-29 16:46 Martin Pool <mbp@samba.org> + + * src/mon.h: Doc rename to dcc_history. + +2003-09-29 16:44 Martin Pool <mbp@samba.org> + + * src/mon.h: Explain why dnotify is cut out. + +2003-09-29 16:33 Martin Pool <mbp@samba.org> + + * NEWS: stdint.h is not on iricks or sloaris either. + +2003-09-29 16:30 Martin Pool <mbp@samba.org> + + * src/access.c, src/h_parsemask.c, src/mon-text.c, src/state.c, + configure.ac: Remove stdint.h. We don't use it, and it does + not exist on FreeBSD 4-STABLE, according to Frerich Raabe. + +2003-09-29 16:16 Martin Pool <mbp@samba.org> + + * configure.ac: Make it just --with-gtk. + +2003-09-29 16:15 Martin Pool <mbp@samba.org> + + * configure.ac: Fix help string for --with-gtk+. + +2003-09-29 16:13 Martin Pool <mbp@samba.org> + + * NEWS, configure.ac: Add support for building with either GNOME + or plain GTK+. + +2003-09-29 16:08 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Remove unnecessary inclusion of headers for + pango. + + * Allow compilation with either GNOME or plain GTK+, depending on + WITH_GNOME and WITH_GTK. + +2003-09-29 16:06 Martin Pool <mbp@samba.org> + + * src/renderer.c: Remove unnecessary inclusion of headers for + gnome, pango and glade, and use of gettext macro. + +2003-09-27 23:13 Martin Pool <mbp@samba.org> + + * src/state.h: Fix state.h for use with C++. Patch from Frerich + Raabe. + +2003-09-27 19:42 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version. + +2003-09-25 13:39 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Include GTK as well. + +2003-09-24 15:33 Martin Pool <mbp@samba.org> + + * Makefile.in: Change for new log archiving method. + +2003-09-23 16:12 Martin Pool <mbp@samba.org> + + * NEWS: Prepare for release. + +2003-09-23 15:58 Martin Pool <mbp@samba.org> + + * configure.ac: Run tests for GNOME packages when --with-gnome is + set. + +2003-09-23 15:51 Martin Pool <mbp@samba.org> + + * configure.ac: Bump to version 2.11. + +2003-09-23 15:43 Martin Pool <mbp@samba.org> + + * NEWS, src/distcc.c: Client catches SIGINT, SIGHUP and SIGTERM + and cleans up temporary files before terminating. + +2003-09-23 15:26 Martin Pool <mbp@samba.org> + + * NEWS: Make directories and state files with weak mode bits, to + try to avoid conflicts in shared distcc_dirs. + +2003-09-23 15:24 Martin Pool <mbp@samba.org> + + * src/tempfile.c: dcc_mkdir: Make directory with weak mode bits, + to try to avoid conflicts in shared distcc_dirs. + +2003-09-23 15:22 Martin Pool <mbp@samba.org> + + * src/lock.c: dcc_open_lockfile: Open lockfile with weak mode + bits, to try to avoid conflicts in shared distcc_dirs. + +2003-09-23 15:18 Martin Pool <mbp@samba.org> + + * gnome/: .cvsignore, distccmon-gnome-icon.png, + distccmon-gnome.desktop, distccmon-gnome.glade, + distccmon-gnome.gladep: Merge from branch-pretty. + + Update desktop file to include the right name. + +2003-09-23 15:12 Martin Pool <mbp@samba.org> + + * Makefile.in: Distribute and install GNOME data files. + +2003-09-23 15:00 Martin Pool <mbp@samba.org> + + * NEWS: Change to --with-gnome for consistency with other + packages. + +2003-09-23 14:57 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: The access mask 1.2.3.4/0 should match + anything. + +2003-09-23 14:53 Martin Pool <mbp@samba.org> + + * src/distcc.c: Fix bad bug in main() that caused us to exit + through the wrong path. + +2003-09-23 14:38 Martin Pool <mbp@samba.org> + + * configure.ac, INSTALL: Change to --with-gnome for consistency + with other packages. + +2003-09-23 14:28 Martin Pool <mbp@samba.org> + + * configure.ac: LINUXDOC is no longer a special variable. + +2003-09-23 14:23 Martin Pool <mbp@samba.org> + + * INSTALL, Makefile.in, NEWS, TODO, configure.ac, + doc/release-names.txt, src/clirpc.c, src/compile.c, src/distcc.c, + src/distcc.h, src/mon-fake.c, src/mon-gnome.c, src/mon-text.c, + src/mon.c, src/mon.h, src/remote.c, src/renderer.c, + src/renderer.h, src/state.c, src/state.h, src/util.c, src/util.h, + src/where.c: Merge the new GNOME monitor back from + 'branch-pretty': + + * GNOME monitor now uses a custom GtkCellRenderer subclass + (renderer.c, renderer.h) to draw a scarf-style history of the + states for the slot. + + * Now uses binary state files that are quicker to write out and + read in. Not compatible with monitors from the previous + version. + + * Structure renamed from dcc_mon_list to dcc_history. Text + fields are held directly in the structure to allow it to be + directly written out. + + * State files are written and rewritten in place, rather than + always being renamed into place. We cope reasonably gracefully + when reading back files that are truncated. + + * New strlcpy() utility. + + * Clean up cruft in dcc_lock_one() from when we had transmission + lock files. + + * Better handling of EXEEXT to allow tab completion to work in + Makefiles. + + * GNOME monitor is now constructed using libglade-2, rather than + the hard way. + + * New --enable-profile option for gprof. + + * Depends on libglade, pango, libgnome, libgnomeui, at least if + you want the graphical monitor. + + * Change UNUSED() macro to make sure the variable is not + accidentally used. + + * Rename state tags to consistent DCC_STATE_* + +2003-09-23 14:02 Martin Pool <mbp@samba.org> + + * Makefile.in: Doc. + +2003-09-23 14:00 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Change colors to a set selected from the GNOME + palette that are easier to distinguish. + +2003-09-23 13:44 Martin Pool <mbp@samba.org> + + * gnome/distccmon-gnome.glade, src/mon-gnome.c: Remove About and + Key windows, which don't do anything very useful at the moment. + +2003-09-22 17:33 Martin Pool <mbp@samba.org> + + * src/mon.c: Check structure size when loading binary state + files. + +2003-09-22 17:32 Martin Pool <mbp@samba.org> + + * src/: state.c, state.h, where.c: Don't make the client's state + structure global. + + * Don't need dcc_timeval_to_microseconds anymore. + +2003-09-22 17:29 Martin Pool <mbp@samba.org> + + * TODO: Remove done items. + +2003-09-22 17:24 Martin Pool <mbp@samba.org> + + * src/state.h: Add a size field to the state struct. + +2003-09-22 17:22 Martin Pool <mbp@samba.org> + + * src/mon.h: Don't need dcc_timeval_to_double + +2003-09-22 17:13 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Don't need sys/time.h + +2003-09-22 17:12 Martin Pool <mbp@samba.org> + + * src/lock.c: Don't need state.h anymore. + +2003-09-22 17:10 Martin Pool <mbp@samba.org> + + * src/: compile.c, distcc.c: Don't use STARTUP state anymore. + +2003-09-22 16:50 Martin Pool <mbp@samba.org> + + * INSTALL: Note gnome dependencies. + +2003-09-22 15:53 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Lower the priority of scanning for changes, so + that we're more likely to keep the UI responsive. + +2003-09-22 14:53 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Doc + +2003-09-22 14:51 Martin Pool <mbp@samba.org> + + * src/remote.c: Store hostname in state file, not the host + definition string. + +2003-09-20 19:36 Martin Pool <mbp@samba.org> + + * NEWS: Try safe lzo decompressor, to try to catch cases where + the compressed data is corrupt or our output buffer is too + small. + +2003-09-20 16:42 Martin Pool <mbp@samba.org> + + * src/compress.c: Try safe lzo decompressor, to try to catch + cases where the compressed data is corrupt or our output buffer + is too small. + +2003-09-19 17:23 Martin Pool <mbp@samba.org> + + * gnome/: distccmon-gnome-icon.png, distccmon-gnome.glade, + distccmon-gnome.gladep: Move icons. + + * Add menu item to show color key. + + * Set size through allocation of scroll area, not through the + window default_size. + +2003-09-19 17:21 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Add menu option to show chart key. + +2003-09-19 17:21 Martin Pool <mbp@samba.org> + + * src/: renderer.c, renderer.h: Set bar width so that the whole + history cell is filled. + +2003-09-19 16:53 Martin Pool <mbp@samba.org> + + * gnome/.cvsignore: Rename icon PNG + +2003-09-19 16:51 Martin Pool <mbp@samba.org> + + * gnome/distccmon-gnome.glade: Rename icon png. + +2003-09-19 16:35 Martin Pool <mbp@samba.org> + + * gnome/distccmon-gnome.desktop: Add draft FreeDesktop .desktop + definition. + +2003-09-19 16:02 Martin Pool <mbp@samba.org> + + * src/renderer.c: Choose bar width such that the complete history + roughly fills the cell. + +2003-09-19 15:40 Martin Pool <mbp@samba.org> + + * src/mon.c: Quieten warnings when polling state files. + +2003-09-19 15:39 Martin Pool <mbp@samba.org> + + * src/state.c: Change state name to "Preprocess". + +2003-09-19 15:15 Martin Pool <mbp@samba.org> + + * src/renderer.c: Doc. + +2003-09-19 14:57 Martin Pool <mbp@samba.org> + + * src/: mon-gnome.c, renderer.c, renderer.h: Create graphics + contexts for drawing state strips just once at startup, rather + than every time we draw a rectangle. Ought to be much more + efficient. + +2003-09-19 14:43 Martin Pool <mbp@samba.org> + + * configure.ac: Add --enable-profile option. + + * Cleanup CPPFLAGS generation. + +2003-09-19 14:29 Martin Pool <mbp@samba.org> + + * src/dparent.c, NEWS: In non-forking mode, make sure to close + the accepted fd after processing a request. + +2003-09-19 14:01 Martin Pool <mbp@samba.org> + + * NEWS: Allow access masks like 0.0.0.0/0, meaning allow access + from anywhere. Some adjustments required to allow for + behaviour of C bitshift operators. + +2003-09-19 13:58 Martin Pool <mbp@samba.org> + + * src/access.c: Allow access masks like 0.0.0.0/0, meaning allow + access from anywhere. Some adjustments required to allow for + behaviour of C bitshift operators. + +2003-09-19 13:07 Martin Pool <mbp@samba.org> + + * Makefile.in: Use an autoconf substitution for EXEEXT, rather + than a Make variable, so that bash's tab completion doesn't get + confused by the targets. + +2003-09-19 12:45 Martin Pool <mbp@samba.org> + + * NEWS: Manpage updates. + +2003-09-19 12:44 Martin Pool <mbp@samba.org> + + * man/distcc.1: Suggest using SCons. + +2003-09-19 12:41 Martin Pool <mbp@samba.org> + + * man/distcc.1: [no log message] + +2003-09-19 12:35 Martin Pool <mbp@samba.org> + + * man/distcc.1: More explanation of Make and compiler errors. + +2003-09-19 12:30 Martin Pool <mbp@samba.org> + + * man/distcc.1: More discussion of where to place localhost in + the list. + +2003-09-19 12:21 Martin Pool <mbp@samba.org> + + * src/tempfile.c: [no log message] + +2003-09-19 12:06 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-09-19 12:03 Martin Pool <mbp@samba.org> + + * patches/: backlog-sample.c, colorgcc, compression.patch, + connect-timeout-02.diff, daemon-address-binding.diff, + distcc-ethereal.diff, distcc-hostlist.diff, distcc-hostopt.patch, + distccd-clean-path.diff, prefork-sample.c, state-in-home.diff, + trylzo.c: Remove obsolete patches. + +2003-09-19 11:47 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-09-18 19:53 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Retain history of 100 states. + +2003-09-18 18:58 Martin Pool <mbp@samba.org> + + * src/renderer.c: Draw "DONE" states as empty. + +2003-09-18 18:32 Martin Pool <mbp@samba.org> + + * src/renderer.c: Render the slot history as a set of state + stripes. This looks great! + +2003-09-18 18:18 Martin Pool <mbp@samba.org> + + * src/renderer.c: Kill dead code. + +2003-09-18 18:01 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Trim the history queue length every time we + add to it. + +2003-09-18 17:58 Martin Pool <mbp@samba.org> + + * src/renderer.c: Cope with the "history" property being a GQueue + of state values, rather than a list of dcc_history structures. + + * Just the first state is drawn through the whole cell at the + moment. + +2003-09-18 17:57 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Fix pointer error in prepending to an existing + history queue. + +2003-09-18 17:55 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Fix up code to insert at end. + +2003-09-18 17:48 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Actually go ahead and store the state history + in a queue in all rows. Create this queue when the row is + first inserted. + + * Change appended rows to go through dcc_insert_row_from_task() + so that we can set up the queue. + +2003-09-18 17:25 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Doc + + * Store a GQueue of state values in the table row, so that the + cell renderer can easily read back all of them and draw them. + + * Split out code to insert a row into dcc_insert_row_from_task(), + because it needs to construct a new GQueue. + + * rename dcc_clear_row -> dcc_set_row_idle() + +2003-09-18 17:05 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Fix number of columns. + +2003-09-18 17:04 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Add textual State column. + +2003-09-18 17:00 Martin Pool <mbp@samba.org> + + * src/mon.c: Don't sort localhost specially. I think this was + buggy. + +2003-09-18 16:28 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: After we finish the task list, clear any rows + remaining in the table. + +2003-09-18 16:21 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: dcc_update_store_from_tasks: Fix bug that + caused it to lock up when it hit a host with no name or file or + in DONE state. + +2003-09-18 16:13 Martin Pool <mbp@samba.org> + + * src/renderer.c: Silently ignore NULL "history" properties. + +2003-09-18 16:12 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Add a "Slot" column, visible in the list. + + * First cut at a method for updating the tree model in place, + rather than deleting it and creating a new one. Takes + advantage of the tree model and the task list being in the same + order to detect changed, added or deleted rows. + + Partially working. + +2003-09-18 15:40 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Typo + +2003-09-18 15:38 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Split code for merging task list into list + store into new function dcc_update_store_From_tasks(), in + preparation for doing an update-in-place rather than clearing + it and reloading. + + * COLUMN_HISTORY is currently set to NULL. It will become a + pointer to a list of state values. + + * task_list is no longer global. It is held in memory only + during the update. + +2003-09-18 15:22 Martin Pool <mbp@samba.org> + + * gnome/distccmon-gnome.glade: Vertical scrollbar auto; + horizontal scrollbar never. + +2003-09-18 15:20 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Doc. + + * Move gtk_list_store_new() to near the column number + declarations to help keep them in step. + + * Drop unused dcc_timeval_to_double(). + +2003-09-18 15:06 Martin Pool <mbp@samba.org> + + * src/renderer.c: Render the state cell solidly filled with the + color for the current state. + +2003-09-18 15:02 Martin Pool <mbp@samba.org> + + * src/renderer.c: Remove dead code. + +2003-09-18 14:59 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Show file name in the table too. + +2003-09-18 14:54 Martin Pool <mbp@samba.org> + + * Makefile.in, gnome/distccmon-gnome.glade, src/mon-gnome.c, + src/renderer.c: Roll back to using a table and cellrenderer. + + I think the immediately previous approach of having the monitor + keep + track of state history and draw an unlabelled striped bar is + probably pretty good. However, I'd like to also rely on the + regular + table widget to give us space to draw it. + + This code builds and gives an empty table. The renderer is + here but + disabled. + +2003-09-18 14:14 Martin Pool <mbp@samba.org> + + * src/compress.c: Fix up types for printing size_ts and for + interfacing with minilzo. Detected when building on ia64 for + Debian. + +2003-09-18 10:48 Martin Pool <mbp@samba.org> + + * autogen.sh: "sed 1q" is more portable than using head to chop + the version out of autoconf. Reported by Alexandre Oliva. + +2003-09-18 10:39 Martin Pool <mbp@samba.org> + + * AUTHORS: [no log message] + +2003-09-18 10:20 Martin Pool <mbp@samba.org> + + * NEWS: Note portability fixes. + +2003-09-18 10:17 Martin Pool <mbp@samba.org> + + * src/ncpus.c, NEWS: In all cases, if we failed to determine the + number of CPUs using sysconf, then assume 1. + +2003-09-18 10:15 Martin Pool <mbp@samba.org> + + * src/ncpus.c: If we failed to determine the number of CPUs using + sysconf, then assume 1. + +2003-09-18 10:14 Martin Pool <mbp@samba.org> + + * src/ncpus.c: bsdi can use the BSD method of finding NCPUs as + well. Reported by Nick Amato. + +2003-09-17 17:24 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Accumulate all task lists in a GSList + (currently never truncated) and draw striped bars showing past + tasks. Currently they are not placed on the right row, so the + stripes are all pushed up towards the top. + +2003-09-17 16:10 Martin Pool <mbp@samba.org> + + * src/: mon-gnome.c, state.c, state.h: Rework monitor yet again: + :-/ + + * State files no longer hold a history of that process's state, + just its current information, and they are removed when the + process exits. + + This means that we cannot get very fine-grained plots of + transitions + between states, but it seemed to be hard to get that + information + displayed smoothly without burning a lot of CPU. In addition, + we + were getting hundreds of leftover state files, which slow down + traversing the directory and are not really necessary. + + I'll try instead putting the burden of remembering and painting + history onto the monitor, since it's the only program that + really + needs that information. + +2003-09-17 15:44 Martin Pool <mbp@samba.org> + + * src/mon.c: Files only 60s old are now considered too old. + +2003-09-17 15:41 Martin Pool <mbp@samba.org> + + * NEWS, autogen.sh: Fix autogen.sh for recent versions of GNU + coreutils. Reported by Lisa Seelye. + +2003-09-17 15:36 Martin Pool <mbp@samba.org> + + * src/: state.c, distcc.c: Move back towards removing state files + when the client process that they belong to exits. + +2003-09-17 12:27 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Skip tasks on no host + + * Draw labels again + + * Refresh every 300ms + +2003-09-17 12:24 Martin Pool <mbp@samba.org> + + * src/renderer.c: GtkCellRenderer is no longer needed + +2003-09-17 12:21 Martin Pool <mbp@samba.org> + + * COPYING.FDL: The GNU FDL need not be included, because the SGML + manual is gone. All the documentation is in the manpages, + which are GPL'd. + +2003-09-17 12:16 Martin Pool <mbp@samba.org> + + * man/distcc.1: Set date. + +2003-09-17 12:14 Martin Pool <mbp@samba.org> + + * man/: distccd.1, distcc.1: Add no-warranty statement. + +2003-09-17 12:11 Martin Pool <mbp@samba.org> + + * Makefile.in: COPYING.FDL is no longer included, because the + manpages are GPL'd. + +2003-09-16 19:27 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Only draw rectangles of >=1 width. + +2003-09-16 19:17 Martin Pool <mbp@samba.org> + + * src/: mon-gnome.c, mon.c, state.c, state.h: Handle times as + microseconds-since-epoch rather than doubles. + + * Rework task drawing routine to correctly handle tasks that have + already completed. + + Currently working but a bit slow. + +2003-09-16 19:06 Martin Pool <mbp@samba.org> + + * patches/lisa--recursive-mkdir-uid-distccdir.patch: Patch from + Lisa. + +2003-09-16 19:00 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Better attempt at drawing current and previous + tasks. + +2003-09-16 18:38 Martin Pool <mbp@samba.org> + + * src/distcc.c: Make a better attempt at always recording DONE + when we are. + +2003-09-16 18:13 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Center text labels in bars. + + * Set bar height to 1.5x text height. + + * Draw host name once per row. + +2003-09-16 18:03 Martin Pool <mbp@samba.org> + + * src/: mon-gnome.c, state.h: Much simpler fix for identifying + multiple tasks in the same slot: now that things are sorted + properly, we can just find neighbouring history reports and + check if they're the same. That should make drawing past tasks + easy... + +2003-09-16 15:57 Martin Pool <mbp@samba.org> + + * src/state.h: Add a pointer to the next on this slot. + +2003-09-16 15:55 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Update every 200ms + + * Allocate rows for each host slot, so that we can draw multiple + tasks onto each line. + +2003-09-16 15:08 Martin Pool <mbp@samba.org> + + * src/mon.c: Sort localhost to the front of the list of tasks. + +2003-09-16 15:04 Martin Pool <mbp@samba.org> + + * src/mon.c: Return list of running tasks sorted by hostname and + slot to make monitor displays more likely to keep tasks in a + stable position. + +2003-09-16 14:36 Martin Pool <mbp@samba.org> + + * src/mon.c: Don't need signal.c + +2003-09-16 14:23 Martin Pool <mbp@samba.org> + + * NEWS: Note that we should now work on BSD/OS. + +2003-09-16 14:20 Martin Pool <mbp@samba.org> + + * NEWS: Call getpgrp() rather than getpgid(), because it's the + POSIX.1 standard function. Suggestion from Nick Amato. + +2003-09-16 14:19 Martin Pool <mbp@samba.org> + + * src/exec.c: Call getpgrp() rather than getpgid(), because it's + the POSIX.1 standard function. + +2003-09-16 13:56 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Don't draw border. + + * Do get proper alignment between host names and task bars. + + * Include slot number in the name. + +2003-09-16 13:28 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Draw host names on left. (Not very well. :-) + +2003-09-16 13:24 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Leave space on the left to draw hostnames, and + draw a splitter bar at that point. + + * Draw a border around the drawingarea. + +2003-09-16 13:10 Martin Pool <mbp@samba.org> + + * Makefile.in: Roll back to using a GtkDrawingArea rather than a + table. renderer.c is no longer needed. + +2003-09-16 13:08 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Fix up rollback. + +2003-09-16 13:07 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Roll back to 1.43.2.37, using a GtkDrawingArea + rather than a table. + +2003-09-16 12:42 Martin Pool <mbp@samba.org> + + * gnome/distccmon-gnome.glade: Merge back to DrawingArea in + 1.1.2.14. No other changes. + +2003-09-15 17:57 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Redraw the chart more frequently than we + reload the task list, so that scrolling seems smoother. + +2003-09-15 17:32 Martin Pool <mbp@samba.org> + + * src/renderer.c: Fix horizontal gaps between stripes. + +2003-09-15 17:30 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Update every 200ms + +2003-09-15 17:23 Martin Pool <mbp@samba.org> + + * src/renderer.c: Draw tasks as multiple strips for each state. + +2003-09-15 17:18 Martin Pool <mbp@samba.org> + + * src/: mon-gnome.c, mon.h: Remove old GCs + + * Make dcc_timeval_to_double global + +2003-09-15 17:14 Martin Pool <mbp@samba.org> + + * src/mon-fake.c: Split out code for fake monitor data; currently + not used. + +2003-09-15 17:02 Martin Pool <mbp@samba.org> + + * src/renderer.c: Partially merge some code from the old + GtkDrawingArea implementation, so that we have better-factored + code for drawing state strips. + +2003-09-15 16:50 Martin Pool <mbp@samba.org> + + * src/renderer.c: Fix unused params. + +2003-09-15 16:36 Martin Pool <mbp@samba.org> + + * src/distcc.h: UNUSED macro should mangle the variable name to + make sure that parameters marked UNUSED are not accidentally + used. + +2003-09-15 16:34 Martin Pool <mbp@samba.org> + + * src/renderer.c: Draw state color and filename from the history + record. + +2003-09-15 16:29 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Go back to a "history" property, being a + pointer to a list of tasks. + +2003-09-15 16:21 Martin Pool <mbp@samba.org> + + * src/: renderer.c, mon-gnome.c: Go back to a "history" property, + being a pointer to a list of tasks. + +2003-09-15 16:04 Martin Pool <mbp@samba.org> + + * src/where.c: Only enter BLOCKED state when we need to sleep + waiting for a slot. + +2003-09-15 16:03 Martin Pool <mbp@samba.org> + + * src/where.c: Sleep only 1s when bored. + +2003-09-15 16:02 Martin Pool <mbp@samba.org> + + * src/state.h: Expose client state. + +2003-09-15 16:01 Martin Pool <mbp@samba.org> + + * src/where.c: Fix code that caused us not to record the right + slot number for local builds. Remove old code left over from + transmission locks. + +2003-09-15 15:53 Martin Pool <mbp@samba.org> + + * src/: lock.c, mon-gnome.c, renderer.c, state.c, state.h, where.c: + * Store slot number as an integer in the state file. + +2003-09-15 15:51 Martin Pool <mbp@samba.org> + + * src/mon-text.c: Show slot number in text display. + +2003-09-15 15:33 Martin Pool <mbp@samba.org> + + * src/: mon-gnome.c, renderer.c, state.h: Change to storing slot + name in the state file so that we can easily work out which + tasks to draw on which line. Use a global variable to publish + that information to the cell renderer. + +2003-09-15 14:54 Martin Pool <mbp@samba.org> + + * src/renderer.c: Make the colored region fill the whole strip. + +2003-09-15 14:46 Martin Pool <mbp@samba.org> + + * src/renderer.c: Draw text for jobs vertically centered within + their rectangle. + +2003-09-15 00:41 Martin Pool <mbp@samba.org> + + * src/renderer.c: Draw text into the task blocks. + +2003-09-14 20:17 Martin Pool <mbp@samba.org> + + * src/renderer.c: Draw a border around the state rectangle, and + try to take the padding into account when drawing. + +2003-09-14 19:48 Martin Pool <mbp@samba.org> + + * Makefile.in: Cosmetic + +2003-09-14 19:24 Martin Pool <mbp@samba.org> + + * src/: mon-gnome.c, renderer.c: Renderer now draws process + states in something like the right color. + +2003-09-14 17:43 Martin Pool <mbp@samba.org> + + * src/renderer.c: Add get/set code for history property. + +2003-09-14 17:40 Martin Pool <mbp@samba.org> + + * src/: renderer.c, renderer.h: The implementation structures for + the cell renderer can be more private. + +2003-09-14 17:38 Martin Pool <mbp@samba.org> + + * src/renderer.c: Add a "task-history" property to the + CellRenderer, currently storing only an integer that will be + the current task's state. We don't handle sets/gets on it yet. + +2003-09-14 17:33 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Allow sorting by host name. + + * Make the tasks column in the list model store an integer, so + that we can give it the current task's state. Bind this cell + to the "task-history" property of the renderer. + +2003-09-14 17:18 Martin Pool <mbp@samba.org> + + * src/: mon-gnome.c, mon-text.c, mon.c, mon.h, state.c, state.h: + Rename dcc_client_history to just dcc_history. + +2003-09-14 17:17 Martin Pool <mbp@samba.org> + + * NEWS: Add release header. + +2003-09-14 17:09 Martin Pool <mbp@samba.org> + + * src/renderer.c: Doc + +2003-09-12 17:23 Martin Pool <mbp@samba.org> + + * src/renderer.h: Add state field to _DccCellRendererChart + +2003-09-12 17:16 Martin Pool <mbp@samba.org> + + * src/renderer.c: Implement dcc_cell_renderer_chart_get_size + +2003-09-12 17:08 Martin Pool <mbp@samba.org> + + * src/renderer.c: Add a simpleminded implementation of + dcc_cell_renderer_chart_render() that can draw the chart cells as + black rectangles. + +2003-09-12 15:58 Martin Pool <mbp@samba.org> + + * src/renderer.c: Implement the get_property and set_property + methods. + +2003-09-12 15:49 Martin Pool <mbp@samba.org> + + * src/renderer.c: Fix call to g_type_register_static, which needs + a reference to the parent type. + +2003-09-12 15:46 Martin Pool <mbp@samba.org> + + * src/: renderer.c, renderer.h: Add GTK Type boilerplate to + create a new GtkCellRenderer. + +2003-09-12 13:08 Martin Pool <mbp@samba.org> + + * Makefile.in, src/mon-gnome.c, src/renderer.c, src/renderer.h: + Put renderer interface into renderer.h + +2003-09-12 13:05 Martin Pool <mbp@samba.org> + + * Makefile.in, src/mon-gnome.c, src/renderer.c: Split out draft + GtkCellRenderer into its own file. + +2003-09-11 19:07 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Start adding a custom renderer. Doesn't do + anything yet. + +2003-09-11 18:57 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: As an experiment, draw pixbufs into the task + cells using a GtkCellRendererPixmap, rather than text. This + seems to be working OK. + +2003-09-11 18:47 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Put hostname and state into the tree model as + they're updated. + +2003-09-11 18:47 Martin Pool <mbp@samba.org> + + * gnome/distccmon-gnome.glade: Turn off rules_hint on table. + +2003-09-11 18:23 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Add a task column. + +2003-09-11 18:17 Martin Pool <mbp@samba.org> + + * gnome/distccmon-gnome.glade, src/mon-gnome.c: Move back towards + using a table, but now with space for our own GtkCellRenderer + to draw a chart for each host slot. At the moment nothing is + in the table, just a column for host names. + +2003-09-11 17:44 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Cut out trace messages. + +2003-09-11 17:31 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Use real task information. + + * Avoid coloring in areas that will be hidden by the border. + + * Make the border the correct width. + +2003-09-11 17:15 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Draw text labels in black. + + * Add a second file to the fake information. + + * Set the start time on fake files. + + * Draw all states for a file, using the old code but adapted to + drawing on the DrawingArea not a canvas. + +2003-09-11 15:19 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Draw tasks from a faked up list, rather than + just drawing arbitrary rectangles. + + * Redraw window using gtk_widget_queue_draw rather than Gdk. + This seems to fix a problem with redraw. Perhaps we were + passing the wrong rectangle. + +2003-09-11 15:02 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Set bar height from font height. + + Now when you change the GNOME system font, all the bars redraw to + the right height. That is so cool. :-) + +2003-09-10 22:51 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Cut out expose trace events. + +2003-09-10 22:48 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Stub out display of tasks so that we do get + something correctly drawn again. + +2003-09-10 18:27 Martin Pool <mbp@samba.org> + + * Makefile.in, configure.ac: We need Pango as well for GNOME. + +2003-09-10 18:27 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Start adding support for fake monitor data for + testing. + +2003-09-10 17:03 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Draw tasks from the task list. + +2003-09-10 16:25 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Draw tasks by creating a new PangoLayout each + time using the GTK+ helper. + +2003-09-10 16:13 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Draw labels onto file rectangles using Pango. + How cool! + +2003-09-10 15:27 Martin Pool <mbp@samba.org> + + * gnome/distccmon-gnome.glade: Put the chart drawing into a + GtkAlignment so that we can get a 6px border around it. It was + looking a bit cramped against the window border. + +2003-09-10 15:17 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Allocate GCs for all states. + + * Draw nice gray outlines around all task rectangles. + +2003-09-10 15:05 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Invalidate/repaint the chart widget every time + we update the list. + +2003-09-10 15:00 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Factor out code for drawing state rectangles + (back) into dcc_draw_state_rect(). + + * Draw a whole array of dummy tasks. + +2003-09-10 14:55 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Allocate a graphics context in the appropriate + color and use it to draw our dummy tasks. + +2003-09-10 14:32 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Stub for on_chart_drawing_expose(). + +2003-09-10 14:19 Martin Pool <mbp@samba.org> + + * gnome/distccmon-gnome.glade, src/mon-gnome.c: Rework again: + + * Start adding a 'key' window showing all the state colors. + + * Go back to a DrawingArea for showing the chart (just + experimental). + + * Delete table view from monitor. + +2003-09-09 18:17 Martin Pool <mbp@samba.org> + + * src/state.h: States must be listed in the order in which + they're run. + +2003-09-09 18:15 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Update every 150ms. + + * Don't update the table. + + * Don't include DONE tasks. + + * Left-align filename. + + * Don't outline tasks. + + * Reorder color list for new state enum. + + * Make sure all states are drawn properly. + + This is leaking memory badly! + +2003-09-09 17:54 Martin Pool <mbp@samba.org> + + * src/compile.c: Record input filename as soon as it is known. + +2003-09-09 17:53 Martin Pool <mbp@samba.org> + + * src/state.c: Don't update state times that are already + recorded. + +2003-09-09 17:52 Martin Pool <mbp@samba.org> + + * src/where.c: Go into BLOCKED state at the start of the locking + phase, so that we don't need to update repeatedly. + +2003-09-09 17:29 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Draw compilation tasks as striated rectangles. + Handling of DONE tasks is not OK yet. + +2003-09-09 17:14 Martin Pool <mbp@samba.org> + + * src/: compile.c, distcc.c: Go into STARTUP state earlier in the + client process. + +2003-09-09 17:09 Martin Pool <mbp@samba.org> + + * src/state.c: Make sure the time is recorded even for state 0. + In fact, always update the time whenever dcc_note_state() is + called. + +2003-09-09 16:57 Martin Pool <mbp@samba.org> + + * src/compile.c: Please do use DCC_STATE_STARTUP so that we know + when we started. + +2003-09-09 16:43 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Factor out code to create canvas items for the + task + +2003-09-09 16:21 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Color task bars according to current state. + +2003-09-08 21:12 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Check for glade definition file in ., ./gnome, + and DATADIR. + +2003-09-08 21:10 Martin Pool <mbp@samba.org> + + * Makefile.in: Fix Make syntax + +2003-09-08 21:09 Martin Pool <mbp@samba.org> + + * Makefile.in: Pass in DATADIR (e.g. /usr/local/share) when + installing. + +2003-09-08 18:11 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: More experiments in drawing. + +2003-09-08 18:10 Martin Pool <mbp@samba.org> + + * gnome/distccmon-gnome.glade: Try a Canvas in a GtkAlignment + +2003-09-08 17:47 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: More progress on canvas display + + * Skip done tasks + + * Show a nice vertical stack of running tasks, with the file name + in each, and drawn with reasonable colors. + +2003-09-08 17:33 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: More progress on canvas display + + * Put all bars into an overall group, so that they can all be + removed every time we redraw. + + * Create all process bars in one group each time. + +2003-09-08 16:39 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: More fixups for new state mechanism + + * Convert state to a string before putting it into the table. + + * Skip done tasks. + +2003-09-08 16:26 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Fix up (mostly renames) for new monitor + interface. + +2003-09-08 16:21 Martin Pool <mbp@samba.org> + + * src/mon-text.c: Skip display of Done tasks. + +2003-09-08 16:20 Martin Pool <mbp@samba.org> + + * src/state.c: Add missing state names. + +2003-09-08 16:19 Martin Pool <mbp@samba.org> + + * src/state.c: Make sure to actually record our state! + +2003-09-08 16:12 Martin Pool <mbp@samba.org> + + * src/: state.c, state.h, mon-text.c: Put state names into a new + function dcc_get_state_name, rather than into constants. + +2003-09-08 16:08 Martin Pool <mbp@samba.org> + + * src/mon.c: Processes that have exited can still be returned. + +2003-09-08 16:01 Martin Pool <mbp@samba.org> + + * src/mon.c: Now that we're storing client history, it's OK to + return information about processes that have already exited. + We just need to make sure that their state gets set to + DCC_STATE_DONE. + +2003-09-08 15:59 Martin Pool <mbp@samba.org> + + * src/state.c: Put the client pid into the state file. + +2003-09-08 15:57 Martin Pool <mbp@samba.org> + + * src/: mon.c, state.c, state.h: Store a magic number in the + binary state file as a little protection. + + * Align magic and pid fields to unsigned longs. + +2003-09-08 15:51 Martin Pool <mbp@samba.org> + + * src/state.c: Store history of state transitions in the state + file. + +2003-09-08 15:48 Martin Pool <mbp@samba.org> + + * NEWS, src/clirpc.c, src/compile.c, src/distcc.c, src/mon-text.c, + src/mon.c, src/mon.h, src/remote.c, src/state.c, src/state.h, + src/where.c: Many changes to the representation of the client + state to make it easier to draw a history. + + * State is now stored as a natively encoded struct in a disk + file, rather than using our network protocol. This is slightly + faster, makes it easier to store multiple fields, and avoids + tangling up the state file handling (which ought to ignore + errors) with network IO. + + * States can now be written and read with one atomic IO, and we + don't use temporary files. + + * States are represented by integers not strings. + + * There is space in the state file for a history of times that it + entered particular states. + +2003-09-08 15:29 Martin Pool <mbp@samba.org> + + * src/: util.h, util.c: Add strlcpy() if missing. + +2003-09-08 15:29 Martin Pool <mbp@samba.org> + + * configure.ac: Add check for strlcpy(). + +2003-09-08 13:17 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Draw rectangles onto the canvas for each job + that's currently running. + +2003-09-08 13:11 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Set canvas scroll region at startup. + +2003-09-08 13:04 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Draw little rectangles into the chart from the + timer callback to prove that we can. + +2003-09-08 12:51 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Prepare to update both table and chart from + one timer callback. Refactor into a part that gets the process + list and a new function that updates the table model. + + * Add some prototypes for functions called by glade to silence + compiler warnings. + +2003-09-08 12:45 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Rename setup_proc_view -> setup_table_view. + + * Doc. + +2003-09-08 12:44 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Document design of chart view. + +2003-09-07 22:54 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Draw a rectangle onto the chart to see it + working. + +2003-09-07 19:09 Martin Pool <mbp@samba.org> + + * gnome/distccmon-gnome.glade: Swich from a DrawingArea to a + Canvas for the chart view. + +2003-09-07 19:04 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Swich from a DrawingArea to a Canvas for the + chart view. + +2003-09-07 19:03 Martin Pool <mbp@samba.org> + + * Makefile.in: Move mon-gnome.c back to src/ + + * Pull out common list of packages to be passed to pkg-config. + + * Compile mon-gnome.c separate from linking. + +2003-09-07 18:53 Martin Pool <mbp@samba.org> + + * gnome/mon-gnome.c, src/mon-gnome.c: Move mon-gnome.c back to + src/ + +2003-09-05 17:01 Martin Pool <mbp@samba.org> + + * gnome/mon-gnome.c: Abort if we can't find the glade XML file. + +2003-09-04 15:20 Martin Pool <mbp@samba.org> + + * man/distcc.1: Clear up explanation of --allow option. + + * Note that "gcc hello.c" is not split. + +2003-09-03 12:41 Martin Pool <mbp@samba.org> + + * src/where.c, NEWS: Sleep only one second when blocked, to try + to reduce idle time when recovering from an overloaded period. + +2003-09-01 23:20 Martin Pool <mbp@samba.org> + + * gnome/: distccmon-gnome.glade, mon-gnome.c: Draw big black + ellipse in the chart area. + +2003-09-01 23:15 Martin Pool <mbp@samba.org> + + * gnome/: distccmon-gnome.glade, mon-gnome.c: Try to make View + menu items toggle each other. Not working yet. + +2003-09-01 23:09 Martin Pool <mbp@samba.org> + + * gnome/distccmon-gnome.glade: Put tabs on the notebook just for + the time being. + +2003-09-01 23:02 Martin Pool <mbp@samba.org> + + * gnome/: distccmon-gnome.glade, mon-gnome.c: Flip between view + notebook pages when view menu items are chosen. + +2003-09-01 22:47 Martin Pool <mbp@samba.org> + + * gnome/: distccmon-gnome.glade, mon-gnome.c: Add a cute monkey + icon. + + * Add an About box and hook it up appropriately. + +2003-09-01 22:23 Martin Pool <mbp@samba.org> + + * gnome/: distccmon-gnome.glade, mon-gnome.c: Hook up process + table to Glade. The existing processs monitoring functions are + now working again. + +2003-09-01 22:09 Martin Pool <mbp@samba.org> + + * gnome/: distccmon-gnome.glade, mon-gnome.c: Get load bar hooked + up for Gnome monitor. + +2003-09-01 22:04 Martin Pool <mbp@samba.org> + + * gnome/: distccmon-gnome.glade, mon-gnome.c: More merges of + monitor code into Glade interface. + + * Set size of Glade window at startup and tweak scrollbars. + +2003-09-01 21:39 Martin Pool <mbp@samba.org> + + * gnome/mon-gnome.c: Merge in all the GNOME monitor code from + HEAD. + +2003-09-01 21:23 Martin Pool <mbp@samba.org> + + * configure.ac: Check for other necessary libraries when + --enable-gnome is given. + + * Bump version. + +2003-09-01 13:33 Martin Pool <mbp@samba.org> + + * TODO: Idea of using gkrellm + +2003-09-01 11:30 Martin Pool <mbp@samba.org> + + * man/distccd.1: Add a little more explanation of --allow. + +2003-08-28 15:05 Martin Pool <mbp@samba.org> + + * TODO: Update for done tasks. + +2003-08-28 15:02 Martin Pool <mbp@samba.org> + + * man/distccd.1: Note that ccache can't be called from distccd. + +2003-08-28 14:33 Martin Pool <mbp@samba.org> + + * NEWS, man/distcc.1: Note about problems with no_subtree_check. + +2003-08-28 14:31 Martin Pool <mbp@samba.org> + + * TODO: DEPENDENCIES_OUTPUT is not directly a problem for distcc. + +2003-08-28 12:48 Martin Pool <mbp@samba.org> + + * cases/mmaptest.c: Bug has been isolated; no longer need this + test case. + +2003-08-28 12:45 Martin Pool <mbp@samba.org> + + * cases/mmaptest.c: More tests for NFS bug. + +2003-08-26 15:56 Martin Pool <mbp@samba.org> + + * cases/mmaptest.c: Do the mmapped IO in a child process, to be + more similar to ccache/distcc. + +2003-08-26 12:01 Martin Pool <mbp@samba.org> + + * cases/: .cvsignore, mmaptest.c: Add test for mmap-on-NFS + problems + +2003-08-25 16:06 Martin Pool <mbp@samba.org> + + * src/pump.c: Doc + +2003-08-25 12:48 Martin Pool <mbp@samba.org> + + * src/: arg.c, compile.c, compress.c, serve.c: Patch from Wayne + Davison to fix Solaris warnings + +2003-08-25 11:55 Martin Pool <mbp@samba.org> + + * src/: compress.c, io.c, io.h, pump.c: Add DISTCC_MMAP option, + defaults to on. May be useful in working around bugs with mmap + on NFS. + +2003-08-25 11:13 Martin Pool <mbp@samba.org> + + * man/distcc.1, man/distccd.1, NEWS: Document DISTCC_MMAP. + +2003-08-15 14:17 Martin Pool <mbp@samba.org> + + * Makefile.in, gnome/distccmon-gnome.glade, + gnome/distccmon-gnome.gladep, gnome/mon-gnome.c: Initial stub + version of the monitor. + +2003-08-15 14:16 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Move gnome monitor into its own directory. + +2003-08-14 18:12 Martin Pool <mbp@samba.org> + + * TODO, gnome/distccmon-gnome.glade, gnome/distccmon-gnome.gladep, + gnome/mon-gnome.c: Start doing a better GNOME monitor. + +2003-08-13 13:05 Martin Pool <mbp@samba.org> + + * TODO: Note problem with DEPENDENCIES_OUTPUT. + +2003-08-13 12:57 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version. + +2003-08-12 13:34 Martin Pool <mbp@samba.org> + + * man/distcc.1: Update manpage date. + +2003-08-12 13:27 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Set DISTCC_DIR when running tests to give + better isolation between tests and anything else that might be + happening on the machine. + +2003-08-12 13:18 Martin Pool <mbp@samba.org> + + * Makefile.in: make distcheck ought to run maintainer-check and + also check that the directory can be cleaned. + +2003-08-12 13:10 Martin Pool <mbp@samba.org> + + * NEWS: Note "make clean" problem is fixed. + +2003-08-12 13:09 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version to 2.10.1 + +2003-08-12 11:42 Martin Pool <mbp@samba.org> + + * Makefile.in: Fix "make clean" problem in lzo. Reported by Lisa + Marie Seelye. + +2003-08-11 16:09 Martin Pool <mbp@samba.org> + + * cases/hello.c: Make hello actually say hello + +2003-08-11 16:07 Martin Pool <mbp@samba.org> + + * distcc-check: Allow the compiler to be changed. + +2003-08-11 16:05 Martin Pool <mbp@samba.org> + + * NEWS, configure.ac: Prepare for release. + +2003-08-11 15:51 Martin Pool <mbp@samba.org> + + * TODO: Suggestions from Lisa on the monitor. + +2003-08-11 15:46 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Fix from wayned for crash when DISTCC_DIR is + set. + +2003-08-11 15:43 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Doc. + +2003-08-11 15:40 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: [no log message] + +2003-08-11 15:33 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-08-11 15:32 Martin Pool <mbp@samba.org> + + * man/distcc.1: Corrections from Frerich Raabe. + +2003-08-11 15:18 Martin Pool <mbp@samba.org> + + * src/exec.c, NEWS: For simple compile failures, don't say "with + exit code 1". + +2003-08-11 15:15 Martin Pool <mbp@samba.org> + + * src/exec.c: Doc. + +2003-08-07 15:42 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-08-05 12:09 Martin Pool <mbp@samba.org> + + * src/exitcode.h: Add include guard. + +2003-08-05 11:56 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove roadmap page, because it's now largely + complete. + +2003-08-05 11:53 Martin Pool <mbp@samba.org> + + * Makefile.in: Make sure examples get installed into doc/example. + +2003-08-05 11:48 Martin Pool <mbp@samba.org> + + * doc/example-init, doc/example/init, doc/example/init-suse, + doc/example/logrotate, doc/example/xinetd, Makefile.in, + doc/example.xinetd: Move all example files into doc/example. + +2003-07-25 17:34 Martin Pool <mbp@samba.org> + + * doc/results.txt: [no log message] + +2003-07-25 17:25 Martin Pool <mbp@samba.org> + + * bench/Summary.py: Show summary table properly. + +2003-07-25 15:50 Martin Pool <mbp@samba.org> + + * src/state.c, NEWS: Roll back to writing state into temporary + files. + +2003-07-25 15:36 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc + +2003-07-25 15:35 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: If the daemon fails to bind to the desired + port, keep trying other ones. + +2003-07-25 15:21 Martin Pool <mbp@samba.org> + + * NEWS: Store state files by writing and rewriting them directly, + rather than renaming every time. That was starting to take a + fair fraction of our syscalls. + +2003-07-25 15:15 Martin Pool <mbp@samba.org> + + * src/state.c: Fix state file names. + +2003-07-25 15:14 Martin Pool <mbp@samba.org> + + * src/state.c: Store state files by writing and rewriting them + directly, rather than renaming every time. That was starting + to take a fair fraction of our syscalls. + +2003-07-25 14:56 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-07-25 14:53 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Make temp filenames more random. + +2003-07-25 14:51 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Check return code when closing the temporary + file after creating it. + +2003-07-25 14:47 Martin Pool <mbp@samba.org> + + * src/tempfile.c: O_NOFOLLOW is not needed with O_EXCL and + O_CREAT, because they never follow symlinks. + + * Doc. + +2003-07-25 14:39 Martin Pool <mbp@samba.org> + + * src/tempfile.c: dcc_make_tmpnam: Fix the case where the chosen + name already exists. + +2003-07-25 14:34 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Create temporary files in a loop, with O_EXCL + and O_NOFOLLOW to try to guard against collision with existing + files or links. + +2003-07-25 14:15 Martin Pool <mbp@samba.org> + + * src/: cpp.c, serve.c: Better template names for temporary + files. + +2003-07-25 14:08 Martin Pool <mbp@samba.org> + + * configure.ac: Check for gettimeofday + +2003-07-25 13:52 Martin Pool <mbp@samba.org> + + * src/: tempfile.c, tempfile.h: dcc_get_top_dir can be static, + and does not need to return a newly-allocated string. + +2003-07-25 13:32 Martin Pool <mbp@samba.org> + + * src/: lock.c, mon.c, state.c, tempfile.c, tempfile.h: Make sure + lock dir and state dir are only created the first time we use + them. + +2003-07-25 13:22 Martin Pool <mbp@samba.org> + + * NEWS, src/lock.c, src/mon.c, src/state.c, src/tempfile.c, + src/tempfile.h: Temporary directory is now gone. Working files + are created directly under $TMPDIR, as they are for gcc. Lock + files and state files are stored under DISTCC_DIR. + +2003-07-25 13:18 Martin Pool <mbp@samba.org> + + * src/distcc.c: Temporary directory is no longer used. + +2003-07-25 12:35 Martin Pool <mbp@samba.org> + + * Makefile.in: cleanup.c is also needed by monitors. + +2003-07-25 11:53 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Daemon runs from root directory, not the + temporary directory. + + * Doc. + +2003-07-25 11:51 Martin Pool <mbp@samba.org> + + * src/daemon.c, src/tempfile.h, NEWS: Daemon runs from root + directory, not the temporary directory. + +2003-07-24 18:58 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Doc + +2003-07-24 18:46 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Remove dead fifo code. + +2003-07-24 18:45 Martin Pool <mbp@samba.org> + + * Makefile.in, src/cleanup.c, src/tempfile.c, src/tempfile.h: + Factor out tempfile cleanup into a new file cleanup.c + +2003-07-24 18:43 Martin Pool <mbp@samba.org> + + * patches/ccache-uncached-err.diff: Patch to ccache to avoid + caching network errors. + +2003-07-24 18:20 Martin Pool <mbp@samba.org> + + * NEWS: Note about tmpdir fixes. + +2003-07-24 18:17 Martin Pool <mbp@samba.org> + + * src/tempfile.c: dcc_get_tempdir: Make sure that if we fail the + first time we don't pass back a bogus directory on future + attempts. + +2003-07-24 18:12 Martin Pool <mbp@samba.org> + + * src/distcc.c: Check up front in the client that the working + directory can be created, otherwise we get a whole pile of + errors when it fails. + +2003-07-24 17:58 Martin Pool <mbp@samba.org> + + * src/: cpp.c, lock.c, lock.h, serve.c, state.c, tempfile.c, + tempfile.h, timefile.c: Change temporary filename handling to + consistently use error returns and check them. + +2003-07-23 17:19 Martin Pool <mbp@samba.org> + + * src/: state.c, tempfile.c, tempfile.h: dcc_make_dir: Rename to + dcc_safe_mkdir. Check the ownership of the directory after it + is created to help guard against an attacker creating the + directory. + +2003-07-23 17:18 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-07-23 16:56 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Doc. + +2003-07-23 16:11 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Don't check that TMPDIR starts with '/'. + + * dcc_setup_tempdir can be static. + +2003-07-23 16:11 Martin Pool <mbp@samba.org> + + * src/tempfile.h: dcc_setup_tempdir can be static. + +2003-07-23 16:09 Martin Pool <mbp@samba.org> + + * NEWS: Don't check that TMPDIR starts with '/'. + +2003-07-22 18:02 Martin Pool <mbp@samba.org> + + * src/pump.c: Doc. + +2003-07-22 17:36 Martin Pool <mbp@samba.org> + + * src/lock.c: Be strict about enums. + +2003-07-22 17:35 Martin Pool <mbp@samba.org> + + * src/: clirpc.c, rpc.c, rpc.h: waitstatus is not unsigned. + +2003-07-22 17:34 Martin Pool <mbp@samba.org> + + * src/filename.c: dcc_output_from_source: Remove dead variable. + +2003-07-22 17:33 Martin Pool <mbp@samba.org> + + * configure.ac: Remove doubled CFLAG. + +2003-07-22 17:30 Martin Pool <mbp@samba.org> + + * src/exec.c: waitstatus is not unsigned. + +2003-07-22 17:25 Martin Pool <mbp@samba.org> + + * src/: exec.h, distcc.h: waitstatus is not unsigned. + +2003-07-22 17:24 Martin Pool <mbp@samba.org> + + * src/compile.c: Signedness warning correction; reported by + Dimitri Papadopoulos. + +2003-07-22 17:21 Martin Pool <mbp@samba.org> + + * src/remote.c: timeval.h is not needed. + +2003-07-22 17:19 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Snip out dcc_mkfifo + +2003-07-22 16:58 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-07-22 16:57 Martin Pool <mbp@samba.org> + + * man/distcc.1: Document UNCACHED_ERR_FD. + +2003-07-22 16:55 Martin Pool <mbp@samba.org> + + * man/distcc.1: Note that ccache doesn't handle compilation from + .i files. + +2003-07-22 16:47 Martin Pool <mbp@samba.org> + + * src/daemon.c: Factor out code for setting the daemon's path. + + * Show path for daemon at startup. + +2003-07-22 16:43 Martin Pool <mbp@samba.org> + + * src/daemon.c: daemon/main: The daemon no longer trims its path, + because it will emit warnings if a masqueraded directory is + detected. + +2003-07-22 16:42 Martin Pool <mbp@samba.org> + + * src/util.c: dcc_trim_path: This is no longer called by the + server, only by the client. So remove support for detecting + ccache, and require the compiler name to always be specified. + +2003-07-22 16:38 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-07-22 16:35 Martin Pool <mbp@samba.org> + + * src/distcc.c: Remove duplicated dcc_find_basename(). + +2003-07-22 14:16 Martin Pool <mbp@samba.org> + + * distcc-check: Doc + +2003-07-22 14:13 Martin Pool <mbp@samba.org> + + * NEWS: Default niceness is 5. + +2003-07-22 14:11 Martin Pool <mbp@samba.org> + + * src/: daemon.c, dopt.c, dopt.h, util.c: Increment niceness by 5 + by default. + +2003-07-22 14:08 Martin Pool <mbp@samba.org> + + * man/distccd.1: Clarify that niceness is an increment not an + absolute value. + + * Default niceness is 5. + +2003-07-22 13:58 Martin Pool <mbp@samba.org> + + * NEWS: Nasty note about SCO. + +2003-07-22 13:53 Martin Pool <mbp@samba.org> + + * doc/results.txt: SSH results. + +2003-07-22 12:43 Martin Pool <mbp@samba.org> + + * README.packaging: More suggestions about cross compiling from + Dag Wieers. + +2003-07-21 17:37 Martin Pool <mbp@samba.org> + + * src/serve.c: dcc_run_job: Before executing the compiler, check + the server's path and emit a warning if it looks like a symlink + to distcc. + +2003-07-21 17:36 Martin Pool <mbp@samba.org> + + * NEWS: Note about finding the right compiler on the volunteer. + +2003-07-21 17:14 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc. + +2003-07-21 16:35 Martin Pool <mbp@samba.org> + + * src/: distcc.c: Doc. + +2003-07-21 16:31 Martin Pool <mbp@samba.org> + + * src/distcc.c: distcc/main: Rename variable. + +2003-07-21 16:25 Martin Pool <mbp@samba.org> + + * src/distcc.c: dcc_get_my_basename: Rename to dcc_find_basename, + which is a better name, and just make it work on a string, + rather than looking in an argv. This function is really no + longer distcc-specific. + +2003-07-21 16:06 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version. + +2003-07-21 15:50 Martin Pool <mbp@samba.org> + + * man/distcc.1: Remove PP + +2003-07-21 15:24 Martin Pool <mbp@samba.org> + + * configure.ac, NEWS: 2.9 release. + +2003-07-21 15:14 Martin Pool <mbp@samba.org> + + * configure.ac: Make sure GNOME_BIN actually gets set. + +2003-07-21 15:10 Martin Pool <mbp@samba.org> + + * Makefile.in: lzoconf.h needs to be distributed. + +2003-07-21 15:07 Martin Pool <mbp@samba.org> + + * doc/results.txt: [no log message] + +2003-07-21 14:59 Martin Pool <mbp@samba.org> + + * src/util.c, NEWS: When trimming the path to avoid recursive + invocations, stop as soon as we find one non-symlink compiler. + This should help avoid the path getting trimmed down far too + much on the server. Patch from Wayne Davison. + +2003-07-21 14:49 Martin Pool <mbp@samba.org> + + * man/distccd.1: Suggest inetd limit be raised to 6000 + +2003-07-21 14:42 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-07-21 14:40 Martin Pool <mbp@samba.org> + + * src/compress.c: dcc_compress_lzo1x_alloc can be static. + +2003-07-21 14:20 Martin Pool <mbp@samba.org> + + * src/distcc.h: dcc_compress_lzo1x_alloc can be static. + +2003-07-21 12:45 Martin Pool <mbp@samba.org> + + * NEWS: Note about documentation. + +2003-07-21 12:35 Martin Pool <mbp@samba.org> + + * src/compress.c: Trace message for use of mmap. + +2003-07-21 12:31 Martin Pool <mbp@samba.org> + + * src/pump.c: Trace message for receipt using mmap. + +2003-07-21 12:23 Martin Pool <mbp@samba.org> + + * src/daemon.c: Tweak daemon startup message. + +2003-07-21 12:21 Martin Pool <mbp@samba.org> + + * src/daemon.c: Show gnu-host in daemon startup message. + +2003-07-21 12:13 Martin Pool <mbp@samba.org> + + * src/: daemon.c, daemon.h, dparent.c: Factor out code to show + daemon startup message, and include the daemon mode in it. + +2003-07-21 12:08 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-07-21 12:02 Martin Pool <mbp@samba.org> + + * src/hosts.c: Update host grammar from manpage. + +2003-07-21 12:01 Martin Pool <mbp@samba.org> + + * man/distcc.1: Grammar fixes: + + * Be consistent about quoting. * Add LOCAL_HOST. * Make USER + option in SSH production. + +2003-07-21 11:59 Martin Pool <mbp@samba.org> + + * man/distcc.1: Add ccache URL + + * Cleanup + +2003-07-21 11:56 Martin Pool <mbp@samba.org> + + * man/distccd.1: Some cleanups from Tim and myself. + +2003-07-21 11:42 Martin Pool <mbp@samba.org> + + * man/distcc.1: Many suggestions from Tim: + + * Add quickstart section. + + * Consistent capitalization of "make" + + * Grammar/readability fixes. + + * Move up section about ccache with distcc + + * Clear up host grammar section. + + * What to do about broken makefiles. + +2003-07-21 11:21 Martin Pool <mbp@samba.org> + + * NEWS: Note mmap support. + + * Delete trailing whitespace. + +2003-07-21 11:17 Martin Pool <mbp@samba.org> + + * man/distcc.1: Add information about compression. + +2003-07-18 16:50 Martin Pool <mbp@samba.org> + + * src/pump.c: dcc_r_bulk_plain: For uncompressed data coming in, + we know the exact right length and so we only need to truncate + the file once. + +2003-07-18 16:48 Martin Pool <mbp@samba.org> + + * src/pump.c: Receive bulk data by writing into an mmaped file, + or otherwise reading in and writing out one big buffer. + +2003-07-18 16:41 Martin Pool <mbp@samba.org> + + * doc/results.txt: [no log message] + +2003-07-18 16:39 Martin Pool <mbp@samba.org> + + * src/pump.c: Start implementing dcc_r_bulk_plain + +2003-07-18 16:32 Martin Pool <mbp@samba.org> + + * src/: bulk.c, clirpc.c, io.c, io.h, pump.c: Rename dcc_pump_in + for consistency. + + * Doc. + +2003-07-18 16:21 Martin Pool <mbp@samba.org> + + * src/: bulk.c, compress.c, compress.h, distcc.h, pump.c: Make + compression function naming consistent. + + * Remove compress.h + +2003-07-18 16:00 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Fix silly error in ParseHostSpec_Case. + +2003-07-18 15:59 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Fix VersionOption_Case for new version + string that mentions two protocols. + +2003-07-18 15:58 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add partial test for parsing host + specifications with the LZO option. + +2003-07-18 15:57 Martin Pool <mbp@samba.org> + + * src/hosts.c: ',' should also terminate TCP hostnames. + +2003-07-18 15:48 Martin Pool <mbp@samba.org> + + * NEWS: More about compression. + +2003-07-18 15:45 Martin Pool <mbp@samba.org> + + * NEWS: Add support for ",lzo" option at the end of host + specifications. + +2003-07-18 15:43 Martin Pool <mbp@samba.org> + + * src/hosts.c: ',' should also terminate SSH hostnames. + +2003-07-18 15:42 Martin Pool <mbp@samba.org> + + * src/hosts.c: Add support for ",lzo" option at the end of host + specifications. + +2003-07-18 15:02 Martin Pool <mbp@samba.org> + + * doc/results.txt: Results from 3.4 snapshot. + +2003-07-18 13:16 Martin Pool <mbp@samba.org> + + * src/: rpc.h, rpc.c: Remove obsolete dcc_compr_for_proto() + +2003-07-18 13:15 Martin Pool <mbp@samba.org> + + * src/: clirpc.c, distcc.h, hosts.c, hosts.h, lock.c, remote.c: + Store both protocol and compression method in the host + definition. Simpler than converting between them all the way + through. + +2003-07-18 12:21 Martin Pool <mbp@samba.org> + + * src/distcc.h: Reorder enums to top. + +2003-07-18 12:18 Martin Pool <mbp@samba.org> + + * src/distcc.h: Make dcc_compress values not be 0-based. + +2003-07-18 12:01 Martin Pool <mbp@samba.org> + + * Makefile.in, src/clirpc.c, src/clirpc.h, src/distcc.h, + src/remote.c: Remove clirpc.h. + +2003-07-18 11:35 Martin Pool <mbp@samba.org> + + * src/: clirpc.c, distcc.h, help.c, hosts.h, lock.c, mon-gnome.c, + mon-text.c, mon.c, remote.c, rpc.c, rpc.h, serve.c, srvrpc.c, + state.c: Start adding support for talking either protocol 1 or + 2. Store protocol in host specification and propagate it + through relevant functions. + +2003-07-17 22:09 Martin Pool <mbp@samba.org> + + * src/hosts.c: Document upcoming compression option for host + specifications. + +2003-07-17 22:01 Martin Pool <mbp@samba.org> + + * doc/protocol-2.txt: [no log message] + +2003-07-17 22:00 Martin Pool <mbp@samba.org> + + * Makefile.in: Include description of protocol version 2. + +2003-07-17 21:59 Martin Pool <mbp@samba.org> + + * doc/protocol-2.txt: Description of protocol version 2. + +2003-07-17 17:18 Martin Pool <mbp@samba.org> + + * src/bulk.c: Doc. + +2003-07-17 17:16 Martin Pool <mbp@samba.org> + + * src/: compile.c, compile.h, remote.c: Pass source filename to + dcc_compile_remote and set the state file from there so that we + can get the filename in the first status message. + +2003-07-17 17:11 Martin Pool <mbp@samba.org> + + * src/compress.c: Doc. + + * Only use mmap for buffers larger than 64k. + +2003-07-17 17:04 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-07-17 17:03 Martin Pool <mbp@samba.org> + + * man/distcc.1: Add hostspec grammar + + * Some formatting changes. + +2003-07-17 17:00 Martin Pool <mbp@samba.org> + + * src/hosts.c: Fix grammar nit. + +2003-07-17 16:39 Martin Pool <mbp@samba.org> + + * man/distccd.1, src/dopt.c: Document --wizard. + +2003-07-17 16:35 Martin Pool <mbp@samba.org> + + * NEWS, man/distccd.1: Change to starting 2+NCPUS jobs by + default. + +2003-07-17 16:31 Martin Pool <mbp@samba.org> + + * src/dparent.c: Change to starting 2+NCPUS jobs by default. + +2003-07-17 16:24 Martin Pool <mbp@samba.org> + + * Makefile.in: Clean lzo/ directory. Patch from Wayne Davison. + +2003-07-17 15:52 Martin Pool <mbp@samba.org> + + * distcc-check: Doc + +2003-07-17 10:37 Martin Pool <mbp@samba.org> + + * man/distccd.1: There was some confusion about the meaning of + "proportional to" in the description of -j. Now make it + clearer that the number of jobs is higher than the number of + CPUs. + +2003-07-16 12:33 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove the "tested" page. + +2003-07-15 19:00 Martin Pool <mbp@samba.org> + + * src/mapfile.c: Remove mapfile; mmap is now called directly. + +2003-07-15 18:51 Martin Pool <mbp@samba.org> + + * src/compress.c: Quieten warning. + +2003-07-15 18:50 Martin Pool <mbp@samba.org> + + * src/compress.c: Doc + + * dcc_receive_lzo1x: Pass the right value to munmap(). + +2003-07-15 18:47 Martin Pool <mbp@samba.org> + + * src/bulk.c: dcc_r_file: We need to open the file read/write, + not just wronly, to be able to mmap it. + +2003-07-15 18:45 Martin Pool <mbp@samba.org> + + * src/compress.c: dcc_compress_lzo1x_file: Make sure to return an + error if the munmap failed, because we might not have managed + to write everything out. + + * dcc_receive_lzo1x: First cut at decompressing into a writable + mmap'd buffer. + +2003-07-15 18:23 Martin Pool <mbp@samba.org> + + * src/compile.c: Disable "startup" state. + +2003-07-15 18:21 Martin Pool <mbp@samba.org> + + * src/compress.c: dcc_compress_lzo1x_file: Try to use mmap() to + read the input file if mmap() is available. If not, fall back + to using malloc and read(). + +2003-07-15 18:20 Martin Pool <mbp@samba.org> + + * doc/results.txt: Results from compilation on 10Mbps network. + +2003-07-15 18:18 Martin Pool <mbp@samba.org> + + * Makefile.in: mapfile is no longer needed -- we just mmap as + necessary. + +2003-07-15 18:10 Martin Pool <mbp@samba.org> + + * configure.ac, NEWS: Don't check for GTK+ unless --enable-gnome + is requested, because it's a needless portability risk on + platforms that don't have it. + +2003-07-15 18:04 Martin Pool <mbp@samba.org> + + * configure.ac: Check for mmap() + +2003-07-15 18:02 Martin Pool <mbp@samba.org> + + * src/: bulk.c, compress.c, compress.h: Factor out code to + compress from a file. + +2003-07-15 17:57 Martin Pool <mbp@samba.org> + + * src/bulk.c: dcc_calc_rate: Guard against division by zero + (which never seems to happen). + + * Doc. + +2003-07-15 17:51 Martin Pool <mbp@samba.org> + + * NEWS: Note compression. + +2003-07-15 17:40 Martin Pool <mbp@samba.org> + + * src/: distcc.h, dopt.h, srvnet.c: Clean up dopt headers. + +2003-07-15 17:38 Martin Pool <mbp@samba.org> + + * doc/results.txt: Notes on testing compression. + +2003-07-15 17:23 Martin Pool <mbp@samba.org> + + * src/distcc.h: Change protocol version to 2 so that + incompatibilities with old servers are trapped. + + Eventually we need to switch intelligently. + +2003-07-15 17:12 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Make columns in the GNOME monitor resizable, + as well as auto-resizing. + +2003-07-15 11:32 Martin Pool <mbp@samba.org> + + * src/bulk.c: dcc_r_file: Doc. Fix uninitialized variable for + 0-length files. + +2003-07-14 22:02 Martin Pool <mbp@samba.org> + + * src/compress.c: Show decompression ratio as small:large. + +2003-07-14 21:51 Martin Pool <mbp@samba.org> + + * src/pump.c: dcc_pump_in: Handle 0-byte optimization too. + +2003-07-14 21:45 Martin Pool <mbp@samba.org> + + * src/bulk.c: Add optimization of not doing any compression for + 0-byte files. + +2003-07-14 21:39 Martin Pool <mbp@samba.org> + + * src/pump.c: dcc_pump_out: No longer needed because dcc_x_file + now switches based on compression. + + * Fix parameter ordering bug for dcc_pump_in + +2003-07-14 21:38 Martin Pool <mbp@samba.org> + + * src/io.h: compress.h: New header. + +2003-07-14 21:38 Martin Pool <mbp@samba.org> + + * src/dopt.c: Fix --wizard. + +2003-07-14 21:38 Martin Pool <mbp@samba.org> + + * src/: compress.c, compress.h: dcc_compress_lzo1x_alloc: New + function to just compress in memory without doing IO. + + * compress.h: New header. + +2003-07-14 21:36 Martin Pool <mbp@samba.org> + + * src/bulk.c: New dcc_x_file_lzo1x: Read in the file, compress + it, and then write out that buffer. This has to be done in a + single level because the token has to include the compressed + length. + + * dcc_x_file: Handle compression. + +2003-07-14 21:24 Martin Pool <mbp@samba.org> + + * src/dopt.c: Rename to --wizard. + +2003-07-14 21:22 Martin Pool <mbp@samba.org> + + * src/dopt.c: Add -X, --maintainer option that adds all settings + for running under gdb. + +2003-07-14 18:10 Martin Pool <mbp@samba.org> + + * src/: bulk.c, bulk.h, clirpc.c, serve.c: dcc_x_file doesn't + need to return the file size anymore. + +2003-07-14 18:07 Martin Pool <mbp@samba.org> + + * src/: bulk.c, bulk.h, remote.c, serve.c: Set default + compression to LZO1X -- which is not working now, and breaks + compatibility + + * Start factoring out code for receiving a token and file into + dcc_r_token_file + +2003-07-14 17:55 Martin Pool <mbp@samba.org> + + * src/: bulk.c, bulk.h, clirpc.c, clirpc.h, remote.c, serve.c: + Propagate compression setting through all routines. + +2003-07-14 17:49 Martin Pool <mbp@samba.org> + + * src/: bulk.c, bulk.h, clirpc.c, compress.c, distcc.h, io.h, + pump.c: Start moving bulk data receipt through dcc_pump_in, + which does decompression if needed. Remove null + dcc_r_file_body. + +2003-07-14 17:43 Martin Pool <mbp@samba.org> + + * src/: compress.c, io.h, pump.c: Rename compression functions to + lzo_1x, the generic name for the algorithm family we're using. + +2003-07-14 17:38 Martin Pool <mbp@samba.org> + + * src/compress.c: Doc + +2003-07-14 17:35 Martin Pool <mbp@samba.org> + + * doc/results.txt: [no log message] + +2003-07-14 17:35 Martin Pool <mbp@samba.org> + + * man/.cvsignore: Ignore built HTML files. + +2003-07-14 16:56 Martin Pool <mbp@samba.org> + + * man/distccd.1: [no log message] + +2003-07-14 16:52 Martin Pool <mbp@samba.org> + + * Makefile.in: Don't install README.packaging or SuSE example + init script. + +2003-07-14 16:49 Martin Pool <mbp@samba.org> + + * Makefile.in: Strip out linuxdoc, because all the information + there has been merged into the manpages. + +2003-07-14 16:47 Martin Pool <mbp@samba.org> + + * Makefile.in: Add upload-man target to make the manual available + on the web page. + + * There's no need to install README.popt. + + * Fix targets to build html from troff. + +2003-07-14 16:44 Martin Pool <mbp@samba.org> + + * man/: distccd.1, distcc.1: Credit other people. + +2003-07-14 16:35 Martin Pool <mbp@samba.org> + + * man/distccd.1: Document DISTCC_SAVE_TEMPS + +2003-07-14 16:34 Martin Pool <mbp@samba.org> + + * man/distccd.1: Merge option descriptions and other things. + +2003-07-14 16:15 Martin Pool <mbp@samba.org> + + * man/distcc.1: Merge more information. + +2003-07-14 15:50 Martin Pool <mbp@samba.org> + + * man/distccd.1: Merge more information. + +2003-07-14 15:44 Martin Pool <mbp@samba.org> + + * man/distcc.1: Merge more information. + +2003-07-14 15:16 Martin Pool <mbp@samba.org> + + * man/distcc.1: Merge more information. + +2003-07-14 14:54 Martin Pool <mbp@samba.org> + + * Makefile.in: Add targets to build HTML from manpages. + +2003-07-14 14:47 Martin Pool <mbp@samba.org> + + * man/distccd.1: Start adding more details about the server. + +2003-07-14 14:46 Martin Pool <mbp@samba.org> + + * man/distcc.1: Merge stuff about cross-compiling. + + * More about security. + +2003-07-14 14:41 Martin Pool <mbp@samba.org> + + * INSTALL: More about how to install distccd. + +2003-07-14 14:33 Martin Pool <mbp@samba.org> + + * man/distcc.1: More manpage documentation. + +2003-07-14 13:45 Martin Pool <mbp@samba.org> + + * man/distcc.1: Put a lot more useful information into the manual + page. + +2003-07-14 12:42 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Information on reporting bugs has been + merged into a separate file. + +2003-07-14 12:35 Martin Pool <mbp@samba.org> + + * doc/reporting-bugs.txt: Merge more information on reporting + problems from the SGML manual. + +2003-07-14 12:32 Martin Pool <mbp@samba.org> + + * Makefile.in: Include information on how to report bugs + effectively. + +2003-07-14 12:31 Martin Pool <mbp@samba.org> + + * doc/reporting-bugs.txt: Information on how to report bugs + effectively. + +2003-07-14 12:20 Martin Pool <mbp@samba.org> + + * Makefile.in: Include example-init in package. + +2003-07-14 12:14 Martin Pool <mbp@samba.org> + + * src/mon.c: Increase allowable age of state files to 300s. + +2003-07-14 12:09 Martin Pool <mbp@samba.org> + + * Makefile.in: mon-notify.o is not currently used by the + monitors. + +2003-07-14 11:53 Martin Pool <mbp@samba.org> + + * bench/compiler.py: Don't put commas in path names because they + can cause trouble with some linker command. + +2003-07-14 10:51 Martin Pool <mbp@samba.org> + + * src/: mon-gnome.c, mon-notify.c, mon.c: Fix header ordering. + +2003-07-14 10:47 Martin Pool <mbp@samba.org> + + * configure.ac: Remove standard GTK test macros because we don't + use them. + +2003-07-13 18:40 Martin Pool <mbp@samba.org> + + * Makefile.in: Clean up files which were duplicated in dist_files + and pkgdoc_DOCS. + +2003-07-13 18:09 Martin Pool <mbp@samba.org> + + * patches/.cvsignore: Add built program. + +2003-07-13 18:08 Martin Pool <mbp@samba.org> + + * src/: distcc.h, h_argvtostr.c, h_exten.c, h_issource.c, + h_scanargs.c, h_strip.c, io.h, mon-text.c, state.c: Clean up + header inclusions. + +2003-07-13 18:07 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc + +2003-07-13 17:57 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-07-13 17:55 Martin Pool <mbp@samba.org> + + * DEPENDENCIES, Makefile.in: Remove DEPENDENCIES file, which is + being merged into INSTALL. + +2003-07-13 17:30 Martin Pool <mbp@samba.org> + + * INSTALL: Rewrite installation instructions to be specific to + distcc and to cover all the main steps. + +2003-07-13 12:44 Martin Pool <mbp@samba.org> + + * configure.ac, NEWS: Autodetect the right behaviour for + --enable-gnome: + + If explicitly enabled, insist that the GTK+ libraries be + present. + + If explicitly disabled, don't even look for them. + + Otherwise, build the GTK+ monitor if possible. + +2003-07-12 22:57 Martin Pool <mbp@samba.org> + + * man/distcc.1: Correction for duplicated word by Tobias + Stoeckmann. + +2003-07-12 17:04 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc. + +2003-07-12 16:57 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Fix up checks for remote assembly listings: + we *can* distribute these, unless a filename is specified. + +2003-07-12 16:52 Martin Pool <mbp@samba.org> + + * src/arg.c, NEWS: Add checks for -Wa options that produce an + assembler listing file. + +2003-07-12 11:45 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add tests for new -o and -Wa,-al handling. + +2003-07-12 01:31 Martin Pool <mbp@samba.org> + + * src/compress.c: Add implementation of LZO decompression. + +2003-07-12 01:30 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-07-12 00:58 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc. + +2003-07-11 18:21 Martin Pool <mbp@samba.org> + + * bench/Build.py: Make sure full paths are generated for log + files. + + * Add support for programs that use C++. + +2003-07-11 18:20 Martin Pool <mbp@samba.org> + + * bench/compiler.py: Make default compiler setups consistent with + ones specified by -c + + * Add support for programs that use C++ + +2003-07-11 18:19 Martin Pool <mbp@samba.org> + + * bench/ProjectDefs.py: Add other definitions needed for building + firebird. + +2003-07-11 18:18 Martin Pool <mbp@samba.org> + + * cases/simple.c: Simple test with no header files. + +2003-07-11 17:27 Martin Pool <mbp@samba.org> + + * bench/compiler.py: New/better naming of build directories: now + just 'dist,2'. + +2003-07-11 17:26 Martin Pool <mbp@samba.org> + + * bench/ProjectDefs.py: Comment out Mozilla, which is having + trouble on Debian. + + * Add MozillaFirebird. + +2003-07-11 17:25 Martin Pool <mbp@samba.org> + + * bench/Build.py: Put build logs in the build directory so + they're easier to find and use. + +2003-07-11 15:19 Martin Pool <mbp@samba.org> + + * bench/ProjectDefs.py: Fix unpacked_subdir for Mozilla + +2003-07-11 15:15 Martin Pool <mbp@samba.org> + + * distcc-check: Make sure we do move into the right scratch + directory + + * Remove with -f on completion so that we don't fail if the files + were never created. + +2003-07-11 15:14 Martin Pool <mbp@samba.org> + + * bench/Project.py: We need wget --continue to get the intended + behaviour. + +2003-07-11 15:10 Martin Pool <mbp@samba.org> + + * bench/Summary.py: Don't give an error when trying to print a + summary table of no compilations. + +2003-07-11 15:06 Martin Pool <mbp@samba.org> + + * doc/results.txt: More benchmark stuff. + +2003-07-11 14:50 Martin Pool <mbp@samba.org> + + * bench/Summary.py: Fix uname usage. + +2003-07-11 14:50 Martin Pool <mbp@samba.org> + + * bench/Project.py: Use wget not snarf, because its progress bar + works better with tty and non-tty setups. + +2003-07-11 14:47 Martin Pool <mbp@samba.org> + + * bench/benchmark.py: Show -a in help. + +2003-07-11 14:47 Martin Pool <mbp@samba.org> + + * bench/ProjectDefs.py: Fix apache 2.0.43 link, which has moved. + + * Add Mozilla 1.4 (not tested yet) + +2003-07-11 14:28 Martin Pool <mbp@samba.org> + + * NEWS: When run as "distcc foo.o -o foo", work out that foo.o is + an object file not a compiler name. This can happen with + Mozilla. + +2003-07-11 14:28 Martin Pool <mbp@samba.org> + + * src/implicit.c: When run as "distcc foo.o -o foo", work out + that foo.o is an object file not a compiler name. This can + happen with Mozilla. + + * Many documentation updates to reflect the way that masquerade + invocation now works -- a lot of the comments in this file were + written before it was added. + +2003-07-11 14:20 Martin Pool <mbp@samba.org> + + * src/: filename.h, distcc.h, implicit.c: Move declarations for + filename.c into filename.h. + +2003-07-11 14:18 Martin Pool <mbp@samba.org> + + * src/filename.h: dcc_is_object: New function. + +2003-07-11 14:17 Martin Pool <mbp@samba.org> + + * src/filename.c: dcc_is_object: New function. + + * filename.c: Doesn't need sys/stat.h. + + * Doc. + +2003-07-11 14:13 Martin Pool <mbp@samba.org> + + * Doxyfile: Don't produce LaTeX + +2003-07-11 14:10 Martin Pool <mbp@samba.org> + + * src/filename.c: Doc + +2003-07-11 14:09 Martin Pool <mbp@samba.org> + + * patches/.cvsignore: Ignore built programs. + +2003-07-11 13:34 Martin Pool <mbp@samba.org> + + * src/: exec.c, exec.h: dcc_execvp() can be static + +2003-07-09 18:30 Martin Pool <mbp@samba.org> + + * src/compress.c, TODO: Start a decompressor. + +2003-07-09 18:06 Martin Pool <mbp@samba.org> + + * src/compress.c: First cut at implementation of dcc_send_lzo1x1. + +2003-07-09 18:05 Martin Pool <mbp@samba.org> + + * src/mapfile.c: Finish implementing dcc_map_input_file. + +2003-07-09 17:52 Martin Pool <mbp@samba.org> + + * src/mapfile.c, Makefile.in, src/io.h: Add simple mmap routine + for reading input files. + +2003-07-09 17:42 Martin Pool <mbp@samba.org> + + * configure.ac: Check for sys/mman.h + +2003-07-09 17:39 Martin Pool <mbp@samba.org> + + * src/pump.c: Call dcc_send_lzo1x1 for compressed mode. + +2003-07-09 17:38 Martin Pool <mbp@samba.org> + + * src/: hostfile.c, io.h, loadfile.c: Rename dcc_load_file to + dcc_load_file_string to be more clear. + +2003-07-09 17:17 Martin Pool <mbp@samba.org> + + * patches/trylzo.c: Simple test harness to measure lzo1x1 + compression. + +2003-07-09 16:49 Martin Pool <mbp@samba.org> + + * src/compress.c: Stub file for doing bulk compression. + +2003-07-09 16:28 Martin Pool <mbp@samba.org> + + * Makefile.in, src/bulk.c, src/bulk.h, src/clirpc.c, src/clirpc.h, + src/io.c, src/io.h, src/pump.c, src/remote.c, src/serve.c: + Refactor bulk-IO code, and start adding support for compression. + Nothing is actually compressed yet. + +2003-07-09 16:25 Martin Pool <mbp@samba.org> + + * src/timebuild: Remove 'timebuild' script because it's replaced + by a better benchmark script. + +2003-07-09 15:54 Martin Pool <mbp@samba.org> + + * src/sendfile.c: Handle EINTR from sendfile(). + +2003-07-09 15:44 Martin Pool <mbp@samba.org> + + * configure.ac: Remove check for poptGetContext that made us get + an unnecessary second -lpopt option. + +2003-07-09 15:39 Martin Pool <mbp@samba.org> + + * Makefile.in: Doc + +2003-07-09 15:38 Martin Pool <mbp@samba.org> + + * Makefile.in: Start including lzo support: include it on the + include path and in the distribution and build minilzo.o. + +2003-07-09 15:37 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version. + +2003-07-09 14:31 Martin Pool <mbp@samba.org> + + * TODO: Notes on distcc-check and globally visible state. + +2003-07-09 14:17 Martin Pool <mbp@samba.org> + + * TODO: Update for current progress. + +2003-07-09 13:41 Martin Pool <mbp@samba.org> + + * TODO: 0-length output files are now handled OK. + +2003-07-09 13:13 Martin Pool <mbp@samba.org> + + * NEWS: Correction to NEWS: in fact the GNOME monitor is not + smart about making updates only when visible. + +2003-07-09 13:04 Martin Pool <mbp@samba.org> + + * NEWS: Credit Marcelo Matus. + +2003-07-09 12:46 Martin Pool <mbp@samba.org> + + * NEWS: Bump version to 2.8 + +2003-07-09 12:01 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version to 2.8 + +2003-07-08 17:02 Martin Pool <mbp@samba.org> + + * doc/results.txt: More results from SSH + +2003-07-08 16:58 Martin Pool <mbp@samba.org> + + * src/md.c, Makefile.in: Remove md.c because we can't do anything + very useful here. + +2003-07-08 16:49 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc. + +2003-07-08 16:49 Martin Pool <mbp@samba.org> + + * Makefile.in, src/cpp.h: Remove md.c + +2003-07-08 16:45 Martin Pool <mbp@samba.org> + + * Makefile.in: Add security page. + +2003-07-08 16:11 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-07-08 15:59 Martin Pool <mbp@samba.org> + + * src/cpp.c: Doc. + +2003-07-08 15:45 Martin Pool <mbp@samba.org> + + * src/: arg.c, arg.h, argutil.c, clirpc.c, compile.c, cpp.c, + distcc.c, distcc.h, exec.c, implicit.c, md.c, serve.c, srvrpc.c, + ssh.c, strip.c: Move argument-handing prototypes to arg.h + +2003-07-08 15:41 Martin Pool <mbp@samba.org> + + * src/arg.h, Makefile.in: arg.h: new file. + +2003-07-08 15:17 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc. + +2003-07-08 15:11 Martin Pool <mbp@samba.org> + + * src/md.c: Doc + +2003-07-08 15:05 Martin Pool <mbp@samba.org> + + * src/cpp.c: dcc_cpp_maybe: Call dcc_fudge_md. + +2003-07-08 15:03 Martin Pool <mbp@samba.org> + + * src/: md.c, cpp.h: md.c: new file for dependency generation. + +2003-07-08 14:59 Martin Pool <mbp@samba.org> + + * Makefile.in: md.c: new file. + +2003-07-08 14:53 Martin Pool <mbp@samba.org> + + * src/strip.c: Doc. + +2003-07-08 14:49 Martin Pool <mbp@samba.org> + + * src/cpp.c: Doc. + +2003-07-08 14:44 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc. + +2003-07-08 14:36 Martin Pool <mbp@samba.org> + + * src/: arg.c, argutil.c: Move functions that are to do with + handling argv[] arrays but not really distcc-specific + intelligence from arg.c to argutil.c. + + * Delete dcc_deepcopy_argv which is no longer used. + +2003-07-08 14:34 Martin Pool <mbp@samba.org> + + * Makefile.in: argutil.c: New file containing argv[] utilities. + + * Clean up harness object lists to use $(common_obj) + +2003-07-08 14:31 Martin Pool <mbp@samba.org> + + * src/argutil.c: New file containing argv[] utilities. + +2003-07-08 14:24 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add test for distcc cc -otesttmp.o + +2003-07-08 14:01 Martin Pool <mbp@samba.org> + + * NEWS: dcc_set_output: Add support for -ofoo.o. Based on a + patch from Tsutomu Yasuda. + +2003-07-08 13:57 Martin Pool <mbp@samba.org> + + * src/arg.c: dcc_set_output: Add support for -ofoo.o. Based on a + patch from Tsutomu Yasuda. + +2003-07-08 13:46 Martin Pool <mbp@samba.org> + + * distcc-check: Simple sanity-check script. + +2003-07-08 13:23 Martin Pool <mbp@samba.org> + + * doc/example-init: Example Red Hat init file from Andrew Morton. + +2003-07-08 13:20 Martin Pool <mbp@samba.org> + + * NEWS: Example xinetd configuration from akpm. + +2003-07-08 13:19 Martin Pool <mbp@samba.org> + + * doc/example.xinetd: Doc + +2003-07-08 13:16 Martin Pool <mbp@samba.org> + + * doc/example.xinetd, Makefile.in: Example xinetd configuration + from akpm. + +2003-07-08 13:06 Martin Pool <mbp@samba.org> + + * src/remote.c: Doc. + +2003-07-08 12:42 Martin Pool <mbp@samba.org> + + * src/: clinet.c, io.c, io.h, sendfile.c: dcc_select_for_write, + dcc_select_for_read: Both now take a timeout parameter, which + is set by default to 15 for opening connections, and 300s for + IO during a transfer. This should reduce problems with + timeouts during an SSH connection. + +2003-07-08 12:39 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-07-08 12:18 Martin Pool <mbp@samba.org> + + * src/clinet.c: dcc_connect_timed: When connecting, we need to + select() until the new socket is writeable, not readable. This + bug was previously masked by the inverted call in + dcc_select_for_read(). + +2003-07-08 12:14 Martin Pool <mbp@samba.org> + + * src/remote.c: dcc_remote_connect: Factor out code to open a + connection from dcc_compile_remote. + +2003-07-07 23:57 Martin Pool <mbp@samba.org> + + * NEWS: dcc_run_job: Use separate input and output file + descriptors, to support sshds that use pipes to run programs + rather than local sockets. Suggestion from Felix Lee. + +2003-07-07 23:53 Martin Pool <mbp@samba.org> + + * src/io.c: Handle EINTR from read and write. + +2003-07-07 23:44 Martin Pool <mbp@samba.org> + + * src/io.c: dcc_select_for_write: Handle EINTR. + + * Doc. + +2003-07-07 23:37 Martin Pool <mbp@samba.org> + + * src/io.c, NEWS: dcc_select_for_read: Fix silly parameter + ordering mistake. + +2003-07-07 23:31 Martin Pool <mbp@samba.org> + + * src/io.c: dcc_select_for_read: Fix warning. + +2003-07-07 23:27 Martin Pool <mbp@samba.org> + + * src/io.c: dcc_select_for_read: Better trace messages. + +2003-07-07 23:17 Martin Pool <mbp@samba.org> + + * src/: daemon.c, daemon.h, dparent.c, prefork.c, serve.c: + dcc_run_job: Use separate input and output file descriptors, to + support sshds that use pipes to run programs rather than local + sockets. Suggestion from Felix Lee. + +2003-07-07 23:15 Martin Pool <mbp@samba.org> + + * configure.ac: Don't give a warning about linuxdoc, because we + do it during installation. + +2003-07-07 23:03 Martin Pool <mbp@samba.org> + + * src/: serve.c: Doc. + +2003-07-07 22:57 Martin Pool <mbp@samba.org> + + * NEWS: If Linuxdoc was not detected, just give a small warning + and not an error while installing. + +2003-07-07 22:25 Martin Pool <mbp@samba.org> + + * Makefile.in: If Linuxdoc was not detected, just give a small + warning and not an error while installing. + +2003-07-07 18:35 Martin Pool <mbp@samba.org> + + * doc/protocol-1.txt: Document the changes to support 0-byte + output. + +2003-07-07 18:34 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-07-07 18:33 Martin Pool <mbp@samba.org> + + * test/badcc: Add mode to generate empty output. + +2003-07-07 18:08 Martin Pool <mbp@samba.org> + + * src/clirpc.c: Retrieval of the output file is now determined by + the remote compiler status, not the DOTO length. This allows + us to correctly get back a 0-length output file from a + successful compile. + +2003-07-07 18:03 Martin Pool <mbp@samba.org> + + * src/remote.c: Doc. + +2003-07-07 17:59 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2003-07-07 17:48 Martin Pool <mbp@samba.org> + + * src/: bulk.h, bulk.c: Be more careful about treating token + parameters as unsigned. + +2003-07-07 17:28 Martin Pool <mbp@samba.org> + + * configure.ac, NEWS: Better test for vararg macro support that + correctly identifies apple gcc brokenness. From Matt Watson + <mwatson@apple.com>. + +2003-07-07 16:44 Martin Pool <mbp@samba.org> + + * NEWS: distccmon-text: Output should always be line-buffered, + even if not writing to a terminal. + +2003-07-07 15:27 Martin Pool <mbp@samba.org> + + * src/mon-text.c: distccmon-text: Output should always be + line-buffered, even if not writing to a terminal. + +2003-07-07 15:23 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Doc. + +2003-07-07 13:50 Martin Pool <mbp@samba.org> + + * src/state.c: dcc_note_state: Quote strings in trace message. + +2003-07-07 12:55 Martin Pool <mbp@samba.org> + + * src/mon.h, NEWS: Protect against repeated inclusion. + Suggestion from Fr'ed'eric Forjan. + +2003-07-07 12:53 Martin Pool <mbp@samba.org> + + * src/mon.h: mon.h now uses "extern C" so that it can be included + from C++ programs. Suggestion from Fr'ed'eric Forjan. + +2003-06-25 17:50 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Doc. + +2003-06-25 17:48 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Always update load, even if not onscreen, so + that we don't show a dummy message at startup. + +2003-06-25 17:46 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Increase niceness at startup. + +2003-06-25 17:43 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c, NEWS: distccmon-gnome: Prevent selection of + rows in the treeview. Emphasize horizontal rows + ("rules-hint"). + +2003-06-25 17:28 Martin Pool <mbp@samba.org> + + * NEWS: distccmon-gnome: Check whether the window is iconified or + withdrawn, and if so then don't update. This slightly reduces + the load in those cases. + +2003-06-25 17:12 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Expose a reference to the GtkTreeView widget + and use that in the update callback. + + * Check whether the window is iconified or withdrawn, and if so + then don't update. This slightly reduces the load in those + cases. + +2003-06-25 11:31 Martin Pool <mbp@samba.org> + + * NEWS: Prepare for 2.7.1 + +2003-06-25 11:28 Martin Pool <mbp@samba.org> + + * patches/state-in-home.diff: Store rolled-back ~/.distcc/state + patch. + +2003-06-25 11:27 Martin Pool <mbp@samba.org> + + * Makefile.in: Fix EXEEXT on gnome binaries. + +2003-06-25 11:26 Martin Pool <mbp@samba.org> + + * configure.ac: Prepare for 2.7.1 + + * Fix EXEEXT on gnome binaries. + +2003-06-25 10:59 Martin Pool <mbp@samba.org> + + * src/state.c, NEWS: Roll back: put the state in the temporary + directory, because storing it in home does not seem to fix + ebuild. + +2003-06-24 13:40 Martin Pool <mbp@samba.org> + + * patches/hosts-from-file-raabe.diff: hosts-from-file-raabe.diff + Has been merged + +2003-06-21 14:21 Martin Pool <mbp@samba.org> + + * DEPENDENCIES: Note that libgnome is no longer required. + +2003-06-21 13:45 Martin Pool <mbp@samba.org> + + * TODO: Updates based on work done recently. + +2003-06-21 13:42 Martin Pool <mbp@samba.org> + + * NEWS, src/state.c: State files now in ~/.distcc/state + +2003-06-21 13:13 Martin Pool <mbp@samba.org> + + * src/arg.c: Fix constness. + +2003-06-20 17:32 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Doc. + +2003-06-20 17:29 Martin Pool <mbp@samba.org> + + * configure.ac: Add autoconf test for GTK+-2.0 (but don't call it + yet.) + + * Change --enable-gnome to just check for GTK+. + +2003-06-20 17:25 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: stdint.h is not needed. + +2003-06-20 17:23 Martin Pool <mbp@samba.org> + + * Makefile.in, NEWS: distccmon-gnome now depends only on gtk+-2.0 + +2003-06-20 17:18 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Follow the advice in the GTK+ 2.2 API: + + * Don't call gtk_widget_set_usize and gtk_window_set_policy, but + instead just gtk_window_set_default_size. + + This gives us the same default size and allows the user to + shrink + the window, but doesn't let them shrink it right down to zero. + +2003-06-20 17:15 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Add some other necessary headers. + +2003-06-20 17:14 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Update to use just the GTK+ 2.0 API, and + nothing from libgnomeui. + +2003-06-16 18:40 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove stupid autom4te.cache from distclean + +2003-06-16 18:36 Martin Pool <mbp@samba.org> + + * src/arg.c: Remove TODO about -MD because the information is in + TODO and I think I know how to fix it now. + +2003-06-16 18:33 Martin Pool <mbp@samba.org> + + * src/cpp.c: Doc + +2003-06-16 18:30 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version + +2003-06-16 17:51 Martin Pool <mbp@samba.org> + + * configure.ac, NEWS: Release 2.7. + +2003-06-16 17:50 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc + +2003-06-16 17:39 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-06-16 17:06 Martin Pool <mbp@samba.org> + + * TODO: Notes on dnotify. + +2003-06-16 16:59 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-06-16 16:50 Martin Pool <mbp@samba.org> + + * Makefile.in: Need to link LIBS in to get functions like + inet_ntoa on Solaris, etc. + +2003-06-16 16:31 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Make the tree sortable. + +2003-06-16 14:39 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Doc. + +2003-06-16 14:38 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Put commas in load average line. + +2003-06-16 14:37 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Load bar now actually shows the system load as + we go. + + * Load bar is initialized at startup. + +2003-06-16 14:31 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Add a callback to update the load indicator. + +2003-06-16 14:26 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Fix up load indicator. + +2003-06-16 14:17 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Start adding a load indicator at the bottom of + the window. + +2003-06-16 13:48 Martin Pool <mbp@samba.org> + + * src/mon-notify.c, Makefile.in, src/mon.c: mon-notify.c: New + file to keep the dnotify stuff out of mon.c + +2003-06-16 13:41 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Remove dnotify support, because the signals + seem to cause trouble with GNOME, and too-frequent updates are + bad for our CPU usage. + +2003-06-16 13:15 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Doc + +2003-06-16 13:07 Martin Pool <mbp@samba.org> + + * NEWS: Check for sys/select.h, which is not present on HP-UX. + +2003-06-16 13:03 Martin Pool <mbp@samba.org> + + * configure.ac, src/io.c: Check for sys/select.h, which is not + present on HP-UX. + +2003-06-16 12:48 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Doc. + +2003-06-16 12:43 Martin Pool <mbp@samba.org> + + * src/mon.c: Doc. + +2003-06-16 12:33 Martin Pool <mbp@samba.org> + + * src/: clirpc.c, clirpc.h, compile.c, exec.c, exec.h, mon.c, + rpc.c, rpc.h, serve.c, srvrpc.c: Store all token parameter + values, including lengths and waitstatuses to unsigned + throughout the program. Fixes some warnings on Sun and + probably a bit safer. + +2003-06-16 12:25 Martin Pool <mbp@samba.org> + + * src/arg.c: dcc_note_compiled: Fix constness. + +2003-06-16 12:25 Martin Pool <mbp@samba.org> + + * src/util.c: snprintf.h is needed. + +2003-06-16 12:24 Martin Pool <mbp@samba.org> + + * src/distcc.h: Change dcc_trace_argv macro to try to quieten + warnings on Sun. + +2003-06-16 12:21 Martin Pool <mbp@samba.org> + + * src/trace.h: Add RS_STMT_START macros from glib, to quieten + warnings on Sun. + +2003-06-16 12:19 Martin Pool <mbp@samba.org> + + * src/hosts.c: snprintf.h is needed. + +2003-06-16 12:17 Martin Pool <mbp@samba.org> + + * src/: mon-gnome.c, mon.c, mon.h: Rename dcc_gnome_setup_dnotify + to dcc_gnome_setup_notify to be less Linux-specific. + + * Add documentation on the mon interface to help people writing + new monitors. + +2003-06-16 12:08 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Doc + +2003-06-16 12:05 Martin Pool <mbp@samba.org> + + * configure.ac: Fix configure messages. + +2003-06-16 12:04 Martin Pool <mbp@samba.org> + + * configure.ac: Only check for libgnomeui-2.0 if --enable-gnome + was specified. + +2003-06-16 11:27 Martin Pool <mbp@samba.org> + + * doc/results.txt: Notes on performance of monitor with dnotify. + +2003-06-14 20:09 Martin Pool <mbp@samba.org> + + * TODO: IPv6 is now done. + +2003-06-14 20:08 Martin Pool <mbp@samba.org> + + * TODO: Notes on nicely handling gcc -MD. + +2003-06-13 17:30 Martin Pool <mbp@samba.org> + + * src/clinet.c: Doc. + +2003-06-13 14:57 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Change default size + + * Print out a star when we reread the directory. + +2003-06-13 14:39 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Even if we can use dnotify, still poll every + 10s to clean up dead files. + +2003-06-13 14:33 Martin Pool <mbp@samba.org> + + * src/mon.c: Also listen for deletion notifications to make sure + that we notice when the last compiler quits. + +2003-06-13 14:31 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Attach to dnotify prompts from mon.c and drain + them as they arrive. + +2003-06-13 14:28 Martin Pool <mbp@samba.org> + + * src/mon.c: dcc_mon_setup_dnotify: Check that the fcntl to set + F_NOTIFY suceeded -- this can fail on linux systems that don't + have dnotify in the kernel. + +2003-06-13 12:55 Martin Pool <mbp@samba.org> + + * NEWS: Fix spelling mistake. + +2003-06-13 12:18 Martin Pool <mbp@samba.org> + + * src/mon.c: Dnotify stuff now actually writes to the dummy pipe + when the state changes. + +2003-06-13 12:14 Martin Pool <mbp@samba.org> + + * src/: mon.c, state.c: Doc. + +2003-06-12 22:02 Martin Pool <mbp@samba.org> + + * src/mon.c: Doc + +2003-06-12 21:58 Martin Pool <mbp@samba.org> + + * src/mon.c: Fix up half-committed code. + +2003-06-12 21:55 Martin Pool <mbp@samba.org> + + * configure.ac, src/mon-gnome.c: Fix up half-committed code. + +2003-06-12 18:13 Martin Pool <mbp@samba.org> + + * TODO, src/mon-gnome.c, src/mon.c, src/mon.h: Start adding + dnotify support for monitor rather than polling. + +2003-06-12 18:02 Martin Pool <mbp@samba.org> + + * Makefile.in: Fix distccmon-gnome + +2003-06-12 18:00 Martin Pool <mbp@samba.org> + + * Makefile.in: Make sure to use the right cpp flags when building + distccmon-gnome + +2003-06-12 17:56 Martin Pool <mbp@samba.org> + + * Makefile.in: distccmon-gnome needs nonblocking routines from + netutil.o + +2003-06-12 17:50 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Refactor + +2003-06-12 17:37 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Doc. + +2003-06-12 17:27 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: GTK 2.0 manual says that gtk_timeout_add is + deprecated in favour of g_timeout_add. + +2003-06-12 17:26 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Show USER@HOST in monitor title bar, because + it's possible people will run this remotely. + +2003-06-12 16:57 Martin Pool <mbp@samba.org> + + * NEWS: If --enable-gnome was specified, then check that + libgnomeui is actually present. + +2003-06-12 16:52 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version + + * If --enable-gnome was specified, then check that libgnomeui is + actually present. + +2003-06-12 16:38 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Doc + +2003-06-12 16:27 Martin Pool <mbp@samba.org> + + * DEPENDENCIES: Describe dependencies for GNOME. + +2003-06-12 16:25 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: The GTK tree model is now updated on each new + monitor state. It seems to be working correctly. + +2003-06-12 16:09 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Reindent only. + +2003-06-12 16:06 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Add a callback every 0.5s. At the moment it + does nothing. + +2003-06-12 15:56 Martin Pool <mbp@samba.org> + + * TODO: More small updates. + +2003-06-12 15:51 Martin Pool <mbp@samba.org> + + * TODO: Remove many done TODO items, and add notes on some + continuing ones. + +2003-06-12 15:40 Martin Pool <mbp@samba.org> + + * src/clirpc.c: Doc + +2003-06-12 13:47 Martin Pool <mbp@samba.org> + + * src/compile.c: dcc_build_somewhere: input_fname must be + initialized to NULL so that in the case of a very early + fallback to local compilation we don't read an invalid pointer + and crash. + +2003-06-12 13:44 Martin Pool <mbp@samba.org> + + * src/: clirpc.c, remote.c, state.c: Remove infrequently-hit + states. + +2003-06-12 13:42 Martin Pool <mbp@samba.org> + + * src/compile.c: Remove "Startup" state because it's very + unlikely to be hit. + +2003-06-12 12:53 Martin Pool <mbp@samba.org> + + * configure.ac: Prepare for 2.6 release. + +2003-06-12 12:41 Martin Pool <mbp@samba.org> + + * src/prefork.c: dcc_preforking_parent: Put in another 1s sleep + between collecting dead children and starting new ones. + +2003-06-12 12:35 Martin Pool <mbp@samba.org> + + * NEWS: Reorder sections. + + Patch from Sean MacLennan: + + * dcc_ncpus for Linux: make sure that we don't return 0 cpus. + +2003-06-12 12:34 Martin Pool <mbp@samba.org> + + * src/ncpus.c: Patch from Sean MacLennan: + + * dcc_ncpus for Linux: make sure that we don't return 0 cpus. + +2003-06-12 12:14 Martin Pool <mbp@samba.org> + + * NEWS: Get ready for 2.66 release. + +2003-06-12 12:04 Martin Pool <mbp@samba.org> + + * Makefile.in: Include doc/status-1.txt in distribution. + +2003-06-12 12:00 Martin Pool <mbp@samba.org> + + * doc/status-1.txt: Update to describe the implemented monitor + design. + +2003-06-12 09:53 Martin Pool <mbp@samba.org> + + * NEWS: Reorder items + +2003-06-12 09:30 Martin Pool <mbp@samba.org> + + * NEWS: Note changed tmpdir name. + +2003-06-12 00:34 Martin Pool <mbp@samba.org> + + * src/mon.c: Skip state files for which the process no longer + exists. + +2003-06-12 00:29 Martin Pool <mbp@samba.org> + + * src/state.c: Call the blocked state "starved". + +2003-06-12 00:28 Martin Pool <mbp@samba.org> + + * src/state.c: Call the blocked state "bored" + +2003-06-12 00:26 Martin Pool <mbp@samba.org> + + * src/mon.c: Doc. + +2003-06-12 00:17 Martin Pool <mbp@samba.org> + + * src/clirpc.c: Doc. + +2003-06-12 00:15 Martin Pool <mbp@samba.org> + + * src/clirpc.c: Add more states: distinguish more states: waiting + for preprocessor, sending source, and receiving object. + +2003-06-12 00:12 Martin Pool <mbp@samba.org> + + * src/: state.h, state.c: Add more states. + +2003-06-12 00:09 Martin Pool <mbp@samba.org> + + * src/mon-text.c: Clip columns to appropriate widths. + +2003-06-12 00:04 Martin Pool <mbp@samba.org> + + * src/: compile.c: Note input filename as soon as it has been + determined. + +2003-06-12 00:03 Martin Pool <mbp@samba.org> + + * src/: compile.c, compile.h, remote.c, where.c, where.h: Roll + back the rest of the xmit lock code. + + * Rely on state code to keep track of what source file we're + compiling. + +2003-06-11 22:41 Martin Pool <mbp@samba.org> + + * src/: compile.c, state.c, state.h: Show another state during + startup. + +2003-06-11 22:38 Martin Pool <mbp@samba.org> + + * src/state.c: Doc + +2003-06-11 22:37 Martin Pool <mbp@samba.org> + + * src/clirpc.c: dcc_retrieve_results: Try to keep the right file + name when updating state. + +2003-06-11 22:36 Martin Pool <mbp@samba.org> + + * TODO: Thoughts on -MD support. + +2003-06-11 22:36 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-06-11 22:34 Martin Pool <mbp@samba.org> + + * src/remote.c: Doc + +2003-06-11 22:31 Martin Pool <mbp@samba.org> + + * src/remote.c: dcc_compile_remote: Try to keep the right file + name when updating state. + +2003-06-11 22:30 Martin Pool <mbp@samba.org> + + * src/where.c: dcc_lock_pause: Set state notification when + blocked. + +2003-06-11 22:29 Martin Pool <mbp@samba.org> + + * src/: state.c, state.h: dcc_note_state: constness + +2003-06-11 22:29 Martin Pool <mbp@samba.org> + + * src/: filename.h, filename.c: dcc_find_basename: constness + +2003-06-11 22:26 Martin Pool <mbp@samba.org> + + * src/state.c: dcc_note_state: Remember the previously-set + filename and host, so that we can just change state without + needing to always know the filename. + +2003-06-11 22:22 Martin Pool <mbp@samba.org> + + * src/: state.c, state.h: Add STATE_BLOCKED. + +2003-06-11 22:21 Martin Pool <mbp@samba.org> + + * src/state.h: Delete garbage comment. + +2003-06-11 17:22 Martin Pool <mbp@samba.org> + + * src/mon.c: Doc. + +2003-06-11 17:20 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove done todo + +2003-06-11 17:19 Martin Pool <mbp@samba.org> + + * doc/results.txt: Measurements with state notes turned on. + +2003-06-11 17:18 Martin Pool <mbp@samba.org> + + * src/: compile.c, compile.h, remote.c: dcc_compile_remote: Input + filename is passed in for use in state notes. + +2003-06-11 17:17 Martin Pool <mbp@samba.org> + + * src/remote.c: dcc_compile_remote: xmit_lock_fd is unused for + now. + +2003-06-11 17:14 Martin Pool <mbp@samba.org> + + * src/remote.c: Doc. + +2003-06-11 17:07 Martin Pool <mbp@samba.org> + + * src/mon-text.c: Doc. + +2003-06-11 17:02 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-06-11 16:59 Martin Pool <mbp@samba.org> + + * src/mon-text.c: Take one optional parameter, which sets a time + to wait between refreshes. + + Currently done using usleep(), which may not be portable. + +2003-06-11 16:58 Martin Pool <mbp@samba.org> + + * src/mon.c: dcc_mon_poll: Fix memory scribble. + +2003-06-11 16:53 Martin Pool <mbp@samba.org> + + * src/state.c: Doc. + +2003-06-11 16:46 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-06-11 16:29 Martin Pool <mbp@samba.org> + + * src/state.c: Only unlink file before replacing on cygwin. + +2003-06-11 16:24 Martin Pool <mbp@samba.org> + + * src/state.c: Write state out into temporary files and rename + into place, to try to avoid monitors ever seeing half-full + files. + +2003-06-11 15:19 Martin Pool <mbp@samba.org> + + * src/mon.c: Reduce max age to 30s. + +2003-06-11 15:06 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Include hostname in tempdir name, to avoid + problems when /tmp is shared. + +2003-06-11 15:03 Martin Pool <mbp@samba.org> + + * NEWS: Note distccmon-text. + +2003-06-11 15:00 Martin Pool <mbp@samba.org> + + * src/tempfile.c: dcc_make_tmpnam: Just use asprintf() now we + have it, rather than doing the equivalent by hand. + + Use the plain pid in temporary filenames rather than + zero-filling + it. + +2003-06-11 14:55 Martin Pool <mbp@samba.org> + + * src/mon-text.c: Dump out the monitor list in a simple text + table form. + +2003-06-11 14:50 Martin Pool <mbp@samba.org> + + * src/mon.c: Doc + + * dcc_mon_kill_old: Always close fd on failure. + + * Build up a list of dcc_mon_list structures as the files are + read in. + + * dcc_mon_list_free: Walk down the list, freeing each link. + +2003-06-11 14:24 Martin Pool <mbp@samba.org> + + * src/mon.c: Read host and file variabels from state. + +2003-06-11 14:22 Martin Pool <mbp@samba.org> + + * src/mon.c: Put in constant for the time to allow statefiles to + live, and reduce to 60s. + + * Read state string. + +2003-06-11 14:19 Martin Pool <mbp@samba.org> + + * src/mon.c: Check for and kill old state files. + + * Read in the start of the state file. + +2003-06-11 14:15 Martin Pool <mbp@samba.org> + + * src/: rpc.c, rpc.h, srvrpc.c: dcc_r_token_string: New function + factored out. + +2003-06-11 14:06 Martin Pool <mbp@samba.org> + + * src/exitcode.h: Add EXIT_GONE + +2003-06-11 12:41 Martin Pool <mbp@samba.org> + + * src/mon-text.c: distccmon-gnome: Emit blank at end. + +2003-06-11 12:41 Martin Pool <mbp@samba.org> + + * src/mon.c: dcc_mon_do_file: Open each state file and handle + missing ones. + + * dcc_mon_poll: Fix reference to freed memory. + +2003-06-11 12:35 Martin Pool <mbp@samba.org> + + * src/: state.c, state.h: dcc_state_prefix: Export identifying + prefix for state files. + +2003-06-11 12:35 Martin Pool <mbp@samba.org> + + * src/mon.c: dcc_mon_do_file: New function. Skip everything but + state files. + +2003-06-11 12:31 Martin Pool <mbp@samba.org> + + * src/mon.c: dcc_mon_poll: Partial implementation that just + traverses the directory. + +2003-06-11 12:30 Martin Pool <mbp@samba.org> + + * src/mon-text.c: Set trace level from environment. + +2003-06-11 12:30 Martin Pool <mbp@samba.org> + + * src/distcc.c, src/distcc.h, src/traceenv.c, Makefile.in: + dcc_set_trace_from_env: Split out into new file src/traceenv.c, + so that this can also be used from monitor programs. + +2003-06-11 12:29 Martin Pool <mbp@samba.org> + + * .cvsignore: Ignore distccmon-text binary. + +2003-06-11 12:24 Martin Pool <mbp@samba.org> + + * src/trace.c: Default trace should get all messages allowed by + log level. + +2003-06-11 12:22 Martin Pool <mbp@samba.org> + + * Makefile.in: Build and install distccmon-text + +2003-06-11 12:19 Martin Pool <mbp@samba.org> + + * src/trace.c: Typo + +2003-06-11 12:18 Martin Pool <mbp@samba.org> + + * src/trace.c: If no logger has been initialized when the first + message goes out, then write to stderr. + +2003-06-11 12:13 Martin Pool <mbp@samba.org> + + * src/mon.h: Declare part of the monitor API + +2003-06-11 12:13 Martin Pool <mbp@samba.org> + + * src/mon-text.c: Hook in to trace code. + +2003-06-11 12:11 Martin Pool <mbp@samba.org> + + * Makefile.in: More routines are needed for monitors + +2003-06-11 12:06 Martin Pool <mbp@samba.org> + + * src/mon-text.c: Hook in to trace code. + + * Doc. + +2003-06-11 12:04 Martin Pool <mbp@samba.org> + + * src/: exec.c, util.c: dcc_remove_if_exists: Move to util.c + +2003-06-11 12:04 Martin Pool <mbp@samba.org> + + * Makefile.in: Add mon_obj variable for building monitor + programs. + +2003-06-11 11:58 Martin Pool <mbp@samba.org> + + * src/mon-text.c: src/mon-text.c: New file. + +2003-06-11 11:57 Martin Pool <mbp@samba.org> + + * Makefile.in: Include src/mon-gnome.c in distribution + + * src/mon-text.c: New file. + +2003-06-11 11:51 Martin Pool <mbp@samba.org> + + * src/state.c: dcc_note_state: Put client pid in state. + +2003-06-11 11:50 Martin Pool <mbp@samba.org> + + * Makefile.in, src/mon.c, src/mon.h: src/mon.c, src/mon.h: New + files. + +2003-06-11 11:48 Martin Pool <mbp@samba.org> + + * src/: clirpc.c, remote.c: Add more calls to publish state. + +2003-06-11 11:43 Martin Pool <mbp@samba.org> + + * src/state.c: dcc_note_state: Handle null file or host names. + +2003-06-11 11:39 Martin Pool <mbp@samba.org> + + * src/: distcc.c, state.c, state.h: Call dcc_remove_state_file + from atexit in client. + +2003-06-11 11:37 Martin Pool <mbp@samba.org> + + * src/state.c: dcc_remove_state_file: Implement. + +2003-06-11 11:35 Martin Pool <mbp@samba.org> + + * src/state.c: dcc_open_state_file: Release memory after use. + +2003-06-11 11:32 Martin Pool <mbp@samba.org> + + * src/: rpc.c, rpc.h: dcc_x_token_string: Make buffer const. + +2003-06-11 11:31 Martin Pool <mbp@samba.org> + + * src/state.c: dcc_note_state: Include file and host too. + +2003-06-11 11:28 Martin Pool <mbp@samba.org> + + * src/state.c: dcc_note_state: Include state string as well. + +2003-06-11 11:26 Martin Pool <mbp@samba.org> + + * src/clirpc.c: dcc_x_argv: Call dcc_x_token_string rather than + doing it inline. + +2003-06-11 11:22 Martin Pool <mbp@samba.org> + + * src/: rpc.h, rpc.c: dcc_x_token_string: New function factored + out. + +2003-06-11 11:06 Martin Pool <mbp@samba.org> + + * Makefile.in: Subst in LINUXDOC. + +2003-06-11 11:02 Martin Pool <mbp@samba.org> + + * configure.ac: AC_ARG_VAR LINUXDOC + +2003-06-11 11:00 Martin Pool <mbp@samba.org> + + * configure.ac: Add a check for existence of linuxdoc. + +2003-06-11 10:47 Martin Pool <mbp@samba.org> + + * src/snprintf.h: snprintf.h needs to include stdarg.h to get + va_list. Possibly fixes IRIX. + +2003-06-10 18:23 Martin Pool <mbp@samba.org> + + * NEWS: Patch from Paul Russell: + + * If the compiler is not found on the server and is a + fully-qualified + name, then strip off the full name and just look for it on the + path. + +2003-06-10 18:16 Martin Pool <mbp@samba.org> + + * src/exec.c: Doc. + +2003-06-10 18:15 Martin Pool <mbp@samba.org> + + * src/exec.c: Patch from Paul Russell: + + * If the compiler is not found on the server and is a + fully-qualified + name, then strip off the full name and just look for it on the + path. + +2003-06-10 18:00 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-06-10 18:00 Martin Pool <mbp@samba.org> + + * NEWS: Note new state files. + +2003-06-10 17:57 Martin Pool <mbp@samba.org> + + * src/stat.c, src/stat.h, src/state.c, src/state.h, Makefile.in, + src/compile.c: Rename stat.* to state.* + +2003-06-10 17:57 Martin Pool <mbp@samba.org> + + * src/stat.h: dcc_remove_state_file: New function. + +2003-06-10 17:56 Martin Pool <mbp@samba.org> + + * src/stat.c: dcc_get_state_file: New function to return the name + of the state file for this process. + + * dcc_note_state: Start writing into state file. + +2003-06-10 17:43 Martin Pool <mbp@samba.org> + + * src/compile.c: Update state directory when compiling locally. + +2003-06-10 17:42 Martin Pool <mbp@samba.org> + + * src/arg.c: Factor out "compile from %s to %s" message into its + own function, and log only the basename. Should prevent + page-widening in server logs. + +2003-06-10 17:41 Martin Pool <mbp@samba.org> + + * src/: stat.c, stat.h: dcc_note_state only logs the basename of + the file. + +2003-06-10 17:39 Martin Pool <mbp@samba.org> + + * src/stat.c: dcc_note_state: Trim filename down to basename. + +2003-06-10 17:37 Martin Pool <mbp@samba.org> + + * NEWS: Try to fix UTF-8 coding, which seemed to be mangled by + CVS. + +2003-06-10 17:31 Martin Pool <mbp@samba.org> + + * NEWS: In compilation log message, just show the basename of the + file to make it more compact. + +2003-06-10 17:23 Martin Pool <mbp@samba.org> + + * src/: stat.h, stat.c: Add compile state constants. + +2003-06-10 17:16 Martin Pool <mbp@samba.org> + + * src/: filename.h, filename.c: dcc_find_basename: New function. + +2003-06-10 16:57 Martin Pool <mbp@samba.org> + + * src/compile.c: Remove unneeded header. + +2003-06-10 16:55 Martin Pool <mbp@samba.org> + + * src/: stat.c, stat.h: dcc_note_state: New function to record + what the client's up to. + +2003-06-10 16:54 Martin Pool <mbp@samba.org> + + * src/: bulk.c, distcc.h: Move O_BINARY ifdef to distcc.h + +2003-06-10 15:56 Martin Pool <mbp@samba.org> + + * Makefile.in: New file stat.h + +2003-06-10 15:55 Martin Pool <mbp@samba.org> + + * src/: stat.c, stat.h: New file stat.h + + * Add routine to open a state file. + +2003-06-10 15:55 Martin Pool <mbp@samba.org> + + * .cvsignore: Ignore distccmon-gnome. + +2003-06-10 15:49 Martin Pool <mbp@samba.org> + + * src/stat.c: Doc + + * Add function to create/return state directory. + +2003-06-10 15:47 Martin Pool <mbp@samba.org> + + * src/tempfile.h: Split code for idempotent directory creation + out into a new function dcc_make_dir, so that it can be used by + state file code. + +2003-06-10 15:33 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Split code for idempotent directory creation + out into a new function dcc_make_dir, so that it can be used by + state file code. + +2003-06-10 15:23 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Add columns for file and host + + * Add more sample data + + * Refactor code to create table view. + +2003-06-10 15:14 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Set a more reasonable default size. + +2003-06-10 15:09 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Refactor into smaller functions + + * Remove horizontal scrollbar; vertical only as needed. + + * Remove dummy text entry + +2003-06-10 15:00 Martin Pool <mbp@samba.org> + + * NEWS: Start adding a GNOME-based monitor. + +2003-06-10 14:58 Martin Pool <mbp@samba.org> + + * Makefile.in: make clean: Remove distccmon-gnome, even if it's + currently not configured on. + +2003-06-10 14:57 Martin Pool <mbp@samba.org> + + * Makefile.in, configure.ac: Add --enable-gnome configure option. + When set, build and install distccmon-gnome. + +2003-06-09 23:09 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Add more sample data. + +2003-06-09 23:07 Martin Pool <mbp@samba.org> + + * Makefile.in: Add hardcoded rule for distccmon-gnome. + +2003-06-09 23:05 Martin Pool <mbp@samba.org> + + * doc/status-1.txt: Update status indicator notes. + +2003-06-09 23:03 Martin Pool <mbp@samba.org> + + * src/stat.c: Stub for status indicator. + +2003-06-09 19:23 Martin Pool <mbp@samba.org> + + * src/mon-gnome.c: Start of a monitor implementation in GTK+-2.2. + Displays a window with a list containing only "42". + +2003-06-09 18:37 Martin Pool <mbp@samba.org> + + * src/: mon-gnome.c, mon-gtk.c: Stub implementation of GNOME + monitor. + +2003-06-09 18:35 Martin Pool <mbp@samba.org> + + * src/: netutil.c, netutil.h: Add implementation of hstrerror() + for systems that don't have it. + +2003-06-09 18:28 Martin Pool <mbp@samba.org> + + * Makefile.in: src/stat.c: New file. + +2003-06-09 15:23 Martin Pool <mbp@samba.org> + + * src/mon-gtk.c: Add a stub GTK+ monitor interface -- compiles + and shows an empty window but does nothing. + +2003-06-09 14:26 Martin Pool <mbp@samba.org> + + * NEWS: Note that hstrerror() is now supplied. + +2003-06-09 12:47 Martin Pool <mbp@samba.org> + + * src/remote.c: Remove more unneeded headers. + +2003-06-09 12:43 Martin Pool <mbp@samba.org> + + * src/: distcc.c, compile.c: Remove more unneeded headers. + +2003-06-09 12:36 Martin Pool <mbp@samba.org> + + * src/distcc.c: Remove more unneeded headers. + +2003-06-09 12:33 Martin Pool <mbp@samba.org> + + * src/distcc.c: Remove unneeded headers. + +2003-06-08 20:05 Martin Pool <mbp@samba.org> + + * test/testdistcc.py, NEWS: Fix silly typo that made + maintainer-check fail in ParseHostSpec_Case. + +2003-06-08 19:52 Martin Pool <mbp@samba.org> + + * Makefile.in, src/compile.c, src/compile.h, src/distcc.c: Split + other client-side compile functionality into src/compile.c. + src/distcc.c now only has the top-level client code. + + * src/compile.c: New file. + +2003-06-08 19:43 Martin Pool <mbp@samba.org> + + * Makefile.in, src/compile.h, src/distcc.c, src/remote.c: Split + dcc_compile_remote into src/remote.c, and make it public. + + * compile.h, remote.c: New files. + +2003-06-08 19:36 Martin Pool <mbp@samba.org> + + * TODO: Multiple updates to TODO file. + +2003-06-08 19:19 Martin Pool <mbp@samba.org> + + * src/distcc.c, NEWS: Look for UNCACHED_ERR_FD environment + variable, to allow distcc networking errors to avoid being + cached by ccache. + +2003-06-06 13:07 Martin Pool <mbp@samba.org> + + * TODO: OpenMOSIX autodiscovery + +2003-06-05 17:44 Martin Pool <mbp@samba.org> + + * TODO: Rearrange comments on DNS A and SRV records. + + * Move question about --enable-final to web. + +2003-06-05 17:34 Martin Pool <mbp@samba.org> + + * TODO: 2.5 bug is fixed. + +2003-06-05 17:26 Martin Pool <mbp@samba.org> + + * Makefile.in: Include doc/protocol-1.txt in distribution. + +2003-06-05 17:21 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version back to 2.6cvs + +2003-06-05 17:03 Martin Pool <mbp@samba.org> + + * NEWS: Note connection timeout added in 2.5.1. + +2003-06-05 16:53 Martin Pool <mbp@samba.org> + + * NEWS, configure.ac: Prepare for 2.5.1 release. + +2003-06-05 16:48 Martin Pool <mbp@samba.org> + + * src/io.c, NEWS: sys/time.h might be needed for select on SuSE + 7.1 (spe158). + +2003-06-05 16:45 Martin Pool <mbp@samba.org> + + * src/hosts.c, NEWS: dcc_parse_multiplier must advance over the + multiplier to be able to read things like "angry/30:3000" + correctly. Patch from Wayne Davison. + +2003-06-05 16:43 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Get out these fixes in 2.5.1. + +2003-06-05 16:42 Martin Pool <mbp@samba.org> + + * test/testdistcc.py, NEWS: Add check for support of old + multiplier format. (angry/44:300) + +2003-06-05 16:41 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc + +2003-06-05 16:39 Martin Pool <mbp@samba.org> + + * configure.ac: Get out these fixes in 2.5.1. + +2003-06-05 16:36 Martin Pool <mbp@samba.org> + + * NEWS: Get out these fixes in 2.5.1. + +2003-06-05 16:17 Martin Pool <mbp@samba.org> + + * src/: clinet.c, netutil.c, netutil.h, srvnet.c: Rename + everything called 'sa_len' because this is #defined on IRIX. + (Yuk) + +2003-06-05 16:12 Martin Pool <mbp@samba.org> + + * NEWS: Fix IRIX. + +2003-06-05 16:09 Martin Pool <mbp@samba.org> + + * NEWS: Recode as UTF-8. + +2003-06-05 16:08 Martin Pool <mbp@samba.org> + + * NEWS: Solaris fixes from Tomas. + +2003-06-05 16:08 Martin Pool <mbp@samba.org> + + * src/daemon.h: dcc_master_pid is really a pid_t. + +2003-06-05 16:07 Martin Pool <mbp@samba.org> + + * src/netutil.c: Can't use "sun" as an identifier on gcc Solaris + 8. + +2003-06-05 16:03 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-06-04 23:19 Martin Pool <mbp@samba.org> + + * src/dparent.c: Doc. + +2003-06-04 11:22 Martin Pool <mbp@samba.org> + + * doc/status-1.txt: Notes on design possibilities. + +2003-06-03 08:37 Martin Pool <mbp@samba.org> + + * doc/noent.txt: Transient bug while compiling. + +2003-06-03 08:23 Martin Pool <mbp@samba.org> + + * doc/status-1.txt: Notes on status reporting + +2003-06-02 15:48 Martin Pool <mbp@samba.org> + + * src/netutil.c: This file needs snprintf.h + + * AF_LOCAL might be missing on Solaris. + +2003-06-02 15:45 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-06-02 14:46 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-06-02 13:20 Martin Pool <mbp@samba.org> + + * src/dparent.c: Clarify "%d CPUs online" message. + + http://groups.google.com/groups?q=distcc&hl=en&lr=&ie=UTF-8&oe=UTF-8&scoring=d&selm=1054494726.347698%40auth2.dns.griffin.net.uk&rnum=1 + +2003-06-02 13:13 Martin Pool <mbp@samba.org> + + * survey.txt: Clarify privacy clause for survey. + +2003-06-02 13:11 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-05-31 00:29 Martin Pool <mbp@samba.org> + + * doc/protocol-1.txt: Start handling empty output files. + +2003-05-31 00:29 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-05-30 23:49 Martin Pool <mbp@samba.org> + + * src/: bulk.c, distcc.h: dcc_open_read can be static. + +2003-05-30 23:47 Martin Pool <mbp@samba.org> + + * src/bulk.c: Remove dead code. + +2003-05-30 12:58 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add section about Mailing lists. + +2003-05-30 12:45 Martin Pool <mbp@samba.org> + + * src/dsignal.c: Doc. + +2003-05-29 09:00 Martin Pool <mbp@samba.org> + + * src/access.c: Doc + +2003-05-28 17:34 Martin Pool <mbp@samba.org> + + * src/: clinet.c, io.c: Increase timeout to 15s. + + * Move select() check into dcc_select_for_read + +2003-05-28 17:28 Martin Pool <mbp@samba.org> + + * src/clinet.c: dcc_connect_timed: Add trace. + +2003-05-28 17:16 Martin Pool <mbp@samba.org> + + * src/clinet.c: Doc + +2003-05-28 17:13 Martin Pool <mbp@samba.org> + + * TODO, doc/results.txt: [no log message] + +2003-05-28 17:01 Martin Pool <mbp@samba.org> + + * src/clinet.c: Impose 5s timeout on opening TCP connections. + Change to using nonblocking sockets (just while opening). + +2003-05-28 16:16 Martin Pool <mbp@samba.org> + + * Makefile.in: Move check functionality to maintainer-check, + because I don't want it to run by default on the build farm. + +2003-05-28 16:13 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-05-28 16:11 Martin Pool <mbp@samba.org> + + * src/distcc.c: Include hostdef string in "failed to distribute" + warning. + +2003-05-28 16:03 Martin Pool <mbp@samba.org> + + * src/: netutil.h, ssh.c, netutil.c: dcc_set_nonblocking, + dcc_set_blocking: Move to netutil.h + +2003-05-28 15:57 Martin Pool <mbp@samba.org> + + * TODO: The server in fact already generates the right extension + name for temporary files. But this might be a problem for the + proposed new protocol. + +2003-05-28 15:50 Martin Pool <mbp@samba.org> + + * src/serve.c: dcc_run_job: Split some code out into + dcc_input_tmpnam. + +2003-05-28 15:50 Martin Pool <mbp@samba.org> + + * doc/results.txt: [no log message] + +2003-05-28 15:46 Martin Pool <mbp@samba.org> + + * TODO: Preforking is now done. + +2003-05-28 15:45 Martin Pool <mbp@samba.org> + + * TODO: Thoughts on boredom and temporary file extensions. + +2003-05-28 15:29 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml, NEWS: Document use from inetd. + + * Document -j option. + +2003-05-28 15:08 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Notes on running daemon from init and + standalone. + +2003-05-28 14:51 Martin Pool <mbp@samba.org> + + * NEWS: dcc_setpgid: Rename to dcc_new_pgrp. + + * dcc_new_pgrp: Don't call setpgid() if we're already a process + group leader, because this fails with EPERM if we happen to + also be a session group leader. + +2003-05-28 14:42 Martin Pool <mbp@samba.org> + + * src/: dparent.c, exec.c, exec.h: dcc_setpgid: Rename to + dcc_new_pgrp. + + * dcc_new_pgrp: Don't call setpgid() if we're already a process + group leader, because this fails with EPERM if we happen to + also be a session group leader. + +2003-05-28 14:31 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version + +2003-05-28 14:13 Martin Pool <mbp@samba.org> + + * NEWS: Need types.h + +2003-05-28 14:03 Martin Pool <mbp@samba.org> + + * src/daemon.c: Need types.h + +2003-05-27 19:18 Martin Pool <mbp@samba.org> + + * src/serve.c: Tweak trace message. + +2003-05-27 19:17 Martin Pool <mbp@samba.org> + + * src/bulk.c: Disable dcc_x_file_timed, which is no longer + called. + +2003-05-27 19:12 Martin Pool <mbp@samba.org> + + * configure.ac, NEWS, doc/release-names.txt: Prepare for 2.5 + release. + +2003-05-27 19:11 Martin Pool <mbp@samba.org> + + * src/daemon.c: Doc. + + * If getpeername() fails on a socket then continue anyhow. + +2003-05-27 19:08 Martin Pool <mbp@samba.org> + + * TODO: SSH child is now collected by the client. + +2003-05-27 18:55 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-05-27 18:54 Martin Pool <mbp@samba.org> + + * src/distcc.c: Only collect SSH child if we actually started + one. (How embarrassing.) + +2003-05-27 18:48 Martin Pool <mbp@samba.org> + + * src/distcc.c: Log elapsed time for whole compilation. + +2003-05-27 18:42 Martin Pool <mbp@samba.org> + + * src/: serve.c, clirpc.c: Don't time transmission of a file: + because a large fraction of it can be stuck in network buffers + it is not a very accurate measure. + +2003-05-27 18:39 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-05-27 18:35 Martin Pool <mbp@samba.org> + + * TODO: Note on handling SIGCHLD from cpp. + +2003-05-27 18:17 Martin Pool <mbp@samba.org> + + * src/: distcc.c: Doc. + +2003-05-27 18:16 Martin Pool <mbp@samba.org> + + * src/: clirpc.c, distcc.c, exec.c, exec.h, serve.c: + dcc_report_rusage: Merge into dcc_collect_child because they're + coupled. + + * dcc_collect_child: Don't pass back rusage. Do take a + descriptive name for the child. + + * dcc_compile_remote: Collect the SSH child after the connection + is closed. + +2003-05-27 18:06 Martin Pool <mbp@samba.org> + + * src/distcc.c: Add pointer to manual in usage message. + +2003-05-27 17:54 Martin Pool <mbp@samba.org> + + * src/netutil.c: dcc_sockaddr_to_string: Remove "INET" from IP + address. + +2003-05-27 17:54 Martin Pool <mbp@samba.org> + + * src/clinet.c: dcc_connect_by_addr: Print sockaddr in raw form. + +2003-05-27 15:11 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: ParseMask_Case: Better error message. + +2003-05-27 14:58 Martin Pool <mbp@samba.org> + + * doc/results.txt: Notes on prefork mode. + +2003-05-27 14:43 Martin Pool <mbp@samba.org> + + * src/daemon.h: Fix decl. + +2003-05-27 14:42 Martin Pool <mbp@samba.org> + + * src/hosts.c: Fix C syntax. + +2003-05-27 14:41 Martin Pool <mbp@samba.org> + + * TODO: Update notes on fsh/ssh. + +2003-05-27 12:26 Martin Pool <mbp@samba.org> + + * src/serve.c: Tweak log messages. + +2003-05-27 11:44 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Recommend using log files. + +2003-05-27 11:41 Martin Pool <mbp@samba.org> + + * src/prefork.c: dcc_preforked_child can be static. + +2003-05-27 11:07 Martin Pool <mbp@samba.org> + + * src/exec.c: dcc_critique_status: Tweak log output. + +2003-05-27 11:05 Martin Pool <mbp@samba.org> + + * src/exec.c: dcc_critique_status: Better message for termination + by signal. + +2003-05-27 11:00 Martin Pool <mbp@samba.org> + + * src/lock.c: Show lock fd in trace messages. + +2003-05-27 10:59 Martin Pool <mbp@samba.org> + + * src/srvnet.c: dcc_sockaddr_to_ip now indicates which AF it is. + +2003-05-27 10:58 Martin Pool <mbp@samba.org> + + * src/netutil.c: Better description of AF_UNIX sockets. + +2003-05-27 10:54 Martin Pool <mbp@samba.org> + + * src/netutil.c: dcc_sockaddr_to_string: Handle AF_LOCAL and + unknown AF addresses. Return "INET 1.2.1.2:323" to distinguish + AFs. + +2003-05-27 10:49 Martin Pool <mbp@samba.org> + + * src/: netutil.c, netutil.h, srvnet.c: dcc_sockaddr_to_ip: + Rename to dcc_sockaddr_to_string. + +2003-05-27 10:46 Martin Pool <mbp@samba.org> + + * src/bulk.c: Doc + +2003-05-27 10:43 Martin Pool <mbp@samba.org> + + * src/bulk.c: Tweak trace message. + +2003-05-27 10:42 Martin Pool <mbp@samba.org> + + * src/sendfile.c: Doc. + +2003-05-27 10:28 Martin Pool <mbp@samba.org> + + * src/: distcc.c, where.c: Disable XMIT locks for the moment. + +2003-05-26 18:43 Martin Pool <mbp@samba.org> + + * doc/results.txt: More testing. + +2003-05-26 18:39 Martin Pool <mbp@samba.org> + + * doc/results.txt: More testing. + +2003-05-26 18:09 Martin Pool <mbp@samba.org> + + * NEWS: Client no longer considers NCPUs. + +2003-05-26 18:08 Martin Pool <mbp@samba.org> + + * src/bulk.c: Tweak trace message. + +2003-05-26 17:53 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-05-26 17:45 Martin Pool <mbp@samba.org> + + * src/hosts.c: Fix warning. + +2003-05-26 17:44 Martin Pool <mbp@samba.org> + + * src/hosts.c, Makefile.in: Don't look at the number of CPUs on + the client; it's too expensive. + +2003-05-26 17:39 Martin Pool <mbp@samba.org> + + * src/srvnet.c, src/dparent.c, NEWS: Log full passive sockaddr in + listen message. + +2003-05-26 17:36 Martin Pool <mbp@samba.org> + + * src/dparent.c: Shuffle startup messages. + +2003-05-26 17:34 Martin Pool <mbp@samba.org> + + * src/dsignal.c, NEWS: Make sure to remove handler before + re-raising signal, or Valgrind gets its kickers in a knot. + +2003-05-26 17:30 Martin Pool <mbp@samba.org> + + * src/serve.c: dcc_service_job: Split off code for checking + access control. + +2003-05-26 17:13 Martin Pool <mbp@samba.org> + + * src/: daemon.c, daemon.h, distcc.h, dparent.c, prefork.c, + serve.c, srvnet.c, srvnet.h: Use the sockaddr passed in by + accept() when a connection is accepted, rather than doing an + extra getpeername() call. + + * dcc_accept_job: Rename to dcc_service_job, since accept() is no + longer called from here. + +2003-05-26 17:00 Martin Pool <mbp@samba.org> + + * NEWS: dcc_listen_by_addr: Show sockaddr if bind fails. + +2003-05-26 16:58 Martin Pool <mbp@samba.org> + + * src/netutil.c: dcc_sockaddr_to_ip: sin_port is in network byte + order. + +2003-05-26 16:57 Martin Pool <mbp@samba.org> + + * src/srvnet.c: Fix silly typo. + +2003-05-26 16:56 Martin Pool <mbp@samba.org> + + * src/srvnet.c: dcc_listen_by_addr: Show sockaddr if bind fails. + +2003-05-26 16:53 Martin Pool <mbp@samba.org> + + * src/netutil.c: dcc_sockaddr_to_ip: Show port number as well as + IP address. + +2003-05-26 16:46 Martin Pool <mbp@samba.org> + + * src/srvnet.c: Split out "address family" part from "connection + from" message. + +2003-05-26 16:35 Martin Pool <mbp@samba.org> + + * src/daemon.c: Fix syntax problem and missing header. + +2003-05-26 16:34 Martin Pool <mbp@samba.org> + + * NEWS: Move daemon into temporary directory during startup. + +2003-05-26 16:33 Martin Pool <mbp@samba.org> + + * src/daemon.c: Doc. + +2003-05-26 16:32 Martin Pool <mbp@samba.org> + + * src/daemon.c: main: Refactor error handling. + + * Move daemon into temporary directory during startup. + +2003-05-26 16:29 Martin Pool <mbp@samba.org> + + * src/: tempfile.c, tempfile.h: dcc_enter_tempdir: New function. + +2003-05-26 16:27 Martin Pool <mbp@samba.org> + + * src/tempfile.c, NEWS: Just use decimal userid rather than + username in temporary directory. + +2003-05-26 16:22 Martin Pool <mbp@samba.org> + + * src/setuid.c: Undo 1.3 + +2003-05-26 16:21 Martin Pool <mbp@samba.org> + + * src/setuid.c: Move opt_user to somewhere it can be reached by + tmpfile. + +2003-05-26 16:19 Martin Pool <mbp@samba.org> + + * NEWS: Use username or decimal userid for temporary directory + name. + +2003-05-26 15:55 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2003-05-26 15:54 Martin Pool <mbp@samba.org> + + * src/serve.c: Fix naming of stdout, stderr temporary files. + + * Call server object file .o. + +2003-05-26 15:51 Martin Pool <mbp@samba.org> + + * src/serve.c: dcc_accept_job: Close down ecolog connection to + server error log, so that we don't leak fds in prefork mode. + +2003-05-26 15:48 Martin Pool <mbp@samba.org> + + * src/trace.c: rs_remove_logger: New function to allow turning + off loggers without shutting everything down. + +2003-05-26 15:42 Martin Pool <mbp@samba.org> + + * src/trace.h: rs_remove_logger: New function. + +2003-05-26 15:38 Martin Pool <mbp@samba.org> + + * src/prefork.c: Message when child exits. + +2003-05-26 15:13 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add tests for new host multiplicity + specifications. + +2003-05-26 15:12 Martin Pool <mbp@samba.org> + + * src/dsignal.c: Remove unneeded headers. + +2003-05-26 15:07 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: TCP hosts can now be specified in the + more logical form of HOST:PORT/MUL. + + * Explain when and where to list localhost. + +2003-05-26 15:02 Martin Pool <mbp@samba.org> + + * src/hosts.c, NEWS: TCP hosts can now be specified in the more + logical form of HOST:PORT/MUL. + +2003-05-26 14:58 Martin Pool <mbp@samba.org> + + * src/h_hosts.c: Log to stderr. + +2003-05-26 14:54 Martin Pool <mbp@samba.org> + + * src/hosts.c: dcc_parse_multiplier: Remove unnecessary string + copy. + +2003-05-26 14:51 Martin Pool <mbp@samba.org> + + * src/hosts.c: Doc. + +2003-05-26 14:48 Martin Pool <mbp@samba.org> + + * src/dsignal.c: dcc_parent_terminate: Rename to + dcc_daemon_terminate because it's now done in both parent and + children. + +2003-05-26 14:47 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Run tests in prefork mode. + +2003-05-26 14:46 Martin Pool <mbp@samba.org> + + * src/: daemon.h, dparent.c, dsignal.c, prefork.c, serve.c: Don't + change the signal handler when starting a child, because this + is racy and not straightforward. Instead, keep track of the pid + of the master daemon, and in the signal handler check if that's + who we are when running cleanup. + +2003-05-26 14:34 Martin Pool <mbp@samba.org> + + * NEWS: Call server-side output object files .o, not .out. Patch + from rishikesh shetty. + +2003-05-26 14:28 Martin Pool <mbp@samba.org> + + * src/prefork.c: Doc. + +2003-05-26 14:24 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Assume localhost has one CPU when checking + host parsing. + +2003-05-26 14:20 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Wait status for a terminated daemon is now + TERM, not 0. + + * Use --no-prefork for the moment to check nothing was broken. + +2003-05-26 14:13 Martin Pool <mbp@samba.org> + + * src/dparent.c: Don't catch signals until we've established our + own process group, because we don't want to accidentally kill + the caller's process group. + + * More trace messages. + +2003-05-26 14:12 Martin Pool <mbp@samba.org> + + * src/: exec.h, exec.c: dcc_setpgid: Return an error if we fail + to create a process group, because we rely on being separated + for proper shutdown. + +2003-05-26 13:55 Martin Pool <mbp@samba.org> + + * src/exec.c: dcc_setpgid: Return an error if we fail to create a + process group, because we rely on being separated for proper + shutdown. + +2003-05-26 13:34 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Fix warning + +2003-05-26 13:14 Martin Pool <mbp@samba.org> + + * src/tempfile.c: tmpfile list must be volatile. + +2003-05-26 13:10 Martin Pool <mbp@samba.org> + + * src/dparent.c: dcc_standalone_server: Even in --no-detach mode, + create a new process group. + +2003-05-26 13:09 Martin Pool <mbp@samba.org> + + * src/prefork.c: dcc_preforking_parent: We don't need to create a + new process group because it has already been done at a higher + level. + +2003-05-26 13:08 Martin Pool <mbp@samba.org> + + * src/exec.c: Doc. + +2003-05-26 12:15 Martin Pool <mbp@samba.org> + + * Makefile.in: h_hosts now needs ncpus.c + +2003-05-26 12:08 Martin Pool <mbp@samba.org> + + * NEWS: Note prefork support. + +2003-05-26 12:06 Martin Pool <mbp@samba.org> + + * src/: srvrpc.c, serve.c: Split server-specific RPC code into + its own file. + +2003-05-26 12:05 Martin Pool <mbp@samba.org> + + * Makefile.in, src/rpc.h: src/srvrpc.c: New file. + +2003-05-26 12:00 Martin Pool <mbp@samba.org> + + * src/daemon.c: Doc. + +2003-05-26 11:53 Martin Pool <mbp@samba.org> + + * NEWS: Kill process group on termination signal. + +2003-05-26 11:50 Martin Pool <mbp@samba.org> + + * src/: prefork.c, dparent.c: "up to n children" is only a debug + message. + +2003-05-26 11:49 Martin Pool <mbp@samba.org> + + * src/dparent.c: Split out code for logging terminated children. + + * Show signal names if appropriate when a child exits. + + * If a child is terminated, this is just an info log not an + error. + +2003-05-26 11:49 Martin Pool <mbp@samba.org> + + * src/daemon.c: Doc + +2003-05-26 11:44 Martin Pool <mbp@samba.org> + + * src/dsignal.c: dcc_child_terminate: No log message when the + child is terminated, the parent can do it. + +2003-05-26 11:40 Martin Pool <mbp@samba.org> + + * src/dsignal.c: Termination signal handlers re-raise the signal + and therefore should not _exit, because the signal is blocked + until we try to return. + +2003-05-26 08:38 Martin Pool <mbp@samba.org> + + * src/: daemon.h, dparent.c, dsignal.c, prefork.c: Use a separate + signal handler for daemon children, that cleans up temporary + files but doesn't kill the group. + +2003-05-25 21:10 Martin Pool <mbp@samba.org> + + * src/: daemon.h, dparent.c, dsignal.c, prefork.c, serve.c, util.c: + Rework some daemon signal handling designs to better suit a + preforking server. + + * Daemon now runs in a single process group in all modes. + + * Use signal() rather than sigaction() for simplicity. + + * Killing the daemon kills all running children. This is more + consistent with other daemons like Apache. Any clients ought + to + fall back to local compilation, as they will have to do + anyhow. + Daemon is killed by reraising the signal, rather than exiting. + + * Print a message when terminated by a signal that fits better + with + the strsignal() output. + + * When terminated, explicitly run cleanups rather than relying + on + exit(). + + * Accepted children are not run in a separate group, because + this + will not work for preforked jobs. + +2003-05-25 17:39 Martin Pool <mbp@samba.org> + + * src/prefork.c: Doc + + * dcc_preforking_parent: Should wait until a child exits before + bothering about starting a new one. + +2003-05-25 17:32 Martin Pool <mbp@samba.org> + + * src/prefork.c: Doc + +2003-05-25 17:29 Martin Pool <mbp@samba.org> + + * src/: daemon.h, dparent.c, prefork.c: dcc_reap_kids: Flags + ought to allow distinguishing between needing to reap at least + one child, and just checking for any of them. We don't want to + wait until all the children exited. + + This fixes the problem of the preforked parent waiting until + all the + children have exited before starting any more. + +2003-05-25 16:34 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Note that DISTCC_LOG doesn't change the + server. + + * Add section on how to shut down distccd. + +2003-05-25 16:23 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Bump version to 2.5. + + * Add descriptions of some new error codes. + +2003-05-23 19:19 Martin Pool <mbp@samba.org> + + * src/dparent.c: Doc + +2003-05-23 19:15 Martin Pool <mbp@samba.org> + + * src/daemon.c, NEWS: Make sure that the right syslog facility is + opened. + +2003-05-23 19:04 Martin Pool <mbp@samba.org> + + * src/: .cvsignore, daemon.c, daemon.h, distcc.h, dparent.c, + dsignal.c, prefork.c: Split prefork stuff into prefork.c. + + * Split daemon stuff into daemon.h. + +2003-05-23 19:03 Martin Pool <mbp@samba.org> + + * Makefile.in: No more recursive Make. + +2003-05-23 18:33 Martin Pool <mbp@samba.org> + + * src/: distcc.h, dopt.c, dopt.h, dparent.c: New option + --no-prefork + + * Add simple implementation of preforking: just create max_jobs + children and let them all accept connections. They time out + after a few requests. + +2003-05-23 15:50 Martin Pool <mbp@samba.org> + + * NEWS, src/dopt.c, src/dopt.h, src/dparent.c: Add new --jobs, -j + option to server to set limit on incoming jobs. + +2003-05-23 15:48 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version to 2.5cvs + +2003-05-23 15:48 Martin Pool <mbp@samba.org> + + * README.libiberty: Remove libiberty stuff + +2003-05-23 14:54 Martin Pool <mbp@samba.org> + + * src/dparent.c: Remove quote. + +2003-05-23 14:51 Martin Pool <mbp@samba.org> + + * src/dparent.c: dcc_reap_kids: Add option to block until a child + exits. + + * dcc_forking_parent: Block waiting for a child to complete + before accepting any new connections when we've exceeded the + maximum number of connections. + +2003-05-23 14:30 Martin Pool <mbp@samba.org> + + * src/dparent.c: Rename /_loop/_parent/ + +2003-05-23 14:29 Martin Pool <mbp@samba.org> + + * src/dparent.c: max_kids: New variable to impose a limit on + concurrent servers. + +2003-05-23 14:21 Martin Pool <mbp@samba.org> + + * src/dparent.c: Fix prototype + +2003-05-23 14:20 Martin Pool <mbp@samba.org> + + * src/dparent.c: Refactor daemon parent loop into separate + versions for nofork and forking mode, so that we don't need + checks for mode at more than one place. + +2003-05-23 14:05 Martin Pool <mbp@samba.org> + + * src/hosts.c: Doc + +2003-05-23 14:04 Martin Pool <mbp@samba.org> + + * src/hosts.c: Set default local task limit to twice the number + of CPUs. + +2003-05-23 13:38 Martin Pool <mbp@samba.org> + + * TODO: Remove done items. + +2003-05-23 13:02 Martin Pool <mbp@samba.org> + + * NEWS, configure.ac: Prepare for 2.4.2 release + +2003-05-23 12:58 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2003-05-23 12:47 Martin Pool <mbp@samba.org> + + * src/netutil.c, NEWS: Fix string allocation bug in + dcc_sockaddr_to_ip that could cause a server crash. + +2003-05-23 12:17 Martin Pool <mbp@samba.org> + + * NEWS, src/distcc.h, src/hostfile.c, src/hosts.c: Better error + messages if DISTCC_HOSTS or host files are empty. Patch from + Wayne Davison. + +2003-05-22 19:06 Martin Pool <mbp@samba.org> + + * doc/results.txt: [no log message] + +2003-05-22 19:05 Martin Pool <mbp@samba.org> + + * TODO: More notes on feeding from a FIFO. + +2003-05-22 17:39 Martin Pool <mbp@samba.org> + + * src/sendfile.c: Doc. + +2003-05-22 16:40 Martin Pool <mbp@samba.org> + + * Makefile.in: libiberty is no longer used by distcc. + +2003-05-22 16:24 Martin Pool <mbp@samba.org> + + * src/bulk.c, NEWS: Open output files in the same way that GNU as + does, by only trying to remove them if they're >0 bytes, and + ignoring failure to remove. + + This fixes compilation directed to /dev/null, which is used by + some + configure scripts. + + Reported by Hal Duston. + +2003-05-22 16:12 Martin Pool <mbp@samba.org> + + * cases/fooey.c: Another developer scratch test. + +2003-05-22 16:09 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Fix /dev/null test. + +2003-05-22 15:51 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add test case for "-o /dev/null", reported + by Hal Duston. Currently fails. + +2003-05-22 15:48 Martin Pool <mbp@samba.org> + + * configure.ac: Update to 2.5cvs + +2003-05-22 15:24 Martin Pool <mbp@samba.org> + + * configure.ac: Update to 2.4.1 + +2003-05-22 15:21 Martin Pool <mbp@samba.org> + + * NEWS: Patch from Frerich Raabe: + + * Add strndup on platforms that don't have it. + +2003-05-22 11:25 Martin Pool <mbp@samba.org> + + * src/hosts.c, NEWS: Patch from Frerich Raabe: + + * Add strndup on platforms that don't have it. + +2003-05-22 11:13 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version to 2.4.1cvs + + * Check for function and declaration of strndup. + +2003-05-22 10:03 Martin Pool <mbp@samba.org> + + * man/: distcc.1, distccd.1: Add email addresses. + +2003-05-21 16:57 Martin Pool <mbp@samba.org> + + * TODO: Note on waking up bored clients. + +2003-05-21 16:47 Martin Pool <mbp@samba.org> + + * configure.ac, NEWS: Get ready for 2.4 release + +2003-05-21 16:45 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: NoHosts_Case needs to reset + DISTCC_FALLBACK=1 to test the desired behaviour. + +2003-05-21 16:41 Martin Pool <mbp@samba.org> + + * src/: clirpc.c, distcc.c, exec.c, exec.h, serve.c: + dcc_critique_status: Add butt-ugly verbose parameter, so that + diagnostics on command completion are only given high status in + cases where the user is likely to want to see them. + +2003-05-21 16:39 Martin Pool <mbp@samba.org> + + * doc/results.txt: Notes on backoff. + +2003-05-21 16:30 Martin Pool <mbp@samba.org> + + * src/timefile.c: dcc_remove_timefile: Better messages. + +2003-05-21 16:26 Martin Pool <mbp@samba.org> + + * src/h_hosts.c: Renamed to dcc_get_hostlist + +2003-05-21 16:25 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-05-21 16:24 Martin Pool <mbp@samba.org> + + * src/clinet.c: Doc. + +2003-05-21 16:16 Martin Pool <mbp@samba.org> + + * src/distcc.c: dcc_build_somewhere: Allow for the fallback code + to be invoked because of failure to choose a host, e.g. because + they're all down or none were defined. + +2003-05-21 16:10 Martin Pool <mbp@samba.org> + + * src/where.c: dcc_pick_host_from_list: Return EXIT_NO_HOSTS on + failure, not 0. This makes sure that all failures are caught + in common code and that DISTCC_FALLBACK is always applied. + +2003-05-21 16:09 Martin Pool <mbp@samba.org> + + * src/exitcode.h: New code EXIT_NO_HOSTS + +2003-05-21 16:07 Martin Pool <mbp@samba.org> + + * src/: where.h, where.c, distcc.c: dcc_pick_host_from_env: + rename to dcc_pick_host_from_list, since hosts can now come + from files too. + +2003-05-21 16:04 Martin Pool <mbp@samba.org> + + * src/where.c: If removing disliked hosts leaves us with nothing, + then use localhost instead. + +2003-05-21 15:55 Martin Pool <mbp@samba.org> + + * src/backoff.c: Doc + +2003-05-21 15:55 Martin Pool <mbp@samba.org> + + * doc/results.txt: [no log message] + +2003-05-21 15:54 Martin Pool <mbp@samba.org> + + * src/: backoff.c, backoff.h, hosts.c, where.c: Backoff from + disliked hosts for 60 seconds. + +2003-05-21 15:53 Martin Pool <mbp@samba.org> + + * NEWS: Note sleep changes and backoff. + +2003-05-21 15:38 Martin Pool <mbp@samba.org> + + * src/: hosts.h, hosts.c: dcc_free_hostdef: New function. + +2003-05-21 15:25 Martin Pool <mbp@samba.org> + + * src/: hosts.h, hosts.c, where.c: Rename dcc_preferred_hosts to + dcc_get_hostlist. + +2003-05-21 15:23 Martin Pool <mbp@samba.org> + + * src/where.c: Sleep for just 2s if a host is not free. + +2003-05-21 14:09 Martin Pool <mbp@samba.org> + + * src/where.c, NEWS: dcc_lock_pause: Replace simple 0.1s sleep + with a truncated exponential backoff starting at 1s and going + up to 8s. 0.1s is very short compared to the period a compile + typically takes to complete, and if we hit this code at all + then we're probably overloaded. + +2003-05-21 14:01 Martin Pool <mbp@samba.org> + + * src/lock.c: Doc. + +2003-05-21 14:00 Martin Pool <mbp@samba.org> + + * src/timefile.c: dcc_mark_timefile: Fix error check + +2003-05-21 13:57 Martin Pool <mbp@samba.org> + + * src/: backoff.c, distcc.c: backoff.c, backoff.h: New files. + +2003-05-21 13:56 Martin Pool <mbp@samba.org> + + * src/distcc.c: dcc_build_somewhere: Remember when a server + failed or not. + +2003-05-21 13:55 Martin Pool <mbp@samba.org> + + * src/: backoff.h, backoff.c: dcc_enjoyed_host, + dcc_disliked_host: New function that remember when a server + failed. + +2003-05-21 13:51 Martin Pool <mbp@samba.org> + + * Makefile.in: backoff.c, backoff.h: New files. + +2003-05-21 13:44 Martin Pool <mbp@samba.org> + + * src/timefile.c: dcc_remove_timefile, dcc_check_timefile: Cope + with timestamp files that don't exist. + +2003-05-21 13:35 Martin Pool <mbp@samba.org> + + * src/timefile.c: dcc_mark_timefile, dcc_remove_timefile: add + trace messages. + +2003-05-21 13:34 Martin Pool <mbp@samba.org> + + * src/: timefile.c, timefile.h: dcc_remove_timefile, + dcc_check_timefile: New functions. + +2003-05-21 13:30 Martin Pool <mbp@samba.org> + + * src/timefile.h, Makefile.in, src/lock.h: timefile.h: New header + for timefile.c + +2003-05-21 13:22 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-05-21 13:21 Martin Pool <mbp@samba.org> + + * Makefile.in, src/lock.c, src/lock.h, src/timefile.c: + timefile.c: New file. + + * Export some functions from lock.c needed to do timestamps. + + * dcc_mark_timefile: Very simple implementation of time markers. + +2003-05-21 13:19 Martin Pool <mbp@samba.org> + + * src/climasq.c: Doc + +2003-05-21 13:14 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc. + +2003-05-21 11:49 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-05-20 22:35 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-05-20 12:00 Martin Pool <mbp@samba.org> + + * survey.txt: Add request to send misconfigurations to the list + rather than to the survey. + +2003-05-19 18:21 Martin Pool <mbp@samba.org> + + * TODO: Describe use of SSH. + + * Notes about localhost scheduling. + +2003-05-19 18:17 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Bump version. + +2003-05-19 18:16 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml, NEWS: Describe use of SSH. + +2003-05-19 18:02 Martin Pool <mbp@samba.org> + + * doc/results.txt: Results from SSH. + +2003-05-19 17:50 Martin Pool <mbp@samba.org> + + * src/lock.c: dcc_lock_host: Use hostdef_string, not hostname. + +2003-05-19 17:47 Martin Pool <mbp@samba.org> + + * TODO, src/hosts.c: Move notes about multi-A-records to TODO, + since it probably won't happen. + +2003-05-19 17:43 Martin Pool <mbp@samba.org> + + * NEWS: dcc_critique_status now takes a hostdef, not a hostname, + so that it can give better error messages. Update all callers. + +2003-05-19 17:41 Martin Pool <mbp@samba.org> + + * src/exec.c: dcc_critique_status: Don't print function name in + errors. + +2003-05-19 17:39 Martin Pool <mbp@samba.org> + + * src/: clirpc.c, distcc.c, exec.c, exec.h, hosts.c, serve.c: + dcc_critique_status now takes a hostdef, not a hostname, so that + it can give better error messages. Update all callers. + +2003-05-19 17:29 Martin Pool <mbp@samba.org> + + * src/: distcc.c, exec.c, exec.h, lock.c: Move towards passing + around hostdefs, rather than hostnames, because they provide + better explanations now that we have multiple protocols and + different ports. + + At the moment done just for dcc_note_execution. + +2003-05-19 17:20 Martin Pool <mbp@samba.org> + + * src/hosts.h: Add verbatim name to hostdef struct. + +2003-05-19 17:18 Martin Pool <mbp@samba.org> + + * NEWS: If remote compilation fails, give an error rather than + just a notice. People might want to know. + +2003-05-19 17:16 Martin Pool <mbp@samba.org> + + * cases/bad.c: Test case for errors. + +2003-05-19 17:15 Martin Pool <mbp@samba.org> + + * src/exec.c: If remote compilation fails, give an error rather + than just a notice. People might want to know. + +2003-05-19 17:10 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc. + +2003-05-19 16:58 Martin Pool <mbp@samba.org> + + * src/: filename.c: Doc. + +2003-05-19 16:43 Martin Pool <mbp@samba.org> + + * NEWS, src/clinet.c, src/netutil.c, src/srvnet.c: Don't use the + RFC2553 getaddrinfo/getnameinfo API by default, because it + seems to be slower on OS X and possibly problematic on other + systems. It can be enabled with --enable-rfc2553 if you want + to use IPv6, multi-homed servers, or want to test the new API. + +2003-05-19 16:08 Martin Pool <mbp@samba.org> + + * doc/results.txt: Notes on getaddrinfo vs gethostinfo. + +2003-05-19 16:08 Martin Pool <mbp@samba.org> + + * configure.ac: Add --enable-rfc2553 configuration option. + +2003-05-19 16:08 Martin Pool <mbp@samba.org> + + * TODO: Notes on name handling and statistics. + +2003-05-19 16:07 Martin Pool <mbp@samba.org> + + * NEWS: Patch from Paul Green to start supporting VOS: + + * Use autoconf EXEEXT in Makefile. Remove sbin_programs. + + * Add VOS implementation of dcc_ncpus. + + * Once socklen_t, in_addr_t and in_port_t have been typedef'd, + set the feature macros for them. + + * src/util.c needs netdb.h + +2003-05-19 13:08 Martin Pool <mbp@samba.org> + + * src/hosts.c, TODO: Merge comment from Alexandre about keeping + the HOSTS syntax such that it can be handled from the shell. + +2003-05-19 12:25 Martin Pool <mbp@samba.org> + + * Makefile.in, src/ncpus.c, src/types.h, src/util.c: Patch from + Paul Green to start supporting VOS: + + * Use autoconf EXEEXT in Makefile. Remove sbin_programs. + + * Add VOS implementation of dcc_ncpus. + + * Once socklen_t, in_addr_t and in_port_t have been typedef'd, + set the feature macros for them. + + * src/util.c needs netdb.h + +2003-05-16 17:52 Martin Pool <mbp@samba.org> + + * src/where.c, NEWS: If an IO error occurs while trying to get a + lock, bail out rather than getting stuck. + +2003-05-16 17:47 Martin Pool <mbp@samba.org> + + * src/filename.c: Doc. + +2003-05-16 17:43 Martin Pool <mbp@samba.org> + + * src/cpp.c: dcc_cpp_maybe: Doc, add trace. + +2003-05-16 17:40 Martin Pool <mbp@samba.org> + + * src/cpp.c: dcc_cpp_maybe: Pull out all the + preprocessor-extension logic and just call dcc_preproc_exten, + which already knows all about C++ and ObjC and ObjC++. + +2003-05-16 17:37 Martin Pool <mbp@samba.org> + + * src/cpp.c: Logic cleanup on Dara's patch. + + * For C++ source files, call the preprocessor output .ii. + +2003-05-16 17:24 Martin Pool <mbp@samba.org> + + * Makefile.in: Fix upload-dist. + +2003-05-16 17:23 Martin Pool <mbp@samba.org> + + * src/cpp.c, src/filename.c, NEWS: Merge cleaned-up patch from + Dara Hazeghi to recognize ObjC extensions. Still not clear. + +2003-05-16 17:18 Martin Pool <mbp@samba.org> + + * doc/results.txt: Update from experiments today on kernel. + +2003-05-16 17:16 Martin Pool <mbp@samba.org> + + * NEWS: Bump to 2.4cvs. + + * Merge patch to recognize Objective C files, by Dara Hazeghi. + +2003-05-16 17:14 Martin Pool <mbp@samba.org> + + * configure.ac: Bump to 2.4cvs. + +2003-05-16 17:10 Martin Pool <mbp@samba.org> + + * cases/hello-objc.m: Add compile-command. + +2003-05-16 17:09 Martin Pool <mbp@samba.org> + + * cases/hello-objc.m: Example case for Objective C, from Dara + Hazeghi. + +2003-05-16 15:15 Martin Pool <mbp@samba.org> + + * src/distcc.c: Fix typo in usage message. + +2003-05-16 15:07 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-05-16 14:46 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Prepare for 2.3 release. + +2003-05-16 14:09 Martin Pool <mbp@samba.org> + + * NEWS: Prepare for 2.3 release. + +2003-05-16 13:43 Martin Pool <mbp@samba.org> + + * configure.ac: Prepare for 2.3 release. + +2003-05-15 15:14 Martin Pool <mbp@samba.org> + + * src/util.c: Update trace message. + +2003-05-14 10:47 Martin Pool <mbp@samba.org> + + * src/util.c: dcc_trim_path: More trace information. + +2003-05-13 15:47 Martin Pool <mbp@samba.org> + + * src/srvnet.c: HAVE_GETADDRINFO version of dcc_socket_listen: + check that the port is in range, because getaddrinfo doesn't + trap it. + +2003-05-13 15:37 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.c, util.c, util.h: Patch from Wayne + Davison: + + * When trimming our path, look for the name we were invoked under + rather than "cc". + +2003-05-13 15:26 Martin Pool <mbp@samba.org> + + * NEWS: Doc updates. + +2003-05-13 11:46 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-05-11 12:31 Martin Pool <mbp@samba.org> + + * src/daemon.c, NEWS: dcc_setup_startup_log: Send startup errors + to stderr, unless that is a socket. Perhaps a better heuristic + for working out when we can stand to have e.g. bad option + warnings go there. + +2003-05-11 12:21 Martin Pool <mbp@samba.org> + + * src/daemon.c: dcc_set_lifetime: Remove "set alarm for" message, + which tends to leak into syslog when testing. + +2003-05-11 12:18 Martin Pool <mbp@samba.org> + + * NEWS: Update status of IPv6. + +2003-05-11 12:17 Martin Pool <mbp@samba.org> + + * src/srvnet.c: Coallesce log entries. + + * Doc. + +2003-05-11 12:04 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-05-09 14:05 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Remove chapter on "internals", because + this is covered in the protocol documentation file, etc. + +2003-05-08 18:02 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Document DISTCC_SSH, host list files, and + execution over SSH. + +2003-05-08 17:17 Martin Pool <mbp@samba.org> + + * NEWS: Updates to manual. + +2003-05-08 17:13 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Better description of how --help and + --version work with the client. + + * Document DISTCC_FALLBACK. + +2003-05-08 17:05 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Rename "Invoking" section to "Setting + up", because this is what it's really about now. + + * Add SGML markup. + + * Rephrase some sections about masquerading. + +2003-05-08 17:01 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Update section about security to describe + ssh and new options. + +2003-05-08 16:52 Martin Pool <mbp@samba.org> + + * src/srvnet.c: Restore access control checking for IPv4 + connections. + +2003-05-08 16:51 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: AccessDenied_Case depends on falling back + to local compilation. + +2003-05-08 16:44 Martin Pool <mbp@samba.org> + + * src/h_hosts.c: dcc_parse_hosts_env renamed to + dcc_preferred_hosts. + +2003-05-08 16:43 Martin Pool <mbp@samba.org> + + * src/clinet.c: non-GETADDRINFO version of dcc_connect_by_name: + Pass the right socklen. + +2003-05-08 16:42 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Set DISTCC_FALLBACK=0 for most compilations + so that we can be more sure that distribution failures will be + visible. + +2003-05-08 15:47 Martin Pool <mbp@samba.org> + + * src/clinet.c: Remove unused vars. + +2003-05-07 17:27 Martin Pool <mbp@samba.org> + + * src/srvnet.c: dcc_socket_listen, dcc_prefer_ipv4: Try to listen + on an IPv4 address if there is an acceptable one, because + that's the least disruptive change from the previous code and + it avoids ugly "::127.0.0.1" strings. + +2003-05-07 17:02 Martin Pool <mbp@samba.org> + + * src/srvnet.c: dcc_check_client: Update to be AF-indepedent. + Does not do checks yet. + +2003-05-07 16:58 Martin Pool <mbp@samba.org> + + * src/: netutil.c, netutil.h: dcc_sockaddr_to_hostname renamed to + dcc_sockaddr_to_ip, which is more accurate. Add a + non-getnameinfo() implementation. + +2003-05-07 16:48 Martin Pool <mbp@samba.org> + + * Makefile.in, src/netutil.c, src/netutil.h: netutil.c, + netutil.h: New files. + + * dcc_sockaddr_to_hostname: New function that hides inet_ntoa vs + getnameinfo. + +2003-05-07 16:38 Martin Pool <mbp@samba.org> + + * configure.ac: Check for sockaddr_storage.ss_family, since + ss_len doesn't seem to exist in glibc. If we have it, define + HAVE_SOCKADDR_STORAGE. + +2003-05-07 16:24 Martin Pool <mbp@samba.org> + + * configure.ac: Check for inet_ntop and inet_ntoa + +2003-05-07 16:18 Martin Pool <mbp@samba.org> + + * src/srvnet.c, NEWS: dcc_socket_listen: Dual implementations for + getaddrinfo and old API. + + The new implementation specifies AI_PASSIVE if no --listen + address + is given, so it should be able to accept connections on all + ports or + protocols. + +2003-05-07 16:06 Martin Pool <mbp@samba.org> + + * src/srvnet.c: dcc_listen_by_addr, dcc_socket_listen: Factor out + the code that creates and listens on a socket from the code + that works out the address to use, so that we can use + getaddrinfo when available. + + Also, remove assumptions about socket addresses always being + IPv4. + +2003-05-07 16:04 Martin Pool <mbp@samba.org> + + * src/clinet.c: Doc. + +2003-05-07 15:57 Martin Pool <mbp@samba.org> + + * doc/dietlibc-distcc.trace: strace using dietlibc, just for + interest. + +2003-05-07 15:56 Martin Pool <mbp@samba.org> + + * NEWS, src/clinet.c, src/clinet.h, src/distcc.c: Use + getaddrinfo() if it's available for opening connections, to + better handle multihomed servers and start supporting IPv6. + +2003-05-07 15:26 Martin Pool <mbp@samba.org> + + * src/clinet.c: dcc_open_socket_out: Add a second definition of + this function to be used on machines with getaddrinfo. + +2003-05-07 15:25 Martin Pool <mbp@samba.org> + + * configure.ac: Check for getaddrinfo, getnameinfo, and struct + sockaddr_storage. + +2003-05-07 15:20 Martin Pool <mbp@samba.org> + + * src/clinet.c: dcc_open_socket_out: Check client name before + creating a socket. (Not a big deal for now, but will be needed + for AF-independence.) + +2003-05-07 12:23 Martin Pool <mbp@samba.org> + + * NEWS: hostlist.c fix + + * snprintf.c fixes. + +2003-05-07 12:21 Martin Pool <mbp@samba.org> + + * configure.ac: Add check from Samba for va_copy, which is needed + for building our snprintf. + +2003-05-07 12:21 Martin Pool <mbp@samba.org> + + * cases/.cvsignore: Ignore built programs. + +2003-05-07 12:20 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-05-07 12:07 Martin Pool <mbp@samba.org> + + * src/snprintf.c: Update ifdefs to make sure that this file + compiles to an (almost) empty object file on systems that already + have all the functions we need. + +2003-05-07 11:53 Martin Pool <mbp@samba.org> + + * src/hosts.c: dcc_parse_hosts_env: Remove obsolete function. + +2003-05-07 11:52 Martin Pool <mbp@samba.org> + + * src/hosts.c: Trace messages when reading in host lists. + +2003-05-07 11:50 Martin Pool <mbp@samba.org> + + * src/hostfile.c: Remove unnecessary recursion protection. + + * Trace message when reading a file. + +2003-05-07 11:49 Martin Pool <mbp@samba.org> + + * src/loadfile.c: Fix silly pointer error when loading a host + file. + +2003-05-07 11:15 Martin Pool <mbp@samba.org> + + * src/snprintf.h: Fix all HAVE_DECL_ uses: these are defined to + zero rather than left undefined by autoconf if the decl is + missing. + +2003-05-07 11:14 Martin Pool <mbp@samba.org> + + * src/snprintf.c: Merge from samba HEAD: + + * Fix floating point handling. + + * Make snprintf test work better. + + * If the system's vsnprintf is not C99 compliant, then we need to + override both vsnprintf and snprintf to make sure the correct + code is always called. + + Also: + + * Make sure LDOUBLE, VA_COPY, etc are defined even if the system + already has some snprintf routines. + + * Always include snprintf.h, so that we get declarations for the + functions in this file. + +2003-05-07 10:27 Martin Pool <mbp@samba.org> + + * README.packaging: Note about using ./configure options to set + directories, and DESTDIR. + +2003-05-07 10:23 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: "for 2.2" + +2003-05-07 10:23 Martin Pool <mbp@samba.org> + + * NEWS, linuxdoc/distcc.sgml: Document --listen, plus other + cleanups. Patch from Frerich Raabe. + +2003-05-07 10:13 Martin Pool <mbp@samba.org> + + * cases/lzotest.c: Hacky test to examine efficiency of minilzo. + +2003-05-06 18:21 Martin Pool <mbp@samba.org> + + * TODO: Merge some stuff. + +2003-05-06 18:18 Martin Pool <mbp@samba.org> + + * doc/scheduling.txt: Merge into TODO + +2003-05-06 18:16 Martin Pool <mbp@samba.org> + + * doc/new-scheduler.txt: Merged into doc/results.txt + +2003-05-06 18:16 Martin Pool <mbp@samba.org> + + * doc/results.txt: Move "new-scheduler.txt" results (from + February) into the results.txt file. + +2003-05-06 17:36 Martin Pool <mbp@samba.org> + + * doc/protocol-3.txt: Only a draft + +2003-05-06 17:34 Martin Pool <mbp@samba.org> + + * doc/protocol-3.txt: Rephrase. + + * Don't compress 0-length data. + + * Insert COMP packets. + + * Questions about how to describe temporaries. + +2003-05-06 17:11 Martin Pool <mbp@samba.org> + + * doc/protocol-3.txt: Describe input and output files. + + * Start updating request and response descriptions. + +2003-05-06 16:54 Martin Pool <mbp@samba.org> + + * doc/protocol-3.txt: Describe handshaking on reused connections. + + * Describe compression. + +2003-05-06 16:02 Martin Pool <mbp@samba.org> + + * doc/protocol-3.txt: More updates towards version 3 protocol. + +2003-05-06 14:55 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-05-06 13:12 Martin Pool <mbp@samba.org> + + * src/dparent.c, src/ncpus.c, NEWS: Two Mac OS X fixes from + Benjamin Reed: Use the BSD method to discover the number of + CPUs, and include types.h where it is needed. + +2003-05-05 22:42 Martin Pool <mbp@samba.org> + + * src/trace.h: Doc + +2003-05-05 22:31 Martin Pool <mbp@samba.org> + + * src/HACKING: Just about everything in this file has been + implemented! The ideas which are not done yet are now in TODO. + + We're almost a year old now. + +2003-05-05 22:29 Martin Pool <mbp@samba.org> + + * src/rpc.c: Fix printf formatting error. + +2003-05-05 18:46 Martin Pool <mbp@samba.org> + + * src/trace.h: Doc + +2003-05-05 18:40 Martin Pool <mbp@samba.org> + + * src/distcc.h: Doc + +2003-05-05 18:07 Martin Pool <mbp@samba.org> + + * TODO: Remove page marks + +2003-05-05 18:01 Martin Pool <mbp@samba.org> + + * TODO: Notes on feeding from fifo. + +2003-05-05 17:56 Martin Pool <mbp@samba.org> + + * TODO: Notes on streaming output + +2003-05-05 17:49 Martin Pool <mbp@samba.org> + + * doc/protocol-3.txt: Start writing notes about a version 3 + protocol. + +2003-05-05 17:44 Martin Pool <mbp@samba.org> + + * NEWS: Better description of network error detection. + +2003-05-05 17:36 Martin Pool <mbp@samba.org> + + * src/rpc.c: dcc_explain_mismatch: After a protocol problem, show + up to 200 bytes of printable context. + +2003-05-05 17:26 Martin Pool <mbp@samba.org> + + * NEWS, src/rpc.c: dcc_explain_mismatch: New function, to give + more information in the case of a protocol mismatch. Most + importantly, if an unexpected response is seen then we give a + bit more text from the network in the hope that it will help + diagnose the problem. + +2003-05-05 16:58 Martin Pool <mbp@samba.org> + + * src/clirpc.c: Doc. + +2003-05-05 16:54 Martin Pool <mbp@samba.org> + + * src/: clirpc.c, rpc.c: dcc_r_result_header, dcc_r_cc_status: + These are client-specific, so move them to clirpc.c. + +2003-05-05 16:53 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version. + +2003-05-05 16:28 Martin Pool <mbp@samba.org> + + * NEWS, configure.ac: Prepare for 2.2 release. + +2003-05-05 16:27 Martin Pool <mbp@samba.org> + + * src/hosts.h: Remove CVS tag. + +2003-05-05 16:23 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-05-05 16:21 Martin Pool <mbp@samba.org> + + * TODO: Add a basic --listen option, based on a patch by Neil + Mansilla. + +2003-05-05 16:17 Martin Pool <mbp@samba.org> + + * src/dopt.c, src/dopt.h, src/dparent.c, src/srvnet.c, + src/srvnet.h, NEWS: Add a basic --listen option, based on a + patch by Neil Mansilla. + +2003-05-05 16:05 Martin Pool <mbp@samba.org> + + * patches/andresen-gcc-wrapper-r2.tbz2: Remove Gentoo-only patch. + +2003-05-05 15:54 Martin Pool <mbp@samba.org> + + * TODO: Update TODO list. + +2003-05-05 15:30 Martin Pool <mbp@samba.org> + + * src/distcc.c: (dcc_show_usage): Describe where the host list + comes from -- this is important because it is a configurable + option. Add documentation for SSH syntax. + +2003-05-05 15:16 Martin Pool <mbp@samba.org> + + * test/testdistcc.py, NEWS: Test host file support. + +2003-05-05 15:15 Martin Pool <mbp@samba.org> + + * NEWS: Note about support for host files. + +2003-05-05 15:14 Martin Pool <mbp@samba.org> + + * Makefile.in: h_hosts: Now needs hostfile.o and io.o + +2003-05-05 15:08 Martin Pool <mbp@samba.org> + + * src/: hosts.c, hosts.h, where.c: If DISTCC_HOSTS is not set, + look in ~/.distcc/hosts, or otherwise /etc/distcc/hosts. + +2003-05-05 15:03 Martin Pool <mbp@samba.org> + + * src/hostfile.c: Doc + +2003-05-05 15:01 Martin Pool <mbp@samba.org> + + * cases/empty.s: Empty assembler file for testing. + +2003-05-05 15:01 Martin Pool <mbp@samba.org> + + * Makefile.in: SYSCONFDIR must be quoted for C. + +2003-05-05 14:37 Martin Pool <mbp@samba.org> + + * src/: hosts.c, hosts.h, util.c, util.h: (dcc_dup_part): Move to + util.c. + +2003-05-05 14:35 Martin Pool <mbp@samba.org> + + * TODO: Build .debs or .rpms? + +2003-05-05 14:24 Martin Pool <mbp@samba.org> + + * TODO: Build .debs or .rpms? + +2003-05-05 14:19 Martin Pool <mbp@samba.org> + + * src/hostfile.c: (dcc_parse_hosts_file): New function. + +2003-05-05 12:59 Martin Pool <mbp@samba.org> + + * Makefile.in, src/hostfile.c: New file: src/hostfile.c + + * where.o and hosts.o don't need to be linked into the server, + only the client. + +2003-05-05 12:56 Martin Pool <mbp@samba.org> + + * Makefile.in: (SRC): Sort. + +2003-05-05 12:53 Martin Pool <mbp@samba.org> + + * src/loadfile.c: dcc_load_file: Move everything back into a + single function. Actually allocate a buffer and read into it. + +2003-05-04 23:17 Martin Pool <mbp@samba.org> + + * src/loadfile.c: dcc_load_file: Split into a second function to + ease error checking. + + * dcc_load_fd: New function. Allocate a memory buffer for the + file after discovering its size. + +2003-05-04 23:13 Martin Pool <mbp@samba.org> + + * src/loadfile.c: dcc_load_file: Check size of file and complain + about those that are too large. + +2003-05-04 23:06 Martin Pool <mbp@samba.org> + + * Makefile.in, src/exitcode.h, src/io.h, src/loadfile.c: Start + adding code to load a whole file in to memory, so that we can + read hosts from a file. + +2003-05-04 23:00 Martin Pool <mbp@samba.org> + + * patches/hosts-from-file-raabe.diff: Old patch from Frerich to + read hosts from a file. + +2003-05-04 22:48 Martin Pool <mbp@samba.org> + + * src/: arg.c, bulk.c, clinet.c, dopt.c, exec.c, filename.c, + h_argvtostr.c, h_exten.c, h_hosts.c, h_issource.c, h_scanargs.c, + h_strip.c, help.c, hosts.c, lock.c, rpc.c, sendfile.c, serve.c, + srvnet.c, tempfile.c, trace.c, util.c, where.c, zip.c: Remove + all dependencies on assert.h. Most of them were not used, and + the rest are better written using our standard error handling + library. + +2003-05-04 22:43 Martin Pool <mbp@samba.org> + + * configure.ac: More spacing in output. + +2003-05-04 22:42 Martin Pool <mbp@samba.org> + + * Makefile.in: Start adding support for a host list file: define + SYSCONFDIR, and show it when displaying paths. + +2003-05-04 22:31 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version to 2.2cvs + +2003-05-04 22:29 Martin Pool <mbp@samba.org> + + * TODO: Notes about compression and reading hosts from a file. + +2003-05-04 21:38 Martin Pool <mbp@samba.org> + + * doc/protocol-1.txt: Suggestions from Brad Hards: + + * Correction about SOUT. + + * Explain a bit more about waitstatus. + +2003-05-04 17:24 Martin Pool <mbp@samba.org> + + * NEWS, linuxdoc/distcc.sgml: Add documentation for --allow and + --user, by Frerich Raabe. + +2003-05-04 12:01 Martin Pool <mbp@samba.org> + + * TODO: Update todo list. + +2003-05-04 11:21 Martin Pool <mbp@samba.org> + + * NEWS, news.el: Roll over NEWS for new release. + + * Move news.el into mode variables at the bottom of the NEWS + file. + +2003-05-03 23:57 Martin Pool <mbp@samba.org> + + * NEWS, configure.ac: Prepare for 2.1 release. + +2003-05-03 17:56 Martin Pool <mbp@samba.org> + + * doc/protocol-1.txt: Ask for questions. + + * Describe all the packets in the request and the response. + +2003-05-03 13:39 Martin Pool <mbp@samba.org> + + * TODO: Note about preprocessing remotely. + +2003-05-03 12:05 Martin Pool <mbp@samba.org> + + * TODO: Note about never running locally. + +2003-04-30 12:17 Martin Pool <mbp@samba.org> + + * TODO: Link to API for async name lookups. + +2003-04-27 00:18 Martin Pool <mbp@samba.org> + + * doc/protocol-1.txt: Add some documentation of the protocol in + the current version. Pretty good but does not cover the + complete sequence yet. + +2003-04-19 23:08 Martin Pool <mbp@samba.org> + + * NEWS: Test harnesses may need snprintf.o linked in as well. + Reported by Joe Meslovich as broken on Solaris. + +2003-04-19 21:55 Martin Pool <mbp@samba.org> + + * Makefile.in: Test harnesses may need snprintf.o linked in as + well. Reported by Joe Meslovich as broken on Solaris. + +2003-04-17 12:26 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-04-14 13:05 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-04-14 13:02 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-04-13 19:00 Martin Pool <mbp@samba.org> + + * TODO: Notes from UML. + +2003-04-13 17:35 Martin Pool <mbp@samba.org> + + * TODO: Note about setting listen address. + +2003-04-13 17:18 Martin Pool <mbp@samba.org> + + * TODO: Notes about DISTCC_HOSTS syntax. + +2003-04-10 16:42 Martin Pool <mbp@samba.org> + + * src/help.c: Add quote. + +2003-04-08 16:23 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-04-08 13:58 Martin Pool <mbp@samba.org> + + * patches/n_cpus.txt: n_cpus.txt Remove merged code + +2003-04-04 17:39 Martin Pool <mbp@samba.org> + + * patches/: distcc-path.patch, distccd-path.patch: + distcc-path.patch distccd-path.patch Delete merged patches + +2003-04-04 17:38 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-04-04 17:32 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-04-04 17:28 Martin Pool <mbp@samba.org> + + * src/io.c: tcp_cork_sock: Don't complain about ENOTSUPP when + uncorking. + +2003-04-04 17:24 Martin Pool <mbp@samba.org> + + * src/: rpc.c, io.h: dcc_read_int: Remove dead function. + +2003-04-04 17:20 Martin Pool <mbp@samba.org> + + * src/: io.c: Doc. + +2003-04-04 17:19 Martin Pool <mbp@samba.org> + + * src/io.c: dcc_pump_readwrite: Increase transfer buffer to + 256kB, and move it off the stack. + +2003-04-04 17:16 Martin Pool <mbp@samba.org> + + * src/io.c: dcc_pump_readwrite: Doc. + +2003-04-04 17:12 Martin Pool <mbp@samba.org> + + * src/io.c, NEWS: dcc_pump_readwrite: Should print an error on + unexpected end of input, rather than treating it as success. + Why did I do that? + +2003-04-04 17:11 Martin Pool <mbp@samba.org> + + * NEWS: Note about nonblocking support. + +2003-04-04 16:59 Martin Pool <mbp@samba.org> + + * src/io.c: dcc_pump_readwrite: Only select on file descriptors + after we get EAGAIN. + + * dcc_readx, dcc_writex: Clarify. + +2003-04-04 15:54 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Patch from Wayne Davison to document + DISTCCD_PATH. + +2003-04-04 15:51 Martin Pool <mbp@samba.org> + + * cases/hello.m: Example ObjC program from Dara Hazeghi + +2003-04-04 12:19 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-04-04 12:06 Martin Pool <mbp@samba.org> + + * src/util.c: dcc_abspath: Memory overflow ought to be fatal. + +2003-04-04 12:00 Martin Pool <mbp@samba.org> + + * NEWS, src/climasq.c, src/daemon.c, src/distcc.c, src/util.c, + src/util.h: Merged patch from Wayne Davison: + + Try to prevent distcc from invoking itself recursively either on + the server, or as cc -E on the client. + + * dcc_trim_path: New code to remove from the PATH any directories + that contain "cc" as a link to something that looks like ccache + or distcc. + + * climasq.c: Munge path as appropriate. + + * daemon.c/main: Use DISTCCD_PATH if set, otherwise trim path. + + * distcc.c/main: Trim path. + +2003-04-04 11:45 Martin Pool <mbp@samba.org> + + * src/daemon.c: Factor out code for checking whether to be inetd. + +2003-04-04 10:41 Martin Pool <mbp@samba.org> + + * README.packaging: Note about ssh and path to distccd + + * Note about --allow + + * Note about distcc user + + * Prefer --daemon + +2003-04-04 10:33 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-04-04 10:32 Martin Pool <mbp@samba.org> + + * NEWS: Change behaviour of distccd for log messages encountered + during startup, before options are parsed. These are now + written to stderr only if that is a tty, and otherwise to + syslog. This is intended to prevent log messages from distccd + getting mixed into the network protocol when it is run from + inetd. + +2003-04-04 10:21 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: NoDetachDaemon_Case: Specify --daemon to + suppress diagnostic message. + +2003-04-04 10:19 Martin Pool <mbp@samba.org> + + * src/daemon.c: dcc_setup_startup_log: Split out code for sending + startup messages to either stderr or syslog. + + * distccd/main: refactor code for deciding whether to be inetd or + standalone. + + * dcc_setup_real_log: Rename function for setting final log + destination. + + * Doc. + +2003-04-04 10:04 Martin Pool <mbp@samba.org> + + * src/daemon.c: Change behaviour of distccd for log messages + encountered during startup, before options are parsed. These + are now written to stderr only if that is a tty, and otherwise + to syslog. This is intended to prevent log messages from + distccd getting mixed into the network protocol when it is run + from inetd. + +2003-04-04 10:01 Martin Pool <mbp@samba.org> + + * src/: distcc.c, distcc.h, help.c: Show version in log at client + startup. + +2003-04-04 09:43 Martin Pool <mbp@samba.org> + + * patches/distcc-path.patch: Patch from Wayne to clean path of + masquerade links. + +2003-04-03 16:21 Martin Pool <mbp@samba.org> + + * NEWS: Note rusage format fix. + +2003-04-03 14:39 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-04-03 14:37 Martin Pool <mbp@samba.org> + + * test/comfychair.py: Better log message. + +2003-04-03 14:29 Martin Pool <mbp@samba.org> + + * src/distcc.c: Factor out code to find basename from argv. + +2003-04-03 10:23 Martin Pool <mbp@samba.org> + + * src/: distcc.h, serve.c: Patch from Wayne Davison: + + * Removed prototype for dcc_trace_argv() (since it's a define + now). + + * Use "else while(0)" instead of "else {}" so that using the + dcc_trace_argv() define doesn't result in two C statements. + + * Return the "ret" value in dcc_r_request_header() when it's + non-0. + +2003-04-02 17:26 Martin Pool <mbp@samba.org> + + * src/util.c: dcc_exit: Remove silly printf bug that made all + rusage messages inaccurate. + +2003-04-02 17:16 Martin Pool <mbp@samba.org> + + * patches/: distcc-hostopt.patch, distccd-path.patch, + distccd-version.patch: Patches from Wayne + +2003-04-02 17:12 Martin Pool <mbp@samba.org> + + * TODO: More protocol wonderings. + +2003-04-02 16:43 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Update todos. + +2003-04-02 16:37 Martin Pool <mbp@samba.org> + + * src/: arg.c, distcc.h: dcc_trace_argv: Convert to a macro so + that it shows the right function name in trace messages. + +2003-04-02 16:33 Martin Pool <mbp@samba.org> + + * src/: io.c: dcc_readx, dcc_writex: Only select() on the fd + after we've got EAGAIN. It might not be necessary in many + cases. + +2003-04-02 16:30 Martin Pool <mbp@samba.org> + + * src/sendfile.c: dcc_pump_sendfile: Check for select() failure. + +2003-04-02 16:27 Martin Pool <mbp@samba.org> + + * src/io.c: Doc + +2003-04-02 15:25 Martin Pool <mbp@samba.org> + + * src/: climasq.c, distcc.c, distcc.h: Make + dcc_support_masquerade() return standard error codes. + +2003-04-02 15:16 Martin Pool <mbp@samba.org> + + * src/: util.c, arg.c: Remove incorrect EXIT_FAULURE + +2003-04-02 15:10 Martin Pool <mbp@samba.org> + + * Makefile.in, src/climasq.c, src/distcc.c, src/distcc.h: Split + masquerade support into climasq.c + +2003-04-02 15:10 Martin Pool <mbp@samba.org> + + * src/safeguard.c: Doc + +2003-04-02 15:05 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc + +2003-04-02 14:57 Martin Pool <mbp@samba.org> + + * src/serve.c: Remove one more old "-1" error code. Patch from + Wayne Davison. + +2003-04-02 14:54 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc + +2003-04-02 14:49 Martin Pool <mbp@samba.org> + + * src/: io.c, rpc.c: Move rpc-specific functions from io.c into + rpc.c. + +2003-04-02 14:46 Martin Pool <mbp@samba.org> + + * src/dopt.c: Make --no-fork undocumented. + +2003-04-02 14:43 Martin Pool <mbp@samba.org> + + * src/sendfile.c: dcc_pump_sendfile: Only select() on the output + socket after sendfile has failed with EAGAIN. Otherwise we can + miss the case where the remote host has closed the connection + on us, as can happen if we connect contrary to --allow. + +2003-04-02 14:42 Martin Pool <mbp@samba.org> + + * src/io.c: Trace message when select()ing + +2003-04-02 14:41 Martin Pool <mbp@samba.org> + + * src/distcc.h, src/exec.c, src/exec.h, src/safeguard.c, + Makefile.in: Split safeguard functions out into their own file. + +2003-04-02 12:39 Martin Pool <mbp@samba.org> + + * doc/results.txt: SSH results. + +2003-04-02 12:27 Martin Pool <mbp@samba.org> + + * NEWS: Note removal of "return -1". + +2003-04-02 11:55 Martin Pool <mbp@samba.org> + + * NEWS: Update SSH news. + +2003-04-02 11:00 Martin Pool <mbp@samba.org> + + * TODO: Notes on DISTCC_SSH. + +2003-04-02 10:58 Martin Pool <mbp@samba.org> + + * src/ssh.c: Doc + +2003-04-02 10:46 Martin Pool <mbp@samba.org> + + * TODO: Note about documenting SSH. + +2003-04-01 13:59 Martin Pool <mbp@samba.org> + + * Makefile.in: Split binary downloads onto their own page. + +2003-03-31 23:16 Martin Pool <mbp@samba.org> + + * src/bulk.c: Show more precision when printing transfer rates. + +2003-03-31 18:48 Martin Pool <mbp@samba.org> + + * src/sendfile.c: Check network is ready to write before + attempting sendfile. + +2003-03-31 18:47 Martin Pool <mbp@samba.org> + + * src/: io.h, io.c: Export select_for_* + +2003-03-31 18:46 Martin Pool <mbp@samba.org> + + * src/io.c: Before reading or writing a socket, select() on it to + make sure it's available. Makes things work when our network + socket is really a nonblocking connection to ssh. + +2003-03-31 18:43 Martin Pool <mbp@samba.org> + + * src/ssh.c: Don't send server log to stderr by default. + +2003-03-31 18:36 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2003-03-31 18:36 Martin Pool <mbp@samba.org> + + * src/io.c: dcc_readx: Handle reading from nonblocking + socketpairs/pipes. + +2003-03-31 18:34 Martin Pool <mbp@samba.org> + + * src/ssh.c: Use nonblocking pipes to ssh. + + * Add --log-stderr when invoking the remote daemon. + +2003-03-31 18:30 Martin Pool <mbp@samba.org> + + * src/bulk.c: Doc. + +2003-03-31 18:18 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version + +2003-03-31 18:17 Martin Pool <mbp@samba.org> + + * src/distcc.c: For ssh support, we need to allow for separate + fds writing to and reading from the network, because our + connection to the ssh client may be over pipes, which are + one-way connections. + + Therefore split them out into separate fds in the code. + +2003-03-31 18:14 Martin Pool <mbp@samba.org> + + * NEWS: Preliminary support for ssh. + +2003-03-31 18:08 Martin Pool <mbp@samba.org> + + * src/ssh.c: Make the dcc end of the socketpairs/pipes talking to + ssh be blocking, even if ssh needs blocking ones. Does this + work? + +2003-03-31 18:02 Martin Pool <mbp@samba.org> + + * src/io.c: dcc_readx: Stub handler for EAGAIN. + +2003-03-31 18:00 Martin Pool <mbp@samba.org> + + * src/io.c: Reindent only. + +2003-03-31 17:55 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Fix silly Python bug. + +2003-03-31 17:49 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Giving a bogus port number now gives you + EXIT_BAD_ARGUMENTS. + +2003-03-31 17:48 Martin Pool <mbp@samba.org> + + * src/: dparent.c, srvnet.c, srvnet.h: open_socket_in: Rename to + conventional name 'dcc_socket_listen', and return an exit code. + +2003-03-31 17:44 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Allow default daemon lifetime of 60s, and + 300s for BigAssFile. + +2003-03-31 17:42 Martin Pool <mbp@samba.org> + + * patches/.cvsignore: Ignore built test programs. + +2003-03-31 17:42 Martin Pool <mbp@samba.org> + + * src/: arg.c, bulk.c, clirpc.c, distcc.c, dparent.c, exec.c, + filename.c, hosts.c, io.c, sendfile.c, serve.c, srvnet.c, + tempfile.c, util.c: Get medieval on "return -1" in old code. + Everything ought to return a standard error code now. + +2003-03-31 17:30 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc + +2003-03-31 17:22 Martin Pool <mbp@samba.org> + + * src/distcc.c, NEWS: Add DISTCC_FALLBACK environment variable. + If set to 0, means that failure to distribute will be + considered an overall failure. By default, a networking error + means that compilation will be retried locally. + +2003-03-31 17:11 Martin Pool <mbp@samba.org> + + * src/io.c, NEWS: Better error handling when corks are not + supported on a particular system or socket. + +2003-03-31 17:08 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Revert r1.129: sending logs to stderr + doesn't work very well. The daemon can get sigpipe while + writing them and similar problems. + +2003-03-31 17:02 Martin Pool <mbp@samba.org> + + * test/testdistcc.py, NEWS: Test invalid --allow masks. + +2003-03-31 17:00 Martin Pool <mbp@samba.org> + + * src/: distcc.h, ssh.c: dcc_ssh_connect: Fix const-ness of + strings. + +2003-03-31 17:00 Martin Pool <mbp@samba.org> + + * src/distcc.c: First cut of support for distcc-over-ssh. + + * dcc_compile_remote: For ssh-mode connections, try to open up + using dcc_ssh_connect. + +2003-03-31 16:59 Martin Pool <mbp@samba.org> + + * src/arg.c: Undo constness of argv[] arguments, it just doesn't + work well in gcc. + +2003-03-31 16:55 Martin Pool <mbp@samba.org> + + * src/: distcc.h, ssh.c: Undo constness of argv[] arguments, it + just doesn't work well in gcc. + +2003-03-31 16:54 Martin Pool <mbp@samba.org> + + * TODO: More notes on new scheduler. + +2003-03-31 16:54 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-03-31 16:45 Martin Pool <mbp@samba.org> + + * src/distcc.h: dcc_trace_argv: Fix constness of parameter. + + * dcc_ssh_connect: Export prototype. + +2003-03-31 16:44 Martin Pool <mbp@samba.org> + + * src/arg.c: dcc_trace_argv: Fix constness of parameter. + +2003-03-31 16:39 Martin Pool <mbp@samba.org> + + * Makefile.in: Include ssh.o in client build. + +2003-03-31 16:38 Martin Pool <mbp@samba.org> + + * src/ssh.c: dcc_ssh_connect: If no username is specified, don't + pass the -l option. If no machine is specified, abort. If no + path is given, just use "distccd". + +2003-03-31 16:33 Martin Pool <mbp@samba.org> + + * src/ssh.c: Remove blocking_io support; it shouldn't be needed + if we're only using ssh not rsh. + + * Update to build cleanly in this tree. + + * dcc_run_piped_cmd: Make sure pipes are always closed because + the program will not necessarily abort if we fail to connect + and we don't want to leak file descriptors. + + * dcc_ssh_connect: Build connection command in argv[] not a + string, so that we can avoid invoking a shell. + +2003-03-31 16:02 Martin Pool <mbp@samba.org> + + * TODO: Many more notes about single-queue multi-server + scheduler. + +2003-03-31 15:59 Martin Pool <mbp@samba.org> + + * src/serve.c: Remove dead code. + +2003-03-31 15:37 Martin Pool <mbp@samba.org> + + * patches/backlog-sample.c: Sample that tries to use TCP + connection backlogs to give the client some information about + whether the server is busy. Doesn't seem to work very well. + +2003-03-31 14:59 Martin Pool <mbp@samba.org> + + * TODO: Update + +2003-03-31 14:54 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc. + +2003-03-31 14:53 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add new case exercising dcc_check_address + and h_parsemask. + +2003-03-31 14:48 Martin Pool <mbp@samba.org> + + * src/access.c: Doc + +2003-03-31 14:34 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: NoDetachDaemon_Case: prevent logs from + background process getting into build process's stderr. + +2003-03-31 14:28 Martin Pool <mbp@samba.org> + + * src/dsignal.c, NEWS: dcc_parent_terminate: No need to + explicitly remove pid file; it will be cleaned up in atexit(). + +2003-03-31 14:25 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Allow log output from the server into + stderr so that it can be presented if a test case fails. + +2003-03-31 14:22 Martin Pool <mbp@samba.org> + + * NEWS, test/testdistcc.py: Add test that --allow does in fact + deny connections as it should. + +2003-03-31 14:14 Martin Pool <mbp@samba.org> + + * TODO, doc/ssh-notes.txt, doc/to-test.txt: Move notes on future + design options into ./TODO. + +2003-03-31 14:14 Martin Pool <mbp@samba.org> + + * doc/lock-deadlock.txt: Remove old bug report. + +2003-03-31 14:10 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Remove done TODOs + +2003-03-31 14:09 Martin Pool <mbp@samba.org> + + * patches/prefork-sample.c: Doc + +2003-03-29 11:06 Martin Pool <mbp@samba.org> + + * NEWS: Retrospective release name. + +2003-03-28 18:57 Martin Pool <mbp@samba.org> + + * TODO: Notes about preforking. + +2003-03-28 18:43 Martin Pool <mbp@samba.org> + + * patches/prefork-sample.c: Experimental code to see if we can + just have every preforked child accept() on the socket + +2003-03-28 18:20 Martin Pool <mbp@samba.org> + + * doc/interceptor.txt: interceptor.txt Remove old file + +2003-03-28 18:12 Martin Pool <mbp@samba.org> + + * configure.ac, NEWS: Prepare for 2.0.1 release. + +2003-03-28 18:12 Martin Pool <mbp@samba.org> + + * Makefile.in: Dereference symbolic files when producing tarball. + +2003-03-28 17:33 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Masquerade came out in 2.0, not 1.3. + +2003-03-28 16:47 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-03-28 16:17 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Get ready for 2.0 release. + +2003-03-28 16:13 Martin Pool <mbp@samba.org> + + * NEWS, configure.ac: Get ready for 2.0 release. + +2003-03-28 16:11 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove old doc/ files from the distribution. + +2003-03-28 16:02 Martin Pool <mbp@samba.org> + + * src/distcc.c: Remove "HOST/MAX:PORT" syntax from --help. I + don't want to make this fully "public" yet because I'm not sure + this is the ideal way to set this value in the future. + +2003-03-28 15:58 Martin Pool <mbp@samba.org> + + * NEWS, test/testdistcc.py: Test DISTCC_LOG being set to an + unwriteable file. + +2003-03-28 15:55 Martin Pool <mbp@samba.org> + + * NEWS: Test suite now works with Python 1.5 or later. + +2003-03-28 15:53 Martin Pool <mbp@samba.org> + + * test/comfychair.py: Remove dependency on os.spawnvp, which is + not in Python1.5 + +2003-03-28 15:52 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: NoHosts_Case: Python 1.5 can't delete + environment variables, so just set them to empty. + +2003-03-28 15:50 Martin Pool <mbp@samba.org> + + * src/distcc.c, NEWS: If the file specified by DISTCC_LOG can't + be opened, then show an error and use stderr. Previously all + errors were just lost. + +2003-03-28 15:45 Martin Pool <mbp@samba.org> + + * src/distcc.c, NEWS: If DISTCC_LOG is an empty string, treat as + undefined. + +2003-03-28 15:42 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: runcmd_background now takes a string, not a + sequence. + + * Python1.5 doesn't have ''.split. + +2003-03-28 15:27 Martin Pool <mbp@samba.org> + + * test/: comfychair.py, testdistcc.py: Remove dependency on + popen4, which is not present in Python 1.5. + + * runcmd and related functions now return stdout and stderr + messages separately. Many tests must be updated to allow for + this. + + * Refactor some tests towards a flatter hierarchy. + + * Assert that the compiler should not normally produce errors or + other messages. + +2003-03-28 13:58 Martin Pool <mbp@samba.org> + + * test/comfychair.py: Remove list comprehension, which is not + available in Python 1.5. + +2003-03-28 13:54 Martin Pool <mbp@samba.org> + + * TODO: Note on static linking. + +2003-03-28 13:51 Martin Pool <mbp@samba.org> + + * test/testdistcc.py, NEWS: On BSD, 'true' and 'false' are in + /usr/bin (?) not /bin. + +2003-03-28 13:44 Martin Pool <mbp@samba.org> + + * NEWS: Notes on test improvments. + +2003-03-28 13:40 Martin Pool <mbp@samba.org> + + * Makefile.in: Makefile (check, installcheck): If Python is not + found then just print "tests skipped" rather than failing. + This should make the results on the build farm a bit more + clear. + +2003-03-28 13:37 Martin Pool <mbp@samba.org> + + * configure.ac: If Python is not found in the path, then just + leave $(PYTHON) blank rather than setting it to 'false'. + +2003-03-28 11:59 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove redundant setting of $(LIBS): autoconf puts + -lpopt in there if it's needed. + +2003-03-28 11:57 Martin Pool <mbp@samba.org> + + * configure.ac: (Hopefully) better check for socket() and + gethostbyname() that will avoid unnecessarily linking libnsl on + Linux. Taken from Samba, which got it from CVS. + +2003-03-27 19:16 Martin Pool <mbp@samba.org> + + * TODO: Note on DNS timeouts. + +2003-03-27 15:58 Martin Pool <mbp@samba.org> + + * src/rpc.h: dcc_x_token_int: Token parameters are unsigned. + +2003-03-27 15:54 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-03-27 15:45 Martin Pool <mbp@samba.org> + + * src/rpc.c: dcc_x_token_int: Remove call to snprintf to format + outgoing packets. It really sticks out in valgrind and this is + a reasonably common function. + +2003-03-27 15:33 Martin Pool <mbp@samba.org> + + * src/: io.c, io.h: dcc_write_int: Remove dead function. + +2003-03-27 15:31 Martin Pool <mbp@samba.org> + + * src/: io.h, io.c: dcc_write_str: Remove dead function. + +2003-03-27 15:29 Martin Pool <mbp@samba.org> + + * src/clirpc.c: dcc_x_argv: Avoid redundant strlen() computation. + +2003-03-27 15:08 Martin Pool <mbp@samba.org> + + * src/arg.c, src/distcc.h, src/exec.c, src/serve.c, src/ssh.c, + src/strip.c, NEWS: Factor out code for tracing argv[] arrays. + By avoiding conversion unless it is actually going to be logged + we save a few cycles. + + This also addresses some cases where the printable form was not + freed after creation, although that shouldn't ever matter much + in + such a short-lived program. + +2003-03-27 11:39 Martin Pool <mbp@samba.org> + + * Makefile.in: Allow for implementations of 'install' that can + only process one file at a time. GNU's 'install-sh' is one + such. + +2003-03-27 11:08 Martin Pool <mbp@samba.org> + + * NEWS: Don't install linuxdoc-info by default, either from CVS + or distributions. + +2003-03-27 10:37 Martin Pool <mbp@samba.org> + + * Makefile.in: Don't install linuxdoc-info by default, either + from CVS or distributions. + +2003-03-27 10:30 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove overall 'upload' target: we don't want to + upload the manual when the web site is uploaded. + +2003-03-26 23:36 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Manual is for 1.3cvs. + +2003-03-23 12:18 Martin Pool <mbp@samba.org> + + * Makefile.in: Don't ship unmerged patches in the tarball. + +2003-03-23 12:17 Martin Pool <mbp@samba.org> + + * patches/resolver-timeout.diff: resolver-timeout.diff Resolver + timeout draft patch from Jonas Jensen + +2003-03-22 09:44 Martin Pool <mbp@samba.org> + + * patches/connect-timeout.diff: Remove old draft patch. + +2003-03-21 19:02 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Get rid of Python 2 ism. + +2003-03-21 18:59 Martin Pool <mbp@samba.org> + + * src/ncpus.c: Try looking for the predefined "__hpux" or + "__hpux__" not "hpux". + +2003-03-21 18:47 Martin Pool <mbp@samba.org> + + * NEWS, test/testdistcc.py: Use randomly chosen TCP port for the + server when running tests. + +2003-03-21 18:46 Martin Pool <mbp@samba.org> + + * NEWS: Use --allow=127.0.0.1 when starting daemon + +2003-03-21 18:41 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Use --allow=127.0.0.1 when starting daemon + + * killDaemon: if the daemon has already exited, perhaps because + of an alarmclock, and removed it's pid file, then don't worry + about killing it. + +2003-03-21 18:32 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: SimpleDistCC_Case.__init__: remove + redundant code: logging has moved into comfychair.TestCase. + + * SimpleDistCC_Case: Allow subclasses to change lifetime of + daemon or command used to start it. + + * By default daemon only lives 10s. For ThousandFold_Case and + Concurrent_Case it needs to live up to 2 minutes. + +2003-03-21 18:24 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: NoDetachDaemon_Case: Shouldn't need + --lifetime for this test. + +2003-03-21 18:21 Martin Pool <mbp@samba.org> + + * test/testdistcc.py, NEWS: Specify limited lifetime when running + daemon, so that if it is not cleaned up by the tests it will go + away after a little while anyhow. + +2003-03-21 18:18 Martin Pool <mbp@samba.org> + + * NEWS, configure.ac, src/dsignal.c: If we have strsignal(), then + log the signal name rather than number when terminating. + +2003-03-21 18:12 Martin Pool <mbp@samba.org> + + * src/dsignal.c: Also print a message when terminating on + SIGALRM. + +2003-03-21 18:11 Martin Pool <mbp@samba.org> + + * Makefile.in, src/distcc.h, src/dparent.c, src/dsignal.c: Split + signal-handling code into new file dsignal.c + +2003-03-21 17:56 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.h, dparent.c: Make sure lifetime limit + applies even when the daemon detaches: after forking to + dissociate from the session, reset the alarm clock. + +2003-03-21 17:25 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: NoHosts_Case: Cleanup to get it working + with the new framework. + +2003-03-21 16:27 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: NoHosts_Case: Better log message. + +2003-03-21 16:24 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: NoDetachDaemon_Case: Make sure daemon is + killed off. + +2003-03-21 16:21 Martin Pool <mbp@samba.org> + + * test/comfychair.py: Update from Subversion + +2003-03-21 16:21 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Move code for entering rundir into + comfychair. + + * Change killing of daemon to be a cleanup rather than part of + teardown. + +2003-03-21 14:00 Martin Pool <mbp@samba.org> + + * src/: daemon.c, dopt.c, dparent.c, serve.c: Rename opt.h to + dopt.h, to be consistent with dopt.c. + +2003-03-21 13:59 Martin Pool <mbp@samba.org> + + * TODO: CCACHE_ERR_FD + +2003-03-21 13:56 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove "=distcheck" directory on successful + completion. + +2003-03-21 13:55 Martin Pool <mbp@samba.org> + + * Makefile.in: Include types.h in distribution. + +2003-03-21 13:54 Martin Pool <mbp@samba.org> + + * Makefile.in, src/dopt.h, src/opt.h: Rename opt.h to dopt.h, to + be consistent with dopt.c. + +2003-03-21 13:46 Martin Pool <mbp@samba.org> + + * NEWS, src/daemon.c, src/dopt.c, src/opt.h: * Add new + undocumented (heh) "--lifetime" option that causes the daemon to + expire after a certain period. + +2003-03-21 13:44 Martin Pool <mbp@samba.org> + + * test/comfychair.py: Doc. + +2003-03-21 12:58 Martin Pool <mbp@samba.org> + + * src/sendfile.c: printf type correctness. + +2003-03-21 12:51 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-03-21 12:34 Martin Pool <mbp@samba.org> + + * NEWS: types.h: New file, to give typedefs for missing systems + types. Include this in files that need it. Move typedefs from + random source files into here. + + * Add in_addr_t, which is int by default. + +2003-03-21 12:34 Martin Pool <mbp@samba.org> + + * src/types.h: in_addr_t should perhaps be ulong by default. + +2003-03-21 12:31 Martin Pool <mbp@samba.org> + + * src/: access.c, clinet.c, dopt.c, h_parsemask.c, srvnet.c, + types.h: types.h: New file, to give typedefs for missing + systems types. Include this in files that need it. Move + typedefs from random source files into here. + + * Add in_addr_t, which is int by default. + +2003-03-21 12:21 Martin Pool <mbp@samba.org> + + * configure.ac: Check for existence of sys/socket.h + + * Check for in_addr_t + +2003-03-21 12:20 Martin Pool <mbp@samba.org> + + * src/srvnet.c: If socklen_t is missing, make it a size_t. + +2003-03-21 12:14 Martin Pool <mbp@samba.org> + + * src/snprintf.h, NEWS: Fix incorrect config macro names: should + be HAVE_DECL_ASPRINTF not HAVE_ASPRINTF_DECL. Fixes + declaration warnings on Solaris. + +2003-03-21 12:02 Martin Pool <mbp@samba.org> + + * NEWS: Should build on IRIX. + +2003-03-21 11:58 Martin Pool <mbp@samba.org> + + * NEWS: Don't include Info file in the distribution. It's a bit + redundant to ship the documentation in three forms (SGML, HTML, + Info), and people can build it or download it if they want to. + + * Don't rebuild all Linuxdoc files for distribution, only the + ones which need to be included. + +2003-03-21 11:54 Martin Pool <mbp@samba.org> + + * Makefile.in: Don't include Info file in the distribution. It's + a bit redundant to ship the documentation in three forms (SGML, + HTML, Info), and people can build it or download it if they + want to. + + * Don't rebuild all Linuxdoc files for distribution, only the + ones which need to be included. + +2003-03-19 09:34 Martin Pool <mbp@samba.org> + + * configure.ac: Change check for in_port_t, which exists on + Solaris, but which isn't found in just sys/types.h and + netinet/in.h. + +2003-03-19 09:28 Martin Pool <mbp@samba.org> + + * src/ncpus.c: Try to fix BSD dcc_ncpus(). + +2003-03-18 21:18 Martin Pool <mbp@samba.org> + + * src/ssh.c: piped_child: Update to take an argv[] array rather + than a simple command so that we can avoid running a shell. + +2003-03-18 18:15 Martin Pool <mbp@samba.org> + + * configure.ac: Check whether the C compiler supports inlining, + etc. Needed for popt. + +2003-03-18 17:47 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Cast to int when calling printf. + +2003-03-18 17:46 Martin Pool <mbp@samba.org> + + * src/snprintf.h: Add conditional declaration of vsnprintf. + +2003-03-18 17:45 Martin Pool <mbp@samba.org> + + * src/ncpus.c: Add FreeBSD/OpenBSD/NetBSD implementation. + +2003-03-18 17:36 Martin Pool <mbp@samba.org> + + * src/ncpus.c: Fix includes. + +2003-03-18 17:35 Martin Pool <mbp@samba.org> + + * src/ncpus.c: Add a separate definition of dcc_ncpus for HP-UX + (not tested), and URLs describing this. + +2003-03-18 17:27 Martin Pool <mbp@samba.org> + + * src/ncpus.c, NEWS: Add credit to Dimitri PAPADOPOULOS-ORFANOS + for reporting how to do this on various systems. + +2003-03-18 17:25 Martin Pool <mbp@samba.org> + + * src/ncpus.c: Check for definition of _SC_NPROCESSORS_ONLN + (linux), and _SC_NPROC_ONLN (Irix), and call the appropriate + sysconf. + +2003-03-18 17:21 Martin Pool <mbp@samba.org> + + * src/ncpus.c: Include prototypes for this file. + +2003-03-18 17:20 Martin Pool <mbp@samba.org> + + * NEWS: Clean up some warnings on IRIX. + +2003-03-18 17:20 Martin Pool <mbp@samba.org> + + * src/ncpu.c, src/ncpus.c, Makefile.in: Rename ncpu.c to ncpus.c + to be consistent with the function name. + +2003-03-18 17:18 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Cast mode_t to int when passing to printf. + +2003-03-18 17:17 Martin Pool <mbp@samba.org> + + * src/: rpc.c, tempfile.c: Include snprintf.h for systems that + don't have these functions. + +2003-03-18 17:15 Martin Pool <mbp@samba.org> + + * src/: exec.c: Cast pid_t to long when passing to printf. + +2003-03-18 17:13 Martin Pool <mbp@samba.org> + + * src/trace.c: Update copyright. + + * Remove done TODOs. + + * Include snprintf.h to quieten warning on machines that don't + have vsnprintf, such as IRIX. + +2003-03-18 17:11 Martin Pool <mbp@samba.org> + + * NEWS, src/dparent.c: Print number of online CPUs when daemon + starts up. + +2003-03-18 17:09 Martin Pool <mbp@samba.org> + + * src/distcc.h: Add prototype for dcc_ncpus. + +2003-03-18 17:04 Martin Pool <mbp@samba.org> + + * Makefile.in, src/ncpu.c: Add basic code to detect the number of + online processors, at least on Linux. + +2003-03-18 16:56 Martin Pool <mbp@samba.org> + + * NEWS: Reorder news items. + +2003-03-18 15:21 Martin Pool <mbp@samba.org> + + * TODO: Add note to try out masquerade with make-kpkg. + +2003-03-18 14:27 Martin Pool <mbp@samba.org> + + * patches/daemon-address-binding.diff: Patch from Neil Mansilla: + + * Add --address option to daemon, to make it bind only a + particular address. + + I don't know if this is bloat (should be done through inetd?) or + a good idea. Therefore not merged yet. + +2003-03-18 14:24 Martin Pool <mbp@samba.org> + + * test/comfychair.py: Decode waitstatus values when a command + fails. + +2003-03-17 22:25 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-03-14 15:49 Martin Pool <mbp@samba.org> + + * TODO: Update status: + + * Kernel 2.5 bug + + * SQMS scheduler + + * --allow is done + + * Distributed caching + +2003-03-13 17:33 Martin Pool <mbp@samba.org> + + * NEWS: Note that SIGTERM handling race for server is now fixed. + +2003-03-13 17:31 Martin Pool <mbp@samba.org> + + * test/comfychair.py: Merge from svn r30 + +2003-03-13 17:29 Martin Pool <mbp@samba.org> + + * patches/distccd-clean-path.diff: Draft patch from Wayne Davison + to try to keep masquerade connections off the server's $PATH. + +2003-03-13 17:28 Martin Pool <mbp@samba.org> + + * patches/: compression.patch, swhite-lzo-compress.diff: Updated + draft patch from Stephen White to do LZO compression. + +2003-03-13 17:27 Martin Pool <mbp@samba.org> + + * patches/distcc-ethereal.diff: Draft patch to Ethereal + <ethereal.com> to decode/dissect distcc connections. + +2003-03-12 19:08 Martin Pool <mbp@samba.org> + + * src/dparent.c: Fix small signal handling race that would + occasionally cause distccd not to exit when signalled. Pointed + out by Vance Lankhaar, solution advice from Andrew Tridgell. + + The problem was that a signal could arrive after we checked the + global indicator, but before entering accept(). So the daemon + would + need to wait for the accept to complete before it could respond + to + the signal. + + Since the daemon only needs to do very simple cleanup, we now + simply + do it in line in the signal handler and never return. + +2003-03-12 18:56 Martin Pool <mbp@samba.org> + + * src/dparent.c: FIXME about bug reported by Vance: the daemon + sometimes doesn't exit on receipt of SIGTERM, which makes the + test suite hang. + +2003-03-12 17:12 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: assert_regexp renamed to assert_re_search + +2003-03-12 17:09 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Fix incorrect regexp assertion + +2003-03-12 16:51 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: explainFailure, fail, assertEquals, + assertNotEqual, assertReMatch: these are now present in + ComfyChair and don't need to be in this file. + +2003-03-12 16:40 Martin Pool <mbp@samba.org> + + * test/comfychair.py: Update from Subversion r24: + + ------------------------------------------------------------------------ + rev 24: mbp | 2003-03-12 16:32:53 +1100 (Wed, 12 Mar 2003) | 4 + lines + + * Fix calls to explain_failure() + + * comfychair.main: If test names are specified, run them. + ------------------------------------------------------------------------ + rev 23: mbp | 2003-03-12 16:28:29 +1100 (Wed, 12 Mar 2003) | 2 + lines + + * Fix --help message. + +2003-03-12 16:37 Martin Pool <mbp@samba.org> + + * NEWS: Many internal updates to ComfyChair framework. + +2003-03-12 16:11 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Change to using new ComfyChair.main() + method, rather than implementing it by hand. + +2003-03-12 15:43 Martin Pool <mbp@samba.org> + + * test/comfychair.py: Import updated ComfyChair from Subversion: + renamed methods, new main() method, etc. + +2003-03-12 15:42 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: SimpleDistCC_Case.__init__ needs to call + the base constructor method. + + * Update for renamed methods in latest ComfyChair. + +2003-03-11 17:42 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-03-10 15:34 Martin Pool <mbp@samba.org> + + * src/util.c: IRIX might need sys/time.h before sys/resource.h + +2003-03-10 15:13 Martin Pool <mbp@samba.org> + + * src/util.c: Check for sys/resource.h + +2003-03-10 15:10 Martin Pool <mbp@samba.org> + + * configure.ac: Check for sys/resource.h + +2003-03-10 15:08 Martin Pool <mbp@samba.org> + + * configure.ac: Check for getrusage. + +2003-03-10 14:12 Martin Pool <mbp@samba.org> + + * NEWS: Give credit for masquerade mode. + +2003-03-10 13:46 Martin Pool <mbp@samba.org> + + * configure.ac: Test for getwd and getcwd + +2003-03-10 10:58 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove ssh.o from client for the time being. + +2003-03-10 10:16 Martin Pool <mbp@samba.org> + + * patches/: distcc-1.2.1-masquerade.patch, masquerade.patch: + Remove merged 'masquerade' patch. + +2003-03-10 10:07 Martin Pool <mbp@samba.org> + + * src/io.c: sendfile.h no longer needed here. Thanks to Wayne + Davison. + +2003-03-09 20:28 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Re-add "if your disks are too empty". + +2003-03-09 10:43 Martin Pool <mbp@samba.org> + + * configure.ac: Advance version to 1.3cvs. + +2003-03-09 10:14 Martin Pool <mbp@samba.org> + + * Makefile.in: Add ssh module to build. + +2003-03-08 22:48 Martin Pool <mbp@samba.org> + + * .cvsignore: Ignore =distcheck directory + +2003-03-08 21:53 Martin Pool <mbp@samba.org> + + * NEWS: Note about merged masquerade mode. + + * Reindent stuff. + +2003-03-08 21:47 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-03-08 10:43 Martin Pool <mbp@samba.org> + + * src/sendfile.c: Fix cast in call to sprintf for platforms where + ssize_t != int. Found on Alpha Linux in the hp Compaq + testdrive. + +2003-03-08 10:39 Martin Pool <mbp@samba.org> + + * src/implicit.c: Doc + +2003-03-08 10:29 Martin Pool <mbp@samba.org> + + * NEWS: Fix cast in call to sprintf for platforms where ssize_t + != int. Found on Alpha Linux in the hp Compaq testdrive. + +2003-03-05 13:02 Martin Pool <mbp@samba.org> + + * configure.ac, linuxdoc/distcc.sgml, src/distcc.c, src/exec.c, + src/exec.h, src/serve.c, src/util.c, src/util.h: masquerade patch + from Wayne Davison: + + * Add 'masquerade' option, where a link to distcc is created in + e.g. /usr/lib/distcc/bin/cc so that it can catch calls to 'cc'. + + * Check for getwd in configure + + * Update manual to document 'masquerade' + + * Update manual to say default port is 3632. + + * Document /MAX syntax in --help. + +2003-03-03 12:42 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-03-02 10:31 Martin Pool <mbp@samba.org> + + * configure.ac: Update for release. + +2003-03-02 09:52 Martin Pool <mbp@samba.org> + + * NEWS: Update for release. + +2003-03-01 23:54 Martin Pool <mbp@samba.org> + + * README.popt: URL for popt. + +2003-03-01 23:49 Martin Pool <mbp@samba.org> + + * src/: setuid.c, setuid.h: Fix constness of opt_user. + +2003-03-01 09:12 Martin Pool <mbp@samba.org> + + * src/lock.c, NEWS: SUSv3 says that locking functions can return + EACCES for contention. HP-UX does this; perhaps Cygwin does + too. + +2003-02-28 14:18 Martin Pool <mbp@samba.org> + + * configure.ac, NEWS: Check existence of ctype.h. Pointed out by + Tom Matelich. + +2003-02-28 14:15 Martin Pool <mbp@samba.org> + + * patches/masquerade.patch: Masquerade patch from Wayne Davison + +2003-02-28 10:45 Martin Pool <mbp@samba.org> + + * NEWS: Header for 1.2.3 release. + + * dcc_make_lock_filename: Windoze can't handle ':' in filenames. + Pointed out by Heiko Elger. + +2003-02-28 10:41 Martin Pool <mbp@samba.org> + + * src/lock.c: dcc_make_lock_filename: Windoze can't handle ':' in + filenames. Pointed out by Heiko Elger. + +2003-02-28 10:40 Martin Pool <mbp@samba.org> + + * src/lock.c: Doxygen janitor + +2003-02-28 08:02 Martin Pool <mbp@samba.org> + + * src/lock.c: Fix unreachable trace message. Thanks to Dimitri + Papadopoulos-Orfanos. + +2003-02-27 16:07 Martin Pool <mbp@samba.org> + + * Makefile.in: analog-resolve: Tweak jdresolve invocation + +2003-02-27 15:58 Martin Pool <mbp@samba.org> + + * Makefile.in: analog-resolve: Tweak jdresolve invocation + +2003-02-27 13:23 Martin Pool <mbp@samba.org> + + * patches/n_cpus.txt: n_cpus.txt Notes on determining NCPUs, from + Dimitri PAPADOPOULOS + +2003-02-27 13:14 Martin Pool <mbp@samba.org> + + * patches/connect-timeout-02.diff: connect-timeout-02.diff + Connection timeout patch from Oscar Esteban + +2003-02-27 13:09 Martin Pool <mbp@samba.org> + + * patches/connect-timeout.diff: connect-timeout.diff Connection + timeout patch from Oscar Esteban + +2003-02-27 12:52 Martin Pool <mbp@samba.org> + + * Makefile.in, OLDNEWS: Remove empty/dead OLDNEWS file. + +2003-02-27 12:36 Martin Pool <mbp@samba.org> + + * NEWS: Add missing release comments. + +2003-02-27 12:32 Martin Pool <mbp@samba.org> + + * NEWS: Add release date. + +2003-02-27 12:20 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc + +2003-02-27 12:18 Martin Pool <mbp@samba.org> + + * Makefile.in: Be more selective in uploading linuxdoc files. + +2003-02-27 11:52 Martin Pool <mbp@samba.org> + + * Makefile.in: Make distcheck should use $MAKE. + +2003-02-27 11:50 Martin Pool <mbp@samba.org> + + * Makefile.in: Distribute the uncompressed info file: this makes + patch across the source distribution work, and possibly helps + bzip2 compress the whole distribution. + +2003-02-27 11:38 Martin Pool <mbp@samba.org> + + * src/sendfile.c: Add HP-UX implementation of sys_sendfile, based + on a note from Tom Matelich and the manual. Not tested on an + HP-UX machine yet. + +2003-02-27 11:17 Martin Pool <mbp@samba.org> + + * Makefile.in: clirpc.h: New header + +2003-02-27 11:14 Martin Pool <mbp@samba.org> + + * Makefile.in, NEWS: Add a simple distcheck target. + +2003-02-27 11:10 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove deleted tests from $(test_SOURCE) + +2003-02-27 11:06 Martin Pool <mbp@samba.org> + + * Makefile.in: Fix command to remove dist dir before building. + +2003-02-27 10:25 Martin Pool <mbp@samba.org> + + * src/access.c: The FreeBSD manual suggests <sys/types.h> might + be needed here to make in_addr_t work. + +2003-02-27 10:20 Martin Pool <mbp@samba.org> + + * configure.ac: Check for stdint.h + +2003-02-27 10:18 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-02-27 10:17 Martin Pool <mbp@samba.org> + + * NEWS: Call this release 1.2.2. + + * Note about updated Makefile. + +2003-02-26 16:36 Martin Pool <mbp@samba.org> + + * test/: basecases.py, testdistcc.py: Move basecases back into + testdistcc + +2003-02-26 12:35 Martin Pool <mbp@samba.org> + + * test/: setuidcases.py, testdistcc.py: Splitting tests across + several files seems not to be a good idea at the moment. It + doesn't really make it easier to navigate. A new factoring is + desirable. + + * setuidcases.py merged back into testdistcc.py + +2003-02-26 12:33 Martin Pool <mbp@samba.org> + + * test/: EmptySource.py, ScanArgs.py, testdistcc.py: Splitting + tests across several files seems not to be a good idea at the + moment. It doesn't really make it easier to navigate. A new + factoring is desirable. + + * EmptySource.py, ScanArgs.py merged back into testdistcc.py + +2003-02-26 12:28 Martin Pool <mbp@samba.org> + + * test/ScanArgs.py: Remove RunCmd_Case, whose functionality has + now migrated up into ComfyChair. + +2003-02-26 12:27 Martin Pool <mbp@samba.org> + + * test/.cvsignore: Ignore ./testtmp/ if it happens to be here. + +2003-02-26 12:27 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Remove RunCmd_Case, whose functionality has + now migrated up into ComfyChair. + + * Add GPL. + +2003-02-26 12:25 Martin Pool <mbp@samba.org> + + * test/basecases.py: Remove RunCmd_Case, whose functionality has + now migrated up into ComfyChair. + +2003-02-26 12:22 Martin Pool <mbp@samba.org> + + * test/comfychair.py: runCmdNoWait: add missing "import os" + +2003-02-26 12:21 Martin Pool <mbp@samba.org> + + * test/comfychair.py: Copy from distcc HEAD + + * Make sure to print out any errors that happen while running + tests, not only the ComfyChair-specific exceptions. + +2003-02-26 12:18 Martin Pool <mbp@samba.org> + + * test/comfychair.py: Merge from tpot's comfychair HEAD checkin: + + * report failure to construct + + * add skip_on_noexec to runCmdUnchecked + +2003-02-26 12:13 Martin Pool <mbp@samba.org> + + * test/comfychair.py: Add GPL. + + * Add runCmdNoWait to run things in the background. + + * Don't use '+=' to support Python 1.5. + +2003-02-26 11:52 Martin Pool <mbp@samba.org> + + * NEWS: ./configure should not be removed by distclean, only by + maintainer-clean. + + * Make Makefile work with pmake + +2003-02-26 11:51 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove '$^' variable, which doesn't work with + pmake. + +2003-02-26 11:47 Martin Pool <mbp@samba.org> + + * Makefile.in: ./configure should not be removed by distclean, + only by maintainer-clean. + +2003-02-26 11:44 Martin Pool <mbp@samba.org> + + * Makefile.in: Change to old-style implicit rules, in the hope of + getting this to compile on non-GNU Make. + +2003-02-25 23:29 Martin Pool <mbp@samba.org> + + * src/ssh.c: More cleanups/merges. Still not working. + +2003-02-25 23:14 Martin Pool <mbp@samba.org> + + * src/ssh.c: Merge more code from rsync. Still not working. + +2003-02-25 23:10 Martin Pool <mbp@samba.org> + + * configure.ac: Add socketpair test from rsync. + +2003-02-25 22:50 Martin Pool <mbp@samba.org> + + * src/ssh.c: ssh.c Check in non-working skeleton ssh code from + rsync and cvs + +2003-02-25 22:37 Martin Pool <mbp@samba.org> + + * src/clinet.c: Doc + +2003-02-25 22:36 Martin Pool <mbp@samba.org> + + * src/trace.h: Don't use __FUNCTION__ if not building on gnuc. + +2003-02-25 22:26 Martin Pool <mbp@samba.org> + + * configure.ac, NEWS: Check for inet_aton in libresolv, which + might fix Solaris 2.6. + +2003-02-25 22:23 Martin Pool <mbp@samba.org> + + * src/distcc.c: Clear up unused vars + + * Doc + +2003-02-25 22:22 Martin Pool <mbp@samba.org> + + * NEWS, src/distcc.c: Avoid repeatedly locking localhost when + it's chosen from the host list, because we don't have reentrant + locks on Cygwin. + +2003-02-25 22:09 Martin Pool <mbp@samba.org> + + * src/distcc.c: Typo + +2003-02-25 22:08 Martin Pool <mbp@samba.org> + + * Makefile.in, src/clirpc.c, src/clirpc.h, src/distcc.c: Split + client RPC code into its own file to slim distcc.c. + +2003-02-25 22:04 Martin Pool <mbp@samba.org> + + * patches/distcc-1.2.1-masquerade.patch: Patch from Wayne Davison + to masquerade as cc. + +2003-02-25 22:01 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc + +2003-02-25 21:49 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version to 1.3cvs + +2003-02-25 21:26 Martin Pool <mbp@samba.org> + + * .cvsignore: Ignore linbot-report. + +2003-02-25 21:25 Martin Pool <mbp@samba.org> + + * Makefile.in: Delete directory used to make distribution tarball + before starting to build it. + +2003-02-25 21:23 Martin Pool <mbp@samba.org> + + * TODO: Notes about asprintf and Linuxdoc. + +2003-02-25 16:59 Martin Pool <mbp@samba.org> + + * NEWS: Note about libiberty redaction. + +2003-02-25 16:57 Martin Pool <mbp@samba.org> + + * NEWS, configure.ac: Update for 1.2.1 release. + +2003-02-25 16:51 Martin Pool <mbp@samba.org> + + * Makefile.in: Fix typo + +2003-02-25 16:48 Martin Pool <mbp@samba.org> + + * src/snprintf.c: Quieten compiler warning. + +2003-02-25 16:47 Martin Pool <mbp@samba.org> + + * configure.ac: Also check for snprintf + +2003-02-25 16:38 Martin Pool <mbp@samba.org> + + * src/arg.c: Fix small memory leak. + +2003-02-25 16:33 Martin Pool <mbp@samba.org> + + * src/exec.c: Remove dead function dcc_close_extra_fds. + +2003-02-25 16:28 Martin Pool <mbp@samba.org> + + * Makefile.in: Don't use "python -V" because it apparently + doesn't work on 1.5. Just look directly in sys.version. + +2003-02-25 16:14 Martin Pool <mbp@samba.org> + + * Makefile.in: Print Python version before running tests to help + in debugging remote problems. + +2003-02-25 16:08 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Remove unnecessary 'unittest' import + +2003-02-25 16:07 Martin Pool <mbp@samba.org> + + * test/testdistcc.py, NEWS: Return code from running the tests + now indicates whether they worked or not. + +2003-02-25 16:06 Martin Pool <mbp@samba.org> + + * test/comfychair.py: Refactor function + + * comfychair.runtests now returns a value that can be returned + from system.exit + +2003-02-25 15:53 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Remove += operator not supported in old + Pythons. + +2003-02-25 15:22 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Don't use fn(*tup) calling convention, + because it's not supported in earlier Python versions. Use + apply instead. + +2003-02-25 15:18 Martin Pool <mbp@samba.org> + + * configure.ac: Don't worry about -Winline, because nothing in + distcc is explicitly inlined. + +2003-02-25 15:14 Martin Pool <mbp@samba.org> + + * DEPENDENCIES: We need autoconf >=2.53 + +2003-02-25 15:13 Martin Pool <mbp@samba.org> + + * configure.ac: Check for vsnprintf as well. + +2003-02-25 15:06 Martin Pool <mbp@samba.org> + + * Makefile.in: Make sure snprintf.o actually gets linked in. + +2003-02-25 11:28 Martin Pool <mbp@samba.org> + + * src/lock.c: Include local declarations for asprintf if + necessary. + +2003-02-25 11:27 Martin Pool <mbp@samba.org> + + * Makefile.in, NEWS, configure.ac, src/h_hosts.c, src/hosts.c, + src/lock.c, src/tempfile.c, src/trace.c, src/where.c: Remove + libiberty asprintf. Might fix problems with headers on Solaris + and BSD. + + * Add asprintf etc from Samba HEAD. + + * Define _GNU_SOURCE in CPPFLAGS so that it is set for autoconf + tests. + + * Add configure test for C99-compliant vsnprintf from Samba HEAD. + +2003-02-25 11:07 Martin Pool <mbp@samba.org> + + * src/: snprintf.c, snprintf.h: Add *printf implementation from + Samba HEAD. + +2003-02-24 16:39 Martin Pool <mbp@samba.org> + + * configure.ac: Remove -Wredundant-decls, because it causes noise + with some system headers. + +2003-02-24 16:35 Martin Pool <mbp@samba.org> + + * configure.ac: Remove -W options that are implied by -Wall. + +2003-02-24 16:29 Martin Pool <mbp@samba.org> + + * Makefile.in: Include %.o target for Makes that have a wierd + built-in definition. + +2003-02-24 16:24 Martin Pool <mbp@samba.org> + + * NEWS: Add ansidecl.h from libiberty (from gdb-5.3) + +2003-02-24 16:20 Martin Pool <mbp@samba.org> + + * Makefile.in: Add ansidecl.h from libiberty (from gdb-5.3) + +2003-02-24 16:15 Martin Pool <mbp@samba.org> + + * NEWS: Update NEWS + +2003-02-24 16:12 Martin Pool <mbp@samba.org> + + * src/io.c: Remove redundant inclusion of assert.h + +2003-02-24 16:10 Martin Pool <mbp@samba.org> + + * configure.ac, Makefile.in: Try to find Python during + configuration. + +2003-02-24 15:56 Martin Pool <mbp@samba.org> + + * Makefile.in: Allow installation to complete even if the tools + to build Linuxdoc are missing. + +2003-02-24 15:05 Martin Pool <mbp@samba.org> + + * Makefile.in: installcheck needs to look in the build directory + as well as in the installed path to find the harness programs. + In the future perhaps there ought to be a subset of tests that + skips the harnesses. + +2003-02-24 14:58 Martin Pool <mbp@samba.org> + + * Makefile.in: Add "installcheck" target that can be called by + the buildfarm. + +2003-02-24 14:48 Martin Pool <mbp@samba.org> + + * configure.ac: Check autoconf >= 2.53 + + * Don't use AC_CONFIG_LIBOBJ_DIR because it's not in ac 2.53 + +2003-02-24 14:39 Martin Pool <mbp@samba.org> + + * configure.ac: FIXME + +2003-02-24 13:59 Martin Pool <mbp@samba.org> + + * autogen.sh: Merge back from the samba/HEAD autogen.sh 1.2, + which jerry updated to work on more systems, including RH7.2. + +2003-02-24 13:33 Martin Pool <mbp@samba.org> + + * NEWS: foo + +2003-02-24 13:19 Martin Pool <mbp@samba.org> + + * NEWS: foo + +2003-02-24 13:15 Martin Pool <mbp@samba.org> + + * NEWS: Dummy checkin to test build farm. + +2003-02-24 11:54 Martin Pool <mbp@samba.org> + + * NEWS: Dummy checkin to test build farm. + +2003-02-24 09:52 Martin Pool <mbp@samba.org> + + * configure.ac: Update version to 1.2.1cvs. + +2003-02-22 20:29 Martin Pool <mbp@samba.org> + + * NEWS: Get ready for 1.2 release. + +2003-02-22 20:22 Martin Pool <mbp@samba.org> + + * configure.ac: Set bug report address to the list, not me. + +2003-02-22 20:21 Martin Pool <mbp@samba.org> + + * configure.ac: Get ready for 1.2 release. + +2003-02-22 12:55 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove Docbook from distribution. + +2003-02-22 12:53 Martin Pool <mbp@samba.org> + + * Makefile.in: filename.h: New file. + +2003-02-22 12:41 Martin Pool <mbp@samba.org> + + * src/: arg.c, cpp.c, distcc.c, distcc.h, exec.c, exec.h, + filename.c, filename.h, hosts.c, implicit.c, lock.c, serve.c, + strip.c, trace.h: Cleanups to fix various gcc warnings. + +2003-02-22 12:20 Martin Pool <mbp@samba.org> + + * src/distcc.h: Remove redundant decls. + +2003-02-22 12:19 Martin Pool <mbp@samba.org> + + * configure.ac: Turn on more compiler warnings. + +2003-02-22 12:16 Martin Pool <mbp@samba.org> + + * TODO: Turn on more compiler warnings. + + * Note about statistics. + +2003-02-22 12:07 Martin Pool <mbp@samba.org> + + * src/hosts.c: Refactor code into new function + dcc_parse_localhost. + +2003-02-22 11:58 Martin Pool <mbp@samba.org> + + * src/hosts.c: Fix comments + +2003-02-22 11:56 Martin Pool <mbp@samba.org> + + * NEWS: Roll back to Linuxdoc for the manual. + +2003-02-22 11:37 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Ask people to report bugs to the mailing + list, not to me. + +2003-02-22 11:35 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: distcc.sgml Resurrect Linuxdoc manual + +2003-02-22 11:25 Martin Pool <mbp@samba.org> + + * Makefile.in: Use rsync --delete when uploading manual to delete + unneeded files. + +2003-02-22 11:12 Martin Pool <mbp@samba.org> + + * Makefile.in: Roll back to Linuxdoc for the manual. Docbook + tools seem to be still too unstable. + +2003-02-21 11:54 Martin Pool <mbp@samba.org> + + * Makefile.in: Add "links" web page + +2003-02-21 10:13 Martin Pool <mbp@samba.org> + + * patches/distcc-line3.diff: Patch from Tim Janik to absolutize + #line directives. + +2003-02-21 10:08 Martin Pool <mbp@samba.org> + + * doc/lca2003/slides/.cvsignore: Ignore built Postscript + +2003-02-21 10:05 Martin Pool <mbp@samba.org> + + * Makefile.in: Include additional Python files in distribution. + +2003-02-19 13:09 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: By default only one job is run locally now. + +2003-02-18 17:55 Martin Pool <mbp@samba.org> + + * NEWS: Postscript and PDF turned off for now. + +2003-02-18 17:44 Martin Pool <mbp@samba.org> + + * Makefile.in: Add target to build "nochunks" (one big page) + manual. + +2003-02-18 17:22 Martin Pool <mbp@samba.org> + + * Makefile.in: Add upload-usermanual target. + +2003-02-18 15:15 Martin Pool <mbp@samba.org> + + * Makefile.in: Put usermanual files correctly into distribution. + +2003-02-18 15:14 Martin Pool <mbp@samba.org> + + * Makefile.in: Add targets/rules to build, distribute and install + the Docbook-XML manual. + +2003-02-18 14:37 Martin Pool <mbp@samba.org> + + * doc/aoss2002/slides/: README.aoss2002, aoss4.mgp, flow.dia, + flow.png: Move AOSS2002 slides + +2003-02-14 15:40 Martin Pool <mbp@samba.org> + + * TODO: Add note about slow networks. + +2003-02-13 18:10 Martin Pool <mbp@samba.org> + + * src/where.c: Don't use XMIT locks for localhost, because there + is no transmission phase. + +2003-02-13 18:00 Martin Pool <mbp@samba.org> + + * src/distcc.c: Change completion message for remote compile to + "compile on FOO" rather than "gcc on FOO". Easier to grep for. + +2003-02-13 17:56 Martin Pool <mbp@samba.org> + + * src/hosts.c: /N syntax now *sets* the number of slots, rather + than setting a multiplier. + + * Default for localhost is now 1. + +2003-02-13 17:13 Martin Pool <mbp@samba.org> + + * src/hosts.c: Add HOST/NSLOTS syntax to limit number of tasks. + Patch from Rusty. + +2003-02-13 16:50 Martin Pool <mbp@samba.org> + + * src/where.c: dcc_lock_one: New implementation: + + The previous code was far too heavily biased towards the first + machine, because it tried to find any empty CPU slot there even + if + other machines were idle. Now, the outer loop is the slot + number, + and we try all hosts with at least that many slots. + + We acquire the CPU lock before getting the XMIT lock. + +2003-02-13 16:27 Martin Pool <mbp@samba.org> + + * src/where.c: Typo: didn't set CPU slot properly. + +2003-02-13 16:19 Martin Pool <mbp@samba.org> + + * src/: distcc.c, lock.c, where.c, where.h: Update new scheduler + to use two locks: one controlling access to the remote + machine's CPU, and one serializing the network connection to + the machine to avoid inadvertent synchronization. + +2003-02-13 15:52 Martin Pool <mbp@samba.org> + + * TODO: Add compiler warnings from Daniel Veilard + +2003-02-12 18:24 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Import new setuidcases module. + +2003-02-12 18:12 Martin Pool <mbp@samba.org> + + * test/setuidcases.py: New file to check --user option. + +2003-02-12 18:08 Martin Pool <mbp@samba.org> + + * test/comfychair.py: require(), require_root(): New functions + that causes a test to be skipped unless particular conditions + are met. + +2003-02-12 17:46 Martin Pool <mbp@samba.org> + + * test/comfychair.py: Merge from comfychair CVS + +2003-02-11 11:18 Martin Pool <mbp@samba.org> + + * src/lock.c: Fixme. + +2003-02-07 21:17 Martin Pool <mbp@samba.org> + + * src/: distcc.c, where.c, where.h: Rename dcc_pick_buildhost to + dcc_pick_host_from_env + +2003-02-05 23:11 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-02-05 23:07 Martin Pool <mbp@samba.org> + + * Makefile.in: Don't delete config.status with plain "make + clean", because it's really at the same level as the Makefile. + +2003-02-05 23:05 Martin Pool <mbp@samba.org> + + * src/bulk.c, NEWS: Add O_BINARY bit needed for Cygwin. Based on + a patch from Helind. + +2003-02-05 22:43 Martin Pool <mbp@samba.org> + + * DEPENDENCIES: Note about dietlibc. + +2003-02-05 22:41 Martin Pool <mbp@samba.org> + + * Makefile.in: Update "*clean" targets: cleaning should remove + configure state files; maintainer-clean should remove all + autoconf files that can be regenerated. + + From a patch by Paul Russell. + +2003-02-05 21:52 Martin Pool <mbp@samba.org> + + * TODO: Note about manpages. + +2003-02-05 19:14 Martin Pool <mbp@samba.org> + + * src/distcc.h: opt_allowed needs to be declared extern. Found + by tcc. + +2003-02-05 19:11 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-02-05 19:10 Martin Pool <mbp@samba.org> + + * src/io.c: Change assert to trace call to make dietlibc happy + +2003-02-05 19:08 Martin Pool <mbp@samba.org> + + * src/clinet.c: fixme + +2003-02-04 23:02 Martin Pool <mbp@samba.org> + + * src/where.c: Cleanup comments. + +2003-02-04 22:58 Martin Pool <mbp@samba.org> + + * NEWS, src/bulk.c, src/bulk.h, src/distcc.c, src/serve.c: Show + timing on transmission of DOTI and DOTO files. + +2003-02-04 22:48 Martin Pool <mbp@samba.org> + + * src/bulk.c: Remove dcc_r_fifo, which is no longer called + because we no longer support feeding the compiler from a fifo. + +2003-02-04 19:58 Martin Pool <mbp@samba.org> + + * Makefile.in, src/bulk.c, src/bulk.h, src/distcc.c, src/serve.c: + Show transfer rate for transmitted files. + +2003-02-04 19:55 Martin Pool <mbp@samba.org> + + * src/: timeval.c, timeval.h: Add GNU function for calculating + the difference between timevals. + +2003-02-04 19:29 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-02-04 19:21 Martin Pool <mbp@samba.org> + + * configure.ac: Add ./lib to include path so libiberty.h can be + found. + +2003-02-03 12:50 Martin Pool <mbp@samba.org> + + * src/rpc.h: Doc + +2003-02-03 12:49 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-02-03 01:15 Martin Pool <mbp@samba.org> + + * doc/new-scheduler.txt: Notes on new scheduler + +2003-02-03 00:59 Martin Pool <mbp@samba.org> + + * NEWS: Describe new scheduling algorithm. + +2003-02-03 00:44 Martin Pool <mbp@samba.org> + + * src/where.c: Better message + +2003-02-03 00:43 Martin Pool <mbp@samba.org> + + * src/distcc.c: Fixme + +2003-02-03 00:28 Martin Pool <mbp@samba.org> + + * src/where.c: Doc + +2003-02-03 00:27 Martin Pool <mbp@samba.org> + + * src/distcc.c: Hold transmit lock only while sending request. + +2003-02-03 00:27 Martin Pool <mbp@samba.org> + + * src/where.c: Doc + +2003-02-03 00:27 Martin Pool <mbp@samba.org> + + * src/: lock.c, lock.h: (dcc_unlock): New function. + +2003-02-03 00:13 Martin Pool <mbp@samba.org> + + * src/: distcc.c, lock.c, lock.h, where.c, where.h: Lock + functions pass back their fd so that it can be released later. + + * (dcc_lock_host): Clean up error handling. + +2003-02-03 00:06 Martin Pool <mbp@samba.org> + + * src/lock.h: Add lock_fd parameter to dcc_lock_host and + dcc_lock_local functions + +2003-02-03 00:04 Martin Pool <mbp@samba.org> + + * src/lock.c: Doc + +2003-02-03 00:04 Martin Pool <mbp@samba.org> + + * src/lock.c: Remove redundant dcc_get_tempdir call. + +2003-02-03 00:03 Martin Pool <mbp@samba.org> + + * src/lock.c: Split lockfile creation into dcc_open_lockfile + +2003-02-03 00:01 Martin Pool <mbp@samba.org> + + * src/: where.c, where.h: Document locking system. + + * Add a "lockname" parameter to allow for multiple locks in the + future. + + * WORK IN PROGRESS: Start moving towards new transmission-based + locking, where we hold the lock only while sending. Not done + yet. + +2003-02-03 00:00 Martin Pool <mbp@samba.org> + + * src/: lock.c, lock.h: Document locking system. + + * Add a "lockname" parameter to allow for multiple locks in the + future. + +2003-02-02 23:44 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove linuxdoc targets from the Makefile to allow + for transition to Docbook. Docbook manual is not built yet + because of issues with Debian's xsltproc. + +2003-02-02 23:34 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-02-02 23:31 Martin Pool <mbp@samba.org> + + * Makefile.in: Add README.libiberty to distributed files. + +2003-02-02 23:31 Martin Pool <mbp@samba.org> + + * README.libiberty: Check in some files from libiberty. + +2003-02-02 23:30 Martin Pool <mbp@samba.org> + + * src/lock.c: (dcc_lock_host): Add doc. + + Change "already locked" to less ambiguous "%s is busy". + + Update to use standard exit codes. + +2003-02-02 23:24 Martin Pool <mbp@samba.org> + + * src/exitcode.h: Add EXIT_BUSY. + +2003-02-02 22:56 Martin Pool <mbp@samba.org> + + * src/lock.c: Use libiberty for asprintf(). + + * (dcc_make_lock_filename): Rewrite to use asprintf() rather than + a fixed-length buffer. Safer and simpler. + + Lock filenames now take into account the port as well as the + hostname, and it supports ssh schemes. + +2003-02-02 22:54 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-02-02 22:48 Martin Pool <mbp@samba.org> + + * Makefile.in: Include libiberty source in distribution. + +2003-02-02 22:48 Martin Pool <mbp@samba.org> + + * configure.ac: Add lib/ directory + + * Check for asprintf() and vasprintf() and replace them if not + present. + +2003-02-02 22:06 Martin Pool <mbp@samba.org> + + * TODO: Notes on Docbook. + + * Notes on a minimal gcc for clients. + +2003-02-02 16:30 Martin Pool <mbp@samba.org> + + * linuxdoc/: distcc.sgml, footer.html: Remove Linuxdoc + documentation now that it's been converted to Docbook XML + +2003-02-02 16:30 Martin Pool <mbp@samba.org> + + * NEWS: Note conversion of user manual. + +2003-02-02 16:18 Martin Pool <mbp@samba.org> + + * patches/timj-line1.diff: Patch from Tim Janik to post-process + the preprocessor output to absolutify file names. It works and + it's nicely written, but I'm not yet convinced that the benefit + is justified. + +2003-02-02 14:38 Martin Pool <mbp@samba.org> + + * src/.cvsignore: Don't ignore .d and .i files, since they + shouldn't be generated anymore. + +2003-02-02 14:37 Martin Pool <mbp@samba.org> + + * Makefile.in, contrib/distcc-absolutify, contrib/netpwd, + contrib/stage-cc-wrapper.patch: Additional contributed scripts + by Alexandre Oliva useful in building gcc using distcc. From + his mail of 14 Aug 2002. + +2003-01-31 15:03 Martin Pool <mbp@samba.org> + + * src/where.c: Doc + +2003-01-31 11:48 Martin Pool <mbp@samba.org> + + * analog/.cvsignore: Ignore generated files. + +2003-01-31 11:17 Martin Pool <mbp@samba.org> + + * TODO: Notes on corks, scheduling, and tcp options. + +2003-01-31 10:56 Martin Pool <mbp@samba.org> + + * TODO: Notes about scheduling from BBQ + +2003-01-31 10:42 Martin Pool <mbp@samba.org> + + * TODO: Note about #pragma implementation + +2003-01-29 15:52 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Grammar fixes. + +2003-01-29 12:14 Martin Pool <mbp@samba.org> + + * src/dopt.c: (distccd_show_usage): Remove vestigial argument to + printf + + * (distccd_parse_options): Fix return code handling + + * Doc + +2003-01-29 00:52 Martin Pool <mbp@samba.org> + + * Makefile.in: Typo + +2003-01-29 00:50 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: TODO + +2003-01-29 00:49 Martin Pool <mbp@samba.org> + + * src/: access.h, distcc.h, dopt.c, srvnet.c: Add --allow, -a + option to distccd. Build up a list of allowed client + addresses. Check against them when a client connects; drop the + connection if it's not allowed. + +2003-01-29 00:46 Martin Pool <mbp@samba.org> + + * NEWS: Note new --allow option. + +2003-01-29 00:19 Martin Pool <mbp@samba.org> + + * src/: access.c, access.h, h_parsemask.c: Add code to actually + check whether access ought to be allowed. + +2003-01-29 00:08 Martin Pool <mbp@samba.org> + + * src/: access.c, access.h, h_parsemask.c: Start adding IP-based + access control. So far, a function to parse matchers like + 10.0.0.0/8. + +2003-01-29 00:07 Martin Pool <mbp@samba.org> + + * Makefile.in, .cvsignore: Add new h_parsemask test harness. + +2003-01-29 00:02 Martin Pool <mbp@samba.org> + + * doc/lca2003/slides/: .cvsignore, distcc-lca2003.mgp, flow.dia, + flow.png: Add LCA2003 slides. + +2003-01-28 23:14 Martin Pool <mbp@samba.org> + + * Makefile.in: Add access.c and access.h + +2003-01-28 19:57 Martin Pool <mbp@samba.org> + + * NEWS, src/exec.c: * Use putenv() rather than setenv() to fit + into SUSv2 and work on Solaris + 8. Pointed out by Dimitri Papadopoulos. + +2003-01-28 19:52 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: TODO + +2003-01-28 01:24 Martin Pool <mbp@samba.org> + + * src/access.c: Empty file + +2003-01-28 01:21 Martin Pool <mbp@samba.org> + + * src/lock.c: Doc + +2003-01-28 01:19 Martin Pool <mbp@samba.org> + + * src/dopt.c: Fix string syntax problem. + +2003-01-28 01:18 Martin Pool <mbp@samba.org> + + * configure.ac: Version to 1.2cvs + +2003-01-28 01:18 Martin Pool <mbp@samba.org> + + * src/help.c: Please send bugs to the mailing list + +2003-01-28 01:17 Martin Pool <mbp@samba.org> + + * src/help.c: Update copyright + +2003-01-28 01:06 Martin Pool <mbp@samba.org> + + * Makefile.in: Add missing Python source. + +2003-01-28 01:05 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-01-28 01:01 Martin Pool <mbp@samba.org> + + * src/: dparent.c, daemon.c: srvnet.h: new header + +2003-01-28 00:56 Martin Pool <mbp@samba.org> + + * NEWS, configure.ac: Update for 1.1 + +2003-01-28 00:52 Martin Pool <mbp@samba.org> + + * NEWS: Updates to manual + +2003-01-28 00:21 Martin Pool <mbp@samba.org> + + * analog/extract_version_downloads.py: Simple script to show the + number of downloads of each version. + +2003-01-27 23:23 Martin Pool <mbp@samba.org> + + * src/lock.c: Doc + +2003-01-27 23:19 Martin Pool <mbp@samba.org> + + * TODO: Note about taking host list from a file. + +2003-01-27 23:16 Martin Pool <mbp@samba.org> + + * src/distcc.h: New srvnet.h header + +2003-01-27 23:16 Martin Pool <mbp@samba.org> + + * patches/andresen-gcc-wrapper-r2.tbz2: Patch from Eric Andresen + for Gentoo bug #13897 to add some kind of wrapper. + +2003-01-27 23:13 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doxygen cleanups + +2003-01-27 23:11 Martin Pool <mbp@samba.org> + + * src/dparent.c: Just refuse root once at the top level of + distccd. We don't support binding reserved ports so there's no + need to do it any later as far as I can see. + +2003-01-27 23:06 Martin Pool <mbp@samba.org> + + * src/dopt.c: Doc + + * Add new --user option. Warning is printed if this is used when + not started by root. + + * Sort option table into alphabetical order. + +2003-01-27 23:03 Martin Pool <mbp@samba.org> + + * src/: exec.h, exec.c: Doc + +2003-01-27 23:01 Martin Pool <mbp@samba.org> + + * src/exitcode.h: Give the exitcode enum a name + + * Add EXIT_SETUID_FAILED and EXIT_ACCESS_DENIED + +2003-01-27 22:59 Martin Pool <mbp@samba.org> + + * src/hosts.h: Fix Doxygen glitch + +2003-01-27 22:58 Martin Pool <mbp@samba.org> + + * src/io.c: Split sendfile wrappers out into src/sendfile.c + +2003-01-27 22:55 Martin Pool <mbp@samba.org> + + * src/: setuid.c, setuid.h: New code for discarding privileges + when run by root. + +2003-01-27 22:54 Martin Pool <mbp@samba.org> + + * src/serve.c: src/srvnet.h: New header + + * Log client name (and in the future, check access) very early in + connection handling. + + * Doc. + +2003-01-27 22:53 Martin Pool <mbp@samba.org> + + * src/trace.h: Update Doxygen. + +2003-01-27 22:50 Martin Pool <mbp@samba.org> + + * src/util.h: Move srvnet functions to srvnet.h + +2003-01-27 22:41 Martin Pool <mbp@samba.org> + + * src/util.c: Message when exiting should always just be level + 'info'. + + * Just show 4 decimal places in time measurements. Higher than + that may not be very meaningful. + +2003-01-27 22:36 Martin Pool <mbp@samba.org> + + * src/srvnet.c: src/srvnet.h: New header + + * Doc + + * Prepare for IP access-control checks + +2003-01-27 22:35 Martin Pool <mbp@samba.org> + + * src/srvnet.h: src/srvnet.h: New header + +2003-01-27 22:33 Martin Pool <mbp@samba.org> + + * src/sendfile.c: Move sendfile support into sendfile.c + + * Doc + + * Better handling of unsupported systems + +2003-01-27 22:30 Martin Pool <mbp@samba.org> + + * Makefile.in: src/sendfile.c: Split sendfile into a separate + source file + + * src/setuid.c, src/setuid.h: Add new ability to change persona + when started by root + + * src/srvnet.h: Move server-side network functions to their own + file. + +2003-01-27 22:28 Martin Pool <mbp@samba.org> + + * src/daemon.c: Update Doxygen tags + + * Remove unneeded headers + + * Discard root privileges if we have them. + +2003-01-27 22:27 Martin Pool <mbp@samba.org> + + * src/: arg.c, clinet.c: Update Doxygen tags + +2003-01-27 22:25 Martin Pool <mbp@samba.org> + + * NEWS: tcpwrappers isn't in after all, because it's poorly + documented and I'm not convinced it's a good fit for distccd. + For example, it can only normally be configured by root, but we + want to make sure that distccd can be installed and run by + ordinary users. + +2003-01-27 22:24 Martin Pool <mbp@samba.org> + + * bench/: Build.py, Project.py: Better messages while build is in + progress. + +2003-01-27 22:23 Martin Pool <mbp@samba.org> + + * bench/ProjectDefs.py: Point at glibc 2.3.1 rather than 2.3 in + the hope that this will work better. (It doesn't build yet + unfortunately.) + +2003-01-27 22:21 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-01-27 22:21 Martin Pool <mbp@samba.org> + + * README.packaging: Please use shlibs + + * Please use proper gcc names + +2003-01-27 22:18 Martin Pool <mbp@samba.org> + + * configure.ac: Doc + + * Fix help string for --with-included-popt + + * Some cleanups + + * Look for setgroups() + +2003-01-27 22:17 Martin Pool <mbp@samba.org> + + * NEWS, OLDNEWS: Update NEWS for recent commits + + * Keep all change notes in the NEWS file per GNU standards. + OLDNEWS is now empty. + +2003-01-27 22:15 Martin Pool <mbp@samba.org> + + * README: Update performance for current project status + +2003-01-27 22:12 Martin Pool <mbp@samba.org> + + * TODO: Many TODO updates. + +2003-01-27 22:06 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc + +2003-01-27 21:49 Martin Pool <mbp@samba.org> + + * .cvsignore, Doxyfile: Add Doxygen configuration. Not called + from Makefile. + +2003-01-27 21:35 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Just show CVS date, not version. + + * Update to version 1.1. + + * Update: distccd now sends error messages back to the client as + well as to its local log file. + + * Remove "author" section left over from man page. + + * Describe --verbose option. + + * Add description of new EXIT_RECURSION code + + * Move "Compatibility" section into a new chapter. + + * Move "Cross compilation" into a new chapter, because it's not + relevant to many users. + + * Reformat Huxley quote to make it fit better. + + * Rearrange introduction. + + * Warning not to use --no-fork. + + * Document --no-detach. + +2003-01-24 20:16 Martin Pool <mbp@samba.org> + + * NEWS, src/srvnet.c: Don't log client hostname, only the IP + address. It's not really necessary and can slow us down. + +2003-01-24 20:08 Martin Pool <mbp@samba.org> + + * NEWS, src/distcc.c, src/distcc.h, src/exec.c, src/exec.h, + src/exitcode.h: Add environment variable to check for + inadvertent recursion. + +2003-01-24 20:03 Martin Pool <mbp@samba.org> + + * bench/buildutil.py: Better error message for command failures + +2003-01-24 19:54 Martin Pool <mbp@samba.org> + + * NEWS: Add check for inadvertent recursion + +2003-01-24 19:52 Martin Pool <mbp@samba.org> + + * TODO: Many updates to TODO + +2003-01-24 19:51 Martin Pool <mbp@samba.org> + + * bench/compiler.py: Don't explicitly say "gcc-3.2", because it's + not available under that name on Red Hat 8.0. + +2003-01-20 11:22 Martin Pool <mbp@samba.org> + + * NEWS, configure.ac: Fix configure test for hstrerror(). + (Frerich Raabe) + +2003-01-19 20:50 Martin Pool <mbp@samba.org> + + * bench/Summary.py: Fix bugs in printing statistics. + +2003-01-19 20:29 Martin Pool <mbp@samba.org> + + * bench/buildutil.py: Better formatting time messages. + +2003-01-19 20:27 Martin Pool <mbp@samba.org> + + * bench/Summary.py: Better handling of statistics generation or + build failures. + +2003-01-19 18:45 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc. + +2003-01-19 18:43 Martin Pool <mbp@samba.org> + + * test/: ScanArgs.py, basecases.py, testdistcc.py: Split some + Python classes out into separate files. + +2003-01-19 18:19 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc. + +2003-01-19 15:10 Martin Pool <mbp@samba.org> + + * src/dopt.c: Remove ifdef'd code. + +2003-01-18 23:57 Martin Pool <mbp@samba.org> + + * configure.ac: TODO about finding Python. + +2003-01-18 23:55 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Roll back change to version number format. + +2003-01-18 23:48 Martin Pool <mbp@samba.org> + + * src/: .cvsignore, config.h.in: Build config.h.in, rather than + storing in CVS. + +2003-01-18 23:46 Martin Pool <mbp@samba.org> + + * src/io.c, NEWS: Flag platforms that have a sendfile() function, + but that aren't explicitly supported, because it seems to vary + substantially. At the moment only FreeBSD and Linux are known. + +2003-01-18 23:43 Martin Pool <mbp@samba.org> + + * configure.ac: Fix text formatting. + +2003-01-18 23:41 Martin Pool <mbp@samba.org> + + * test/testdistcc.py, NEWS: Be less strict in checking the output + from the plain text preprocessor, because this seems to have + changed in gcc 3.2. + +2003-01-18 23:36 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Update copyright + + * Allow for new --version output + + * Fix accidental extra newline in C source, when we wanted the + escape sequence "\n" + + * Change way the preprocessor is called -- not working yet. + +2003-01-18 22:53 Martin Pool <mbp@samba.org> + + * .cvsignore: Ignore files produced by autoconf. + +2003-01-18 22:51 Martin Pool <mbp@samba.org> + + * bench/benchmark.py, NEWS: Projects can now be selected by + unambiguous name prefix + +2003-01-18 22:39 Martin Pool <mbp@samba.org> + + * configure.ac: Update copyright + +2003-01-18 22:38 Martin Pool <mbp@samba.org> + + * config.guess, config.sub: Update from Debian autotools-dev + +2003-01-18 22:27 Martin Pool <mbp@samba.org> + + * config.sub: Resurrect + +2003-01-18 22:22 Martin Pool <mbp@samba.org> + + * bench/: Build.py, Summary.py, actions.py, benchmark.py, + statistics.py: Make std dev and variance methods handle + too-short sequences by returning None, rather than failing. + + * Add -n option to run benchmarks repeatedly. + +2003-01-18 22:21 Martin Pool <mbp@samba.org> + + * aclocal.m4, config.guess, config.sub, configure: Stop storing + autoconf junk in CVS + +2003-01-18 22:19 Martin Pool <mbp@samba.org> + + * TODO: Need to document benchmark. + +2003-01-18 22:10 Martin Pool <mbp@samba.org> + + * Makefile.in: Invite people to pass BENCH_ARGS to Make to + control the benchmark. + +2003-01-18 22:02 Martin Pool <mbp@samba.org> + + * Makefile.in: Include bench/statistics.py in distribution. + +2003-01-18 22:00 Martin Pool <mbp@samba.org> + + * bench/Summary.py, bench/statistics.py, NEWS: Start to add + support in the Summary class for repeated runs of a benchmark, + plus a new "statistics" library containing code to do mean and + std dev. + +2003-01-18 21:50 Martin Pool <mbp@samba.org> + + * NEWS: Roll over news + +2003-01-18 21:49 Martin Pool <mbp@samba.org> + + * OLDNEWS: Put in correct version of old news file. + +2003-01-18 21:36 Martin Pool <mbp@samba.org> + + * OLDNEWS: Roll over NEWS. + +2003-01-17 12:05 Martin Pool <mbp@samba.org> + + * configure, configure.ac: Bump version to 1.1cvs + +2003-01-17 12:00 Martin Pool <mbp@samba.org> + + * src/daemon.c: FIXME about running as root. + +2003-01-17 11:37 Martin Pool <mbp@samba.org> + + * src/daemon.c: fixme + +2003-01-16 11:36 Martin Pool <mbp@samba.org> + + * configure: Prepare for 1.0 release. + +2003-01-16 11:32 Martin Pool <mbp@samba.org> + + * configure.ac: Prepare for 1.0 release. + +2003-01-16 11:28 Martin Pool <mbp@samba.org> + + * NEWS, configure.ac: Prepare for 1.0 release. + +2003-01-16 11:06 Martin Pool <mbp@samba.org> + + * Makefile.in: Include benchmark source in tarball. + + * bzip tarball rather than gzipping it, to save a little space. + +2003-01-15 22:22 Martin Pool <mbp@samba.org> + + * bench/benchmark.py: Doc + +2003-01-14 16:25 Martin Pool <mbp@samba.org> + + * NEWS: Build .bz2 tarball rather than .tgz + + * Remove PS and PDF from tarball. + +2003-01-14 16:03 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2003-01-14 15:46 Martin Pool <mbp@samba.org> + + * Makefile.in: Do not include PDF or PS in the tarball, or + install them by default. This may save some space in the + distribution. They can be built from source using the Linuxdoc + tool, or downloaded. + +2003-01-14 15:03 Martin Pool <mbp@samba.org> + + * Makefile.in: Resolve logfile lines in order. + +2003-01-14 15:01 Martin Pool <mbp@samba.org> + + * bench/.cvsignore: Ignore bench.log + +2003-01-14 00:54 Martin Pool <mbp@samba.org> + + * src/io.c: Correct calling of sendfile on BSD + +2003-01-13 14:47 Martin Pool <mbp@samba.org> + + * TODO: [no log message] + +2003-01-13 12:24 Martin Pool <mbp@samba.org> + + * Makefile.in: Benchmark must be run from bench/ directory. + +2003-01-12 23:59 Martin Pool <mbp@samba.org> + + * bench/Summary.py: Show uname in summary. + +2003-01-12 23:51 Martin Pool <mbp@samba.org> + + * bench/Summary.py: Show uname in summary. + +2003-01-12 23:40 Martin Pool <mbp@samba.org> + + * bench/Project.py: Doc snarf bug. + +2003-01-12 23:24 Martin Pool <mbp@samba.org> + + * Makefile.in, NEWS: * Remove Plucker file: nobody seems to be + downloading it, and it's + easy enough for people to build if they're interested. + +2003-01-12 23:09 Martin Pool <mbp@samba.org> + + * bench/Summary.py: Store results into Summary in the order in + which they are generated. + +2003-01-12 23:05 Martin Pool <mbp@samba.org> + + * bench/: Build.py, actions.py: Add action to "make clean" if + desired. Off by default. + +2003-01-12 22:58 Martin Pool <mbp@samba.org> + + * bench/: Build.py, CompilerSpec.py, benchmark.py, compiler.py: + Add -c option to specify compilers to run. + + * Remove 'CompilerSpec' module to 'compiler' so that it can more + easily have some static methods. + +2003-01-12 22:43 Martin Pool <mbp@samba.org> + + * bench/Summary.py: Print a heading on the results, plus the date + and the host list. + +2003-01-12 22:37 Martin Pool <mbp@samba.org> + + * bench/: actions.py, benchmark.py: Split intelligence about + action selection into a new module. + + * Auto-generation action help table. + + * Turn 'scrub' off by default. + +2003-01-12 22:20 Martin Pool <mbp@samba.org> + + * bench/: Summary.py, buildutil.py: Show all times in %.4f format + -- about the right amount of precision. + +2003-01-12 22:18 Martin Pool <mbp@samba.org> + + * bench/: Build.py, Project.py, benchmark.py: Put intelligence + about running various Actions in order into the Build and + Project classes. + + * More --help documentation for actions. + +2003-01-12 22:10 Martin Pool <mbp@samba.org> + + * bench/: Build.py, Project.py, Summary.py, benchmark.py, + buildutil.py: Further refactoring: put the combination of a + project and a compiler into a new Build object. + + * Put each Build in a separate directory, rather than using one + directory per Project that is overwritten every time. More scope + now for retrying or investigating failed builds. + +2003-01-12 22:09 Martin Pool <mbp@samba.org> + + * bench/CompilerSpec.py: Don't use commas in directory names + because it causes trouble with some Makefiles. + +2003-01-12 21:43 Martin Pool <mbp@samba.org> + + * bench/Project.py: Doc + +2003-01-12 21:38 Martin Pool <mbp@samba.org> + + * bench/: CompilerSpec.py, benchmark.py: Split CompilerSpec into + its own file. + +2003-01-12 21:32 Martin Pool <mbp@samba.org> + + * bench/: Project.py, ProjectDefs.py, Summary.py, benchmark.py: + Split Project class and project definitions out into two new + source files. + + * Rename Compiler to CompilerSpec and change name format. + +2003-01-12 20:50 Martin Pool <mbp@samba.org> + + * bench/: Summary.py, benchmark.py: Split Summary class out into + its own file, and print summaries out in a tabular form rather + than as Python data definitions. + +2003-01-12 20:50 Martin Pool <mbp@samba.org> + + * bench/.cvsignore: Ignore download directory and .pyc files. + +2003-01-09 11:06 Martin Pool <mbp@samba.org> + + * bench/benchmark.py: Run snarf quietly + + * Doc + +2003-01-08 18:28 Martin Pool <mbp@samba.org> + + * bench/benchmark.py: Add GNU Hello so that there's something + small for testing the benchmark program. + + * Add --list-projects option. + + * Allow selection of actions to perform with --actions=ACTIONS. + +2003-01-08 18:03 Martin Pool <mbp@samba.org> + + * bench/benchmark.py: Push mainline code into a main() routine. + +2003-01-08 18:01 Martin Pool <mbp@samba.org> + + * bench/benchmark.py: Add Project configuration for Wine + + * Implement the 'unpacked_subdir' Project option, to handle + projects like Wine whose unpacked directory is named + differently from the tarball. + + * Doc. + +2003-01-06 15:53 Martin Pool <mbp@samba.org> + + * bench/benchmark.py: Doc + +2003-01-06 11:24 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2003-01-06 11:24 Martin Pool <mbp@samba.org> + + * Makefile.in: Split old news items out into a separate page. + +2003-01-02 19:52 Martin Pool <mbp@samba.org> + + * NEWS: Doc macrobenchmark. + +2003-01-02 16:31 Martin Pool <mbp@samba.org> + + * TODO: Explanation of KDE's --enable-final option, and impact on + parallelism. + + * Half explain "Supermarket scheduler" idea. + + * Half explain load balancer. + +2003-01-02 15:58 Martin Pool <mbp@samba.org> + + * DEPENDENCIES: Add notes about macrobenchmark. + +2003-01-01 10:01 Martin Pool <mbp@samba.org> + + * Makefile.in: Add new "benchmark" target to invoke the + macrobenchmark suite. The Makefile prints a notice and checks + that the hosts are set up before starting the script. + +2003-01-01 09:24 Martin Pool <mbp@samba.org> + + * bench/benchmark.py: Use env(1) to find python2.2. (Frerich + Raabe) + + Really the right way is to call through the Makefile to use + $(PYTHON). + +2003-01-01 09:22 Martin Pool <mbp@samba.org> + + * bench/: benchmark, benchmark.py: Rename bench/benchmark to + bench/benchmark.py. + +2003-01-01 09:19 Martin Pool <mbp@samba.org> + + * Makefile.in: Use a $(PYTHON) variable so that it can be + overridden if the name varies. + +2002-12-17 17:17 Martin Pool <mbp@samba.org> + + * news.el, news.emacs: Store settings in elisp rather than as + mode variables. + +2002-12-17 10:27 Martin Pool <mbp@samba.org> + + * bench/benchmark: If a build fails, then record that but + continue. If the overall build is interrupted, just stop. + +2002-12-16 21:29 Martin Pool <mbp@samba.org> + + * bench/benchmark: Doc + + * Better link for kernel + +2002-12-16 21:21 Martin Pool <mbp@samba.org> + + * bench/benchmark: Add gdb + + * Add md5sum and configure command for linux-2.4.20 + + * Automatically detect and resume interrupted downloads. Do + downloads into a temporary directory and move them on + completion. + +2002-12-16 21:15 Martin Pool <mbp@samba.org> + + * bench/benchmark: b* Project._rm_files: Do this silently and only + as necessary. + +2002-12-16 21:12 Martin Pool <mbp@samba.org> + + * bench/benchmark: Remove log files at the start of a build. (We + use separate logfiles for each case and phase, so this loses no + information.) + +2002-12-16 21:08 Martin Pool <mbp@samba.org> + + * bench/benchmark: Rename /SourceTree/Project/ + +2002-12-16 21:07 Martin Pool <mbp@samba.org> + + * bench/benchmark: Doc. + + * Just check for download once when we start working on a + project. + + * Scrub the tree just once when finished on a project. + +2002-12-16 21:03 Martin Pool <mbp@samba.org> + + * bench/benchmark: Doc. + + * Add MD5 for GIMP. + + * When configuring GIMP, turn off Perl support because it seems + not to work on Sid and it's not really necessary. + +2002-12-16 20:59 Martin Pool <mbp@samba.org> + + * bench/benchmark: Scrub source directories after successful + build to save disk space. + + * Try boring slow gcc build first, to see if it works. + +2002-12-16 20:50 Martin Pool <mbp@samba.org> + + * bench/benchmark: Doc + +2002-12-16 20:43 Martin Pool <mbp@samba.org> + + * bench/benchmark: SourceTree.build: Accumulate statistics in + Summary object on completion of building. Fix syntax error. + + * Take list of project names from command line. If none are + specified, build all known projects. + +2002-12-16 20:38 Martin Pool <mbp@samba.org> + + * bench/benchmark: SourceTree.run_cmd: Return status and elapsed + time. + + * SourceTree.build: Remove obsolete make_args argument. + + * Summary: New class holding overall results of building. + +2002-12-16 20:34 Martin Pool <mbp@samba.org> + + * bench/benchmark: Doc. + + * Try to make shell commands more readable. + + * Add GIMP URL. + +2002-12-16 20:24 Martin Pool <mbp@samba.org> + + * bench/benchmark: Store separate make and distcc logs for + configuring and building, in a per-project per-compiler + directory. DISTCC_LOG no longer needs to be set beforehand. + + * Add more MD5sums. + + * Add correct configuration and build commands for the kernel. + +2002-12-16 20:15 Martin Pool <mbp@samba.org> + + * bench/benchmark: Add new Compiler class, encapsulating $(CC) + and Make options. + + * Add URLs for GNU Make and Linux-2.4.20. + + * Store build logs into a directory identified by both project + and compiler. + +2002-12-16 19:59 Martin Pool <mbp@samba.org> + + * bench/benchmark: Add support for packages which need to be + built from a subdirectory of their unpacked directory. In + particular, Samba needs to be built from "samba-2.2.7/source". + +2002-12-16 19:54 Martin Pool <mbp@samba.org> + + * bench/benchmark: Add MD5 sums for other packages. + + * Add Samba tree. (Doesn't work yet, needs a different configure + command to handle source being in source/) + +2002-12-16 19:49 Martin Pool <mbp@samba.org> + + * bench/.cvsignore: Ignore output files. + +2002-12-16 19:48 Martin Pool <mbp@samba.org> + + * bench/benchmark: Send all build log messages to a persistent + file in a standard location. + + * make_dir: New utility function. + + * Properly check MD5sum for files before unpacking. + +2002-12-16 19:41 Martin Pool <mbp@samba.org> + + * bench/benchmark: Store MD5sum of files in the benchmark source + and verify them before use. + + * Allow overriding $(CC) when the program is configured. + + * Add glib-2.0.7 test. + + * Test with distcc and plain cc. + +2002-12-16 19:24 Martin Pool <mbp@samba.org> + + * bench/benchmark: (SourceTree.configure, SourceTree.build): + Redirect configure and build output into log files so that the + display is uncluttered. + +2002-12-16 19:21 Martin Pool <mbp@samba.org> + + * bench/benchmark: (SourceTree): Cleaner handling of directories. + +2002-12-16 19:11 Martin Pool <mbp@samba.org> + + * bench/benchmark: (SourceTree.run_cmd): Show time to execute + each command. + + * (SourceTree): Don't use the time(1) command, but just measure + elapsed time. + +2002-12-16 19:03 Martin Pool <mbp@samba.org> + + * bench/benchmark: (SourceTree.run_cmd): Show commands as they're + executed. + + * (SourceTree): Time commands as they're run. + + * (SourceTree.scrub): Remove build trees before starting to build + them. + + * (SourceTree.build): Allow passing options such as -j to make. + +2002-12-16 16:49 Martin Pool <mbp@samba.org> + + * bench/benchmark, NEWS: New macro-benchmark and test suite for + distcc. + + This is the start of a script that runs distcc to build various + open source programs, as an overall test of correctness, and to + measure performance of a distcc installation. + + It relies on the user to install and configure distcc servers and + clients, but handles the work of downloading, preparing, and + building packages by itself. + + * benchmark: New file. + +2002-12-16 16:44 Martin Pool <mbp@samba.org> + + * lzo/.cvsignore: Ignore built files for minilzo + +2002-12-16 14:43 Martin Pool <mbp@samba.org> + + * lzo/: Makefile, README.LZO, lzoconf.h, minilzo.c, minilzo.h, + testmini.c: Import minilzo-1.08 library. Not linked in to main + program yet. + +2002-12-16 14:42 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2002-12-16 11:56 Martin Pool <mbp@samba.org> + + * patches/swhite-lzo-compress.diff: Patch from Stephen White + + * First cut at adding LZO compression, turned on by client-side + environment variable and setting a high bit in the protocol + number to indicate its use. Uses static copy of lzo. + +2002-12-16 11:40 Martin Pool <mbp@samba.org> + + * src/: h_scanargs.c, h_argvtostr.c: Reindent to java / 4-space + style. + +2002-12-16 11:32 Martin Pool <mbp@samba.org> + + * patches/README.patches: Disclaim warranty on these patches. + +2002-12-13 12:06 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Bump version to 0.16cvs. + +2002-12-13 12:04 Martin Pool <mbp@samba.org> + + * NEWS, linuxdoc/distcc.sgml: (Cross-Compilation): The + recommended convention for gcc names is <target>-gcc-<version>, + and GCC 3.3 will install itself under this name. (Alexandre + Oliva, Claes Wallin) + +2002-12-13 11:06 Martin Pool <mbp@samba.org> + + * configure, configure.ac: Bump version to 0.16cvs. + +2002-12-13 09:58 Martin Pool <mbp@samba.org> + + * NEWS, OLDNEWS: Roll over NEWS. + +2002-12-12 20:57 Martin Pool <mbp@samba.org> + + * NEWS, configure, configure.ac: Bump version to 0.15. + +2002-12-12 20:45 Martin Pool <mbp@samba.org> + + * doc/results.txt: Current linux-2.4.19 benchmark results. + +2002-12-12 20:40 Martin Pool <mbp@samba.org> + + * configure: Run autoconf. + +2002-12-12 20:17 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Suggest using qualified compiler names + rather than -b and -V options, because those options didn't + work very well in earlier gcc versions. + + Based on an explanation from Alexandre Oliva. + +2002-12-12 20:06 Martin Pool <mbp@samba.org> + + * Makefile.in, NEWS: Rename TARGET_ROOT variable to the more + standard name of DESTDIR. (Alexandre Oliva) + +2002-12-12 20:03 Martin Pool <mbp@samba.org> + + * doc/irc/openprojects-distcc-20020807.txt: Random notes about + distcc + +2002-12-12 19:45 Martin Pool <mbp@samba.org> + + * src/help.c: [Tests are more useful if they're actually run. :-/] + + * (dcc_show_version): Use intended syntax in --version output. + +2002-12-12 19:41 Martin Pool <mbp@samba.org> + + * test/testdistcc.py, src/help.c: (dcc_show_version, + VersionOption_Case): --version now shows default port. + +2002-12-12 19:38 Martin Pool <mbp@samba.org> + + * doc/flood.txt: flood.txt: Notes on network performance. + +2002-12-12 19:38 Martin Pool <mbp@samba.org> + + * src/: distcc.c, distcc.h, dopt.c, hosts.c: Put default port + into DISTCC_DEFAULT_PORT preprocessor constant, rather than + copying it everywhere. + +2002-12-12 19:34 Martin Pool <mbp@samba.org> + + * aclocal.m4: Rerun autoconf. + +2002-12-12 19:33 Martin Pool <mbp@samba.org> + + * TODO: TODO: New file. Many random notes about things to do, + moved from the user manual. + +2002-12-12 19:31 Martin Pool <mbp@samba.org> + + * src/distcc.c, src/dopt.c, src/hosts.c, test/testdistcc.py, NEWS: + * Change default port from 4200 to IANA-assigned standard for + distcc service "3632". + +2002-12-12 19:30 Martin Pool <mbp@samba.org> + + * analog/.cvsignore: Ignore generated files. + +2002-12-12 19:29 Martin Pool <mbp@samba.org> + + * analog/: httplog.py, print_referers: httplog.py: New file to + parse Apache logs. + + * print_referers: Change to using httplog.py library. + +2002-12-12 19:19 Martin Pool <mbp@samba.org> + + * analog/day.gnuplot: day.gnuplot: New gnuplot file to plot daily + traffic. + +2002-12-12 18:59 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: (Author): Rephrase. + +2002-12-12 18:56 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Move "Reporting Bugs" and "Test Suite" + sections into the introduction chapter. + +2002-12-12 18:43 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Remove empty <appendix> tag. + +2002-12-12 18:41 Martin Pool <mbp@samba.org> + + * NEWS: Only show non-maintainer names in the NEWS file, as in + Subversion. + +2002-12-12 18:38 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml, NEWS: Move "Bugs" chapter into TODO. + (Martin Pool) + +2002-12-12 18:36 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Remove "results" chapter, because this + information is more appropriate for the web site. + + * Start moving bugs/features into TODO. + +2002-12-12 18:12 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2002-12-12 18:09 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: (distcc Compatibility): Remove section + about MOC, because we have nothing at the moment to say. + + Add a new section describing the complex situation for -MD with + gcc + 2.95 and 3.2. + +2002-12-12 17:55 Martin Pool <mbp@samba.org> + + * Makefile.in: (dist_files): Add TODO to distribution. + +2002-12-12 17:39 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: (Bugs): Need a performance regression + suite. + + * (Bugs): Perhaps need to migrate the manual from Linuxdoc to + Docbook Lite. + +2002-12-12 16:53 Martin Pool <mbp@samba.org> + + * analog/traffic.py: traffic.py: Add a new first command line + parameter, either 'day' or 'week' to set grouping quantum. + +2002-12-12 15:47 Martin Pool <mbp@samba.org> + + * src/lock.c: lock.c: Add quotation. + +2002-12-06 11:32 Martin Pool <mbp@samba.org> + + * analog/traffic.gnuplot: traffic.gnuplot: Use log y scale. + +2002-12-06 11:29 Martin Pool <mbp@samba.org> + + * analog/traffic.py: traffic.py: New utility to produce weekly + counts of downloads and accesses. + +2002-12-06 11:07 Martin Pool <mbp@samba.org> + + * analog/traffic.gnuplot: Simple plot of traffic + +2002-12-06 10:19 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml, NEWS: Remove "Results" chapter from + manual: there are now many more detailed results on the web + site, and this information is better suited to storage there, + because it will be updated on a different cycle. End-users + don't really need to have it in their reference. + +2002-12-05 15:22 Martin Pool <mbp@samba.org> + + * doc/release-names.txt: [no log message] + +2002-12-05 14:07 Martin Pool <mbp@samba.org> + + * doc/interceptor.txt: Notes on using an external interceptor + +2002-12-05 10:02 Martin Pool <mbp@samba.org> + + * src/srvnet.c: srvnet.c: (dcc_log_clientname): Clearer error + messages for failure to look up client hostname. + +2002-12-05 10:01 Martin Pool <mbp@samba.org> + + * NEWS: [no log message] + +2002-11-28 04:48 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: We now use ComfyChair not PyUnit + +2002-11-28 04:45 Martin Pool <mbp@samba.org> + + * NEWS: Add section on how to report bugs well + +2002-11-28 04:40 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add section on how to report bugs well + +2002-11-28 04:20 Martin Pool <mbp@samba.org> + + * src/dopt.c: Say that --no-fork is for debugging ONLY + +2002-11-23 04:35 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add TODO + + Bump version to 0.14 + +2002-11-22 19:00 Martin Pool <mbp@samba.org> + + * NEWS: Add note about -MF + +2002-11-21 18:53 Martin Pool <mbp@samba.org> + + * src/cpp.c: Doc + +2002-11-21 18:50 Martin Pool <mbp@samba.org> + + * src/cpp.c: Doc + +2002-11-21 18:46 Martin Pool <mbp@samba.org> + + * NEWS, src/cpp.c, src/strip.c, src/strip.h: Run the preprocessor + with output sent to stdout and redirected to a file, rather than + by using the -o option. This should fix some compilers that + can't handle "-E -o". It may improve gcc behaviour with -MD, but + because gcc behaviour has changed over time it may not be a + complete fix. + +2002-11-21 18:38 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc + +2002-11-21 18:24 Martin Pool <mbp@samba.org> + + * Makefile.in, src/cpp.c, src/cpp.h, src/distcc.c: dcc_cpp_maybe: + Split code to run preprocessor into its own file. + +2002-11-21 18:09 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: DaemonBadPort_Case: avoid polluting system + log files. + +2002-11-21 18:06 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc + +2002-11-21 18:02 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove obsolete/uncalled dist-python target + + Move comfychair into test/ + +2002-11-21 17:21 Martin Pool <mbp@samba.org> + + * analog/.cvsignore: Ignore generated refererlog + +2002-11-21 17:16 Martin Pool <mbp@samba.org> + + * test/: .cvsignore, comfychair.py: Move comfychair into test/ + +2002-11-21 17:06 Martin Pool <mbp@samba.org> + + * cases/empty.i: empty .i file + +2002-11-21 17:05 Martin Pool <mbp@samba.org> + + * DEPENDENCIES: popt is now included in package + +2002-11-21 17:02 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc + +2002-11-21 12:04 Martin Pool <mbp@samba.org> + + * doc/to-test.txt: Add list of trees that would be interesting to + test + +2002-11-20 11:47 Martin Pool <mbp@samba.org> + + * NEWS, configure, configure.ac, src/config.h.in: Fix autoconf + detection of resolv.h on Solaris. (Dimitri Papadopoulos) + +2002-11-20 11:30 Martin Pool <mbp@samba.org> + + * NEWS: Add badly-behaved compiler drop-in for use in testing. + +2002-11-19 14:23 Martin Pool <mbp@samba.org> + + * test/badcc: Add badly-behaved compiler drop-in for use in + testing. + +2002-11-19 13:11 Martin Pool <mbp@samba.org> + + * NEWS, src/exec.c: * Fix waitpid() takes three options. + Required for Irix. (Michael Santy) + +2002-11-19 12:49 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove obsolete comment. + +2002-11-19 12:42 Martin Pool <mbp@samba.org> + + * Makefile.in: OK, now we use install-sh + +2002-11-19 09:09 Martin Pool <mbp@samba.org> + + * analog/print_referers: Better line parser + +2002-11-19 08:57 Martin Pool <mbp@samba.org> + + * analog/distcc.analog: Show more search words. + +2002-11-19 08:54 Martin Pool <mbp@samba.org> + + * Makefile.in: Copy new EmptySource.py file into distribution + +2002-11-19 08:52 Martin Pool <mbp@samba.org> + + * test/.cvsignore: Ignore .pyc files. + +2002-11-19 08:48 Martin Pool <mbp@samba.org> + + * Makefile.in, NEWS, configure, configure.ac: Use the correct + autoconf macros to detect whether install(1) is available and + working, and if not, fall back to using the included install-sh + script. This should fix "make install" on Solaris. (Mike Santy, + Martin Pool) + +2002-11-19 07:45 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: todo + +2002-11-18 13:05 Martin Pool <mbp@samba.org> + + * analog/report/.cvsignore: Ignore built files + +2002-11-18 13:03 Martin Pool <mbp@samba.org> + + * NEWS, test/EmptySource.py, test/testdistcc.py: Add test case for + transmission of a zero-byte file. + +2002-11-18 13:01 Martin Pool <mbp@samba.org> + + * configure: autoconf + +2002-11-16 12:27 Martin Pool <mbp@samba.org> + + * analog/images/: analogo.png, barc1.png, barc16.png, barc2.png, + barc32.png, barc4.png, barc8.png, html2.png: Add analog images + +2002-11-16 12:24 Martin Pool <mbp@samba.org> + + * analog/print_referers: Python script to print web referers + +2002-11-16 12:22 Martin Pool <mbp@samba.org> + + * analog/distcc.analog: Get ready to include bar images in cvs + +2002-11-16 12:19 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version to 0.16cvs + +2002-11-16 12:18 Martin Pool <mbp@samba.org> + + * Makefile.in: Include Scenarios page + +2002-11-16 11:13 Martin Pool <mbp@samba.org> + + * OLDNEWS, NEWS: roll over news + +2002-11-16 09:57 Martin Pool <mbp@samba.org> + + * configure, configure.ac: Bump version to 0.14 + +2002-11-15 18:10 Martin Pool <mbp@samba.org> + + * contrib/distccd-init: distccd Debian init.d script contributed by + Jason Thomas. (Debian #161136) + +2002-11-15 18:07 Martin Pool <mbp@samba.org> + + * NEWS: reformat only + +2002-11-15 18:07 Martin Pool <mbp@samba.org> + + * NEWS: distccd Debian init.d script contributed by Jason Thomas. + (Debian #161136) + +2002-11-15 18:06 Martin Pool <mbp@samba.org> + + * Makefile.in: Include contrib files in distribution. + +2002-11-15 10:06 Martin Pool <mbp@samba.org> + + * src/trace.h: Doc + +2002-11-14 14:09 Martin Pool <mbp@samba.org> + + * NEWS: Make sure PreprocessPlainText_Case runs in the right + directory. + +2002-11-14 14:09 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: TODO (thanks Oscar) + +2002-11-14 14:00 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Make sure PreprocessPlainText_Case runs in + the right directory. + +2002-11-14 12:58 Martin Pool <mbp@samba.org> + + * Makefile.in: Make sure that if Latte processing fails, the output + file is removed + + Remove obsolete maintainer-clean dependencies + +2002-11-13 08:56 Martin Pool <mbp@samba.org> + + * configure, configure.ac, src/config.h.in, src/exec.c: Handle + machines without wait4 by using waitpid instead. + +2002-11-13 08:48 Martin Pool <mbp@samba.org> + + * configure.ac, NEWS: Test for wait4 and wait3, which are missing + on IRIX (Mike Santy) + +2002-11-13 08:46 Martin Pool <mbp@samba.org> + + * src/serve.c: Fix parameter type (suggestion from Dimitri + Papadopoulos) + +2002-11-13 07:47 Martin Pool <mbp@samba.org> + + * configure: autoconf + +2002-11-13 07:44 Martin Pool <mbp@samba.org> + + * Makefile.in, NEWS: Fix silly bug that caused HTML documentation + to be missing from the tarball + +2002-11-13 07:43 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version to 0.14 + +2002-11-13 07:14 Martin Pool <mbp@samba.org> + + * NEWS: Bump version to 0.14 + +2002-11-13 07:11 Martin Pool <mbp@samba.org> + + * src/distcc.c: Take lock on localhost only when compiling locally, + not for all compilations. + +2002-11-13 07:03 Martin Pool <mbp@samba.org> + + * OLDNEWS, NEWS: Roll over news + +2002-11-13 07:01 Martin Pool <mbp@samba.org> + + * src/where.c: Remove dead code. + +2002-11-13 06:02 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version to 0.13.1cvs + +2002-11-12 18:40 Martin Pool <mbp@samba.org> + + * README: Update README + +2002-11-12 18:38 Martin Pool <mbp@samba.org> + + * configure, configure.ac: Prepare for 0.13 release + +2002-11-12 18:34 Martin Pool <mbp@samba.org> + + * NEWS: Prepare for release. + +2002-11-12 18:25 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: More ComfyChair merges. + +2002-11-12 18:24 Martin Pool <mbp@samba.org> + + * configure: autoconf + +2002-11-12 18:23 Martin Pool <mbp@samba.org> + + * configure.ac: Remove --with-extra-includes and --with-extra-libs, + because they just don't work well with autoconf, since they can + only be specified once and repeated appearances will cause only + the last to have effect. The official way for autoconf 2.5 is to + set CPPFLAGS and LDFLAGS. + +2002-11-12 18:21 Martin Pool <mbp@samba.org> + + * configure.ac: Change --with-included-popt + + if not specified, use if necessary + + if specified, then always (or never) use it + +2002-11-12 18:20 Martin Pool <mbp@samba.org> + + * NEWS: If popt is missing and not specified, get it + +2002-11-12 18:14 Martin Pool <mbp@samba.org> + + * configure.ac: If popt is missing and not specified, get it + +2002-11-12 18:11 Martin Pool <mbp@samba.org> + + * Makefile.in: doh + +2002-11-12 18:10 Martin Pool <mbp@samba.org> + + * Makefile.in: Clean popt, binaries, and testtmp from "clean" + target. + +2002-11-12 17:53 Martin Pool <mbp@samba.org> + + * NEWS: Merge tpot's comfychair patch + +2002-11-12 17:47 Martin Pool <mbp@samba.org> + + * NEWS, configure, configure.ac, src/config.h.in: Add config + options for included popt + +2002-11-12 17:39 Martin Pool <mbp@samba.org> + + * configure.ac: Add --with-included-popt option + +2002-11-12 17:37 Martin Pool <mbp@samba.org> + + * Makefile.in: Make 'all' the default + +2002-11-12 17:36 Martin Pool <mbp@samba.org> + + * Makefile.in: Include other necessary files in distribution + +2002-11-12 17:33 Martin Pool <mbp@samba.org> + + * Makefile.in: Clean up some Makefile targets + + Remove GNU makeisms + + Include popt in tarball + +2002-11-12 17:17 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Make MissingCompiler_Case actually test what + it's meant to test. + + Doc. + +2002-11-12 17:11 Martin Pool <mbp@samba.org> + + * NEWS: Update news + +2002-11-12 17:08 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add new exit codes. + + Bump version to 0.13. + +2002-11-12 17:03 Martin Pool <mbp@samba.org> + + * src/: exitcode.h, exec.c: Add EXIT_COMPILER_MISSING + +2002-11-12 16:28 Martin Pool <mbp@samba.org> + + * Makefile.in: Doc + +2002-11-12 08:16 Martin Pool <mbp@samba.org> + + * aclocal.m4, configure, configure.ac, src/config.h.in, + src/srvnet.c: Make inclusion of arpa/nameser.h and resolv.h + conditional + +2002-11-08 18:51 Martin Pool <mbp@samba.org> + + * src/distcc.c: Fix prototypes + +2002-11-08 18:51 Martin Pool <mbp@samba.org> + + * src/exec.c: Doc + +2002-11-08 18:50 Martin Pool <mbp@samba.org> + + * src/distcc.c: On the client, we should take locks only when + compiling locally. cpp is cheap enough that it doesn't really + need to be taken into account. + +2002-11-08 18:49 Martin Pool <mbp@samba.org> + + * src/exec.c: Do not take a lock on localhost when spawning + commands. + + This is intended to get rid of a race condition that will + sometimes deadlock the client: + + Two clients, P1 and P2, are both trying to compile on remote + machine + R. Therefore, they both need to get a lock on localhost to run + cpp, + and on R. If they acquire the locks in the opposite order, + then + they will block holding locks, and deadlock. The ordering is + indeterminate because the cpp lock is acquired from the + separate + process forked to run cpp. + + This was not evident in 0.12 and earlier because there was no + limit on the number of locks that could be taken. + + On the server side, there are better places to regulate process + load than here. We should instead hold off on accepting + connections until we have space to handle them. + + On the client, we should take locks only when compiling locally. + cpp is cheap enough that it doesn't really need to be taken into + account. + +2002-11-08 17:39 Martin Pool <mbp@samba.org> + + * cases/: cpp-set-path.c, foo.h, hello.c: Add small files for + exploring gcc behaviour + +2002-11-05 05:47 Martin Pool <mbp@samba.org> + + * src/exec.c: BSD needs signal.h. Thanks to Ajay Agrawalla. + +2002-11-01 19:12 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: MissingCompiler_Case: Fix function name + +2002-11-01 19:11 Martin Pool <mbp@samba.org> + + * src/serve.c: dcc_accept_job: Fix little prototype consistency + mistake + +2002-11-01 19:08 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc + +2002-11-01 19:08 Martin Pool <mbp@samba.org> + + * src/serve.c: Drop support for using fifos on the server. + + Run compilers in their own process group, and kill them if the + daemon is killed. + + Copy server's output into the error log, and try to always send + it back to the client even if something goes wrong. + +2002-11-01 19:06 Martin Pool <mbp@samba.org> + + * src/: io.c, rpc.c: Use error codes more consistently + +2002-11-01 19:06 Martin Pool <mbp@samba.org> + + * src/exitcode.h: Add EXIT_TRUNCATED and EXIT_PROTOCOL_ERROR + +2002-11-01 19:05 Martin Pool <mbp@samba.org> + + * src/: exec.c, exec.h: Add new utilities: dcc_reset_signal, and + dcc_setpgid + + Doc + +2002-11-01 19:03 Martin Pool <mbp@samba.org> + + * src/dparent.c: Better doc and messages + +2002-11-01 19:02 Martin Pool <mbp@samba.org> + + * src/distcc.c: If cpp returns an error, don't bother trying to run + the compilation locally. + + Upgrade notice -> warning on failure to distribute. Only show + warning or higher on the client by default. + + Don't abruptly close the connection if the remote compiler fails. + +2002-11-01 18:58 Martin Pool <mbp@samba.org> + + * src/bulk.c: Tidyup + +2002-11-01 18:58 Martin Pool <mbp@samba.org> + + * README: Mention DISTCC_LOG and possible future ssh support + +2002-11-01 18:57 Martin Pool <mbp@samba.org> + + * NEWS: Temporarily remove limit on number of local tasks, because + this can cause a deadlock. + + Client does not abruptly drop network connection on compiler + failure but rather reads the 0-byte object file token. (Martin + Pool) + + Rework logger library to allow multiple logger callbacks to be + active at once. This is used for the server, which can write to + its own log files and also send a copy of messages to a buffer to + be sent to the client. + +2002-11-01 18:53 Martin Pool <mbp@samba.org> + + * samples/: bad.c, badcpp.c, hello.c: Add small sample source files + +2002-11-01 17:54 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: * Allow distcc's version to be set to + something like "0.13cvs-nofifo". + + * Add test for handling of a compiler missing from the server. + +2002-11-01 17:51 Martin Pool <mbp@samba.org> + + * src/distcc.c, src/dparent.c, src/exec.c, src/serve.c, + src/where.c, NEWS: * Remove support for feeding the compiler + from a fifo. The gain from + using fifos does not seem to justify the maintenance + burden. (Martin Pool) + + - This makes the behaviour more consistent, because some + platforms + (Cygwin) or filesystems (NFS, strangely) can't use + fifos. It removes + a code path and a slightly complex autodetection. + + - Using fifos makes some potential scheduling improvements + hard: the + server can't make good decisions about how many tasks to + run, because + each one will only use a fraction of the CPU. The + client cannot + serialize file transmission, which would probably be + desirable. + + - Using fifos makes reliably handling compiler failures + slightly + harder: the compiler may crash or exit at any time, + which will in + turn cause the server to hang if it later tries to open + or write to + the fifo. In previous versions, distcc tried to handle + this by + catching SIGCHLD when the child terminated, and aborting + the + operation, but I am not sure that the method is + completely reliable. + + * Use return codes more consistently + + * Change log levels slightly to try to make sure nothing is + emitted for successful compilation or even only compiler + errors. + + * Detached daemon now ignores hangup signal. + + * Follow Unix convention of returning 128+SIGNAL if the + compiler exits + with a signal. (Martin Pool) + + * Write server error messages to a log file and send them + back to + the client on completion. + +2002-11-01 17:25 Martin Pool <mbp@samba.org> + + * src/daemon.c: Doc + +2002-10-31 13:40 Martin Pool <mbp@samba.org> + + * NEWS: More news + +2002-10-31 13:28 Martin Pool <mbp@samba.org> + + * Makefile.in: Add TARGET_ROOT Makefile variable for installation, + when building binary packages. + +2002-10-31 13:15 Martin Pool <mbp@samba.org> + + * NEWS, src/daemon.c, src/exec.c, src/serve.c: Log messages on the + server of severity "warning" or higher are captured and sent back + to the client. + + Do not use atexit() to clean up temporary files, because this can + cause havoc if it's ever called from a child process that forked + but failed to exec. + +2002-10-31 13:11 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Show trace message when temporary files are + deleted + +2002-10-31 13:11 Martin Pool <mbp@samba.org> + + * src/: trace.c, trace.h, distcc.c: Change the logger callback + system so that multiple loggers may be attached at any time. + +2002-10-31 12:35 Martin Pool <mbp@samba.org> + + * src/exec.c: Add trace message for EINTR failure of wait4, because + we don't really expect it to happen. + + Doc. + +2002-10-31 12:34 Martin Pool <mbp@samba.org> + + * src/distcc.h: Define true and false for clarity + +2002-10-31 12:33 Martin Pool <mbp@samba.org> + + * Makefile.in: Include autogen.sh in dist + +2002-10-31 12:32 Martin Pool <mbp@samba.org> + + * configure.ac, src/distcc.c: Doc + +2002-10-31 12:32 Martin Pool <mbp@samba.org> + + * news.emacs: No tabs please + +2002-10-21 20:33 Martin Pool <mbp@samba.org> + + * analog/distcc.analog: Exclude distcc.samba.org from referrer + calculations + +2002-10-18 16:45 Martin Pool <mbp@samba.org> + + * DEPENDENCIES: Add URL for popt + +2002-10-18 11:58 Martin Pool <mbp@samba.org> + + * NEWS: Note Makefile fixes + +2002-10-18 11:57 Martin Pool <mbp@samba.org> + + * configure, configure.ac: Don't use -MD because there seems not to + be a portable way to include the results in the Makefile + +2002-10-18 11:55 Martin Pool <mbp@samba.org> + + * Makefile.in: Check that programs have been built before trying to + install them + +2002-10-18 11:53 Martin Pool <mbp@samba.org> + + * Makefile.in: Put back pkgdoc_DOCS, which somehow got lost + + Distribute pkgdocs as well + +2002-10-18 11:46 Martin Pool <mbp@samba.org> + + * aclocal.m4, configure: Run autoconf + +2002-10-18 11:45 Martin Pool <mbp@samba.org> + + * popt/: findme.c, findme.h, popt.c, popt.h, poptconfig.c, + popthelp.c, poptint.h, poptparse.c, system.h: Import popt-1.7 + +2002-10-18 11:41 Martin Pool <mbp@samba.org> + + * README.popt: Start adding included popt + +2002-10-18 11:38 Martin Pool <mbp@samba.org> + + * README.packaging, Makefile.in: Add note to packagers + +2002-10-18 11:29 Martin Pool <mbp@samba.org> + + * Makefile.in, configure.ac: Remove reference to src/Makefile.in + +2002-10-18 11:29 Martin Pool <mbp@samba.org> + + * NEWS, src/Makefile.in: Get rid of Makefile recursion; build all + source from the toplevel Makefile + +2002-10-18 11:22 Martin Pool <mbp@samba.org> + + * Makefile.in, .cvsignore: Get rid of Makefile recursion; build all + source from the toplevel Makefile + + Binaries are now deposited into the top-level directory + + Drop obsolete pyunit rules + +2002-10-18 10:36 Martin Pool <mbp@samba.org> + + * src/distcc.c: Test that the .i file exists before trying to + transmit it to the server. + + Doc. + +2002-10-17 18:33 Martin Pool <mbp@samba.org> + + * src/arg.c: Better message for object or output files + +2002-10-17 18:32 Martin Pool <mbp@samba.org> + + * NEWS, test/testdistcc.py: Add test case for invocations like + "distcc -c test1.c test2.c". + +2002-10-17 18:22 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc + +2002-10-17 18:21 Martin Pool <mbp@samba.org> + + * NEWS, test/testdistcc.py: Add test case for preprocessing non-C + text, as is done by (for example) xrdb. + + Remove done TODOs + +2002-10-17 18:07 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add test case for #error directive + +2002-10-17 13:40 Martin Pool <mbp@samba.org> + + * NEWS, linuxdoc/distcc.sgml: More Gentoo notes from Ernesto + +2002-10-17 13:29 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml, NEWS: Add Gentoo documentation from Dean + Bailey + +2002-10-16 11:00 Martin Pool <mbp@samba.org> + + * Makefile.in: Don't use "make -C" because some non-GNU makes don't + support -C. Instead, explicitly cd, and do it in a way that + better allows parallelism. + +2002-10-11 11:45 Martin Pool <mbp@samba.org> + + * NEWS, test/testdistcc.py: Split out tests for implied compiler + name into their own class + +2002-10-11 11:40 Martin Pool <mbp@samba.org> + + * doc/lock-deadlock.txt: Doc deadlock observed in 0.13cvs + +2002-10-10 12:56 Martin Pool <mbp@samba.org> + + * Makefile.in: Include where.h + +2002-10-10 12:56 Martin Pool <mbp@samba.org> + + * src/Makefile.in: Cope when there are no .d files + +2002-10-10 12:52 Martin Pool <mbp@samba.org> + + * Makefile.in: Clean up the dist targets; include new patches + +2002-10-10 12:33 Martin Pool <mbp@samba.org> + + * packaging/SuSE/init.d/distcc, NEWS: SuSE init.d script from + Brandon Forehand + +2002-10-10 11:47 Martin Pool <mbp@samba.org> + + * patches/: colorgcc, distcc-hostlist.diff: Patches from Charles + Samuels to store hosts in a file, and to run distcc through + colorcc. + +2002-10-10 10:54 Martin Pool <mbp@samba.org> + + * src/distcc.c: Add FIXME + +2002-10-10 00:33 Martin Pool <mbp@samba.org> + + * src/: distcc.c, distcc.h, exec.c, exec.h, lock.h, serve.c, + where.c, where.h: In lock debug messages, show whether we're + running the compiler or the preprocessor. + +2002-10-07 23:20 Martin Pool <mbp@samba.org> + + * NEWS: Doc + +2002-10-07 23:13 Martin Pool <mbp@samba.org> + + * src/where.c: Add trace + +2002-10-07 23:03 Martin Pool <mbp@samba.org> + + * src/lock.c: Fix parameters for fcntl locks + +2002-10-07 23:02 Martin Pool <mbp@samba.org> + + * src/where.c: Add trace + + Use pid+ppid as a seed for randomly choosing a host when we can't + find a free one. + +2002-10-07 22:54 Martin Pool <mbp@samba.org> + + * src/: Makefile.in, distcc.c, distcc.h, hosts.h, lock.c, lock.h, + where.c: Add code to wait for a blocking lock if no host is + immediately free. + +2002-10-07 22:10 Martin Pool <mbp@samba.org> + + * NEWS, src/dparent.c: When the parent is terminated, don't kill + its process group. Allow children to finish in their own time. + +2002-10-07 22:08 Martin Pool <mbp@samba.org> + + * src/Makefile.in: Include generated dependencies + +2002-10-07 18:17 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: NoDetachDaemon_Case: + + Fix bug in arguments for starting --no-detach daemon + + Correctly wait for daemon after signalling + + Fix log message + +2002-10-07 15:07 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Move code for explaining failures into test + case + + Move setUp/runTest/tearDown structure into framework + + runCmdNoWait(): take a list + + Add test case for --no-detach (broken) + +2002-10-07 14:37 Martin Pool <mbp@samba.org> + + * NEWS: Nicer handling of ^C while running tests: print "INTERRUPT" + and terminate the whole test + +2002-10-07 14:36 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: New runCmdNoWait function needs argument as + string, not list + +2002-10-07 14:28 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: When killing daemon, ping every 200ms to try + to notice faster that it's finished. + + Clean up some function names. + + Add unused DetachDaemon_Case + +2002-10-07 13:57 Martin Pool <mbp@samba.org> + + * NEWS, src/dopt.c, src/dparent.c, src/opt.h: Add --no-detach + option + +2002-10-07 13:52 Martin Pool <mbp@samba.org> + + * NEWS, src/h_hosts.c, src/hosts.c, src/hosts.h, src/lock.c, + src/where.c, test/testdistcc.py: Add per-host limit on number of + compile slots to dcc_hostdef structure. Not used yet, and always + set to 4. + +2002-10-07 13:06 Martin Pool <mbp@samba.org> + + * NEWS, OLDNEWS, configure, configure.ac: Advance version to + 0.13cvs + +2002-10-07 12:39 Martin Pool <mbp@samba.org> + + * NEWS, aclocal.m4, configure, configure.ac: Bump version to 0.12 + +2002-10-07 12:34 Martin Pool <mbp@samba.org> + + * src/where.c: Doc + +2002-10-07 12:29 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Bump to version 0.12 + +2002-10-07 12:16 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Note on adaptive scheduling + +2002-10-07 11:35 Martin Pool <mbp@samba.org> + + * NEWS, src/clinet.c, src/clinet.h, src/distcc.c, src/exec.c, + src/exec.h, src/hosts.c, src/hosts.h, src/lock.c, src/where.c: + Roll back multi-A-record patch: seems to break the test suite, + and on further consideration I think just SRV records might be + cleaner. + +2002-10-07 11:19 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc + +2002-10-07 11:15 Martin Pool <mbp@samba.org> + + * src/hosts.c: Doc about handling host list. + +2002-10-07 11:04 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add note about performance test suite. + +2002-10-06 21:37 Martin Pool <mbp@samba.org> + + * aclocal.m4, configure, configure.ac: Bump version to 0.12cvs + +2002-10-04 11:53 Martin Pool <mbp@samba.org> + + * NEWS: foo + +2002-10-02 15:03 Martin Pool <mbp@samba.org> + + * src/arg.c: Add fixme + +2002-10-02 14:55 Martin Pool <mbp@samba.org> + + * src/distcc.c: Add fixme + +2002-10-02 13:03 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Note about starting the daemon + +2002-10-02 12:47 Martin Pool <mbp@samba.org> + + * doc/irc/: slashnet-distcc-20020919.txt, + slashnet-distcc-20021002.txt: Check in IRC logs + +2002-09-30 23:06 Martin Pool <mbp@samba.org> + + * src/h_hosts.c: Fix extra headers to allow for host definitions + that now include an IP address. + +2002-09-30 23:01 Martin Pool <mbp@samba.org> + + * NEWS, configure, src/clinet.c, src/clinet.h, src/distcc.c, + src/exec.c, src/exec.h, src/hosts.c, src/hosts.h, src/lock.c, + src/where.c: Handle DNS A records that give multiple IP addresses + for a host by distributing work across all the addresses. This + should allow you to create "linux.build.squick.net" that resolves + to all the relevant machines. + + Patch from Andreas Granig, but seems to break some tests. + +2002-09-30 16:06 Martin Pool <mbp@samba.org> + + * NEWS, src/serve.c: wait4() on Solaris can't handle a pid of -1, + which means "any child" on Linux and BSD. Use pid of 0 instead + to collect any children from the same process group. (Kevin + Bailey) + +2002-09-30 15:44 Martin Pool <mbp@samba.org> + + * NEWS, src/arg.c, test/testdistcc.py: Add tests for "gcc -S -o - + foo.c" + +2002-09-30 14:04 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Update version to 0.11 + +2002-09-30 14:00 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Remove done TODO + +2002-09-30 13:46 Martin Pool <mbp@samba.org> + + * Makefile.in: Add roadmap + +2002-09-27 14:50 Martin Pool <mbp@samba.org> + + * NEWS, src/arg.c: Handle "gcc -S foo.c -o -", which ought to write + assembly to stdout. + +2002-09-27 14:20 Martin Pool <mbp@samba.org> + + * src/where.c: Add fixme + +2002-09-27 14:03 Martin Pool <mbp@samba.org> + + * Makefile.in: Add results page + +2002-09-27 13:55 Martin Pool <mbp@samba.org> + + * survey.txt: Add qn about distcc version + +2002-09-26 16:19 Martin Pool <mbp@samba.org> + + * NEWS, OLDNEWS: Roll over NEWS + +2002-09-25 16:36 Martin Pool <mbp@samba.org> + + * src/implicit.c: Doc + +2002-09-25 11:54 Martin Pool <mbp@samba.org> + + * NEWS, configure, configure.ac: Bump version to 0.11 + +2002-09-25 11:43 Martin Pool <mbp@samba.org> + + * Makefile.in, patches/README.patches, + patches/granig_distcc_multi-A-record.diff: Add patches/README, + and Andrea Granig's multi-A-record patch + +2002-09-25 11:39 Martin Pool <mbp@samba.org> + + * Makefile.in: Include patches in distributed tarball + +2002-09-25 11:37 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: GNU Info can't handle having two sections + with the same heading + +2002-09-24 18:18 Martin Pool <mbp@samba.org> + + * NEWS, src/strip.c: Fix (non-exploitable) buffer overrun bug. + +2002-09-23 22:47 Martin Pool <mbp@samba.org> + + * NEWS: Update news + +2002-09-23 22:31 Martin Pool <mbp@samba.org> + + * src/strip.c: List -MD, etc, separately, because we don't know how + other -M options will be parsed in the future. + +2002-09-23 22:29 Martin Pool <mbp@samba.org> + + * src/strip.c: Strip -MF -MT -MQ options that are followed by a + filename + +2002-09-23 22:24 Martin Pool <mbp@samba.org> + + * src/arg.c: Add support for gcc-3.2 new -M options (-MG, etc) + +2002-09-23 15:25 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Update todo list. + + Add section discussing ccache and distcc + +2002-09-23 15:17 Martin Pool <mbp@samba.org> + + * patches/joerg-proof-build-01.diff: Patch from Joerg to do "proof" + by compiling a file on all machines and checking that they're the + same. + +2002-09-23 14:56 Martin Pool <mbp@samba.org> + + * NEWS, src/daemon.c: Do not object to running as group 0, because + on BSD this is "wheel" and many non-privileged users are in it. + +2002-09-23 12:46 Martin Pool <mbp@samba.org> + + * doc/scheduling.txt: More notes + +2002-09-20 12:37 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc + +2002-09-20 11:39 Martin Pool <mbp@samba.org> + + * NEWS, src/strip.c, test/testdistcc.py: Strip more local-only + options + + Add more tests for argument stripping + + dcc_strip_local_args: trace result on completion + +2002-09-20 10:30 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc + +2002-09-20 10:14 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc. + +2002-09-19 00:33 Martin Pool <mbp@samba.org> + + * src/bulk.c: Mode on received files should be 0666&~umask + +2002-09-19 00:06 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc + +2002-09-18 22:58 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc + +2002-09-18 21:36 Martin Pool <mbp@samba.org> + + * NEWS, src/bulk.c, src/daemon.c, test/testdistcc.py: Make + permissions on output files obey umask, etc. Add test case for + this. + + Add option to test case driver to run particular specified tests. + +2002-09-18 16:57 Martin Pool <mbp@samba.org> + + * src/distcc.c, src/h_scanargs.c, src/implicit.c, src/implicit.h, + test/testdistcc.py: Rename dcc_add_implicit to dcc_find_compiler + + Remove "distcc hello.o -o hello" case -- too hard at the moment. + +2002-09-18 16:47 Martin Pool <mbp@samba.org> + + * src/: distcc.c, h_scanargs.c, implicit.c, implicit.h: Reduce + too-long function name + +2002-09-18 16:42 Martin Pool <mbp@samba.org> + + * src/implicit.c: Doc. + +2002-09-18 16:39 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add implicit linker test: "distcc testtmp.o + -o testtmp" + +2002-09-18 16:36 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Fix tests for -MD that were giving a false + pass + + Add basic tests for implict compiler names. + +2002-09-18 16:33 Martin Pool <mbp@samba.org> + + * NEWS, src/Makefile.in, src/h_scanargs.c, test/testdistcc.py: Add + more test cases for implicit compiler name handling. Extend + h_scanargs to exercise this. + +2002-09-18 16:32 Martin Pool <mbp@samba.org> + + * src/arg.c: Fix doc. + +2002-09-18 13:29 Martin Pool <mbp@samba.org> + + * NEWS: Release name + +2002-09-18 10:45 Martin Pool <mbp@samba.org> + + * doc/results.txt: Add results on building inside VMWare + +2002-09-17 18:49 Martin Pool <mbp@samba.org> + + * src/io.c: Doc. + +2002-09-17 13:59 Martin Pool <mbp@samba.org> + + * src/srvnet.c: resolv.h might need sys/types.h on BSD? + +2002-09-17 13:58 Martin Pool <mbp@samba.org> + + * src/implicit.c: Might need sys/types.h on BSD? + +2002-09-16 18:14 Martin Pool <mbp@samba.org> + + * src/clinet.c: Fix docs + +2002-09-16 11:02 Martin Pool <mbp@samba.org> + + * Makefile.in: Upload "tested" page + +2002-09-16 11:01 Martin Pool <mbp@samba.org> + + * README: Update readme text + +2002-09-14 19:02 Martin Pool <mbp@samba.org> + + * src/srvnet.c: Cope without hstrerror(). Thanks to Richard + Zidlicky + +2002-09-14 18:59 Martin Pool <mbp@samba.org> + + * configure, configure.ac, src/config.h.in: Check for presence of + hstrerror function. Richard Zidlicky reports that it is missing + in libc5 + +2002-09-14 18:54 Martin Pool <mbp@samba.org> + + * src/srvnet.c: Cope without socklen_t. Thanks to Richard Zidlicky + +2002-09-14 18:53 Martin Pool <mbp@samba.org> + + * configure, configure.ac, src/config.h.in: Check for socklen_t + +2002-09-14 18:46 Martin Pool <mbp@samba.org> + + * src/clinet.c, NEWS: Remove unnecessary sa_family_t cast. + (Richard Zidlicky) + +2002-09-14 13:35 Martin Pool <mbp@samba.org> + + * NEWS: Doc + +2002-09-14 13:20 Martin Pool <mbp@samba.org> + + * NEWS, configure, configure.ac, src/config.h.in: More helpful + message explaining that popt is needed if it is missing at build + time. + +2002-09-14 10:58 Martin Pool <mbp@samba.org> + + * configure.ac: Doc + +2002-09-14 10:52 Martin Pool <mbp@samba.org> + + * src/dparent.c: Don't set cloexec() on the accept fd -- this seems + to make it close after the first compiler runs. + +2002-09-14 10:51 Martin Pool <mbp@samba.org> + + * NEWS, test/testdistcc.py: Create and use a separate TMPDIR for + each test case. + + Also, rename subdirectories of testtmp + +2002-09-14 10:46 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2002-09-14 10:38 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2002-09-14 10:11 Martin Pool <mbp@samba.org> + + * src/: dparent.c, exec.c: Don't close all fds when starting the + compiler, because this gets a bit confusing with logs and lock + files. However, do set CLOEXEC on the network fds, because the + compiler should never be writing to them. + +2002-09-14 09:52 Martin Pool <mbp@samba.org> + + * src/lock.c, NEWS: Fix leakage of fds when trying to get a lock. + +2002-09-14 09:51 Martin Pool <mbp@samba.org> + + * src/util.c: Doc. + +2002-09-14 09:50 Martin Pool <mbp@samba.org> + + * src/exec.c: Move lock prototypes to lock.h + +2002-09-14 09:48 Martin Pool <mbp@samba.org> + + * src/: lock.h, distcc.h: Rearrange prototypes + +2002-09-14 09:47 Martin Pool <mbp@samba.org> + + * Makefile.in, src/Makefile.in, src/exec.c, src/hosts.c, + src/lock.c, src/lock.h, src/where.c: Split locking code out into + a separate file so that it can be used by the server as well + +2002-09-14 09:46 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Run daemon with --verbose + +2002-09-14 09:33 Martin Pool <mbp@samba.org> + + * src/exec.c: dcc_execvp doesn't return + +2002-09-14 09:32 Martin Pool <mbp@samba.org> + + * NEWS: Whenever a command by either the client or the server, it + counts towards the load on that machine. This covers + undistributed commands, cpp, and compilation. + +2002-09-14 09:32 Martin Pool <mbp@samba.org> + + * src/distcc.c: dcc_compile_local: Don't need to take a lock as a + special case; this is always done now + +2002-09-14 09:30 Martin Pool <mbp@samba.org> + + * src/exec.c: dcc_inside_child: Take a lock on localhost for all + executed commands + +2002-09-14 09:08 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc + +2002-09-14 08:42 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc + +2002-09-14 08:41 Martin Pool <mbp@samba.org> + + * src/exec.c, NEWS: dcc_inside_child: new function to handle setup + and execution of children. Now checks return codes, and makes + sure (very important!) that we can never return above the fork() + call. + +2002-09-14 08:33 Martin Pool <mbp@samba.org> + + * src/exec.c: dcc_redirect_fds: If any redirection fails, return + that error. + +2002-09-14 08:32 Martin Pool <mbp@samba.org> + + * src/util.c: Needs exitcode.h + +2002-09-14 08:31 Martin Pool <mbp@samba.org> + + * src/util.c: dcc_redirect_fd: Return EXIT_IO_ERROR not -1 for + error + +2002-09-14 08:30 Martin Pool <mbp@samba.org> + + * src/util.c: dcc_redirect_fd: Remove calls to rs_fatal() in favour + of returning an error. + +2002-09-14 08:28 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Doc + +2002-09-14 08:26 Martin Pool <mbp@samba.org> + + * OLDNEWS, NEWS: Roll over NEWS + +2002-09-14 08:25 Martin Pool <mbp@samba.org> + + * src/io.c: Failure to write should be an error, but not fatal. We + might want to do something to make sure the process unwinds + properly. + +2002-09-14 08:23 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc + +2002-09-13 17:52 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Update libtool situation. + +2002-09-13 15:40 Martin Pool <mbp@samba.org> + + * doc/ssh-notes.txt: Back-of-envelope calculations on using SSH. + +2002-09-13 13:08 Martin Pool <mbp@samba.org> + + * src/: arg.c: Doc. + +2002-09-13 13:02 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc. + +2002-09-13 12:58 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2002-09-13 12:55 Martin Pool <mbp@samba.org> + + * src/serve.c: Remove done todo + +2002-09-13 12:29 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove done TODO + +2002-09-13 12:28 Martin Pool <mbp@samba.org> + + * Makefile.in: Include new header file + +2002-09-13 12:27 Martin Pool <mbp@samba.org> + + * configure, configure.ac: Bump version to 0.10.1 + +2002-09-13 12:24 Martin Pool <mbp@samba.org> + + * src/serve.c: Define W_EXITCODE with standard Unix meaning if it + is missing. + +2002-09-13 12:22 Martin Pool <mbp@samba.org> + + * src/: distcc.c, distcc.h, exec.c, exec.h, serve.c: Split headers, + also fix fact that pid_t is in sys/types.h. + +2002-09-13 12:20 Martin Pool <mbp@samba.org> + + * configure, configure.ac: Bump version to 0.10.1cvs + +2002-09-12 21:38 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml, src/distcc.c: Update for new syntax, + 'distcc -c hello.c' + +2002-09-12 21:28 Martin Pool <mbp@samba.org> + + * configure, configure.ac: Bump version to 0.10. + +2002-09-12 21:20 Martin Pool <mbp@samba.org> + + * NEWS: Add release name. + +2002-09-12 21:00 Martin Pool <mbp@samba.org> + + * NEWS: Strip emacs stuff. + +2002-09-12 20:43 Martin Pool <mbp@samba.org> + + * NEWS, src/filename.c, test/testdistcc.py: It turns out that .s + and .S files in fact cannot be assembled remotely, because they + might use the gas '.include' pseudo op, which is resolved by the + assembler and would end up reading something from the volunteer's + disk. + + Thanks to Richard Zidlicky for pointing this out. + +2002-09-12 20:15 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc. + +2002-09-12 14:30 Martin Pool <mbp@samba.org> + + * src/: arg.c: Note about difficulties of included files in .s and + .S. + +2002-09-12 12:14 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Update regexp to handle new "cannot + distribute" message format. + +2002-09-12 11:20 Martin Pool <mbp@samba.org> + + * src/strip.c: Remove dumb overoptimization that mangled command + lines + +2002-09-12 11:17 Martin Pool <mbp@samba.org> + + * src/strip.c, NEWS: Strip -M* from remote command lines as well. + +2002-09-12 11:13 Martin Pool <mbp@samba.org> + + * configure.ac: If using gcc, use -MMD for dependency files. + +2002-09-12 11:03 Martin Pool <mbp@samba.org> + + * src/distcc.c, NEWS: If distribution fails, show the name of the + server that we were trying to use. + +2002-09-12 10:58 Martin Pool <mbp@samba.org> + + * src/implicit.c: Document design tradeoffs about implicit compiler + names. + +2002-09-12 10:34 Martin Pool <mbp@samba.org> + + * src/: distcc.c, distcc.h, hosts.c, implicit.c, implicit.h, + where.c: Allow distcc to be directly used with the same syntax as + a compiler: "distcc -c hello.c". At the moment, always calls + "cc". + +2002-09-11 17:19 Martin Pool <mbp@samba.org> + + * Makefile.in, NEWS, src/Makefile.in, src/arg.c, src/distcc.c, + test/testdistcc.py: Allow distcc to be directly used with the + same syntax as a compiler: "distcc -c hello.c". At the moment, + always calls "cc". + +2002-09-11 17:02 Martin Pool <mbp@samba.org> + + * src/: distcc.c, arg.c: Remove done todos. + +2002-09-11 16:44 Martin Pool <mbp@samba.org> + + * NEWS, src/distcc.c, src/h_strip.c, src/strip.c, src/strip.h: Also + strip -L arguments before passing across the network. There's no + good reason why they should be on compilation lines, but it does + happen in GNOME. + +2002-09-11 16:26 Martin Pool <mbp@samba.org> + + * src/distcc.c: Strip -D and -I options before passing the command + line across the network, for clarity (and perhaps a tiny + performance improvement.) + +2002-09-11 16:22 Martin Pool <mbp@samba.org> + + * NEWS: Strip -D and -I options before passing the command line + across the network, for clarity (and perhaps a tiny performance + improvement.) + +2002-09-11 16:20 Martin Pool <mbp@samba.org> + + * NEWS, test/testdistcc.py: Add test case that uses -D on the + compiler command line + +2002-09-11 16:00 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add test cases for scanning -Mfoo + +2002-09-11 15:56 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add test case for arg stripping + +2002-09-11 15:37 Martin Pool <mbp@samba.org> + + * Makefile.in, src/.cvsignore, src/Makefile.in, src/h_strip.c, + src/strip.c, src/strip.h, src/util.h: Add code to strip -D and -I + from command lines before passing them, and test harness for + same. + +2002-09-11 13:08 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc + +2002-09-11 12:43 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc from tpot + +2002-09-09 22:44 Martin Pool <mbp@samba.org> + + * test/testdistcc.py, NEWS: Add a test for running 100 compilations + simultaneously. + +2002-09-09 18:56 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2002-09-09 18:31 Martin Pool <mbp@samba.org> + + * src/dopt.c: Doc. + +2002-09-09 16:13 Martin Pool <mbp@samba.org> + + * src/bulk.c: Log info message giving length after receiving files. + +2002-09-09 16:09 Martin Pool <mbp@samba.org> + + * src/arg.c: Fix docs. + +2002-09-09 13:19 Martin Pool <mbp@samba.org> + + * NEWS, src/arg.c: Allow -MD and -MMD to be distributed, since the + compiler will produce a little file locally. + +2002-09-09 12:58 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add todo + +2002-09-09 11:23 Martin Pool <mbp@samba.org> + + * src/distcc.c, NEWS: Try to make sure to uncork client socket + before closing if cpp fails, to work around Linux 2.2 bug that + causes the socket to jam in FIN_WAIT1. + +2002-09-09 10:34 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc + +2002-09-08 18:13 Martin Pool <mbp@samba.org> + + * NEWS, test/testdistcc.py: Test many simple compilations, in case + there is an infrequent error. + +2002-09-08 17:17 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Actually run CppError_Case + +2002-09-08 17:15 Martin Pool <mbp@samba.org> + + * src/exec.c: Remove old doc. + + dcc_collect_child: Show pid returned from wait4, not input pid. + Much better if called with -1. + +2002-09-08 17:12 Martin Pool <mbp@samba.org> + + * src/serve.c: Factor out code for trapping child exit into new + routine. + +2002-09-08 17:08 Martin Pool <mbp@samba.org> + + * NEWS: update news + +2002-09-08 17:08 Martin Pool <mbp@samba.org> + + * src/util.h: dcc_remove_if_exists: new function + +2002-09-08 17:07 Martin Pool <mbp@samba.org> + + * src/serve.c: Remove pid variable which was causing trouble by not + being initialized before the child exited. Instead, just + wait(-1) to collect whatever child was started. + +2002-09-08 17:03 Martin Pool <mbp@samba.org> + + * src/exec.c: When redirecting an fd in a new process, remove the + file if it already exists. + +2002-09-08 16:59 Martin Pool <mbp@samba.org> + + * src/tempfile.c: dcc_remove_if_exists: new common function + +2002-09-08 16:56 Martin Pool <mbp@samba.org> + + * src/: util.h, exec.c: dcc_redirect_fd: Make name consistent. + +2002-09-08 16:56 Martin Pool <mbp@samba.org> + + * src/util.c: dcc_redirect_fd: Make name consistent. Better error + messages. + +2002-09-08 15:54 Martin Pool <mbp@samba.org> + + * NEWS, src/distcc.c: If .o file is 0 bytes or not created on the + server, do not create it on the client either. + +2002-09-08 15:53 Martin Pool <mbp@samba.org> + + * NEWS, src/serve.c: Attempt to fix a race where the compiler + process could exit without opening its input before we started + writing to the FIFO. In that case, the daemon would hang forever + waiting for the compiler to arrive. In the new code, SIGCHLD + causes a longjmp to break out of trying to feed the compiler. + +2002-09-08 15:25 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2002-09-08 15:01 Martin Pool <mbp@samba.org> + + * NEWS, src/serve.c: If the volunteer compiler exits without + reading all of its input, return the compiler's own exit code + across the network, rather than EXIT_DISTCC_FAILED. + +2002-09-08 14:54 Martin Pool <mbp@samba.org> + + * src/serve.c: remove done todo + +2002-09-08 14:48 Martin Pool <mbp@samba.org> + + * NEWS, test/testdistcc.py: Test compiler that succeeds without + reading input. + +2002-09-08 14:29 Martin Pool <mbp@samba.org> + + * NEWS, test/testdistcc.py: Test handling of a file that causes a + preprocessor error. + +2002-09-08 14:19 Martin Pool <mbp@samba.org> + + * Makefile.in: Don't upload Latte source. + +2002-09-06 14:39 Martin Pool <mbp@samba.org> + + * src/distcc.c: Add fixmes. + +2002-09-05 17:56 Martin Pool <mbp@samba.org> + + * src/zip.c: Doc. + +2002-09-05 11:05 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: todo + +2002-09-05 10:07 Martin Pool <mbp@samba.org> + + * src/exec.c: Doc waitstatus requirements. + +2002-09-04 16:14 Martin Pool <mbp@samba.org> + + * NEWS: Modified patch from Alexandre Oliva to handle "distcc -c -S + testtmp.c". + +2002-09-04 16:11 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Test case for "distcc -c -S testtmp.c", + reported by Alexandre Oliva + +2002-09-04 16:08 Martin Pool <mbp@samba.org> + + * src/arg.c: Modified patch from Alexandre Oliva to handle "distcc + -c -S testtmp.c". + +2002-09-04 15:53 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Test case for "distcc -c -S testtmp.c", + reported by Alexandre Oliva + +2002-09-04 13:48 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2002-09-04 13:46 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Notes on getloadavg() + +2002-09-04 12:59 Martin Pool <mbp@samba.org> + + * doc/lzo-notes.txt: Notes on LZO compression + +2002-09-04 12:53 Martin Pool <mbp@samba.org> + + * src/srvnet.c: Use additional headers possibly required on + Solaris. + +2002-09-04 12:52 Martin Pool <mbp@samba.org> + + * src/config.h.in: Check for -lresolv + +2002-09-04 12:51 Martin Pool <mbp@samba.org> + + * NEWS: Solaris portability fixes + +2002-09-04 12:49 Martin Pool <mbp@samba.org> + + * configure: Look for -lresolv, needed on Solaris. + + + http://docs.sun.com/?q=hstrerror&p=/doc/816-3322/6m9k32d1v&a=view + + Suggestion from Dimitri PAPADOPOULOS-ORFANOS. + +2002-09-04 12:47 Martin Pool <mbp@samba.org> + + * analog/.cvsignore: Ignore downloaded logs + +2002-09-04 12:40 Martin Pool <mbp@samba.org> + + * Makefile.in, src/Makefile.in: Solaris "install -d" can only + create a single directory at a time. + + Suggestion from Dimitri PAPADOPOULOS-ORFANOS. + +2002-09-04 12:38 Martin Pool <mbp@samba.org> + + * configure.ac: Look for -lresolv, needed on Solaris. + + + http://docs.sun.com/?q=hstrerror&p=/doc/816-3322/6m9k32d1v&a=view + + Suggestion from Dimitri PAPADOPOULOS-ORFANOS. + +2002-09-04 12:14 Martin Pool <mbp@samba.org> + + * src/distcc.c: Patch from Dimitri PAPADOPOULOS-ORFANOS to fix + signedness warning. + +2002-09-04 10:06 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Note that server log messages stay on the + server. + +2002-09-03 18:13 Martin Pool <mbp@samba.org> + + * NEWS, OLDNEWS: Roll over NEWS + +2002-09-03 18:12 Martin Pool <mbp@samba.org> + + * man/distccd.1: troff fix + +2002-09-03 18:12 Martin Pool <mbp@samba.org> + + * man/distcc.1: Tiny troff fix + +2002-09-03 18:09 Martin Pool <mbp@samba.org> + + * configure.ac: Set version to 0.10cvs + +2002-09-03 18:02 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc. + +2002-09-03 18:00 Martin Pool <mbp@samba.org> + + * analog/distcc.analog: Turn on weekly report. + + Adjust floors. + +2002-09-03 17:49 Martin Pool <mbp@samba.org> + + * Makefile.in: analog-download: Get archived log files + +2002-09-03 15:45 Martin Pool <mbp@samba.org> + + * NEWS, configure, configure.ac: Bump version to 0.9 + +2002-09-03 14:03 Martin Pool <mbp@samba.org> + + * doc/results.txt: More results. + +2002-09-03 14:02 Martin Pool <mbp@samba.org> + + * Makefile.in: Fix linuxdoc targets so that .ps and .info files + don't get rebuilt if the .gz files are up-to-date. + +2002-09-03 13:49 Martin Pool <mbp@samba.org> + + * Makefile.in: Doc. + +2002-09-03 13:49 Martin Pool <mbp@samba.org> + + * Makefile.in: Change .gz rule to compress "in-place" + +2002-09-03 13:48 Martin Pool <mbp@samba.org> + + * Makefile.in: Add new header files to list of things to + distribute! + +2002-09-03 13:40 Martin Pool <mbp@samba.org> + + * news.emacs: emacs stub to set up NEWS file. + +2002-09-03 10:55 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Split TODOs about load balancing out into + their own section. + + Add nice suggestion from Oscar Esteban about allowing some jobs + to be remotely queued. + +2002-09-02 10:33 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add RFC for DNS SRV. + +2002-09-02 10:32 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: More todo notes. + +2002-09-02 09:21 Martin Pool <mbp@samba.org> + + * Makefile.in: Apache logs have moved on new samba.org machine + +2002-09-02 09:17 Martin Pool <mbp@samba.org> + + * Makefile.in: Add analog-all target + +2002-09-02 07:38 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc. + +2002-09-02 07:16 Martin Pool <mbp@samba.org> + + * src/distcc.c: dcc_retrieve_results: If the remote compiler exited + non-zero, but the transfer was successful, return 0, indicating + that there is no point trying to re-run the job locally. + +2002-09-02 07:12 Martin Pool <mbp@samba.org> + + * src/serve.c: If something went wrong running the compiler, then + make sure the overall status is failure. However, only overwrite + the status code if it was not already !0. + +2002-09-02 07:07 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Set up a distcc client log file for all + tests. + +2002-09-02 07:02 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add test case that runs /bin/false to + simulate a compiler that fails without reading its input. + +2002-09-01 15:33 Martin Pool <mbp@samba.org> + + * NEWS: Doc recent changes + +2002-09-01 15:30 Martin Pool <mbp@samba.org> + + * src/bulk.c: Better message for the case where the compile command + exits without opening the fifo. + +2002-09-01 15:27 Martin Pool <mbp@samba.org> + + * src/serve.c: Fix message + +2002-09-01 15:26 Martin Pool <mbp@samba.org> + + * src/serve.c: If compilation failed, then still collect the + compiler child, and send back a reply, with the waitstatus forced + to be failure. + +2002-09-01 15:15 Martin Pool <mbp@samba.org> + + * src/distcc.c, NEWS: dcc_compile_remote: If transmission to the + server fails, close the socket sooner rather than later so as not + to make the server process wait around unnecessarily. + +2002-09-01 15:12 Martin Pool <mbp@samba.org> + + * src/distcc.c: dcc_compile_remote: Split into smaller functions. + +2002-09-01 15:02 Martin Pool <mbp@samba.org> + + * src/bulk.c: Doc. + +2002-09-01 14:28 Martin Pool <mbp@samba.org> + + * NEWS: Add common routine for setting SIGPIPE handling. + +2002-09-01 14:27 Martin Pool <mbp@samba.org> + + * src/serve.c: Split server-side compile code into slightly smaller + functions + + If a network error is detected while feeding data to the + compiler, then it is sent a SIGHUP. + +2002-09-01 14:08 Martin Pool <mbp@samba.org> + + * NEWS, src/exec.c: Set SIGPIPE handler back to default before + starting compiler tasks. + +2002-09-01 14:06 Martin Pool <mbp@samba.org> + + * src/: clinet.c, serve.c, util.c, util.h: Add common routine for + setting SIGPIPE handling. + +2002-09-01 14:05 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Send distccd log to a file while testing -- + easier for postmortems. + +2002-09-01 13:56 Martin Pool <mbp@samba.org> + + * NEWS, src/dparent.c: Do not try to collect daemon children if + --no-fork was specified. Otherwise that routine collects + compilers, and gives crazy messages like "-2 children". + +2002-09-01 13:43 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2002-09-01 09:18 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2002-09-01 09:09 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2002-09-01 09:07 Martin Pool <mbp@samba.org> + + * src/distcc.c: dcc_compile_remote: Better log message + +2002-09-01 09:06 Martin Pool <mbp@samba.org> + + * src/serve.c: dcc_accept_job: Better log message + +2002-09-01 09:05 Martin Pool <mbp@samba.org> + + * src/distcc.c: Fix silly parameter order bug. + +2002-09-01 08:55 Martin Pool <mbp@samba.org> + + * src/dparent.c: Get rid of cloexec, just close fds by hand. + +2002-09-01 08:52 Martin Pool <mbp@samba.org> + + * src/serve.c: Typo + +2002-09-01 08:50 Martin Pool <mbp@samba.org> + + * src/exec.c, NEWS: Close extra file descriptors before starting + the compiler. + +2002-09-01 08:46 Martin Pool <mbp@samba.org> + + * src/dparent.c: Set close-on-exec flags on listen and accepted + fds. + +2002-09-01 08:43 Martin Pool <mbp@samba.org> + + * src/: util.c, util.h: set_cloexec_flag: new function + +2002-09-01 08:39 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc + +2002-09-01 08:38 Martin Pool <mbp@samba.org> + + * src/: distcc.c, serve.c: dcc_accept_job: + + * Use new dcc_mkfifo routine to make sure the fifo is created + properly. + + * Use new dcc_r_file_body, dcc_r_file and dcc_r_fifo routines to + make + sure each type of temporary file is opened in the right way. + +2002-09-01 08:36 Martin Pool <mbp@samba.org> + + * src/daemon.c: tempfile.h: new header + +2002-09-01 08:34 Martin Pool <mbp@samba.org> + + * NEWS: Doc mkfifo changes and BigAssFile_Case + +2002-09-01 08:31 Martin Pool <mbp@samba.org> + + * src/tempfile.c: dcc_mkfifo: + + * New routine. + + * We now unlink before trying to create a fifo, to make sure + that if + somehow that name is already in use by a file or fifo we won't + get + confused. + +2002-09-01 08:29 Martin Pool <mbp@samba.org> + + * src/: rpc.h, bulk.h: bulk.h: new header + +2002-09-01 08:28 Martin Pool <mbp@samba.org> + + * src/io.c: needs exitcode.h + +2002-09-01 08:27 Martin Pool <mbp@samba.org> + + * src/: bulk.c, dparent.c, where.c: tempfile.h: new header + +2002-09-01 07:52 Martin Pool <mbp@samba.org> + + * src/: tempfile.h, distcc.h: Split out tempfile.c routines into + their own header + +2002-09-01 07:49 Martin Pool <mbp@samba.org> + + * src/bulk.c: Doc. + + dcc_r_file: + + * Unlink the name before starting to receive the file. This may + prevent bugs where the name already existed as a fifo. The + old + code would have opened the fifo rather than replacing it, and + therefore would hang. Afterwards, create with O_EXCL. + + * Check that the file is successfully closed. (Might catch + ENOSPC or similar.) + + dcc_r_fd: Fix return code to be the result of transferring the + contents of the file. + +2002-09-01 07:40 Martin Pool <mbp@samba.org> + + * src/io.c: dcc_close: make return code consistent (EXIT_IO_ERROR, + not errno) + +2002-09-01 07:39 Martin Pool <mbp@samba.org> + + * src/exitcode.h: Add EXIT_IO_ERROR + +2002-09-01 07:37 Martin Pool <mbp@samba.org> + + * src/io.c: dcc_close: log file descriptor correctly. + +2002-08-31 14:50 Martin Pool <mbp@samba.org> + + * src/bulk.c: Doc + +2002-08-31 14:45 Martin Pool <mbp@samba.org> + + * test/testdistcc.py, src/clinet.c: Doc + +2002-08-31 14:43 Martin Pool <mbp@samba.org> + + * src/clinet.c: Doc. + + Make variables consistent. + +2002-08-31 14:31 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc. + +2002-08-31 14:23 Martin Pool <mbp@samba.org> + + * src/: bulk.c, serve.c: Doc. + +2002-08-31 14:13 Martin Pool <mbp@samba.org> + + * src/: bulk.c, io.c, io.h, rpc.c, rpc.h, serve.c: dcc_r_token_int: + Add common routine for reading token and parameter value. + +2002-08-31 14:01 Martin Pool <mbp@samba.org> + + * src/rpc.c: Doc. + +2002-08-31 13:58 Martin Pool <mbp@samba.org> + + * src/: io.c, io.h: dcc_write_token: remove dead function + +2002-08-31 13:56 Martin Pool <mbp@samba.org> + + * src/io.c: Cleanup sendfile code somewhat. + +2002-08-31 13:48 Martin Pool <mbp@samba.org> + + * NEWS, linuxdoc/distcc.sgml, src/distcc.c, src/io.c, + src/tempfile.c, src/util.c, src/util.h: dcc_getenv_bool: Add + parameter giving default value so that things can default to + either on or off. + + Add new environment variable for client and server, + DISTCC_TCP_CORK. Defaults to on, intended mostly for performance + comparison or debugging. + +2002-08-31 13:44 Martin Pool <mbp@samba.org> + + * src/rpc.c: Fix prototype + + Use dcc_x_token_int in one case I missed before + +2002-08-31 12:41 Martin Pool <mbp@samba.org> + + * NEWS, src/bulk.c, src/distcc.c, src/rpc.c, src/rpc.h: Write + token/parameters using a single write() call. May be very + slightly more efficient in CPU and perhaps packets. + +2002-08-31 12:13 Martin Pool <mbp@samba.org> + + * src/io.c: Doc. + +2002-08-30 10:53 Martin Pool <mbp@samba.org> + + * src/dparent.c: Doc. + +2002-08-30 10:51 Martin Pool <mbp@samba.org> + + * src/serve.c: Put cork in correct hole. + +2002-08-29 11:43 Martin Pool <mbp@samba.org> + + * src/trace.c: Doc. + +2002-08-29 11:18 Martin Pool <mbp@samba.org> + + * NEWS, src/io.c: Handle the case of sendfile() transmitting only + part of the supplied + data, similarly to a short write on a socket. This doesn't + often + happen, but can occur if a ptrace debugger attaches while + sendfile is + running. + +2002-08-29 10:35 Martin Pool <mbp@samba.org> + + * NEWS, src/distcc.c: Message for completion of local cpp now gives + the correct hostname. + +2002-08-29 10:21 Martin Pool <mbp@samba.org> + + * src/Makefile.in: Include $CFLAGS when linking so that profiling + works + +2002-08-29 10:17 Martin Pool <mbp@samba.org> + + * NEWS: Display test names while they're running so that long tests + are easier to follow. + +2002-08-29 10:06 Martin Pool <mbp@samba.org> + + * NEWS: Doc + +2002-08-29 10:05 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: When trying to kill the daemon, keep pinging + it to make sure it actually died. This prevents the cases + sometimes tripping over each other. + + Fix damage to assembly cases from previous commit + + Doc + + Remove some dead code + +2002-08-29 09:49 Martin Pool <mbp@samba.org> + + * src/dparent.c: Create the pid file from the parent process, so + that we can be sure that it exists before the parent exits. + +2002-08-29 09:24 Martin Pool <mbp@samba.org> + + * src/dparent.c: Turn on signal handlers in parent. Why were they + off? + +2002-08-29 08:50 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add missing newline + +2002-08-29 08:50 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add test for compilation of a large file + (200,000 lines) + +2002-08-29 08:13 Martin Pool <mbp@samba.org> + + * src/serve.c: Uncork sock before exiting. + +2002-08-29 06:50 Martin Pool <mbp@samba.org> + + * src/bulk.c: quote + +2002-08-28 11:33 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc. + +2002-08-28 10:35 Martin Pool <mbp@samba.org> + + * NEWS, src/tempfile.c: Properly support platforms with 32-bit + pids, such as Cygwin. Patch from Aaron Lehmann. + +2002-08-28 10:18 Martin Pool <mbp@samba.org> + + * src/Makefile.in: Remove 'check' target because it must be run + from the parent + +2002-08-26 09:37 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Notes about Cygwin and LNX-BBC volunteers + into TODO list. + +2002-08-26 08:52 Martin Pool <mbp@samba.org> + + * NEWS, configure, configure.ac: On FreeBSD, the sa_family_t type + is defined in <sys/socket.h> (Patch from Dennis Taylor) + +2002-08-26 08:48 Martin Pool <mbp@samba.org> + + * aclocal.m4, configure, configure.ac, NEWS: Bump version to 0.9cvs + +2002-08-26 08:43 Martin Pool <mbp@samba.org> + + * NEWS, OLDNEWS: roll over news + +2002-08-15 18:51 Martin Pool <mbp@samba.org> + + * configure: autoconf + +2002-08-15 18:41 Martin Pool <mbp@samba.org> + + * configure.ac: Set version + +2002-08-15 14:39 Martin Pool <mbp@samba.org> + + * NEWS: Ready for release. + +2002-08-15 12:56 Martin Pool <mbp@samba.org> + + * src/distcc.c: Tweak message + +2002-08-15 12:45 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add assertReMatch utility function + + When testing invalid server names, look in the log for the + warning message. + +2002-08-15 12:24 Martin Pool <mbp@samba.org> + + * src/distcc.c: Only emit the "running locally" notice when the job + ought to be distributed but is not. So having the host set to be + local, or non-distributable arguments just silently works. + +2002-08-15 12:10 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Add headers, remove dead variable + +2002-08-15 12:03 Martin Pool <mbp@samba.org> + + * src/filename.c: Doc + +2002-08-15 11:59 Martin Pool <mbp@samba.org> + + * src/serve.c: dcc_accept_job: patch from Chris Halls to make us + more robust against files where we can't work out the + preprocessor extension. + +2002-08-15 11:57 Martin Pool <mbp@samba.org> + + * NEWS, src/filename.c: Correctly handle compilation of C++ code + under ccache, by properly recognizing the .ii extension. Same + patch from both Stephen White and Chris Halls. + +2002-08-15 11:17 Martin Pool <mbp@samba.org> + + * configure: Run autoconf + +2002-08-12 06:36 Martin Pool <mbp@samba.org> + + * configure.ac: Fix quoting. + +2002-08-10 15:28 Martin Pool <mbp@samba.org> + + * src/where.c: Doc. + + Don't truncate lock files, open them with open(). + +2002-08-10 15:26 Martin Pool <mbp@samba.org> + + * src/bulk.c: Doc. + +2002-08-10 15:19 Martin Pool <mbp@samba.org> + + * src/: distcc.c, exec.c: Doc. + +2002-08-10 15:13 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Explain that we don't keep trying if we + fail to connect. + +2002-08-10 15:11 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc. + +2002-08-10 15:08 Martin Pool <mbp@samba.org> + + * NEWS, src/distcc.c, test/testdistcc.py: If anything goes wrong + with remote compilation other than the remote compiler returning + an error, then run it locally instead. + +2002-08-10 15:07 Martin Pool <mbp@samba.org> + + * src/tempfile.c: dcc_getenv_bool(): new function to make behaviour + of DISTCC_VERBOSE etc consistent. + +2002-08-10 15:05 Martin Pool <mbp@samba.org> + + * src/: arg.c, dparent.c: Adjust error severity levels. + +2002-08-10 15:04 Martin Pool <mbp@samba.org> + + * src/trace.c: rs_format_msg: put the function name before the + severity rather than after. I hate to change message formats but + this seems more readable. + +2002-08-10 15:01 Martin Pool <mbp@samba.org> + + * src/: util.c, util.h: dcc_getenv_bool(): new function to make + behaviour of DISTCC_VERBOSE etc consistent. + +2002-08-10 14:59 Martin Pool <mbp@samba.org> + + * src/trace.c: Make notice messages have a "Notice: " prefix. + +2002-08-10 14:50 Martin Pool <mbp@samba.org> + + * src/clinet.c: Doc + +2002-08-10 14:39 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Put all scratch directories under 'testtmp' + to keep things tidy. + +2002-08-10 14:19 Martin Pool <mbp@samba.org> + + * configure: Run autoconf + +2002-08-09 18:10 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Clearer text about env vars. + +2002-08-09 18:08 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add doc for DISTCC_SAVE_TEMPS + +2002-08-09 18:02 Martin Pool <mbp@samba.org> + + * survey.txt: Better text. + +2002-08-09 17:59 Martin Pool <mbp@samba.org> + + * survey.txt: Better text. + +2002-08-09 17:56 Martin Pool <mbp@samba.org> + + * Makefile.in: Upload survey. + +2002-08-09 17:55 Martin Pool <mbp@samba.org> + + * Makefile.in: Install survey.txt into docs + +2002-08-09 17:53 Martin Pool <mbp@samba.org> + + * configure, configure.ac, survey.txt, src/survey.txt: Running + configure now shows a click-wrapish version of the GPL, plus + information on installation directories, and a request to + complete the survey. + +2002-08-09 17:42 Martin Pool <mbp@samba.org> + + * README: Add survey + +2002-08-09 17:33 Martin Pool <mbp@samba.org> + + * src/survey.txt: Add survey + +2002-08-09 16:43 Martin Pool <mbp@samba.org> + + * NEWS: Add documentation for --no-fifo and --log-stderr. + +2002-08-09 16:29 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add documentation for --no-fifo and + --log-stderr. + +2002-08-09 16:15 Martin Pool <mbp@samba.org> + + * NEWS: Show host specification syntax in --help + +2002-08-09 16:13 Martin Pool <mbp@samba.org> + + * src/distcc.c: Better --help message + +2002-08-09 16:11 Martin Pool <mbp@samba.org> + + * src/distcc.c: Show host specification syntax in --help + +2002-08-09 16:02 Martin Pool <mbp@samba.org> + + * NEWS, OLDNEWS: Roll over NEWS + +2002-08-09 16:01 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Document that $DISTCC_HOSTS can now specify + ports. + +2002-08-08 12:27 Martin Pool <mbp@samba.org> + + * contrib/dmake: Example script contributed by Luke Gorrie + +2002-08-05 23:33 Martin Pool <mbp@samba.org> + + * Makefile.in: There's always one. + +2002-08-05 23:25 Martin Pool <mbp@samba.org> + + * Makefile.in: Add rules to build NEWS and signature files, and to + upload everything to the ftp site. + +2002-08-05 23:19 Martin Pool <mbp@samba.org> + + * configure, configure.ac: Bump version to 0.7; run autoconf. + +2002-08-05 23:19 Martin Pool <mbp@samba.org> + + * README: Note that it probably works on Cygwin now. + +2002-08-05 23:07 Martin Pool <mbp@samba.org> + + * DEPENDENCIES: Add --with-extra-includes and --with-extra-libs + configure options, as in CVS. + + This helps people on platforms such as Solaris and BSD where some + things install into /usr/local, but that is not on the default + path. + +2002-08-05 23:01 Martin Pool <mbp@samba.org> + + * configure.ac, src/Makefile.in: Add --with-extra-includes and + --with-extra-libs configure options, as in CVS. + + This helps people on platforms such as Solaris and BSD where some + things install into /usr/local, but that is not on the default + path. + +2002-08-05 19:47 Martin Pool <mbp@samba.org> + + * Makefile.in: Another attempt at packaging and installing the + manual, but coping on machines without linuxdoc. + +2002-08-05 19:46 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2002-08-05 19:39 Martin Pool <mbp@samba.org> + + * Makefile.in: Make 'all' the default target again. + +2002-08-05 19:28 Martin Pool <mbp@samba.org> + + * Makefile.in: Fix packaging of Linuxdoc html. + +2002-08-05 19:22 Martin Pool <mbp@samba.org> + + * NEWS: Set version for release. + +2002-08-05 15:44 Martin Pool <mbp@samba.org> + + * Makefile.in: Make all latte HTML files depend on style.latte + +2002-08-05 15:15 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add todo + +2002-08-03 23:31 Martin Pool <mbp@samba.org> + + * NEWS: Doc + +2002-08-03 23:29 Martin Pool <mbp@samba.org> + + * NEWS: Add release name + +2002-08-03 23:28 Martin Pool <mbp@samba.org> + + * NEWS: Note that documentation is shipped. + +2002-08-03 18:21 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: We could strip -D and -I from command + lines. + +2002-08-02 15:00 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Remove debugging stub + +2002-08-02 14:58 Martin Pool <mbp@samba.org> + + * src/exec.c: Remove old message + +2002-08-02 14:56 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Don't try to link file which is expected not + to compile. + +2002-08-02 14:43 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Run daemon on port 42000 for testing. + + Check that compiling an invalid file produces no output file. + + Use absolute path for pid file so that it's not confused by + changing directories. + +2002-08-02 14:28 Martin Pool <mbp@samba.org> + + * NEWS: host:port syntax now supported. + +2002-08-02 14:23 Martin Pool <mbp@samba.org> + + * src/: distcc.c, distcc.h, dparent.c, exec.c, hosts.c, hosts.h, + serve.c, where.c: Move towards using passing around dcc_hostdef + structures, rather than just hostnames, so that we can start + supporting nonstandard ports and eventually ssh. + +2002-08-02 14:20 Martin Pool <mbp@samba.org> + + * src/filename.c: Use strrchr() rather than rindex(): they ought to + be identical, but Valgrind seems to dislike rindex() + +2002-08-02 14:19 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc + +2002-08-02 11:59 Martin Pool <mbp@samba.org> + + * NEWS: --log-stderr + +2002-08-02 11:56 Martin Pool <mbp@samba.org> + + * src/: daemon.c, dopt.c, opt.h: Add --log-stderr option, intended + mainly for testing/debugging + +2002-08-02 11:39 Martin Pool <mbp@samba.org> + + * .cvsignore: Ignore *.tmp + +2002-08-02 11:36 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Run all test cases within their own scratch + directory. + +2002-08-01 23:58 Martin Pool <mbp@samba.org> + + * src/serve.c: Add the ability to use either a fifo or a regular + temporary file for input to the compiler, controlled by --no-fifo + or failure to create the fifo. + +2002-08-01 23:39 Martin Pool <mbp@samba.org> + + * src/: daemon.c, dparent.c, serve.c: dcc_accept_job: return + standard exit code + +2002-08-01 23:34 Martin Pool <mbp@samba.org> + + * src/: daemon.c, dparent.c, io.c, io.h: Explicitly close the + socket before exiting, so that we have a better chance of + catching network transmission errors. + +2002-08-01 23:20 Martin Pool <mbp@samba.org> + + * NEWS, src/dopt.c, src/opt.h: Add --no-fifo option. Doesn't do + anything yet. + +2002-08-01 23:19 Martin Pool <mbp@samba.org> + + * Makefile.in: Fix cvsplot target. + +2002-08-01 23:17 Martin Pool <mbp@samba.org> + + * NEWS: Doc + +2002-08-01 23:12 Martin Pool <mbp@samba.org> + + * contrib/distcc.sh: This file, contributed by Dimitri + PAPADOPOULOS-ORFANOS <papadopo@shfj.cea.fr> may be installed as + "cc" somewhere on your $PATH ahead of the real gcc. That allows + you to just use regular Makefiles without modifying them to + change hardcoded calls to cc. + + This script will be a bit slow because of the overhead of running + things through a shell. In a future release, this function + should be supported directly by distcc, which should be a bit + faster. + +2002-08-01 23:02 Martin Pool <mbp@samba.org> + + * src/dparent.c: Define WAIT_ANY if it is missing, as seems to be + the case on Cygwin. + +2002-08-01 22:11 Martin Pool <mbp@samba.org> + + * src/exec.c: Doc. + +2002-08-01 22:07 Martin Pool <mbp@samba.org> + + * src/serve.c: Cygwin needs <signal.h> not <sys/signal.h> + +2002-08-01 21:44 Martin Pool <mbp@samba.org> + + * src/exec.c: Cope without WCOREDUMP, which is missing on Cygwin. + +2002-08-01 21:34 Martin Pool <mbp@samba.org> + + * NEWS, configure, configure.ac, src/config.h.in, src/distcc.h: If + sa_family_t is missing, try just defining it as int. Might help + Cygwin. + +2002-08-01 21:16 Martin Pool <mbp@samba.org> + + * src/where.c: Try using fcntl locks in addition to lockf and + flock. Perhaps this will fix Cygwin. Thanks to Marco Alanen. + +2002-08-01 17:41 Martin Pool <mbp@samba.org> + + * src/: daemon.c, dopt.c, opt.h: Make errors from command-line + options go to stderr. + +2002-08-01 17:14 Martin Pool <mbp@samba.org> + + * Makefile.in: Always build check programs before running checks, + even with -j. + + Specify complete PATH to binaries when running tests, so that + they can change into subdirectories. + +2002-07-25 17:14 Martin Pool <mbp@samba.org> + + * Makefile.in: Remove file that's no longer in CVS from distro. + +2002-07-25 17:11 Martin Pool <mbp@samba.org> + + * doc/results.txt: Add results file; not much here yet. + +2002-07-25 16:58 Martin Pool <mbp@samba.org> + + * Makefile.in: Add a somewhat-hacky "make dist" target to build a + tarball. + + Compared to just "cvs export", this means we get to include built + versions of the documents, which is nice for people who can't + easily get the Linuxdoc SGML tools to work. It does make the + binary bigger because there are so many formats, though. + + Also, we omit things that end users might not want, such as the + Latte web site source. People can get it from CVS (or rsync) if + they care. + +2002-07-25 16:08 Martin Pool <mbp@samba.org> + + * configure, configure.ac: Bump version + +2002-07-24 19:03 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Clear the environment before running the + child -- this avoids any problems with the developer's + environment. + +2002-07-24 19:02 Martin Pool <mbp@samba.org> + + * src/dparent.c: Change the semantics for detaching a little bit: + we now do it once the socket is listening. This is rather more + useful for the test suite, because the suite now knows for sure + that when the parent exits, it can go ahead and try to connect. + +2002-07-24 18:58 Martin Pool <mbp@samba.org> + + * DEPENDENCIES, Makefile.in: Test case now requires python 2.2 for + proper unsetenv() semantics + +2002-07-24 18:50 Martin Pool <mbp@samba.org> + + * NEWS: foo + +2002-07-24 18:49 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Avoid using asprintf() because it's missing on + Solaris + +2002-07-24 18:49 Martin Pool <mbp@samba.org> + + * src/where.c: dcc_make_lock_filename: new function + + Avoid using asprintf() because it's missing on Solaris + +2002-07-24 18:48 Martin Pool <mbp@samba.org> + + * src/exitcode.h: Doc + +2002-07-24 17:57 Martin Pool <mbp@samba.org> + + * src/dparent.c: remove pid file if daemon exits on signal + +2002-07-24 17:55 Martin Pool <mbp@samba.org> + + * src/dparent.c, NEWS: Log pid even if running with --no-fork. + Remove pid file on exit. + +2002-07-24 14:39 Martin Pool <mbp@samba.org> + + * Makefile.in, configure, configure.ac, patches/distc, + patches/distc++: Suggestion from Dimitri PAPADOPOULOS-ORFANOS: + should check for -lnsl and -lsocket on Solaris. + +2002-07-24 14:38 Martin Pool <mbp@samba.org> + + * OLDNEWS, NEWS: Roll over news + +2002-07-23 11:36 Martin Pool <mbp@samba.org> + + * Makefile.in: Add the start of an FAQ, and the AOSS4 slides. + +2002-07-22 16:45 Martin Pool <mbp@samba.org> + + * Makefile.in: Doc. + +2002-07-12 11:46 Martin Pool <mbp@samba.org> + + * configure: Rerun autoconf + +2002-07-12 11:44 Martin Pool <mbp@samba.org> + + * Makefile.in: "make install" doesn't imply install-linuxdoc + +2002-07-12 11:38 Martin Pool <mbp@samba.org> + + * Makefile.in: "make install" doesn't imply install-linuxdoc + +2002-07-12 11:34 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Start adding to the test framework a way for + test cases to provide their own explanation of why they failed. + In particular, for ones that run shell commands, dump out all the + commands that were run, and their output. + +2002-07-12 11:33 Martin Pool <mbp@samba.org> + + * src/distcc.c: Give a proper error message for "distcc --fubar", + even when we would have chosen to run the command locally. + +2002-07-12 11:32 Martin Pool <mbp@samba.org> + + * src/daemon.c: If stdin is neither a socket nor a tty assume + --daemon mode. This is more compatible with previous usage. + +2002-07-12 11:19 Martin Pool <mbp@samba.org> + + * src/arg.c: Correct message for "distcc --bad-option" + +2002-07-12 10:51 Martin Pool <mbp@samba.org> + + * configure.ac: Set version for release. + +2002-07-12 10:45 Martin Pool <mbp@samba.org> + + * NEWS: Update news for release. + +2002-07-12 10:39 Martin Pool <mbp@samba.org> + + * DEPENDENCIES: Clarify requirements for libpopt + +2002-07-12 10:37 Martin Pool <mbp@samba.org> + + * Makefile.in: Install info files into the right directory + +2002-07-10 15:37 Martin Pool <mbp@samba.org> + + * src/arg.c: dcc_set_action_opt: Need to also understand how to + transform "gcc -S hello.c" to "gcc -o hello.i -E hello.c" for the + client. + +2002-07-10 15:11 Martin Pool <mbp@samba.org> + + * NEWS, src/arg.c, src/distcc.h, src/filename.c: distcc will now + distribute jobs which use -s to compile but not + assemble. Previously they were always run locally, but there's + no + strong reason why they must be. Unfortunately you need to + upgrade + both the client and server for this to work, because old servers + will + refuse to run gcc with -s. + +2002-07-10 14:07 Martin Pool <mbp@samba.org> + + * NEWS, src/tempfile.c: dcc_cleanup_tempfiles: If + $DISTCC_SAVE_TEMPS is set to "1", then files are not actually + deleted -- good for debugging. + +2002-07-09 14:38 Martin Pool <mbp@samba.org> + + * Makefile.in: Add page with current problems + +2002-07-09 12:06 Martin Pool <mbp@samba.org> + + * Makefile.in: Add target to run Linbot to check for broken links. + +2002-07-08 17:20 Martin Pool <mbp@samba.org> + + * configure: autogen + +2002-07-08 17:18 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.h: Fix prototypes + +2002-07-08 17:17 Martin Pool <mbp@samba.org> + + * src/dopt.c: distccd_show_usage: Document new options + +2002-07-08 17:16 Martin Pool <mbp@samba.org> + + * NEWS: dcc_scan_args: -M causes the preprocessor to produce a list + of make-style dependencies on header files, either to stdout or + to a local file. It implies -E, so only the preprocessor is run, + not the compiler. There would be no point trying to distribute + it even if we could. + +2002-07-08 17:13 Martin Pool <mbp@samba.org> + + * src/daemon.c, linuxdoc/distcc.sgml: Change --inetd and --daemon + defaults: + + - if both are specified, die + - if either is specified, do that + - if stdin is a socket or tty assume inetd or daemon + respectively + - otherwise, complain + +2002-07-08 17:03 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Document more distccd command-line options + +2002-07-08 17:00 Martin Pool <mbp@samba.org> + + * man/distcc.1: Syntax fix + +2002-07-08 16:57 Martin Pool <mbp@samba.org> + + * DEPENDENCIES: Clarify dependencies + +2002-07-08 16:54 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Clarify that distcc returns the same value + as the compiler. + +2002-07-08 16:53 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Clarify description how to get environment + variables set properly. + +2002-07-08 16:50 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Clarify description of jobs which are + distributed or local, give an example of a typical command that + can be distributed. + +2002-07-08 16:46 Martin Pool <mbp@samba.org> + + * src/arg.c: dcc_scan_args: -M causes the preprocessor to produce a + list of make-style dependencies on header files, either to stdout + or to a local file. It implies -E, so only the preprocessor is + run, not the compiler. There would be no point trying to + distribute it even if we could. + +2002-07-08 16:33 Martin Pool <mbp@samba.org> + + * Makefile.in: Doc. + +2002-07-07 22:23 Martin Pool <mbp@samba.org> + + * NEWS: Works on FreeBSD? + +2002-07-07 22:12 Martin Pool <mbp@samba.org> + + * src/Makefile.in: Have to respect $LDFLAGS so we can build on BSD. + Thanks Lauri! + +2002-07-07 22:11 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: SyntaxError_Case: Be less fussy about the + exact compiler error message + +2002-07-07 21:58 Martin Pool <mbp@samba.org> + + * configure.ac: Doc. + +2002-07-07 21:52 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: --version output has changed to include build + date and to just say "protocol 1" + +2002-07-07 21:46 Martin Pool <mbp@samba.org> + + * src/arg.c: Temporary fix for "distcc -c hello.c" + +2002-07-07 21:43 Martin Pool <mbp@samba.org> + + * NEWS: Note about valgrind fix + +2002-07-07 21:02 Martin Pool <mbp@samba.org> + + * Makefile.in: We don't build the web pages or manual by default, + because many people will not have the tools to do it. Just use + all-web or all-linuxdoc if you want them. + +2002-07-07 21:01 Martin Pool <mbp@samba.org> + + * DEPENDENCIES, README: Put the documentation of dependencies in a + separate file where it can be more easily found by people doing + ports. + +2002-07-07 20:08 Martin Pool <mbp@samba.org> + + * src/arg.c: dcc_argv_tostr: If out of memory, give an error and + exit, rather than aborting. + + Apparently Valgrind doesn't like using strchr(s, 0) to find the + terminating nul. I wonder why? + +2002-07-07 19:51 Martin Pool <mbp@samba.org> + + * src/distcc.h: Add missing prototype + +2002-07-07 19:40 Martin Pool <mbp@samba.org> + + * src/: .cvsignore, h_argvtostr.c: Start new test case h_argvtostr + +2002-07-07 19:38 Martin Pool <mbp@samba.org> + + * src/: Makefile.in, arg.c, filename.c, distcc.h: Split filename + manipulation code out into new file filename.c + +2002-07-07 19:36 Martin Pool <mbp@samba.org> + + * src/distcc.c: Get ready to handle command lines with implied + compiler. + +2002-07-06 18:24 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc about the idea of handling "distcc -c hello.c" + +2002-07-06 18:11 Martin Pool <mbp@samba.org> + + * src/distcc.c: Remove old docs. + +2002-07-06 18:07 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Document --ping option. + +2002-07-06 18:00 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: The log now shows execution time; remove + this from the todo list. + +2002-07-06 16:49 Martin Pool <mbp@samba.org> + + * src/: clinet.c, clinet.h, distcc.c, distcc.h: + dcc_open_socket_out: use the standard error return mechanism + +2002-07-06 16:44 Martin Pool <mbp@samba.org> + + * src/: daemon.c, dparent.c: Include build date/time in daemon + startup message + +2002-07-06 16:41 Martin Pool <mbp@samba.org> + + * src/help.c: dcc_show_version: Include build date/time + +2002-07-06 16:32 Martin Pool <mbp@samba.org> + + * src/clinet.c: dcc_open_socket_out: Return EXIT_CONNECT_FAILED if + it did (or indeed for all client socket-opening errors at the + moment.) + +2002-07-06 16:24 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Notes about distcc with autoconf.Doc. + +2002-07-06 16:18 Martin Pool <mbp@samba.org> + + * src/: distcc.c, distcc.h, exec.c, serve.c, util.c, util.h: + myhostname: rename to dcc_gethostname for consistency + + dcc_spawn_child, dcc_redirect_fds: add another parameter + specifying redirection for stdin, so that the same routine can be + used on the client (with regular stdin) or on the server (with + /dev/null) + + dcc_compile_local: Run the compiler as a child process, not over + the top of us. + + distcc/main: Log exit code. + +2002-07-06 16:02 Martin Pool <mbp@samba.org> + + * src/distcc.c: Rename dcc_run_remote and dcc_build_locally to + dcc_compile_* to be consistent. + +2002-07-06 15:57 Martin Pool <mbp@samba.org> + + * src/exec.c: Doc. + +2002-07-06 15:56 Martin Pool <mbp@samba.org> + + * NEWS: dcc_exit: Show self and children's CPU time usage when + exiting. + +2002-07-06 15:54 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml, src/where.c: dcc_pick_buildhost: If the + host specification is invalid or missing, fall back to building + locally with a warning. + +2002-07-06 15:51 Martin Pool <mbp@samba.org> + + * src/where.c: dcc_pick_buildhost: bug fix: if we fail to parse the + host specification, then return the right error. + +2002-07-06 15:50 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: More detail on handling of invalid + hostspecs. + +2002-07-06 15:46 Martin Pool <mbp@samba.org> + + * src/util.c: dcc_exit: Show self and children's CPU time usage + when exiting. + +2002-07-05 17:12 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Note about libtool. + +2002-07-05 16:48 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add note about Makefiles which don't use + $(CC). + +2002-07-05 12:48 Martin Pool <mbp@samba.org> + + * NEWS, src/daemon.c, src/dopt.c, src/opt.h: Add --daemon and + --inetd options, so that you can properly start a remote daemon + with a single-line ssh command. + +2002-07-05 12:32 Martin Pool <mbp@samba.org> + + * src/dparent.c: Need sys/ioctl.h + +2002-07-05 11:31 Martin Pool <mbp@samba.org> + + * configure, configure.ac: Put docs in $prefix/share/doc + +2002-07-05 11:21 Martin Pool <mbp@samba.org> + + * Makefile.in: Add "make showpaths" target to show where "make + install" will put things. + +2002-07-04 23:42 Martin Pool <mbp@samba.org> + + * NEWS: Show CPU usage of compiler, cpp, etc + +2002-07-04 23:39 Martin Pool <mbp@samba.org> + + * .cvsignore, src/daemon.c, src/distcc.c, src/distcc.h, src/exec.c, + src/serve.c: Show CPU usage of compiler, cpp, etc + +2002-07-04 23:38 Martin Pool <mbp@samba.org> + + * Makefile.in: Fix "make install" + +2002-07-04 23:23 Martin Pool <mbp@samba.org> + + * Makefile.in: Shush linuxdoc + +2002-07-04 23:10 Martin Pool <mbp@samba.org> + + * src/exec.c: Doc. + +2002-07-04 23:06 Martin Pool <mbp@samba.org> + + * src/exec.c: Better trace message. + +2002-07-04 23:06 Martin Pool <mbp@samba.org> + + * src/dparent.c: Doc. + +2002-07-04 23:05 Martin Pool <mbp@samba.org> + + * src/exec.c: Fix inverted test on waitpid() result. + + Doc. + +2002-07-04 23:01 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc (passing server errors back to client) + +2002-07-04 22:56 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Note about tcpwrappers. + + Note that you can now set the server port number. + +2002-07-04 22:46 Martin Pool <mbp@samba.org> + + * src/daemon.c: Doc. + +2002-07-04 22:15 Martin Pool <mbp@samba.org> + + * Makefile.in: distclean removes config.log + + Better maintainer-clean rules + +2002-07-04 22:12 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc. + +2002-07-04 22:03 Martin Pool <mbp@samba.org> + + * Makefile.in, linuxdoc/.cvsignore, man/.cvsignore: More Makefile + fiddling + + - make "all" the default rule again + - add "upload-linuxdoc" + - try make SGML stuff build properly + +2002-07-04 21:48 Martin Pool <mbp@samba.org> + + * Makefile.in, configure, configure.ac, linuxdoc/Makefile.in: Move + linuxdoc stuff into top-level Makefile too + +2002-07-04 21:31 Martin Pool <mbp@samba.org> + + * Makefile.in, configure, configure.ac, man/Makefile.in: Move man/ + makefile into top level + +2002-07-03 23:11 Martin Pool <mbp@samba.org> + + * Makefile.in: New design of the web site, now using Latte. + +2002-07-03 20:31 Martin Pool <mbp@samba.org> + + * Makefile.in, analog/Makefile, analog/distcc.analog: Fiddle analog + Make rules; use jdresolve to do DNS resolution. + +2002-07-03 19:58 Martin Pool <mbp@samba.org> + + * analog/.cvsignore: Ignore more stuff + +2002-07-03 16:57 Martin Pool <mbp@samba.org> + + * Makefile.in: Further Makefile fudging + +2002-07-03 16:54 Martin Pool <mbp@samba.org> + + * analog/.cvsignore: Ignore built files. + +2002-07-03 16:47 Martin Pool <mbp@samba.org> + + * Makefile.in: Move web/latte rules into top-level Makefile. + + Add more maintainer-clean rules + +2002-07-02 17:14 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: We now have proper C++ support, so s/C/C or + C++/ where appropriate. + +2002-07-02 17:11 Martin Pool <mbp@samba.org> + + * man/: distcc.1, distccd.1: Update manpages, and remove + information that is redundant with the SGML manual. I think + between them, the big manual and --help are more useful than man + pages, and they're certainly easier to maintain. + +2002-07-02 12:05 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add bug. + +2002-07-01 19:39 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Clearer explanation of multiprocessor + scheduling. + +2002-07-01 19:36 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add CVS revision. + +2002-07-01 19:35 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add new error codes 105, 106 + +2002-07-01 19:32 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Make titles consistent + +2002-07-01 19:31 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Remove redundant SMP section + +2002-07-01 19:27 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: "Leaky buckets" explanation of scheduling + algorithm. + +2002-07-01 09:38 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc + +2002-07-01 09:34 Martin Pool <mbp@samba.org> + + * src/dopt.c: Fix small syntax error + +2002-07-01 09:34 Martin Pool <mbp@samba.org> + + * src/dopt.c: Add --verbose option for daemon + +2002-07-01 09:23 Martin Pool <mbp@samba.org> + + * NEWS: emacs-fu + +2002-07-01 09:22 Martin Pool <mbp@samba.org> + + * NEWS: Reformat + +2002-07-01 09:15 Martin Pool <mbp@samba.org> + + * NEWS, src/daemon.c, src/distcc.h, src/dparent.c, src/serve.c: + Move check for !getuid() up to a higher level so that the daemon + refuses to start at all. + +2002-07-01 09:08 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Improved quick-start guide. + +2002-06-30 22:01 Martin Pool <mbp@samba.org> + + * linuxdoc/: distcc.sgml: Better URL link. + +2002-06-30 21:59 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add link to ccache. + +2002-06-30 21:59 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Clarify bug about compilers which touch + local files. + +2002-06-30 21:58 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Clarify large-file message. + +2002-06-30 21:55 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Substantially improved section on + cross-compilation; give more details on how to use -b. + +2002-06-30 17:32 Martin Pool <mbp@samba.org> + + * analog/distcc.analog: Show more referers + +2002-06-30 17:32 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Fix regexp for new error message. + +2002-06-30 17:31 Martin Pool <mbp@samba.org> + + * src/: .cvsignore, Makefile.in, hosts.c, where.c: Change to new + hostspec parser + +2002-06-30 00:34 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: All tests now moved across to new framework + +2002-06-30 00:26 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Go back to purely object-based definitions of + test cases + +2002-06-30 00:02 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Fiddle with comfychair interface + +2002-06-30 00:00 Martin Pool <mbp@samba.org> + + * src/: trace.c, trace.h: Rename rs_trace_stderr to + rs_trace_to_file, a more correct name. + +2002-06-29 23:59 Martin Pool <mbp@samba.org> + + * src/dopt.c: Add --log-file option + +2002-06-29 23:58 Martin Pool <mbp@samba.org> + + * src/: dparent.c, distcc.h: Make dcc_become_daemon private + +2002-06-29 23:57 Martin Pool <mbp@samba.org> + + * analog/Makefile: Fix Makefile + +2002-06-29 23:28 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Make comfychair more OO. + +2002-06-29 23:14 Martin Pool <mbp@samba.org> + + * src/serve.c: Refuse to run daemon as root. + +2002-06-29 23:13 Martin Pool <mbp@samba.org> + + * src/hosts.c: Doc. + +2002-06-29 23:00 Martin Pool <mbp@samba.org> + + * doc/scheduling.txt: Notes on scheduling + +2002-06-29 16:39 Martin Pool <mbp@samba.org> + + * src/OLDNEWS: Moved + +2002-06-29 01:49 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add more host parser cases. + +2002-06-29 01:44 Martin Pool <mbp@samba.org> + + * src/hosts.c: Correctly handle ssh tokens with command specified. + +2002-06-29 01:42 Martin Pool <mbp@samba.org> + + * src/h_hosts.c, src/hosts.c, src/hosts.h, test/testdistcc.py: Add + special host type for local compilation. + +2002-06-29 01:38 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Better hosts parser test + +2002-06-29 01:37 Martin Pool <mbp@samba.org> + + * src/hosts.c: Fix parser bug in tcp with specified port. + +2002-06-29 01:32 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Doc. + +2002-06-29 01:25 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add test case for host specification parser. + +2002-06-29 01:24 Martin Pool <mbp@samba.org> + + * src/hosts.c: Hosts parser that works better with missing + components. + +2002-06-29 00:53 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Move more tests from pyunit to comfychair. + It's definitely more comfortable! + +2002-06-29 00:39 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Move more tests from pyunit to comfychair. + It's definitely more comfortable! + +2002-06-28 23:23 Martin Pool <mbp@samba.org> + + * src/srvnet.c: Also show numeric client address in connection + message + +2002-06-28 23:19 Martin Pool <mbp@samba.org> + + * linuxdoc/Makefile.in: Fix Makefile a bit more + +2002-06-28 23:15 Martin Pool <mbp@samba.org> + + * linuxdoc/Makefile.in: Fix Makefile + +2002-06-28 23:14 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Bump version. + + Note about IPv6 + +2002-06-28 23:03 Martin Pool <mbp@samba.org> + + * src/dparent.c: Doc. + +2002-06-28 23:01 Martin Pool <mbp@samba.org> + + * src/dparent.c: When in no-fork mode, clean up files after each + job + +2002-06-28 22:59 Martin Pool <mbp@samba.org> + + * src/Makefile.in: Drop sbin install target. + +2002-06-28 22:49 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Doc. + +2002-06-28 22:14 Martin Pool <mbp@samba.org> + + * src/: dopt.c, dparent.c, opt.h: Add --no-fork option to daemon to + help with some debugging stuff. + +2002-06-28 21:51 Martin Pool <mbp@samba.org> + + * man/distcc.1: Add newline + +2002-06-28 21:50 Martin Pool <mbp@samba.org> + + * man/distccd.1: Make a slightly more useful distccd manpage + +2002-06-28 21:41 Martin Pool <mbp@samba.org> + + * analog/Makefile: Create report/ subdir if it doesn't exist. + +2002-06-28 21:40 Martin Pool <mbp@samba.org> + + * linuxdoc/Makefile.in: Create html/ subdir if it doesn't exist. + +2002-06-28 18:35 Martin Pool <mbp@samba.org> + + * README: Make it clear that we do C++ too! + + Try to explain relationship to gcc. + +2002-06-28 18:20 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: test_option_version: Handle host triples like + i386-unknown-freebsd4.4 (Claes Wallin) + +2002-06-28 16:57 Martin Pool <mbp@samba.org> + + * src/dparent.c: Doc. + +2002-06-28 16:53 Martin Pool <mbp@samba.org> + + * src/: dparent.c, exec.c: The two routines that call waitpid() + must handle EINTR, in case a signal arrives while waiting. + + (Perhaps on BSD if a child exits, you will break out with SIGCHLD + and then need to wait again? Not sure.) + +2002-06-28 16:49 Martin Pool <mbp@samba.org> + + * Makefile.in: Add target to run old (currently broken) pyunit + tests + +2002-06-28 16:47 Martin Pool <mbp@samba.org> + + * src/distcc.h: Add prototypes for hosts.c + +2002-06-28 16:33 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2002-06-28 16:19 Martin Pool <mbp@samba.org> + + * src/: io.c: Better message. + +2002-06-28 16:13 Martin Pool <mbp@samba.org> + + * src/Makefile.in: distccd ought to be in bin/; add rationale. + +2002-06-28 16:04 Martin Pool <mbp@samba.org> + + * NEWS, src/io.c: If the system supports sendfile, but the + particular filesystem we're on (e.g. tmpfs) doesn't, then fall + back to using read/write. + +2002-06-28 16:02 Martin Pool <mbp@samba.org> + + * src/Makefile.in: Makefile must properly inherit configured + variables + +2002-06-28 16:01 Martin Pool <mbp@samba.org> + + * man/Makefile.in: Remove old Makefile target to do with + pre-processed manpages + +2002-06-28 16:00 Martin Pool <mbp@samba.org> + + * configure: foo + +2002-06-28 15:59 Martin Pool <mbp@samba.org> + + * man/Makefile.in: distccd can be run by ordinary users, so + arguably belongs in section 1. + +2002-06-28 13:20 Martin Pool <mbp@samba.org> + + * NEWS: Foo + +2002-06-28 13:18 Martin Pool <mbp@samba.org> + + * README: Update README. + +2002-06-28 13:12 Martin Pool <mbp@samba.org> + + * src/Makefile.in: Make directories before installing into them. + +2002-06-28 13:08 Martin Pool <mbp@samba.org> + + * OLDNEWS: Merge news from 0.5 and make format consistent. + +2002-06-28 13:07 Martin Pool <mbp@samba.org> + + * Makefile.in: Also install top-level documentation (e.g. README) + +2002-06-28 13:05 Martin Pool <mbp@samba.org> + + * configure.ac, linuxdoc/Makefile.in, man/Makefile.in, + src/Makefile.in: More work on 'make install' + +2002-06-28 12:49 Martin Pool <mbp@samba.org> + + * configure.ac, analog/distcc.analog, man/Makefile.in: More + automake removal, mostly for man/ + +2002-06-28 12:48 Martin Pool <mbp@samba.org> + + * Makefile.in: If any sub-make fails, the top-level one should fail + too. + +2002-06-28 12:06 Martin Pool <mbp@samba.org> + + * Makefile.in, configure, configure.ac, linuxdoc/.cvsignore, + src/Makefile.in: More work on conversion away from automake + +2002-06-28 11:56 Martin Pool <mbp@samba.org> + + * linuxdoc/Makefile.in: Cleanup. + + Only remove documents with maintainer-clean. + +2002-06-28 11:50 Martin Pool <mbp@samba.org> + + * linuxdoc/Makefile.in: Remove automake cruft. + +2002-06-28 11:42 Martin Pool <mbp@samba.org> + + * src/io.c: Merge fixup + +2002-06-28 11:41 Martin Pool <mbp@samba.org> + + * patches/ChangeLog: kill changelogs + +2002-06-28 11:40 Martin Pool <mbp@samba.org> + + * missing: remove automake cruft + +2002-06-28 11:38 Martin Pool <mbp@samba.org> + + * .cvsignore, linuxdoc/distcc.sgml, src/arg.c, src/distcc.c, + src/distcc.h, src/exec.c, src/h_scanargs.c, src/io.c, + src/serve.c: Merge changes from freeze_0_5 branch: + + - avoid argv[] overrun bug + + - more trace messages + + - some refactoring/cleanups + + - FreeBSD sendfile portability fix + + - better exit codes + +2002-06-28 11:23 Martin Pool <mbp@samba.org> + + * analog/: Makefile, distcc.analog: Add analog config. + +2002-06-27 22:45 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Also test hostspec parser. + +2002-06-27 22:43 Martin Pool <mbp@samba.org> + + * src/hosts.c: Better messages for EXIT_BAD_HOSTSPEC + +2002-06-27 22:41 Martin Pool <mbp@samba.org> + + * src/hosts.c: dcc_parse_hosts() needs to return EXIT_BAD_HOSTSPEC + if no hosts are defined. + +2002-06-27 22:29 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Port more tests from PyUnit. + +2002-06-27 22:27 Martin Pool <mbp@samba.org> + + * Makefile.in: Run tests against just-built executables. + +2002-06-27 22:12 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Add a slightly nontrivial test that we can + call --version on distcc and distccd. + +2002-06-27 21:59 Martin Pool <mbp@samba.org> + + * Makefile.in: Don't run pyunit by default any more. + +2002-06-27 21:58 Martin Pool <mbp@samba.org> + + * Makefile.in: Call comfy chair and pyunit tests + +2002-06-27 21:57 Martin Pool <mbp@samba.org> + + * test/testdistcc.py: Start of conversion of Python tests to use + comfy chair + +2002-06-27 21:45 Martin Pool <mbp@samba.org> + + * Makefile.in, aclocal.m4: Start getting 'make check' working + without automake. + +2002-06-27 21:45 Martin Pool <mbp@samba.org> + + * src/Makefile.in: Add non-automake rules to build test harnesses. + +2002-06-27 21:34 Martin Pool <mbp@samba.org> + + * src/exitcode.h: Cleanup. + +2002-06-27 21:33 Martin Pool <mbp@samba.org> + + * src/: daemon.c, dparent.c: Fixes for removal of automake. + +2002-06-27 21:29 Martin Pool <mbp@samba.org> + + * src/distcc.h: Add a new host specification string parser (not + called yet except from test case.) + +2002-06-27 21:28 Martin Pool <mbp@samba.org> + + * src/io.c: Reindent. + + Emit trace messages when (un)corking sockets. + +2002-06-27 21:25 Martin Pool <mbp@samba.org> + + * src/trace.h: Change rs_log_critical to rs_log_crit to be + consistent. + +2002-06-27 21:24 Martin Pool <mbp@samba.org> + + * src/srvnet.c: Doc + +2002-06-27 21:24 Martin Pool <mbp@samba.org> + + * src/: hosts.c, where.c: Add a new host specification string + parser (not called yet except from test case.) + +2002-06-27 21:24 Martin Pool <mbp@samba.org> + + * src/h_hosts.c: Print out the results of parsing the host + specification. + + Pass exit code from scanner out. + +2002-06-27 21:23 Martin Pool <mbp@samba.org> + + * src/exitcode.h: Add additional exit codes: compiler crashed, out + of memory, bad hostspec. + + Doc. + +2002-06-27 21:20 Martin Pool <mbp@samba.org> + + * src/dparent.c: Log an info message when standalone daemon starts, + including version. + +2002-06-27 21:20 Martin Pool <mbp@samba.org> + + * src/daemon.c: Log an info message when inetd daemon starts. + +2002-06-27 20:36 Martin Pool <mbp@samba.org> + + * configure, configure.ac: Bump version to 0.5 + +2002-06-27 20:32 Martin Pool <mbp@samba.org> + + * NEWS: Add date, etc. + +2002-06-27 20:28 Martin Pool <mbp@samba.org> + + * NEWS: Update NEWS + +2002-06-27 20:25 Martin Pool <mbp@samba.org> + + * src/io.c: Doc. + +2002-06-27 14:34 Martin Pool <mbp@samba.org> + + * configure, configure.ac: Bump version. + +2002-06-27 13:46 Martin Pool <mbp@samba.org> + + * src/io.c: Try to handle FreeBSD's different API for sendfile() by + introducing a sys_sendfile() portability wrapper. + +2002-06-27 13:23 Martin Pool <mbp@samba.org> + + * Makefile.am, Makefile.in, NEWS, aclocal.m4, autogen.sh, + configure, configure.ac, linuxdoc/Makefile.am, man/Makefile.am, + src/Makefile.am, src/Makefile.in, src/config.h.in, src/help.c: + Get rid of automake, just use plain autoconf 2.53. What a mess! + + Building the basic executables should still work; test cases etc + is probably broken at the moment. + +2002-06-27 10:39 Martin Pool <mbp@samba.org> + + * ChangeLog, Makefile.in, aclocal.m4, contrib/ChangeLog, + doc/ChangeLog, linuxdoc/ChangeLog, linuxdoc/Makefile.in, + man/ChangeLog, man/Makefile.in, src/ChangeLog, src/Makefile.in: + Run autogen Remove dumb ChangeLogs + +2002-06-26 21:59 Martin Pool <mbp@samba.org> + + * Makefile.in, aclocal.m4, configure, depcomp, missing, + linuxdoc/Makefile.in, man/Makefile.in, src/Makefile.in: Upgrade + automake to 1.5. + +2002-06-26 21:59 Martin Pool <mbp@samba.org> + + * NEWS: Set version. + +2002-06-26 21:58 Martin Pool <mbp@samba.org> + + * autogen.sh, .cvsignore: ChangeLogs no longer stored in CVS. + +2002-06-26 21:56 Martin Pool <mbp@samba.org> + + * src/dparent.c: Handle EINTR from waitpid(), which is expected on + FreeBSD. + +2002-06-26 14:49 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Document EXIT_COMPILER_CRASHED. + +2002-06-26 14:44 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc. + + Clearer message for remote compiler failure. + +2002-06-26 14:35 Martin Pool <mbp@samba.org> + + * ChangeLog, contrib/ChangeLog, doc/ChangeLog, linuxdoc/ChangeLog, + man/ChangeLog, patches/ChangeLog, src/ChangeLog: Remove + ChangeLogs -- I'm not convinced that keeping them in CVS makes + much sense. If you want them, autogenerate them. + +2002-06-26 14:21 Martin Pool <mbp@samba.org> + + * configure, configure.ac: Set version to 0.5rc1 + +2002-06-26 14:19 Martin Pool <mbp@samba.org> + + * NEWS, src/arg.c, src/distcc.c, src/distcc.h, src/exec.c, + src/exitcode.h, src/h_hosts.c, src/h_scanargs.c, src/serve.c: Fix + bug in h_hosts that caused us to write off the end of the real + argv[], rather than a copy. Thanks to Julian Seward. + + Use more specific return codes when the remote compiler fails: + EXIT_COMPILER_CRASHED for a signal, or the return code from the + compiler if it exited non-0. + + Refactor client main() to be a bit clearer. + +2002-06-22 14:44 Martin Pool <mbp@samba.org> + + * src/: t_exten, t_issource, t_version: Remove unused sh-based + tests. + +2002-06-22 03:58 Martin Pool <mbp@samba.org> + + * Makefile.in, NEWS, aclocal.m4, configure, configure.ac, + linuxdoc/Makefile.in, man/Makefile.in, src/Makefile.in: Bump + version to 0.5. + +2002-06-22 03:56 Martin Pool <mbp@samba.org> + + * src/trace.h: Doc. + +2002-06-21 19:48 Martin Pool <mbp@samba.org> + + * src/: distcc.h, h_hosts.c, hosts.c, where.c: Make everything + build again :) + +2002-06-21 19:46 Martin Pool <mbp@samba.org> + + * src/hosts.c: Doc. + +2002-06-21 19:34 Martin Pool <mbp@samba.org> + + * src/hosts.c: dcc_parse_hosts_env: Better parser that splits + things into words and recognizes the two types of host + definition. Doesn't do the whole job yet though. + +2002-06-21 19:33 Martin Pool <mbp@samba.org> + + * src/h_hosts.c: h_hosts: Actually print out the results of the + test. Exit 1 if something went wrong or is inconsistent. + +2002-06-21 19:15 Martin Pool <mbp@samba.org> + + * src/: .cvsignore, Makefile.am, Makefile.in, distcc.h, h_hosts.c, + hosts.c, hosts.h, where.c: Start splitting out new host parser. + Doesn't do anything yet. + +2002-06-18 08:50 Martin Pool <mbp@samba.org> + + * linuxdoc/Makefile.in: Keep Makefile.in to allow building without + automake. + +2002-06-13 15:42 Martin Pool <mbp@samba.org> + + * src/: trace.c, trace.h: Cope without varargs macros. All trace + routines are redirected to plain functions. + +2002-06-13 15:41 Martin Pool <mbp@samba.org> + + * Makefile.in, configure, src/config.h.in: Run autoconf + +2002-06-13 15:22 Martin Pool <mbp@samba.org> + + * src/: h_exten.c, h_issource.c, h_scanargs.c: - cope without + varargs macros or __attribute__ + +2002-06-13 15:14 Martin Pool <mbp@samba.org> + + * NEWS, configure.ac, src/arg.c, src/bulk.c, src/distcc.c, + src/distcc.h, src/dopt.c, src/dparent.c, src/exec.c, src/io.c, + src/rpc.c, src/tempfile.c, src/trace.c, src/trace.h, src/util.c, + src/util.h, src/where.c: Modified patch from Petter Reinholdtsen + to try to build on Solaris with Forte cc. + + Specifically: + + - cope without varargs macros or __attribute__ + + - use lockf rather than flock if missing + + - fix bashism + + - put config.h in all files + +2002-06-13 15:02 Martin Pool <mbp@samba.org> + + * Makefile.in, man/Makefile.in: run automake + +2002-06-13 15:01 Martin Pool <mbp@samba.org> + + * README: Remove old performance numbers + + Add supported platforms + +2002-06-13 15:00 Martin Pool <mbp@samba.org> + + * patches/freebsd-mknod.diff: committed + +2002-06-13 14:58 Martin Pool <mbp@samba.org> + + * NEWS, src/serve.c: FreeBSD mknod/mkfifo fix. (Claes Wallin) + +2002-06-13 14:54 Martin Pool <mbp@samba.org> + + * src/dopt.c: Doc. + +2002-06-12 02:44 Martin Pool <mbp@samba.org> + + * NEWS, man/Makefile.am: Makefile.am patch from Petter Reinholdtsen + to correctly install and distribute manpages. (They need to be + updated to include just quick reference information and to point + to the sgml manual.) + +2002-06-12 02:15 Martin Pool <mbp@samba.org> + + * packaging/: README.rpm, distcc.spec: RPM spec file from Ben + Elliston. + +2002-06-12 01:53 Martin Pool <mbp@samba.org> + + * NEWS, OLDNEWS: Roll over NEWS + +2002-06-12 01:52 Martin Pool <mbp@samba.org> + + * src/: bulk.c, distcc.h: Refactor bulk file transfer code in + preparation for gzip compressiong. + +2002-06-12 01:51 Martin Pool <mbp@samba.org> + + * src/io.c: Doc. + +2002-06-12 01:47 Martin Pool <mbp@samba.org> + + * src/zip.c: Skeleton of zip compression. Not used yet. + +2002-06-12 01:39 Martin Pool <mbp@samba.org> + + * man/: .cvsignore, Makefile.in: Keep files generated by automake, + but not by configure. + +2002-06-12 01:39 Martin Pool <mbp@samba.org> + + * patches/freebsd-mknod.diff: Patch from Claes Wallin for FreeBSD. + +2002-06-12 01:37 Martin Pool <mbp@samba.org> + + * man/.cvsignore: Ignore autoconf generated files. + +2002-06-12 01:36 Martin Pool <mbp@samba.org> + + * linuxdoc/.cvsignore: Ignore generated files. + +2002-06-09 02:58 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Bump version to 0.4 + +2002-06-09 02:53 Martin Pool <mbp@samba.org> + + * ChangeLog, contrib/ChangeLog, doc/ChangeLog, linuxdoc/ChangeLog, + man/ChangeLog, patches/ChangeLog, src/ChangeLog: update + ChangeLogs + +2002-06-09 02:51 Martin Pool <mbp@samba.org> + + * configure, linuxdoc/Makefile, linuxdoc/Makefile.am, man/Makefile, + man/Makefile.am, src/Makefile.in: Shuffle Makefiles + +2002-06-09 02:50 Martin Pool <mbp@samba.org> + + * NEWS: Update news + +2002-06-09 02:40 Martin Pool <mbp@samba.org> + + * src/Makefile.am: Add missing file + +2002-06-09 02:38 Martin Pool <mbp@samba.org> + + * configure.ac: Bump version to 0.4 Get rid of old test scripts Add + new Makefiles + +2002-06-09 02:34 Martin Pool <mbp@samba.org> + + * NEWS: Doc. + +2002-06-09 02:32 Martin Pool <mbp@samba.org> + + * src/dopt.c: Hide --tasks from help since it does nothing. + +2002-06-09 02:09 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add section on SMP. + +2002-06-09 02:02 Martin Pool <mbp@samba.org> + + * src/dparent.c: Doc. + +2002-06-09 01:58 Martin Pool <mbp@samba.org> + + * ChangeLog, contrib/ChangeLog, linuxdoc/ChangeLog, + patches/ChangeLog, src/ChangeLog: update changelog + +2002-06-09 01:50 Martin Pool <mbp@samba.org> + + * src/dparent.c: Factor out code to collect children. Keep track + of how many are running. + +2002-06-09 01:44 Martin Pool <mbp@samba.org> + + * src/: daemon.c, dparent.c: Change server to a more traditional + Unix model of forking after accepting -- possibly less + efficient, but I was having trouble managing an orderly shutdown + of all children and this is simpler. + +2002-06-09 01:43 Martin Pool <mbp@samba.org> + + * src/Makefile.in: Run autoconf + +2002-06-09 01:42 Martin Pool <mbp@samba.org> + + * NEWS: Doc + +2002-06-09 00:23 Martin Pool <mbp@samba.org> + + * NEWS: .S and .s probably works now. + +2002-06-09 00:21 Martin Pool <mbp@samba.org> + + * src/: arg.c, distcc.h, serve.c: Correctly infer preprocessed + filename from source filename. So for example if we're + processing a .S file, then we need to call the tmpfile .s so that + the compiler driver understands that it should just run the + assembler. + +2002-06-09 00:08 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Note that network errors will not be + detected. + +2002-06-09 00:05 Martin Pool <mbp@samba.org> + + * src/dopt.c: Doc. + +2002-06-09 00:03 Martin Pool <mbp@samba.org> + + * src/arg.c: Server should log input and output filename too. + +2002-06-08 23:54 Martin Pool <mbp@samba.org> + + * src/: arg.c: Log input and output filename. + +2002-06-08 23:45 Martin Pool <mbp@samba.org> + + * src/dparent.c: Daemon parent tries to close listen_fd after + forking children, because it's no longer required. + +2002-06-08 23:43 Martin Pool <mbp@samba.org> + + * src/: Makefile.am, daemon.c, distcc.h, dparent.c: Split + daemon-standalone-parent code into a separate file. + +2002-06-08 23:35 Martin Pool <mbp@samba.org> + + * src/daemon.c: Lots of doc updates. + +2002-06-08 23:30 Martin Pool <mbp@samba.org> + + * src/daemon.c: Update docs. + +2002-06-08 23:24 Martin Pool <mbp@samba.org> + + * NEWS: Note --pid-file. + +2002-06-08 23:10 Martin Pool <mbp@samba.org> + + * src/daemon.c: Add log message for stdin being a socket + +2002-06-08 23:09 Martin Pool <mbp@samba.org> + + * src/srvnet.c: open_socket_in: check that port number is + reasonable + +2002-06-08 22:54 Martin Pool <mbp@samba.org> + + * linuxdoc/: .cvsignore, Makefile: Fix Plucker filename + +2002-06-08 22:49 Martin Pool <mbp@samba.org> + + * linuxdoc/.cvsignore: Add Plucker-ized manual + +2002-06-08 22:48 Martin Pool <mbp@samba.org> + + * linuxdoc/Makefile: Better name for Plucker file. + +2002-06-08 22:40 Martin Pool <mbp@samba.org> + + * src/daemon.c: Consistently call dcc_exit(). + + Notice immediately when one of our children dies, and reap all of + them. + + When all children die or the parent is signalled, the parent + should kill the process group and itself. + +2002-06-08 22:31 Martin Pool <mbp@samba.org> + + * src/util.h: Fix function attributes. + +2002-06-08 22:16 Martin Pool <mbp@samba.org> + + * src/distcc.h: Clean up prototypes. + +2002-06-08 22:11 Martin Pool <mbp@samba.org> + + * src/daemon.c: Clean up exit codes. + + If fork() fails, log an error, but keep trying. + + Try to listen on socket before going into background, so that + failure is visible to the calling script. + +2002-06-08 22:00 Martin Pool <mbp@samba.org> + + * src/distcc.c: Detect invocations like "distcc -c" + +2002-06-08 22:00 Martin Pool <mbp@samba.org> + + * src/exitcode.h, linuxdoc/distcc.sgml: Renumber exit codes so that + 100 is a generic distcc failure. + +2002-06-08 21:44 Martin Pool <mbp@samba.org> + + * src/dopt.c: Fix help message for --pid-file + +2002-06-08 21:43 Martin Pool <mbp@samba.org> + + * src/: daemon.c, dopt.c, opt.h: Add --pid-file option to save + daemon's pid. + +2002-06-08 21:42 Martin Pool <mbp@samba.org> + + * Makefile.in: Update autoconf stuff + +2002-06-08 14:24 Martin Pool <mbp@samba.org> + + * linuxdoc/Makefile: Don't build Linuxdoc by default because many + machines won't have the tools. + +2002-06-08 13:49 Martin Pool <mbp@samba.org> + + * src/dopt.c: Fix overzealous memory mistake. + +2002-06-07 16:17 Martin Pool <mbp@samba.org> + + * ChangeLog, doc/ChangeLog, linuxdoc/ChangeLog, man/ChangeLog, + src/ChangeLog: auto-update ChangeLog + +2002-06-07 11:09 Martin Pool <mbp@samba.org> + + * man/: .cvsignore, Makefile, distcc.1, distccd.1: Correction from + Juan F. Codagnone for Makefile -- should call groff, not man, to + transform manpages + + Also, add a little stub distccd page. Both need to be updated to + show just the basic information and refer to the manual for more + info. + +2002-06-06 18:21 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Improve cross-compile section. + +2002-06-06 17:52 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Update doc: test suite has now been + written. + +2002-06-06 00:22 Martin Pool <mbp@samba.org> + + * Makefile.in, NEWS, configure, configure.ac, src/config.h.in, + src/daemon.c, src/distcc.h, src/dopt.c, src/exitcode.h, + src/opt.h: Improvements to demon: + + - make daemon put itself into background when running alone + + - daemon preforks children according to --tasks option, notes if + they + die, and kills them when terminated + + - --port option to set listening port (currently not useful, + since + you can't set port on client) + +2002-06-05 19:00 Martin Pool <mbp@samba.org> + + * src/dopt.c: Fix mostly-harmless leaks of poptContext. Detected + by valgrind -- how cool! + +2002-06-05 18:53 Martin Pool <mbp@samba.org> + + * NEWS, src/tempfile.c: Add support for TMPDIR. Not tested. + +2002-06-05 17:22 Martin Pool <mbp@samba.org> + + * src/: bulk.c, daemon.c, distcc.c, exec.c, where.c: Doc. + +2002-06-02 15:02 Martin Pool <mbp@samba.org> + + * NEWS: Test cvs + +2002-06-02 14:28 Martin Pool <mbp@samba.org> + + * linuxdoc/Makefile, man/Makefile: Fix recursive make targets + +2002-06-02 14:18 Martin Pool <mbp@samba.org> + + * linuxdoc/Makefile, man/Makefile: Fix recursive make targets + +2002-06-02 14:10 Martin Pool <mbp@samba.org> + + * Makefile.in, linuxdoc/Makefile: automake + +2002-06-02 14:09 Martin Pool <mbp@samba.org> + + * src/: Makefile.in, daemon.c, exitcode.h: Start using consistent + return codes across all programs. + +2002-06-02 14:07 Martin Pool <mbp@samba.org> + + * contrib/make-j: make-j script from Alexandre Oliva + <aoliva@redhat.com> for use with distcc + + Tests which machines are up, and runs Make with concurrency set + appropriately. + +2002-06-02 13:59 Martin Pool <mbp@samba.org> + + * src/: .cvsignore, Makefile.am, Makefile.in, arg.c, clinet.c, + daemon.c, distcc.c, exitcode.h, h_scanargs.c, help.c, serve.c, + srvnet.c, trace.c, trace.h, util.c, util.h, where.c: Many + changes: + + Start using consistent return codes across all programs. + + Add h_scanargs to allow pyunit to test argument analysis. + + If -fprofile-args, -ftest-coverage or -x is seen in arguments, + run locally. + + Handle "gcc -c -c hello.c" + + Better help message. + + Start handling .s files (doesn't work yet) + + Fix insertion of program/pid into trace msgs. + +2002-06-02 13:56 Martin Pool <mbp@samba.org> + + * configure, configure.ac: FreeBSD installs its version of libpopt + into /usr/local/, but does not put that on the default library + and header path. We used to add that path if building on *bsd*, + but bje points out that will break cross-compilation, and it's + kind of ugly anyhow. + +2002-06-02 13:55 Martin Pool <mbp@samba.org> + + * autogen.sh: Don't configure from autogen.sh + +2002-06-02 13:54 Martin Pool <mbp@samba.org> + + * Makefile.am, Makefile.in: Also descend into linuxdoc, pyunit and + man directories. + +2002-06-02 13:51 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: More documentation, especially about bugs. + +2002-06-02 13:50 Martin Pool <mbp@samba.org> + + * NEWS, OLDNEWS: Roll over news. + +2002-05-31 16:36 Martin Pool <mbp@samba.org> + + * configure, configure.ac: Apparently FreeBSD needs sys/types.h + before netinet/in.h. From Frerich Raabe. + +2002-05-31 16:20 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add distcc link. + +2002-05-31 16:10 Martin Pool <mbp@samba.org> + + * linuxdoc/Makefile: Move to distcc.samba.org. + +2002-05-31 16:09 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Manual is now current for 0.3 + +2002-05-31 16:08 Martin Pool <mbp@samba.org> + + * linuxdoc/footer.html: Fix distcc homepage link. + +2002-05-30 08:31 Martin Pool <mbp@samba.org> + + * configure.ac: Documentation from ben + +2002-05-29 14:35 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: More notes from recent discussions. + +2002-05-29 14:21 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc. + +2002-05-28 23:11 Martin Pool <mbp@samba.org> + + * ChangeLog, Makefile.am, Makefile.in, linuxdoc/ChangeLog, + src/ChangeLog: Commit Makefile rule + +2002-05-28 23:09 Martin Pool <mbp@samba.org> + + * Makefile.am: Need to distribute ChangeLogs across directories + +2002-05-28 23:04 Martin Pool <mbp@samba.org> + + * ChangeLog: Update ChangeLog from CVS + +2002-05-28 23:00 Martin Pool <mbp@samba.org> + + * Makefile.in, aclocal.m4, src/Makefile.in: autoconf + +2002-05-28 22:58 Martin Pool <mbp@samba.org> + + * Makefile.in, src/Makefile.in: update autoconf + +2002-05-28 22:58 Martin Pool <mbp@samba.org> + + * src/NEWS: Moved to parent directory + +2002-05-28 22:56 Martin Pool <mbp@samba.org> + + * NEWS: Go ahead and release. + +2002-05-28 22:38 Martin Pool <mbp@samba.org> + + * aclocal.m4, configure, configure.ac, src/Makefile.am: Bump + version to 0.3. + + Try to get "make dist" working. + +2002-05-28 19:50 Martin Pool <mbp@samba.org> + + * Makefile.in, configure, src/Makefile.in: rerun autoconf + +2002-05-28 19:32 Martin Pool <mbp@samba.org> + + * configure.ac: Suggestion from Frerich to fix check for *bsd*. + +2002-05-28 15:38 Martin Pool <mbp@samba.org> + + * src/.cvsignore: Ignore temp file. + +2002-05-28 15:29 Martin Pool <mbp@samba.org> + + * aclocal.m4, configure.ac, src/Makefile.am, src/Makefile.in, + src/t_version: Add another trivial test suggested by bje + +2002-05-28 15:18 Martin Pool <mbp@samba.org> + + * Makefile.in, configure, configure.ac, src/config.h.in, + src/help.c: Export gnu host triple in --version + +2002-05-28 15:07 Martin Pool <mbp@samba.org> + + * Makefile.in, aclocal.m4, config.guess, config.sub, configure, + configure.ac, src/Makefile.in: Detect BSD, and add /usr/local/ to + the CFLAGS and LDFLAGS. + +2002-05-28 14:31 Martin Pool <mbp@samba.org> + + * aclocal.m4: Silly autoconf + +2002-05-28 14:24 Martin Pool <mbp@samba.org> + + * patches/: distc, distc++: Single files that call 'distcc gcc' -- + possibly needed for Makefiles that assume the compiler is a + single word. (Does this include libtool?) + +2002-05-28 14:18 Martin Pool <mbp@samba.org> + + * src/: .cvsignore, Makefile.in, config.h.in: Check in extra + autoconf-generated files. + +2002-05-28 14:17 Martin Pool <mbp@samba.org> + + * src/timebuild: Very primitive script for timing tests. + +2002-05-28 13:52 Martin Pool <mbp@samba.org> + + * src/: h_exten.c, h_issource.c: Additional fixes for + rs_program_name. + +2002-05-28 13:48 Martin Pool <mbp@samba.org> + + * Makefile.in, configure, configure.ac, src/serve.c: BSD needs + sys/signal.h. + +2002-05-28 12:43 Martin Pool <mbp@samba.org> + + * .cvsignore, COPYING.FDL, Makefile.am, Makefile.in, aclocal.m4, + configure, install-sh, missing, mkinstalldirs: Keep a copy of + autotools files in CVS, to help people on machines with different + versions. Bah, humbug! + +2002-05-28 12:37 Martin Pool <mbp@samba.org> + + * ChangeLog, doc/ChangeLog, linuxdoc/ChangeLog, man/ChangeLog: + Regenerate ChangeLogs + +2002-05-28 12:28 Martin Pool <mbp@samba.org> + + * src/: ChangeLog, daemon.c, distcc.c, trace.c, trace.h: Clean up + rs_program_name shmozlle + +2002-05-27 00:58 Martin Pool <mbp@samba.org> + + * src/srvnet.c: Doc + +2002-05-27 00:14 Martin Pool <mbp@samba.org> + + * configure.ac: Doc + +2002-05-26 01:44 Martin Pool <mbp@samba.org> + + * .cvsignore, src/.cvsignore: Ignore extra garbage + +2002-05-26 01:38 Martin Pool <mbp@samba.org> + + * configure.ac: Need to also look in sys/types.h for in_port_t on + BSD. + +2002-05-26 01:35 Martin Pool <mbp@samba.org> + + * src/arg.c: Good fix from Ian Reinhart Geiser for silly mistake in + dcc_set_file_extension that I think would show up in "gcc -c + hello.c". + +2002-05-26 01:27 Martin Pool <mbp@samba.org> + + * NEWS, src/serve.c: Ignore SIGPIPE in daemon as well as client. + + Thanks to Ben Elliston. + +2002-05-26 01:21 Martin Pool <mbp@samba.org> + + * configure.ac, src/clinet.c, NEWS: Try to cope without in_port_t. + + Thanks to Luke Gorrie. + +2002-05-26 01:11 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.c, h_exten.c, h_issource.c, trace.c: Cope + without program_invocation_short_name, as some GNU libc/cc + combinations don't seem to have it (???) + +2002-05-26 00:54 Martin Pool <mbp@samba.org> + + * src/trace.c: Replace calls to strnlen with strlen, because it + will always be short enough and FreeBSD doesn't have strnlen + +2002-05-26 00:49 Martin Pool <mbp@samba.org> + + * configure.ac, src/help.c: Ignore strange new automake variables, + just use PACKAGE and VERSION + +2002-05-26 00:47 Martin Pool <mbp@samba.org> + + * NEWS: Fix Ian's name. + +2002-05-26 00:46 Martin Pool <mbp@samba.org> + + * NEWS: M-/ strikes again :-) + +2002-05-26 00:42 Martin Pool <mbp@samba.org> + + * src/io.c: If there are no corks on this computer, don't try to + use them. + +2002-05-26 00:32 Martin Pool <mbp@samba.org> + + * configure.ac, src/arg.c, src/bulk.c, src/clinet.c, src/daemon.c, + src/distcc.c, src/exec.c, src/h_exten.c, src/h_issource.c, + src/io.c, src/rpc.c, src/serve.c, src/srvnet.c, src/tempfile.c, + src/util.c, src/where.c, NEWS: Test for sys/sendfile.h and + sendfile(), and if we don't have them use plain read/write + instead. + + Remove unnecessary dependencies on sys/sendfile.h + +2002-05-26 00:23 Martin Pool <mbp@samba.org> + + * autogen.sh: Don't say "make all", because on some platforms you + might really need gmake. + +2002-05-26 00:08 Martin Pool <mbp@samba.org> + + * autogen.sh: Need to also run aclocal to install automake stuff. + + Also need to run autoheader early on in the process, because + automake depends on finding config.h.in. + +2002-05-26 00:04 Martin Pool <mbp@samba.org> + + * NEWS: Note help with automake + +2002-05-26 00:01 Martin Pool <mbp@samba.org> + + * autogen.sh: Handle ChangeLog + +2002-05-25 23:57 Martin Pool <mbp@samba.org> + + * src/.cvsignore: More test cases + +2002-05-25 23:55 Martin Pool <mbp@samba.org> + + * src/Makefile.am: Get rid of editing mistake. + + _SOURCES is a magic name for automake, so don't use it for common + source. + + Thanks to Frerich Raabe. + +2002-05-25 23:50 Martin Pool <mbp@samba.org> + + * autogen.sh: Add a script to do everything necessary to build from + CVS. This is needed because automake requires a spliff to get + out of bed, and the generated files are shipped in tarballs but + not stored in CVS. + +2002-05-25 23:47 Martin Pool <mbp@samba.org> + + * configure.ac: Fix shell syntax: square brackets can't be used in + configure.ac because they clash with m4. + +2002-05-25 19:23 Martin Pool <mbp@samba.org> + + * src/: Makefile.am, h_issource.c, t_issource: Add another test + +2002-05-25 19:23 Martin Pool <mbp@samba.org> + + * configure.ac: chmod test files + +2002-05-25 18:57 Martin Pool <mbp@samba.org> + + * src/: arg.c, distcc.c, distcc.h: Recognize the .ii extension that + ccache uses for preprocessed C++ code. (Ian Reinhart Geiser) + +2002-05-25 18:55 Martin Pool <mbp@samba.org> + + * NEWS: * Convert to using GNU automake and autoconf, so that + distcc can + better handle portability, distribution and testing. + (Martin + Pool) + + * Start adding some "make check" tests. (Martin Pool) + +2002-05-25 18:51 Martin Pool <mbp@samba.org> + + * src/arg.c: Recognize the .ii extension that ccache uses for + preprocessed C++ code. + +2002-05-25 18:50 Martin Pool <mbp@samba.org> + + * src/: .cvsignore, Makefile.am, arg.c, distcc.h, h_exten.c, + t_exten: Add a test harness and script to test the simplest + function we have -- finding the extension of a filename. + +2002-05-25 18:34 Martin Pool <mbp@samba.org> + + * src/GNUmakefile: This Makefile is no longer needed because we + have automake. + +2002-05-25 18:33 Martin Pool <mbp@samba.org> + + * .cvsignore, src/.cvsignore: Ignore automake-generated files + +2002-05-25 16:02 Martin Pool <mbp@samba.org> + + * configure.ac, src/Makefile.am, src/help.c, src/trace.c: More + automake integration fixes. Builds properly now. + +2002-05-25 15:47 Martin Pool <mbp@samba.org> + + * .cvsignore, AUTHORS, COPYING, INSTALL, Makefile, Makefile.am, + NEWS, OLDNEWS, configure.ac, src/.cvsignore, src/Makefile.am: + Convert to automake. Don't know if it works yet. + +2002-05-24 16:45 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add GNU FDL stuff. + +2002-05-24 15:17 Martin Pool <mbp@samba.org> + + * src/: distcc.c, distcc.h, exec.c, NEWS: Only fiddle with the + compiler's stdin/out/err when running on the server, not on the + client. This should make cpp from stdin work. (Reported by Ian + Reinhart Geiser from KDE.) + +2002-05-24 15:15 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc. + +2002-05-24 15:11 Martin Pool <mbp@samba.org> + + * src/: distcc.h, exec.c: Split out code to redirect stdin/out/err, + because we don't want to do this locally. + +2002-05-24 13:49 Martin Pool <mbp@samba.org> + + * Makefile: Add always_ChangeLog target + +2002-05-24 13:47 Martin Pool <mbp@samba.org> + + * src/serve.c: Use a FIFO to feed preprocessed source from the + daemon into the compiler, so that compilation can be overlapped + with network transit. + +2002-05-24 13:22 Martin Pool <mbp@samba.org> + + * src/NEWS: Support C++ compilation by correctly detecting + prefixes. + +2002-05-24 13:22 Martin Pool <mbp@samba.org> + + * src/arg.c: Better error messages for when we encounter an + argument that is not a source file name. + +2002-05-24 13:19 Martin Pool <mbp@samba.org> + + * src/arg.c: Fix little syntax error. + +2002-05-24 13:18 Martin Pool <mbp@samba.org> + + * src/arg.c: Change code to recognize source files so that it will + detect all the C++ variants. Based on a patch from ian reinhart + geiser. + + Factor source file recognition into its own function. + +2002-05-24 13:03 Martin Pool <mbp@samba.org> + + * src/arg.c: Refactor code to set file extension, so that we can + handle things like "foo.cpp" where the source extension is longer + than ".o". Based on a patch from ian reinhart geiser, but more + defensive. + +2002-05-23 16:19 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Fix SGML. + +2002-05-23 16:17 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Texinfo can't handle having two headings + with the same name. + +2002-05-23 16:12 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add explanation of special meaning of + "localhost" in DISTCC_HOSTS. + + Move results around. + +2002-05-21 18:17 Martin Pool <mbp@samba.org> + + * src/: NEWS, OLDNEWS: Roll over NEWS + +2002-05-21 18:10 Martin Pool <mbp@samba.org> + + * src/GNUmakefile: Set version to 0.2.99 + +2002-05-21 17:20 Martin Pool <mbp@samba.org> + + * src/serve.c: Doc. + +2002-05-20 16:00 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Fix SGML + +2002-05-20 15:57 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add section about libtool. + + Add results for building glib-1.2. + +2002-05-20 14:38 Martin Pool <mbp@samba.org> + + * src/GNUmakefile: linuxdoc/ subdir is no longer here. + +2002-05-20 14:30 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Cleaner CVS stuff. + +2002-05-20 14:26 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Cleaner CVS stuff. + +2002-05-20 14:25 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Better explanation of issues around SSH. + +2002-05-20 14:06 Martin Pool <mbp@samba.org> + + * src/trace.c: Doc. + +2002-05-20 14:02 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Clarify handling of compiler error + messages. + +2002-05-20 13:54 Martin Pool <mbp@samba.org> + + * linuxdoc/.cvsignore: Better exclude specification + +2002-05-20 13:54 Martin Pool <mbp@samba.org> + + * linuxdoc/: Makefile, footer.html: Add HTML footer + +2002-05-20 13:46 Martin Pool <mbp@samba.org> + + * Makefile, cvs2cl.ufile: Add top-level makefile + +2002-05-20 13:35 Martin Pool <mbp@samba.org> + + * src/NEWS: News for something that happened last week! + +2002-05-20 13:23 Martin Pool <mbp@samba.org> + + * src/HACKING: Cleanup + +2002-05-20 13:21 Martin Pool <mbp@samba.org> + + * linuxdoc/distcc.sgml: Add results. + +2002-05-19 18:09 Martin Pool <mbp@samba.org> + + * linuxdoc/: .cvsignore, Makefile, distcc.sgml: Move directory + +2002-05-17 15:45 Martin Pool <mbp@samba.org> + + * src/GNUmakefile: Set version to 0.2 + +2002-05-17 14:10 Martin Pool <mbp@samba.org> + + * src/help.c: Add email address + +2002-05-17 14:09 Martin Pool <mbp@samba.org> + + * src/: GNUmakefile, distcc.c, distcc.h, dopt.c, help.c: Improve + --help messages, and make all programs response to --version + properly. + +2002-05-17 13:45 Martin Pool <mbp@samba.org> + + * src/daemon.c: Doc. + +2002-05-16 17:56 Martin Pool <mbp@samba.org> + + * src/arg.c: If -o is not specified, gcc dumps the object file in + the current directory, not the source directory. Make our + behaviour the same. + +2002-05-16 17:27 Martin Pool <mbp@samba.org> + + * src/: arg.c, distcc.c, distcc.h: Try to handle cases like "gcc -c + hello.c" by appending "-o hello.o" to the end. + + This doesn't work yet for files not in the current directory. + +2002-05-16 15:53 Martin Pool <mbp@samba.org> + + * .cvsignore, src/GNUmakefile: Add a nice simple user manual + +2002-05-16 13:48 Martin Pool <mbp@samba.org> + + * src/HACKING: Note about cpp performance. + +2002-05-15 23:13 Martin Pool <mbp@samba.org> + + * src/HACKING: Doc. + +2002-05-15 18:19 Martin Pool <mbp@samba.org> + + * src/: HACKING, tempfile.c, where.c: Doc. + +2002-05-15 17:45 Martin Pool <mbp@samba.org> + + * src/where.c: Better trace msg + +2002-05-15 17:44 Martin Pool <mbp@samba.org> + + * man/.cvsignore: Ignore generated + +2002-05-15 17:44 Martin Pool <mbp@samba.org> + + * doc/distcc-irc.txt: Rough notes from irc + +2002-05-15 17:38 Martin Pool <mbp@samba.org> + + * src/: distcc.h, tempfile.c, where.c: Use simple file locks to + spread work across hosts + +2002-05-15 17:23 Martin Pool <mbp@samba.org> + + * src/where.c: Split out code for parsing list of hosts, and + actually picking a host to use. + + Doc about locking method for distributing work. + +2002-05-15 16:15 Martin Pool <mbp@samba.org> + + * src/: GNUmakefile, bulk.c, distcc.c, distcc.h, rpc.h, serve.c, + where.c: Back out of the compression changes; they seem like a + premature optimization + +2002-05-15 16:07 Martin Pool <mbp@samba.org> + + * src/HACKING: Scratch numbers on compression + +2002-05-15 15:57 Martin Pool <mbp@samba.org> + + * src/serve.c: Use correct proto version + +2002-05-15 15:54 Martin Pool <mbp@samba.org> + + * src/: bulk.c, distcc.c, io.h, rpc.h, serve.c: zlevel is passed + everywhere but ignored + +2002-05-15 15:51 Martin Pool <mbp@samba.org> + + * src/: GNUmakefile, distcc.c, serve.c: Server accepts GZIP token + +2002-05-15 15:45 Martin Pool <mbp@samba.org> + + * src/HACKING: Note about server-side error handling + +2002-05-15 15:42 Martin Pool <mbp@samba.org> + + * src/: distcc.c, distcc.h: Bump proto version to 2; send GZIP + token in header to request compression + +2002-05-15 15:35 Martin Pool <mbp@samba.org> + + * src/: distcc.c, distcc.h, where.c: Parse zlevel out of _HOSTS + +2002-05-15 15:27 Martin Pool <mbp@samba.org> + + * src/: bulk.c, io.c, io.h: Factor out common methods of bulk + transfer + +2002-05-15 15:26 Martin Pool <mbp@samba.org> + + * src/GNUmakefile: Bump version + +2002-05-15 15:20 Martin Pool <mbp@samba.org> + + * man/distcc.1: Note about mtimes + +2002-05-15 15:13 Martin Pool <mbp@samba.org> + + * src/bulk.c: Doc + +2002-05-15 15:10 Martin Pool <mbp@samba.org> + + * src/GNUmakefile: Set version to 1.0 + +2002-05-15 15:09 Martin Pool <mbp@samba.org> + + * .cvsignore, man/distcc.1, src/HACKING, src/distcc.c, src/trace.c, + src/trace.h: Allow log messages from distcc to be separated from + stderr + +2002-05-15 15:01 Martin Pool <mbp@samba.org> + + * src/: GNUmakefile, bulk.c, rpc.c: Split out file transfer code + +2002-05-15 14:56 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Add quote + +2002-05-15 14:56 Martin Pool <mbp@samba.org> + + * src/distcc.c: Handle --help + +2002-05-15 14:56 Martin Pool <mbp@samba.org> + + * man/distcc.1: Add more links + +2002-05-15 14:55 Martin Pool <mbp@samba.org> + + * man/Makefile: Add PDF target + +2002-05-15 14:50 Martin Pool <mbp@samba.org> + + * src/distcc.c: Show environment variables in usage message for + distcc + +2002-05-13 13:30 Martin Pool <mbp@samba.org> + + * src/GNUmakefile: Add "install" target. + +2002-05-13 13:27 Martin Pool <mbp@samba.org> + + * src/dopt.c: Fix dumb "break" mistake in option parsing. + +2002-05-06 09:10 Martin Pool <mbp@samba.org> + + * src/dopt.c: Add --nice option + +2002-05-05 19:23 Martin Pool <mbp@samba.org> + + * src/: GNUmakefile, daemon.c, distcc.h, dopt.c: Start adding + daemon command-line handling + +2002-05-05 19:22 Martin Pool <mbp@samba.org> + + * src/trace.c: Better formatting when not using the pid. + +2002-05-05 19:21 Martin Pool <mbp@samba.org> + + * README: Note library dependencies + +2002-05-02 15:17 Martin Pool <mbp@samba.org> + + * man/distcc.1: More stuff. + +2002-05-02 14:25 Martin Pool <mbp@samba.org> + + * man/distcc.1: More manpage updates. + +2002-05-02 13:26 Martin Pool <mbp@samba.org> + + * man/: Makefile, distcc.1: Add the start of a man page. + +2002-05-01 12:42 Martin Pool <mbp@samba.org> + + * src/io.c: "i've always wanted to use sendfile(), but never had a + reason until now" + +2002-05-01 12:31 Martin Pool <mbp@samba.org> + + * README: Add author name. + +2002-04-30 20:48 Martin Pool <mbp@samba.org> + + * README, src/README: Rearrange + +2002-04-30 18:15 Martin Pool <mbp@samba.org> + + * src/: exec.c: Doc. + +2002-04-30 18:06 Martin Pool <mbp@samba.org> + + * src/serve.c: Make file sizes correct even if compilation fails. + +2002-04-30 18:05 Martin Pool <mbp@samba.org> + + * src/: distcc.h, serve.c, srvnet.c: daemon logs client names + +2002-04-30 18:04 Martin Pool <mbp@samba.org> + + * src/exec.c: Doc + +2002-04-30 17:50 Martin Pool <mbp@samba.org> + + * src/trace.c: you're never going to want program or pid in a + syslog message, because it's redundant. + +2002-04-30 17:48 Martin Pool <mbp@samba.org> + + * src/: serve.c, exec.c: Log job completion + +2002-04-30 17:45 Martin Pool <mbp@samba.org> + + * src/daemon.c: Log opening of port + +2002-04-30 17:38 Martin Pool <mbp@samba.org> + + * src/exec.c: If compiler finished OK, that's an INFO level message + +2002-04-30 17:34 Martin Pool <mbp@samba.org> + + * src/: distcc.c, rpc.c, rpc.h, serve.c: Record size of files + transferred + +2002-04-30 17:31 Martin Pool <mbp@samba.org> + + * src/: daemon.c, trace.c, trace.h: More flexible trace formatting + +2002-04-30 17:22 Martin Pool <mbp@samba.org> + + * src/trace.c: Fix stderr logging. + +2002-04-30 17:19 Martin Pool <mbp@samba.org> + + * src/: daemon.c, trace.c, trace.h: distccd logs to syslog/daemon. + +2002-04-30 17:13 Martin Pool <mbp@samba.org> + + * src/: trace.c, trace.h: Big rework of trace system so that the + trace implementation gets to format the string, possibly using a + helper function. + +2002-04-30 16:35 Martin Pool <mbp@samba.org> + + * src/srvnet.c: Delete dead code + +2002-04-30 15:46 Martin Pool <mbp@samba.org> + + * src/io.c: Don't ever just exit + +2002-04-30 15:45 Martin Pool <mbp@samba.org> + + * src/daemon.c: Don't abort if accept() fails. + +2002-04-30 15:29 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Make cleanup code reusable. + +2002-04-30 15:28 Martin Pool <mbp@samba.org> + + * src/srvnet.c: Need to listen() on socket before accept() + +2002-04-30 15:20 Martin Pool <mbp@samba.org> + + * src/distcc.c: Fix silly pointer bug + +2002-04-30 15:17 Martin Pool <mbp@samba.org> + + * src/: GNUmakefile, daemon.c, srvnet.c, util.h: Really simple + standalone mode. + +2002-04-30 14:43 Martin Pool <mbp@samba.org> + + * src/: GNUmakefile, daemon.c, distcc.h, serve.c: Split out daemon + stuff in preparation for listening on our own socket. + +2002-04-30 14:41 Martin Pool <mbp@samba.org> + + * src/io.c: Cast from gcc warning + +2002-04-30 14:41 Martin Pool <mbp@samba.org> + + * src/distcc.c: Trace + +2002-04-30 14:22 Martin Pool <mbp@samba.org> + + * src/: README, distcc.c: Add DISTCC_VERBOSE env var + +2002-04-30 14:09 Martin Pool <mbp@samba.org> + + * src/rpc.c: Add necessary cast, thanks to gcc. + +2002-04-30 14:09 Martin Pool <mbp@samba.org> + + * src/HACKING: Doc. + +2002-04-30 14:04 Martin Pool <mbp@samba.org> + + * src/rpc.c: If we fail to receive a file, delete the destination + rather than leaving it truncated. + +2002-04-30 14:03 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.c: Don't send the .o file unless + compilation succeeded. + +2002-04-30 13:54 Martin Pool <mbp@samba.org> + + * src/distcc.c: If no build hosts are set, just run here. + +2002-04-30 13:53 Martin Pool <mbp@samba.org> + + * src/GNUmakefile: Add targets to run cflow. + +2002-04-30 13:50 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc. + +2002-04-30 13:02 Martin Pool <mbp@samba.org> + + * src/distcc.c: Do clean up temporary files. + +2002-04-30 13:00 Martin Pool <mbp@samba.org> + + * src/distcc.c: Better help message. + +2002-04-30 12:58 Martin Pool <mbp@samba.org> + + * src/GNUmakefile: Turn on more warnings + +2002-04-30 12:54 Martin Pool <mbp@samba.org> + + * src/where.c: Fix gcc warning. + +2002-04-29 20:08 Martin Pool <mbp@samba.org> + + * src/clinet.c: Note from Huxley + +2002-04-29 15:28 Martin Pool <mbp@samba.org> + + * src/where.c: Doc. + +2002-04-29 15:23 Martin Pool <mbp@samba.org> + + * src/daemon.c: Doc. + +2002-04-29 15:20 Martin Pool <mbp@samba.org> + + * src/: clinet.c, distcc.c: Doc. + +2002-04-29 15:17 Martin Pool <mbp@samba.org> + + * src/clinet.c: Handle EPIPE as a regular error + +2002-04-29 14:52 Martin Pool <mbp@samba.org> + + * src/daemon.c: Clean up temp files if build is successful + +2002-04-29 14:50 Martin Pool <mbp@samba.org> + + * src/daemon.c: Docs about better performance. + +2002-04-29 14:45 Martin Pool <mbp@samba.org> + + * src/where.c: Docs about better methods of choosing compile hosts. + +2002-04-28 23:46 Martin Pool <mbp@samba.org> + + * src/: arg.c, clinet.c, daemon.c, io.c, where.c: Clean up + +2002-04-28 23:43 Martin Pool <mbp@samba.org> + + * src/README: Notes on building the kernel + +2002-04-28 23:05 Martin Pool <mbp@samba.org> + + * src/GNUmakefile: Change version to 0.1cvs + +2002-04-28 22:50 Martin Pool <mbp@samba.org> + + * src/exec.c: Better messages + +2002-04-28 22:50 Martin Pool <mbp@samba.org> + + * src/arg.c: Better quoting for commands + +2002-04-28 22:45 Martin Pool <mbp@samba.org> + + * src/: README, distcc.c, distcc.h, exec.c: Make the magic name + localhost + + Better execution messages + +2002-04-28 22:32 Martin Pool <mbp@samba.org> + + * src/: README, distcc.c: Make the magic name LOCALHOST, not LOCAL + +2002-04-28 22:30 Martin Pool <mbp@samba.org> + + * src/where.c: Randomize by pid/ppid, rather than time(), because + it is likely that multiple copies might be forked within a second + by make -j. + +2002-04-28 22:29 Martin Pool <mbp@samba.org> + + * src/io.c: Fix headers + +2002-04-28 20:54 Martin Pool <mbp@samba.org> + + * src/README: Add title. + +2002-04-28 20:41 Martin Pool <mbp@samba.org> + + * src/: clinet.c, daemon.c, distcc.h, io.c, io.h: Also cork + response from the server + +2002-04-28 20:41 Martin Pool <mbp@samba.org> + + * src/trace.c: Larger log buffer for chunky gcc lines + +2002-04-28 20:37 Martin Pool <mbp@samba.org> + + * src/distcc.c: Cork and uncork socket around request. + +2002-04-28 20:36 Martin Pool <mbp@samba.org> + + * src/distcc.c: Cope properly when not running cpp. + +2002-04-28 20:35 Martin Pool <mbp@samba.org> + + * src/: clinet.c, distcc.h: Add code to cork a socket + +2002-04-28 20:26 Martin Pool <mbp@samba.org> + + * src/: exec.c, rpc.c: Better trace + +2002-04-28 20:15 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.c: Fiddle debug and tempfile stuff to + better support debugging. + +2002-04-28 20:13 Martin Pool <mbp@samba.org> + + * src/README: Some initial numbers on performance building rsync. + +2002-04-28 19:38 Martin Pool <mbp@samba.org> + + * src/clinet.c: Fix messages + +2002-04-28 19:31 Martin Pool <mbp@samba.org> + + * src/io.c: Quieten trace + +2002-04-28 19:27 Martin Pool <mbp@samba.org> + + * src/: distcc.c, distcc.h, exec.c, util.c, util.h: Show program + and hostname in completion message. + +2002-04-28 19:19 Martin Pool <mbp@samba.org> + + * src/io.c: Fix nasty bug that caused us to read much more than we + wanted. + +2002-04-28 19:16 Martin Pool <mbp@samba.org> + + * src/rpc.c: More trace + +2002-04-28 19:16 Martin Pool <mbp@samba.org> + + * src/daemon.c: Fix tempfile names. + +2002-04-28 19:07 Martin Pool <mbp@samba.org> + + * src/distcc.c: Better messages. + +2002-04-28 19:04 Martin Pool <mbp@samba.org> + + * src/where.c: Typo. + +2002-04-28 19:03 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Better error message. + +2002-04-28 19:02 Martin Pool <mbp@samba.org> + + * src/: clinet.c, distcc.c, distcc.h: Actually try to use a random + remote host. + +2002-04-28 18:58 Martin Pool <mbp@samba.org> + + * src/where.c: Add routine to pick a random build host + +2002-04-28 18:58 Martin Pool <mbp@samba.org> + + * src/trace.h: Add rs_log_warning + +2002-04-28 18:57 Martin Pool <mbp@samba.org> + + * src/io.c: Quieten warning + +2002-04-28 18:55 Martin Pool <mbp@samba.org> + + * src/README: Doc + +2002-04-28 17:02 Martin Pool <mbp@samba.org> + + * src/rpc.c: dcc_x_file: If a file does not exist, send it as empty + rather than aborting. + +2002-04-28 17:00 Martin Pool <mbp@samba.org> + + * src/distcc.c: If the remote compiler fails, we don't need to try + again locally. (Actually, we might want to, but don't worry + about that for now.) + +2002-04-28 16:55 Martin Pool <mbp@samba.org> + + * src/: distcc.c, rpc.c, rpc.h: Receive and display remote + stdout/stderr. + +2002-04-28 16:52 Martin Pool <mbp@samba.org> + + * src/daemon.c: Capture and send compiler's stdout/stderr. + +2002-04-28 16:47 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.c, distcc.h, exec.c, util.c, util.h: Get + ready for catching compiler stdout/stderr. + +2002-04-28 15:20 Martin Pool <mbp@samba.org> + + * src/distcc.c: Show proto ver in version info. + +2002-04-28 15:19 Martin Pool <mbp@samba.org> + + * src/: clinet.c, distcc.c, daemon.c: Doc. + +2002-04-28 15:15 Martin Pool <mbp@samba.org> + + * src/: GNUmakefile, where.c: Add where.c + +2002-04-28 15:14 Martin Pool <mbp@samba.org> + + * src/: README, distcc.c, distcc.h, exec.c: Run cpp in background + while trying to connect. + +2002-04-28 15:13 Martin Pool <mbp@samba.org> + + * src/GNUmakefile: Should use CFLAGS to link too + +2002-04-28 13:22 Martin Pool <mbp@samba.org> + + * src/distcc.c: Better message when compiler fails. + +2002-04-28 13:19 Martin Pool <mbp@samba.org> + + * src/: distcc.c, distcc.h, exec.c: Get ready for async subcommands + +2002-04-28 13:14 Martin Pool <mbp@samba.org> + + * src/arg.c: Better message + +2002-04-28 13:12 Martin Pool <mbp@samba.org> + + * src/: GNUmakefile, arg.c, clinet.c, daemon.c, distcc.c, distcc.h, + io.h, tempfile.c, util.c: More splint-based checks + +2002-04-28 12:37 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Check permissions on temporary dir + +2002-04-28 12:33 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Automatically set up temp dir when needed + + Fix temp dir permissions + +2002-04-28 12:32 Martin Pool <mbp@samba.org> + + * src/GNUmakefile: Turn off dynamic dependencies for the moment + +2002-04-28 12:29 Martin Pool <mbp@samba.org> + + * src/: GNUmakefile, arg.c, clinet.c, daemon.c, distcc.c, io.c, + io.h, rpc.c, trace.c, trace.h, util.c: Splint codeups + +2002-04-28 12:16 Martin Pool <mbp@samba.org> + + * src/trace.h: Remove broken non-gcc stuff + +2002-04-28 12:15 Martin Pool <mbp@samba.org> + + * src/GNUmakefile: Add SPLINT target + +2002-04-28 12:08 Martin Pool <mbp@samba.org> + + * src/: distcc.h, tempfile.c: Add routine to cleanup temporary + files. + +2002-04-28 12:03 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.c, distcc.h, io.c, tempfile.c: Better + (secure?) temporary name routine. + +2002-04-28 12:03 Martin Pool <mbp@samba.org> + + * src/arg.c: Doc + +2002-04-25 20:03 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc. + +2002-04-25 20:00 Martin Pool <mbp@samba.org> + + * src/io.c: Use a larger copy buffer. + +2002-04-25 19:59 Martin Pool <mbp@samba.org> + + * src/distcc.c: Be quiet by default + +2002-04-25 19:32 Martin Pool <mbp@samba.org> + + * src/: arg.c, daemon.c: Fix filename substitution code. + +2002-04-25 19:26 Martin Pool <mbp@samba.org> + + * src/arg.c: Fix message + +2002-04-25 19:24 Martin Pool <mbp@samba.org> + + * src/: daemon.c, exec.c, io.c, io.h: Split out code for reading + length-preceded strings. + +2002-04-25 19:11 Martin Pool <mbp@samba.org> + + * src/daemon.c: Properly nul-terminate argv strings + +2002-04-25 19:07 Martin Pool <mbp@samba.org> + + * src/distcc.h: Fix header + +2002-04-25 19:05 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.h: Drop job structure altogether. + + The server no longer needs to use the client's argument parsing + system. + +2002-04-25 19:00 Martin Pool <mbp@samba.org> + + * src/: arg.c, distcc.h: Drop dead code + +2002-04-25 18:57 Martin Pool <mbp@samba.org> + + * src/rpc.c: Better log + +2002-04-25 18:56 Martin Pool <mbp@samba.org> + + * src/: io.h, rpc.c: Rename to dcc_r_token + +2002-04-25 18:54 Martin Pool <mbp@samba.org> + + * src/io.c: IO errors need not cause us to abort. + +2002-04-25 18:52 Martin Pool <mbp@samba.org> + + * src/daemon.c: Generate our slightly more proper temporary names. + +2002-04-25 18:51 Martin Pool <mbp@samba.org> + + * src/trace.h: Add rs_log_critical convenience. + +2002-04-25 18:48 Martin Pool <mbp@samba.org> + + * src/io.c: dcc_expect_token: check expected token is sane, and if + read fails then say what we were hoping for + +2002-04-25 18:44 Martin Pool <mbp@samba.org> + + * src/trace.c: Show pid in log messages. + +2002-04-25 18:43 Martin Pool <mbp@samba.org> + + * src/: arg.c, distcc.h: Add dcc_set_input + +2002-04-25 18:37 Martin Pool <mbp@samba.org> + + * src/: arg.c, daemon.c, distcc.c, distcc.h, rpc.c, rpc.h: Clean + argc, argv, wait status stuff out of job structure. + +2002-04-25 18:28 Martin Pool <mbp@samba.org> + + * src/arg.c: Better log messages from arg scanner + +2002-04-25 18:18 Martin Pool <mbp@samba.org> + + * src/distcc.c: Actually go ahead and run cpp if necessary. + +2002-04-25 18:07 Martin Pool <mbp@samba.org> + + * src/exec.c: Doc. + +2002-04-25 18:06 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.h, exec.c: Cleanup dcc_run_child + +2002-04-25 18:01 Martin Pool <mbp@samba.org> + + * src/: arg.c, distcc.h, exec.c: Show whole command being executed. + +2002-04-25 17:50 Martin Pool <mbp@samba.org> + + * src/distcc.c: log message + +2002-04-25 17:42 Martin Pool <mbp@samba.org> + + * src/GNUmakefile: Sketchy routines to build temporary filenames + +2002-04-25 17:38 Martin Pool <mbp@samba.org> + + * src/tempfile.c: Sketchy routines to build temporary filenames + +2002-04-25 17:38 Martin Pool <mbp@samba.org> + + * src/distcc.c: Get closer to running cpp locally + +2002-04-25 17:37 Martin Pool <mbp@samba.org> + + * src/: arg.c, distcc.h: Add more argv[] utilities + +2002-04-25 17:09 Martin Pool <mbp@samba.org> + + * src/arg.c: Fix harmless glitch. Better message. + +2002-04-25 17:07 Martin Pool <mbp@samba.org> + + * src/util.c: Fix inverted sense in str_startswith + +2002-04-25 16:59 Martin Pool <mbp@samba.org> + + * src/: arg.c, daemon.c, distcc.c, distcc.h, exec.c: Prepare to run + preprocessor on client + +2002-04-25 15:46 Martin Pool <mbp@samba.org> + + * src/arg.c: Better handle the case of being passed a + non-preprocessed file. + +2002-04-25 14:12 Martin Pool <mbp@samba.org> + + * src/arg.c: Fix headers. + +2002-04-25 14:12 Martin Pool <mbp@samba.org> + + * src/: util.c, util.h: Add str_startswith + +2002-04-25 14:08 Martin Pool <mbp@samba.org> + + * src/: distcc.c, distcc.h: Start adding support for running cpp + ourselves before going across the network. + +2002-04-25 14:07 Martin Pool <mbp@samba.org> + + * src/daemon.c: Error out if we somehow get a request to run cpp on + the server. + +2002-04-25 14:04 Martin Pool <mbp@samba.org> + + * src/arg.c: Parse out -o options; also work out whether we ought + to call cpp. + +2002-04-25 13:34 Martin Pool <mbp@samba.org> + + * src/: arg.c, daemon.c, distcc.c, distcc.h: Start refactoring + argument scanner. + +2002-04-25 13:15 Martin Pool <mbp@samba.org> + + * src/rpc.c: Must truncate temp file as we start receiving. + +2002-04-25 12:00 Martin Pool <mbp@samba.org> + + * src/GNUmakefile: Doc. + +2002-04-25 11:59 Martin Pool <mbp@samba.org> + + * src/: GNUmakefile, Makefile: The dependency stuff in the makefile + current requires GNU Make, so change the filename to reflect + that. + +2002-04-25 01:33 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.c, io.c, rpc.c, rpc.h: client now receives + DOTO file from the server and stores it in the destination + +2002-04-25 01:23 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.c, io.c, io.h, rpc.c, rpc.h: Send back + compiler wait-status and .o file + +2002-04-25 01:11 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.c, rpc.c, rpc.h: Client now waits for the + start of the response from the server + +2002-04-25 01:11 Martin Pool <mbp@samba.org> + + * src/Makefile: Add rpc.c + + Make clean cleans .d files + +2002-04-25 00:27 Martin Pool <mbp@samba.org> + + * src/: distcc.h, exec.c: Examine and remember the cc exit code. + +2002-04-25 00:18 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.c, distcc.h, exec.c, io.h: Server now + starts sending a response back. + +2002-04-25 00:04 Martin Pool <mbp@samba.org> + + * src/: arg.c, daemon.c, distcc.c, distcc.h: Improve server-side + argument argument parsing + +2002-04-24 23:52 Martin Pool <mbp@samba.org> + + * src/arg.c: Better debug for server-side substitution + +2002-04-24 23:44 Martin Pool <mbp@samba.org> + + * src/util.c: fix file-style + +2002-04-24 23:44 Martin Pool <mbp@samba.org> + + * src/distcc.c: message when sending is complete + +2002-04-24 23:43 Martin Pool <mbp@samba.org> + + * src/: daemon.c, util.h: redirect stderr to prevent fouling socket + +2002-04-24 23:30 Martin Pool <mbp@samba.org> + + * src/distcc.c: Clean up; add error checks. + +2002-04-24 23:30 Martin Pool <mbp@samba.org> + + * src/clinet.c: Clean up imported code, and in particular log + messages + +2002-04-24 23:29 Martin Pool <mbp@samba.org> + + * src/arg.c: Fix comment + +2002-04-24 23:29 Martin Pool <mbp@samba.org> + + * src/Makefile: Store version in Makefile + +2002-04-24 23:17 Martin Pool <mbp@samba.org> + + * src/clinet.c: Copy in network code from rsync. Currently + hardcoded to localhost:4200. + +2002-04-24 18:05 Martin Pool <mbp@samba.org> + + * src/: .cvsignore, Makefile, clinet.c, distcc.c, distcc.h: Start + changes to connect across the network rather than dumping to a + file. + +2002-04-24 16:29 Martin Pool <mbp@samba.org> + + * src/distcc.c: Doc + +2002-04-24 16:13 Martin Pool <mbp@samba.org> + + * src/: Makefile, arg.c, daemon.c, distcc.c, distcc.h, exec.c, + io.c: daemon will now actually compile programs + +2002-04-24 00:51 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.c, distcc.h, exec.c, io.c, io.h: Make the + server receive the .i file into a temporary file. + +2002-04-24 00:50 Martin Pool <mbp@samba.org> + + * src/Makefile: Fix 'make clean' + +2002-04-24 00:49 Martin Pool <mbp@samba.org> + + * src/.cvsignore: Ignore any .i files that might be around + +2002-04-24 00:21 Martin Pool <mbp@samba.org> + + * src/: Makefile, distcc.c, distcc.h, exec.c: Split out code to run + the compiler + +2002-04-24 00:10 Martin Pool <mbp@samba.org> + + * src/: README, daemon.c, distcc.c, distcc.h, io.c, io.h, trace.h: + Server now reads argv from network. + +2002-04-23 17:37 Martin Pool <mbp@samba.org> + + * src/: daemon.c, distcc.c, distcc.h, io.c: Start adding code to + let the daemon read requests. + +2002-04-23 16:39 Martin Pool <mbp@samba.org> + + * src/io.c: Split out more common code. + + Send the bulk of the file. + + Add a no-op distccd. + +2002-04-23 16:33 Martin Pool <mbp@samba.org> + + * src/: .cvsignore, Makefile, daemon.c, distcc.c, distcc.h: Split + out more common code. + + Send the bulk of the file. + + Add a no-op distccd. + +2002-04-23 14:55 Martin Pool <mbp@samba.org> + + * src/: .cvsignore, Makefile, distcc.c, distcc.h, trace.c, util.c: + Split utilities into their own file + +2002-04-23 14:44 Martin Pool <mbp@samba.org> + + * src/distcc.c: Add framework for sending requests to server, but + just send them to a tmpfile instead. + +2002-04-23 14:24 Martin Pool <mbp@samba.org> + + * src/distcc.c: Put arguments into a jobinfo_t struct. + +2002-04-23 14:14 Martin Pool <mbp@samba.org> + + * src/distcc.c: Try to detect .i and .o files + +2002-04-23 13:47 Martin Pool <mbp@samba.org> + + * src/distcc.c: Handle empty command line. + +2002-04-23 13:25 Martin Pool <mbp@samba.org> + + * src/.cvsignore: Ignore built files + +2002-04-23 13:24 Martin Pool <mbp@samba.org> + + * src/: trace.c, trace.h: Copy trace routines from librsync + +2002-04-23 13:22 Martin Pool <mbp@samba.org> + + * src/: distcc.c, .cvsignore, HACKING, Makefile: Copy very simple + code into public samba cvs + diff --git a/distcc/INSTALL b/distcc/INSTALL new file mode 100644 index 0000000..2a09826 --- /dev/null +++ b/distcc/INSTALL @@ -0,0 +1,190 @@ +Installation instructions for distcc -*- indented-text -*- + + +distcc is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. distcc comes with ABSOLUTELY NO WARRANTY, +for details see the licence. + +If you find distcc useful, please consider donating to the Samba +Foundation to help cover our costs in publishing free +software. (Please mention distcc in your donation.) + +Please report any problems to distcc@lists.samba.org. + + +Prerequisites +------------- + +To build distcc you need + + GNU Make + A C compiler + +You can optionally have + + libpopt + + If this is not found on your system, it will be statically linked in. + + Python >=2.0 + + To run the test suite with "make maintainer-check" or the + benchmark. + + linuxdoc SGML tools + + To rebuild the documentation from its SGML source. + + autoconf >=2.5 + + To rebuild the configure scripts if you edit configure.ac. + +To build the optional GNOME monitor (--with-gnome), you need the +GNOME2 development libraries, and in particular + + gtk+ >=2.0 + libgnome >=2.0 + libgnomeui >= 2.0 + libglade >= 2.0 + libpango + +The monitor can also be built without GNOME desktop integration +(--with-gtk), in which case you need only + + gtk+ >=2.0 + libglade >= 2.0 + + +Preliminaries +------------- + +distcc can be installed and used without requiring root access. +Adjust directories appropriately when installing. + + +Compiling distcc +---------------- + +Compilation follows the standard GNU pattern: + + $ ./configure --help + $ ./configure + $ make + # make install + +Note that the default GNU "sysconfdir" is /usr/local/etc. You may +want to change this to /etc. + + $ ./configure --sysconfdir=/etc + +You can set an installation prefix if you want to put distcc in /opt: + + $ ./configure --prefix=/opt/distcc/ + +distcc needs to be installed on all client and server machines. + +If you would like a graphical client-side monitor to show running +jobs, you can choose either --with-gnome or --with-gtk. + +If you would like to try running distcc over IPv6, use +--enable-rfc2553. You must have a reasonably recent operating system +or this is likely to fail in complex ways. + + +Starting the daemon +------------------- + +This stage is only required if you want to run distcc over TCP +sockets, rather than SSH connections. TCP is faster but less secure +and should only be used on trusted networks. + +In TCP mode distccd can run either from inetd or as a standalone +daemon. Running standalone is recommended. + +To run standalone, run a command like this, either from the command +line or from the system startup scripts. + + distccd --daemon + +If the daemon is started from an rc script, then make sure that it +sees a PATH setting which can find any compilers installed in +nonstandard directories. + +You should create a "distcc" account on server machines so that distcc +can run with minimal privilege. It is not necessary for this account +to own any files or have a home directory. If this account doesn't +exist, distccd uses the "nobody" account. + +By default distccd writes messages to the "daemon" syslog, which +typically ends up in /var/log/messages or /var/log/daemon. + +You can set IP-based access control using the --allow and --listen +options, in either inetd or daemon mode: + + distccd --allow 10.4.20.0/24 + +distccd does not need to run on machines that will only act as +clients. + +See the manual for more information. + + +Set up the host list +-------------------- + +On the client machines, store a list of servers names in +~/.distcc/hosts. If you're using TCP connections, it should look like +this: + + localhost red green blue + +For SSH connections + + localhost @red @green @blue + +The hosts should be listed in descending order of speed. localhost +should normally be first, unless it is signficantly slower than +another machine. + +See the manual for more information. + + +Create the masquerade directories +--------------------------------- + +The easiest way to use distcc is in "masquerade" mode, where it is +installed on the path to "catch" calls to the compiler and redirect +them over the network. Other options are discussed in the manual. + +For instance, you could create the directory named /usr/lib/distcc/bin +and populate it with links. + +# mkdir /usr/lib/distcc/bin +# cd /usr/lib/distcc/bin +# ln -s ../../../bin/distcc gcc +# ln -s ../../../bin/distcc cc +# ln -s ../../../bin/distcc g++ +# ln -s ../../../bin/distcc c++ + +Do this for all compiler names that you use. + +Then, to use distcc, a user just needs to put the directory +/usr/lib/distcc/bin early in the PATH and distcc will handle the rest. + + export PATH=/usr/lib/distcc/bin:$PATH + + +Use with ccache +--------------- + +The best way to use is to set up a similar masquerade directory for +ccache, and put it on the path before distcc. + + +Complete the survey +------------------- + +Once you have distcc working for your own application, please complete +and mail in the survey in survyey.txt. diff --git a/distcc/Makefile.in b/distcc/Makefile.in new file mode 100644 index 0000000..c7c1d43 --- /dev/null +++ b/distcc/Makefile.in @@ -0,0 +1,669 @@ +# Top-level Makefile(.in) for distcc + +# Copyright (C) 2002, 2003, 2004 by Martin Pool + +# Note that distcc no longer uses automake, but this file is still +# structured in a somewhat similar way. + +# Remember that a CVS checkout of this project contains some +# directories that will not be present in a tarball distribution. +# So, those directories must not be built by regular +# commands (make all, make clean, make distclean), only by +# maintainer-* or explicit invocations. + +## VARIABLES + +PACKAGE = @PACKAGE_NAME@ +VERSION = @PACKAGE_VERSION@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +SHELL = @SHELL@ + +# These autoconf variables may contain recursive Make expansions, and +# so they have to be done here rather than written into config.h. + +CFLAGS = @CFLAGS@ +WERROR_CFLAGS = @WERROR_CFLAGS@ +POPT_CFLAGS = @POPT_CFLAGS@ + +LDFLAGS = @LDFLAGS@ +CC = @CC@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ ${DIR_DEFS} -Isrc -I$(srcdir)/lzo + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include +docdir = @docdir@ +pkgdatadir = $(datadir)/@PACKAGE_NAME@ + +# These must be done from here, not from autoconf, because they can +# contain variable expansions written in Make syntax. Ew. +DIR_DEFS = -DSYSCONFDIR="\"${sysconfdir}\"" -DPKGDATADIR="\"${pkgdatadir}\"" + +# arguments to pkgconfig +GNOME_PACKAGES = @GNOME_PACKAGES@ +GNOME_CFLAGS = @GNOME_CFLAGS@ +GNOME_LIBS = @GNOME_LIBS@ + +LIBS = @LIBS@ + +DESTDIR = + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ + +# You might need to override this depending on the name under which +# Python is installed here. +PYTHON = @PYTHON@ + +dist_files = \ + src/config.h.in \ + $(dist_lzo) \ + $(dist_contrib) \ + $(dist_patches) \ + $(dist_common) \ + $(MEN) \ + $(pkgdoc_DOCS) \ + $(example_DOCS) \ + $(popt_EXTRA) $(popt_SRC) $(popt_HEADERS) \ + $(SRC) $(HEADERS) \ + $(test_SOURCE) \ + $(bench_PY) \ + $(dist_extra) \ + $(gnome_data) + +dist_lzo = lzo/minilzo.c lzo/minilzo.h lzo/lzoconf.h lzo/.stamp-conf.in + +dist_contrib = contrib/distcc-absolutify \ + contrib/distcc.sh \ + contrib/distccd-init \ + contrib/dmake \ + contrib/make-j \ + contrib/netpwd \ + contrib/stage-cc-wrapper.patch \ + contrib/redhat/init \ + contrib/redhat/logrotate \ + contrib/redhat/sysconfig \ + contrib/redhat/xinetd + +bench_PY = bench/Build.py bench/Project.py bench/ProjectDefs.py \ + bench/Summary.py bench/actions.py bench/benchmark.py \ + bench/buildutil.py bench/compiler.py bench/statistics.py + +pkgdoc_DOCS = AUTHORS COPYING NEWS README \ + INSTALL \ + TODO \ + doc/protocol-1.txt doc/status-1.txt \ + doc/protocol-2.txt \ + doc/reporting-bugs.txt \ + survey.txt + +example_DOCS = \ + doc/example/init doc/example/init-suse \ + doc/example/logrotate \ + doc/example/xinetd \ + +# These are included in the distribution but not installed into the +# doc dir. +dist_extra = \ + README.packaging ChangeLog ChangeLog.old + +mkinstalldirs = $(SHELL) $(srcdir)/mkinstalldirs +man1dir = $(mandir)/man1 +man8dir = $(mandir)/man8 + +test_SOURCE = test/comfychair.py \ + test/testdistcc.py + +dist_common = Makefile.in install-sh configure configure.ac \ + config.guess config.sub mkinstalldirs autogen.sh + +# It seems a bit unnecessary to ship patches in the released tarballs. +# People who are so keen as to apply unsupported patches ought to use +# CVS, or at least get them from the list. +dist_patches = + +TAR = tar +GZIP = gzip +GZIP_OPT = -9v + +BZIP2 = bzip2 + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir = $(PACKAGE_TARNAME)-$(VERSION) +tarball = $(PACKAGE_TARNAME)-$(VERSION).tar +tarball_bz2 = $(tarball).bz2 +tarball_sig = $(tarball_bz2).asc +distnews = $(PACKAGE_TARNAME)-$(VERSION).NEWS + +common_obj = src/arg.o src/argutil.o \ + src/cleanup.o src/compress.o \ + src/trace.o src/util.o src/io.o src/exec.o \ + src/rpc.o src/tempfile.o src/bulk.o src/help.o src/filename.o \ + src/lock.o \ + src/netutil.o \ + src/pump.o \ + src/sendfile.o \ + src/safeguard.o src/snprintf.o src/timeval.o \ + src/dotd.o \ + src/hosts.o src/hostfile.o \ + src/implicit.o src/loadfile.o \ + lzo/minilzo.o + +distcc_obj = src/backoff.o \ + src/climasq.o src/clinet.o src/clirpc.o \ + src/compile.o src/cpp.o \ + src/distcc.o \ + src/remote.o \ + src/ssh.o src/state.o src/strip.o \ + src/timefile.o src/traceenv.o \ + src/include_server_if.o \ + src/where.o \ + src/emaillog.o \ + $(common_obj) + +distccd_obj = src/access.o \ + src/daemon.o src/dopt.o src/dparent.o src/dsignal.o \ + src/ncpus.o \ + src/prefork.o \ + src/stringmap.o \ + src/serve.o src/setuid.o src/srvnet.o src/srvrpc.o src/state.o \ + src/stats.o \ + src/fix_debug_info.o \ + $(common_obj) @BUILD_POPT@ + +lsdistcc_obj = src/lsdistcc.o \ + src/clinet.o src/io.o src/netutil.o src/trace.o src/util.o \ + src/rslave.o \ + lzo/minilzo.o + +# Objects that need to be linked in to build monitors +mon_obj = \ + src/cleanup.o \ + src/filename.o \ + src/io.o \ + src/mon.o \ + src/netutil.o \ + src/argutil.o \ + src/rpc.o \ + src/snprintf.o src/state.o \ + src/tempfile.o src/trace.o src/traceenv.o \ + src/util.o + +gnome_obj = src/history.o src/mon-gnome.o \ + src/renderer.o + +h_exten_obj = src/h_exten.o $(common_obj) +h_issource_obj = src/h_issource.o $(common_obj) +h_scanargs_obj = src/h_scanargs.o $(common_obj) +h_hosts_obj = src/h_hosts.o $(common_obj) +h_argvtostr_obj = src/h_argvtostr.o $(common_obj) +h_strip_obj = src/h_strip.o $(common_obj) src/strip.o +h_parsemask_obj = src/h_parsemask.o $(common_obj) src/access.o +h_sa2str_obj = src/h_sa2str.o $(common_obj) src/srvnet.o src/access.o +h_ccvers_obj = src/h_ccvers.o $(common_obj) +h_dotd_obj = src/h_dotd.o $(common_obj) +h_fix_debug_info = src/h_fix_debug_info.o $(common_obj) +h_compile_obj = src/h_compile.o $(common_obj) src/compile.o src/timefile.o \ + src/backoff.o src/emaillog.o src/remote.c src/clinet.o \ + src/clirpc.o src/include_server_if.o src/state.o src/where.o \ + src/ssh.o src/strip.o src/cpp.o + +# All source files, for the purposes of building the distribution +SRC = src/stats.c \ + src/access.c src/arg.c src/argutil.c \ + src/backoff.c src/bulk.c \ + src/cleanup.c \ + src/climasq.c src/clinet.c src/clirpc.c src/compile.c \ + src/compress.c src/cpp.c \ + src/daemon.c src/distcc.c src/dsignal.c \ + src/dopt.c src/dparent.c src/exec.c src/filename.c \ + src/h_argvtostr.c \ + src/h_exten.c src/h_hosts.c src/h_issource.c src/h_parsemask.c \ + src/h_sa2str.c src/h_scanargs.c src/h_strip.c \ + src/h_dotd.c src/h_compile.c \ + src/help.c src/history.c src/hosts.c src/hostfile.c \ + src/implicit.c src/io.c \ + src/loadfile.c src/lock.c \ + src/mon.c src/mon-notify.c src/mon-text.c \ + src/mon-gnome.c \ + src/ncpus.c src/netutil.c \ + src/prefork.c src/pump.c \ + src/remote.c src/renderer.c src/rpc.c \ + src/safeguard.c src/sendfile.c src/setuid.c src/serve.c \ + src/snprintf.c src/state.c \ + src/srvnet.c src/srvrpc.c src/ssh.c \ + src/stringmap.c src/strip.c \ + src/tempfile.c src/timefile.c \ + src/timeval.c src/traceenv.c \ + src/trace.c src/util.c src/where.c \ + src/lsdistcc.c src/rslave.c \ + src/dotd.c src/include_server_if.c \ + src/emaillog.c \ + src/fix_debug_info.c + + +HEADERS = src/stats.h \ + src/access.h \ + src/bulk.h \ + src/clinet.h src/compile.h \ + src/daemon.h \ + src/distcc.h src/dopt.h src/exitcode.h \ + src/fix_debug_info.h \ + src/hosts.h src/implicit.h \ + src/mon.h \ + src/netutil.h \ + src/renderer.h src/rpc.h \ + src/snprintf.h src/state.h \ + src/stringmap.h \ + src/timefile.h src/timeval.h src/trace.h \ + src/types.h \ + src/util.h \ + src/exec.h src/lock.h src/where.h src/srvnet.h \ + src/rslave.h \ + src/dotd.h src/include_server_if.h \ + src/emaillog.h + +man1_MEN = man/distcc.1 man/distccd.1 man/distccmon-text.1 +man_HTML = man/distcc_1.html man/distccd_1.html man/distccmon_text_1.html +MEN = $(man1_MEN) + +gnome_data = gnome/distccmon-gnome-icon.png \ + gnome/distccmon-gnome.desktop + +popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \ + popt/popthelp.o popt/poptparse.o + +popt_SRC=popt/findme.c popt/popt.c popt/poptconfig.c \ + popt/popthelp.c popt/poptparse.c + +popt_HEADERS = popt/findme.h popt/popt.h popt/poptint.h popt/system.h + +popt_EXTRA = popt/README.popt popt/.stamp-conf.in + + +# You might think that distccd ought to be in sbin, because it's a +# daemon. It is a grey area. However, the Linux Filesystem Hierarchy +# Standard (FHS 2.2) says that sbin is for programs "used exclusively +# by the system administrator". + +# distccd will often be used by non-root users, and when we support +# ssh it will be somewhat important that it be found in their default +# path. Therefore on balance it seems better to put it in bin/. + +# Package maintainers can override this if absolutely necessary, but I +# would prefer that they do not. -- mbp + +bin_PROGRAMS = \ + distcc@EXEEXT@ \ + distccd@EXEEXT@ \ + distccmon-text@EXEEXT@ \ + lsdistcc@EXEEXT@ \ + @GNOME_BIN@ + +check_PROGRAMS = \ + h_argvtostr@EXEEXT@ \ + h_exten@EXEEXT@ \ + h_fix_debug_info@EXEEXT@ \ + h_hosts@EXEEXT@ \ + h_issource@EXEEXT@ \ + h_parsemask@EXEEXT@ \ + h_sa2str@EXEEXT@ \ + h_scanargs@EXEEXT@ \ + h_strip@EXEEXT@ \ + h_dotd@EXEEXT@ \ + h_compile@EXEEXT@ + +## OVERALL targets + +## IMPLICIT BUILD rules + +.SUFFIXES: .html .latte .o .c + +.c.o: + $(CC) $(CPPFLAGS) $(WERROR_CFLAGS) $(CFLAGS) -o $@ -c $< + +## OVERALL targets + +## NOTE: "all" must be the first (default) rule, aside from patterns. + +all: $(bin_PROGRAMS) + +# src/config.h.in is used by config.status +Makefile: Makefile.in src/config.h.in config.status + ./config.status + +## BUILD targets + +# We would like to detect when config.h.in has changed: this should trigger +# config.status to be rerun. But if the config.h file actually does not change +# as a result of running config.status (a feature of autoconf), then +# config.status will be rerun every time. That's confusing. So, the rule +# +# src/config.h: src/config.h.in +# ./config.status +# +# is not sufficient. + +src/config.h: src/config.h.stamp + +src/config.h.stamp: src/config.h.in + ./config.status + touch src/config.h.stamp + +# Grab the dependency files generated by gcc's -MD option. +-include */*.d + +# Disable some warnings for popt/*.c. +$(popt_OBJS): CFLAGS += $(POPT_CFLAGS) + +distcc@EXEEXT@: $(distcc_obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(distcc_obj) $(LIBS) + +distccd@EXEEXT@: $(distccd_obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(distccd_obj) $(LIBS) + +distccmon-text@EXEEXT@: $(mon_obj) src/mon-text.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(mon_obj) src/mon-text.o $(LIBS) + +lsdistcc@EXEEXT@: $(lsdistcc_obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(lsdistcc_obj) $(LIBS) + +h_exten@EXEEXT@: $(h_exten_obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(h_exten_obj) $(LIBS) + +h_issource@EXEEXT@: $(h_issource_obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(h_issource_obj) $(LIBS) + +h_sa2str@EXEEXT@: $(h_sa2str_obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(h_sa2str_obj) $(LIBS) + +h_scanargs@EXEEXT@: $(h_scanargs_obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(h_scanargs_obj) $(LIBS) + +h_hosts@EXEEXT@: $(h_hosts_obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(h_hosts_obj) $(LIBS) + +h_argvtostr@EXEEXT@: $(h_argvtostr_obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(h_argvtostr_obj) $(LIBS) + +h_parsemask@EXEEXT@: $(h_parsemask_obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(h_parsemask_obj) $(LIBS) + +h_strip@EXEEXT@: $(h_strip_obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(h_strip_obj) $(LIBS) + +h_ccvers@EXEEXT@: $(h_ccvers_obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(h_ccvers_obj) $(LIBS) + +h_dotd@EXEEXT@: $(h_dotd_obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(h_dotd_obj) $(LIBS) + +h_fix_debug_info@EXEEXT@: $(h_fix_debug_info) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(h_fix_debug_info) $(LIBS) + +h_compile@EXEEXT@: $(h_compile_obj) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(h_compile_obj) $(LIBS) + + +src/h_fix_debug_info.o: src/fix_debug_info.c + $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) \ + -DTEST \ + $(srcdir)/src/fix_debug_info.c + +src/mon-gnome.o: src/mon-gnome.c + $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) \ + $(GNOME_CFLAGS) \ + $(srcdir)/src/mon-gnome.c + +src/renderer.o: src/renderer.c + $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) \ + $(GNOME_CFLAGS) \ + $(srcdir)/src/renderer.c + +distccmon-gnome@EXEEXT@: $(mon_obj) $(gnome_obj) + $(CC) -o $@ $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LIBS) \ + $(GNOME_CFLAGS) $(GNOME_LIBS) \ + $(mon_obj) $(gnome_obj) + + +## Dist targets + +# The sub-targets copy (and if necessary, build) various files that +# have to go into the tarball. They also create necessary directories +# -- bear in mind that they might be run in parallel. + +# This looks a bit gross to me, but it's not as bad as it might be :-/ + +dist: + -rm -fr $(distdir) + $(MAKE) dist-files + $(TAR) cfh $(tarball) $(distdir) + $(BZIP2) -vf $(tarball) + rm -r $(distdir) + cp NEWS $(distnews) + +distcheck: dist + rm -rf '+distcheck' + mkdir '+distcheck' + cd '+distcheck' && bunzip2 < ../$(tarball_bz2) | $(TAR) xv && \ + cd $(distdir) && ./configure --prefix=`pwd`/prefix && \ + $(MAKE) && $(MAKE) install && $(MAKE) maintainer-check && \ + $(MAKE) clean + rm -rf '+distcheck' + +dist-sign: + gpg -a --detach-sign $(tarball_bz2) + +# the sort function removes duplicates +dist-files: $(dist_files) + for f in $(dist_files); do mkdir -p $(distdir)/`dirname $$f` || exit 1; \ + cp -a $(srcdir)/$$f $(distdir)/$$f || exit 1; done + +## BUILD manual targets +man/distcc_1.html: man/distcc.1 + troff2html -man man/distcc.1 > $@ + +man/distccd_1.html: man/distccd.1 + troff2html -man man/distccd.1 > $@ + +man/distccmon_text_1.html: man/distccmon-text.1 + troff2html -man man/distccmon-text.1 > $@ + + +###################################################################### +## CHECK targets + +check_programs: $(check_PROGRAMS) $(bin_PROGRAMS) + +TESTDISTCC_OPTS = + +# WARNING: This resets the path to avoid any confusion caused by +# having distcc masquerades already on the path. If you have gcc +# installed elsewhere this won't work.... +maintainer-check: check_programs + if test x$(PYTHON) != x; then \ + $(PYTHON) -c 'import sys; print sys.version'; \ + PATH=`pwd`:/usr/local/bin:/bin:/usr/bin \ + $(PYTHON) $(srcdir)/test/testdistcc.py $(TESTDISTCC_OPTS); \ + else echo "WARNING: python not found; tests skipped"; \ + fi + +# NB: This does not depend upon install; you might want to test another version. +maintainer-installcheck: check_programs + if test x$(PYTHON) != x; then \ + $(PYTHON) -c 'import sys; print sys.version'; \ + PATH="$(bindir):`pwd`:$$PATH" $(PYTHON) $(srcdir)/test/testdistcc.py; \ + else echo "WARNING: python not found; tests skipped"; \ + fi + +check: + @echo Please try 'make maintainer-check' instead. +installcheck: + @echo Please try 'make maintainer-check' instead. + +# Runs the tests in lzo-mode. +lzo-check: + $(MAKE) TESTDISTCC_OPTS=--lzo maintainer-check + +# Runs the tests with valgrind. +valgrind-check: + $(MAKE) TESTDISTCC_OPTS=--valgrind maintainer-check + +# This is an integration test which runs the distcc tests +# using distcc-pump. So you need to build distcc-pump first. +# Run "make" in the distcc_pump directory before running this test. +pump-check: + $(srcdir)/../pump $(MAKE) TESTDISTCC_OPTS=--pump maintainer-check +# TODO(fergus): Move this rule to ../Makefile.in. + +# The following target is useful for running a single test at a time. +# Sample usage: +# make TESTNAME=Lsdistcc_Case singletest +# make TESTNAME=Lsdistcc_Case TESTDISTCC_OPTS=--valgrind singletest +TESTNAME = NoDetachDaemon_Case # Override this with the desired test. +single-test: check_programs + PATH=`pwd`:/usr/local/bin:/bin:/usr/bin \ + $(PYTHON) $(srcdir)/test/onetest.py $(TESTDISTCC_OPTS) $(TESTNAME) + +###################################################################### +## BENCHMARK targets +benchmark: + @echo "The distcc macro-benchmark uses your existing distcc installation" + @if [ "$$DISTCC_HOSTS" ]; \ + then echo "DISTCC_HOSTS=\"$$DISTCC_HOSTS\""; \ + else echo "You must set up servers and set DISTCC_HOSTS before running the benchmark"; \ + exit 1; \ + fi + @echo "This benchmark may download a lot of source files, and it takes a " + @echo "long time to run. Interrupt now if you want." + @echo + @echo "Pass BENCH_ARGS to make to specify which benchmarks to run." + @echo + @sleep 5 + cd bench && $(PYTHON) benchmark.py $(BENCH_ARGS) + + +## CLEAN targets + +# Also clean binaries which are optionally built. Also remove .d files; old ones +# may confuse 'make'. +clean: clean-autoconf clean-lzo + rm -f src/*.[od] popt/*.[od] + rm -f $(check_PROGRAMS) $(bin_PROGRAMS) + rm -f distccmon-gnome + rm -rf testtmp + +clean-autoconf: + rm -f config.cache config.log + +clean-lzo: + rm -f lzo/*.[od] lzo/testmini + +maintainer-clean: distclean \ + maintainer-clean-autoconf clean + +# configure and co are distributed, but not in CVS +maintainer-clean-autoconf: + rm -f configure src/config.h.in + +distclean-autoconf: + rm -f Makefile src/config.h config.status config.cache config.log + rm -rf autom4te.cache + +distclean: distclean-autoconf clean + + +## MAINTAINER targets + +upload-man: $(man_HTML) + rsync -avz $(man_HTML) \ + --exclude CVS --exclude '*~' --exclude '*.latte' \ + samba.org:/home/httpd/distcc/man/ + +upload-dist: + rsync -avP $(tarball_bz2) $(distnews) $(tarball_sig) samba.org:/home/ftp/pub/distcc/ + + + +### INSTALL targets + +# TODO: Allow root directory to be overridden for use in building +# packages. + + + +showpaths: + @echo "'make install' will install distcc as follows:" + @echo " man pages $(DESTDIR)$(man1dir)" + @echo " documents $(DESTDIR)$(docdir)" + @echo " programs $(DESTDIR)$(bindir)" + @echo " system configuration $(DESTDIR)$(sysconfdir)" + @echo " shared data files $(DESTDIR)$(pkgdatadir)" + + +# install-sh can't handle multiple arguments, but we don't need any +# tricky features so mkinstalldirs and cp will do + +install: showpaths install-doc install-man install-programs install-example @INSTALL_GNOME@ + +install-programs: $(bin_PROGRAMS) + $(mkinstalldirs) $(DESTDIR)$(bindir) + for p in $^; do \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir) || exit 1; \ + done + +install-man: $(man1_MEN) + $(mkinstalldirs) $(DESTDIR)$(man1dir) + for p in $^; do \ + $(INSTALL_DATA) $$p $(DESTDIR)$(man1dir) || exit 1; \ + done + +install-doc: $(pkgdoc_DOCS) + $(mkinstalldirs) $(DESTDIR)$(docdir) + for p in $^; do \ + $(INSTALL_DATA) $$p $(DESTDIR)$(docdir) || exit 1; \ + done + +install-example: $(example_DOCS) + $(mkinstalldirs) $(DESTDIR)$(docdir)/example + for p in $^; do \ + $(INSTALL_DATA) $$p $(DESTDIR)$(docdir)/example || exit 1; \ + done + +install-gnome-data: $(gnome_data) + $(mkinstalldirs) $(DESTDIR)$(pkgdatadir) + for p in $^; do \ + $(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir) || exit 1; \ + done + +# For distcc-pump + +.PHONY: echo_common_obj +echo_common_obj: + echo $(common_obj) + +.PHONY: echo_srcdir +echo_srcdir: + cd $(srcdir) && pwd + +.PHONY: echo_srcdir_parent +echo_srcdir_parent: + cd $(srcdir)/.. && pwd diff --git a/distcc/NEWS b/distcc/NEWS new file mode 100644 index 0000000..8548c3b --- /dev/null +++ b/distcc/NEWS @@ -0,0 +1,2144 @@ +distcc-pump-1.0 "My prices are insane." 2008-??-?? + + FEATURES: + + * New protocol, version 3, allowing for preprocessing on distcc servers. + + * New component: an include server for incremental static analysis of include + dependencies. This software is written in Python 2.4. + + BUG FIXES (TODO: include all kegel, manos, dongmin, et al patches): + + + PORTABILITY: + + * Tested under Linux only. Processing of object code rewrites debug info + (so server paths are replaced with client paths), but this works for ELF + code only. + + + +distcc-2.18.3 "Porsche safari" 2004-11-30 + + BUG FIXES: + + * Fix for incorrect handling of -x and -specs from Michal Welnicki. + + + TESTS: + + * Fix false pass in tests for -x and -specs. + + +distcc-2.18.2 "Bees and lavender" 2004-11-12 + + BUG FIXES: + + * Fix problem in checking errno after connect(). Fix by Jean + Delvare and Dan Kegel. + + + PORTABILITY: + + * Fix prototype problem causing build failure on amd64. Patch + from Andreas Jochens. (Debian #280399, #280644). + +distcc-2.18.1 "Reality-based computing" 2004-11-03 + + BUG FIXES: + + * Fix run-time warnings about gtk_tree_model_row_changed() when + built with recent versions of GTK+. + + * gcc option -specs= must be run locally so that it can read the + local spec file. Reported by Chris Yeoh. + + + PORTABILITY: + + * Fix Solaris build problem reported by Dimitri Papadopoulos. + + * Fix problem with reading hosts files in DOS CRLF format. + Reported by Sebastien Perochon. + + +distcc-2.18 "Billionaires on stilts" 2004-10-12 + + BUG FIXES: + + * Fix longjmp() bug that can cause distcc to crash when a timeout + elapses. + + * Fix compile-time problem with dcc_trace when configured with + --enable-rfc2553. Reported by Greg Earle. + + * Fix warning about warn_unused_result for older versions of gcc. + + * No timeout on local preprocessing or on compilation. No + timeouts on DNS lookups other than whatever is built in to the + DNS resolver. There are timeouts on network transmission and on + opening connections. + + * Remove mmap() for receive of uncompressed data, to avoid various + problems. + + + CHANGES: + + * The --allow option is now mandatory for daemon mode. As a + security feature, distccd will refuse to run without an IP + access control list. + + * conftest.* built by autoconf is always done locally, to make + configure tests faster and safer. + + + DOCUMENTATION: + + * Better description of use with ccache. + + + PORTABILITY: + + * Fix various warnings reported by Dimitri Papadopoulos. + + * Fix Tru64 build problem reported by Gary V. Vaughan. + + +distcc-2.17 "Divers Alarums" 2004-07-31 + + FEATURES: + + * Performance improvements for distccmon-gnome. + + * Added timeous for connection to servers, transmission of jobs + and remote compilation. If the timeout expires, the job is run + locally. This should make distcc cope better if some or all of + the servers are unreachable or failing. + + * Also add timeouts in server to kick out stalled or disconnected + clients. + + + BUG FIXES: + + * If remote compilation fails because of a signal in a later phase + of the compilation causing an exit with code >=128, retry + compilation locally. Patch from Jakub Stachowski. + + + DOCUMENTATION: + + * Manpage fix from Jean Delvare. + + + PORTABILITY: + + * Cygwin portability fix for WCOREDUMP, reported by Eric Frias. + + +distcc-2.16 "Salt" 2004-07-08 + + SECURITY: + + * Fix bug that might cause IP-based access control rules not to be + interpreted correctly on 64-bit platforms. (CAN-2004-0601) + + + BUG FIXES: + + * Fix small memory leaks in distccmon-gnome and distccmon-text. + + + FEATURES: + + * Use a GNOME status bar with a grab handle for distccmon-gnome. + Patch from Nathan Fredrickson. + + + PORTABILITY: + + * Better detection of systems with a popt library installed but + no popt.h. Reported by Sean Kelly. + + * Fix bug in reporting crashed daemon children that showed up on + systems without strsignal, such as Mac OS 10.2. Reported by + Benjamin Reed. + + * Update testdistcc.py to work on ia64 linux. + + + INTERNAL: + + * Simplify dcc_log_child_exited. + + * Include copyright and licence in --version output, as suggested + by GNU programs. + + +distcc-2.15 "feel good for ten seconds" 2004-07-06 + + BUG FIXES: + + * Fix crash bug in receiving LZO compressed data into a mmapped + file. Reported by Arkadiusz Miskiewicz. + + * Remove redundant temporary file cleanup in non-forking mode. + + + FEATURES: + + * Client calculates and can display the overall throughput in + preprocessed bytes per second for remote jobs. + + + REMOVALS: + + * The deprecated fork-after-exec mode controlled by the + --no-prefork option has been removed. + + * mmap is no longer used for compressed data to simplify the code. + + + PORTABILITY: + + * Additional fixes to Red Hat / Fedora scripts, by Colins Walters. + + + INTERNAL: + + * Daemon now chdirs to $TMPDIR at startup rather than /. This + allows dumping core, among other things. + + +distcc-2.14 "Lake Albina" 2004-05-02 + + FEATURES: + + * The host file is looked up in $DISTCC_DIR/hosts, not hardcoded + to ~/.distcc/hosts. The default for $DISTCC_DIR is still + ~/.distcc. Suggested by Sebastien Perochon. + + * Source file name is included in success/failure messages, e.g. + + distcc[6655] ERROR: compile ./cases/bad.c on cardhu failed + + * distcc can now be built with a build directory separate from the + source directory. Patch from Dennis Henriksen. + + * Added --randomize option to host list to help spread the load + across large shared clusters. From patch by Google + (Josh Hyman <joshh@google.com>). + + DOCUMENTATION: + + * Add documentation of DISTCC_DIR, and other fixes. Patch from + Thomas Schwinge. + + * Slightly improved distcc --help. + + + BUG FIXES: + + * Decompression buffer can dynamically resize to allow for very + gassy files. From a patch by Joe Buehler. + + + PORTABILITY: + + * Add sample scripts for Red Hat / Fedora, by Colin Walters. + + * mmap is always disabled on HP-UX, because the inconsistent page + case is a bit dangerous for the way distcc uses mmap. Suggested + by Joe Buehler. + + +distcc-2.13 "Carnal Bunt" 2004-03-02 + + SECURITY: + + * Enforce IPv4 access control lists when the daemon is listening + on an IPv6 port. This only applies when the server was compiled + using --enable-rfc2553 and run with --allow. + + + FEATURES: + + * Hash comments are allowed in host list files. + + + INTERNAL: + + * Use TCP_DEFER_ACCEPT on Linux to avoid some wasted context + switching when a new connection comes in to the server. + + + BUG FIXES: + + * Some fixes for connections over SSH when built using + --enable-rfc2553. Reported by Jeff Rizzo. + + * Handle arguments like "-xcpp" and "-Wa,-xarch=v8". Suggested by + Ben Scarlet. + + * Fix resource exhaustion when DISTCC_SAVE_TEMPS is set. Reported + by Mark DeGeorge. + + * Fix problems in running IPv6-enabled builds on kernels without + IPv6 support. Reported by Lisa Seelye. + + + DOCUMENTATION: + + * More instructions for distributors/packagers. + + + PORTABILITY: + + * Many portability patches from Albert Chin. These patches were + tested on: AIX 4.3.2, 5.1; HP-UX 10.20, 11.00, 11i; IRIX 6.5; + Redhat Linux 7.1, 9; Solaris 2.5.1, 2.6, 7, 8, 9; Tru64 UNIX + 4.0D, 5.1. + + * Possibly fix mmap problem on HP-UX with compressed transfers. + Reported by Joe Buehler. + + + TESTING: + + * Add test for compilation with compression. + + * Testsuite portability patch from Albert Chin. The tests pass + on: HP-UX 10.20, 11.00, 11i; IRIX 6.5; Redhat Linux7.1, 9; + Solaris 7, 8, 9; Tru64 UNIX 4.0d, 5.1. + + +distcc-2.12.1 "Shatner's Bassoon" 2004-01-09 + + BUG FIXES: + + * When checking if a process exists, accept EPERM as indicating it + exists but isn't ours. This allows watching the directory of a + different user, subject only to filesystem permissions. + Reported by Ernst Bachmann. + + * Correct a bug introduced in 2.12 that made distccd fail to start + when run by root because setgid failed. Fix from Wayne Davison. + + * --without-gnome, --without-gtk now turn those options off rather + than on. + + DOCUMENTATION: + + * New man page for distccmon-text, by Shri Shrikumar and Martin + Pool. + + +distcc-2.12 "Figgy Pudding" 2003-12-19 + + FEATURES: + + * New --log-level feature allows logging of only errors rather + than messages for each connection. + + * IPv6 support now works better when distcc is configured with + --enable-rfc2553. The server can normally accept either IPv4 or + IPv6 connections. + + * New --with-docdir configure option to set install location for + documents. The default is the same as previously. Patch from + Harold L Hunt II. + + + INTERNAL: + + * GNU-style ChangeLog is now included in the package. Please keep + it up to date if you make your own changes! + + + PORTABILITY: + + * setgroups() was broken by Mac OS X Panther so that it will not + accept setgroups(0, NULL) to clear the group list. Instead we + now set the group list to our single primary gid. Suggestion + from Wayne Davison. + + * sendfile problems on FreeBSD 4.9-RC fixed. Patch from Allan + Saddi. + + * MAXPATHLEN is provided if it's not defined, which is the case on + GNU Hurd. Reported by Santiago Vila as Debian #219600. + + + BUG FIXES: + + * Check pkg-config information GNOME/GTK+ is now checked at + configure time, not build time. This is a bit quicker than + running the script for every file we build, and means that + PKG_CONFIG_PATH only needs to be set for configure. + + + DOCUMENTATION: + + * Small documentation corrections. + + +distcc-2.11.2 "Muscovado" 2003-10-23 + + BUG FIXES: + + * Correct the handling of --without-gnome. Reported by Dimitri + Papadopoulos. + + * Fatal signal handlers for client and daemon should reset the + signal vector before doing anything else, to protect against an + (unlikely) spin if the signal is re-sent. + + * Corrections to .desktop file from Dag Wieers. + + + INTERNAL: + + * Remove dependency on libglade for GTK+ and GNOME monitor + programs. + + + PORTABILITY: + + * IRIX portability fixes from Dimitri Papadopoulos. + + * Use AC_TYPE_SIGNAL to generate correct signal handler return + types. (It can be either int or void.) + + + DOCUMENTATION: + + * Various manual updates. + + * Update to xinetd example from Dag Wieers. + + +distcc-2.11.1 "Burnt sugar" 2003-10-08 + + FEATURES: + + * The graphical monitor can now be configured with either + --with-gnome or --with-gtk. In the second case, the GNOME + libraries are not used. In both cases the resulting program is + called distccmon-gnome and the functional differences are fairly + small. + + + BUG FIXES: + + * An error message is emitted and compilation fails if distcc + cannot use the specified TMPDIR. This can happen if distccd is + started by root with a TMPDIR only accessible to root. + Reported by Brett Dikeman. + + * GNOME data files are now only installed when the application is + configured with --with-gnome or --with-gtk. Files are installed + into a distcc/ subdirectory of the configured data directory. + (By default this is /usr/local/share/distcc/). Reported by Erik + Jan Tromp and Noe`l Ko"the. + + * Fix bug in sending compressed files where errors were ignored. + + * C++ compilation using -frepo must be local. Reported by Andrew + Slater. + + + PORTABILITY: + + * Don't use stdint.h, which is not available on FreeBSD 4-STABLE, + IRIX or Solaris. Reported by Frerich Raabe. + + + DOCUMENTATION: + + * Corrections to distcc manpage reported by Lionel Sausin. + + * Documentation of how to write monitor programs, from Frerich + Raabe. + + + INTERNAL: + + * Fix state.h for use with C++. Patch from Frerich Raabe. + + +distcc-2.11 "Sugar fix" 2003-09-23 + + INCOMPATIBILITIES: + + * The GNOME monitor is now configured using --with-gnome (not + --enable-gnome) to be more consistent with GNU standards. + + * The state file format has changed, so old distcc monitor + programs will not see new compiler processes and vice versa. + + + FEATURES: + + * Nice new GNOME monitor, showing strip-charts (or "scarves") of + the state of each processor slot over time. + + * --allow 0.0.0.0/0 is accepted as meaning "allow access from + anywhere". Debian #207831, suggested by Matthijs Kooijman. + + + BUG FIXES: + + * If we fail to determine the number of CPUs on the machine, + assume it is 1. This may fix problems on exotic machines where + the detection call is almost but not quite right. + + * In non-forking mode, make sure to close the accepted fd after + processing a request. + + * Use "safe" LZO1 decompression for protection against program or + network errors. + + * Lock and state files are created with the weakest permissions + permitted by the umask. This is intended to reduce problems + seen when $DISTCC_DIR is shared between two users, such as when + compiling as root during program installation. + + * Client deletes temporary files when interrupted. + + + INTERNAL: + + * Add debugging option DISTCC_MMAP, which can be set to 0 to + disable use of mmap for receiving files. + + * New --enable-profile configure option to turn on gprof. + + * Many changes to the representation of the client state to make + it easier to draw a history. State is now stored as a natively + encoded struct in a disk file, rather than using our network + protocol. + + + PERFORMANCE: + + * Sleep only one second when blocked waiting for a CPU, to try to + reduce idle time when recovering from an overloaded period. + + + DOCUMENTATION: + + * Document problems with "no_subtree_check" on NFS. + + * The GNU Free Documentation License is no longer distributed, + because the documentation is now included under the GNU GPL. + + * Document bad Makefiles or mismatched compilers as common causes + of failure. + + * Describe where to put "localhost" in the host list. + + + PORTABILITY: + + * Fixes for BSD/OS (BSDi) from Nick Amato. + + * Fixes for portability issues in autogen.sh from Lisa Seelye and + Alexandre Oliva. + + +distcc-2.10.1 2003-08-12 + + BUG FIXES: + + * Fix problem in "make clean" reported by Lisa Seelye. + + +distcc-2.10 "Hunger is the best sauce" 2003-08-11 + + SECURITY: + + * Fix issues in temporary file handling that could allow a local + attacker to interfere with another user's distcc processes. + + + FEATURES: + + * Daemon niceness is incremented by +5 by default. (This can be + changed by --nice.) + + * The per-user configuration directory can be set by $DISTCC_DIR. + It defaults to the old value of ~/.distcc/. + + * For regular compile failure, don't say "with exit code 1". + + + BUG FIXES: + + * The server now emits warnings to the log and to the client if + its PATH is set such that it will recursively run a distcc + client. This check is done at run time for the requested + compiler name. The server's $PATH is not modified in other + ways. This may help reduce problems with finding the right + remote compiler. + + + PORTABILITY: + + * SCO/Caldera operating systems are no longer supported due to + their recent absurd attacks against Linux and IBM. + + * TMPDIR is no longer required to start with '/', so that Cygwin + paths starting with a drive letter may be used. Reported by + Heiko Elger. + + + DOCUMENTATION: + + * Various man page updates. + + + INTERNAL: + + * Daemon now sits in the root directory while running, not the + temporary directory. + + * Temporary directory is gone. Working files are created directly + under $TMPDIR. + + * Lock files and state files are stored under DISTCC_DIR, rather + than in /tmp. + + + TESTING: + + * Test cases are more robust in choosing a daemon port number. + +distcc-2.9 "Grace under pressure" 2003-07-21 + + FEATURES: + + * Optional LZO1X compression of network traffic, to make distcc + faster on slow or overloaded networks. This is turned on by + appending ",lzo" to each host specification. + + Both client and server must be updated for this to work. Old + clients and servers are supported when compression is off, which + is the default. + + Compression is probably only worthwhile on networks slower than + 100Mbps, but it will depend on the usual factors of CPU, network + and code complexity. Thanks to Markus F.X.J. Oberhumer for the + LZO library. + + + BUG FIXES: + + * Handle invocations like "distcc foo.o -o foo", which can be + generated by Mozilla. + + * Handle invocations like "distcc -Wa,-al=foo.lst -c foo.c", which + write an assembler listing to a file and cannot be run remotely. + + * When trimming the path to avoid recursive invocations, stop as + soon as we find one non-symlink compiler. This should help + avoid the path getting trimmed down far too much on the server. + Patch from Wayne Davison. + + + PERFORMANCE: + + * The daemon by default allows 2+NCPUS, rather than 3*NCPUS. The + two extras are to allow for some processes to be blocked on + network IO, but allowing more than two of them is probably not + useful on multiprocessor machines. + + * Larger files are sent and received using memory mappings where + possible. + + * Use of mmap and compression makes distcc substantially faster in + at least some cases. + + + DOCUMENTATION: + + * Convert the documentation to a series of regular Unix manpages + for easier reference and so they can be used more easily on + diverse platforms. The Linuxdoc-SGML manual has been removed + from the distribution. Thanks to Tim Potter for review + suggestions. + + + TESTING: + + * Add tests for new -o and -Wa,-al handling. + + + +distcc-2.8 "Play in the traffic" 2003-07-09 + + FEATURES: + + * Small enhancements to GNOME monitor appearance. + + + BUG FIXES: + + * Fix problem with nonblocking IO for SSH connections that causes + a busy spin. SSH connections are now far more efficient. + Reported by Marcelo Matus. + + * distccmon-text flushes output after each line, even if stdout is + not a terminal. This allows it to more easily be run in polling + mode under another program. Suggestion from Hamish Rodda. + + * distccd now works properly with SSH servers that use pipes + rather than socketpairs to run the daemon. Previously it would + fail with an error when trying to write to stdin. Suggestion + from Felix Lee. + + * Correctly handle invocations like "gcc -ofoo.o -c foo.c", where + the output filename is run on to the -o option. Based on a + patch from Tsutomu Yasuda. + + + INTERNAL: + + * mon.h is now safe for inclusion in C++ programs, and protected + against multiple inclusion. Suggestion from Frédérick Forjan. + + * Increased timeout for nonblocking network IO apart from + connections to 5 minutes. + + + PORTABILITY: + + * Detect and avoid Apple gcc cpp-precomp brokenness. Patch from + Matt Watson. + + * Better handling of builds on machines which do not have the + linuxdoc-sgml toolchain. Suggestion from Frerich Raabe. + + + DOCUMENTATION: + + * Include an example xinetd configuration file from Andrew Morton. + + +distcc-2.7.1 "Expedition" 2003-06-25 + + PORTABILITY: + + * distccmon-gnome now depends only on GTK+ 2.0, not on the GNOME + libraries. + + * Fix for compilation of the GNOME monitor on BSD. + + * Fix for compilation of the monitor on Cygwin. + + +distcc-2.7 "The Hard Way" 2003-06-16 + + FEATURES: + + * Graphical compile monitor for GNOME 2.x. Configure with + --enable-gnome to build it. + + + PORTABILITY: + + * Possible fix for compilation on HP-UX. + + + INTERNAL: + + * Sanity check GNOME libraries during configuration if + --enable-gnome was specified. + + +distcc-2.6 "The Watcher in the Water" 2003-06-12 + + FEATURES: + + * New program distccmon-text shows the state of any distcc + processes run by the current user. It can be run by hand or + read by a shell script. Should be popular with vmstat fans. + + * New environment variable $UNCACHED_ERR_FD allows client errors + to be redirected from stderr to another file descriptor, so that + distcc errors are not cached by ccache. This is an improvment + because (almost?) all distcc messages are transient things such + as failure to connect to a remote host, and it is confusing to + have them cached. + + (This needs a corresponding patch to ccache to set this, or for + it to be assigned to a duplicate of stderr before invoking + cccache.) + + * In compilation log message, just show the basename of the file + to make it more compact. + + + BUG FIXES: + + * If an compiler cannot be executed then try searching the path + for the basename of the compiler. This can fix cases where the + compiler is invoked with an absolute name but it is in a + different directory on the server. Patch from Paul Russell. + + + PORTABILITY: + + * Fix build on platforms that don't have hstrerror(), such as + Solaris 2.6. + + * Handle sysconf(_SC_NPROCESSORS_ONLN) returning 0 processors, + which has been observed on ARM Linux and previously threw + distccd into a spin. Patch from Sean MacLennan. + + + INTERNAL: + + * New mon.c interface for writing compilation monitors. + + * State directory name includes hostname for robustness when the + temporary directory is shared. + + * Client writes out notes about its state to files that can be + watched by external monitor programs. + + * Partial GNOME-based monitor interface, built when distcc is + configured with --enable-gnome. + + + TESTING + + * Fix silly typo that made maintainer-check give a false failure + in ParseHostSpec_Case. + + +distcc-2.5.1 "disable extra paranoia" 2003-06-05 + + FEATURES: + + * Fifteen second timeout on connection attempts. Hosts that are + unreachable in this time are blacklisted for another minute. + + + BUG FIXES: + + * Fix setpgid() failure when started directly from init(8). + Reported by George Garvey. + + * Correct parsing of old-style TCP multiplier specification + (e.g. "phathost/10:3600"). Patch from Wayne Davison. + + + PORTABILITY: + + * Fix socklen_t compilation problem on Darwin. + + * Fix compilation problems on Solaris 8. Report from Tomas Ögren. + + * Fix compilation problems on IRIX. (IRIX cannot accept a + variable named "sa_len".) Report from Peter Naulls. + + * Fix compilation on SuSE Linux 7.1 for Alpha. + + + DOCUMENTATION: + + * Add more details about starting distccd to the user manual. + + + TESTING: + + * Add test for correct parsing of old-style TCP multiplier + specification (e.g. "phathost/10:3600"). + + +distcc-2.5 "give them heaps" 2003-05-27 + + FEATURES: + + * The standalone daemon now "preforks" before accepting + connections to reduce per-request overhead. Can be disabled by + --no-prefork, which restores the standard Unix behaviour. + + * Restrict the number of jobs accepted onto the server at any + time. By default this is determined automatically depending on + the number of CPUs on the server, but it can be set using the + --jobs, -j option. Replaces never-used --concurrent, -n + option. + + * When the daemon is terminated, the entire process group is shut + down, including any compilations in progress. + + * Load limits on TCP hosts can now be specified in the more + consistent form of "HOST:PORT/MUL" rather than "HOST/MUL:PORT". + The old form is still supported. + + * Better error message for "bind failed". + + * Better "listening on" message at startup. + + * More meaningful reporting of transmission and compilation times + in logs. + + + BUG FIXES: + + * Fix bug that caused some messages to go to the 'user' syslog + facility rather than 'daemon' as presently. + + * Fix problem with terminating the daemon when running under + Valgrind. + + + INTERNAL: + + * Refactor daemon loop. + + * Server-side temporary object files are called .o, not .out. + Suggestion from rishikesh shetty. + + * Temporary directory name changed to decimal userid, rather than + hexadecimal userid. Easier to recognize. + + * Daemon changes into state directory at startup. + + * SSH child is collected and checked when the connection is + closed. + + +distcc-2.4.2 "hard and fast" 2003-05-23 + + BUG FIXES: + + * Fix compilation directed to /dev/null by handling output files + the same way as the GNU BFD library. Reported by Hal Duston. + + * Better error messages if DISTCC_HOSTS or host files are empty. + Patch from Wayne Davison. + + * Fix string allocation bug in dcc_sockaddr_to_ip that could cause + a server crash. + + +distcc-2.4.1 2003-05-22 + + PORTABILITY: + + * Add strndup() for non-GNU platforms. Patch from Frerich Raabe. + + +distcc-2.4 "sparky will reign" 2003-05-21 + + FEATURES: + + * Preliminary support for distribution of Objective C and + Objective C++ compilation. Based on a patch from Dara Hazeghi. + + * If remote compilation fails, give a visible error. People might + want to know, particularly if something is failing on one + particular machine. + + * Error messages report host definitions more consistently, rather + than just hostnames. + + * Better handling of attempts to run more concurrent compilations + than there are available slots. distcc now sleeps for a few + seconds to avoid thrashing the client machine. + + * Unavailable servers are now shunned for 60 seconds so as to + avoid wasting time connecting to machines that are down, not + running distccd, etc. (However hosts that are simply not + responding (e.g. firewalled) are not handled perfectly yet.) + + + BUG FIXES: + + * If an IO error occurs while trying to get a lock, bail out rather + than getting stuck. + + * Don't use the RFC2553 getaddrinfo/getnameinfo API by default, + because it seems to be slower on OS X and possibly problematic + on other systems. It can be enabled with --enable-rfc2553 if + you want to use IPv6, multi-homed servers, or want to test the + new API. + + + PORTABILITY: + + * Preliminary STRATUS VOS portability work from Paul Green. + + + DOCUMENTATION: + + * More description of execution over SSH. + + + +distcc-2.3 "come down like a ton of bricks" 2003-05-16 + + FEATURES: + + * Respond more gracefully to protocol derailments. In particular, + banner messages sometimes seem to get into the stream when + distcc is run from inetd, and they were previously a bit hard to + diagnose. This won't fix the configuration problem that causes + them, but it should make the problem obvious. + + * The client now tries all addresses for each server, in the order + returned by the resolver. + + * Client and server now use IPv6 if requested, where this is + supported by the system. The server still binds to an IPv4 + address by default, but this can be set by the --listen option. + Client access control is not supported yet for IPv6. + + + BUG FIXES: + + * Fix possible bug in loading host list files. + + * Startup errors are now reported to stderr, unless that is a + socket in which case they are sent to syslog. This should be a + better tradeoff between making errors obvious and the + requirements of inetd mode. + + + DOCUMENTATION: + + * Add description of --listen to manual, plus other improvements. + Patch from Frerich Raabe. + + * Various clarifications to the manual. + + * Add documentation of DISTCC_FALLBACK, DISTCC_SSH, execution over + SSH, and host list files. + + + PORTABILITY: + + * Two Mac OS X fixes from Benjamin Reed: Use the BSD method to + discover the number of CPUs, and include types.h where it is + needed. + + * Improved portability of snprintf fallback implementation. Now + works again on dietlibc/Linux. Some fixes merged from Samba + HEAD. + + +distcc-2.2 "nosurname" 2003-05-05 + + FEATURES: + + * If $DISTCC_HOSTS is not set, the host list is taken from from + ~/.distcc/hosts, if that exists, or otherwise + ${sysconfdir}/distcc/hosts. (The location of this last one is + set by the configure option --sysconfdir. It defaults to + /usr/local/etc.) + + * Add --listen option to distccd, to control which IP address is + used to listen for connections. May be useful for access + control on dual-homed machines. Based on a patch by Neil + Mansilla. + + + DOCUMENTATION: + + * Add documentation for --allow and --user, by Frerich Raabe. + + + TESTING: + + * Add test case for host list file. + + * Try to prevent server messages getting into syslog during + testing. + + +distcc-2.1 "Don't mind if I do!" 2003-05-03 + + FEATURES: + + * Support for execution over ssh! + + Hosts to be contacted over SSH should be specified as '@HOST' or + 'USER@HOST'. distccd must be installed on the volunteer host, but it + need not be running and there is no need to set up ssh tunnels. + + Compilations run under the user's account, and connections are securely + authenticated and encrypted. + + SSH is substantially slower than plain TCP connections, but they can + still be faster than local compilation. + + + * The search path is examined in both the client and server, and + directories containing distcc (and ccache, where appropriate) masquerade + hooks are removed. This should help prevent distcc accidentally + invoking itself recursively on either client or server. Patch from + Wayne Davison. + + + BUG FIXES: + + * Fix up warning about pid file being removed twice. + + * Better error handling when corks are not supported on a particular + system or socket. + + * Fix incorrect display of CPU usage statistics in server log and client. + + * Change behaviour of distccd for log messages encountered during startup, + before options are parsed. These are now written to stderr only if that + is a tty, and otherwise to syslog. This is intended to prevent log + messages from distccd getting mixed into the network protocol when it is + run from inetd. + + * Correctly trap unexpected end of input when copying a file using + read/write. + + * Test harnesses may need snprintf.o linked in as well. Reported by Joe + Meslovich as broken on Solaris. + + + TESTING: + + * Add test that --allow does in fact deny connections as it should. + + * Add tests for parsing of --allow options. + + * Add DISTCC_FALLBACK environment variable. If set to 0, means that + failure to distribute will be considered an overall failure. By + default, a networking error means that compilation will be retried + locally. + + + INTERNALS: + + * Many cleanups of error handling code. + + * Trace distcc version at startup to help with bug reporting. + + * Update IO code to handle nonblocking sockets, because we (may?) need to + use nonblocking socketpairs to talk to SSH. + + + +distcc-2.0.1 "colorful savings on all your favorite medications" 2003-03-28 + + BUG FIXES: + + * Fix comfychair.py library missing from distribution. + + +distcc-2.0 "shoot through like a Bondi tram" 2003-03-28 + + BUG FIXES: + + * Fix small signal handling race that would occasionally cause distccd not + to exit when signalled. Pointed out by Vance Lankhaar. + + * If DISTCC_LOG is an empty string, treat as undefined. + + * If the file specified by DISTCC_LOG can't be opened, then show an + error and use stderr. Previously, error messages were just lost. + + + FEATURES: + + * New "masquerade" mode: distcc can be linked into a directory on the + search path as 'cc'. By Wayne Davison and Martin Pool. + + * Detect number of online processors on the server. At the moment it is + just logged but in the future it might be used to guide scheduling. + Thanks to Dimitri Papadopoulos-Orfanos for describing how to do this on + many operating systems. + + * Log signal name when terminating, on systems with strsignal(). + + + PERFORMANCE: + + * Internal CPU efficiency fixes in logging and RPC code. + + + PORTABILITY: + + * Apparently now builds on IRIX. Reports about whether it works would be + welcome. + + * Fix cast in call to sprintf for platforms where ssize_t != int. Found + on Alpha Linux in the hp Compaq testdrive. + + * Clean up some warnings on IRIX. + + * Fix problem with vsnprintf() declarations on Solaris 8. + + * Cope when in_addr_t and socklen_t are not defined, as is the case on + FreeBSD 3.3. + + * Fix test suite to allow for 'true' and 'false' being in /usr/bin on + BSD. + + + TESTING: + + * Many internal updates to ComfyChair framework. + + * Test suite now works with Python 1.5 or later. + + * Add new undocumented (heh) "--lifetime" option that causes the daemon to + expire after a certain period. + + * Specify limited lifetime when running daemon, so that if it is not + cleaned up by the tests it will go away after a little while anyhow. + + * Use "--allow" to limit connections to localhost when running + daemon for testing. + + * Use randomly chosen TCP port for the server when running tests. This + makes repeated or concurrent invocations of the test less likely to + conflict. + + * On machines without Python, just say "test skipped" rather than failing. + + * Test DISTCC_LOG being set to an unwriteable file. + + + REMOVALS: + + * The GNU Info form of the manual is no longer included in the source + distribution or installed by default. It can be built from SGML if + desired, with "make install-linuxdoc-info". + + +distcc-1.2.3 "stubborn tiny lights" 2003-03-02 + + PORTABILITY: + + * Don't use ':' in lock filenames, because that's a bit too tough for + Windows. This only affects Cygwin clients, not servers. Pointed out by + Heiko Elger. + + * Check existence of ctype.h. Fixes warnings when building popt. Pointed + out by Tom Matelich. + + * Fix "access denied" errors on lock files on HP-UX and Cygwin, so clients + on those platforms should work. Reported by Tom Matelich, Heiko Elger + and others. + + +distcc-1.2.2 "clustering darkness forever" 2003-02-27 + + BUG FIXES: + + * "make distclean" should not remove ./configure. + + + PORTABILITY: + + * Don't assume POSIX-style reentrant file locks, which can't be supported on + Cygwin. + + * Check for inet_aton in libresolv, which might fix Solaris 2.6. + + * Remove some gnudity from the Makefile in an attempt to build with + non-GNU Make. + + * Attempted fix for header files on BSD. + + * Attempted sendfile implementation for HP-UX. + + + TESTING: + + * Add a simple "make distcheck" target to test that the tarball is built + properly. + +distcc-1.2.1 "you know you're right" 2003-02-25 + + BUG FIXES: + + * Better detection of python2.2 during configuration. + + * Allow installation from CVS on machines that don't have the Linuxdoc tools. + + * Check for autoconf >= 2.53 when configuring. Remove dependencies on + features from later versions of autoconf to allow autogen to run on Red + Hat Linux 7.2 systems. + + + TESTING: + + * Add "make installcheck" target. + + * "make check" now fails if any of the tests fail to run. + + * distcc is now built on the build.samba.org build farm. Please contribute + machines if you want your platform to be properly supported. + + + PORTABILITY: + + * Remove libiberty, and use Samba's asprintf() implementation instead. Yay + copy and paste. This should fix problems with asprintf and ansidecls.h on + Solaris, BSD, and Cygwin. + + +distcc-1.2 "lizard drinking" 2003-02-22 + + FEATURES: + + * New scheduler makes a better attempt at keeping remote machines solidly + loaded by allowing only one request at a time to be in transit to remote + machines, therefore letting the actual compiler start sooner. Gives + about a 10% improvement in some circumstances. The new algorithm should + also be a better foundation for adding compression or server-side load + limiting. + + * New --allow option for distccd allows IP-based access control in either + inetd or standalone daemon modes. + + * Locking mechanism now distinguishes between daemons on different ports + of the same machine for the purposes of load balancing. + + * Print timing and estimated rate on bulk data transfers. + + * Open binary files in O_BINARY mode on Cygwin. May fix some corruption + problems on this platform. More investigation would be appreciated. + Based on a patch by Helind. + + + PORTABILITY: + + * Use putenv() rather than setenv() to fit into SUSv2 and work on Solaris + 8. Pointed out by Dimitri Papadopoulos. + + * Add some functions from libiberty to aid portability. + + +distcc-1.1 "balls to the wall" 2003-01-28 + + BUGS: + + * Flag platforms that have a sendfile() function, but that aren't + explicitly supported, because it seems to vary substantially. At the + moment only FreeBSD and Linux are known. + + * Fix configure test for hstrerror(). Patch from Frerich Raabe. + + * Check for inadvertent recursion, where distcc calls itself as the + compiler. Causes an exit with value 111. + + * Don't log client hostname, only the IP address. It's not really + necessary and can slow us down. + + * If run by root, discard privileges rather than flagging an error. The + persona to assume is set by the --user option and defaults to "distcc". + The user "nobody" or uid 65534 is used as a fallback if the named user + is not found. + + + BENCHMARK: + + * Allow for running benchmarks repeatedly, printing the mean and standard + deviation of run time. + + * Projects may now be selected by an unambiguous prefix of their name, so + you can just say "benchmark hello" rather than "benchmark hello-2.1.1". + + * Print better explanatory messages while the benchmark is running. + + + TESTING: + + * Update some tests to work with changed behaviour of gcc 3.2 as well as + 2.95. + + + DOCUMENTATION: + + * Many updates to distcc User Manual. + + * Comply with GNU Standards by keeping all messages in the NEWS file, not + just those for the current release. + + +distcc-1.0 "consider the oyster" 2003-01-16 + + BUG FIXES: + + * Fix sendfile() bug on FreeBSD that could cause files to be + mistransmitted. Perhaps not manifest on x86? Reported by Kris + Kennaway. + + + PACKAGING: + + * Distribute as .tar.bz2 rather than .tar.gz. (We pay by the byte.) + + + DOCUMENTATION: + + * The recommended convention for gcc names is <target>-gcc-<version>, and + GCC 3.3 will install itself under this name. (Alexandre Oliva, Claes + Wallin) + + + BENCHMARK: + + * New macro-benchmark and test suite for distcc. Invoke it with "make + benchmark." It takes a long time to run and causes a lot of source code + to be downloaded, but should be self-contained. + + This is the start of a script that runs distcc to build various open + source programs, as an overall test of correctness, and to measure + performance of a distcc installation. It relies on the user to install + and configure distcc servers and clients, but handles the work of + downloading, preparing, and building packages by itself. + + There are still some rough edges on the script, but it may be of + interest. + + * Add control over which phases of the benchmark are run. + + * Add ability to run tests repeatedly and report mean and standard + deviation. + + + REMOVALS: + + * Remove Plucker file: nobody seems to be downloading it, and it's + easy enough for people to build if they're interested. + + * Remove PDF and Postscript from documentation in tarball. They are still + available from the web site or may be built from source. + +distcc-0.15 "petrified forest" 2002-12-12 + + INCOMPATIBILITIES: + + * Change default port from 4200 to IANA-assigned standard for distcc + service "3632". Compatibility with old installations can be retained by + explicitly setting --port=4200 on the server, or using "HOST:PORT" on + the client. + + * Fake-root directory for "make install" is now set by DESTDIR, not + TARGET_ROOT. (Alexandre Oliva.) + + + BUG FIXES: + + * Run the preprocessor with output sent to stdout and redirected to a + file, rather than by using the -o option. This should fix some + compilers that can't handle "-E -o". It may improve gcc behaviour with + -MD, but because gcc behaviour has changed over time it may not be a + complete fix. + + For gcc 3.2 it is recommended that -MF be used to explicitly set the + dependency output filename. + + + TESTING: + + * Add test case for transmission of a zero-byte file. + + * Add badly-behaved compiler drop-in for use in testing. + + + PORTABILITY: + + * Use the correct autoconf macros to detect whether install(1) is + available and working, and if not, fall back to using the included + install-sh script. This should fix "make install" on Solaris. (Mike + Santy) + + * Fix waitpid() takes three options. Required for Irix. (Michael Santy) + + * Fix autoconf detection of resolv.h on Solaris. (Dimitri Papadopoulos) + + + DOCUMENTATION: + + * Describe information to include in a bug report. + + * Remove "Results" chapter from manual: there are now many more detailed + results on the web site, and this information is better suited to + storage there, because it will be updated on a different cycle. + End-users don't really need to have it in their reference. + + * Remove "MOC Compatibility" section from manual because at the moment + there is nothing to say. + + * Add a new section about the complexities of gcc -MD. + + * Remove "Bugs" section from the manual, and put it into a new TOOD file + instead. Keep information about reporting bugs and using the test + suite, but put it in a different section. + + +distcc-0.14 "no agonizing hanging weights" 2002-11-13 + + BUG FIXES: + + * Take lock on localhost only when compiling locally, not for all + compilations. This removes the accidental limit of only 4 overall jobs. + (Martin Pool) + + * Fix Makefile bug that caused HTML documentation to be missing from the + distribution tarball. (Frerich Raabe, Martin Pool) + + * Make PreprocessPlainText_Case run in appropriate subdirectory. (Martin + Pool) + + + PORTABILITY: + + * Test for wait4 and wait3, which are missing on IRIX. (Mike Santy, + Martin Pool) + + + DOCUMENTATION: + + * Include example init.d script. (Jason Thomas) + +distcc-0.13 "Armistice" 2002-11-11 + + FEATURES: + + * New --no-detach option to cause the server not to detach from its + parent. It still forks normally when a connection is accepted. This + may be useful with daemontools or other frameworks that prefer the + daemon not to detach. (Martin Pool) + + * Log messages on the server of severity "warning" or higher are captured + and sent back to the client. (Martin Pool) + + * If the local preprocessor fails, do not re-run the job locally because + it would presumably fail in the same way. (Martin Pool) + + * By default, the client only sends "warning" or higher messages to + stderr, so that nothing extra is logged unless there is possibly a + failure in distcc itself. With a DISTCC_LOG file, "notices" and higher + are logged. (Martin Pool) + + * Better messages when a compiler exits or crashes. (Martin Pool) + + * If the compiler because of a signal, return 128+SIGNAL, per Unix + convention. (Martin Pool) + + * Compilers and preprocessors are now run in their own process groups, and + terminated if the daemon is killed. (Martin Pool) + + * When the daemon parent is terminated, it does not kill all its children. + Instead, they're allowed to finish whatever they're working on, and then + exit. This allows for more graceful shutdown. (Martin Pool) + + * More specific exit codes for some error cases. Don't panic. (Martin + Pool) + + * Include popt library and --with-included-popt configure option to aid + installation on systems that don't have it. By default it is statically + linked in only if the build machine does not have a suitable library and + header. (Martin Pool) + + + REMOVALS: + + * Remove support for feeding the compiler from a fifo. The gain from + using fifos does not seem to justify the maintenance burden. (Martin Pool) + + - This makes the behaviour more consistent, because some platforms + (Cygwin) or filesystems (NFS, strangely) can't use fifos. It removes + a code path and a slightly complex autodetection. + + - Using fifos makes some potential scheduling improvements hard: the + server can't make good decisions about how many tasks to run, because + each one will only use a fraction of the CPU. The client cannot + serialize file transmission, which would probably be desirable. + + - Using fifos makes reliably handling compiler failures slightly + harder: the compiler may crash or exit at any time, which will in + turn cause the server to hang if it later tries to open or write to + the fifo. In previous versions, distcc tried to handle this by + catching SIGCHLD when the child terminated, and aborting the + operation, but I am not sure that the method is completely reliable. + + + BUG FIXES: + + * Detached daemon now ignores hangup signal. (Martin Pool) + + * When the parent is terminated, don't kill its process group. Allow + children to finish in their own time. (Martin Pool) + + * Detect the case where cpp claims to have succeeded, but did not actually + produce any output. (Martin Pool) + + * Do not use atexit() to clean up temporary files, because this can cause + havoc if it's ever called from a child process that forked but failed to + exec. (Martin Pool) + + * Handle "gcc -S foo.c -o -", which ought to write assembly to stdout. + (Alexandre Oliva) + + * Fix bug in handling IO errors (e.g. dropped connection) in the server. + (Martin Pool) + + * If we fail to cork a socket, continue anyhow. (Martin Pool) + + * Make error handling for IO more consistent. (Martin Pool) + + * Follow Unix convention of returning 128+SIGNAL if the compiler exits + with a signal. (Martin Pool) + + + TESTING: + + * Add tests for parsing slot limit from host specification. (Martin Pool) + + * Daemon tests collect dead servers faster, so the tests run a bit + faster. (Martin Pool) + + * Nicer handling of ^C while running tests: print "INTERRUPT" and + terminate the whole test. (Martin Pool) + + * Add new tests for scanning command lines with an implied compiler name. + (Martin Pool) + + * When the parent is terminated, don't kill its process group. Allow + children to finish in their own time. (Martin Pool) + + * Detect the case where cpp claims to have succeeded, but did not actually + produce any output. (Martin Pool) + + * Add test case for #error directive. (Martin Pool) + + * Add test case for preprocessing non-C text, as is done by (for example) + xrdb. (Martin Pool) + + * Add test case for invocations like "distcc -c test1.c test2.c". (Martin Pool) + + * Add test for handling of a compiler missing from the server. (Martin Pool) + + * Allow distcc's version to be set to something like "0.13cvs-nofifo". + (Martin Pool) + + * Add test for handling of a compiler missing from the server. (Martin + Pool) + + * Improved ComfyChair testing framework. (Tim Potter, Martin Pool) + + + PORTABILITY: + + * Includes example init.d script for SuSE 7.x and 8.0. Not installed by + default. (Brandon Forehand) + + + DOCUMENTATION: + + * Document use with Gentoo Linux. (Dean Bailey, Ernesto, Martin Pool) + + + INTERNAL: + + * Get rid of recursive Make and fix various small Makefile bugs. (Martin + Pool) + + * Add $(TARGET_ROOT) variable for "make install", for use in building + binary packages. (Martin Pool, Nick Moffitt) + + * wait4() on Solaris can't handle a pid of -1, which means "any child" on + Linux and BSD. Use pid of 0 instead to collect any children from the + same process group. (Kevin Bailey) + + * Client does not abruptly drop network connection on compiler failure but + rather reads the 0-byte object file token. (Martin Pool) + + * Rework logger library to allow multiple logger callbacks to be active at + once. This is used for the server, which can write to its own log files + and also send a copy of messages to a buffer to be sent to the client. + (Martin Pool) + +distcc-0.12 "Klein, kosten- und schnörkellos" 2002-10-07 + + BUG FIXES: + + * Handle "gcc -S foo.c -o -", which ought to write assembly to stdout. + (Alexandre Oliva) + + PORTABILITY: + + * wait4() on Solaris can't handle a pid of -1, which means "any child" on + Linux and BSD. Use pid of 0 instead to collect any children from the + same process group. (Kevin Bailey) + + TESTING: + + * Add tests for "-o -". (Martin Pool) + +distcc-0.11 "Nuclear Bedtime Story" 2002-09-25 + + FEATURES: + + * More helpful message explaining that popt is needed if it is missing at + build time. (Martin Pool) + + * Better stripping of options from remote command lines. (Martin Pool) + + * Handle the new -MM, -MG, -MP, -MF, -MT, -MQ options for gcc 3.x. + (Stephan Kulow, Martin Pool) + + + PERFORMANCE: + + * Whenever a command by either the client or the server, it counts towards + the load on that machine. This covers undistributed commands, cpp, and + compilation. This should avoid the bias in earlier versions towards + overloading the client. (Martin Pool) + + + BUG FIXES: + + * IO errors should not cause the process to terminate straight away, + because they are properly handled and we may have important cleanup to + do. (Martin Pool) + + * Fix error handling in code for executing compilers. (Martin Pool) + + * Fix leakage of file descriptors when trying to acquire a lock. (Martin + Pool) + + * Do not object to running as group 0, because on BSD this is "wheel" and + many non-privileged users are in it. (Frerich Raabe, Martin Pool) + + * Fix (non-exploitable) buffer overrun bug. (Dave Zarzycki) + + + PORTABILITY: + + * Fixes to build on Linux libc5. (Richard Zidlicky, Martin Pool) + + + TESTING: + + * Keep $TMPDIR separate for each test case. (Martin Pool) + + * testdistcc.py now optionally takes arguments saying which tests to run. + (Martin Pool) + + * Test permissions on output files are correct. (Martin Pool) + + * Add more test cases for implicit compiler name handling. Extend + h_scanargs to exercise this. (Martin Pool) + + * More tests for argument stripping. (Martin Pool) + +distcc-0.10 "shiny fast red thing" 2002-09-12 + + FEATURES: + + * Allow distcc to be directly used with the same syntax as a compiler: + "distcc -c hello.c". At the moment, always calls "cc". (Martin Pool) + + * If distribution fails, show the name of the server that we were trying + to use. (Martin Pool) + + * Strip -D, -I, -L, -M* options before passing the command line across the + network, for clarity (and perhaps a tiny performance improvement.) + Also, this allows new clients which support -MD to be used with old + servers that can't handle it. (Martin Pool) + + + BUG FIXES: + + * Correctly handle "gcc -c -S hello.c", which should only assemble, not + compile. (Alexandre Oliva) + + * If the volunteer compiler exits without reading all of its input, return + the compiler's own exit code across the network, rather than + EXIT_DISTCC_FAILED. (Martin Pool) + + * Attempt to fix a race where the compiler process could exit without + opening its input before we started writing to the FIFO. In that case, + the daemon would hang forever waiting for the compiler to arrive. In + the new code, SIGCHLD causes a longjmp to break out of trying to feed + the compiler. (Martin Pool) + + * If .o file is 0 bytes or not created on the server, do not create it on + the client either. (Martin Pool) + + * Fix bug that caused compilation to fail if an old compiler output file + existed. (Martin Pool) + + * Try to make sure to uncork client socket before closing if cpp fails, to + work around Linux 2.2 bug that causes the socket to jam in FIN_WAIT1. + See <http://marc.theaimsgroup.com/?l=linux-netdev&r=1&b=200209&w=2>. + (Martin Pool) + + * Invocations of gcc that use -MD or -MMD can be distributed, although -M + cannot be. Both client and server must be updated to make this work. + (Martin Pool) + + * It turns out that .s and .S files in fact cannot be assembled remotely, + because they might use the gas '.include' pseudo op, which is resolved + by the assembler and would end up reading something from the volunteer's + disk. (Richard Zidlicky, Martin Pool) + + + PORTABILITY: + + * Solaris portability fixes. (Dimitri PAPADOPOULOS-ORFANOS) + + + TESTS: + + * Test handling of -c and -S. (Martin Pool) + + * Test handling of a file that causes a preprocessor error. (Martin Pool) + + * Test compiler that succeeds without reading input. (Martin Pool) + + * Test many simple compilations, in case there is an infrequent error. + (Martin Pool) + + * Test many concurrent compilations. (Martin Pool) + + * Test using -D on the compiler command line. (Martin Pool) + + * Tests for .s and .S files. (Martin Pool) + +distcc-0.9 "samui desu ne?" 2002-09-03 + + FEATURES: + + * Add new environment variable for client and server, DISTCC_TCP_CORK. + Defaults to on, intended mostly for performance comparison or + debugging. (Martin Pool) + + PORTABILITY: + + * Properly support platforms with 32-bit pids, such as Cygwin. (Aaron + Lehmann, Martin Pool) + + * On FreeBSD, the sa_family_t type is defined in <sys/socket.h> (Dennis + Taylor) + + BUG FIXES: + + * Fix bugs related to leftover fifos in the temporary directory causing + occasional server hangs. (Martin Pool) + + * Stop the compiler from inheriting file descriptors connected to the + network. This was causing the client to hang if the server abnormally + terminated while the compiler was reading from a fifo. (Martin Pool) + + * Handle the case of sendfile() transmitting only part of the supplied + data, similarly to a short write on a socket. This doesn't often + happen, but can occur if a ptrace debugger attaches while sendfile is + running. (Martin Pool) + + * When run with --daemon and not --no-fork, the parent does not detach + until the pid file has been created. This removes a slight race window + that sometimes confused the test scripts. (Martin Pool) + + * Message for completion of local cpp now gives the correct hostname. + (Martin Pool) + + * Do not try to collect daemon children if --no-fork was specified. + (Martin Pool) + + * Set SIGPIPE handler back to default before starting compiler tasks. + (Martin Pool) + + * If a network error is detected while feeding input to the compiler, then + it is terminated with a SIGHUP. (Martin Pool) + + * If transmission to the server fails, close the socket sooner rather than + later so as not to make the server process wait around unnecessarily. + (Martin Pool) + + * Better handling of the case where the compiler command exits without + reading its input. (Martin Pool) + + * Make sure compilation children are always properly collected, even if + transmission failed. (Martin Pool) + + PERFORMANCE: + + * Write token/parameters using a single write() call. May be very + slightly more efficient in CPU and perhaps packets. (Martin Pool) + + TESTS: + + * Display test names while they're running so that long tests are easier + to follow. (Martin Pool) + + * When cleaning up after running the dameon, make sure it's really dead + before proceeding, so that tests don't trip over each other. (Martin + Pool) + + * New test of compilation of a largish (~4MB) C file to a ~5MB object + file. (Martin Pool) + +distcc-0.8 "cat and girl" 2002-08-15 + + FEATURES: + + * If for any reason a job can't be distributed, it is run locally rather + than failing. This includes servers which are not running or + unreachable, servers which crash, bad host specifications, etc. (Martin + Pool) + + * --help for distcc explains more about host specifications. (Martin + Pool) + + BUG FIXES: + + * Correctly handle compilation of C++ code under ccache, by properly + recognizing the .ii extension. (Stephen White, Chris Halls) + + * Boolean environment variables (e.g. DISTCC_SAVE_TEMPS, DISTCC_VERBOSE) + are now consistently required to be literally "1" to count as true. + (Martin Pool) + + DOCUMENTATION: + + * Document that $DISTCC_HOSTS can now specify ports. (Martin Pool) + + * Document --no-fifo and --log-stderr. (Martin Pool) + +distcc-0.7 "Pipeline Authority" 2002-08-05 + + FEATURES: + + * Can now either use fifos for feeding the compiler or not. This can be + controlled by --no-fifo to the server. By default, it tries a fifo and + falls back to using regular temporarily files if that fails, as it will + on Cygwin or an NFS-mounted /tmp. (Martin Pool) + + * --log-stderr option, intended mainly for debugging or testing. (Martin + Pool) + + * DISTCC_HOSTS can now specify non-default port numbers using "host:port" + syntax. (Martin Pool) + + DOCUMENTATION: + + * Built documentation (HTML, PS, PDF, Info) is now shipped in the + distributed tarball, so that you can more easily install it on a machine + lacking the Linuxdoc SGML tools. You still need them to modify and + rebuild the documentation, of course. (Martin Pool) + + BUG FIXES: + + * Log pid even if running with --no-fork. Remove pid file on exit. + (Martin Pool) + + PORTABILITY: + + * Try fcntl locks in addition to lockf and flock; apparently this helps + portability to Cygwin. (Martin Pool, Marco Alanen) + + * Port to Cygwin. (Martin Pool, Marco Alanen) + + * Partial port to Solaris. (Dimitri PAPADOPOULOS-ORFANOS, Martin Pool) + + TESTABILITY: + + * Further internal improvements to test suite. (Martin Pool) + + * Test suite should now run whether or not there is a daemon listening on + localhost, because it uses a non-standard port for testing. (Martin + Pool) + +distcc-0.6 "reptilian agenda" (12 July 2002) + + FEATURES: + + * Daemon now refuses to run as root, because this is just too ridiculously + insecure. (Martin Pool) + + * Output shows CPU time taken by distcc and programs that it runs. (Martin + Pool) + + * distcc will now distribute jobs which use -s to compile but not assemble. + Previously they were always run locally, but there's no strong reason why + they must be. Unfortunately you need to upgrade both the client and + server for this to work, because old servers will refuse to run gcc with + -s. (Martin Pool) + + BUG FIXES: + + * -M<anything> option implies that cpp must be run locally, because it will + want to write dependency information to a file. (Martin Pool) + + * Add --daemon and --inetd options, so that you can properly start a remote + daemon with a single-line ssh command. (Martin Pool) + + * Fix bugs related to collecting child processes. (Probably not very + user-visible.) (Martin Pool) + + * Fixed some Makefile-related bugs causing "make install" breakage and + similar things. (Martin Pool) + + * If the system supports sendfile, but the particular filesystem we're on + (e.g. tmpfs) doesn't, then fall back to using read/write. (Eivind Magnus + Hvidevold, Martin Pool) + + * Change to argument analyzer to placate Valgrind. Possibly this was a + memory corruption bug, but I can't see it. I think Valgrind was just too + picky. (Martin Pool) + + PORTABILITY: + + * Build on FreeBSD, though you do need GNU make. (Lauri Watts, Martin + Pool) + + DOCUMENTATION: + + * Better description of how to do cross-compilation. (Martin Pool) + + TESTING: + + * Improved Python test suite. (Martin Pool) + + INTERNAL CHANGES: + + * Get rid of automake; just use plain autoconf 2.53. (Martin Pool) + + * If $DISTCC_SAVE_TEMPS is set to "1", then files are not actually deleted + -- good for debugging. (Martin Pool) + +distcc-0.5 "Unacceptable Behaviour" (27 June 2002) + + FEATURES: + + * Use more specific return codes when the remote compiler fails: + EXIT_COMPILER_CRASHED for a signal, or the return code from the + compiler if it exited non-0. + + FIXES: + + * Fix bug in h_hosts that caused us to write off the end of the + real argv[], rather than a copy. Thanks to Julian Seward. + (Martin Pool) + + PORTABILITY: + + * Cope on compilers without varargs macros. (Petter Reinholdtsen, Martin + Pool) + + * Build on Solaris. (Petter Reinholdtsen, Martin Pool) + + * FreeBSD fixes. (Claes Wallin, Frerich Raabe, Michael + Nottebrock, Martin Pool) + + DOCUMENTATION: + + * Manpages are correctly distributed and installed. (Petter Reinholdtsen) + + TESTING: + + * Test suite now runs a server on localhost and tests against it, + and shuts it down on completion. (Martin Pool) + + * More test cases. (Martin Pool) + +distcc-0.4 "Wisdom Like Silence" (9 June 2002) + + ENHANCEMENTS: + + * Assembly and assembly-with-preprocessor files can now be + assembled remotely. (Martin Pool) + + * Client now emits no messages unless there is a warning or error, + or $DISTCC_VERBOSE is specified. This improves operation with + ccache. (Martin Pool) + + * Client and server both respect $TMPDIR if set. (Martin Pool) + + * Standalone server puts itself in the background and detaches from + controlling tty. (Martin Pool) + + * Server has --port option. Currently useless, since there's no + corresponding option on the client. (Martin Pool) + + * Server has --pid-file option. (Martin Pool) + + * Server now allows multiple concurrent compile tasks, forking per + connection. (Martin Pool) + + BUG FIXES: + + * gcc invocations with -fprofile-arcs or -ftest-coverage that + would emit coverage information to a local file are always run + locally. (Martin Pool) + + * Handle lines like "gcc -c -c hello.c". (Martin Pool) + + DOCUMENTATION: + + * Various enhancements to the user manual. (Martin Pool) + + INTERNAL: + + * Add a partial test suite based on PyUnit. Python 2 is now + required to run the test suite, though not to just build or run + distcc. (Martin Pool) + +distcc-0.3 "The Anticipation of a New Lover's Arrival" (28 May 2002) + + ENHANCEMENTS: + + * Support C++ compilation (including with ccache) by correctly + detecting prefixes. (Ian Reinhart Geiser, Martin Pool) + + * Use a FIFO to feed preprocessed source from the daemon into the + compiler, so that compilation can be overlapped with network + transit. (Martin Pool) + + + BUG FIXES: + + * Only fiddle with the compiler's stdin/out/err when running on + the server, not on the client. This should make cpp from stdin + work. (Reported by Ian Reinhart Geiser from KDE) (Martin Pool) + + * Prevent server crashing on aborted connectiong by using EPIPE + rather than SIGPIPE in daemon as well as client. (Martin Pool, + Ben Elliston.) + + + PORTABILITY: + + * Builds on GNU/Linux, FreeBSD, and others if you're lucky. + (Martin Pool, Frerich Raabe, Luke Gorrie) + + + INTERNAL: + + * Convert to using GNU automake and autoconf, so that distcc can + better handle portability, distribution and testing. (Martin + Pool, Frerich Raabe, Ian Reinhart Geiser) + + * Start adding some "make check" tests. (Martin Pool) + +distcc-0.2 (17 May 2002) + + ENHANCEMENTS: + + * First public release + + * Correctly and usefully builds various large programs + +Local variables: +mode: indented-text +indented-tabs-mode: nil +coding: utf-8 +End: diff --git a/distcc/README b/distcc/README new file mode 100644 index 0000000..e8ed7ee --- /dev/null +++ b/distcc/README @@ -0,0 +1,39 @@ + + distcc -- a free distributed C/C++ compiler system + + http://distcc.samba.org/ + + by Martin Pool <mbp@samba.org> + + +distcc is a program to distribute compilation of C or C++ code across +several machines on a network. distcc should always generate the same +results as a local compile, is simple to install and use, and is often +two or more times faster than a local compile. + +Unlike other distributed build systems, distcc does not require all +machines to share a filesystem, have synchronized clocks, or to have +the same libraries or header files installed. Machines can be running +different operating systems, as long as they have compatible binary +formats or cross-compilers. + +distcc sends the complete preprocessed source code across the network +for each job, so all it requires of the volunteer machines is that +they be running the distccd daemon, and that they have an appropriate +compiler installed. + +distcc is not itself a compiler, but rather a front-end to the GNU +C/C++ compiler (gcc), or another compiler of your choice. All the +regular gcc options and features work as normal. + +distcc is designed to be used with GNU make's parallel-build feature +(-j). Shipping files across the network takes time, but few cycles on +the client machine. Any files that can be built remotely are +essentially "for free" in terms of client CPU. + +distcc is now reasonably stable and can successfully compile the Linux kernel, +rsync, KDE, GNOME (via GARNOME), Samba and Ethereal. distcc is nearly +linearly scalable for small numbers of machines: for a typical case, three +machines are 2.6 times faster than one. + +distcc is distributed under the GNU General Public Licence v2. diff --git a/distcc/README.packaging b/distcc/README.packaging new file mode 100644 index 0000000..1b35ccd --- /dev/null +++ b/distcc/README.packaging @@ -0,0 +1,75 @@ +$Id: README.packaging,v 1.7 2004/02/20 04:11:26 mbp Exp $ -*- indented-text -*- + +Please read this file if you distribute packages of distcc and +consider these requests. + + - If you make available packages or ports for some system, please + send mail to the list so that I can include a link on the web site. + + - If you make change to program, please append to the version number + so that it can be distinguished from the upstream version, e.g. in + bug reports, and document your changes. (For example, change it to + "0.13-foo11" if you modify it for the Fooix distribution.) + + I request this because I have had distributors introduce broken + patches into distcc, and if somebody asks for support I want to + know they're not using the same source. I have seen this happen on + samba and rsync as well and it wastes everybody's time when the two + parties see different programs as "foo-1.2.3". + + In the steady state there ought to be little need for distributors + to patch anything; any reasonably portability fixes will be merged + and if they add new features it deserves a different version. + + - Please install distccd into a directory that is on the default + $PATH. (If sbin is not on the path for all users, please don't put + it there.) This is important to making ssh work without hassle, + and is compliant with the Linux filesystem hierarchy standard + (FHS). + + - distcc uses the standard GNU configure options to set installation + directories. In particular, you may want to change --prefix=/usr, + and --sysconfdir=/etc. In addition you can use $(DESTDIR) when + doing "make install" to install into a virtual root directory. + + - Because the daemon does not authenticate connections, please check + that the administrator understands the consequences before starting + it. Do not start it automatically when the package is installed. + + - If your installation script prompts for parameters, consider asking + for a list of allowed netmasks to pass to the daemon's --allow + option. + + - When installing the daemon, please create a system user called + "distcc" for the use of the daemon. This is better than running + the daemon as "nobody". You can either remove the user or leave it + around if the package is uninstalled, depending on your + distribution's policy. + + - I'd prefer for distributions to arrange for distccd to run as a + standalone daemon (--daemon), not from inetd. It is a bit easier + to support, and in the future there may be optimizations that only + work in standalone mode. + + - If any patches are necessary for portability please forward them to + me so that they can be considered for inclusion upstream. + + - Check that distcc uses shared libraries for popt and other things, + if that makes sense on your system. In particular, make sure + libraries in /usr/local are linked properly. + + - Try to make sure gcc is installed with fully-qualified names to aid + users of distcc. (e.g. 'gcc-3.2', 'i386-linux-gcc-3.2' and + 'i386-redhat-linux-cc-3.2.2'). This makes it much more likely that + people will be able to plug-and-go for cross-architecture or + cross-OS builds. It's good to name even native compilers this way + so that they can participate in heterogenous builds. If you don't + maintain the compiler packages for your OS, please talk to the + person who does. + + - Consider putting this line into /etc/services + +distcc 3632/tcp # distributed compiler + + +Thankyou for your help. diff --git a/distcc/TODO b/distcc/TODO new file mode 100644 index 0000000..0d3b23c --- /dev/null +++ b/distcc/TODO @@ -0,0 +1,1112 @@ +TODO list for distcc + +See also TODO comments in source files and doc/todo/ + + + +convert web site from latte to say php + + Latte is nice, but seems to be gradually becoming unmaintained; + not in Ubuntu or Gentoo. + + +failing to resolve a host should be a soft failure + + + +State files depend on host byte order and break when DISTCC_DIR is +shared between heterogenous machines. Of course sharing this +directory is probably a bad idea anyhow. + + + +error messages get badly interleaved + + Large writes are not always atomic. + + When running parallel compiles that produce many warnings/errors, + the errors can get mixed up, both between lines and within lines. + + Someone suggested writing out through stdio, but I don't see why + that would particularly help. + + This needs to be done even when writing to a file. + + It might be more useful to voluntarily write output one line at a + time so as to increase the chance that each line is written atomically. + + + +hardcode "gcc" not "cc"? + + I don't think distcc works with anything else. So why take the + risk of calling anything else? + + +monitor/state/lock files be on NFS + + What happens if the processes are missing? + + Should we perhaps specially handle files created by a remote + machine, e.g. but the hostname in? + + Handle ESTALE or short EOF. + + http://groups.google.com/groups?selm=netappCJyvKo.MrI%40netcom.com + + + + +if connection fails, reschedule remotely? + + See messages from Heiko + + Perhaps if compilation on one remote machine fails, try another, rather + than falling back to localhost? + + However, we do need to make sure that if all remote possibilities + are eliminated, then we still run locally. + + Perhaps we should more carefully distinguish e.g. "failed to connect", + "server dropped connection", etc etc. + + Backing off from downed machines makes this a little + less unnecessary. + + +auto-check socklen_t mess + + Dmitri says: + +> By the way, about the accept() argument type (int, size_t, or socklen_t) +> issue I had already reported in a previous post, an autoconf macro is +> available after all. See: +> http://www.gnu.org/software/ac-archive/htmldoc/ac_prototype_accept.html +> http://www.gnu.org/software/ac-archive/htmldoc/ac_func_accept_argtypes.html +> It would be better to fix this specific issue, as I think it could break +> 64-bit builds where the type of the argument is actually important. + + + Perhaps it should be int if not defined. See accept(2). + + +some kind of memory leak in gnome monitor? + + +"compiler not found" + + Perhaps distinguish this as a separate error case. We need to + trap the error from exec on the server, pass that back across the + network, and then handle it specially on the client. + + Back off from the machine where it failed and retry locally? + + This would be more useful when we explicitly set compiler versions. + + +scheduler should allow for clock/bus speed + + (Perhaps front-side bus speed is dominant, since compiling won't + fit in cache?) + + Suppose we have one 2GHz and one 1GHz machine. Jobs will take + roughly twice as long to run on the second one; conversely we can + run two jobs on the first one in the time it takes to run one on + the second machine. + + + +gkrellm monitor for distcc + + Ought to work with client-server mode + + Possibly easier than writing everything ourselves + + Show number of running jobs? + + +don't change the path + + Rather than getting into this mess of changing the $PATH, perhaps + we should just check more carefully at the moment that we execute + things? + + One problem with this might be interaction with ccache. If we + have doubly masqueraded distcc:ccache:gcc, then ccache probably + needs to see itself as the first item on the path to be able to + find the right gcc. + + Perhaps we should remove items from the path, rather than trimming + the path? + + It would be good to unify the code in dcc_support_masquerade() + with dcc_trim_path(). + + Perhaps distccd should do path munging when it gets a request + rather than at startup. It's ugly that the daemon's idea of the + correct path may be wrong if files are changed after the daemon is + started. + + +DEPENDENCIES_OUTPUT + + The problem is when the preprocessor and compiler are both run + with this variable set. The compiler appends directions for + compiling from the temporary .i to the temporary .o, which is + unwanted. + + This is a problem for ccache (now fixed), but not a problem for + distcc because we always run the preprocessor and always locally. + The remote compiler doesn't see the variable. + + +multiple cleanup calls at end + + why is this happening? + + +monitor + + There's two things that could be monitored. First is the daemon running + on `this' computer and the client that is sending processes across the + network. + + lisa writes: + + Some things I'd like to see for the daemon: + 1) Uptime + 2) Configuration (port, lzo compression? ssh enabled? etc) + 3) Number of jobs done (and a spread of the types of errors reported) + 4) Average throughput + 5) Current compiling tasks (pid, Src, filesize, filename, time recv'd) + + + For the client (ie, distccmon-gnome replacement): + On a per job basis + For SEND and RECEIVE state: + 1) Current throughput + 2) Type of connection (ssh? port? lzo?) + 3) pid + 4) filename + For (remote) COMPILE state: + 1) The actual pre-processed filename + 2) Type of connection (ssh? port? lzo?) + 3) pid + For (local) LINKING state: + 1) The actual pre-processed filename + 2) pid + 3) Where the object code was compiled + 4) The post-linked filenamed (gcc ... -o [display this]) + For (local) PREPROCESS state: + 1) filename + 2) pid + + A tall order to be sure, and it'd suck to do the GUI... but you asked. + :) + + + +unlink .i file as soon as it has been opened for sending + + Might help with vm performance by hinting to the kernel that it + will be discarded. + + Possibly reduces the chances of temporary files being left behind. + + However, will not work on Windows. + + + +variable to add extra remote cflags, to handle icpc + + + +handle -xc++, etc + + Can be either one or two arguments. + + +handle -Wp,-MF + + Some makefiles seem to generate this. Aarg! + + + +Installation as an SSH subsystem + + Might make use easier on Windows. I don't see any real advantage + on Unix. + + I think the daemon should already be OK for this. It just + requires a slight change in the way we call ssh from the client. + + In fact, if you just wrote a small script that rearranged the + arguments and put that in DISTCC_SSH then everything would + probably be fine already. + + +control through command line + + Handle options like + + --distcc-verbose + --distcc-hosts= + + to allow options to be set on the command line. + + I'm not sure this is a good idea or useful. + + +If we have produced a .i file and need to fall back to running locally +then use that rather than the original source. On the other hand, +falling back to running the original command is possibly more robust. + + * @todo Make absolutely sure that if we fail, the .o file is removed. + * Perhaps it would be better to receive to a temporary file and then + * rename into place? On the other hand, gcc seems to just write + * directly, and if we fail or crash then Make ought to know not to + * use it. + * + * @todo Count the preprocessor, and any compilations run locally, against the + * load of localhost. In doing this, make sure that we cannot deadlock + * against a load limit, by having a case where we need to hold one lock and + * take another to make progress. I don't think there should be any such case + * -- we can release the cpp lock before starting the main compiler. + * + +allow more control over verbosity + + For example, for the client, it would be nice to get just 'info' + level messages about things that can or can't be distributed. + + +split gcc-specific argument parsing into a separate module + + + +boredom + + When there are too many jobs submitted by make, then we have to + wait until any slot is available. Unfortunately there is no + OS-level locking system I can think of that allows us to block + waiting for any one of a number of resources. + + If there are no slots to run, then at the moment we just sleep for + 2s. This is OK, but can leave the processor idle. It would be + better to be woken up by other processes as they exit. One way to + do this would be to listen on a named pipe for notifications. + + This must be backed up by a sleep timer because we may not get the + notification if e.g. the other process is killed. Also it won't + work on Cygwin, which doesn't have named pipes. + + Simply doing a select() on a pipe allows us to block for a while + or until signalled. Simply doing a nonblocking write of one byte + to the pipe ought to allow waking up exactly one of the sleepers. + + Using an OS level semaphore to guard access to slots might work + with some fudging, but there is no good portable implementation of + them so it is moot. + + When woken, the clients can do one full round of trying to get a + slot and then go back to sleep. + + This "guides" the OS scheduler towards keeping (almost) the exact + number of clients activated, without too many of them spinning. + + We can't make the timeout too high, or the client will idle for a + long time waiting for it. But if we make it too low then we have + the thundering herd problem that currently exists... + + Perhaps this is overengineering: people shouldn't make the -j + number so high that this is hit very often, and we need to have + the timeout anyhow, so why not just rely on it. + + Just listening on a pipe is cheaper than checking all the locks. + + + +intel CC + + Does not understand the .ii extension. + + We need to specify -xc++ to make it properly compile C++ from + preprocessed source. + + Is it OK to just get the user to add this? + + Perhaps we could add it always? + + Do we need a DISTCC_ADD_OPTIONS variable? + + +clean up temp files when a client is signalled + + Interrupting a compilation is pretty common. It might be good to + handle this more cleanly. + + We can also remove status files. This would reduce the need for + monitor clients to handle dead state files, which might reduce + problems to do with viewing compilations by another user. + + +globally visible status files + + Perhaps store in a world-writable /var/lib/distcc, so that + they're visible even when TMPDIR or HOME has been reset, as when + building with emerge. + + Another good case to support is compilation from inside a chroot + jail. + + It might also be nice to be able to see other people using your + machine either as a client or as a server. + + This requires passing a trust boundary when publishing information + across accounts. The directory needs to be writable and the + programs need to be robust against other users trying to cause + mischief. + + It's perhaps not great to allow that kind of security issue in a + default installation. Should we really create a mode 777 + directory by default? umask will put some restrictions on what + can be seen. + + Alternatively, have an environment variable that sets the state + location. If people want it globally visible they can set it to a + global location. + + +dnotify in monitor + + This has been implemented, but I pulled it out because I'm not + convinced it is a good idea. + + Signals into GTK seem to cause some trouble when running from + valgrind etc. + + Polling is not too expensive, and is nice and simple. It also + allows easier ways to handle corner cases like cleaning up state + files left over after a compiler is terminated. + + Could set up dnotify on the state directory so that we don't have + to keep polling it. This would slightly reduce our CPU usage when + idle, and might allow for faster updates when busy. + + We still have to scan the whole directory though, so we don't want + to do it too often. + + I'm not sure how to nicely integrate this into GNOME though. + dnotify sends us a signal, which doesn't seem to fit in well with + the GNOME system. Perhaps the dummy pipe trick? Or perhaps we + can jump out of the signal? + + We can't call GTK code from inside. + + state changes are "committed" by renaming the file, so we'd want + to listen for DN_RENAME I think. + + We need to make sure not to get into a loop by reacting to our own + delete events. + + +SSH connection hoarding + + It might be nice to hold open SSH connections to avoid the network + and CPU overhead of opening new ones. + + However, fsh is far too slow, probably because of being written in + Python. + + It's only going to work on systems which can pass file descriptors + and therefore needs to be optional. Probably this only works on + Unix. + + Building the kernel between the three x2000s seems to make + localhost thrash. A few jobs (but not many) get passed out to the + other machines. + + Perhaps for C++ or something with really large files fsh would be + better because the cost of starting Python would be amortized + across more work. + + I don't think this needs to be done in distcc. It can be a + completely separate project to just rewrite fsh into C. Indeed + you could even be compatible with the Python implementation and + just write the short-lived client bit in C. + + +Masquerade + + It might be nice to automatically create the directory and + symlinks. However we don't know what compiler names they'll want + to hook... + + Probably the best that we can do is provide clear instructions for + users or package distributors to set this up. + + +Packaging + + Perhaps build RPMS and .debs? + + Is it easy to build a static (or LSB-compliant?) .rpm on Debian? + + What about an apt repository? + + +Statistics + + Accumulate statistics on how many jobs are built on various machines. + + Want to be able to do something like "watch ccache -s". + + Perhaps just dump files into a status directory where they can be + examined? + + Ignore (or delete) files over ~60s old. This avoids problems with + files hanging around from interrupted compilations. + + +refactor name handling + + Common function that looks at file extensions and returns + information about them + + - what is the preprocessed form of this extension? + - does this need preprocessing? + - is this a source file? + + +check that EINTR is handled in all cases + + +check that all lengths are unsigned 32-bit + + I think this is done, but it's worth checking a bit more. + + +abort when cpp fails + + The same SIGCHLD handling approach used to feed the compiler from + a fifo might be used to abort early if the preprocessor fails. + This will happen reasonably often, whenever there is a problem + with an include, ifdef, comment, etc. + + It might save waiting for a long connection to complete. + + One complication is that we know the compiler ought to consume all + its input but we don't know when cpp ought to finish. So the + sigchld handler will have to check if it failed or not. If it + failed, then abort compilation. If it did not fail, then keep + going with the connection or whatever. + + This is probably not worthwhile at the moment because connections + generally seem faster than waiting for cpp. + + +feed compiler from fifo + + Probably quite desirable, because it allows the compiler to start + work sooner. + + This was originally removed because of some hitches to do with + process termination. I think it can be put back in reliably, but + only if this is fixed. Perhaps we need to write to the compiler + in nonblocking mode? + + Perhaps it would be better to talk to both the compiler and + network in nonblocking mode? It is pretty desirable to pull + information from the network as soon as possible, so that the TCP + windows and buffers can open right up. + + Check CVS to remember what originally went wrong here. + + Events that we need to consider: + + Client forks + + Compiler opens pipe + + Client exits + + Server opens pipe + + There are a few possibilities here: + + Client opens fifo, reads all input, and exits. The normal + success case. + + Client never reads from fifo and just exits. Would happen if + the compiler command line was wrong. + + Client reads from fifo but not the whole thing, and then + exits. + + Opening the fifo is a synchronization point: in blocking mode + neither the compiler or server can proceed past here until the other + one opens it. If the compiler exits, then the server ought to be + broken out of it by a SIGCHLD. But there is a race condition + here: the SIGCHLD might happen just before the open() call. + + We need to either jump out of the signal handler and abort the + compilation, or use a non-blocking open and a dummy pipe to break + the select(). + + If we jump out with longjmp then this makes the code a bit + convoluted. + + Alternatively the signal handler could just do a nonblocking open + on the pipe, which would allow the open to complete, if it had not + already. + + This was last supported in 0.12. That version doesn't handle the + compiler exiting without opening the pipe though. + + +streaming input output + + We could start sending the preprocessed source out before it is + complete. This would require a protocol that allows us to send + little chunks from various streams, followed by an EOF. + + This can certainly be done -- fsh and ssh do it. However, + particularly if we want to allow for streaming more than one thing + at a time, then getting all the timing conditions right to avoid + deadlock caused by bubbles of data in TCP pipes. rsync has had + trouble with this. It's even more hairy when running over ssh. + + So on the whole I am very skeptical about doing this. Even when + refactored into a general 'distexec', this is more about batch + than interactive processing. + + +assemble on client + + May be useful if there is a cross compiler but no cross assembler, + as is supposed to be the case for PPC AIX. See thread by Stuart D + Gathman. Would also allow piping output back to client, if the + protocol was changed to support that. + + +web site + + http://user-mode-linux.sourceforge.net/thanks.html + + +sendfile + + perhaps try sendfile to receive as well, if this works on any platforms. + + +static linking + + cachegrind shows that a large fraction of client runtime is spent in the + dynamic linker, which is kind of a waste. In principle using dietlibc + might reduce the fixed overhead of the client. However, the nsswitch + functions are always dynamically linked: even if we try to produce a + static client it will include dlopen and eventually indirectly get libc, + so it's probably not practical. + + +testing + + How to use Debian's make-kpkg with distcc? Does it work with the + masquerade feature? + + http://moin.conectiva.com.br/files/AptRpm/attachments/apt-0.5.5cnc4.1.tar.bz2 + + +coverage + + Try running with gcov. May require all tests to be run from the same + directory (no chdir) so that the .da files can accumulate properly. + + +slow networks + + Use Linux Traffic Control to simulate compilation across a slow + network. + + +scheduling onto localhost + + Where does local execution fit into the picture? + + Perhaps we could talk to a daemon on localhost to coordinate with + other processes, though that's a bit yucky. + + However the client should use the same information and shared + state as the daemon when deciding whether it can take on another + job. + + At the moment we just use a fixed number of slots, by default 4, + and this seems to work adequately. + + +make "localhost" less magic + + Recognizing this magic string and treating it differently from + 127.0.0.1 or the canonical name of the host is perhaps a bit + strange. People do seem to get it wrong. I can't think of a + better simple solution though. + + +blacklist/lock by IP, not by name + + Means we need reliable addr-to-string for IPv4 and IPv6. + + Any downside to this? + + Would fix Zygo's open Debian bug. + + +DNS multi-A-records + + build.foo.com expands to a list of all IP addresses for building. + + Need to choose an appropriate target that has the right compilers. + + Probably not a good idea. + + If we go to using DNS roundrobin records, or if people have the same + HOSTS set on different machines, then we can't rely on the ordering of + hosts. Perhaps we should always shuffle them? + + ssh is an interesting case because we probably want to open the + connection using the hostname, so that the ssh config's "Host" + sections can have the proper effect. + + Sometimes people use multi A records for machines with several + routeable interfaces. In that case it would be bad to assume the + machine can run multiple jobs, and it is better to let the + resolver work out which address to use. + + +DNS SRV records + + Can only be updated by zone administrator -- unless you have + dynamic DNS, which is quite possible. + + + +better scheduler + + What's the best way to schedule jobs? Multiprocessor machines present + a considerable complication, because we ought to schedule to them even + if they're already busy. + + We don't know how many more jobs will arrive in the future. This + might be the first of many, or it might be the last, or all jobs might + be sequenced in this stage of compilation. + + Generic OS scheduling theory suggests (??) that we should schedule a + job in the place where it is likely to complete fastest. In other + words, we should put it on the fastest CPU that's not currently busy. + + We can't control the overall amount of concurrency -- that's down to + Make. I think all we really want is to keep roughly the same number + of jobs running on each machine. + + I would rather not require all clients to know the capabilities of the + machines they might like to use, but it's probably acceptable. + + We could also take the current load of the CPUs into account, but I'm + not sure if we could get the information back fast enough for it to + make a difference. + + Note that loadavg on Linux includes processes stuck in D state, + which are not necessarily using any CPU. + + + We want to approximate all tasks on the network being in a single queue, + from which the servers invite tasks as cycles become available. + + However, we also want to preserve the classic-TCP model of clients opening + connections to servers, because this makes the security model + straightforward, works over plain TCP, and also can work over SSH. + + http://www.cs.panam.edu/~meng/Course/CS6354/Notes/meng/master/node4.html + + Research this more. + + We "commit" to using a particular server at the last possible moment: when + we start sending a job to it. This is almost certainly preferable to + queueing up on a particular server when we don't know that it will be the + next one free. + + One analogy for this is patients waiting in a medical center to see one of + several doctors. They all wait in a common waiting room (the queue) until + a doctor (server) is free. Normally the doctors would come into the + waiting room to say "who's next?", but the constraint of running over TCP + means that in our case the doctors cannot initiate the transaction. + + One approach would be to have a central controller (ie receptionist), who + knows which clients are waiting and which servers are free, but I don't + really think the complexity is justified at this stage. + + Imagine if the clients sat so that they could see which doctor had their + door open and was ready to accept a new patient. The first client who + sees that then gets up to go through that door. There is a possibility of + a race when two patients head for the door at the same time, but we just + need to make sure that only one of them wins, and that the other returns + to her seat and keeps looking rather than getting stuck. + + Ideally this will be built on top of some mechanism that does not rely on + polling. + + I had wondered whether it would work to use refused TCP connections to + indicate that a server's door is closed, but I think that is no good. + + It seems that at least on Linux, and probably on other platforms, you + cannot set the TCP SYN backlog down to zero for a socket. The kernel will + still accept new connections on behalf of the process if it is listening, + even if it's asked for no backlog and if it's not accepting them yet. + netstat shows these processes just in + + It looks like the only way to reliably have the server turn away + connections is to either close its listening socket when it's too busy, or + drop connections. This would work OK, but it forces the client into + retrying, which is inefficient and ugly. + + Suppose clients connect and then wait for a prompt from the server before + they begin to send. For multiple servers the client would keep opening + connections to new machines until it got an invitation to send a job. + + This requires a change to the protocol but it can be made backward + compatible if necessary, though perhaps that's not necessary. + + This would have the advantage of working over either TCP or SSH. The main + problem is that the client will potentially need to open connections to + many machines before it can proceed. + + We almost certainly need to do this with nonblocking IO, but that should + be reasonably portable. + + Local compilation needs to be handled by lockfiles or some similar + mechanism. + + So in pseudocode this will be something like + + looking_fds = [] + while not accepted: + select() on looking_fds: + if any have failed, remove them + if any have sent an invitation: + close all others + use the accepted connection + open a new connection + + I'm not sure if connections should be opened in random order or the order + they're listed. + + Clients are almost certainly not going to be accepted in the order in + which they arrive. + + If the client sends its job early then it doesn't hurt anybody else. I + suppose it could open a lot of connections but that sort of fairness issue + is not really something that distcc needs to handle. (Just block the user + if they misbehave.) + + We can't use select() to check for the ability to run a process locally. + Perhaps the select() needs to timeout and we can then, say, check the load + average. + + +problems with new protocol + + Does anyone actually want this? I really need an example of + somewhere where it would be useful. + + The server may need to know the right extension for the temporary + file to make the compiler behave in the right way. In fact, + knowing the acceptable temporary filenames is part of the + application definition. + + +Compression + + Can compression automatically be turned on, rather than requiring + user configuration? I can't tell at the moment when would be the + right time to do that. + + Is it cheap enough to always have it on? We not only pay the cost + of compression, but we also need to give up on using sendfile() + and therefore pay for more kernel-userspace transitions and some + data copying. Therefore probably not, at least for GigE. + + +User Manual + + The UML manual is very good + + - Add some documentation of the benchmark system. Does this belong + in the manual, or in a separate manual? + + - FAQ: Can't you check the gcc version? No, because gcc programs which + report the same versions number can have different behaviours, perhaps due + to vendor/distributor patches. + + + +Just cpp and linker? + + Is it easy to describe how to install only the bits of gcc needed for + distcc clients? Basically the driver, header, linker, and specs. Would + this save much space? + + Certainly installing gcc is much easier than installing a full cross + development environment, because you don't need headers or libraries. So + if you have a target machine that is a bit slower but not terrible (or you + don't have many of them) it might be convenient to do most of your builds + on the target, but rely on helpers with cross-compilers to help out. + + +-g support + + I'm told that gcc may fix this properly in a future release. There would + then be no need to kludge around it in distcc. + + Perhaps detect the -g option, and then absolutify filenames passed to the + compiler. This will cause absolute filenames to appear in error messages, + but I don't see any easy way to have both correct stabs info and also + correct error messages. + + Is anything else wrong with this approach? + + +kill compiler + + If the client is killed, it will close the connection. The server ought + to kill the compiler so as to prevent runaway processes on the server. + + This probably involves selecting() for read on the connection. + + The compilation will complete relatively soon anyhow, so it's not worth + doing this unless there is a simple implementation. + + +tcp fiddling + + I wonder if increasing the maximum window size (sys.net.core.wmem_default, + etc) will help anything? It's probably dominated by scheduling + inefficiency at the moment. + + The client does seem to spend time in wait_for_tcp_memory, which + might be benefitted by increasing the available memory. + + +benchmark + + Try aspell and xmms, which may have strange Makefiles. + + glibc + gtk/glib + glibc++ + qt + gcc + gdb + linux + openoffice + mozilla + + +rsync-like distributed caching + + Look in the remote machine's cache as well. + + Perhaps use a SQUID-like broadcast of the file digest and other critical + details to find out if any machine in the workgroup has the file cached. + Perhaps this could be built on top of a more general file-caching + mechanism that maps from hash to body. At the moment this sounds like + premature optimization. + + Send source as an rdiff against the previous version. + + Needs to be able to fall back to just sending plain text of course. + + Perhaps use different compression for source and binary. + + librsync is probably not stable enough to do this very well. + + +--ping option + + It would be nice to have a <tt>--ping</tt> client option to contact + all the remote servers, and perhaps return some kind of interesting + information. + + Output should be machine-parseable e.g. to use in removing + unreachable machines from the host list. + + Perhaps send little fixed signatures, based on --version. Would + this ever be useful? + + +non-CC-specific Protocol + + Perhaps rather than getting the server to reinterpret the command + line, we should mark the input and output parameters on the client. + So what's sent across the network might be + + distcc -c @@INPUT@@ -o @@OUTPUT@@ + + It's probably better to add additional protocol sections to say + which words should be the input and output files than to use magic + values. + + The attraction is that this would allow a particularly knotty part + of code to be included only in the client and run only once. If any + bugs are fixed in this, then only the client will need to be + upgraded. This might remove most of the gcc-specific knowledge from + the server. + + Different clients might be used to support various very different + distributable jobs. + + We ought to allow for running commands that don't take an input or + output file, in case we want to run "gcc --version". + + The drawback is that probably new servers need to be installed to + handle the new protocol version. + + I don't know if there's really a compelling reason to do this. If + the argument parser depends on things that can only be seen on the + client, such as checking whether files exist, then this may be + needed. + + The server needs to use an appropriately-named temporary file. + + +gcc wierdnesses: + + distcc needs to handle <tt>$COMPILER_PATH</tt> and + <tt>$GCC_EXEC_PREFIX</tt> in some sensible way, if there is one. + Not urgent because I have never heard of them being used. + + +networking timeouts: + + Also we want a timeout for name resolution. The GNU resolver has + a specific feature to do this. On other systems we probably need + to use alarm(), but that might be more trouble than it is worth. Jonas + Jensen says: + + Timing out the connect call could be done easier than this, just by + interrupting it with a SIGALRM, but that's not enough to abort + gethostbyname. This method of longjmp'ing from a signal handler is what + they use in curl, so it should be ok. + + + + +configurable timeout? + + Maybe make the various timeouts configurable? Isn't it possible + to choose values that suit everyone? + + Maybe the initial connection timeout should be shorter? + + +waitstatus + + Make sure that native waitstatus formats are the same as the + Unix/Linux/BSD formats used on the wire. (See + <http://www.opengroup.org/onlinepubs/007904975/functions/wait.html>, + which says they may only be interpreted by macros.) I don't know + of any system where they're different. + + +override compiler name + + distcc could support cross-compilation by a per-volunteer option to + override the compiler name. On the local host, it might invoke gcc + directly, but on some volunteers it might be necessary to specify a more + detailed description of the compiler to get the appropriate cross tool. + This might be insufficient for Makefiles that need to call several + different compilers, perhaps gcc and g++ or different versions of gcc. + Perhaps they can make do with changing the DISTCC host settings at + appropriate times. + + I'm not convinced this complexity is justified. + + Rusty is doing this in ccontrol, which is possibly a better place + for it. + + +use spawn() on Windows + + fork() is very slow. Can we get away with only using spawn()? + + + +Installable package for Windows + + Also, it would be nice to have an easily installable package for Windows + that makes the machine be a Cygwin-based compile volunteer. It probably + needs to include cross-compilers for Linux (or whatever), or at least + simple instructions for building them. + + + +autodetection (Rendezvous, etc) + + http://dotlocal.org/mdnsd/ + + The Apple licence is apparently not GPL compatible. + + Brad reckons SLP is a better fit. + + Automatic detection ("zero configuration") of compile volunteers is + probably not a good idea, because it might be complicated to implement, + and would possibly cause breakage by distributing to machines which are + not properly configured. + + +OpenMOSIX autodiscovery + + what is this? + + +central configuration + + + Notwithstanding the previous point, centralized configuration for a site + would be good, and probably quite practical. Setting up a list of + machines centrally rather than configuring each one sounds more friendly. + The most likely design is to use DNS SRV records (RFC2052), or perhaps + multi-RR A records. For exmaple, compile.ozlabs.foo.com would resolve to + all relevant machines. Another possibility would be to use SLP, the + Service Location Protocol, but that adds a larger dependency and it seems + not to be widely deployed. + + + +Large-scale Distribution + + distcc in it's present form works well on small numbers of close machines + owned by the same people. It might be an interesting project to + investigate scaling up to large numbers of machines, which potentially do + not trust each other. This would make distcc somewhat more like other + "peer-to-peer" systems like Freenet and Napster. + + +preprocess remotely + + Some people might like to assume that all the machines have the same + headers installed, in which case we really can preprocess remotely and + only ship the source. Imagine e.g. a Clearcase environment where the same + filesystem view is mounted on all machines, and they're all running the + exact same system release. + + It's probably not really a good idea, because it will be marginally faster + but much more risky. It is possible, though, and perhaps people building + files with enormous headers would like it. + + Perhaps those people should just use a different tool like dmake, etc. + + +Local variables: +mode: indented-text +indent-tabs-mode: nil +End: diff --git a/distcc/autogen.sh b/distcc/autogen.sh new file mode 100755 index 0000000..d18d318 --- /dev/null +++ b/distcc/autogen.sh @@ -0,0 +1,24 @@ +#! /bin/sh + +# Run this script to build distcc from CVS. + +## first try the default names +AUTOHEADER="autoheader" +AUTOCONF="autoconf" + +if which $AUTOCONF > /dev/null +then + : +else + echo "$0: need autoconf 2.53 or later to build distcc from CVS" >&2 + exit 1 +fi + +echo "$0: running $AUTOHEADER" +$AUTOHEADER || exit 1 + +echo "$0: running $AUTOCONF" +$AUTOCONF || exit 1 + +echo "Now run ./configure and then make." +exit 0 diff --git a/distcc/bench/Build.py b/distcc/bench/Build.py new file mode 100755 index 0000000..67d2817 --- /dev/null +++ b/distcc/bench/Build.py @@ -0,0 +1,151 @@ +# distcc/benchmark -- automated system for testing distcc correctness +# and performance on various source trees. + +# Copyright (C) 2002, 2003 by Martin Pool + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA + +from Project import Project +from compiler import CompilerSpec +import buildutil +from buildutil import make_dir, run_cmd, rm_files +import re, os, sys, time + + + +class Build: + """A Build is a combination of a Project and CompilerSpec. + + """ + def __init__(self, project, compiler, n_repeats): + self.project = project + self.compiler = compiler + self.n_repeats = n_repeats + + self.base_dir = os.path.join(os.getcwd(), "build", self.project.name, self.compiler.name) + self.unpacked_dir = os.path.join(self.base_dir, self.project.unpacked_subdir) + + # Some packages need to be started from a subdirectory of their + # unpacked form. For example, Samba is compiled from the "source/" + # subdirectory of the unpacked source. + if self.project.build_subdir: + self.build_dir = os.path.join(self.unpacked_dir, project.build_subdir) + else: + self.build_dir = self.unpacked_dir + + self.log_dir = self.build_dir + + def __repr__(self): + return "Build(%s, %s)" % (`self.project`, `self.compiler`) + + + def unpack(self): + """Unpack from source tarball into build directory""" + if re.search(r"\.tar\.bz2$", self.project.package_file): + tar_fmt = "tar xf %s --bzip2" + else: + tar_fmt = "tar xfz %s" + + tar_cmd = tar_fmt % os.path.join(os.getcwd(), self.project.package_dir, + self.project.package_file) + + make_dir(self.base_dir) + print "** Unpacking..." + run_cmd("cd %s && %s" % (self.base_dir, tar_cmd)) + + + def configure(self, compiler): + """Run configuration command for this tree, if any.""" + self.compiler = compiler + + make_dir(self.log_dir) + + configure_log = os.path.join(self.log_dir, "bench-configure.log") + distcc_log = os.path.join(self.log_dir, "bench-configure-distcc.log") + + rm_files((configure_log, distcc_log)) + + print "** Configuring..." + run_cmd("cd %s && \\\nDISTCC_LOG='%s' \\\nCC='%s' \\\nCXX='%s' \\\n%s \\\n>%s 2>&1" % + (self.build_dir, distcc_log, self.compiler.cc, + self.compiler.cxx, + self.project.configure_cmd, configure_log)) + + + def build(self, sum): + """Actually build the package.""" + + build_log = os.path.join(self.log_dir, "bench-build.log") + prebuild_log = os.path.join(self.log_dir, "bench-prebuild.log") + + distcc_log = os.path.join(self.log_dir, "bench-build-distcc.log") + + rm_files((build_log, distcc_log)) + + print "** Building..." + if self.project.pre_build_cmd: + cmd = ("cd %s && %s > %s 2>&1" % (self.build_dir, + self.project.pre_build_cmd, + prebuild_log)) + run_cmd(cmd) + + cmd = ("cd %s && \\\n%s \\\nDISTCC_LOG='%s' \\\nCC='%s' \\\nCXX='%s' \\\n%s \\\n>%s 2>&1" % + (self.build_dir, self.project.build_cmd, distcc_log, + self.compiler.cc, + self.compiler.cxx, + self.compiler.make_opts, + build_log)) + result, elapsed = run_cmd(cmd) + return elapsed + + + def clean(self): + clean_log = os.path.join(self.log_dir, "bench-clean.log") + print "** Cleaning build directory" + cmd = "cd %s && make clean >%s 2>&1" % (self.build_dir, clean_log) + run_cmd(cmd) + + + def scrub(self): + print "** Removing build directory" + run_cmd("rm -rf %s" % self.unpacked_dir) + + + def build_actions(self, actions, summary): + """Carry out selected actions. + + Catch exceptions and handle.""" + try: + times = [] + if 'sweep' in actions: + self.scrub() + if 'unpack' in actions: + self.unpack() + if 'configure' in actions: + self.configure(self.compiler) + for i in range(self.n_repeats): + if 'build' in actions: + times.append(self.build(summary)) + if 'clean' in actions: + self.clean() + if 'scrub' in actions: + self.scrub() + summary.store(self.project, self.compiler, times) + except KeyboardInterrupt: + raise + except: + apply(sys.excepthook, sys.exc_info()) # print traceback + summary.store(self.project, self.compiler, 'FAIL') diff --git a/distcc/bench/Project.py b/distcc/bench/Project.py new file mode 100755 index 0000000..9551917 --- /dev/null +++ b/distcc/bench/Project.py @@ -0,0 +1,114 @@ +# distcc/benchmark -- automated system for testing distcc correctness +# and performance on various source trees. + +# Copyright (C) 2002, 2003 by Martin Pool + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA + +import re, os, sys, time +from buildutil import make_dir, run_cmd + + +# Trees of software to be built. +trees = { } + + +class Project: + """Defines a project to be built and tested. + + The Python process remains in the top-level directory for the + whole process. Commands are kicked off in subdirectories if + necessary. + + 'subdir' variables give just a single component of a name; 'dir' variables + give a full path.""" + + def __init__(self, url, package_file=None, + md5=None, + name=None, + configure_cmd=None, + pre_build_cmd = None, + build_cmd=None, + unpacked_subdir=None, + build_subdir=None, + source_name=None): + self.url = url + if not package_file: + package_file = url.split('/')[-1] + self.package_file = package_file + + if not name: + name = re.match(r"(.*)\.tar(\.gz|\.bz2|)$", package_file).group(1) + self.name = name + + self.md5 = md5 + + self.configure_cmd = configure_cmd or "./configure" + self.build_cmd = build_cmd or "make" + self.source_name = source_name or name + self.pre_build_cmd = pre_build_cmd + + self.package_dir = "packages" + self.download_dir = "download" + + # By default, we assume the package creates an unpacked + # directory whose name is the same as the tarball. For + # example, Wine's tarball is "Wine-xxxxxxx", but it unpacks to + # "wine-xxxxxxxx". + self.unpacked_subdir = unpacked_subdir or self.source_name + self.build_subdir = build_subdir + + + def register(self): + trees[self.name] = self + + + def __repr__(self): + return "Project(name=%s)" % `self.name` + + + def download(self): + """Download package from vendor site""" + + make_dir(self.package_dir) + make_dir(self.download_dir) + + if not os.path.isfile(os.path.join(self.package_dir, self.package_file)): + # XXX: snarf gets upset if the HTTP server returns "416 + # Requested Range Not Satisfiable" because the file is already + # totally downloaded. This is kind of a snarf bug. + print "** Downloading" + run_cmd("cd %s && wget --continue %s" % + (self.download_dir, self.url)) + run_cmd("mv %s %s" % + (os.path.join(self.download_dir, self.package_file), + self.package_dir)) + + def md5check(self): + if self.md5: + print "** Checking source package integrity" + run_cmd("cd %s && echo '%s' | md5sum -c /dev/stdin" % + (self.package_dir, self.md5)) + + + def pre_actions(self, actions): + """Perform actions preparatory to building according to selection.""" + + if 'download' in actions: + self.download() + if 'md5check' in actions: + self.md5check() + diff --git a/distcc/bench/ProjectDefs.py b/distcc/bench/ProjectDefs.py new file mode 100755 index 0000000..ec66490 --- /dev/null +++ b/distcc/bench/ProjectDefs.py @@ -0,0 +1,100 @@ +# distcc/benchmark -- automated system for testing distcc correctness +# and performance on various source trees. + +# Copyright (C) 2002, 2003, 2004 by Martin Pool + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA + +__doc__ = """distcc benchmark project definitions""" + +from Project import Project + +# Would like to test glibc, but it needs a separate source and build +# directory, and this tool doesn't support that yet. + +# disable-sanity-checks is needed to stop it wanting linuxthreads -- +# the resulting library is useless, but this is only a test. + +#Project(url = 'http://ftp.gnu.org/pub/gnu/glibc/glibc-2.3.2.tar.bz2', +# configure_cmd = './configure --disable-sanity-checks' +# ).register() + +#Project(url='http://mirror.aarnet.edu.au/pub/gnu/libc/glibc-2.3.tar.bz2', +# configure_cmd='./configure --disable-sanity-checks', +# md5='fd20b4a9feeb2b2f0f589b1a9ae8a5e2 glibc-2.3.tar.bz2').register() + +Project(url='http://archive.apache.org/dist/httpd/httpd-2.0.43.tar.gz', + md5='8051de5d160c43d4ed2cc47dc9be6fd3 httpd-2.0.43.tar.gz').register() + +Project(url='ftp://ftp.gtk.org/pub/gtk/v2.0/glib-2.0.7.tar.bz2', + md5='5882b1e729f57cb18af653a2f504197b glib-2.0.7.tar.bz2').register() + +Project(url='http://us3.samba.org/samba/ftp/old-versions/samba-2.2.7.tar.gz', + build_subdir='source', + ).register() + +Project(url='http://ftp.gnu.org/gnu/make/make-3.80.tar.bz2', + md5='0bbd1df101bc0294d440471e50feca71 *make-3.80.tar.bz2' + ).register() + +# failed: "make: *** No rule to make target `defconfig'. Stop." +#Project(url='http://public.ftp.planetmirror.com/pub/linux/kernel/v2.4/linux-2.4.20.tar.bz2', +# configure_cmd='make defconfig', +# build_cmd='make bzImage', +# ).register() + +Project(url='http://www.kernel.org/pub/linux/kernel/v2.5/linux-2.5.51.tar.bz2', + md5='2300b7b7d2ce4c017fe6dae49717fd9a *linux-2.5.51.tar.bz2', + configure_cmd='make defconfig', + build_cmd='make bzImage' + ).register() + +Project(url='http://sources-redhat.oc1.mirrors.redwire.net/gdb/old-releases/gdb-5.3.tar.gz', + ).register() + +Project(url='ftp://212.8.35.65/pub/FreeBSD/distfiles/gimp-1.2.3.tar.bz2', + md5='b19235f19f524f772a4aef597a69b1da *gimp-1.2.3.tar.bz2', + configure_cmd='./configure --disable-perl', + ).register() + +Project(url='http://ibiblio.org/pub/linux/system/emulators/wine/wine-0.9.3.tar.bz2', + ).register() + +Project(url='http://public.planetmirror.com.au/pub/gnu/hello/hello-2.1.1.tar.gz', + md5='70c9ccf9fac07f762c24f2df2290784d *hello-2.1.1.tar.gz', + ).register() + + +# XXX: Does not build on Debian at the moment, problem with libIDL-config + +# Project(url='http://mirror.aarnet.edu.au/pub/mozilla/releases/mozilla1.4/src/mozilla-source-1.4.tar.bz2', +# name='mozilla-1.4', +# configure_cmd="LIBIDL_CONFIG=libIDL-config-2 ./configure", +# unpacked_subdir='mozilla', +# ).register() + + +Project(url='http://ftp.mozilla.org/pub/firebird/releases/0.6/MozillaFirebird-0.6-source.tar.bz2', + name='MozillaFirebird', + unpacked_subdir='mozilla', + ).register() + +Project(url='http://ftp.azc.uam.mx/mirrors/samba/samba-3.0.7.tar.gz', + name='samba-3.0.7', + build_subdir='source', + configure_cmd='./configure', + pre_build_cmd = 'make proto', + ).register() diff --git a/distcc/bench/Summary.py b/distcc/bench/Summary.py new file mode 100755 index 0000000..33c8111 --- /dev/null +++ b/distcc/bench/Summary.py @@ -0,0 +1,76 @@ +# distcc/benchmark -- automated system for testing distcc correctness +# and performance on various source trees. + +# Copyright (C) 2002, 2003 by Martin Pool + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA + +class Summary: + """Stores and prints results of building different things""" + + # Table is a sequence, because we prefer to have things printed + # out in the order they were executed. + + def __init__(self): + self._table = [] + + def store(self, project, compiler, elapsed_times): + """ + elapsed_times is a sequence of elapsed times to build the project. + A sequence because we can build projects repeatedly. + """ + self._table.append((project.name, compiler.name, elapsed_times)) + + def print_raw(self): + from pprint import pprint + pprint(self._table) + + def print_table(self): + import time, os, sys + import statistics + + # if nothing was run, skip it + if not len(self._table): + return + + """Print out in a nice tabular form""" + print """ + ======================== + distcc benchmark results + ======================== + +""" + print "Date: ", time.ctime() + print "DISTCC_HOSTS: %s" % `os.getenv('DISTCC_HOSTS')` + sys.stdout.flush() + os.system("uname -a") + + print "%-20s %-30s %8s %8s" % ('project', 'compiler', 'time', 's.d.') + + for row in self._table: + print "%-20s %-30s " % row[:2], + times = row[2] + if times == 'FAIL': + print '%9s' % 'FAIL' + else: + mean = statistics.mean(times) + sd = statistics.std(times) + print "%8.4fs" % mean, + if sd is None: + print "%9s" % "n/a" + else: + print "%8.4fs" % sd + diff --git a/distcc/bench/actions.py b/distcc/bench/actions.py new file mode 100755 index 0000000..d6c3544 --- /dev/null +++ b/distcc/bench/actions.py @@ -0,0 +1,51 @@ +# distcc/benchmark -- automated system for testing distcc correctness +# and performance on various source trees. + +# Copyright (C) 2002, 2003 by Martin Pool + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA + +# Tuples of (name, default, descr) +all_actions = [('download', True, ''), + ('md5check', True, 'check file was downloaded correctly'), + ('sweep', True, 'remove build directory before unpacking'), + ('unpack', True, 'unpack source'), + ('configure', True, ''), + ('clean', True, 'run "make clean" or equivalent'), + ('build', True, ''), + ('scrub', True, 'remove build directory')] + + +def action_help(): + print "Actions:" + for action, default, descr in all_actions: + default_ch = default and '*' or ' ' + print " %c %-20s %s" % (default_ch, action, descr) + print " (* = on by default)" + + +# Filter out only actions where 'default' is true +default_actions = [a[0] for a in all_actions if a[1]] + + +def parse_opt_actions(optarg): + import sys + opt_actions = optarg.split(',') + action_names = [a[0] for a in all_actions] + for oa in opt_actions: + if oa not in action_names: + raise ValueError, ("no such action: %s" % `oa`) + return opt_actions diff --git a/distcc/bench/benchmark.py b/distcc/bench/benchmark.py new file mode 100755 index 0000000..a4f80b3 --- /dev/null +++ b/distcc/bench/benchmark.py @@ -0,0 +1,176 @@ +#! /usr/bin/python + +# distcc/benchmark -- automated system for testing distcc correctness +# and performance on various source trees. + +# Copyright (C) 2002, 2003, 2004 by Martin Pool + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA + + +# Unlike the main distcc test suite, this program *does* require you +# to manually set up servers on your choice of machines on the +# network, and make sure that they all have appropriate compilers +# installed. The performance measurements obviously depend on the +# network and hardware available. + +# It also depends on you having the necessary dependencies to build +# the software. If you regularly build software on Linux you should +# be OK. Some things (the GIMP) will be harder than others. + +# On some platforms, it may be impossible to build some targets -- for +# example, Linux depends on having a real-mode x86 assembler, which +# probably isn't installed on Solaris. + +# Note that running this program will potentially download many +# megabytes of test data. + + +# TODO: Support applying patches after unpacking, before building. +# For example, they might be needed to fix -j bugs in the Makefile. + +# TODO: In stats, show ratio of build time to slowest build time. (Or +# to first one run?) + +# TODO: Allow choice of which compiler and make options to use. + +# TODO: Try building something large in C++. + +# TODO: Set CXX as well. + +# TODO: Add option to run tests repeatedly and show mean and std. dev. + +# TODO: Perhaps add option to do "make clean" -- this might be faster +# than unzipping and configuring every time. But perhaps also less +# reproducible. + +# TODO: Add option to run tests on different sets or orderings of +# machines. + + +import re, os, sys, time +from getopt import getopt + +from Summary import Summary +from Project import Project, trees +from compiler import CompilerSpec +from Build import Build +import actions, compiler + +import ProjectDefs # this adds a lot of definitions to 'trees' + + +def error(msg): + sys.stderr.write(msg + "\n") + + +def list_projects(): + names = trees.keys() + names.sort() + for n in names: + print n + + +def find_project(name): + """ + Return the nearest unique match for name. + """ + best_match = None + for pn in trees.keys(): + if pn.startswith(name): + if best_match: + raise ValueError, "ambiguous prefix %s" % name + else: + best_match = pn + + if not best_match: + raise ValueError, "nothing matches %s" % name + else: + return trees[best_match] + + + +def show_help(): + print """Usage: benchmark.py [OPTION]... [PROJECT]... +Test distcc relative performance building different projects. +By default, all known projects are built. + +Options: + --help show brief help message + --list-projects show defined projects + -c, --compiler=COMPILER specify one compiler to use + -n N repeat compilation N times + -a, --actions=ACTIONS comma-separated list of action phases + to perform + +Compilers can be specified as either "local,N" to run N copies of gcc, +or dist,N to run N copies of distcc. Multiple -c options specify +different scenarios to measure. The default is to run a nonparallel +local compile and a parallel distributed compile. +""" +actions.action_help() + + +# -a is for developer use only and not documented; unless you're +# careful the results will just be confusing. + + + + +###################################################################### +def main(): + """Run the benchmark per arguments""" + sum = Summary() + options, args = getopt(sys.argv[1:], 'a:c:n:', + ['list-projects', 'actions=', 'help', 'compiler=']) + opt_actions = actions.default_actions + set_compilers = [] + opt_repeats = 1 + + for opt, optarg in options: + if opt == '--help': + show_help() + return + elif opt == '--list-projects': + list_projects() + return + elif opt == '--actions' or opt == '-a': + opt_actions = actions.parse_opt_actions(optarg) + elif opt == '--compiler' or opt == '-c': + set_compilers.append(compiler.parse_opt(optarg)) + elif opt == '-n': + opt_repeats = int(optarg) + + if not set_compilers: + set_compilers = compiler.default_compilers() + + # Find named projects, or run all by default + if args: + chosen_projects = [find_project(name) for name in args] + else: + chosen_projects = trees.values() + + for proj in chosen_projects: + proj.pre_actions(opt_actions) + for comp in set_compilers: + build = Build(proj, comp, opt_repeats) + build.build_actions(opt_actions, sum) + + sum.print_table() + +if __name__ == '__main__': + main() + diff --git a/distcc/bench/buildutil.py b/distcc/bench/buildutil.py new file mode 100755 index 0000000..8a43353 --- /dev/null +++ b/distcc/bench/buildutil.py @@ -0,0 +1,49 @@ +# distcc/benchmark -- automated system for testing distcc correctness +# and performance on various source trees. + +# Copyright (C) 2002, 2003 by Martin Pool + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA + + +def make_dir(d): + import os + if not os.path.isdir(d): + os.makedirs(d) + + +def run_cmd(cmd, expected=0): + import time, os + + before = time.time() + print '%% %s' % cmd + result = os.system(cmd) + after = time.time() + elapsed = (after - before) + print '%16.4fs elapsed\n' % elapsed + if expected is not None: + if expected != result: + raise AssertionError("command failed: expected status %d, got %d", + expected, result) + return result, elapsed + + +def rm_files(file_list): + import os + for f in file_list: + if os.path.exists(f): + os.unlink(f) + diff --git a/distcc/bench/compiler.py b/distcc/bench/compiler.py new file mode 100755 index 0000000..3cc9d1d --- /dev/null +++ b/distcc/bench/compiler.py @@ -0,0 +1,63 @@ +# distcc/benchmark -- automated system for testing distcc correctness +# and performance on various source trees. + +# Copyright (C) 2002, 2003 by Martin Pool + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA + +class CompilerSpec: + """Describes a compiler/make setup. + + Used to define different situations such as local compilation, and + various degrees of parallelism.""" + + def __init__(self, cc=None, cxx=None, make_opts=None, name=None): + self.cc = cc or 'gcc' + self.cxx = cxx or 'c++' + self.make_opts = make_opts or '' + self.name = name or (self.cc + "__" + self.make_opts).replace(' ', '_') + + +def default_compilers(): + return [parse_opt('local,1'), + parse_opt('dist,8'), + ] + +def parse_opt(optarg): + """Parse command-line specification of a compiler + + XXX: I don't really know what the best syntax for this is. For + the moment, it is "local" or "dist", followed by a comma and a + -j number. Perhaps we need to be able to specify host lists here + too. + """ + where, howmany = optarg.split(',') + howmany = int(howmany) + if where == 'local': + return CompilerSpec(name='local_%02d' % howmany, + cc='cc', + cxx='c++', + make_opts='-j%d' % howmany) + elif where == 'dist': + return CompilerSpec(name='dist_%02d' % howmany, + cxx='distcc c++', + cc='distcc cc', + make_opts='-j%d' % howmany) + else: + raise ValueError, ("don't understand %s" % `where`) + + + diff --git a/distcc/bench/statistics.py b/distcc/bench/statistics.py new file mode 100755 index 0000000..1565752 --- /dev/null +++ b/distcc/bench/statistics.py @@ -0,0 +1,47 @@ +#! /usr/bin/env python2.2 + +# distcc/benchmark -- automated system for testing distcc correctness +# and performance on various source trees. + +# Copyright (C) 2003 by Martin Pool + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA + + +# Based in part on http://starship.python.net/crew/jhauser/NumAdd.py.html by Janko Hauser + + +import Numeric + +def var(m): + """ + Variance of m. + """ + if len(m) < 2: + return None + mu = Numeric.average(m) + return (Numeric.add.reduce(Numeric.power(Numeric.ravel(m)-mu, 2)) + / (len(m)-1.)) + +def std(m): + """ + Standard deviation of m. + """ + v = var(m) + return v and Numeric.sqrt(v) + +def mean(m): + return Numeric.average(m) diff --git a/distcc/config.guess b/distcc/config.guess new file mode 100755 index 0000000..9b1384b --- /dev/null +++ b/distcc/config.guess @@ -0,0 +1,1400 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002 Free Software Foundation, Inc. + +timestamp='2002-11-30' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Per Bothner <per@bothner.com>. +# Please send patches to <config-patches@gnu.org>. Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# This shell variable is my proudest work .. or something. --bje + +set_cc_for_build='tmpdir=${TMPDIR-/tmp}/config-guess-$$ ; +(old=`umask` && umask 077 && mkdir $tmpdir && umask $old && unset old) + || (echo "$me: cannot create $tmpdir" >&2 && exit 1) ; +dummy=$tmpdir/dummy ; +files="$dummy.c $dummy.o $dummy.rel $dummy" ; +trap '"'"'rm -f $files; rmdir $tmpdir; exit 1'"'"' 1 2 15 ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + rm -f $files ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; +unset files' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + macppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvmeppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mipseb-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + eval $set_cc_for_build + cat <<EOF >$dummy.s + .data +\$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main +main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + $CC_FOR_BUILD -o $dummy $dummy.s 2>/dev/null + if test "$?" = 0 ; then + case `$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + 2-1307) + UNAME_MACHINE="alphaev68" + ;; + 3-1307) + UNAME_MACHINE="alphaev7" + ;; + esac + fi + rm -f $dummy.s $dummy && rmdir $tmpdir + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit 0;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + DRS?6000:UNIX_SV:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7 && exit 0 ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include <stdio.h> /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c \ + && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 + rm -f $dummy.c $dummy && rmdir $tmpdir + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit 0 ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 + rm -f $dummy.c $dummy && rmdir $tmpdir + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include <stdlib.h> + #include <unistd.h> + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi + rm -f $dummy.c $dummy && rmdir $tmpdir + fi ;; + esac + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 + rm -f $dummy.c $dummy && rmdir $tmpdir + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3D:*:*:*) + echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + # Determine whether the default compiler uses glibc. + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <features.h> + #if __GLIBC__ >= 2 + LIBC=gnu + #else + LIBC= + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + rm -f $dummy.c && rmdir $tmpdir + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit 0 ;; + x86:Interix*:3*) + echo i586-pc-interix3 + exit 0 ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + rm -f $dummy.c && rmdir $tmpdir + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + rm -f $dummy.c && rmdir $tmpdir + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit 0 ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit 0 ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit 0 ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit 0 ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit 0 ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit 0 ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit 0 ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit 0 ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit 0 ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <features.h> + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + rm -f $dummy.c && rmdir $tmpdir + test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit 0 ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit 0 ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit 0 ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit 0 ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit 0 ;; + i*86:*:5:[78]*) + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit 0 ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit 0 ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit 0 ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + echo `uname -p`-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit 0 ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit 0 ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit 0 ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit 0 ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit 0 ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit 0 ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include <sys/param.h> + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include <sys/param.h> +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && rm -f $dummy.c $dummy && rmdir $tmpdir && exit 0 +rm -f $dummy.c $dummy && rmdir $tmpdir + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +cat >&2 <<EOF +$0: unable to guess system type + +This script, last modified $timestamp, has failed to recognize +the operating system you are using. It is advised that you +download the most up to date version of the config scripts from + + ftp://ftp.gnu.org/pub/gnu/config/ + +If the version you run ($0) is already up to date, please +send the following data and any information you think might be +pertinent to <config-patches@gnu.org> in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/distcc/config.sub b/distcc/config.sub new file mode 100755 index 0000000..f0675aa --- /dev/null +++ b/distcc/config.sub @@ -0,0 +1,1469 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002 Free Software Foundation, Inc. + +timestamp='2002-11-30' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Please send patches to <config-patches@gnu.org>. Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit 0;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k \ + | m32r | m68000 | m68k | m88k | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mipsisa32 | mipsisa32el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | ns16k | ns32k \ + | openrisc | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh3e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* \ + | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* \ + | clipper-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* \ + | m32r-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39 | mipstx39el \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh3e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ + | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* | tic30-* | tic4x-* | tic54x-* | tic80-* | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ + | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + or32 | or32-*) + basic_machine=or32-unknown + os=-coff + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2) + basic_machine=i686-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3d) + basic_machine=alpha-cray + os=-unicos + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic4x | c4x*) + basic_machine=tic4x-unknown + os=-coff + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4 | sh3eb | sh4eb | sh[1234]le | sh3ele) + basic_machine=sh-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparc | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/distcc/configure.ac b/distcc/configure.ac new file mode 100644 index 0000000..f93fab3 --- /dev/null +++ b/distcc/configure.ac @@ -0,0 +1,455 @@ +dnl Process this file with autoconf to produce a configure script + +# "We are ugly but we have the music" +# -- Leonard Cohen + +# http://jerkcity.com/jerkcity1335.html + + +# This is the configure script for distcc. +# Copyright (C) 2002, 2003, 2004 by Martin Pool + +# As of 0.6cvs, distcc no longer uses automake, only autoconf. +AC_PREREQ(2.53) +AC_INIT(distcc, + esyscmd(source ../version.sh && echo -n $DISTCC_PUMP_VERSION), + [distcc-pump@google.com]) + +AC_CONFIG_HEADERS(src/config.h) +AC_CANONICAL_HOST + +# FreeBSD installs its version of libpopt into /usr/local/, but does +# not put that on the default library and header path. +# Solaris doesn't even ship libpopt. We used to add that path if +# building on *bsd*, but bje points out that will break +# cross-compilation, and it's kind of ugly anyhow. Anyhow, you can +# either set CPPFLAGS and LDFLAGS when running configure, or use +# --with-extra-foo. + +##### defaults + +dnl --with-docdir +AC_DEFUN([DISTCC_WITH_DOCDIR], +[AC_ARG_WITH(docdir, + AC_HELP_STRING([--with-docdir=DIR], + [Use DIR to store documentation files (default ${datadir}/doc/distcc)]), + [with_docdir=$withval]) +if test "x$with_docdir" = "x" ; then + docdir='${datadir}/doc/distcc' +else + docdir=$with_docdir +fi +AC_SUBST(docdir) +]) + +dnl Run the check for --with-docdir +DISTCC_WITH_DOCDIR + +# Check for socklen_t, and do something appropiate on systems +# that don't have it. +AC_CHECK_TYPE([socklen_t], ,[ + AC_MSG_CHECKING([for socklen_t equivalent]) + AC_CACHE_VAL([dcc_cv_socklen_t_equiv], + [ + # Systems have either "struct sockaddr *" or + # "void *" as the second argument to getpeername + dcc_cv_socklen_t_equiv= + for arg2 in "struct sockaddr" void; do + for t in int size_t unsigned long "unsigned long"; do + AC_TRY_COMPILE([ +#include <sys/types.h> +#include <sys/socket.h> + +int getpeername (int, $arg2 *, $t *); +],[ +$t len; +getpeername(0,0,&len); +],[ + dcc_cv_socklen_t_equiv="$t" + break +]) + done + done + + if test "x$dcc_cv_socklen_t_equiv" = x; then + AC_MSG_ERROR([Cannot find a type to use in place of socklen_t]) + fi + ]) + AC_MSG_RESULT($dcc_cv_socklen_t_equiv) + AC_DEFINE_UNQUOTED(socklen_t, $dcc_cv_socklen_t_equiv, + [type to use in place of socklen_t if not defined])], + [#include <sys/types.h> +#include <sys/socket.h>]) + +# TODO: Handle program transform rules by autoconf. + +### Checks for configure options + +AC_ARG_WITH(included-popt, + AC_HELP_STRING([--with-included-popt], [use bundled popt library, not from system])) + +AC_ARG_ENABLE(rfc2553, + AC_HELP_STRING([--enable-rfc2553], [use getaddrinfo, getnameinfo, etc]), + AC_DEFINE(ENABLE_RFC2553,1,[Use getaddrinfo(), getnameinfo(), etc])) + + +AC_ARG_WITH(gnome, + AC_HELP_STRING([--with-gnome], [build GNOME-based monitor])) + +if test x"$with_gnome" = xyes +then + GNOME_BIN=distccmon-gnome + AC_DEFINE(WITH_GNOME,1,[Use GNOME]) +fi + +AC_ARG_WITH(gtk, + AC_HELP_STRING([--with-gtk], [build GTK+-based monitor])) +if test x"$with_gtk" = xyes +then + GNOME_BIN=distccmon-gnome + AC_DEFINE(WITH_GTK,1,[Use GTK+]) +fi + +AC_ARG_ENABLE(profile, + AC_HELP_STRING([--enable-profile], [turn on gprof])) + +if test x"$enable_profile" = xyes +then + CFLAGS="$CFLAGS -pg -g" +fi + + +# Now get the package configuration information for whatever packages +# we need. It's faster to just do it once during configuration. +if test "x${with_gnome}" = xyes +then + GNOME_PACKAGES="gtk+-2.0 libgnome-2.0 libgnomeui-2.0 pango" +elif test "x${with_gtk}" = xyes +then + GNOME_PACKAGES="gtk+-2.0" +else + GNOME_PACKAGES="" +fi + +for pkg in $GNOME_PACKAGES +do + AC_MSG_CHECKING([version of $pkg]) + if gnomevers=`pkg-config --modversion $pkg` + then + AC_MSG_RESULT($gnomevers) + else + AC_MSG_ERROR([$pkg was not found by pkg-config]) + fi +done + +if test x${with_gnome} = xyes -o x${with_gtk} = xyes +then + INSTALL_GNOME="install-gnome-data" + AC_MSG_CHECKING([GNOME/GTK+ cflags]) + GNOME_CFLAGS="`pkg-config --cflags $GNOME_PACKAGES`" || AC_MSG_ERROR([failed to get cflags]) + AC_MSG_RESULT([${GNOME_CFLAGS}]) + + AC_MSG_CHECKING([GNOME/GTK+ libraries]) + GNOME_LIBS="`pkg-config --libs $GNOME_PACKAGES`" || AC_MSG_ERROR([failed to get libs]) + AC_MSG_RESULT([${GNOME_LIBS}]) +fi + +AC_SUBST(GNOME_PACKAGES) +AC_SUBST(GNOME_CFLAGS) +AC_SUBST(GNOME_LIBS) +AC_SUBST(INSTALL_GNOME) + +dnl Checks for programs +AC_PROG_CC +POPT_CFLAGS="" +WERROR_CFLAGS="" +if test x"$GCC" = xyes +then + CFLAGS="$CFLAGS -MD \ +-W -Wall -Wimplicit -Wuninitialized \ +-Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings \ +-Waggregate-return -Wstrict-prototypes -Wmissing-prototypes \ +-Wnested-externs -Wpointer-arith -Wmissing-declarations" + # Would like -Wunreachable-code here, but it generates too many false + # positives. + + # We want warnings to be treated as errors. + # Note that we can't include this in CFLAGS, + # because that would effect the configure tests, + # causing some of the tests to fail when they should succeed. + WERROR_CFLAGS="-Werror" + + # For popt/*.c, we disable unused variable warnings. + POPT_CFLAGS="-Wno-unused" + + AC_MSG_NOTICE([Adding gcc options: $CFLAGS]) +fi +AC_SUBST(POPT_CFLAGS) +AC_SUBST(WERROR_CFLAGS) +AC_ISC_POSIX + + +# Apple's OS X gcc has a cpp-precomp "feature" that breaks standard +# variadic macros. If we can disable it, do so. + + +# This is needed for our included version of popt. +CPPFLAGS="$CPPFLAGS -DHAVE_CONFIG_H" + +# Needed to get various GNU-only functions. They're all autodetected +# by configure so we can cope without them, but we want them if they're +# there. +CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" + +AC_PROG_MAKE_SET +AC_PROG_INSTALL + +# TODO: Perhaps try to find a command name that invokes Python2.2, and +# write that in to the makefile for use in running benchmarks, etc. +# Perhaps it's reasonable to count on it always being "python2.2", but +# that will break when we're on to a later version. + +AC_CHECK_PROGS(PYTHON, [python2.4 python2.3 python-2.3 python2.2 python-2.2 python]) +AC_ARG_VAR(PYTHON, [Python interpreter to use for running tests]) +# NB: Cannot use AC_CONFIG_LIBOBJ_DIR here, because it's not present +# in autoconf 2.53. + +AC_C_INLINE +AC_C_BIGENDIAN + +######################################################################## +### Checks for header files + +# Some of these are needed by popt (or other libraries included in the future). + +AC_CHECK_HEADERS([unistd.h sys/types.h sys/sendfile.h sys/signal.h]) +AC_CHECK_HEADERS([ctype.h sys/resource.h sys/socket.h sys/select.h]) +AC_CHECK_HEADERS([netinet/in.h], [], [], +[#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +]) +AC_CHECK_HEADERS([arpa/nameser.h], [], [], +[#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +]) +AC_CHECK_HEADERS([resolv.h], [], [], +[#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#if HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif +#if HAVE_ARPA_NAMESER_H +# include <arpa/nameser.h> +#endif +]) + +AC_CHECK_HEADERS([float.h mcheck.h alloca.h sys/mman.h sys/loadavg.h]) +AC_CHECK_HEADERS([elf.h]) +AC_CHECK_HEADERS([fnmatch.h]) + +###################################################################### +dnl Checks for types + +AC_CHECK_TYPES([in_port_t, in_addr_t], , , + [ +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#if HAVE_SYS_SOCKET_H +# include <sys/socket.h> +#endif +#if HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif +#if HAVE_ARPA_NAMESER_H +# include <arpa/nameser.h> +#endif +]) + + + +######################################################################## +### Checks for libraries. + +# The following test taken from the cvs sources via Samba: +# If we can't find connect, try looking in -lsocket, -lnsl, and -linet. +# The Irix 5 libc.so has connect and gethostbyname, but Irix 5 also has +# libsocket.so which has a bad implementation of gethostbyname (it +# only looks in /etc/hosts), so we only look for -lsocket if we need +# it. +AC_SEARCH_LIBS(gethostent, [nsl]) +AC_SEARCH_LIBS(setsockopt, [socket]) +AC_SEARCH_LIBS(hstrerror, [resolv]) +AC_SEARCH_LIBS(inet_aton, [resolv]) + +if test x"$with_included_popt" != x"yes" && test x"$with_included_popt" != xno +then + # If not explicitly requested, guess. + # People might have the library but not the header, in which case we + # still need to use the included copy. + AC_CHECK_HEADER(popt.h, , [with_included_popt=yes]) +fi +AC_CACHE_SAVE + +AC_MSG_CHECKING([whether to use included libpopt]) +if test x"$with_included_popt" = x"yes" +then + AC_MSG_RESULT($srcdir/popt) + # popt_OBJS gets appended to distccd object list + BUILD_POPT='$(popt_OBJS)' + CPPFLAGS="$CPPFLAGS -I$srcdir/popt" +else + LIBS="$LIBS -lpopt" + AC_MSG_RESULT(no) +fi + + + +######################################################################## +# Check for types +AC_TYPE_SIGNAL + + +######################################################################## +# Checks for library functions, using libraries discovered above +CPPFLAGS="$CPPFLAGS -I$srcdir/src" + +AC_CHECK_FUNCS([getpagesize]) +AC_CHECK_FUNCS([sendfile setsid flock lockf hstrerror strerror setuid setreuid]) +AC_CHECK_FUNCS([getuid geteuid mcheck wait4 wait3 waitpid setgroups getcwd]) +AC_CHECK_FUNCS([snprintf vsnprintf vasprintf asprintf getcwd getwd]) +AC_CHECK_FUNCS([getrusage strsignal gettimeofday]) +AC_CHECK_FUNCS([getaddrinfo getnameinfo inet_ntop inet_ntoa]) +AC_CHECK_FUNCS([strndup mmap strlcpy]) + +AC_CHECK_FUNCS([getloadavg]) + +AC_CHECK_DECLS([snprintf, vsnprintf, vasprintf, asprintf, strndup]) + +AC_MSG_CHECKING([if mmap() supports MAP_FAILED]) +AC_TRY_COMPILE([ +#ifdef HAVE_SYS_MMAN_H +# include <sys/mman.h> +#endif],[ +#ifdef HAVE_MMAP +if (mmap (NULL, 0, 0, 0, 0, 0) == MAP_FAILED) + return 0; +#else +#error mmap unavailable +#endif], ,[ + AC_DEFINE([MAP_FAILED], [(void *)-1L], + [Define if MAP_FAILED constant not available]) +]) +AC_MSG_RESULT() + + +dnl +dnl Test if the preprocessor understand vararg macros +dnl +AC_MSG_CHECKING([for vararg macro support]) +AC_TRY_COMPILE([#define func(a, b...) do { } while (0)], +[func("a"); func("a", "b"); func("a", "b", "c")], +[AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_VARARG_MACROS, , [Define if your cpp has vararg macros])], +[AC_MSG_RESULT(no)]) + +AC_CACHE_CHECK([for __va_copy],samba_cv_HAVE_VA_COPY,[ +AC_TRY_LINK([#include <stdarg.h> +va_list ap1,ap2;], [__va_copy(ap1,ap2);], +samba_cv_HAVE_VA_COPY=yes,samba_cv_HAVE_VA_COPY=no)]) +if test x"$samba_cv_HAVE_VA_COPY" = x"yes"; then + AC_DEFINE(HAVE_VA_COPY,1,[Whether __va_copy() is available]) +fi + +AC_CACHE_CHECK([for C99 vsnprintf],rsync_cv_HAVE_C99_VSNPRINTF,[ +AC_TRY_RUN([ +#include <sys/types.h> +#include <stdarg.h> +void foo(const char *format, ...) { + va_list ap; + int len; + char buf[5]; + + va_start(ap, format); + len = vsnprintf(0, 0, format, ap); + va_end(ap); + if (len != 5) exit(1); + + if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(1); + + exit(0); +} +main() { foo("hello"); } +], +rsync_cv_HAVE_C99_VSNPRINTF=yes,rsync_cv_HAVE_C99_VSNPRINTF=no,rsync_cv_HAVE_C99_VSNPRINTF=cross)]) +if test x"$rsync_cv_HAVE_C99_VSNPRINTF" = x"yes"; then + AC_DEFINE(HAVE_C99_VSNPRINTF, 1, [define if vsnprintf is C99 compliant]) +fi + + +AC_CACHE_CHECK([for working socketpair],rsync_cv_HAVE_SOCKETPAIR,[ +AC_TRY_RUN([ +#include <sys/types.h> +#include <sys/socket.h> + +main() { + int fd[2]; + exit((socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != -1) ? 0 : 1); +}], +rsync_cv_HAVE_SOCKETPAIR=yes,rsync_cv_HAVE_SOCKETPAIR=no,rsync_cv_HAVE_SOCKETPAIR=cross)]) +if test x"$rsync_cv_HAVE_SOCKETPAIR" = x"yes"; then + AC_DEFINE(HAVE_SOCKETPAIR, 1, [define if you have a working socketpair]) +fi + +dnl Checks for structures +AC_CHECK_MEMBER([struct sockaddr_storage.ss_family], + AC_DEFINE(HAVE_SOCKADDR_STORAGE, 1, [define if you have struct sockaddr_storage]),, + [#include <sys/socket.h>]) + +dnl ##### Output +AC_SUBST(docdir) +AC_SUBST(CFLAGS) +AC_SUBST(LDFLAGS) +AC_SUBST(CPPFLAGS) +AC_SUBST(BUILD_POPT) +AC_SUBST(GNOME_BIN) +dnl AC_DEFINE_UNQUOTED(PACKAGE, $PACKAGE, [Package name]) +dnl AC_DEFINE_UNQUOTED(VERSION, $VERSION, [Package version]) +AC_DEFINE_UNQUOTED(GNU_HOST, ["$host"], [Your gnu-style host triple]) +AC_OUTPUT([Makefile] popt/.stamp-conf lzo/.stamp-conf ) + + +##### Finalization + +# Display success, installation paths, and GPL licence statement. +echo ' ' +${MAKE-make} showpaths +echo ' ' +cat <<EOF + + $PACKAGE_NAME $PACKAGE_VERSION configured + + Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. Unauthorized redistribution is + prohibited by law. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +After installing distcc, please complete the survey in the file "survey.txt". + +EOF diff --git a/distcc/contrib/distcc-absolutify b/distcc/contrib/distcc-absolutify new file mode 100644 index 0000000..a3d2beb --- /dev/null +++ b/distcc/contrib/distcc-absolutify @@ -0,0 +1,47 @@ +#! /bin/sh +# Copyright 2002 Free Software Foundation +# by Alexandre Oliva <aoliva@redhat.com> + +# This script is Free Software, and it can be copied, distributed and +# modified as defined in the GNU General Public License. A copy of +# its license can be downloaded from http://www.gnu.org/copyleft/gpl.html + +# This is a wrapper for distcc that turns relative pathnames into +# network-neutral ones. It modifies anything containing a slash and +# not starting with dash or slash, as well as -B flags. We need not +# be concerned about -I and -L, since distcc always does preprocessing +# and linking locally. + + +# If the first pathname is relative (.../xgcc, ./libtool, etc), +case "$1" in +[^/]*/*) + nargs=$# + basedir=`${NETPWD-netpwd}` + # then process arguments + for arg + do + case $arg in + -B[^/]*) + arg=-B$basedir/`echo "X$arg" | sed -e '1s/^X-B//'` + ;; + [^-/]*/*) + arg=$basedir/$arg + ;; + esac + set fnord ${1+"$@"} "$arg" + done + shift $nargs # take list of fnords out + shift $nargs # take original args out + ;; +esac + +# Now run the real distcc thingie, or just run the program directly if +# distcc is found to be missing. +if test -x ${REAL_DISTCC-/usr/bin/distcc}; then + x=${REAL_DISTCC-/usr/bin/distcc} +else + x=$1 + shift +fi +exec $x ${1+"$@"} diff --git a/distcc/contrib/distcc.sh b/distcc/contrib/distcc.sh new file mode 100644 index 0000000..b6b3307 --- /dev/null +++ b/distcc/contrib/distcc.sh @@ -0,0 +1,40 @@ +#! /bin/sh + +# This file, contributed by Dimitri PAPADOPOULOS-ORFANOS <papadopo@shfj.cea.fr> +# may be installed as "cc" somewhere on your $PATH ahead of the real gcc. That +# allows you to just use regular Makefiles without modifying them to change +# hardcoded calls to cc. + +# This script will be a bit slow because of the overhead of running +# things through a shell. In a future release, this function should +# be supported directly by distcc, which should be a bit faster. + +DISTCC_HOME=/usr/local/distcc + +name=`basename $0` + +if [ "$name" = distcc ]; then + echo "In normal use distcc is not called by its real name." 1>&2 + echo "Instead create links to the actual compiler you wish to run, e.g." 1>&2 + echo " ln -s distcc gcc" 1>&2 + echo "and make sure the link is before the real compiler in your path." 1>&2 + exit 1 +fi + +unset found +IFS=: +for item in $PATH; do + if [ -x "$item/$name" -a ! -d "$item/$name" ]; then + if [ `cd $item; /bin/pwd` != `/bin/pwd` ]; then + found=true + break + fi + fi +done + +if [ -n "$found" ]; then + exec "distcc $item/$name $@" +else + echo "$name: not found" 1>&2 +fi +exit 1 diff --git a/distcc/contrib/distccd-init b/distcc/contrib/distccd-init new file mode 100644 index 0000000..46938a2 --- /dev/null +++ b/distcc/contrib/distccd-init @@ -0,0 +1,70 @@ +#! /bin/sh +# +# distccd Debian init.d script contributed by Jason Thomas. (Debian #161136) +# +# skeleton example file to build /etc/init.d/ scripts. +# This file should be used to construct scripts for /etc/init.d. +# +# Written by Miquel van Smoorenburg <miquels@cistron.nl>. +# Modified for Debian GNU/Linux +# by Ian Murdock <imurdock@gnu.ai.mit.edu>. +# +# Version: @(#)skeleton 1.9.1 08-Apr-2002 miquels@cistron.nl +# + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/bin/distccd +NAME=distccd +DESC="Distributed Compiler Daemon" +DAEMON_ARGS="--nice=10 --port=4200 --pid-file=/var/run/$NAME.pid \ + --log-file=/var/log/$NAME.log --daemon" + +test -x $DAEMON || exit 0 + +set -e + +# we need permission to write to the pid file +touch /var/run/$NAME.pid +chown distccd /var/run/$NAME.pid + +case "$1" in + start) + echo -n "Starting $DESC: $NAME" + start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ + --chuid distccd \ + --exec $DAEMON -- $DAEMON_ARGS + echo "." + ;; + stop) + echo -n "Stopping $DESC: $NAME " + start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ + --oknodo \ + --exec $DAEMON + echo "." + ;; + restart|force-reload) + # + # If the "reload" option is implemented, move the "force-reload" + # option to the "reload" entry above. If not, "force-reload" is + # just the same as "restart". + # + echo -n "Restarting $DESC: $NAME" + start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ + --oknodo \ + --exec $DAEMON + sleep 1 + start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ + --chuid distccd \ + --exec $DAEMON -- $DAEMON_ARGS + echo "." + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 + + diff --git a/distcc/contrib/distccd-on-servers b/distcc/contrib/distccd-on-servers new file mode 100755 index 0000000..437171c --- /dev/null +++ b/distcc/contrib/distccd-on-servers @@ -0,0 +1,145 @@ +#! /bin/bash + + +# Copyright 2007 Google Inc. All Rights Reserved. +# +# A script for installing and controlling distccd on servers. +# +# This script allows for easy testing of distcc. It does not depend on +# RPM, debian or other packaging techniques. + + +function Usage { + printf "Usage: server-test {start|stop|restart|install|ps|status}\n\ +Obligatory environment variables:\n\ + DISTCC_LOC Location of distcc, a path of the form ../distcc.\n\ + DISTCCD_MACHINES Hostnames of compiler servers.\n\ + DISTCCD_REMOTE_LOC Path where distcc_pump/distcc resides on servers.\n\ + DISTCCD_ARGS Arguments and options for distccd command on server.\n\ + DISTCCD_TMPDIR Exported to server as TMPDIR before start.\n\ +See script for details.\n\ +" +} + +trap "Usage" EXIT +: ${DISTCC_LOC:?} +: ${DISTCCD_MACHINES:?} +: ${DISTCCD_REMOTE_LOC:?} +: ${DISTCCD_ARGS:?} +: ${DISTCCD_TMPDIR:?} +trap EXIT + + +function Doing { + printf "\nDOING $1\n" +} + + +function Install { + bad_server=0 + for SERVER in $DISTCCD_MACHINES; do + Doing $SERVER + ssh $SERVER "mkdir --parents $DISTCCD_REMOTE_LOC"\ + || { bad_server=$SERVER; continue; } + ssh $SERVER "rm -rf $DISTCCD_REMOTE_LOC/distcc" \ + || { bad_server=$SERVER; continue; } + scp -r -q $DISTCC_LOC $SERVER:$DISTCCD_REMOTE_LOC/distcc \ + || { bad_server=$SERVER:; continue; } + done + if [ "$bad_server" != 0 ]; then + echo "ERROR: installation on $bad_server failed (and maybe others)" 1>&2 + return 1 + fi + return 0 +} + + +function Start { + bad_server=0 + for SERVER in $DISTCCD_MACHINES; do + Doing $SERVER + ssh $SERVER \ + "TMPDIR=$DISTCCD_TMPDIR; $DISTCCD_REMOTE_LOC/distcc/distccd $DISTCCD_ARGS"\ + || { bad_server=$SERVER; continue; } + done + if [ $bad_server != 0 ]; then + echo "ERROR: starting distccd on $bad_server failed (and maybe others)" 1>&2 + return 1 + fi + return 0 +} + + +function Psing { + for SERVER in $DISTCCD_MACHINES; do + Doing $SERVER + ssh $SERVER \ + "ps ux | grep \"$DISTCCD_REMOTE_LOC.*[d]istccd\"" + done +} + + +function Status { + for SERVER in $DISTCCD_MACHINES; do + Doing $SERVER + # The [d] construct prevents the grep command itself from being recognized. + ssh $SERVER \ + "if ps ux | grep -q \" $DISTCCD_REMOTE_LOC/distcc/distcc[d] \"; then\ + echo $SERVER is running distccd;\ + fi;\ + " + done +} + + +function Stop { + for SERVER in $DISTCCD_MACHINES; do + Doing $SERVER + ssh $SERVER \ + "while grep Stopping \ + <(ps ux | grep \"$DISTCCD_REMOTE_LOC.*[d]istcc\" | \ + (read X PID Z; \ + if [ -n \"\$PID\" ]; then\ + echo \"Stopping process\" \$PID; kill \$PID;\ + fi)); do\ + :;\ + done; " + done +} + + + +case "$1" in + start) + echo "Start" + Start + ;; + stop) + echo "Stop" + Stop + ;; + restart) + echo "Restart" + Stop + sleep 1 + Start + ;; + install) + echo "Install" + Install + ;; + status) + echo "Status" + Status + ;; + ps) + echo "Run 'ps'" + Psing + ;; + *) + Usage + exit 1 + ;; +esac + + diff --git a/distcc/contrib/dmake b/distcc/contrib/dmake new file mode 100644 index 0000000..8e0ac85 --- /dev/null +++ b/distcc/contrib/dmake @@ -0,0 +1,16 @@ +#! /bin/sh + +# Example script contributed by Luke Gorrie + +# "Drop-in" front end to 'make' that uses the distributed compile farm +# via `distcc' + +# Compile farm hosts are stored in ~bluetail/distcc-hosts. We exclude +# the local machine to free up resources for preprocessing and +# linking, since it seems to be the bottleneck (at least on +# kookaburra). + +DISTCC_HOSTS=$(sed s/$(hostname -s)// < /home/share/bluetail/distcc-hosts) + +make CC='/home/share/luke/bin/distcc gcc' -j 7 "$@" + diff --git a/distcc/contrib/make-j b/distcc/contrib/make-j new file mode 100644 index 0000000..013484f --- /dev/null +++ b/distcc/contrib/make-j @@ -0,0 +1,21 @@ +#! /bin/sh + +# make-j script from Alexandre Oliva <aoliva@redhat.com> for use with distcc + +# Tests which machines are up, and runs Make with concurrency set +# appropriately. + +hostlist=$DISTCC_HOSTS +distcc_port=4200 +DISTCC_HOSTS= +count=0 +for h in $hostlist; do + echo trying $h... >&2 + if test "x$h" = xlocalhost || nc -z $h $distcc_port; then + echo added $h... >&2 + DISTCC_HOSTS=`echo $DISTCC_HOSTS $h` # remove leading blank + count=`expr $count + 1` + fi +done +export DISTCC_HOSTS +exec make -j $count ${1+"$@"} diff --git a/distcc/contrib/netpwd b/distcc/contrib/netpwd new file mode 100644 index 0000000..863cb6e --- /dev/null +++ b/distcc/contrib/netpwd @@ -0,0 +1,26 @@ +#! /bin/sh +# Copyright 2002 Free Software Foundation +# by Alexandre Oliva <aoliva@redhat.com> + +# This script is Free Software, and it can be copied, distributed and +# modified as defined in the GNU General Public License. A copy of +# its license can be downloaded from http://www.gnu.org/copyleft/gpl.html + +# Turn a local pathname into a network-neutral one. It assumes +# /net/$HOSTNAME/pathname can access $HOSTNAME's /pathname from other +# machines, and that /net/$HOSTNAME is actually mounted (by amd) +# inside /.automount/$HOSTNAME/root, so it compensates for that. + +dir=`${REAL_PWD-pwd}` +case $dir in +/net/*) + ;; +/.automount/*/root/*) + dir=/net/`echo "$dir" | sed -e '1s,^/\.automount/,,' -e 's,/root/,/,'` + ;; +*) + dir=/net/${HOSTNAME-`uname -n`}$dir + ;; +esac +echo $dir +exit 0 diff --git a/distcc/contrib/redhat/init b/distcc/contrib/redhat/init new file mode 100644 index 0000000..4df2f6e --- /dev/null +++ b/distcc/contrib/redhat/init @@ -0,0 +1,83 @@ +#!/bin/sh +# +# Init file for Distccd - A distributed compilation front-end. +# WARNING: Don't enable on untrusted networks +# +# Written by Dag Wieers <dag@wieers.com>. +# +# chkconfig: - 80 20 +# description: Distccd - distributed compilation front-end (daemon) \ +# WARNING: Don't enable on untrusted networks +# +# processname: distccd +# +# config: /etc/sysconfig/distccd + +source /etc/init.d/functions +source /etc/sysconfig/network + +### Check that networking is up. +[ "${NETWORKING}" == "no" ] && exit 0 + +[ -x "/usr/bin/distccd" ] || exit 1 + +### Default variables +SYSCONFIG="/etc/sysconfig/distccd" +OPTIONS="" +USER="distcc" +DISTCCPATH="$PATH" + +### Read configuration +[ -r "$SYSCONFIG" ] && source "$SYSCONFIG" + +RETVAL=0 +prog="distccd" +desc="Distributed Compiler daemon" + +start() { + echo -n $"Starting $desc ($prog): " + PATH="$DISTCCPATH" daemon --user "$USER" $prog --daemon --log-file="/var/log/distccd.log" $OPTIONS + RETVAL=$? + echo + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$prog + return $RETVAL +} + +stop() { + echo -n $"Shutting down $desc ($prog): " + killproc $prog + RETVAL=$? + echo + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$prog + return $RETVAL +} + +restart() { + stop + start +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart|reload) + restart + ;; + condrestart) + [ -e /var/lock/subsys/$prog ] && restart + RETVAL=$? + ;; + status) + status $prog + RETVAL=$? + ;; + *) + echo $"Usage $0 {start|stop|restart|condrestart|status}" + RETVAL=1 +esac + +exit $RETVAL diff --git a/distcc/contrib/redhat/logrotate b/distcc/contrib/redhat/logrotate new file mode 100644 index 0000000..edbecae --- /dev/null +++ b/distcc/contrib/redhat/logrotate @@ -0,0 +1,5 @@ +/var/log/distccd.log { + missingok + copytruncate + notifempty +} diff --git a/distcc/contrib/redhat/sysconfig b/distcc/contrib/redhat/sysconfig new file mode 100644 index 0000000..a5ad5bd --- /dev/null +++ b/distcc/contrib/redhat/sysconfig @@ -0,0 +1,8 @@ +### See distcc(1) manual page for more information on these options. +### + +#OPTIONS="--nice 5 --jobs 5 --allow 10.0.0.0/24 --port 1234" +#USER="distcc" + +### Set this if don't want distccd to use gcc or g++ by accident. +#DISTCCPATH="/usr/lib/distcc/bin" diff --git a/distcc/contrib/redhat/xinetd b/distcc/contrib/redhat/xinetd new file mode 100644 index 0000000..023f390 --- /dev/null +++ b/distcc/contrib/redhat/xinetd @@ -0,0 +1,17 @@ +# default: off +# description: Distccd - distributed compilation front-end (xinetd) \ +# Please disable the daemon if you enable this. \ +# WARNING: Don't enable on untrusted networks +service distccd +{ + disable = yes + socket_type = stream + protocol = tcp + port = 3632 + type = UNLISTED + wait = no + user = distcc + server = /usr/bin/distccd + server_args = --inetd --log-file="/var/log/distccd.log" + only_from = 127.0.0.1 +} diff --git a/distcc/contrib/stage-cc-wrapper.patch b/distcc/contrib/stage-cc-wrapper.patch new file mode 100644 index 0000000..cb3d004 --- /dev/null +++ b/distcc/contrib/stage-cc-wrapper.patch @@ -0,0 +1,81 @@ +Index: Makefile.in +=================================================================== +RCS file: /cvs/gcc/egcs/Makefile.in,v +retrieving revision 1.110 +diff -u -p -r1.110 Makefile.in +--- Makefile.in 8 Jul 2002 21:40:41 -0000 1.110 ++++ Makefile.in 14 Aug 2002 02:49:35 -0000 +@@ -251,7 +251,7 @@ GCJ_FOR_TARGET = + # variable is passed down to the gcc Makefile, where it is used to + # build libgcc2.a. We define it here so that it can itself be + # overridden on the command line. +-GCC_FOR_TARGET = $$r/gcc/xgcc -B$$r/gcc/ $(FLAGS_FOR_TARGET) ++GCC_FOR_TARGET = $(STAGE_CC_WRAPPER) $$r/gcc/xgcc -B$$r/gcc/ $(FLAGS_FOR_TARGET) + + AS_FOR_TARGET = ` \ + if [ -f $$r/gas/as-new ] ; then \ +Index: configure.in +=================================================================== +RCS file: /cvs/gcc/egcs/configure.in,v +retrieving revision 1.176 +diff -u -p -r1.176 configure.in +--- configure.in 6 Aug 2002 09:26:29 -0000 1.176 ++++ configure.in 14 Aug 2002 02:49:38 -0000 +@@ -1554,10 +1554,10 @@ cat >$sedtemp <<EOF + s:^TARGET_CONFIGDIRS[ ]*=.*$:TARGET_CONFIGDIRS = ${target_configdirs}: + s%^TARGET_CONFIGARGS[ ]*=.*$%TARGET_CONFIGARGS = ${targargs}% + s%^FLAGS_FOR_TARGET[ ]*=.*$%FLAGS_FOR_TARGET = ${FLAGS_FOR_TARGET}% +-s%^CC_FOR_TARGET[ ]*=.*$%CC_FOR_TARGET = ${CC_FOR_TARGET}% +-s%^GCJ_FOR_TARGET[ ]*=.*$%GCJ_FOR_TARGET = ${GCJ_FOR_TARGET}% +-s%^CXX_FOR_TARGET[ ]*=.*$%CXX_FOR_TARGET = ${qCXX_FOR_TARGET}% +-s%^CXX_FOR_TARGET_FOR_RECURSIVE_MAKE[ ]*=.*$%CXX_FOR_TARGET_FOR_RECURSIVE_MAKE = ${qqCXX_FOR_TARGET}% ++s%^CC_FOR_TARGET[ ]*=.*$%CC_FOR_TARGET = \$(STAGE_CC_WRAPPER) ${CC_FOR_TARGET}% ++s%^GCJ_FOR_TARGET[ ]*=.*$%GCJ_FOR_TARGET = \$(STAGE_CC_WRAPPER) ${GCJ_FOR_TARGET}% ++s%^CXX_FOR_TARGET[ ]*=.*$%CXX_FOR_TARGET = \$(STAGE_CC_WRAPPER) ${qCXX_FOR_TARGET}% ++s%^CXX_FOR_TARGET_FOR_RECURSIVE_MAKE[ ]*=.*$%CXX_FOR_TARGET_FOR_RECURSIVE_MAKE = \$(STAGE_CC_WRAPPER) ${qqCXX_FOR_TARGET}% + s%^TARGET_SUBDIR[ ]*=.*$%TARGET_SUBDIR = ${target_subdir}% + s%^BUILD_SUBDIR[ ]*=.*$%BUILD_SUBDIR = ${build_subdir}% + s%^BUILD_CONFIGARGS[ ]*=.*$%BUILD_CONFIGARGS = ${buildargs}% +Index: gcc/Makefile.in +=================================================================== +RCS file: /cvs/gcc/egcs/gcc/Makefile.in,v +retrieving revision 1.933 +diff -u -p -r1.933 Makefile.in +--- gcc/Makefile.in 13 Aug 2002 23:11:37 -0000 1.933 ++++ gcc/Makefile.in 14 Aug 2002 02:49:43 -0000 +@@ -175,7 +175,7 @@ USER_H = $(srcdir)/ginclude/stdarg.h $(s + # The GCC to use for compiling libgcc.a and crt*.o. + # Usually the one we just built. + # Don't use this as a dependency--use $(GCC_PASSES) or $(GCC_PARTS). +-GCC_FOR_TARGET = ./xgcc -B./ -B$(build_tooldir)/bin/ -isystem $(build_tooldir)/include -isystem $(build_tooldir)/sys-include ++GCC_FOR_TARGET = $(STAGE_CC_WRAPPER) ./xgcc -B./ -B$(build_tooldir)/bin/ -isystem $(build_tooldir)/include -isystem $(build_tooldir)/sys-include + + # This is used instead of ALL_CFLAGS when compiling with GCC_FOR_TARGET. + # It omits XCFLAGS, and specifies -B./. +@@ -3330,7 +3330,7 @@ stage1_copy: stage1_build + echo stage2_build > stage_last + + stage2_build: stage1_copy +- $(MAKE) CC="stage1/xgcc$(exeext) -Bstage1/ -B$(build_tooldir)/bin/" \ ++ $(MAKE) CC="$(STAGE_CC_WRAPPER) stage1/xgcc$(exeext) -Bstage1/ -B$(build_tooldir)/bin/" \ + STAGE_PREFIX=stage1/ \ + $(STAGE2_FLAGS_TO_PASS) + $(STAMP) stage2_build +@@ -3342,7 +3342,7 @@ stage2_copy: stage2_build + echo stage3_build > stage_last + + stage3_build: stage2_copy +- $(MAKE) CC="stage2/xgcc$(exeext) -Bstage2/ -B$(build_tooldir)/bin/" \ ++ $(MAKE) CC="$(STAGE_CC_WRAPPER) stage2/xgcc$(exeext) -Bstage2/ -B$(build_tooldir)/bin/" \ + STAGE_PREFIX=stage2/ \ + $(STAGE2_FLAGS_TO_PASS) + $(STAMP) stage3_build +@@ -3355,7 +3355,7 @@ stage3_copy: stage3_build + echo stage4_build > stage_last + + stage4_build: stage3_copy +- $(MAKE) CC="stage3/xgcc$(exeext) -Bstage3/ -B$(build_tooldir)/bin/" \ ++ $(MAKE) CC="$(STAGE_CC_WRAPPER) stage3/xgcc$(exeext) -Bstage3/ -B$(build_tooldir)/bin/" \ + STAGE_PREFIX=stage3/ \ + $(STAGE2_FLAGS_TO_PASS) + $(STAMP) stage4_build diff --git a/distcc/doc/example/init b/distcc/doc/example/init new file mode 100644 index 0000000..e6ff03a --- /dev/null +++ b/distcc/doc/example/init @@ -0,0 +1,80 @@ +#! /bin/sh +# +# chkconfig: - 60 20 +# description: The distcc deamon +# http://distcc.samba.org +# +# processname: distccd + +# This is a Red Hat init.d file to start distccd. To install it, copy +# it into /etc/init.d/distccd, and add appropriate links into the +# rc?.d directories. + +# It may need to be tweaked for other distributions or versions. + +# You may wish to accept parameters from the user to set access +# control options. + + + +# Get config. +. /etc/sysconfig/network + +# Get functions +. /etc/init.d/functions + +# Check that networking is up. +if [ ${NETWORKING} = "no" ] ; then + exit 0 +fi + +RETVAL=0 +SERVICE=distccd + +start() { + echo -n $"Starting $SERVICE: " + daemon /usr/local/bin/$SERVICE --daemon + RETVAL=$? + echo + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$SERVICE + return $RETVAL +} + +stop() { + echo -n $"Stopping $SERVICE: " + killproc $SERVICE + RETVAL=$? + echo + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$SERVICE + return $RETVAL +} + +restart() { + stop + start +} + +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + status $SERVICE + ;; + restart) + restart + ;; + condrestart) + [ -f /var/lock/subsys/$SERVICE ] && restart || : + ;; + *) + echo $"Usage: $0 {start|stop|status|restart}" + exit 1 + ;; +esac + +exit $? diff --git a/distcc/doc/example/init-suse b/distcc/doc/example/init-suse new file mode 100644 index 0000000..cf9665f --- /dev/null +++ b/distcc/doc/example/init-suse @@ -0,0 +1,96 @@ +#! /bin/sh +# +# Copyright (C) 2002 C. Brandon Forehand +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# /etc/init.d/distcc +# +# and symbolic link +# +# /usr/sbin/rcdistcc +# +### BEGIN INIT INFO +# Provides: distccd +# Required-Start: $network +# Required-Stop: $network +# Default-Start: 3 5 +# Default-Stop: 0 1 2 6 +# Description: Start the distcc daemon +### END INIT INFO + +. /etc/rc.status +. /etc/rc.config + +# Determine the base and follow a runlevel link name. +base=${0##*/} +link=${base#*[SK][0-9][0-9]} + +DISTCC=/usr/local/bin/distccd +DISTCC_OPTS=--daemon +DISTCC_USER=daemon + +# Shell functions sourced from /etc/rc.status: +# rc_check check and set local and overall rc status +# rc_status check and set local and overall rc status +# rc_status -v ditto but be verbose in local rc status +# rc_status -v -r ditto and clear the local rc status +# rc_failed set local and overall rc status to failed +# rc_reset clear local rc status (overall remains) +# rc_exit exit appropriate to overall rc status + +# First reset status of this service +rc_reset +case "$1" in + start) + echo -n "Starting distcc daemon" + ## Start daemon with startproc(8). If this fails + ## the echo return value is set appropriate. + + startproc -u $DISTCC_USER $DISTCC $DISTCC_OPTS + + # Remember status and be verbose + rc_status -v + ;; + stop) + echo -n "Shutting down distcc daemon:" + ## Stop daemon with killproc(8) and if this fails + ## set echo the echo return value. + + killproc -TERM $DISTCC + + # Remember status and be verbose + rc_status -v + ;; + restart) + ## If first returns OK call the second, if first or + ## second command fails, set echo return value. + $0 stop && $0 start + + # Remember status and be quiet + rc_status + ;; + reload) + $0 restart + + # Remember status and be verbose + rc_status -v + ;; + status) + echo -n "Checking for service distccd: " + checkproc $DISTCC && echo OK || echo No process + ;; + *) + echo "Usage: $0 {start|stop|status|restart|reload}" + exit 1 + ;; +esac +rc_exit diff --git a/distcc/doc/example/logrotate b/distcc/doc/example/logrotate new file mode 100644 index 0000000..2bfe1eb --- /dev/null +++ b/distcc/doc/example/logrotate @@ -0,0 +1,12 @@ +# logrotate.d example configuration for distcc, contributed by Dag +# Wieers. + +# The "copytruncate" option means distcc can keep appending to the +# same filehandle. You would otherwise need to shut down and restart +# distccd. + +/var/log/distccd.log { + missingok + copytruncate + notifempty +}
\ No newline at end of file diff --git a/distcc/doc/example/xinetd b/distcc/doc/example/xinetd new file mode 100644 index 0000000..096dcf4 --- /dev/null +++ b/distcc/doc/example/xinetd @@ -0,0 +1,26 @@ +# default: off + +# xinetd service description for distcc, contributed by akpm, updated +# by mbp. + +# To use this, just check the parameters below and copy this file into +# /etc/xinet.d/distcc, or the appropriate location for your system, +# and then restart xinetd. You should also create a 'distcc' user. + +# ===> Note that running from inetd is generally NOT recommended for +# distcc distccd should give better performance when it can run as a +# standalone daemon and regulate its own load. + +service distcc +{ + disable = yes + socket_type = stream + wait = no + user = distcc + server = /usr/local/bin/distccd + server_args = --inetd + + # This makes xinetd cope if there is no service listed in + # /etc/services + type = UNLISTED +} diff --git a/distcc/doc/protocol-1.txt b/distcc/doc/protocol-1.txt new file mode 100644 index 0000000..37f9aed --- /dev/null +++ b/distcc/doc/protocol-1.txt @@ -0,0 +1,213 @@ +description of distcc protocol version 1 +Copyright (C) 2003 by Martin Pool + +disclaimer +---------- + +This document is provided as explanation for people developing or +debugging distcc. Discrepancies between this document and the distcc +code are an error in the document. + +This document is intended to describe distcc 2.0. + +Because this program and document is licensed free of charge, there is +no warranty of any kind, to the extent permitted by applicable law. + +If anything is unclear, please ask on the mailing list. + + +purpose +------- + +The distcc protocol allows a compiler command line plus C preprocessed +source code to be transmitted from a client computer to a server, +where it is compiled. The results (object code, exit status, and/or +error messages) are returned to the client. + + +protocol versioning +------------------- + +This document describes version 1 of the protocol, which is used by +distcc releases up to and including 2.1. + +Future versions of the protocol may vary in any way. + +The client begins its request by identifying the protocol version that +it will use. The server must either respond using the requested +protocol version, or respond with an error in the appropriate protocol +version, or drop the connection. + +There is no mechanisms for negotiation of versions. + +It is envisaged that when software using a new protocol is released, +users will upgrade both clients and servers at the same time. Since +distcc is only used within organizations rather than on the internet +this should be realistic. + + +foundations +----------- + +The distcc protocol runs over a bidirectional non-delimited byte +channel. This is normally a TCP connection, although operation over +the OpenSSH secure shell is also supported. + +Each compilation of a file ("job") corresponds to one invocation of +the client program and connection. + + +control flow +------------ + +The overall structure of the protocol is very simple: + + 1: The client opens a connection, which is accepted by the server. + + 2: The client sends a request. + + 3: The server sends a response. + + 4: The client and server mutually close the connection. + + +connections +----------- + +Connections are initiated by the client. TCP connections are opened +by connecting to the server port, normally 3632. SSH connections are +initiated by running the command "distccd --inetd" over SSH. + +Either party (client or server) may drop the connection at any point, +in which case the job is discarded by both parties. In particular, +the server drops the connection if the client's IP address is not +allowed to connect, or if the client makes a protocol error. + + +packets +------- + +The request and response both consist of a series of packets. Each +packet consists of two or three parts: + + token -- four ascii bytes, defining the type of the packet + + parameter -- eight ascii hexadecimal digits, corresponding to a + 32-bit unsigned quantity + + body -- optionally present, depending on the token + +The sequence in which tokens are sent by both client and server is +always fixed and is specified by this document. + +If the type of packet (determined by the token) requires a body, then +the length of the body is given by the parameter. Otherwise, the +meaning of the parameter depends on the token. + +Closing the channel has no meaning and does not indicate the end of a +packet, although it should correspond with the end of the last packet. +An early close indicates an error. + +[note: Because the sequence of tokens never varies they are strictly +redundant: each party could just read the parameters and bodies in +order and know what they mean from context. Sending the tokens +provides a check that both parties understand the data to mean the +same thing and guards against code or network errors. It also aids +any person examining the network stream.] + +[note: Sending the parameter as hexadecimal is redundant, because four +bytes would be sufficient to encode the 32-bit integer. Sending as +hexadecimal serves as a futher check that the client and server are +synchronized. Incorrect values for the parameter are detected as a +program or network error.] + +[note: The fixed length of the token and length-preceded body allows +IO with a small number of system calls: the header can be read in +exactly twelve bytes, and the body can be read in a single chunk +without needing to parse its contents.] + +[note: The length-preceded format means that data cannot be streamed +out until the process that produced it is complete and the length of +the data is known.] + + +request +------- + +The following packets comprise the request: + +DIST <version> + + Greeting from client, followed by the protocol version, which is + always 1. + +ARGC <nargs> + + Specifies the number of arguments in the command, including the + compiler name. + +ARGV <len> <bytes> + + Repeated <nargs> times. Specifies the string value of one element + of the command. + +DOTI <len> <bytes> + + The contents of the preprocessed source (.i) file. + + +response +-------- + +The following packets comprise the response: + +DONE <version> + + Introduces the response. The version must be 1. + +STAT <status> + + Gives the Unix wait status of the compiler. This 0 for success, + or otherwise (EXITCODE << 8) | (TERMSIGNAL), depending on whether + the compiler returned an error or was terminated by a signal. + (See <sys/wait.h> or a POSIX standard for a full definition.) + +SERR <len> <bytes> + + Contains messages sent to stderr by the compiler. + +SOUT <len> <bytes> + + Contains messages sent to stdout by the compiler. Normally empty + -- errors and warnings for most compilers go to stderr instead. + +DOTO <len> <bytes> + + Contains the object file (.o) produced by the compiler. + + In very early versions, this is missing if the status code is not + zero. + + In versions up to and including 2.7.1, zero-length output files + are not supported. If compilation fails, then the server sends + the file with a length of zero, but the client does not read it. + + From 2.8, things work as follows: + + regular success: + status zero + length nonzero + + succeeded, but zero-byte output: + status zero + length zero + output file is created/touched + + failed: + status nonzero + length sent as zero + + This is a little complex but is compatible with earlier releases. + + This does mean we cannot represent a compiler that produces output + and then fails, but I don't think that is very important. diff --git a/distcc/doc/protocol-2.txt b/distcc/doc/protocol-2.txt new file mode 100644 index 0000000..ab13860 --- /dev/null +++ b/distcc/doc/protocol-2.txt @@ -0,0 +1,38 @@ +description of distcc protocol version 2 +Copyright (C) 2003 by Martin Pool + +disclaimer +---------- + +This document is provided as explanation for people developing or +debugging distcc. Discrepancies between this document and the distcc +code are an error in the document. + +This document is intended to describe distcc 2.9. + +Because this program and document is licensed free of charge, there is +no warranty of any kind, to the extent permitted by applicable law. + +If anything is unclear, please ask on the mailing list. + + +protocol +-------- + +Protocol 2 is a variation of protocol 1. It gets a new version number +because that's the simplest way to indicate the change. + +The protocol number (DIST) sent by the client is set to 2. The server +must respond (DONE) in version 2. + +The content of the "bulk" tokens (DOTI, DOTO, SERR, SOUT) are +compressed using the LZO1X algorithm. + +The token parameter gives the length of the compressed form. + +As a special case, if the uncompressed form is zero bytes, then it is +not compressed but rather sent directly as zero bytes. (Compression +slightly expands a zero byte string.) + +The distcc client and server can handle either protocol 1 or 2 +depending on whether the user configures compression on. diff --git a/distcc/doc/protocol-3-impl.txt b/distcc/doc/protocol-3-impl.txt new file mode 100644 index 0000000..3f7196b --- /dev/null +++ b/distcc/doc/protocol-3-impl.txt @@ -0,0 +1,61 @@ +A list of the important changes done to distcc to support protocol version 3. +More or less in dataflow order. +Does not include various little changes, making functions from static into +global, all around the code; a bug fix in argutil.c, etc. + + - A new protocol version (3) is added. It + supports preprocessing on the server. It also transmits + bulky data compressed, like protocol version 2. + - distcc.h: Added the enum for where to do the cpp. + - hosts.c: Map a set of features (currently a subset of + where to do cpp and whether to do compression) onto + a protocol number. + - rpc.c: The client sometimes sends either a file or + a link to the server. The server needs to be able to + accept either, so dcc_r_sometoken_int introduces some + alternation to the protocol. + - Talking to the include server: + - compile.c: dcc_build_somewhere tries to talk to the + include server, and pushes the information about + the dotd file to dcc_compile_remote. This is where + the fallback-to-the-original-protocol code lives. + - include_server_if.c: Talk to the include server. + - The communication from client to server. The client needs to + send multiple files, and perhaps links, to the server; the + client also needs to send its current working directory, + - remote.c: Entry points for sending multiple files to + the server. + - rpc.c: The server needs to handle not only files, but also + links (directories are handled implicitly). + - clirpc.c: Added a function to send the current working + directory. Added a function, dcc_x_many_files. It sends + multiple files to the server. In addition, it changes + the filenames to chop off the additions of the include + server. + - serve.c: Added a function to receive the current working + directory. + - On the server side, the server receives multiple files, + and the working directory, builds a directory structure + (which it keeps a manifest of, to clean it up at the end) + - srvrpc.c: + Added a function, dcc_r_many_files, to receive multiple + files. In addition, it changes the filenames to put all + the files under a "fake root" directory. + - serve.c: lots of work to set up "fake root" directories, + chdir to the right place, produce a .d file, and + absolutize include directives. + - tempfile.c: Creation of whole temp directories, + not just files. + - cleanup.c: Since we are receiving multiple files, + we need to keep a dynamic list of what temporary + files we create. It can now handle directories. + - ".d" files: the client needs to find out where the dotd file + should go; the server needs to produce it, remove all + references to its (the server's) local filesystem (there are no + gcc options to do this) and send it back to the client. + - dotd.c: Most of the code that handles the dotd: figuring + out if we need it, and where it should go; also, + cleaning it up after it gets created on the server. + - clirpc.c Changed dcc_retrieve_results to retrieve + the dotd file. + diff --git a/distcc/doc/protocol-3.txt b/distcc/doc/protocol-3.txt new file mode 100644 index 0000000..33a879e --- /dev/null +++ b/distcc/doc/protocol-3.txt @@ -0,0 +1,82 @@ +description of distcc protocol version 3 +copyright (C) 2007 Google, Inc + +disclaimer +---------- + +This document is provided as explanation for people developing or +debugging distcc. Discrepancies between this document and the distcc +code are an error in the document. + +protocol +-------- + +Protocol 3 is a significant extension to protocol 2. It is used to send +not the preprocessed file, but enough information to do the preprocessing +on the server. + +The low level protocol (connecting, responding, encoding of short strings, +encoding of numbers, etc.) is the same as with protocols 1/2. Files are sent +compressed, just as with protocol 2. + +The protocol number (DIST) sent by the client is set to 3. The server +must respond (DONE) in version 3. + +request +------- + +Protocol version 3 introduces a alternation point, between LINK and FILE. +Thus, in this version the tags are not purely decorative, as in the previous +protocols. + +The following packets comprise the request: + +DIST <version> + + Version is 3. + +CDIR <len> <bytes> + + The working directory on the client side. Sent just like any ARGV in + protocol versions 1/2. + +ARGC <nargs> + Just like in protocol versions 1/2. + +ARGV <len> <bytes> + Just like in protocol versions 1/2. + +NFIL <nfiles> + How many files or links will be sent. Similar to ARGC. + +NAME <len> <bytes> + The (absolute, crossing-no-symlinks) name of the next file/link to be + sent. Similar to any ARGV. + +FILE <len> <bytes> + The contents of the file. Similar to DOTI in protocol version 2. + +LINK <len> <bytes> + The contents of (the file name pointed to by) a link. Similar to any + ARGV. + +response +-------- + +Exactly as for protocol version 2, but with the following addition at the +end. + +DOTD <len> <bytes> + The contents of the result .d file. Similar to DOTO. + +Notes +----- + +This protocol is most useful in conjuction with an "include server" that +discovers, for each compilation unit, the list of needed files without +actually preprocessing. The protocol for talking to the include server +is simple: distcc sends a CWD packet, and an ARGC/ARGV sequence with the +command line, and receives an ARGC/ARGV sequence with the needed files. + +Ideally, compression of files should be independent of whether preprocessing +happens on the server or on the client. That's not currently true though. diff --git a/distcc/doc/reporting-bugs.txt b/distcc/doc/reporting-bugs.txt new file mode 100644 index 0000000..11726d2 --- /dev/null +++ b/distcc/doc/reporting-bugs.txt @@ -0,0 +1,73 @@ +How to report bugs in distcc -*- indented-text -*- + + +If you are having trouble with distcc, please send email to +distcc@lists.samba.org. Please don't send mail direct to the author: +if you use the list, other people may be able to help you faster and +the answers are archived to help others. + + + * The first aim of a bug report is to let the programmer see the + failure with their own eyes. If you can't be with them to make it + fail in front of them, give them detailed instructions so that + they can make it fail for themselves. + + * In case the first aim doesn't succeed, and the programmer can't + see it failing themselves, the second aim of a bug report is to + describe what went wrong. Describe everything in detail. State + what you saw, and also state what you expected to see. Write down + the error messages, especially if they have numbers in. + + * By all means try to diagnose the fault yourself if you think you + can, but if you do, you should still report the symptoms as well. + + * Write clearly. Say what you mean, and make sure it can't be + misinterpreted. + + * Above all, be precise. + +A good bug report for distcc should include these details: + + * What version of distcc you're using, e.g. "2.7.1". If you got it + from a distribution package rather than building from source, + please say so. + + * Your platform (e.g. "Red Hat 8.0", "HP-UX 11.11") and compiler + "gcc 3.3" + + * What you're trying to do: e.g. "install distcc", "build Mozilla", + "build my own program". + + * What went wrong: e.g. did you get an error message, did it hang, + did it build a program that didn't work, did it not distribute + compilation to machines that ought to get it? You'd be surprised + how many people don't say what actually happened. + + * If you have an example of a compiler invocation that failed, quote + it, e.g.: + + distcc gcc -DHAVE_CONFIG_H -D_GNU_SOURCE -I./src \ + "-DSYSCONFDIR=\"/etc/\"" -I./lzo -g -O2 -W -Wall -W \ + -Wimplicit -Wshadow -Wpointer-arith -Wcast-align \ + -Wwrite-strings -Waggregate-return -Wstrict-prototypes \ + -Wmissing-prototypes -Wnested-externs -o src/clirpc.o \ + -c src/clirpc.c + + * Turn on client and server error logging. On the client, set these + environment variables, and try to reproduce the problem: + + export DISTCC_VERBOSE=1 DISTCC_LOG=/tmp/distcc.log + + Start the server with the --verbose option. If the problem is + intermittent, leave logging enabled and then pull out the lines + from the log file when the problem recurs. + + * If you got an error message on stderr, quote that error exactly. + Find the lines in the log files pertaining to the compile, and + include all of them in your report, by looking at the process ID + in square brackets. If you can't work that out, quote the last + few hundred lines leading up to the failure. + +An error report with all the necessary details is often answered and +resolved within two days or less. If you don't include enough +information to know what is going wrong it can take much longer. diff --git a/distcc/doc/status-1.txt b/distcc/doc/status-1.txt new file mode 100644 index 0000000..9c1e2c5 --- /dev/null +++ b/distcc/doc/status-1.txt @@ -0,0 +1,64 @@ +description of distcc status indicators, version 1 +Copyright (C) 2003 by Martin Pool + +purpose +------- + +This file describes a mooted design for a mechanism for distcc to +indicate its status for the benefit of a separate display program. +This is an external protocol so that there can be different +implementations of status monitors to suit different purposes. + +The protocol is supposed to stay stable for some time to allow people +to write their own monitors. + + +interface +--------- + +The programming interface to this is through the functions in +mon.c/mon.h. Monitor applications should not access the files +directly. + + +state +----- + +The state of a compiler process is described in a few variables + + cpid Process ID of the client + + state String describing its progress in compilation + + file Short source filename + + host Host definition being used + +File or host may be empty strings if they are not yet known. + + +states +------ + +The following states are defined. The list may change in later +releases. + +In 2.6 the client progresses through these states in order, although +not all states may be reached by any particular process. + + Startup Examining command line, host definition and other + settings, and finding a host to use. + + Starved Waiting because all defined hosts are completely busy. + + Connect Opening a TCP or SSH connection to the host and sending + the first part of the request. + + Preprocessor Waiting for the preprocessor to complete. + + Send Sending the preprocessed source. + + Compile Waiting for a local or remote compiler to complete. + + Receive Receiving compilation results. + diff --git a/distcc/gnome/distccmon-gnome-icon.png b/distcc/gnome/distccmon-gnome-icon.png Binary files differnew file mode 100644 index 0000000..fe2db53 --- /dev/null +++ b/distcc/gnome/distccmon-gnome-icon.png diff --git a/distcc/gnome/distccmon-gnome.desktop b/distcc/gnome/distccmon-gnome.desktop new file mode 100644 index 0000000..e5bb319 --- /dev/null +++ b/distcc/gnome/distccmon-gnome.desktop @@ -0,0 +1,13 @@ +[Desktop Entry] +Version=0.9.4 +Encoding=UTF-8 +Exec=distccmon-gnome +Name=distcc monitor +GenericName=Distributed Compile Monitor +Comment=Graphical view of distributed compile tasks +Icon=distccmon-gnome-icon.png +TryExec=distccmon-gnome +Terminal=false +Type=Application +Categories=GNOME;Application;Development; +StartupNotify=true diff --git a/distcc/install-sh b/distcc/install-sh new file mode 100755 index 0000000..e9de238 --- /dev/null +++ b/distcc/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/distcc/lzo/.stamp-conf.in b/distcc/lzo/.stamp-conf.in new file mode 100644 index 0000000..e48829e --- /dev/null +++ b/distcc/lzo/.stamp-conf.in @@ -0,0 +1 @@ +@src_dir@ diff --git a/distcc/lzo/lzoconf.h b/distcc/lzo/lzoconf.h new file mode 100644 index 0000000..96db180 --- /dev/null +++ b/distcc/lzo/lzoconf.h @@ -0,0 +1,451 @@ +/* lzoconf.h -- configuration for the LZO real-time data compression library + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + <markus@oberhumer.com> + http://www.oberhumer.com/opensource/lzo/ + */ + + +#ifndef __LZOCONF_H +#define __LZOCONF_H + +#define LZO_VERSION 0x1080 +#define LZO_VERSION_STRING "1.08" +#define LZO_VERSION_DATE "Jul 12 2002" + +/* internal Autoconf configuration file - only used when building LZO */ +#if defined(LZO_HAVE_CONFIG_H) +# include <config.h> +#endif +#include <limits.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +/*********************************************************************** +// LZO requires a conforming <limits.h> +************************************************************************/ + +#if !defined(CHAR_BIT) || (CHAR_BIT != 8) +# error "invalid CHAR_BIT" +#endif +#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX) +# error "check your compiler installation" +#endif +#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1) +# error "your limits.h macros are broken" +#endif + +/* workaround a cpp bug under hpux 10.20 */ +#define LZO_0xffffffffL 4294967295ul + +#if !defined(LZO_UINT32_C) +# if (UINT_MAX < LZO_0xffffffffL) +# define LZO_UINT32_C(c) c ## UL +# else +# define LZO_UINT32_C(c) c ## U +# endif +#endif + + +/*********************************************************************** +// architecture defines +************************************************************************/ + +#if !defined(__LZO_WIN) && !defined(__LZO_DOS) && !defined(__LZO_OS2) +# if defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows) +# define __LZO_WIN +# elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) +# define __LZO_WIN +# elif defined(__NT__) || defined(__NT_DLL__) || defined(__WINDOWS_386__) +# define __LZO_WIN +# elif defined(__DOS__) || defined(__MSDOS__) || defined(MSDOS) +# define __LZO_DOS +# elif defined(__OS2__) || defined(__OS2V2__) || defined(OS2) +# define __LZO_OS2 +# elif defined(__palmos__) +# define __LZO_PALMOS +# elif defined(__TOS__) || defined(__atarist__) +# define __LZO_TOS +# endif +#endif + +#if (UINT_MAX < LZO_0xffffffffL) +# if defined(__LZO_WIN) +# define __LZO_WIN16 +# elif defined(__LZO_DOS) +# define __LZO_DOS16 +# elif defined(__LZO_PALMOS) +# define __LZO_PALMOS16 +# elif defined(__LZO_TOS) +# define __LZO_TOS16 +# elif defined(__C166__) +# else + /* porting hint: for pure 16-bit architectures try compiling + * everything with -D__LZO_STRICT_16BIT */ +# error "16-bit target not supported - contact me for porting hints" +# endif +#endif + +#if !defined(__LZO_i386) +# if defined(__LZO_DOS) || defined(__LZO_WIN16) +# define __LZO_i386 +# elif defined(__i386__) || defined(__386__) || defined(_M_IX86) +# define __LZO_i386 +# endif +#endif + +#if defined(__LZO_STRICT_16BIT) +# if (UINT_MAX < LZO_0xffffffffL) +# include <lzo16bit.h> +# endif +#endif + +/* memory checkers */ +#if !defined(__LZO_CHECKER) +# if defined(__BOUNDS_CHECKING_ON) +# define __LZO_CHECKER +# elif defined(__CHECKER__) +# define __LZO_CHECKER +# elif defined(__INSURE__) +# define __LZO_CHECKER +# elif defined(__PURIFY__) +# define __LZO_CHECKER +# endif +#endif + + +/*********************************************************************** +// integral and pointer types +************************************************************************/ + +/* Integral types with 32 bits or more */ +#if !defined(LZO_UINT32_MAX) +# if (UINT_MAX >= LZO_0xffffffffL) + typedef unsigned int lzo_uint32; + typedef int lzo_int32; +# define LZO_UINT32_MAX UINT_MAX +# define LZO_INT32_MAX INT_MAX +# define LZO_INT32_MIN INT_MIN +# elif (ULONG_MAX >= LZO_0xffffffffL) + typedef unsigned long lzo_uint32; + typedef long lzo_int32; +# define LZO_UINT32_MAX ULONG_MAX +# define LZO_INT32_MAX LONG_MAX +# define LZO_INT32_MIN LONG_MIN +# else +# error "lzo_uint32" +# endif +#endif + +/* lzo_uint is used like size_t */ +#if !defined(LZO_UINT_MAX) +# if (UINT_MAX >= LZO_0xffffffffL) + typedef unsigned int lzo_uint; + typedef int lzo_int; +# define LZO_UINT_MAX UINT_MAX +# define LZO_INT_MAX INT_MAX +# define LZO_INT_MIN INT_MIN +# elif (ULONG_MAX >= LZO_0xffffffffL) + typedef unsigned long lzo_uint; + typedef long lzo_int; +# define LZO_UINT_MAX ULONG_MAX +# define LZO_INT_MAX LONG_MAX +# define LZO_INT_MIN LONG_MIN +# else +# error "lzo_uint" +# endif +#endif + +typedef int lzo_bool; + + +/*********************************************************************** +// memory models +************************************************************************/ + +/* Memory model for the public code segment. */ +#if !defined(__LZO_CMODEL) +# if defined(__LZO_DOS16) || defined(__LZO_WIN16) +# define __LZO_CMODEL __far +# elif defined(__LZO_i386) && defined(__WATCOMC__) +# define __LZO_CMODEL __near +# else +# define __LZO_CMODEL +# endif +#endif + +/* Memory model for the public data segment. */ +#if !defined(__LZO_DMODEL) +# if defined(__LZO_DOS16) || defined(__LZO_WIN16) +# define __LZO_DMODEL __far +# elif defined(__LZO_i386) && defined(__WATCOMC__) +# define __LZO_DMODEL __near +# else +# define __LZO_DMODEL +# endif +#endif + +/* Memory model that allows to access memory at offsets of lzo_uint. */ +#if !defined(__LZO_MMODEL) +# if (LZO_UINT_MAX <= UINT_MAX) +# define __LZO_MMODEL +# elif defined(__LZO_DOS16) || defined(__LZO_WIN16) +# define __LZO_MMODEL __huge +# define LZO_999_UNSUPPORTED +# elif defined(__LZO_PALMOS16) || defined(__LZO_TOS16) +# define __LZO_MMODEL +# else +# error "__LZO_MMODEL" +# endif +#endif + +/* no typedef here because of const-pointer issues */ +#define lzo_byte unsigned char __LZO_MMODEL +#define lzo_bytep unsigned char __LZO_MMODEL * +#define lzo_charp char __LZO_MMODEL * +#define lzo_voidp void __LZO_MMODEL * +#define lzo_shortp short __LZO_MMODEL * +#define lzo_ushortp unsigned short __LZO_MMODEL * +#define lzo_uint32p lzo_uint32 __LZO_MMODEL * +#define lzo_int32p lzo_int32 __LZO_MMODEL * +#define lzo_uintp lzo_uint __LZO_MMODEL * +#define lzo_intp lzo_int __LZO_MMODEL * +#define lzo_voidpp lzo_voidp __LZO_MMODEL * +#define lzo_bytepp lzo_bytep __LZO_MMODEL * + +#ifndef lzo_sizeof_dict_t +# define lzo_sizeof_dict_t sizeof(lzo_bytep) +#endif + + +/*********************************************************************** +// calling conventions and function types +************************************************************************/ + +/* linkage */ +#if !defined(__LZO_EXTERN_C) +# ifdef __cplusplus +# define __LZO_EXTERN_C extern "C" +# else +# define __LZO_EXTERN_C extern +# endif +#endif + +/* calling convention */ +#if !defined(__LZO_CDECL) +# if defined(__LZO_DOS16) || defined(__LZO_WIN16) +# define __LZO_CDECL __LZO_CMODEL __cdecl +# elif defined(__LZO_i386) && defined(_MSC_VER) +# define __LZO_CDECL __LZO_CMODEL __cdecl +# elif defined(__LZO_i386) && defined(__WATCOMC__) +# define __LZO_CDECL __LZO_CMODEL __cdecl +# else +# define __LZO_CDECL __LZO_CMODEL +# endif +#endif +#if !defined(__LZO_ENTRY) +# define __LZO_ENTRY __LZO_CDECL +#endif + +/* C++ exception specification for extern "C" function types */ +#if !defined(__cplusplus) +# undef LZO_NOTHROW +# define LZO_NOTHROW +#elif !defined(LZO_NOTHROW) +# define LZO_NOTHROW +#endif + + +typedef int +(__LZO_ENTRY *lzo_compress_t) ( const lzo_byte *src, lzo_uint src_len, + lzo_byte *dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +typedef int +(__LZO_ENTRY *lzo_decompress_t) ( const lzo_byte *src, lzo_uint src_len, + lzo_byte *dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +typedef int +(__LZO_ENTRY *lzo_optimize_t) ( lzo_byte *src, lzo_uint src_len, + lzo_byte *dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +typedef int +(__LZO_ENTRY *lzo_compress_dict_t)(const lzo_byte *src, lzo_uint src_len, + lzo_byte *dst, lzo_uintp dst_len, + lzo_voidp wrkmem, + const lzo_byte *dict, lzo_uint dict_len ); + +typedef int +(__LZO_ENTRY *lzo_decompress_dict_t)(const lzo_byte *src, lzo_uint src_len, + lzo_byte *dst, lzo_uintp dst_len, + lzo_voidp wrkmem, + const lzo_byte *dict, lzo_uint dict_len ); + + +/* assembler versions always use __cdecl */ +typedef int +(__LZO_CDECL *lzo_compress_asm_t)( const lzo_byte *src, lzo_uint src_len, + lzo_byte *dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +typedef int +(__LZO_CDECL *lzo_decompress_asm_t)( const lzo_byte *src, lzo_uint src_len, + lzo_byte *dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + + +/* a progress indicator callback function */ +typedef void (__LZO_ENTRY *lzo_progress_callback_t) (lzo_uint, lzo_uint); + + +/*********************************************************************** +// export information +************************************************************************/ + +/* DLL export information */ +#if !defined(__LZO_EXPORT1) +# define __LZO_EXPORT1 +#endif +#if !defined(__LZO_EXPORT2) +# define __LZO_EXPORT2 +#endif + +/* exported calling convention for C functions */ +#if !defined(LZO_PUBLIC) +# define LZO_PUBLIC(_rettype) \ + __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_ENTRY +#endif +#if !defined(LZO_EXTERN) +# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype) +#endif +#if !defined(LZO_PRIVATE) +# define LZO_PRIVATE(_rettype) static _rettype __LZO_ENTRY +#endif + +/* exported __cdecl calling convention for assembler functions */ +#if !defined(LZO_PUBLIC_CDECL) +# define LZO_PUBLIC_CDECL(_rettype) \ + __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL +#endif +#if !defined(LZO_EXTERN_CDECL) +# define LZO_EXTERN_CDECL(_rettype) __LZO_EXTERN_C LZO_PUBLIC_CDECL(_rettype) +#endif + +/* exported global variables (LZO currently uses no static variables and + * is fully thread safe) */ +#if !defined(LZO_PUBLIC_VAR) +# define LZO_PUBLIC_VAR(_type) \ + __LZO_EXPORT1 _type __LZO_EXPORT2 __LZO_DMODEL +#endif +#if !defined(LZO_EXTERN_VAR) +# define LZO_EXTERN_VAR(_type) extern LZO_PUBLIC_VAR(_type) +#endif + + +/*********************************************************************** +// error codes and prototypes +************************************************************************/ + +/* Error codes for the compression/decompression functions. Negative + * values are errors, positive values will be used for special but + * normal events. + */ +#define LZO_E_OK 0 +#define LZO_E_ERROR (-1) +#define LZO_E_OUT_OF_MEMORY (-2) /* not used right now */ +#define LZO_E_NOT_COMPRESSIBLE (-3) /* not used right now */ +#define LZO_E_INPUT_OVERRUN (-4) +#define LZO_E_OUTPUT_OVERRUN (-5) +#define LZO_E_LOOKBEHIND_OVERRUN (-6) +#define LZO_E_EOF_NOT_FOUND (-7) +#define LZO_E_INPUT_NOT_CONSUMED (-8) + + +/* lzo_init() should be the first function you call. + * Check the return code ! + * + * lzo_init() is a macro to allow checking that the library and the + * compiler's view of various types are consistent. + */ +#define lzo_init() __lzo_init2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\ + (int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\ + (int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\ + (int)sizeof(lzo_compress_t)) +LZO_EXTERN(int) __lzo_init2(unsigned,int,int,int,int,int,int,int,int,int); + +/* version functions (useful for shared libraries) */ +LZO_EXTERN(unsigned) lzo_version(void); +LZO_EXTERN(const char *) lzo_version_string(void); +LZO_EXTERN(const char *) lzo_version_date(void); +LZO_EXTERN(const lzo_charp) _lzo_version_string(void); +LZO_EXTERN(const lzo_charp) _lzo_version_date(void); + +/* string functions */ +LZO_EXTERN(int) +lzo_memcmp(const lzo_voidp _s1, const lzo_voidp _s2, lzo_uint _len); +LZO_EXTERN(lzo_voidp) +lzo_memcpy(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len); +LZO_EXTERN(lzo_voidp) +lzo_memmove(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len); +LZO_EXTERN(lzo_voidp) +lzo_memset(lzo_voidp _s, int _c, lzo_uint _len); + +/* checksum functions */ +LZO_EXTERN(lzo_uint32) +lzo_adler32(lzo_uint32 _adler, const lzo_byte *_buf, lzo_uint _len); +LZO_EXTERN(lzo_uint32) +lzo_crc32(lzo_uint32 _c, const lzo_byte *_buf, lzo_uint _len); + +/* misc. */ +LZO_EXTERN(lzo_bool) lzo_assert(int _expr); +LZO_EXTERN(int) _lzo_config_check(void); +typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u; +typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u; +typedef union { void *vp; lzo_bytep bp; lzo_uint32 u32; long l; } lzo_align_t; + +/* align a char pointer on a boundary that is a multiple of `size' */ +LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size); +#define LZO_PTR_ALIGN_UP(_ptr,_size) \ + ((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size))) + +/* deprecated - only for backward compatibility */ +#define LZO_ALIGN(_ptr,_size) LZO_PTR_ALIGN_UP(_ptr,_size) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* already included */ + diff --git a/distcc/lzo/minilzo.c b/distcc/lzo/minilzo.c new file mode 100644 index 0000000..85771eb --- /dev/null +++ b/distcc/lzo/minilzo.c @@ -0,0 +1,2935 @@ +/* minilzo.c -- mini subset of the LZO real-time data compression library + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + <markus@oberhumer.com> + http://www.oberhumer.com/opensource/lzo/ + */ + +/* + * NOTE: + * the full LZO package can be found at + * http://www.oberhumer.com/opensource/lzo/ + */ + +#define __LZO_IN_MINILZO +#define LZO_BUILD + +#ifdef MINILZO_HAVE_CONFIG_H +# include <config.h> +#endif + +#undef LZO_HAVE_CONFIG_H +#include "minilzo.h" + +#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x1080) +# error "version mismatch in miniLZO source files" +#endif + +#ifdef MINILZO_HAVE_CONFIG_H +# define LZO_HAVE_CONFIG_H +#endif + +#if !defined(LZO_NO_SYS_TYPES_H) +# include <sys/types.h> +#endif +#include <stdio.h> + +#ifndef __LZO_CONF_H +#define __LZO_CONF_H + +#if !defined(__LZO_IN_MINILZO) +# ifndef __LZOCONF_H +# include <lzoconf.h> +# endif +#endif + +#if defined(__BOUNDS_CHECKING_ON) +# include <unchecked.h> +#else +# define BOUNDS_CHECKING_OFF_DURING(stmt) stmt +# define BOUNDS_CHECKING_OFF_IN_EXPR(expr) (expr) +#endif + +#if !defined(LZO_HAVE_CONFIG_H) +# include <stddef.h> +# include <string.h> +# if !defined(NO_STDLIB_H) +# include <stdlib.h> +# endif +# define HAVE_MEMCMP +# define HAVE_MEMCPY +# define HAVE_MEMMOVE +# define HAVE_MEMSET +#else +# include <sys/types.h> +# if defined(HAVE_STDDEF_H) +# include <stddef.h> +# endif +# if defined(STDC_HEADERS) +# include <string.h> +# include <stdlib.h> +# endif +#endif + +#if defined(__LZO_DOS16) || defined(__LZO_WIN16) +# define HAVE_MALLOC_H +# define HAVE_HALLOC +#endif + +#undef NDEBUG +#if !defined(LZO_DEBUG) +# define NDEBUG +#endif +#if defined(LZO_DEBUG) || !defined(NDEBUG) +# if !defined(NO_STDIO_H) +# include <stdio.h> +# endif +#endif +#include <assert.h> + +#if !defined(LZO_COMPILE_TIME_ASSERT) +# define LZO_COMPILE_TIME_ASSERT(expr) \ + { typedef int __lzo_compile_time_assert_fail[1 - 2 * !(expr)]; } +#endif + +#if !defined(LZO_UNUSED) +# if 1 +# define LZO_UNUSED(var) ((void)&var) +# elif 0 +# define LZO_UNUSED(var) { typedef int __lzo_unused[sizeof(var) ? 2 : 1]; } +# else +# define LZO_UNUSED(parm) (parm = parm) +# endif +#endif + +#if !defined(__inline__) && !defined(__GNUC__) +# if defined(__cplusplus) +# define __inline__ inline +# else +# define __inline__ +# endif +#endif + +#if defined(NO_MEMCMP) +# undef HAVE_MEMCMP +#endif + +#if !defined(HAVE_MEMCMP) +# undef memcmp +# define memcmp lzo_memcmp +#endif +#if !defined(HAVE_MEMCPY) +# undef memcpy +# define memcpy lzo_memcpy +#endif +#if !defined(HAVE_MEMMOVE) +# undef memmove +# define memmove lzo_memmove +#endif +#if !defined(HAVE_MEMSET) +# undef memset +# define memset lzo_memset +#endif + +#if 0 +# define LZO_BYTE(x) ((unsigned char) (x)) +#else +# define LZO_BYTE(x) ((unsigned char) ((x) & 0xff)) +#endif + +#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b)) +#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b)) +#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c)) +#define LZO_MIN3(a,b,c) ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c)) + +#define lzo_sizeof(type) ((lzo_uint) (sizeof(type))) + +#define LZO_HIGH(array) ((lzo_uint) (sizeof(array)/sizeof(*(array)))) + +#define LZO_SIZE(bits) (1u << (bits)) +#define LZO_MASK(bits) (LZO_SIZE(bits) - 1) + +#define LZO_LSIZE(bits) (1ul << (bits)) +#define LZO_LMASK(bits) (LZO_LSIZE(bits) - 1) + +#define LZO_USIZE(bits) ((lzo_uint) 1 << (bits)) +#define LZO_UMASK(bits) (LZO_USIZE(bits) - 1) + +#define LZO_STYPE_MAX(b) (((1l << (8*(b)-2)) - 1l) + (1l << (8*(b)-2))) +#define LZO_UTYPE_MAX(b) (((1ul << (8*(b)-1)) - 1ul) + (1ul << (8*(b)-1))) + +#if !defined(SIZEOF_UNSIGNED) +# if (UINT_MAX == 0xffff) +# define SIZEOF_UNSIGNED 2 +# elif (UINT_MAX == LZO_0xffffffffL) +# define SIZEOF_UNSIGNED 4 +# elif (UINT_MAX >= LZO_0xffffffffL) +# define SIZEOF_UNSIGNED 8 +# else +# error "SIZEOF_UNSIGNED" +# endif +#endif + +#if !defined(SIZEOF_UNSIGNED_LONG) +# if (ULONG_MAX == LZO_0xffffffffL) +# define SIZEOF_UNSIGNED_LONG 4 +# elif (ULONG_MAX >= LZO_0xffffffffL) +# define SIZEOF_UNSIGNED_LONG 8 +# else +# error "SIZEOF_UNSIGNED_LONG" +# endif +#endif + +#if !defined(SIZEOF_SIZE_T) +# define SIZEOF_SIZE_T SIZEOF_UNSIGNED +#endif +#if !defined(SIZE_T_MAX) +# define SIZE_T_MAX LZO_UTYPE_MAX(SIZEOF_SIZE_T) +#endif + +#if 1 && defined(__LZO_i386) && (UINT_MAX == LZO_0xffffffffL) +# if !defined(LZO_UNALIGNED_OK_2) && (USHRT_MAX == 0xffff) +# define LZO_UNALIGNED_OK_2 +# endif +# if !defined(LZO_UNALIGNED_OK_4) && (LZO_UINT32_MAX == LZO_0xffffffffL) +# define LZO_UNALIGNED_OK_4 +# endif +#endif + +#if defined(LZO_UNALIGNED_OK_2) || defined(LZO_UNALIGNED_OK_4) +# if !defined(LZO_UNALIGNED_OK) +# define LZO_UNALIGNED_OK +# endif +#endif + +#if defined(__LZO_NO_UNALIGNED) +# undef LZO_UNALIGNED_OK +# undef LZO_UNALIGNED_OK_2 +# undef LZO_UNALIGNED_OK_4 +#endif + +#if defined(LZO_UNALIGNED_OK_2) && (USHRT_MAX != 0xffff) +# error "LZO_UNALIGNED_OK_2 must not be defined on this system" +#endif +#if defined(LZO_UNALIGNED_OK_4) && (LZO_UINT32_MAX != LZO_0xffffffffL) +# error "LZO_UNALIGNED_OK_4 must not be defined on this system" +#endif + +#if defined(__LZO_NO_ALIGNED) +# undef LZO_ALIGNED_OK_4 +#endif + +#if defined(LZO_ALIGNED_OK_4) && (LZO_UINT32_MAX != LZO_0xffffffffL) +# error "LZO_ALIGNED_OK_4 must not be defined on this system" +#endif + +#define LZO_LITTLE_ENDIAN 1234 +#define LZO_BIG_ENDIAN 4321 +#define LZO_PDP_ENDIAN 3412 + +#if !defined(LZO_BYTE_ORDER) +# if defined(MFX_BYTE_ORDER) +# define LZO_BYTE_ORDER MFX_BYTE_ORDER +# elif defined(__LZO_i386) +# define LZO_BYTE_ORDER LZO_LITTLE_ENDIAN +# elif defined(BYTE_ORDER) +# define LZO_BYTE_ORDER BYTE_ORDER +# elif defined(__BYTE_ORDER) +# define LZO_BYTE_ORDER __BYTE_ORDER +# endif +#endif + +#if defined(LZO_BYTE_ORDER) +# if (LZO_BYTE_ORDER != LZO_LITTLE_ENDIAN) && \ + (LZO_BYTE_ORDER != LZO_BIG_ENDIAN) +# error "invalid LZO_BYTE_ORDER" +# endif +#endif + +#if defined(LZO_UNALIGNED_OK) && !defined(LZO_BYTE_ORDER) +# error "LZO_BYTE_ORDER is not defined" +#endif + +#define LZO_OPTIMIZE_GNUC_i386_IS_BUGGY + +#if defined(NDEBUG) && !defined(LZO_DEBUG) && !defined(__LZO_CHECKER) +# if defined(__GNUC__) && defined(__i386__) +# if !defined(LZO_OPTIMIZE_GNUC_i386_IS_BUGGY) +# define LZO_OPTIMIZE_GNUC_i386 +# endif +# endif +#endif + +__LZO_EXTERN_C int __lzo_init_done; +__LZO_EXTERN_C const lzo_byte __lzo_copyright[]; +LZO_EXTERN(const lzo_byte *) lzo_copyright(void); +__LZO_EXTERN_C const lzo_uint32 _lzo_crc32_table[256]; + +#define _LZO_STRINGIZE(x) #x +#define _LZO_MEXPAND(x) _LZO_STRINGIZE(x) + +#define _LZO_CONCAT2(a,b) a ## b +#define _LZO_CONCAT3(a,b,c) a ## b ## c +#define _LZO_CONCAT4(a,b,c,d) a ## b ## c ## d +#define _LZO_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e + +#define _LZO_ECONCAT2(a,b) _LZO_CONCAT2(a,b) +#define _LZO_ECONCAT3(a,b,c) _LZO_CONCAT3(a,b,c) +#define _LZO_ECONCAT4(a,b,c,d) _LZO_CONCAT4(a,b,c,d) +#define _LZO_ECONCAT5(a,b,c,d,e) _LZO_CONCAT5(a,b,c,d,e) + +#if 0 + +#define __LZO_IS_COMPRESS_QUERY(i,il,o,ol,w) ((lzo_voidp)(o) == (w)) +#define __LZO_QUERY_COMPRESS(i,il,o,ol,w,n,s) \ + (*ol = (n)*(s), LZO_E_OK) + +#define __LZO_IS_DECOMPRESS_QUERY(i,il,o,ol,w) ((lzo_voidp)(o) == (w)) +#define __LZO_QUERY_DECOMPRESS(i,il,o,ol,w,n,s) \ + (*ol = (n)*(s), LZO_E_OK) + +#define __LZO_IS_OPTIMIZE_QUERY(i,il,o,ol,w) ((lzo_voidp)(o) == (w)) +#define __LZO_QUERY_OPTIMIZE(i,il,o,ol,w,n,s) \ + (*ol = (n)*(s), LZO_E_OK) + +#endif + +#ifndef __LZO_PTR_H +#define __LZO_PTR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__LZO_DOS16) || defined(__LZO_WIN16) +# include <dos.h> +# if 1 && defined(__WATCOMC__) +# include <i86.h> + __LZO_EXTERN_C unsigned char _HShift; +# define __LZO_HShift _HShift +# elif 1 && defined(_MSC_VER) + __LZO_EXTERN_C unsigned short __near _AHSHIFT; +# define __LZO_HShift ((unsigned) &_AHSHIFT) +# elif defined(__LZO_WIN16) +# define __LZO_HShift 3 +# else +# define __LZO_HShift 12 +# endif +# if !defined(_FP_SEG) && defined(FP_SEG) +# define _FP_SEG FP_SEG +# endif +# if !defined(_FP_OFF) && defined(FP_OFF) +# define _FP_OFF FP_OFF +# endif +#endif + +#if !defined(lzo_ptrdiff_t) +# if (UINT_MAX >= LZO_0xffffffffL) + typedef ptrdiff_t lzo_ptrdiff_t; +# else + typedef long lzo_ptrdiff_t; +# endif +#endif + +#if !defined(__LZO_HAVE_PTR_T) +# if defined(lzo_ptr_t) +# define __LZO_HAVE_PTR_T +# endif +#endif +#if !defined(__LZO_HAVE_PTR_T) +# if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED_LONG) +# if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED_LONG) + typedef unsigned long lzo_ptr_t; + typedef long lzo_sptr_t; +# define __LZO_HAVE_PTR_T +# endif +# endif +#endif +#if !defined(__LZO_HAVE_PTR_T) +# if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED) +# if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED) + typedef unsigned int lzo_ptr_t; + typedef int lzo_sptr_t; +# define __LZO_HAVE_PTR_T +# endif +# endif +#endif +#if !defined(__LZO_HAVE_PTR_T) +# if defined(SIZEOF_CHAR_P) && defined(SIZEOF_UNSIGNED_SHORT) +# if (SIZEOF_CHAR_P == SIZEOF_UNSIGNED_SHORT) + typedef unsigned short lzo_ptr_t; + typedef short lzo_sptr_t; +# define __LZO_HAVE_PTR_T +# endif +# endif +#endif +#if !defined(__LZO_HAVE_PTR_T) +# if defined(LZO_HAVE_CONFIG_H) || defined(SIZEOF_CHAR_P) +# error "no suitable type for lzo_ptr_t" +# else + typedef unsigned long lzo_ptr_t; + typedef long lzo_sptr_t; +# define __LZO_HAVE_PTR_T +# endif +#endif + +#if defined(__LZO_DOS16) || defined(__LZO_WIN16) +#define PTR(a) ((lzo_bytep) (a)) +#define PTR_ALIGNED_4(a) ((_FP_OFF(a) & 3) == 0) +#define PTR_ALIGNED2_4(a,b) (((_FP_OFF(a) | _FP_OFF(b)) & 3) == 0) +#else +#define PTR(a) ((lzo_ptr_t) (a)) +#define PTR_LINEAR(a) PTR(a) +#define PTR_ALIGNED_4(a) ((PTR_LINEAR(a) & 3) == 0) +#define PTR_ALIGNED_8(a) ((PTR_LINEAR(a) & 7) == 0) +#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0) +#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0) +#endif + +#define PTR_LT(a,b) (PTR(a) < PTR(b)) +#define PTR_GE(a,b) (PTR(a) >= PTR(b)) +#define PTR_DIFF(a,b) ((lzo_ptrdiff_t) (PTR(a) - PTR(b))) +#define pd(a,b) ((lzo_uint) ((a)-(b))) + +LZO_EXTERN(lzo_ptr_t) +__lzo_ptr_linear(const lzo_voidp ptr); + +typedef union +{ + char a_char; + unsigned char a_uchar; + short a_short; + unsigned short a_ushort; + int a_int; + unsigned int a_uint; + long a_long; + unsigned long a_ulong; + lzo_int a_lzo_int; + lzo_uint a_lzo_uint; + lzo_int32 a_lzo_int32; + lzo_uint32 a_lzo_uint32; + ptrdiff_t a_ptrdiff_t; + lzo_ptrdiff_t a_lzo_ptrdiff_t; + lzo_ptr_t a_lzo_ptr_t; + lzo_voidp a_lzo_voidp; + void * a_void_p; + lzo_bytep a_lzo_bytep; + lzo_bytepp a_lzo_bytepp; + lzo_uintp a_lzo_uintp; + lzo_uint * a_lzo_uint_p; + lzo_uint32p a_lzo_uint32p; + lzo_uint32 * a_lzo_uint32_p; + unsigned char * a_uchar_p; + char * a_char_p; +} +lzo_full_align_t; + +#ifdef __cplusplus +} +#endif + +#endif + +#define LZO_DETERMINISTIC + +#define LZO_DICT_USE_PTR +#if defined(__LZO_DOS16) || defined(__LZO_WIN16) || defined(__LZO_STRICT_16BIT) +# undef LZO_DICT_USE_PTR +#endif + +#if defined(LZO_DICT_USE_PTR) +# define lzo_dict_t const lzo_bytep +# define lzo_dict_p lzo_dict_t __LZO_MMODEL * +#else +# define lzo_dict_t lzo_uint +# define lzo_dict_p lzo_dict_t __LZO_MMODEL * +#endif + +#if !defined(lzo_moff_t) +#define lzo_moff_t lzo_uint +#endif + +#endif + +LZO_PUBLIC(lzo_ptr_t) +__lzo_ptr_linear(const lzo_voidp ptr) +{ + lzo_ptr_t p; + +#if defined(__LZO_DOS16) || defined(__LZO_WIN16) + p = (((lzo_ptr_t)(_FP_SEG(ptr))) << (16 - __LZO_HShift)) + (_FP_OFF(ptr)); +#else + p = PTR_LINEAR(ptr); +#endif + + return p; +} + +LZO_PUBLIC(unsigned) +__lzo_align_gap(const lzo_voidp ptr, lzo_uint size) +{ + lzo_ptr_t p, s, n; + + assert(size > 0); + + p = __lzo_ptr_linear(ptr); + s = (lzo_ptr_t) (size - 1); +#if 0 + assert((size & (size - 1)) == 0); + n = ((p + s) & ~s) - p; +#else + n = (((p + s) / size) * size) - p; +#endif + + assert((long)n >= 0); + assert(n <= s); + + return (unsigned)n; +} + +#ifndef __LZO_UTIL_H +#define __LZO_UTIL_H + +#ifndef __LZO_CONF_H +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if 1 && defined(HAVE_MEMCPY) +#if !defined(__LZO_DOS16) && !defined(__LZO_WIN16) + +#define MEMCPY8_DS(dest,src,len) \ + memcpy(dest,src,len); \ + dest += len; \ + src += len + +#endif +#endif + +#if 0 && !defined(MEMCPY8_DS) + +#define MEMCPY8_DS(dest,src,len) \ + { do { \ + *dest++ = *src++; \ + *dest++ = *src++; \ + *dest++ = *src++; \ + *dest++ = *src++; \ + *dest++ = *src++; \ + *dest++ = *src++; \ + *dest++ = *src++; \ + *dest++ = *src++; \ + len -= 8; \ + } while (len > 0); } + +#endif + +#if !defined(MEMCPY8_DS) + +#define MEMCPY8_DS(dest,src,len) \ + { register lzo_uint __l = (len) / 8; \ + do { \ + *dest++ = *src++; \ + *dest++ = *src++; \ + *dest++ = *src++; \ + *dest++ = *src++; \ + *dest++ = *src++; \ + *dest++ = *src++; \ + *dest++ = *src++; \ + *dest++ = *src++; \ + } while (--__l > 0); } + +#endif + +#define MEMCPY_DS(dest,src,len) \ + do *dest++ = *src++; \ + while (--len > 0) + +#define MEMMOVE_DS(dest,src,len) \ + do *dest++ = *src++; \ + while (--len > 0) + +#if 0 && defined(LZO_OPTIMIZE_GNUC_i386) + +#define BZERO8_PTR(s,l,n) \ +__asm__ __volatile__( \ + "movl %0,%%eax \n" \ + "movl %1,%%edi \n" \ + "movl %2,%%ecx \n" \ + "cld \n" \ + "rep \n" \ + "stosl %%eax,(%%edi) \n" \ + : \ + :"g" (0),"g" (s),"g" (n) \ + :"eax","edi","ecx", "memory", "cc" \ +) + +#elif (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMSET) + +#if 1 +#define BZERO8_PTR(s,l,n) memset((s),0,(lzo_uint)(l)*(n)) +#else +#define BZERO8_PTR(s,l,n) memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n)) +#endif + +#else + +#define BZERO8_PTR(s,l,n) \ + lzo_memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n)) + +#endif + +#if 0 +#if defined(__GNUC__) && defined(__i386__) + +unsigned char lzo_rotr8(unsigned char value, int shift); +extern __inline__ unsigned char lzo_rotr8(unsigned char value, int shift) +{ + unsigned char result; + + __asm__ __volatile__ ("movb %b1, %b0; rorb %b2, %b0" + : "=a"(result) : "g"(value), "c"(shift)); + return result; +} + +unsigned short lzo_rotr16(unsigned short value, int shift); +extern __inline__ unsigned short lzo_rotr16(unsigned short value, int shift) +{ + unsigned short result; + + __asm__ __volatile__ ("movw %b1, %b0; rorw %b2, %b0" + : "=a"(result) : "g"(value), "c"(shift)); + return result; +} + +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +LZO_PUBLIC(lzo_bool) +lzo_assert(int expr) +{ + return (expr) ? 1 : 0; +} + +/* If you use the LZO library in a product, you *must* keep this + * copyright string in the executable of your product. + */ + +const lzo_byte __lzo_copyright[] = +#if !defined(__LZO_IN_MINLZO) + LZO_VERSION_STRING; +#else + "\n\n\n" + "LZO real-time data compression library.\n" + "Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Markus Franz Xaver Johannes Oberhumer\n" + "<markus.oberhumer@jk.uni-linz.ac.at>\n" + "http://www.oberhumer.com/opensource/lzo/\n" + "\n" + "LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE "\n" + "LZO build date: " __DATE__ " " __TIME__ "\n\n" + "LZO special compilation options:\n" +#ifdef __cplusplus + " __cplusplus\n" +#endif +#if defined(__PIC__) + " __PIC__\n" +#elif defined(__pic__) + " __pic__\n" +#endif +#if (UINT_MAX < LZO_0xffffffffL) + " 16BIT\n" +#endif +#if defined(__LZO_STRICT_16BIT) + " __LZO_STRICT_16BIT\n" +#endif +#if (UINT_MAX > LZO_0xffffffffL) + " UINT_MAX=" _LZO_MEXPAND(UINT_MAX) "\n" +#endif +#if (ULONG_MAX > LZO_0xffffffffL) + " ULONG_MAX=" _LZO_MEXPAND(ULONG_MAX) "\n" +#endif +#if defined(LZO_BYTE_ORDER) + " LZO_BYTE_ORDER=" _LZO_MEXPAND(LZO_BYTE_ORDER) "\n" +#endif +#if defined(LZO_UNALIGNED_OK_2) + " LZO_UNALIGNED_OK_2\n" +#endif +#if defined(LZO_UNALIGNED_OK_4) + " LZO_UNALIGNED_OK_4\n" +#endif +#if defined(LZO_ALIGNED_OK_4) + " LZO_ALIGNED_OK_4\n" +#endif +#if defined(LZO_DICT_USE_PTR) + " LZO_DICT_USE_PTR\n" +#endif +#if defined(__LZO_QUERY_COMPRESS) + " __LZO_QUERY_COMPRESS\n" +#endif +#if defined(__LZO_QUERY_DECOMPRESS) + " __LZO_QUERY_DECOMPRESS\n" +#endif +#if defined(__LZO_IN_MINILZO) + " __LZO_IN_MINILZO\n" +#endif + "\n\n" + "$Id: LZO " LZO_VERSION_STRING " built " __DATE__ " " __TIME__ +#if defined(__GNUC__) && defined(__VERSION__) + " by gcc " __VERSION__ +#elif defined(__BORLANDC__) + " by Borland C " _LZO_MEXPAND(__BORLANDC__) +#elif defined(_MSC_VER) + " by Microsoft C " _LZO_MEXPAND(_MSC_VER) +#elif defined(__PUREC__) + " by Pure C " _LZO_MEXPAND(__PUREC__) +#elif defined(__SC__) + " by Symantec C " _LZO_MEXPAND(__SC__) +#elif defined(__TURBOC__) + " by Turbo C " _LZO_MEXPAND(__TURBOC__) +#elif defined(__WATCOMC__) + " by Watcom C " _LZO_MEXPAND(__WATCOMC__) +#endif + " $\n" + "$Copyright: LZO (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Markus Franz Xaver Johannes Oberhumer $\n"; +#endif + +LZO_PUBLIC(const lzo_byte *) +lzo_copyright(void) +{ + return __lzo_copyright; +} + +LZO_PUBLIC(unsigned) +lzo_version(void) +{ + return LZO_VERSION; +} + +LZO_PUBLIC(const char *) +lzo_version_string(void) +{ + return LZO_VERSION_STRING; +} + +LZO_PUBLIC(const char *) +lzo_version_date(void) +{ + return LZO_VERSION_DATE; +} + +LZO_PUBLIC(const lzo_charp) +_lzo_version_string(void) +{ + return LZO_VERSION_STRING; +} + +LZO_PUBLIC(const lzo_charp) +_lzo_version_date(void) +{ + return LZO_VERSION_DATE; +} + +#define LZO_BASE 65521u +#define LZO_NMAX 5552 + +#define LZO_DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define LZO_DO2(buf,i) LZO_DO1(buf,i); LZO_DO1(buf,i+1); +#define LZO_DO4(buf,i) LZO_DO2(buf,i); LZO_DO2(buf,i+2); +#define LZO_DO8(buf,i) LZO_DO4(buf,i); LZO_DO4(buf,i+4); +#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8); + +LZO_PUBLIC(lzo_uint32) +lzo_adler32(lzo_uint32 adler, const lzo_byte *buf, lzo_uint len) +{ + lzo_uint32 s1 = adler & 0xffff; + lzo_uint32 s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == NULL) + return 1; + + while (len > 0) + { + k = len < LZO_NMAX ? (int) len : LZO_NMAX; + len -= k; + if (k >= 16) do + { + LZO_DO16(buf,0); + buf += 16; + k -= 16; + } while (k >= 16); + if (k != 0) do + { + s1 += *buf++; + s2 += s1; + } while (--k > 0); + s1 %= LZO_BASE; + s2 %= LZO_BASE; + } + return (s2 << 16) | s1; +} + +LZO_PUBLIC(int) +lzo_memcmp(const lzo_voidp s1, const lzo_voidp s2, lzo_uint len) +{ +#if (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMCMP) + return memcmp(s1,s2,len); +#else + const lzo_byte *p1 = (const lzo_byte *) s1; + const lzo_byte *p2 = (const lzo_byte *) s2; + int d; + + if (len > 0) do + { + d = *p1 - *p2; + if (d != 0) + return d; + p1++; + p2++; + } + while (--len > 0); + return 0; +#endif +} + +LZO_PUBLIC(lzo_voidp) +lzo_memcpy(lzo_voidp dest, const lzo_voidp src, lzo_uint len) +{ +#if (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMCPY) + return memcpy(dest,src,len); +#else + lzo_byte *p1 = (lzo_byte *) dest; + const lzo_byte *p2 = (const lzo_byte *) src; + + if (len <= 0 || p1 == p2) + return dest; + do + *p1++ = *p2++; + while (--len > 0); + return dest; +#endif +} + +LZO_PUBLIC(lzo_voidp) +lzo_memmove(lzo_voidp dest, const lzo_voidp src, lzo_uint len) +{ +#if (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMMOVE) + return memmove(dest,src,len); +#else + lzo_byte *p1 = (lzo_byte *) dest; + const lzo_byte *p2 = (const lzo_byte *) src; + + if (len <= 0 || p1 == p2) + return dest; + + if (p1 < p2) + { + do + *p1++ = *p2++; + while (--len > 0); + } + else + { + p1 += len; + p2 += len; + do + *--p1 = *--p2; + while (--len > 0); + } + return dest; +#endif +} + +LZO_PUBLIC(lzo_voidp) +lzo_memset(lzo_voidp s, int c, lzo_uint len) +{ +#if (LZO_UINT_MAX <= SIZE_T_MAX) && defined(HAVE_MEMSET) + return memset(s,c,len); +#else + lzo_byte *p = (lzo_byte *) s; + + if (len > 0) do + *p++ = LZO_BYTE(c); + while (--len > 0); + return s; +#endif +} + +#if 0 +# define IS_SIGNED(type) (((type) (1ul << (8 * sizeof(type) - 1))) < 0) +# define IS_UNSIGNED(type) (((type) (1ul << (8 * sizeof(type) - 1))) > 0) +#else +# define IS_SIGNED(type) (((type) (-1)) < ((type) 0)) +# define IS_UNSIGNED(type) (((type) (-1)) > ((type) 0)) +#endif + +#define IS_POWER_OF_2(x) (((x) & ((x) - 1)) == 0) + +static lzo_bool schedule_insns_bug(void); +static lzo_bool strength_reduce_bug(int *); + +#if 0 || defined(LZO_DEBUG) +#include <stdio.h> +static lzo_bool __lzo_assert_fail(const char *s, unsigned line) +{ +#if defined(__palmos__) + printf("LZO assertion failed in line %u: '%s'\n",line,s); +#else + fprintf(stderr,"LZO assertion failed in line %u: '%s'\n",line,s); +#endif + return 0; +} +# define __lzo_assert(x) ((x) ? 1 : __lzo_assert_fail(#x,__LINE__)) +#else +# define __lzo_assert(x) ((x) ? 1 : 0) +#endif + +#undef COMPILE_TIME_ASSERT +#if 0 +# define COMPILE_TIME_ASSERT(expr) r &= __lzo_assert(expr) +#else +# define COMPILE_TIME_ASSERT(expr) LZO_COMPILE_TIME_ASSERT(expr) +#endif + +static lzo_bool basic_integral_check(void) +{ + lzo_bool r = 1; + + COMPILE_TIME_ASSERT(CHAR_BIT == 8); + COMPILE_TIME_ASSERT(sizeof(char) == 1); + COMPILE_TIME_ASSERT(sizeof(short) >= 2); + COMPILE_TIME_ASSERT(sizeof(long) >= 4); + COMPILE_TIME_ASSERT(sizeof(int) >= sizeof(short)); + COMPILE_TIME_ASSERT(sizeof(long) >= sizeof(int)); + + COMPILE_TIME_ASSERT(sizeof(lzo_uint) == sizeof(lzo_int)); + COMPILE_TIME_ASSERT(sizeof(lzo_uint32) == sizeof(lzo_int32)); + + COMPILE_TIME_ASSERT(sizeof(lzo_uint32) >= 4); + COMPILE_TIME_ASSERT(sizeof(lzo_uint32) >= sizeof(unsigned)); +#if defined(__LZO_STRICT_16BIT) + COMPILE_TIME_ASSERT(sizeof(lzo_uint) == 2); +#else + COMPILE_TIME_ASSERT(sizeof(lzo_uint) >= 4); + COMPILE_TIME_ASSERT(sizeof(lzo_uint) >= sizeof(unsigned)); +#endif + +#if (USHRT_MAX == 65535u) + COMPILE_TIME_ASSERT(sizeof(short) == 2); +#elif (USHRT_MAX == LZO_0xffffffffL) + COMPILE_TIME_ASSERT(sizeof(short) == 4); +#elif (USHRT_MAX >= LZO_0xffffffffL) + COMPILE_TIME_ASSERT(sizeof(short) > 4); +#endif +#if (UINT_MAX == 65535u) + COMPILE_TIME_ASSERT(sizeof(int) == 2); +#elif (UINT_MAX == LZO_0xffffffffL) + COMPILE_TIME_ASSERT(sizeof(int) == 4); +#elif (UINT_MAX >= LZO_0xffffffffL) + COMPILE_TIME_ASSERT(sizeof(int) > 4); +#endif +#if (ULONG_MAX == 65535ul) + COMPILE_TIME_ASSERT(sizeof(long) == 2); +#elif (ULONG_MAX == LZO_0xffffffffL) + COMPILE_TIME_ASSERT(sizeof(long) == 4); +#elif (ULONG_MAX >= LZO_0xffffffffL) + COMPILE_TIME_ASSERT(sizeof(long) > 4); +#endif + +#if defined(SIZEOF_UNSIGNED) + COMPILE_TIME_ASSERT(SIZEOF_UNSIGNED == sizeof(unsigned)); +#endif +#if defined(SIZEOF_UNSIGNED_LONG) + COMPILE_TIME_ASSERT(SIZEOF_UNSIGNED_LONG == sizeof(unsigned long)); +#endif +#if defined(SIZEOF_UNSIGNED_SHORT) + COMPILE_TIME_ASSERT(SIZEOF_UNSIGNED_SHORT == sizeof(unsigned short)); +#endif +#if !defined(__LZO_IN_MINILZO) +#if defined(SIZEOF_SIZE_T) + COMPILE_TIME_ASSERT(SIZEOF_SIZE_T == sizeof(size_t)); +#endif +#endif + + COMPILE_TIME_ASSERT(IS_UNSIGNED(unsigned char)); + COMPILE_TIME_ASSERT(IS_UNSIGNED(unsigned short)); + COMPILE_TIME_ASSERT(IS_UNSIGNED(unsigned)); + COMPILE_TIME_ASSERT(IS_UNSIGNED(unsigned long)); + COMPILE_TIME_ASSERT(IS_SIGNED(short)); + COMPILE_TIME_ASSERT(IS_SIGNED(int)); + COMPILE_TIME_ASSERT(IS_SIGNED(long)); + + COMPILE_TIME_ASSERT(IS_UNSIGNED(lzo_uint32)); + COMPILE_TIME_ASSERT(IS_UNSIGNED(lzo_uint)); + COMPILE_TIME_ASSERT(IS_SIGNED(lzo_int32)); + COMPILE_TIME_ASSERT(IS_SIGNED(lzo_int)); + + COMPILE_TIME_ASSERT(INT_MAX == LZO_STYPE_MAX(sizeof(int))); + COMPILE_TIME_ASSERT(UINT_MAX == LZO_UTYPE_MAX(sizeof(unsigned))); + COMPILE_TIME_ASSERT(LONG_MAX == LZO_STYPE_MAX(sizeof(long))); + COMPILE_TIME_ASSERT(ULONG_MAX == LZO_UTYPE_MAX(sizeof(unsigned long))); + COMPILE_TIME_ASSERT(SHRT_MAX == LZO_STYPE_MAX(sizeof(short))); + COMPILE_TIME_ASSERT(USHRT_MAX == LZO_UTYPE_MAX(sizeof(unsigned short))); + COMPILE_TIME_ASSERT(LZO_UINT32_MAX == LZO_UTYPE_MAX(sizeof(lzo_uint32))); + COMPILE_TIME_ASSERT(LZO_UINT_MAX == LZO_UTYPE_MAX(sizeof(lzo_uint))); +#if !defined(__LZO_IN_MINILZO) + COMPILE_TIME_ASSERT(SIZE_T_MAX == LZO_UTYPE_MAX(sizeof(size_t))); +#endif + + r &= __lzo_assert(LZO_BYTE(257) == 1); + + return r; +} + +static lzo_bool basic_ptr_check(void) +{ + lzo_bool r = 1; + + COMPILE_TIME_ASSERT(sizeof(char *) >= sizeof(int)); + COMPILE_TIME_ASSERT(sizeof(lzo_byte *) >= sizeof(char *)); + + COMPILE_TIME_ASSERT(sizeof(lzo_voidp) == sizeof(lzo_byte *)); + COMPILE_TIME_ASSERT(sizeof(lzo_voidp) == sizeof(lzo_voidpp)); + COMPILE_TIME_ASSERT(sizeof(lzo_voidp) == sizeof(lzo_bytepp)); + COMPILE_TIME_ASSERT(sizeof(lzo_voidp) >= sizeof(lzo_uint)); + + COMPILE_TIME_ASSERT(sizeof(lzo_ptr_t) == sizeof(lzo_voidp)); + COMPILE_TIME_ASSERT(sizeof(lzo_ptr_t) == sizeof(lzo_sptr_t)); + COMPILE_TIME_ASSERT(sizeof(lzo_ptr_t) >= sizeof(lzo_uint)); + + COMPILE_TIME_ASSERT(sizeof(lzo_ptrdiff_t) >= 4); + COMPILE_TIME_ASSERT(sizeof(lzo_ptrdiff_t) >= sizeof(ptrdiff_t)); + + COMPILE_TIME_ASSERT(sizeof(ptrdiff_t) >= sizeof(size_t)); + COMPILE_TIME_ASSERT(sizeof(lzo_ptrdiff_t) >= sizeof(lzo_uint)); + +#if defined(SIZEOF_CHAR_P) + COMPILE_TIME_ASSERT(SIZEOF_CHAR_P == sizeof(char *)); +#endif +#if defined(SIZEOF_PTRDIFF_T) + COMPILE_TIME_ASSERT(SIZEOF_PTRDIFF_T == sizeof(ptrdiff_t)); +#endif + + COMPILE_TIME_ASSERT(IS_SIGNED(ptrdiff_t)); + COMPILE_TIME_ASSERT(IS_UNSIGNED(size_t)); + COMPILE_TIME_ASSERT(IS_SIGNED(lzo_ptrdiff_t)); + COMPILE_TIME_ASSERT(IS_SIGNED(lzo_sptr_t)); + COMPILE_TIME_ASSERT(IS_UNSIGNED(lzo_ptr_t)); + COMPILE_TIME_ASSERT(IS_UNSIGNED(lzo_moff_t)); + + return r; +} + +static lzo_bool ptr_check(void) +{ + lzo_bool r = 1; + int i; + char _wrkmem[10 * sizeof(lzo_byte *) + sizeof(lzo_full_align_t)]; + lzo_bytep wrkmem; + lzo_bytepp dict; + unsigned char x[4 * sizeof(lzo_full_align_t)]; + long d; + lzo_full_align_t a; + lzo_full_align_t u; + + for (i = 0; i < (int) sizeof(x); i++) + x[i] = LZO_BYTE(i); + + wrkmem = LZO_PTR_ALIGN_UP((lzo_byte *)_wrkmem,sizeof(lzo_full_align_t)); + +#if 0 + dict = (lzo_bytepp) wrkmem; +#else + + u.a_lzo_bytep = wrkmem; dict = u.a_lzo_bytepp; +#endif + + d = (long) ((const lzo_bytep) dict - (const lzo_bytep) _wrkmem); + r &= __lzo_assert(d >= 0); + r &= __lzo_assert(d < (long) sizeof(lzo_full_align_t)); + + memset(&a,0,sizeof(a)); + r &= __lzo_assert(a.a_lzo_voidp == NULL); + + memset(&a,0xff,sizeof(a)); + r &= __lzo_assert(a.a_ushort == USHRT_MAX); + r &= __lzo_assert(a.a_uint == UINT_MAX); + r &= __lzo_assert(a.a_ulong == ULONG_MAX); + r &= __lzo_assert(a.a_lzo_uint == LZO_UINT_MAX); + r &= __lzo_assert(a.a_lzo_uint32 == LZO_UINT32_MAX); + + if (r == 1) + { + for (i = 0; i < 8; i++) + r &= __lzo_assert((const lzo_voidp) (&dict[i]) == (const lzo_voidp) (&wrkmem[i * sizeof(lzo_byte *)])); + } + + memset(&a,0,sizeof(a)); + r &= __lzo_assert(a.a_char_p == NULL); + r &= __lzo_assert(a.a_lzo_bytep == NULL); + r &= __lzo_assert(NULL == (void *)0); + if (r == 1) + { + for (i = 0; i < 10; i++) + dict[i] = wrkmem; + BZERO8_PTR(dict+1,sizeof(dict[0]),8); + r &= __lzo_assert(dict[0] == wrkmem); + for (i = 1; i < 9; i++) + r &= __lzo_assert(dict[i] == NULL); + r &= __lzo_assert(dict[9] == wrkmem); + } + + if (r == 1) + { + unsigned k = 1; + const unsigned n = (unsigned) sizeof(lzo_uint32); + lzo_byte *p0; + lzo_byte *p1; + + k += __lzo_align_gap(&x[k],n); + p0 = (lzo_bytep) &x[k]; +#if defined(PTR_LINEAR) + r &= __lzo_assert((PTR_LINEAR(p0) & (n-1)) == 0); +#else + r &= __lzo_assert(n == 4); + r &= __lzo_assert(PTR_ALIGNED_4(p0)); +#endif + + r &= __lzo_assert(k >= 1); + p1 = (lzo_bytep) &x[1]; + r &= __lzo_assert(PTR_GE(p0,p1)); + + r &= __lzo_assert(k < 1+n); + p1 = (lzo_bytep) &x[1+n]; + r &= __lzo_assert(PTR_LT(p0,p1)); + + if (r == 1) + { + lzo_uint32 v0, v1; +#if 0 + v0 = * (lzo_uint32 *) &x[k]; + v1 = * (lzo_uint32 *) &x[k+n]; +#else + + u.a_uchar_p = &x[k]; + v0 = *u.a_lzo_uint32_p; + u.a_uchar_p = &x[k+n]; + v1 = *u.a_lzo_uint32_p; +#endif + r &= __lzo_assert(v0 > 0); + r &= __lzo_assert(v1 > 0); + } + } + + return r; +} + +LZO_PUBLIC(int) +_lzo_config_check(void) +{ + lzo_bool r = 1; + int i; + union { + lzo_uint32 a; + unsigned short b; + lzo_uint32 aa[4]; + unsigned char x[4*sizeof(lzo_full_align_t)]; + } u; + + COMPILE_TIME_ASSERT( (int) ((unsigned char) ((signed char) -1)) == 255); + COMPILE_TIME_ASSERT( (((unsigned char)128) << (int)(8*sizeof(int)-8)) < 0); + +#if 0 + r &= __lzo_assert((const void *)&u == (const void *)&u.a); + r &= __lzo_assert((const void *)&u == (const void *)&u.b); + r &= __lzo_assert((const void *)&u == (const void *)&u.x[0]); + r &= __lzo_assert((const void *)&u == (const void *)&u.aa[0]); +#endif + + r &= basic_integral_check(); + r &= basic_ptr_check(); + if (r != 1) + return LZO_E_ERROR; + + u.a = 0; u.b = 0; + for (i = 0; i < (int) sizeof(u.x); i++) + u.x[i] = LZO_BYTE(i); + +#if defined(LZO_BYTE_ORDER) + if (r == 1) + { +# if (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN) + lzo_uint32 a = (lzo_uint32) (u.a & LZO_0xffffffffL); + unsigned short b = (unsigned short) (u.b & 0xffff); + r &= __lzo_assert(a == 0x03020100L); + r &= __lzo_assert(b == 0x0100); +# elif (LZO_BYTE_ORDER == LZO_BIG_ENDIAN) + lzo_uint32 a = u.a >> (8 * sizeof(u.a) - 32); + unsigned short b = u.b >> (8 * sizeof(u.b) - 16); + r &= __lzo_assert(a == 0x00010203L); + r &= __lzo_assert(b == 0x0001); +# else +# error "invalid LZO_BYTE_ORDER" +# endif + } +#endif + +#if defined(LZO_UNALIGNED_OK_2) + COMPILE_TIME_ASSERT(sizeof(short) == 2); + if (r == 1) + { + unsigned short b[4]; + + for (i = 0; i < 4; i++) + b[i] = * (const unsigned short *) &u.x[i]; + +# if (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN) + r &= __lzo_assert(b[0] == 0x0100); + r &= __lzo_assert(b[1] == 0x0201); + r &= __lzo_assert(b[2] == 0x0302); + r &= __lzo_assert(b[3] == 0x0403); +# elif (LZO_BYTE_ORDER == LZO_BIG_ENDIAN) + r &= __lzo_assert(b[0] == 0x0001); + r &= __lzo_assert(b[1] == 0x0102); + r &= __lzo_assert(b[2] == 0x0203); + r &= __lzo_assert(b[3] == 0x0304); +# endif + } +#endif + +#if defined(LZO_UNALIGNED_OK_4) + COMPILE_TIME_ASSERT(sizeof(lzo_uint32) == 4); + if (r == 1) + { + lzo_uint32 a[4]; + + for (i = 0; i < 4; i++) + a[i] = * (const lzo_uint32 *) &u.x[i]; + +# if (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN) + r &= __lzo_assert(a[0] == 0x03020100L); + r &= __lzo_assert(a[1] == 0x04030201L); + r &= __lzo_assert(a[2] == 0x05040302L); + r &= __lzo_assert(a[3] == 0x06050403L); +# elif (LZO_BYTE_ORDER == LZO_BIG_ENDIAN) + r &= __lzo_assert(a[0] == 0x00010203L); + r &= __lzo_assert(a[1] == 0x01020304L); + r &= __lzo_assert(a[2] == 0x02030405L); + r &= __lzo_assert(a[3] == 0x03040506L); +# endif + } +#endif + +#if defined(LZO_ALIGNED_OK_4) + COMPILE_TIME_ASSERT(sizeof(lzo_uint32) == 4); +#endif + + COMPILE_TIME_ASSERT(lzo_sizeof_dict_t == sizeof(lzo_dict_t)); + +#if defined(__LZO_IN_MINLZO) + if (r == 1) + { + lzo_uint32 adler; + adler = lzo_adler32(0, NULL, 0); + adler = lzo_adler32(adler, lzo_copyright(), 200); + r &= __lzo_assert(adler == 0xc76f1751L); + } +#endif + + if (r == 1) + { + r &= __lzo_assert(!schedule_insns_bug()); + } + + if (r == 1) + { + static int x[3]; + static unsigned xn = 3; + register unsigned j; + + for (j = 0; j < xn; j++) + x[j] = (int)j - 3; + r &= __lzo_assert(!strength_reduce_bug(x)); + } + + if (r == 1) + { + r &= ptr_check(); + } + + return r == 1 ? LZO_E_OK : LZO_E_ERROR; +} + +static lzo_bool schedule_insns_bug(void) +{ +#if defined(__LZO_CHECKER) + return 0; +#else + const int clone[] = {1, 2, 0}; + const int *q; + q = clone; + return (*q) ? 0 : 1; +#endif +} + +static lzo_bool strength_reduce_bug(int *x) +{ + return x[0] != -3 || x[1] != -2 || x[2] != -1; +} + +#undef COMPILE_TIME_ASSERT + +int __lzo_init_done = 0; + +LZO_PUBLIC(int) +__lzo_init2(unsigned v, int s1, int s2, int s3, int s4, int s5, + int s6, int s7, int s8, int s9) +{ + int r; + + __lzo_init_done = 1; + + if (v == 0) + return LZO_E_ERROR; + + r = (s1 == -1 || s1 == (int) sizeof(short)) && + (s2 == -1 || s2 == (int) sizeof(int)) && + (s3 == -1 || s3 == (int) sizeof(long)) && + (s4 == -1 || s4 == (int) sizeof(lzo_uint32)) && + (s5 == -1 || s5 == (int) sizeof(lzo_uint)) && + (s6 == -1 || s6 == (int) lzo_sizeof_dict_t) && + (s7 == -1 || s7 == (int) sizeof(char *)) && + (s8 == -1 || s8 == (int) sizeof(lzo_voidp)) && + (s9 == -1 || s9 == (int) sizeof(lzo_compress_t)); + if (!r) + return LZO_E_ERROR; + + r = _lzo_config_check(); + if (r != LZO_E_OK) + return r; + + return r; +} + +#if !defined(__LZO_IN_MINILZO) + +LZO_EXTERN(int) +__lzo_init(unsigned v,int s1,int s2,int s3,int s4,int s5,int s6,int s7); + +LZO_PUBLIC(int) +__lzo_init(unsigned v,int s1,int s2,int s3,int s4,int s5,int s6,int s7) +{ + if (v == 0 || v > 0x1010) + return LZO_E_ERROR; + return __lzo_init2(v,s1,s2,s3,s4,s5,-1,-1,s6,s7); +} + +#endif + +#define do_compress _lzo1x_1_do_compress + +#define LZO_NEED_DICT_H +#define D_BITS 14 +#define D_INDEX1(d,p) d = DM((0x21*DX3(p,5,5,6)) >> 5) +#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) + +#ifndef __LZO_CONFIG1X_H +#define __LZO_CONFIG1X_H + +#if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z) +# define LZO1X +#endif + +#if !defined(__LZO_IN_MINILZO) +#include <lzo1x.h> +#endif + +#define LZO_EOF_CODE +#undef LZO_DETERMINISTIC + +#define M1_MAX_OFFSET 0x0400 +#ifndef M2_MAX_OFFSET +#define M2_MAX_OFFSET 0x0800 +#endif +#define M3_MAX_OFFSET 0x4000 +#define M4_MAX_OFFSET 0xbfff + +#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET) + +#define M1_MIN_LEN 2 +#define M1_MAX_LEN 2 +#define M2_MIN_LEN 3 +#ifndef M2_MAX_LEN +#define M2_MAX_LEN 8 +#endif +#define M3_MIN_LEN 3 +#define M3_MAX_LEN 33 +#define M4_MIN_LEN 3 +#define M4_MAX_LEN 9 + +#define M1_MARKER 0 +#define M2_MARKER 64 +#define M3_MARKER 32 +#define M4_MARKER 16 + +#ifndef MIN_LOOKAHEAD +#define MIN_LOOKAHEAD (M2_MAX_LEN + 1) +#endif + +#if defined(LZO_NEED_DICT_H) + +#ifndef LZO_HASH +#define LZO_HASH LZO_HASH_LZO_INCREMENTAL_B +#endif +#define DL_MIN_LEN M2_MIN_LEN + +#ifndef __LZO_DICT_H +#define __LZO_DICT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(D_BITS) && defined(DBITS) +# define D_BITS DBITS +#endif +#if !defined(D_BITS) +# error "D_BITS is not defined" +#endif +#if (D_BITS < 16) +# define D_SIZE LZO_SIZE(D_BITS) +# define D_MASK LZO_MASK(D_BITS) +#else +# define D_SIZE LZO_USIZE(D_BITS) +# define D_MASK LZO_UMASK(D_BITS) +#endif +#define D_HIGH ((D_MASK >> 1) + 1) + +#if !defined(DD_BITS) +# define DD_BITS 0 +#endif +#define DD_SIZE LZO_SIZE(DD_BITS) +#define DD_MASK LZO_MASK(DD_BITS) + +#if !defined(DL_BITS) +# define DL_BITS (D_BITS - DD_BITS) +#endif +#if (DL_BITS < 16) +# define DL_SIZE LZO_SIZE(DL_BITS) +# define DL_MASK LZO_MASK(DL_BITS) +#else +# define DL_SIZE LZO_USIZE(DL_BITS) +# define DL_MASK LZO_UMASK(DL_BITS) +#endif + +#if (D_BITS != DL_BITS + DD_BITS) +# error "D_BITS does not match" +#endif +#if (D_BITS < 8 || D_BITS > 18) +# error "invalid D_BITS" +#endif +#if (DL_BITS < 8 || DL_BITS > 20) +# error "invalid DL_BITS" +#endif +#if (DD_BITS < 0 || DD_BITS > 6) +# error "invalid DD_BITS" +#endif + +#if !defined(DL_MIN_LEN) +# define DL_MIN_LEN 3 +#endif +#if !defined(DL_SHIFT) +# define DL_SHIFT ((DL_BITS + (DL_MIN_LEN - 1)) / DL_MIN_LEN) +#endif + +#define LZO_HASH_GZIP 1 +#define LZO_HASH_GZIP_INCREMENTAL 2 +#define LZO_HASH_LZO_INCREMENTAL_A 3 +#define LZO_HASH_LZO_INCREMENTAL_B 4 + +#if !defined(LZO_HASH) +# error "choose a hashing strategy" +#endif + +#if (DL_MIN_LEN == 3) +# define _DV2_A(p,shift1,shift2) \ + (((( (lzo_uint32)((p)[0]) << shift1) ^ (p)[1]) << shift2) ^ (p)[2]) +# define _DV2_B(p,shift1,shift2) \ + (((( (lzo_uint32)((p)[2]) << shift1) ^ (p)[1]) << shift2) ^ (p)[0]) +# define _DV3_B(p,shift1,shift2,shift3) \ + ((_DV2_B((p)+1,shift1,shift2) << (shift3)) ^ (p)[0]) +#elif (DL_MIN_LEN == 2) +# define _DV2_A(p,shift1,shift2) \ + (( (lzo_uint32)(p[0]) << shift1) ^ p[1]) +# define _DV2_B(p,shift1,shift2) \ + (( (lzo_uint32)(p[1]) << shift1) ^ p[2]) +#else +# error "invalid DL_MIN_LEN" +#endif +#define _DV_A(p,shift) _DV2_A(p,shift,shift) +#define _DV_B(p,shift) _DV2_B(p,shift,shift) +#define DA2(p,s1,s2) \ + (((((lzo_uint32)((p)[2]) << (s2)) + (p)[1]) << (s1)) + (p)[0]) +#define DS2(p,s1,s2) \ + (((((lzo_uint32)((p)[2]) << (s2)) - (p)[1]) << (s1)) - (p)[0]) +#define DX2(p,s1,s2) \ + (((((lzo_uint32)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0]) +#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0]) +#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0]) +#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0]) +#define DMS(v,s) ((lzo_uint) (((v) & (D_MASK >> (s))) << (s))) +#define DM(v) DMS(v,0) + +#if (LZO_HASH == LZO_HASH_GZIP) +# define _DINDEX(dv,p) (_DV_A((p),DL_SHIFT)) + +#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL) +# define __LZO_HASH_INCREMENTAL +# define DVAL_FIRST(dv,p) dv = _DV_A((p),DL_SHIFT) +# define DVAL_NEXT(dv,p) dv = (((dv) << DL_SHIFT) ^ p[2]) +# define _DINDEX(dv,p) (dv) +# define DVAL_LOOKAHEAD DL_MIN_LEN + +#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A) +# define __LZO_HASH_INCREMENTAL +# define DVAL_FIRST(dv,p) dv = _DV_A((p),5) +# define DVAL_NEXT(dv,p) \ + dv ^= (lzo_uint32)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2]) +# define _DINDEX(dv,p) ((0x9f5f * (dv)) >> 5) +# define DVAL_LOOKAHEAD DL_MIN_LEN + +#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B) +# define __LZO_HASH_INCREMENTAL +# define DVAL_FIRST(dv,p) dv = _DV_B((p),5) +# define DVAL_NEXT(dv,p) \ + dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_uint32)(p[2]) << (2*5))) +# define _DINDEX(dv,p) ((0x9f5f * (dv)) >> 5) +# define DVAL_LOOKAHEAD DL_MIN_LEN + +#else +# error "choose a hashing strategy" +#endif + +#ifndef DINDEX +#define DINDEX(dv,p) ((lzo_uint)((_DINDEX(dv,p)) & DL_MASK) << DD_BITS) +#endif +#if !defined(DINDEX1) && defined(D_INDEX1) +#define DINDEX1 D_INDEX1 +#endif +#if !defined(DINDEX2) && defined(D_INDEX2) +#define DINDEX2 D_INDEX2 +#endif + +#if !defined(__LZO_HASH_INCREMENTAL) +# define DVAL_FIRST(dv,p) ((void) 0) +# define DVAL_NEXT(dv,p) ((void) 0) +# define DVAL_LOOKAHEAD 0 +#endif + +#if !defined(DVAL_ASSERT) +#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG) +static void DVAL_ASSERT(lzo_uint32 dv, const lzo_byte *p) +{ + lzo_uint32 df; + DVAL_FIRST(df,(p)); + assert(DINDEX(dv,p) == DINDEX(df,p)); +} +#else +# define DVAL_ASSERT(dv,p) ((void) 0) +#endif +#endif + +#if defined(LZO_DICT_USE_PTR) +# define DENTRY(p,in) (p) +# define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex] +#else +# define DENTRY(p,in) ((lzo_uint) ((p)-(in))) +# define GINDEX(m_pos,m_off,dict,dindex,in) m_off = dict[dindex] +#endif + +#if (DD_BITS == 0) + +# define UPDATE_D(dict,drun,dv,p,in) dict[ DINDEX(dv,p) ] = DENTRY(p,in) +# define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in) +# define UPDATE_P(ptr,drun,p,in) (ptr)[0] = DENTRY(p,in) + +#else + +# define UPDATE_D(dict,drun,dv,p,in) \ + dict[ DINDEX(dv,p) + drun++ ] = DENTRY(p,in); drun &= DD_MASK +# define UPDATE_I(dict,drun,index,p,in) \ + dict[ (index) + drun++ ] = DENTRY(p,in); drun &= DD_MASK +# define UPDATE_P(ptr,drun,p,in) \ + (ptr) [ drun++ ] = DENTRY(p,in); drun &= DD_MASK + +#endif + +#if defined(LZO_DICT_USE_PTR) + +#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \ + (m_pos == NULL || (m_off = (lzo_moff_t) (ip - m_pos)) > max_offset) + +#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ + (BOUNDS_CHECKING_OFF_IN_EXPR( \ + (PTR_LT(m_pos,in) || \ + (m_off = (lzo_moff_t) PTR_DIFF(ip,m_pos)) <= 0 || \ + m_off > max_offset) )) + +#else + +#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \ + (m_off == 0 || \ + ((m_off = (lzo_moff_t) ((ip)-(in)) - m_off) > max_offset) || \ + (m_pos = (ip) - (m_off), 0) ) + +#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ + ((lzo_moff_t) ((ip)-(in)) <= m_off || \ + ((m_off = (lzo_moff_t) ((ip)-(in)) - m_off) > max_offset) || \ + (m_pos = (ip) - (m_off), 0) ) + +#endif + +#if defined(LZO_DETERMINISTIC) +# define LZO_CHECK_MPOS LZO_CHECK_MPOS_DET +#else +# define LZO_CHECK_MPOS LZO_CHECK_MPOS_NON_DET +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +#endif + +#endif + +#define DO_COMPRESS lzo1x_1_compress + +static +lzo_uint do_compress ( const lzo_byte *in , lzo_uint in_len, + lzo_byte *out, lzo_uintp out_len, + lzo_voidp wrkmem ) +{ +#if 0 && defined(__GNUC__) && defined(__i386__) + register const lzo_byte *ip __asm__("%esi"); +#else + register const lzo_byte *ip; +#endif + lzo_byte *op; + const lzo_byte * const in_end = in + in_len; + const lzo_byte * const ip_end = in + in_len - M2_MAX_LEN - 5; + const lzo_byte *ii; + lzo_dict_p const dict = (lzo_dict_p) wrkmem; + + op = out; + ip = in; + ii = ip; + + ip += 4; + for (;;) + { +#if 0 && defined(__GNUC__) && defined(__i386__) + register const lzo_byte *m_pos __asm__("%edi"); +#else + register const lzo_byte *m_pos; +#endif + lzo_moff_t m_off; + lzo_uint m_len; + lzo_uint dindex; + + DINDEX1(dindex,ip); + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; +#if 1 + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + DINDEX2(dindex,ip); +#endif + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + goto literal; + +try_match: +#if 1 && defined(LZO_UNALIGNED_OK_2) + if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip) +#else + if (m_pos[0] != ip[0] || m_pos[1] != ip[1]) +#endif + { + } + else + { + if (m_pos[2] == ip[2]) + { +#if 0 + if (m_off <= M2_MAX_OFFSET) + goto match; + if (lit <= 3) + goto match; + if (lit == 3) + { + assert(op - 2 > out); op[-2] |= LZO_BYTE(3); + *op++ = *ii++; *op++ = *ii++; *op++ = *ii++; + goto code_match; + } + if (m_pos[3] == ip[3]) +#endif + goto match; + } + else + { +#if 0 +#if 0 + if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3) +#else + if (m_off <= M1_MAX_OFFSET && lit == 3) +#endif + { + register lzo_uint t; + + t = lit; + assert(op - 2 > out); op[-2] |= LZO_BYTE(t); + do *op++ = *ii++; while (--t > 0); + assert(ii == ip); + m_off -= 1; + *op++ = LZO_BYTE(M1_MARKER | ((m_off & 3) << 2)); + *op++ = LZO_BYTE(m_off >> 2); + ip += 2; + goto match_done; + } +#endif + } + } + +literal: + UPDATE_I(dict,0,dindex,ip,in); + ++ip; + if (ip >= ip_end) + break; + continue; + +match: + UPDATE_I(dict,0,dindex,ip,in); + if (pd(ip,ii) > 0) + { + register lzo_uint t = pd(ip,ii); + + if (t <= 3) + { + assert(op - 2 > out); + op[-2] |= LZO_BYTE(t); + } + else if (t <= 18) + *op++ = LZO_BYTE(t - 3); + else + { + register lzo_uint tt = t - 18; + + *op++ = 0; + while (tt > 255) + { + tt -= 255; + *op++ = 0; + } + assert(tt > 0); + *op++ = LZO_BYTE(tt); + } + do *op++ = *ii++; while (--t > 0); + } + + assert(ii == ip); + ip += 3; + if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ || + m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++ +#ifdef LZO1Y + || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++ + || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++ +#endif + ) + { + --ip; + m_len = ip - ii; + assert(m_len >= 3); assert(m_len <= M2_MAX_LEN); + + if (m_off <= M2_MAX_OFFSET) + { + m_off -= 1; +#if defined(LZO1X) + *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2)); + *op++ = LZO_BYTE(m_off >> 3); +#elif defined(LZO1Y) + *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2)); + *op++ = LZO_BYTE(m_off >> 2); +#endif + } + else if (m_off <= M3_MAX_OFFSET) + { + m_off -= 1; + *op++ = LZO_BYTE(M3_MARKER | (m_len - 2)); + goto m3_m4_offset; + } + else +#if defined(LZO1X) + { + m_off -= 0x4000; + assert(m_off > 0); assert(m_off <= 0x7fff); + *op++ = LZO_BYTE(M4_MARKER | + ((m_off & 0x4000) >> 11) | (m_len - 2)); + goto m3_m4_offset; + } +#elif defined(LZO1Y) + goto m4_match; +#endif + } + else + { + { + const lzo_byte *end = in_end; + const lzo_byte *m = m_pos + M2_MAX_LEN + 1; + while (ip < end && *m == *ip) + m++, ip++; + m_len = (ip - ii); + } + assert(m_len > M2_MAX_LEN); + + if (m_off <= M3_MAX_OFFSET) + { + m_off -= 1; + if (m_len <= 33) + *op++ = LZO_BYTE(M3_MARKER | (m_len - 2)); + else + { + m_len -= 33; + *op++ = M3_MARKER | 0; + goto m3_m4_len; + } + } + else + { +#if defined(LZO1Y) +m4_match: +#endif + m_off -= 0x4000; + assert(m_off > 0); assert(m_off <= 0x7fff); + if (m_len <= M4_MAX_LEN) + *op++ = LZO_BYTE(M4_MARKER | + ((m_off & 0x4000) >> 11) | (m_len - 2)); + else + { + m_len -= M4_MAX_LEN; + *op++ = LZO_BYTE(M4_MARKER | ((m_off & 0x4000) >> 11)); +m3_m4_len: + while (m_len > 255) + { + m_len -= 255; + *op++ = 0; + } + assert(m_len > 0); + *op++ = LZO_BYTE(m_len); + } + } + +m3_m4_offset: + *op++ = LZO_BYTE((m_off & 63) << 2); + *op++ = LZO_BYTE(m_off >> 6); + } + +#if 0 +match_done: +#endif + ii = ip; + if (ip >= ip_end) + break; + } + + *out_len = op - out; + return pd(in_end,ii); +} + +LZO_PUBLIC(int) +DO_COMPRESS ( const lzo_byte *in , lzo_uint in_len, + lzo_byte *out, lzo_uintp out_len, + lzo_voidp wrkmem ) +{ + lzo_byte *op = out; + lzo_uint t; + +#if defined(__LZO_QUERY_COMPRESS) + if (__LZO_IS_COMPRESS_QUERY(in,in_len,out,out_len,wrkmem)) + return __LZO_QUERY_COMPRESS(in,in_len,out,out_len,wrkmem,D_SIZE,lzo_sizeof(lzo_dict_t)); +#endif + + if (in_len <= M2_MAX_LEN + 5) + t = in_len; + else + { + t = do_compress(in,in_len,op,out_len,wrkmem); + op += *out_len; + } + + if (t > 0) + { + const lzo_byte *ii = in + in_len - t; + + if (op == out && t <= 238) + *op++ = LZO_BYTE(17 + t); + else if (t <= 3) + op[-2] |= LZO_BYTE(t); + else if (t <= 18) + *op++ = LZO_BYTE(t - 3); + else + { + lzo_uint tt = t - 18; + + *op++ = 0; + while (tt > 255) + { + tt -= 255; + *op++ = 0; + } + assert(tt > 0); + *op++ = LZO_BYTE(tt); + } + do *op++ = *ii++; while (--t > 0); + } + + *op++ = M4_MARKER | 1; + *op++ = 0; + *op++ = 0; + + *out_len = op - out; + return LZO_E_OK; +} + +#undef do_compress +#undef DO_COMPRESS +#undef LZO_HASH + +#undef LZO_TEST_DECOMPRESS_OVERRUN +#undef LZO_TEST_DECOMPRESS_OVERRUN_INPUT +#undef LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT +#undef LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND +#undef DO_DECOMPRESS +#define DO_DECOMPRESS lzo1x_decompress + +#if defined(LZO_TEST_DECOMPRESS_OVERRUN) +# if !defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT) +# define LZO_TEST_DECOMPRESS_OVERRUN_INPUT 2 +# endif +# if !defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT) +# define LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT 2 +# endif +# if !defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND) +# define LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND +# endif +#endif + +#undef TEST_IP +#undef TEST_OP +#undef TEST_LOOKBEHIND +#undef NEED_IP +#undef NEED_OP +#undef HAVE_TEST_IP +#undef HAVE_TEST_OP +#undef HAVE_NEED_IP +#undef HAVE_NEED_OP +#undef HAVE_ANY_IP +#undef HAVE_ANY_OP + +#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT) +# if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 1) +# define TEST_IP (ip < ip_end) +# endif +# if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 2) +# define NEED_IP(x) \ + if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun +# endif +#endif + +#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT) +# if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 1) +# define TEST_OP (op <= op_end) +# endif +# if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 2) +# undef TEST_OP +# define NEED_OP(x) \ + if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun +# endif +#endif + +#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND) +# define TEST_LOOKBEHIND(m_pos,out) if (m_pos < out) goto lookbehind_overrun +#else +# define TEST_LOOKBEHIND(m_pos,op) ((void) 0) +#endif + +#if !defined(LZO_EOF_CODE) && !defined(TEST_IP) +# define TEST_IP (ip < ip_end) +#endif + +#if defined(TEST_IP) +# define HAVE_TEST_IP +#else +# define TEST_IP 1 +#endif +#if defined(TEST_OP) +# define HAVE_TEST_OP +#else +# define TEST_OP 1 +#endif + +#if defined(NEED_IP) +# define HAVE_NEED_IP +#else +# define NEED_IP(x) ((void) 0) +#endif +#if defined(NEED_OP) +# define HAVE_NEED_OP +#else +# define NEED_OP(x) ((void) 0) +#endif + +#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) +# define HAVE_ANY_IP +#endif +#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) +# define HAVE_ANY_OP +#endif + +#undef __COPY4 +#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src) + +#undef COPY4 +#if defined(LZO_UNALIGNED_OK_4) +# define COPY4(dst,src) __COPY4(dst,src) +#elif defined(LZO_ALIGNED_OK_4) +# define COPY4(dst,src) __COPY4((lzo_ptr_t)(dst),(lzo_ptr_t)(src)) +#endif + +#if defined(DO_DECOMPRESS) +LZO_PUBLIC(int) +DO_DECOMPRESS ( const lzo_byte *in , lzo_uint in_len, + lzo_byte *out, lzo_uintp out_len, + lzo_voidp wrkmem ) +#endif +{ + register lzo_byte *op; + register const lzo_byte *ip; + register lzo_uint t; +#if defined(COPY_DICT) + lzo_uint m_off; + const lzo_byte *dict_end; +#else + register const lzo_byte *m_pos; +#endif + + const lzo_byte * const ip_end = in + in_len; +#if defined(HAVE_ANY_OP) + lzo_byte * const op_end = out + *out_len; +#endif +#if defined(LZO1Z) + lzo_uint last_m_off = 0; +#endif + + LZO_UNUSED(wrkmem); + +#if defined(__LZO_QUERY_DECOMPRESS) + if (__LZO_IS_DECOMPRESS_QUERY(in,in_len,out,out_len,wrkmem)) + return __LZO_QUERY_DECOMPRESS(in,in_len,out,out_len,wrkmem,0,0); +#endif + +#if defined(COPY_DICT) + if (dict) + { + if (dict_len > M4_MAX_OFFSET) + { + dict += dict_len - M4_MAX_OFFSET; + dict_len = M4_MAX_OFFSET; + } + dict_end = dict + dict_len; + } + else + { + dict_len = 0; + dict_end = NULL; + } +#endif + + *out_len = 0; + + op = out; + ip = in; + + if (*ip > 17) + { + t = *ip++ - 17; + if (t < 4) + goto match_next; + assert(t > 0); NEED_OP(t); NEED_IP(t+1); + do *op++ = *ip++; while (--t > 0); + goto first_literal_run; + } + + while (TEST_IP && TEST_OP) + { + t = *ip++; + if (t >= 16) + goto match; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 15 + *ip++; + } + assert(t > 0); NEED_OP(t+3); NEED_IP(t+4); +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (PTR_ALIGNED2_4(op,ip)) + { +#endif + COPY4(op,ip); + op += 4; ip += 4; + if (--t > 0) + { + if (t >= 4) + { + do { + COPY4(op,ip); + op += 4; ip += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *ip++; while (--t > 0); + } + else + do *op++ = *ip++; while (--t > 0); + } +#if !defined(LZO_UNALIGNED_OK_4) + } + else +#endif +#endif +#if !defined(LZO_UNALIGNED_OK_4) + { + *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; + do *op++ = *ip++; while (--t > 0); + } +#endif + +first_literal_run: + + t = *ip++; + if (t >= 16) + goto match; +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(3); + t = 3; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - (1 + M2_MAX_OFFSET); + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LOOKBEHIND(m_pos,out); NEED_OP(3); + *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + + while (TEST_IP && TEST_OP) + { +match: + if (t >= 64) + { +#if defined(COPY_DICT) +#if defined(LZO1X) + m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); + t = (t >> 4) - 3; +#elif defined(LZO1Z) + m_off = t & 0x1f; + if (m_off >= 0x1c) + m_off = last_m_off; + else + { + m_off = 1 + (m_off << 6) + (*ip++ >> 2); + last_m_off = m_off; + } + t = (t >> 5) - 1; +#endif +#else +#if defined(LZO1X) + m_pos = op - 1; + m_pos -= (t >> 2) & 7; + m_pos -= *ip++ << 3; + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_pos = op - 1; + m_pos -= (t >> 2) & 3; + m_pos -= *ip++ << 2; + t = (t >> 4) - 3; +#elif defined(LZO1Z) + { + lzo_uint off = t & 0x1f; + m_pos = op; + if (off >= 0x1c) + { + assert(last_m_off > 0); + m_pos -= last_m_off; + } + else + { + off = 1 + (off << 6) + (*ip++ >> 2); + m_pos -= off; + last_m_off = off; + } + } + t = (t >> 5) - 1; +#endif + TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1); + goto copy_match; +#endif + } + else if (t >= 32) + { + t &= 31; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 31 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); + last_m_off = m_off; +#else + m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); +#endif +#else +#if defined(LZO1Z) + { + lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2); + m_pos = op - off; + last_m_off = off; + } +#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN) + m_pos = op - 1; + m_pos -= (* (const lzo_ushortp) ip) >> 2; +#else + m_pos = op - 1; + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif +#endif + ip += 2; + } + else if (t >= 16) + { +#if defined(COPY_DICT) + m_off = (t & 8) << 11; +#else + m_pos = op; + m_pos -= (t & 8) << 11; +#endif + t &= 7; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 7 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off += (ip[0] << 6) + (ip[1] >> 2); +#else + m_off += (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_off == 0) + goto eof_found; + m_off += 0x4000; +#if defined(LZO1Z) + last_m_off = m_off; +#endif +#else +#if defined(LZO1Z) + m_pos -= (ip[0] << 6) + (ip[1] >> 2); +#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN) + m_pos -= (* (const lzo_ushortp) ip) >> 2; +#else + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_pos == op) + goto eof_found; + m_pos -= 0x4000; +#if defined(LZO1Z) + last_m_off = op - m_pos; +#endif +#endif + } + else + { +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = 1 + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(2); + t = 2; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = 1 + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - 1; + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LOOKBEHIND(m_pos,out); NEED_OP(2); + *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + } + +#if defined(COPY_DICT) + + NEED_OP(t+3-1); + t += 3-1; COPY_DICT(t,m_off) + +#else + + TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1); +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) + { + assert((op - m_pos) >= 4); +#else + if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) + { +#endif + COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4 - (3 - 1); + do { + COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *m_pos++; while (--t > 0); + } + else +#endif + { +copy_match: + *op++ = *m_pos++; *op++ = *m_pos++; + do *op++ = *m_pos++; while (--t > 0); + } + +#endif + +match_done: +#if defined(LZO1Z) + t = ip[-1] & 3; +#else + t = ip[-2] & 3; +#endif + if (t == 0) + break; + +match_next: + assert(t > 0); NEED_OP(t); NEED_IP(t+1); + do *op++ = *ip++; while (--t > 0); + t = *ip++; + } + } + +#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) + *out_len = op - out; + return LZO_E_EOF_NOT_FOUND; +#endif + +eof_found: + assert(t == 1); + *out_len = op - out; + return (ip == ip_end ? LZO_E_OK : + (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); + +#if defined(HAVE_NEED_IP) +input_overrun: + *out_len = op - out; + return LZO_E_INPUT_OVERRUN; +#endif + +#if defined(HAVE_NEED_OP) +output_overrun: + *out_len = op - out; + return LZO_E_OUTPUT_OVERRUN; +#endif + +#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND) +lookbehind_overrun: + *out_len = op - out; + return LZO_E_LOOKBEHIND_OVERRUN; +#endif +} + +#define LZO_TEST_DECOMPRESS_OVERRUN +#undef DO_DECOMPRESS +#define DO_DECOMPRESS lzo1x_decompress_safe + +#if defined(LZO_TEST_DECOMPRESS_OVERRUN) +# if !defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT) +# define LZO_TEST_DECOMPRESS_OVERRUN_INPUT 2 +# endif +# if !defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT) +# define LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT 2 +# endif +# if !defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND) +# define LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND +# endif +#endif + +#undef TEST_IP +#undef TEST_OP +#undef TEST_LOOKBEHIND +#undef NEED_IP +#undef NEED_OP +#undef HAVE_TEST_IP +#undef HAVE_TEST_OP +#undef HAVE_NEED_IP +#undef HAVE_NEED_OP +#undef HAVE_ANY_IP +#undef HAVE_ANY_OP + +#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT) +# if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 1) +# define TEST_IP (ip < ip_end) +# endif +# if (LZO_TEST_DECOMPRESS_OVERRUN_INPUT >= 2) +# define NEED_IP(x) \ + if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun +# endif +#endif + +#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT) +# if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 1) +# define TEST_OP (op <= op_end) +# endif +# if (LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT >= 2) +# undef TEST_OP +# define NEED_OP(x) \ + if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun +# endif +#endif + +#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND) +# define TEST_LOOKBEHIND(m_pos,out) if (m_pos < out) goto lookbehind_overrun +#else +# define TEST_LOOKBEHIND(m_pos,op) ((void) 0) +#endif + +#if !defined(LZO_EOF_CODE) && !defined(TEST_IP) +# define TEST_IP (ip < ip_end) +#endif + +#if defined(TEST_IP) +# define HAVE_TEST_IP +#else +# define TEST_IP 1 +#endif +#if defined(TEST_OP) +# define HAVE_TEST_OP +#else +# define TEST_OP 1 +#endif + +#if defined(NEED_IP) +# define HAVE_NEED_IP +#else +# define NEED_IP(x) ((void) 0) +#endif +#if defined(NEED_OP) +# define HAVE_NEED_OP +#else +# define NEED_OP(x) ((void) 0) +#endif + +#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP) +# define HAVE_ANY_IP +#endif +#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP) +# define HAVE_ANY_OP +#endif + +#undef __COPY4 +#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src) + +#undef COPY4 +#if defined(LZO_UNALIGNED_OK_4) +# define COPY4(dst,src) __COPY4(dst,src) +#elif defined(LZO_ALIGNED_OK_4) +# define COPY4(dst,src) __COPY4((lzo_ptr_t)(dst),(lzo_ptr_t)(src)) +#endif + +#if defined(DO_DECOMPRESS) +LZO_PUBLIC(int) +DO_DECOMPRESS ( const lzo_byte *in , lzo_uint in_len, + lzo_byte *out, lzo_uintp out_len, + lzo_voidp wrkmem ) +#endif +{ + register lzo_byte *op; + register const lzo_byte *ip; + register lzo_uint t; +#if defined(COPY_DICT) + lzo_uint m_off; + const lzo_byte *dict_end; +#else + register const lzo_byte *m_pos; +#endif + + const lzo_byte * const ip_end = in + in_len; +#if defined(HAVE_ANY_OP) + lzo_byte * const op_end = out + *out_len; +#endif +#if defined(LZO1Z) + lzo_uint last_m_off = 0; +#endif + + LZO_UNUSED(wrkmem); + +#if defined(__LZO_QUERY_DECOMPRESS) + if (__LZO_IS_DECOMPRESS_QUERY(in,in_len,out,out_len,wrkmem)) + return __LZO_QUERY_DECOMPRESS(in,in_len,out,out_len,wrkmem,0,0); +#endif + +#if defined(COPY_DICT) + if (dict) + { + if (dict_len > M4_MAX_OFFSET) + { + dict += dict_len - M4_MAX_OFFSET; + dict_len = M4_MAX_OFFSET; + } + dict_end = dict + dict_len; + } + else + { + dict_len = 0; + dict_end = NULL; + } +#endif + + *out_len = 0; + + op = out; + ip = in; + + if (*ip > 17) + { + t = *ip++ - 17; + if (t < 4) + goto match_next; + assert(t > 0); NEED_OP(t); NEED_IP(t+1); + do *op++ = *ip++; while (--t > 0); + goto first_literal_run; + } + + while (TEST_IP && TEST_OP) + { + t = *ip++; + if (t >= 16) + goto match; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 15 + *ip++; + } + assert(t > 0); NEED_OP(t+3); NEED_IP(t+4); +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (PTR_ALIGNED2_4(op,ip)) + { +#endif + COPY4(op,ip); + op += 4; ip += 4; + if (--t > 0) + { + if (t >= 4) + { + do { + COPY4(op,ip); + op += 4; ip += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *ip++; while (--t > 0); + } + else + do *op++ = *ip++; while (--t > 0); + } +#if !defined(LZO_UNALIGNED_OK_4) + } + else +#endif +#endif +#if !defined(LZO_UNALIGNED_OK_4) + { + *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; + do *op++ = *ip++; while (--t > 0); + } +#endif + +first_literal_run: + + t = *ip++; + if (t >= 16) + goto match; +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(3); + t = 3; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - (1 + M2_MAX_OFFSET); + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LOOKBEHIND(m_pos,out); NEED_OP(3); + *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + + while (TEST_IP && TEST_OP) + { +match: + if (t >= 64) + { +#if defined(COPY_DICT) +#if defined(LZO1X) + m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); + t = (t >> 4) - 3; +#elif defined(LZO1Z) + m_off = t & 0x1f; + if (m_off >= 0x1c) + m_off = last_m_off; + else + { + m_off = 1 + (m_off << 6) + (*ip++ >> 2); + last_m_off = m_off; + } + t = (t >> 5) - 1; +#endif +#else +#if defined(LZO1X) + m_pos = op - 1; + m_pos -= (t >> 2) & 7; + m_pos -= *ip++ << 3; + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_pos = op - 1; + m_pos -= (t >> 2) & 3; + m_pos -= *ip++ << 2; + t = (t >> 4) - 3; +#elif defined(LZO1Z) + { + lzo_uint off = t & 0x1f; + m_pos = op; + if (off >= 0x1c) + { + assert(last_m_off > 0); + m_pos -= last_m_off; + } + else + { + off = 1 + (off << 6) + (*ip++ >> 2); + m_pos -= off; + last_m_off = off; + } + } + t = (t >> 5) - 1; +#endif + TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1); + goto copy_match; +#endif + } + else if (t >= 32) + { + t &= 31; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 31 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); + last_m_off = m_off; +#else + m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); +#endif +#else +#if defined(LZO1Z) + { + lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2); + m_pos = op - off; + last_m_off = off; + } +#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN) + m_pos = op - 1; + m_pos -= (* (const lzo_ushortp) ip) >> 2; +#else + m_pos = op - 1; + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif +#endif + ip += 2; + } + else if (t >= 16) + { +#if defined(COPY_DICT) + m_off = (t & 8) << 11; +#else + m_pos = op; + m_pos -= (t & 8) << 11; +#endif + t &= 7; + if (t == 0) + { + NEED_IP(1); + while (*ip == 0) + { + t += 255; + ip++; + NEED_IP(1); + } + t += 7 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off += (ip[0] << 6) + (ip[1] >> 2); +#else + m_off += (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_off == 0) + goto eof_found; + m_off += 0x4000; +#if defined(LZO1Z) + last_m_off = m_off; +#endif +#else +#if defined(LZO1Z) + m_pos -= (ip[0] << 6) + (ip[1] >> 2); +#elif defined(LZO_UNALIGNED_OK_2) && (LZO_BYTE_ORDER == LZO_LITTLE_ENDIAN) + m_pos -= (* (const lzo_ushortp) ip) >> 2; +#else + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_pos == op) + goto eof_found; + m_pos -= 0x4000; +#if defined(LZO1Z) + last_m_off = op - m_pos; +#endif +#endif + } + else + { +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = 1 + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(2); + t = 2; COPY_DICT(t,m_off) +#else +#if defined(LZO1Z) + t = 1 + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - 1; + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LOOKBEHIND(m_pos,out); NEED_OP(2); + *op++ = *m_pos++; *op++ = *m_pos; +#endif + goto match_done; + } + +#if defined(COPY_DICT) + + NEED_OP(t+3-1); + t += 3-1; COPY_DICT(t,m_off) + +#else + + TEST_LOOKBEHIND(m_pos,out); assert(t > 0); NEED_OP(t+3-1); +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +#if !defined(LZO_UNALIGNED_OK_4) + if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) + { + assert((op - m_pos) >= 4); +#else + if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) + { +#endif + COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4 - (3 - 1); + do { + COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } while (t >= 4); + if (t > 0) do *op++ = *m_pos++; while (--t > 0); + } + else +#endif + { +copy_match: + *op++ = *m_pos++; *op++ = *m_pos++; + do *op++ = *m_pos++; while (--t > 0); + } + +#endif + +match_done: +#if defined(LZO1Z) + t = ip[-1] & 3; +#else + t = ip[-2] & 3; +#endif + if (t == 0) + break; + +match_next: + assert(t > 0); NEED_OP(t); NEED_IP(t+1); + do *op++ = *ip++; while (--t > 0); + t = *ip++; + } + } + +#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) + *out_len = op - out; + return LZO_E_EOF_NOT_FOUND; +#endif + +eof_found: + assert(t == 1); + *out_len = op - out; + return (ip == ip_end ? LZO_E_OK : + (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); + +#if defined(HAVE_NEED_IP) +input_overrun: + *out_len = op - out; + return LZO_E_INPUT_OVERRUN; +#endif + +#if defined(HAVE_NEED_OP) +output_overrun: + *out_len = op - out; + return LZO_E_OUTPUT_OVERRUN; +#endif + +#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND) +lookbehind_overrun: + *out_len = op - out; + return LZO_E_LOOKBEHIND_OVERRUN; +#endif +} + +/***** End of minilzo.c *****/ + diff --git a/distcc/lzo/minilzo.h b/distcc/lzo/minilzo.h new file mode 100644 index 0000000..e3270f9 --- /dev/null +++ b/distcc/lzo/minilzo.h @@ -0,0 +1,100 @@ +/* minilzo.h -- mini subset of the LZO real-time data compression library + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + <markus@oberhumer.com> + http://www.oberhumer.com/opensource/lzo/ + */ + +/* + * NOTE: + * the full LZO package can be found at + * http://www.oberhumer.com/opensource/lzo/ + */ + + +#ifndef __MINILZO_H +#define __MINILZO_H + +#define MINILZO_VERSION 0x1080 + +#ifdef __LZOCONF_H +# error "you cannot use both LZO and miniLZO" +#endif + +#undef LZO_HAVE_CONFIG_H +#include "lzoconf.h" + +#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION) +# error "version mismatch in header files" +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +/*********************************************************************** +// +************************************************************************/ + +/* Memory required for the wrkmem parameter. + * When the required size is 0, you can also pass a NULL pointer. + */ + +#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS +#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t)) +#define LZO1X_MEM_DECOMPRESS (0) + + +/* compression */ +LZO_EXTERN(int) +lzo1x_1_compress ( const lzo_byte *src, lzo_uint src_len, + lzo_byte *dst, lzo_uintp dst_len, + lzo_voidp wrkmem ); + +/* decompression */ +LZO_EXTERN(int) +lzo1x_decompress ( const lzo_byte *src, lzo_uint src_len, + lzo_byte *dst, lzo_uintp dst_len, + lzo_voidp wrkmem /* NOT USED */ ); + +/* safe decompression with overrun testing */ +LZO_EXTERN(int) +lzo1x_decompress_safe ( const lzo_byte *src, lzo_uint src_len, + lzo_byte *dst, lzo_uintp dst_len, + lzo_voidp wrkmem /* NOT USED */ ); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* already included */ + diff --git a/distcc/man/distcc.1 b/distcc/man/distcc.1 new file mode 100644 index 0000000..68e67f2 --- /dev/null +++ b/distcc/man/distcc.1 @@ -0,0 +1,725 @@ +.TH distcc 1 "27 March 2008" +.SH "NAME" +distcc \- distributed C/C++/ObjC compiler with distcc-pump extensions +.SH "SYNOPSIS" +.B distcc +.I <compiler> [COMPILER OPTIONS] +.PP +.B distcc +.I [COMPILER OPTIONS] +.PP +.B <compiler> +.I [COMPILER OPTIONS] +.SH "DESCRIPTION" +.P +distcc distributes compilation of C code across several machines on a +network. distcc should always generate the same results as a local +compile, it is simple to install and use, and it is often much faster than a +local compile. +.PP +This version incorporates plain distcc as well as an enhancment called distcc-pump. +.PP +For each job, distcc in plain mode sends the complete preprocessed source code +and compiler arguments across the network from the client to a compilation +server. In pump-mode, distcc sends the source code and recursively included +header files, so that both preprocessing and compilation can take place on the +compilation servers. This speeds up the delivery of compilations by up to an +order of magnitude over plain distcc. +.PP +Compilation is driven by a client machine, which is typically the developer's +workstation or laptop. The distcc client runs on this machine, as does make, +the preprocessor (if distcc-pump mode is not used), the linker, and other +stages of the build process. Any number of volunteer machines act as +compilation servers and help the client to build the program, by running the +.B distccd(1) +daemon, C compiler and assembler +as required. +.PP +distcc can run across either TCP sockets (on port 3632 by default), or +through a tunnel command such as ssh(1). For TCP connections the +volunteers must run the distccd(1) daemon either directly or from inetd. +For SSH connections distccd must be installed but should +.B not +be listening for connections. +.PP +TCP connections should only be used on secure networks because there +is no user authentication or protection of source or object code. SSH +connections are typically 25% slower because of processor overhead for +encryption, although this can vary greatly depending on CPUs, network +and the program being built. +.PP +distcc is intended to be used with GNU Make's +.B -j +option, which runs several compiler processes concurrently. distcc +spreads the jobs across both local and remote CPUs. Because distcc is +able to distribute most of the work across the network, a higher +concurrency level can be used than for local builds. As a rule of thumb, +the +.B -j +value should be set to about twice the total number of available server +CPUs but subject to client limitations. This setting allows for maximal +interleaving of tasks being blocked waiting for disk or network IO. Note that +distcc can also work with other build control tools, such as SCons, where similar +concurrency settings must be adjusted. + +The +.B -j +setting, especially for large values of -j, must take into account the CPU load +on the client. Additional measures may be needed to curtail the client load. +For example, concurrent linking should be severely curtailed using auxiliary +locks. The effect of other build activity, such as Java compilation when +building mixed code, should be considered. The +.B --localslots_cpp +parameter is by default set to 16. +This limits the number of concurrent processes that do preprocessing in +plain distcc (non-pump) mode. +Therefore, larger +.B -j +values than 16 may be used without overloading a single-CPU +client due to preprocessing. Such large values may speed up parts of the build +that do not involve C compilations, but they may not be useful to distcc +efficiency in plain mode. + +In contrast, with distcc-pump and say 40 servers, a setting of +.B -j80 +or larger may be appropriate even for single-CPU clients. +.PP +It is strongly recommended that you install the same compiler version +on all machines participating in a build. Incompatible compilers may +cause mysterious compile or link failures. +.SH "QUICKSTART" +.TP +1 +For each machine, download distcc, unpack, and install. +.TP +2 +On each of the servers, run +.B distccd --daemon +optionally with +.B --allow +options to restrict access. +.TP +3 +Put the names of the servers in your environment: +.RS +$ export DISTCC_HOSTS='localhost red green blue' +.RE +.TP +4 +Build! +.RS +$ make -j8 CC=distcc +.RE +.SH "QUICKSTART FOR DISTCC-PUMP MODE" +Proceed as above, but in Step 3, specify that the remove hosts are to carry the +burden of preprocessing and that the files sent over the network should be +compressed: + +.RS +$ export DISTCC_HOSTS='--randomize localhost red,cpp,lzo green,cpp,lzo blue,cpp,lzo' +.RE + +The +.B --randomize +option enforces a uniform usage of compile servers. To enjoy distcc-pump, you +will really need 10 or more server CPUs. Wrap your build inside the pump +command, here assuming 10 servers: + +.RS +$ pump make -j20 CC=distcc +.RE +.SH "HOW PLAIN (NON-PUMP) DISTCC WORKS" +distcc only ever runs the compiler and assembler remotely. With plain distcc, +the preprocessor must always run locally because it needs to access various +header files on the local machine which may not be present, or may not be the +same, on the volunteer. The linker similarly needs to examine libraries and +object files, and so must run locally. +.PP +The compiler and assembler take only a single input file (the +preprocessed source) and produce a single output (the object file). +distcc ships these two files across the network and can therefore run +the compiler/assembler remotely. +.PP +Fortunately, for most programs running the preprocessor is +relatively cheap, and the linker is called relatively +infrequent, so most of the work can be distributed. +.PP +distcc examines its command line to determine which of these +phases are being invoked, and whether the job can be +distributed. + +.SH "HOW DISTCC-PUMP MODE WORKS" +distcc-pump runs the prepreprocessor remotely too. To do so, the preprocessor +must have access to all the files that it would have accessed if had been running +locally. distcc-pump therefore gathers all of the recursively included headers, +except the ones that are part of the compiler installation, and sends them along +with the source file to the compilation server. + +In distcc-pump mode, the server unpacks the set of all source files in a +temporary directory, which contains a directory tree that mirrors the part of +the file system that is relevant to preprocessing, including symbolic links. + +The compiler is then run from the path in the temporary directory that +corresponds to the current working directory on the client. +To find and transmit the many hundreds of files that are often part of a single +compilation, distcc-pump uses an incremental include analysis algorithm. The +include server, which is a Python program started by the pump script wrapper, +implements this algorithm. + +The include server uses static analysis of the macro language to deal with +conditional compilation and computed includes. It uses the property that when a +given header file has already been analyzed for includes, it may not be +necessary to do so again if all the include directives are unchanged (along with +other conditions). + +For large builds, header files are included, on average, hundreds of times. With +distcc-pump mode each such file is analyzed only a few times, perhaps just once, +instead of being preprocessed hundreds of times. Also, each source or header +file is now compressed only once, because the include server memoizes the +compressed files. As a result, the time used for compilation on the server may +drop by close to an order of magnitude over plain distcc. Additionally, +compression time may drop by an order or two of magnitude over plain distcc's +scheme of compressing the preprocessed files. + +As a result, distcc-pump mode is able to push out files up to about ten times +faster than distcc. The total build time may drop 30-70% for large builds +compared to plain distcc mode. +.SH "OPTION SUMMARY" +Most options passed to distcc are interpreted as compiler options. +Two options are understood by distcc itself: +.TP +.B --help +Displays summary instructions. +.TP +.B --version +Displays the distcc client version. +.SH "INSTALLING DISTCC" +There are three different ways to call distcc, to suit different +circumstances: +.RS +.PP +distcc can be installed under the name of the real compiler, to +intercept calls to it and run them remotely. This "masqueraded" +compiler has the widest compatibility with existing source trees, and +is convenient when you want to use distcc for all compilation. The +fact that distcc is being used is transparent to the makefiles. +.PP +distcc can be prepended to compiler command lines, such as "distcc cc +-c hello.c" or CC="distcc gcc". This is convenient when you want to +use distcc for only some compilations or to try it out, but can cause +trouble with some makefiles or versions of libtool that assume $CC +does not contain a space. +.PP +Finally, distcc can be used directly as a compiler. "cc" is always +used as the name of the real compiler in this "implicit" mode. This +can be convenient for interactive use when "explicit" mode does not +work but is not really recommended for new use. +.RE +.PP +Remember that you should not use two methods for calling distcc at the +same time. If you are using a masquerade directory, don't change CC and/or +CXX, just put the directory early on your PATH. If you're not using +a masquerade directory, you'll need to either change CC and/or CXX, or +modify the makefile(s) to call distcc explicitly. +.SH "MASQUERADING" +The basic idea is to create a "masquerade directory" which contains +links from the name of the real compiler to the distcc binary. This +directory is inserted early on the PATH, so that calls to the compiler +are intercepted and distcc is run instead. distcc then removes itself +from the PATH to find the real compiler. +.PP +For example: +.PP +.RS +.nf +# mkdir /usr/lib/distcc/bin +# cd /usr/lib/distcc/bin +# ln -s ../../../bin/distcc gcc +# ln -s ../../../bin/distcc cc +# ln -s ../../../bin/distcc g++ +# ln -s ../../../bin/distcc c++ +.fi +.RE +.PP +Then, to use distcc, a user just needs to put the directory +/usr/lib/distcc/bin early in the PATH, and have set a host list in +DISTCC_HOSTS or a file. distcc will handle the rest. +.PP +Note that this masquerade directory must occur on the PATH earlier +than the directory that contains the actual compilers of the same +names, and that any auxiliary programs that these compilers call (such +as as or ld) must also be found on the PATH in a directory after the +masquerade directory since distcc calls out to the real compiler with +a PATH value that has all directory up to and including the masquerade +directory trimmed off. +.PP +It is possible to get a "recursion error" in masquerade mode, which +means that distcc is somehow finding itself again, not the real +compiler. This can indicate that you have two masquerade directories +on the PATH, possibly because of having two distcc installations in +different locations. It can also indicate that you're trying to mix +"masqueraded" and "explicit" operation. +.SH "USING DISTCC WITH CCACHE" +ccache is a program that speeds software builds by caching the results +of compilations. ccache is normally called before distcc, so that +results are retrieved from a normal cache. Some experimentation may +be required for idiosyncratic makefiles to make everything work together. +.PP +The most reliable method is to set +.IP +.B CCACHE_PREFIX="distcc" +.PP +This tells ccache to run distcc as a wrapper around the real +compiler. ccache still uses the real compiler to detect compiler +upgrades. +.PP +ccache can then be run using either a masquerade directory +.I or +by +setting +.IP +.B CC="ccache gcc" +.PP +As of version 2.2, ccache does not cache compilation from preprocessed +source and so will never get a cache hit if it is run from distccd or +distcc. It must be run only on the client side and before distcc to +be any use. + +distcc-pump mode is not compatible with ccache. +.SH "HOST SPECIFICATIONS" +A "host list" tells distcc which machines to use for compilation. In +order, distcc looks in the +.B $DISTCC_HOSTS +environment variable, the user's +.B $DISTCC_DIR/hosts +file, and the system-wide host +file. If no host list can be found, distcc emits a warning and +compiles locally. +.PP +The host list is a simple whitespace separated list of host +specifications. The simplest and most common form is a host names, +such as +.PP +.RS +.B localhost red green blue +.RE +.PP +distcc prefers hosts towards the start of the list, so machines should +be listed in descending order of speed. In particular, when only a +single compilation can be run (such as from a configure script), the +first machine listed is used (but see +.I --randomize +below). +.PP +Placing +.I localhost +at the right point in the list is important to getting good +performance. Because overhead for running jobs locally is low, +localhost should normally be first. However, it is important that the +client have enough cycles free to run the local jobs and the distcc +client. If the client is slower than the volunteers, or if there are +many volunteers, then the client should be put later in the list or +not at all. As a general rule, if the aggregate CPU speed of the +client is less than one fifth of the total, then the client should be +left out of the list. +.PP +If you have a large shared build cluster and a single shared hosts file, +the above rules would cause the first few machines in the hosts +file to be tried first even though they are likely to be busier than machines +later in the list. To avoid this, place the keyword +.I --randomize +into the host list. This will cause the host list to be randomized, +which should improve performance slightly for large build clusters. +.PP +There are two special host names +.B --localslots +and +.B --localslots_cpp +which are useful for adjusting load on the local machine. The +.B --localslots +host specifies how many jobs that cannot be run remotely that can be run concurrently +on the local machine, while +.B --localslots_cpp +controls how many preprocessors will run in parallel on the local machine. Tuning +these values can improve performance. Linking on large projects +can take large amounts of memory. Running parallel linkers, which cannot be +executed remotely, may +force the machine to swap, which reduces performance over just running the +jobs in sequence without swapping. Getting the number of parallel preprocessors just +right allows you to use larger parallel factors with make, since the local machine +now has some machanism for measuring local resource usage. +.PP +Finally there is the host entry +.PP +Performance depends on the details of the source and makefiles used +for the project, and the machine and network speeds. Experimenting +with different settings for the host list and -j factor may improve +performance. +.PP +The syntax is +.PP +.nf + DISTCC_HOSTS = HOSTSPEC ... + HOSTSPEC = LOCAL_HOST | SSH_HOST | TCP_HOST | OLDSTYLE_TCP_HOST + | GLOBAL_OPTION + LOCAL_HOST = localhost[/LIMIT] + | --localslots=<int> + | --localslots_cpp=<int> + SSH_HOST = [USER]@HOSTID[/LIMIT][:COMMAND][OPTIONS] + TCP_HOST = HOSTID[:PORT][/LIMIT][OPTIONS] + OLDSTYLE_TCP_HOST = HOSTID[/LIMIT][:PORT][OPTIONS] + HOSTID = HOSTNAME | IPV4 + OPTIONS = ,OPTION[OPTIONS] + OPTION = lzo | cpp + GLOBAL_OPTION = --randomize +.fi +.PP +Here are some individual examples of the syntax: +.TP +.B localhost +The literal word "localhost" is interpreted specially to cause +compilations to be directly executed, rather than passed to a daemon +on the local machine. If you do want to connect to a daemon on the +local machine for testing, then give the machine's IP address or real +hostname. (This will be slower.) +.TP +.B IPV4 +A literal IPv4 address, such as +.B 10.0.0.1 +.TP +.B HOSTNAME +A hostname to be looked up using the resolver. +.TP +.B :PORT +Connect to a specified decimal port number, rather than the default of +3632. +.TP +.B @HOSTID +Connect to the host over SSH, rather than TCP. Options for the SSH +connection can be set in +.B ~/.ssh/config +.TP +.B USER@ +Connect to the host over SSH as a specified username. +.TP +.B :COMMAND +Connect over SSH, and use a specified path to find the distccd +server. This is normally only needed if for some reason you can't +install distccd into a directory on the default PATH for SSH +connections. Use this if you get errors like "distccd: command not +found" in SSH mode. +.TP +.B /LIMIT +A decimal limit can be added to any host specification to restrict the +number of jobs that this client will send to the machine. The limit +defaults to four per host (two for localhost), but may be further +restricted by the server. You should only need to increase this for +servers with more than two processors. +.TP +.B ,lzo +Enables LZO compression for this TCP or SSH host. +.TP +.B ,cpp +Enables distcc-pump for this host. Note: the build command must be +wrapped in the pump script in order to start the include server. +.TP +.B --randomize +Randomize the host list before execution. +.PP +Here is an example demonstrating some possibilities: +.PP +.RS +.nf +.B localhost/2 @bigman/16:/opt/bin/distccd oldmachine:4200/1 +.B # cartman is down +.B distant/3,lzo +.fi +.RE +.PP +Comments are allowed in host specifications. Comments start with a +hash/pound sign (\fB#\fP) and run to the end of the line. +.PP +If a host in the list is not reachable distcc will emit a warning and +ignore that host for about one minute. +.SH "COMPRESSION" +The +.B lzo +host option specifies that LZO compression should be used for data +transfer, including preprocessed source, object code and error +messages. Compression is usually economical on networks slower than +100Mbps, but results may vary depending on the network, processors and +source tree. +.PP +Enabling compression makes the distcc client and server use more CPU time, but +less network traffic. The added CPU time is insignificant for distcc-pump. The +compression ratio is typically 4:1 for source and 2:1 for object code. +.PP +Using compression requires both client and server to use at least +release 2.9 of distcc. No server configuration is required: the +server always responds with compressed replies to compressed requests. +.SH "SEARCH PATHS" +.PP +If the compiler name is an absolute path, it is passed verbatim to the +server and the compiler is run from that directory. For example: +.PP +.RS +.B distcc /usr/local/bin/gcc-3.1415 -c hello.c +.RE +.PP +If the compiler name is not absolute, or not fully qualified, +distccd's PATH is searched. When distcc is run from a masquerade +directory, only the base name of the compiler is used. The client's +PATH is used only to run the preprocessor and has no effect on the +server's path. +.SH "TIMEOUTS" +.PP +Both the distcc client and server impose timeouts on transfer of data +across the network. This is intended to detect hosts which are down +or unreachable, and to prevent compiles hanging indefinitely if a +server is disconnected while in use. If a client-side timeout +expires, the job will be re-run locally. +.PP +The timeouts are not configurable at present. +.SH "DIAGNOSTICS" +Error messages or warnings from local or remote compilers are passed +through to diagnostic output on the client. +.PP +distcc can supply extensive debugging information when the verbose +option is used. This is controlled by the +.B DISTCC_VERBOSE +environment variable on the client, and the +.B --verbose +option on the server. For troubleshooting, examine both the client +and server error messages. +.SH "EXIT CODES" +The exit code of distcc is normally that of the compiler: +zero for successful compilation and non-zero otherwise. +.PP +distcc distinguishes between "genuine" errors such as a syntax error +in the source, and "accidental" errors such as a networking problem +connecting to a volunteer. In the case of accidental errors, distcc +will retry the compilation locally unless the DISTCC_FALLBACK option +has been disabled. +.PP +If the compiler exits with a signal, distcc returns an exit code of +128 plus the signal number. +.PP +distcc internal errors cause an exit code between 100 and 127. In +particular +.TP +100 +General distcc failure. +.TP +105 +Out of memory. +.TP +110 +Compiler not found. +.TP +111 +Recursive call to distcc. +.TP +116 +No hosts defined and fallbacks disabled. +.PP +(Others are listed in exitcode.h.) +.SH "FILES" +If $DISTCC_HOSTS is not set, distcc reads a host list from either +.B $DISTCC_DIR/hosts +or a system-wide configuration file set at compile time. The file +locations are shown in the output from +.B distcc --help +.PP +distcc creates a number of temporary and lock files underneath the +temporary directory. +.SH "ENVIRONMENT VARIABLES" +distcc's behaviour is controlled by a number of environment variables. +For most cases nothing need be set if the host list is stored in a +file. +.TP +.B "DISTCC_HOSTS" +Space-separated list of volunteer host specifications. +.TP +.B "DISTCC_VERBOSE" +If set to 1, distcc produces explanatory messages on the standard +error stream or in the log file. This can be helpful in debugging +problems. Bug reports should include verbose output. +.TP +.B "DISTCC_LOG" +Log file to receive messages from distcc itself, rather +than stderr. +.TP +.B "DISTCC_FALLBACK" +By default distcc will compile locally if it fails to distribute a job +to the intended machine, or if no host list can be found. If this +variable is set to 0 then fallbacks are disabled and those +compilations will simply fail. Note that this does not affect jobs +which must always be local such as linking. +.TP +.B "DISTCC_SAVE_TEMPS" +If set to 1, temporary files are not deleted after use. Good for +debugging, or if your disks are too empty. +.TP +.B "DISTCC_TCP_CORK" +If set to 0, disable use of "TCP corks", even if they're present on +this system. Using corks normally helps pack requests into fewer +packets and aids performance. This should normally be left enabled. +.TP +.B DISTCC_SSH +Specifies the command used for opening SSH connections. Defaults to +"ssh" but may be set to a different connection command such as "lsh" +or "tsocks-ssh" that accepts a similar command line. The command is +not split into words and is not executed through the shell. +.TP +.B "DISTCC_DIR" +Per-user configuration directory to store lock files and state files. +By default +.B ~/.distcc/ +is used. +.TP +.B "TMPDIR" +Directory for temporary files such as preprocessor output. By default +/tmp/ is used. +.TP +.B "UNCACHED_ERR_FD" +If set and if DISTCC_LOG is not set, distcc errors are written to the +file descriptor identified by this variable. This variable is +intended mainly for automatic use by ccache, which sets it to avoid +caching transient errors such as network problems. +.TP +.B "DISTCC_ENABLE_DISCREPANCY_EMAIL" +If set, distcc sends an email when a compilation failed remotely, but succeeded +locally. Built-in heuristics prevent some such discrepancy email from being sent if +the problem is that a local file changed between the failing remote compilation +and the succeeding local compilation. +.TP +.B "DCC_EMAILLOG_WHOM_TO_BLAME" +The email address for discrepancy email; the default is "distcc-pump-errors". +.SH "CROSS COMPILING" +Cross compilation means building programs to run on a +machine with a different processor, architecture, or +operating system to where they were compiled. distcc +supports cross compilation, including teams of +mixed-architecture machines, although some changes to the +compilation commands may be required. +.PP +The compilation command passed to distcc must be one that +will execute properly on every volunteer machine to produce +an object file of the appropriate type. If the machines +have different processors, then simply using +.B distcc cc +will probably not work, because that will normally invoke the +volunteer's native compiler. +.PP +Machines with the same CPU but different operating systems may not +necessarily generate compatible .o files. +.PP +Several different gcc configurations can be installed +side-by-side on any machine. If you build gcc from source, +you should use the +.B --program-suffix configuration +options to cause it to be installed with a name that encodes +the gcc version and the target platform. +.PP +The recommended convention for the gcc name is +.I TARGET-gcc-VERSION +such as +.B i686-linux-gcc-3.2 +\&. GCC 3.3 will install itself +under this name, in addition to +.I TARGET-gcc +and, if it's native, +.I gcc-VERSION +and +.I gcc +\&. +.PP +The compiler must be installed under the same name on the +client and on every volunteer machine. +.SH "BUGS" +If you think you have found a distcc bug, please see the file +.I reporting-bugs.txt +in the documentation directory for information on how to report it. +.PP +Some makefiles have missing or extra dependencies that cause incorrect +or slow parallel builds. Recursive make is inefficient and can leave +processors unnecessarily idle for long periods. (See +.I Recursive Make Considered Harmful +by Peter Miller.) Makefile bugs are the most common cause of trees +failing to build under distcc. Alternatives to Make such as +.I SCons +can give much faster builds for some projects. +.PP +Using different versions of gcc can cause confusing build problems +because the header files and binary interfaces have changed over time, +and some distributors have included incompatible patches without +changing the version number. distcc does not protect against using +incompatible versions. Compiler errors about link problems or +declarations in system header files are usually due to mismatched or +incorrectly installed compilers. +.PP +Due to limitations in gcc, gdb may not be able to automatically find +the source files for programs built using distcc in some +circumstances. The gdb +.B directory +command can be used. This should be fixed in gcc 3.4. +.PP +gcc's +.B -MD +option can produce output in the wrong directory if the source and +object files are in different directories and the +.B -MF +option is not used. There is no perfect solution because of +incompatible changes between gcc versions. Explicitly specifying the +dependency output file with +.B -MF +will fix the problem. +.PP +TCP mode connections should only be used on trusted networks. +.PP +Including slow machines in the list of volunteer hosts can slow the +build down. +.PP +When distcc or ccache is used on NFS, the filesystem must be exported +with the +.B no_subtree_check +option to allow reliable renames between directories. +.PP +The compiler can be invoked with a command line +.B gcc hello.c +to both compile and link. distcc doesn't split this into separate +parts, but rather runs the whole thing locally. +.PP +distcc-pump mode reverts to plain distcc mode for source files that contain +includes with absolute paths (either directly or in an included file). +.PP +The .o files produced by discc-pump will be different from those produced +locally: for non-ELF files, the debug information will specify compile +directories of the server. The code itself should be identical. +.PP +For the ELF-format, distcc rewrites the .o files to correct compile directory +path information. While the resulting .o files are not bytewise identical to +what would have been produced by compiling on the local client (due to different +padding, etc), they should be functionally identical. +.PP +In distcc-pump mode, the include server is unable to handle certain very complicated computed +includes as found in parts of the boost library. The include server will time +out and distcc will revert to plain mode. +.PP +Other known bugs may be documented on +.I http://distcc.samba.org/ +.SH "AUTHOR" +distcc was written by Martin Pool <mbp@sourcefrog.net>, with the +co-operation of many scholars including Wayne Davison, Frerich Raabe, +Dimitri Papadopoulos and others noted in the NEWS file. Please report +bugs to <distcc@lists.samba.org>. +.SH "LICENCE" +You are free to use distcc. distcc (including this manual) may be +copied, modified or distributed only under the terms of the GNU +General Public Licence version 2 or later. distcc comes with +absolutely no warrany. A copy of the GPL is included in the file +COPYING. +.SH "SEE ALSO" +distccd(1), ccache(1), gcc(1), make(1) +.I http://distcc.samba.org/ +.I http://ccache.samba.org/ diff --git a/distcc/man/distccd.1 b/distcc/man/distccd.1 new file mode 100644 index 0000000..ee744f0 --- /dev/null +++ b/distcc/man/distccd.1 @@ -0,0 +1,295 @@ +.TH distccd 1 "27 March 2008" +.SH "NAME" +distccd \- distributed C/C++ compiler server +.SH "SYNOPSIS" +.B distccd --daemon +.I [OPTIONS] +.SH "DESCRIPTION" +.I distccd +is the server for the distcc(1) distributed compiler. It accepts and +runs compilation jobs for network clients. +.PP +distcc can run over either TCP or a connection command such as ssh(1). +TCP connections are fast but relatively insecure. SSH connections are +secure but slower. +.PP +For SSH connections, distccd must be installed on the volunteer but +should not run as a daemon -- it will be started over SSH as needed. +SSH connections have several advantages: neither the client nor server +listens on any new ports; compilations run with the privileges of the +user that requested them; unauthorized users cannot access the server; +and source and output is protected in transit. +.PP +For TCP connections, distccd can run either from an inetd-style +program, or as a standalone server. Standalone mode is recommended +because it is slightly more efficient and allows distccd to regulate +the number of incoming jobs. The +.B --listen +and +.B --allow +options can be used for simple IP-based access control. +.PP +distcc may be started either by root or any other user. If run by +root, it gives away privileges and changes to the user specified by +the +.B --user +option, or the user called "distcc", or the user called "nobody". +.PP +distccd does not have a configuration file; it's behaviour is +controlled only by command-line options and requests from +clients. +.SH "STANDALONE SERVER" +The recommended method for running distccd is as a standalone server. +distccd will listen for network connections and fork several child +processes to serve them. +.PP +If you installed distcc using a packaged version you may be able to +start the server using the standard mechanism for your operating +system, such as +.RS +.PP +# service distcc start +.RE +.PP +To start distccd as a standalone service, run a command like +this either as root or an ordinary user: +.RS +.PP +# distccd --daemon +.RE +.SH "RUNNING FROM INIT" +distccd may be run as a standalone daemon under the +control of another program like init(8) or +daemontools. The super-server starts distccd +when the system boots, and whenever it exits. +.PP +distccd should be started just as for a standalone server, +except that the +.B --no-detach +option should be used so that the super-server can monitor it. +.PP +For example, to add distccd as a process to Linux +sysvinit, add this line to +.I /etc/inittab +.RS +.PP +dscc:2345:respawn:/usr/local/bin/distccd --verbose --no-detach --daemon +.RE +.SH "RUNNING FROM INETD" +distccd may be started from a network super-server such as inetd or +xinetd. In this case inetd listens for network connections and +invokes distccd when one arrives. +.PP +This is slightly less efficient than running a standalone distccd +daemon. distccd is not able to regulate the number of concurrent jobs +accepted, but there may be an option in your inetd configuration to do +so. +.PP +For traditional Unix inetd, a line like this can be added +to /etc/inetd.conf: +.RS +.PP +distcc stream tcp nowait.6000 root /usr/local/bin/distccd distccd --inetd +.RE +.PP +inetd imposes a limit on the rate of connections to a service to +protect against accidental or intentional overuse. The default in +Linux NetKit inetd is 40 per minute, which is far too low for distccd. +The \.6000 option raises the limit to 6000 per minute. +.SH "TERMINATING DISTCCD" +To shut down a standalone server, send a SIGTERM +signal to the parent process. The most reliable way to do +this from a script is to use the +.I --pid-file +option to record its process ID. Shutting down the server in this way +should allow any jobs currently in progress to complete. +.SH "OPTIONS" +.TP +.B --help +Display summary usage information. +.TP +.B --version +Shows the daemon version and exits. +.TP +.B -j, --jobs JOBS +Sets a limit on the number of jobs that can be accepted at any time. +By default this is set to two greater than the number of CPUs on the +machine, to allow for some processes being blocked on network IO. +(Daemon mode only.) +.TP +.B -N, --nice NICENESS +Makes the daemon more nice about giving up the CPU to other tasks on +the machine. NICENESS is an increment to the current priority of the +process. The range of priorities depends on the operating system but +is typically 0 to 20. By default the niceness is increased by 5. +.TP +.B -p, --port PORT +Set the TCP port to listen on, rather than the default of 3632. +(Daemon mode only.) +.TP +.B --listen ADDRESS +Instructs the distccd daemon to listen on the IP address +ADDRESS. This can be useful for access control +on dual-homed hosts. (Daemon mode only.) +.TP +.B -P, --pid-file FILE +Save daemon process id to file FILE. (Daemon mode only.) +.TP +.B --user USER +If distccd gets executed as root, change to user USER. +.TP +.B -a, --allow IPADDR[/MASK] +Instructs distccd to accept connections from the IP address +IPADDR. A CIDR mask length can be supplied optionally after a +trailing slash, e.g. 192.168.0.0/24, in which case addresses that +match in the most significant MASK bits will be allowed. If no +--allow options are specified, all clients are allowed. Unauthorized +connections are rejected by closing the TCP connection immediately. A +warning is logged on the server but nothing is sent ot the client. +.TP +.B --job-lifetime SECONDS +Kills a distccd job if it runs for more than SECONDS seconds. This prevents +denial of service from clients that don't properly disconnect and compilers +that fail to terminate. By default this is turned off. +.TP +.B --no-detach +Do not detach from the shell that started the daemon. +.TP +.B --no-fork +Don't fork children for each connection, to allow attaching gdb. +Don't use this if you don't understand it! +.TP +.B --log-file FILE +Send messages to file FILE instead of syslog. +Logging directly to a file is significantly faster than +going via syslog and is recommended. +.TP +.B --log-level LEVEL +Set the minimum severity of error that will be included in the log +file. Useful if you only want to see error messages rather than an +entry for each connection. LEVEL can be any of the standard syslog +levels, and in particular +.I critical, error, warning, notice, info, +or +.I debug. +.TP +.B --log-stderr +Send log messages to stderr, rather than to a file or +syslog. This is mainly intended for use in debugging. Do not use in +inetd mode. +.TP +.B --verbose +Include debug messages in log. Equivalent to +.B --log-level=debug +.TP +.B --wizard +Turn on all options appropriate for starting distccd under gdb: run as +a daemon, log verbosely to stderr, and do not detach or fork. For +wizards only. +.TP +.B --stats +Turn on the statistics HTTP server. By default it is off. +(Daemon mode only.) +.TP +.B --stats-port PORT +Set the TCP port to listen on for HTTP requests, rather than the default of 3633. +(Daemon mode only.) +.TP +.B --inetd +Serve a client connected to stdin/stdout. As the name +suggests, this option should be used when distccd is run +from within a super-server like inetd. distccd +assumes inetd mode when stdin is a socket. +.TP +.B --daemon +Bind and listen on a socket, rather than running from +inetd. This is used for standalone mode. distccd +assumes daemon mode at startup if stdin is a tty, so +--daemon should be explicitly specified when +starting distccd from a script or in a non-interactive +ssh connection. +.SH "SEARCH PATHS" +.PP +distcc can pass either a relative or an absolute name for the compiler +to distccd. If distcc is given an explicit absolute compiler +filename, that name is used verbatim on both the client and server. +If the compiler name is not an absolute path, or if the client is used +in masquerade mode, then the server's PATH is searched. +.PP +distccd inherits its search path from its parent process. By default +distccd tries to remove directories that seem to contain distccd +masquerade links, to guard against inadvertent recursion. The +.B DISTCCD_PATH +environment variable may be used to set the path. +.PP +The search path is logged when --verbose is given. In case of +confusion, check the logs. +.PP +When distccd is run over ssh, the +.I $HOME/.ssh/environment +file may be useful in setting the path. See +.B ssh(1). +.SH "DIAGNOSTICS" +distccd logs messages to syslog's +.I daemon +facility by +default, which normally writes to +.I /var/log/daemon +or +.I /var/log/messages. +Log messages can be sent to a +different file using the +.B --log-file option. +.SH "ENVIRONMENT VARIABLES" +.TP +.B "DISTCC_CMDLIST" +If the environment variable DISTCC_CMDLIST is set, +load a list of supported commands from the file named by DISTCC_CMDLIST, and +refuse to serve any command whose last DISTCC_CMDLIST_MATCHWORDS last words +do not match those of a command in that list. See the comments in src/serve.c. +.TP +.B "DISTCC_CMDLIST_NUMWORDS" +The number of words, from the end of the command, to match. The default is 1. +.TP +.B "DISTCCD_PATH" +When starting distccd, if this value is set it will be used unaltered +for the command-execution PATH. The code that normally tries to +remove masquerade directories from the path is skipped. +.TP +.B "DISTCC_SAVE_TEMPS" +If set to 1, temporary files are not deleted after use. +.PP +Note that +.B "DISTCC_LOG" +does not affect the log destination for the server. +.TP +.B "DISTCC_TCP_DEFER_ACCEPT" +On Linux, turn on the TCP_DEFER_ACCEPT socket option. Defaults to on. +.TP +.B "TMPDIR" +Directory for temporary files such as preprocessor output. By default +/tmp/ is used. +.SH "SEE ALSO" +distcc(1), ccache(1), gcc(1), make(1) +.I http://distcc.samba.org/ +.SH "BUGS" +IP-based access control is not secure against attackers able to spoof +TCP connections, and cannot discriminate different users on a client. +.PP +TCP connections are not secure against attackers able to observe or +modify network traffic. +.PP +Because ccache does not cache compilation from +.B .i +files, it is not useful to call it from distccd. +.SH "LICENCE" +You are free to use distcc. distcc (including this manual) may be +copied, modified or distributed only under the terms of the GNU +General Public Licence version 2 or later. distcc comes with +absolutely no warrany. A copy of the GPL is included in the file +COPYING. +.SH "AUTHOR" +distcc was written by Martin Pool <mbp@sourcefrog.net>, with the +co-operation of many scholars including Wayne Davison, Frerich Raabe, +Dimitri Papadopoulos and others noted in the NEWS file. Please report +bugs to <distcc@lists.samba.org>. diff --git a/distcc/man/distccmon-text.1 b/distcc/man/distccmon-text.1 new file mode 100644 index 0000000..7f7b159 --- /dev/null +++ b/distcc/man/distccmon-text.1 @@ -0,0 +1,56 @@ +.TH distccmon-text 1 "2 October 2004" +.SH "NAME" +.LP +distccmon\-text \- Displays current compilation jobs in text form. +.SH "SYNTAX" +.LP +distccmon-text [DELAY] +.SH "DESCRIPTION" +.LP +Displays current compilation jobs in text form. distccmon-text must +be run on the client machine, with the same setting for +.I DISTCC_DIR +(or home directory) +as the user running the distcc client. +.SH "OPTIONS" +.LP +.TP +\fBDELAY\fR +repeatedly updates after \fIdelay\fP (fractional) seconds. +.SH "OUTPUT FORMAT" +.LP +The output of distccmon-text contains one line for each job currently +being compiled. Each line contains the following columns: +.TP +.I PID +ID of the distcc client process. +.TP +.I STATE +Identifies the phase of operation. In order these may be "Startup", +"Blocked", "Connected", "Preprocess", "Conect", "Send", "Receive" and +"Done". +.TP +.I FILE +The input filename, if known. +.TP +.I HOST[SLOT] +The compile hostname. May be followed in square brackets by the slot +index for that host. +.LP +When a delay is specified, each block of output is terminated by a +blank line. +.SH "EXAMPLES" +.LP +To display currently active jobs (updated every second): +.IP +distccmon\-text 1 +.LP +To display the status once: +.IP +distccmon\-text +.SH "AUTHORS" +.LP +distcc was written by Martin Pool <mbp@sourcefrog.net>, with the co\-operation of many scholars including Wayne Davison, Frerich Raabe, Dimitri Papadopoulos and others noted in the NEWS file. Please report bugs to <distcc@lists.samba.org>. +.SH "SEE ALSO" +.LP d +distccd(1), ccache(1), gcc(1), make(1) http://distcc.samba.org/ http://ccache.samba.org/ diff --git a/distcc/mkinstalldirs b/distcc/mkinstalldirs new file mode 100755 index 0000000..25a0791 --- /dev/null +++ b/distcc/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman <friedman@prep.ai.mit.edu> +# Created: 1993-05-16 +# Public domain + +# $Id: mkinstalldirs,v 1.1 2002/05/28 02:43:45 mbp Exp $ + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/distcc/packaging/RedHat/init.d/distcc b/distcc/packaging/RedHat/init.d/distcc new file mode 100644 index 0000000..70d6d31 --- /dev/null +++ b/distcc/packaging/RedHat/init.d/distcc @@ -0,0 +1,287 @@ +#!/bin/bash +# +# /etc/rc.d/init.d/distcc +# +# Starts the distccd daemon +# +# WARNING: Don't enable on untrusted networks +# +# NOTE: Allows access from all networks listed in clients.allow +# clients.allow is searched for in directories +# /etc/distcc/`dnsdomainname`/clients.allow +# /etc/distcc/clients.allow +# Format of clients.allow is +# addr/size +# addr/size +# addr/size +# etc. e.g. +# 196.168.0.0/16 +# 127.0.0.0/8 +# +# chkconfig: - 80 20 +# description: Start the distcc daemon +# processname: distccd +# + +# +# Determine which kind of configuration we're using +# +system=unknown +if [ -f /etc/debian_version ]; then + system=debian +elif [ -f /etc/redhat-release ]; then + system=redhat +else + echo "$0: Unknown system, please port and contact distcc-admin@google.com" 1>&2 + exit 1 +fi + +OPTIONS="--daemon --stats --job-lifetime=1200" +USER=distcc +PROG="distccd" +PIDFILE=/var/run/$PROG.pid +EXEC="/usr/bin/distccd" + + +if [[ -f /etc/sitename.install ]]; then + # goobuntu + DOMAIN=`cat /etc/sitename.install` + CONFIGDIR=/etc/site/current/distcc + NORESTART=$CONFIGDIR/no-restart +else + # grhat + DOMAIN=`/bin/dnsdomainname` + CONFIGDIR=/etc/distcc + NORESTART=$CONFIGDIR/no-restart +fi + + +if [ $system = redhat ]; then + + . /etc/init.d/functions + + # Source networking configuration. + . /etc/sysconfig/network + + # Check that networking is up. + [ ${NETWORKING} = "no" ] && exit 0 +fi + + +if [ $system = debian ]; then + . /lib/lsb/init-functions + . /etc/default/distcc + thisscript="$0" + if [ ! -f "$thisscript" ]; then + echo "$0: Cannot find myself" 1>&2 + exit 1 + fi + if [ "$STARTDISTCC" != "true" ] ; then + echo "STARTDISTCC is set to false in /etc/default/distcc" + echo "$something is not starting" + exit 0 + fi + touch $PIDFILE + chown $USER $PIDFILE +fi + + + +# Tell distccd to store temp files in /var/tmp/distcc to avoid filling up / +# The sysadmin may want to make /var/tmp/distcc be a symlink to a +# directory on a larger partition (hence the /. on the chown) +TMPDIR=/var/tmp/distcc +export TMPDIR +mkdir -p $TMPDIR +chown $USER $TMPDIR/. +rm -rf $TMPDIR/* || : +chmod 700 $TMPDIR + +RETVAL=0 + +[ -x /usr/bin/distccd ] || exit 0 + +ALLOWFILE="" + + +if test -f $CONFIGDIR/clients.allow; then + ALLOWFILE=$CONFIGDIR/clients.allow +elif test -f $CONFIGDIR/$DOMAIN/clients.allow; then + ALLOWFILE=$CONFIGDIR/$DOMAIN/clients.allow +else + echo "$0: no clients allowed" + exit 1 +fi + + +if test "$ALLOWFILE"x != x; then + ALLOW_OPTIONS=$(sed -e 's/#.*$//' -e '/^[ ]*$/d' -e 's/^/--allow=/' < $ALLOWFILE) + OPTIONS="$OPTIONS $ALLOW_OPTIONS" +fi + + +rh_start() { + echo -n "Starting $PROG" + + if [[ -f $NORESTART ]] + then + echo "failed -- $NORESTART present" + return 1 + fi + + #--- begin crosstool-specific configuration --- + # List directories which might contain installations of crosstool on this node + # This will let users compile on this node regardless of where crosstool + # is installed on client or server + # Neccessary because crosstool compilers are identified not just by + # a command name, but also by the directory they're in (if you have + # several toolchains built for a particular target). + COMPILERS= + # modern crosstool + test -d /usr/crosstool && COMPILERS="$COMPILERS /usr/crosstool/*/*/bin/*-[cg][+c][+c] /usr/crosstool/v*/*/*/bin/*-[cg][+c][+c] /usr/crosstool/v4/*/*/*/bin/*-[cg][+c][+c]" + # old crosstool (which stored everything in a directory named for the build system type) + test -d /opt/crosstool && COMPILERS="$COMPILERS /opt/crosstool/*/*/*/bin/*-[cg][+c][+c]" + test -d /home/build/buildtools/crosstool/v7 && COMPILERS="$COMPILERS /home/build/buildtools/crosstool/v7/*/*/bin/*-[cg][+c][+c]" + if test ! -d $CONFIGDIR; then + mkdir -p $CONFIGDIR + fi + CMDLIST=$CONFIGDIR/commands.allow + # Expand the wildcards in $COMPILERS, put one file per line, empty file if no match + echo $COMPILERS | tr '\040' '\012' > $CMDLIST + ENV="DISTCC_CMDLIST=$CMDLIST DISTCC_CMDLIST_NUMWORDS=5 TMPDIR=$TMPDIR" + #--- done crosstool-specific configuration --- + + daemon --user $USER $ENV $PROG $OPTIONS + RETVAL=$? + echo + [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$PROG + return $RETVAL +} + +rh_stop() { + echo -n "Shutting down $PROG" + killproc $PROG + RETVAL=$? + echo + [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$PROG + return $RETVAL +} + +redhat() { + case "$1" in + start) + rh_start + ;; + stop) + rh_stop + ;; + status) + status $PROG + RETVAL=$? + ;; + restart|reload) + rh_stop + rh_start + RETVAL=$? + ;; + condrestart) + if [ -f /var/lock/subsys/$PROG ]; then + rh_stop + rh_start + RETVAL=$? + fi + ;; + *) + echo $"Usage $0 {start|stop|restart|condrestart|status}" + exit 1 + esac +} + +deb_start() { + log_begin_msg "Starting $PROG..." + + if [[ -f $NORESTART ]] + then + log_end_msg 1 + echo "distcc start failed -- $NORESTART present" + return 1 + fi + + #--- begin crosstool-specific configuration --- + # List directories which might contain installations of crosstool on this node + # This will let users compile on this node regardless of where crosstool + # is installed on client or server + # Neccessary because crosstool compilers are identified not just by + # a command name, but also by the directory they're in (if you have + # several toolchains built for a particular target). + COMPILERS= + # modern crosstool + test -d /usr/crosstool && COMPILERS="$COMPILERS /usr/crosstool/*/*/bin/*-[cg][+c][+c] /usr/crosstool/v*/*/*/bin/*-[cg][+c][+c] /usr/crosstool/v4/*/*/*/bin/*-[cg][+c][+c]" + # old crosstool (which stored everything in a directory named for the build system type) + test -d /opt/crosstool && COMPILERS="$COMPILERS /opt/crosstool/*/*/*/bin/*-[cg][+c][+c]" + test -d /home/build/buildtools/crosstool/v7 && COMPILERS="$COMPILERS /home/build/buildtools/crosstool/v7/*/*/bin/*-[cg][+c][+c]" + if test ! -d $CONFIGDIR; then + mkdir -p $CONFIGDIR + fi + CMDLIST=$CONFIGDIR/commands.allow + # Expand the wildcards in $COMPILERS, put one file per line, empty file if no match + echo $COMPILERS | tr '\040' '\012' > $CMDLIST + export DISTCC_CMDLIST=$CMDLIST + export DISTCC_CMDLIST_NUMWORDS=5 + export TMPDIR=$TMPDIR + + #--- done crosstool-specific configuration --- + + start-stop-daemon --start --name distccd --pidfile $PIDFILE -m --chuid $USER --exec $EXEC -- $OPTIONS || log_end_msg 1 + RETVAL=$? + log_end_msg 0 + return $RETVAL +} + +deb_stop() { + log_begin_msg "Shutting down $PROG..." + start-stop-daemon --stop --name distccd --exec $EXEC --retry 30 || \ + log_success_msg "$PROG not running" + RETVAL=$? + log_end_msg 0 + [ $RETVAL -eq 0 ] && rm -f $PIDFILE + return $RETVAL +} + +debian() { + case "$1" in + start) + deb_start + ;; + stop) + deb_stop + ;; + restart|reload) + deb_stop + deb_start + RETVAL=$? + ;; + condrestart) + if [ -f /var/lock/subsys/$PROG ]; then + deb_stop + deb_start + RETVAL=$? + fi + ;; + *) + echo $"Usage $0 {start|stop|restart|condrestart}" + exit 1 + esac +} + +# See how we were called. + +RETVAL=0 +if [ $system = debian ]; then + debian "$@" +elif [ $system = redhat ]; then + redhat "$@" +fi + +exit $RETVAL + diff --git a/distcc/packaging/RedHat/logrotate.d/distcc b/distcc/packaging/RedHat/logrotate.d/distcc new file mode 100644 index 0000000..52429f7 --- /dev/null +++ b/distcc/packaging/RedHat/logrotate.d/distcc @@ -0,0 +1,13 @@ +# logrotate.d example configuration for distcc, contributed by Dag +# Wieers. + +# The "copytruncate" option means distcc can keep appending to the +# same filehandle. You would otherwise need to shut down and restart +# distccd. + +/var/log/distccd.log { + missingok + copytruncate + notifempty +} + diff --git a/distcc/packaging/RedHat/xinetd.d/distcc b/distcc/packaging/RedHat/xinetd.d/distcc new file mode 100644 index 0000000..ebd9bdc --- /dev/null +++ b/distcc/packaging/RedHat/xinetd.d/distcc @@ -0,0 +1,15 @@ +# default: on +# description: distccd serves C/C++ compilation requests from distcc clients. +# WARNING: This service should ONLY be used on trusted networks. +service distcc +{ + socket_type = stream + protocol = tcp + port = 3632 + wait = no + user = nobody + server = /usr/bin/distccd + server_args = --inetd + disable = yes +} + diff --git a/distcc/popt/.stamp-conf.in b/distcc/popt/.stamp-conf.in new file mode 100644 index 0000000..e48829e --- /dev/null +++ b/distcc/popt/.stamp-conf.in @@ -0,0 +1 @@ +@src_dir@ diff --git a/distcc/popt/README.popt b/distcc/popt/README.popt new file mode 100644 index 0000000..baeb7fe --- /dev/null +++ b/distcc/popt/README.popt @@ -0,0 +1,12 @@ +This is a perfectly ordinary copy of libpopt 1.7, except that the +configure scripts have been munged to make them fit with distcc. NLS +support has been removed, because distcc currently does not use it. + +It is only used on platforms that do not have a sufficiently +up-to-date copy of their own. If you build distcc on a platform which +has popt, this directory should not be used. (You can control that +using the --with-included-popt configure flag.) + +popt has no apparent home page, but the source can be retrieved from + +ftp://ftp.rpm.org/pub/rpm/dist/rpm-4.1.x
\ No newline at end of file diff --git a/distcc/popt/findme.c b/distcc/popt/findme.c new file mode 100644 index 0000000..a950e50 --- /dev/null +++ b/distcc/popt/findme.c @@ -0,0 +1,50 @@ +/** \ingroup popt + * \file popt/findme.c + */ + +/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING + file accompanying popt source distributions, available from + ftp://ftp.rpm.org/pub/rpm/dist. */ + +#include "system.h" +#include "findme.h" + +const char * findProgramPath(const char * argv0) { + char * path = getenv("PATH"); + char * pathbuf; + char * start, * chptr; + char * buf; + + if (argv0 == NULL) return NULL; /* XXX can't happen */ + /* If there is a / in the argv[0], it has to be an absolute path */ + if (strchr(argv0, '/')) + return xstrdup(argv0); + + if (path == NULL) return NULL; + + start = pathbuf = alloca(strlen(path) + 1); + buf = malloc(strlen(path) + strlen(argv0) + sizeof("/")); + if (buf == NULL) return NULL; /* XXX can't happen */ + strcpy(pathbuf, path); + + chptr = NULL; + /*@-branchstate@*/ + do { + if ((chptr = strchr(start, ':'))) + *chptr = '\0'; + sprintf(buf, "%s/%s", start, argv0); + + if (!access(buf, X_OK)) + return buf; + + if (chptr) + start = chptr + 1; + else + start = NULL; + } while (start && *start); + /*@=branchstate@*/ + + free(buf); + + return NULL; +} diff --git a/distcc/popt/findme.h b/distcc/popt/findme.h new file mode 100644 index 0000000..a016b86 --- /dev/null +++ b/distcc/popt/findme.h @@ -0,0 +1,20 @@ +/** \ingroup popt + * \file popt/findme.h + */ + +/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING + file accompanying popt source distributions, available from + ftp://ftp.rpm.org/pub/rpm/dist. */ + +#ifndef H_FINDME +#define H_FINDME + +/** + * Return absolute path to executable by searching PATH. + * @param argv0 name of executable + * @return (malloc'd) absolute path to executable (or NULL) + */ +/*@null@*/ const char * findProgramPath(/*@null@*/ const char * argv0) + /*@*/; + +#endif diff --git a/distcc/popt/popt.c b/distcc/popt/popt.c new file mode 100644 index 0000000..e9c4c17 --- /dev/null +++ b/distcc/popt/popt.c @@ -0,0 +1,1236 @@ +/** \ingroup popt + * \file popt/popt.c + */ + +/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING + file accompanying popt source distributions, available from + ftp://ftp.rpm.org/pub/rpm/dist */ + +#undef MYDEBUG + +#include "system.h" + +#if HAVE_FLOAT_H +#include <float.h> +#endif +#include <math.h> + +#include "findme.h" +#include "poptint.h" + +#ifdef MYDEBUG +/*@unchecked@*/ +int _popt_debug = 0; +#endif + +#ifndef HAVE_STRERROR +static char * strerror(int errno) { + extern int sys_nerr; + extern char * sys_errlist[]; + + if ((0 <= errno) && (errno < sys_nerr)) + return sys_errlist[errno]; + else + return POPT_("unknown errno"); +} +#endif + +#ifdef MYDEBUG +/*@unused@*/ static void prtcon(const char *msg, poptContext con) +{ + if (msg) fprintf(stderr, "%s", msg); + fprintf(stderr, "\tcon %p os %p nextCharArg \"%s\" nextArg \"%s\" argv[%d] \"%s\"\n", + con, con->os, + (con->os->nextCharArg ? con->os->nextCharArg : ""), + (con->os->nextArg ? con->os->nextArg : ""), + con->os->next, + (con->os->argv && con->os->argv[con->os->next] + ? con->os->argv[con->os->next] : "")); +} +#endif + +void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) +{ + con->execPath = _free(con->execPath); + con->execPath = xstrdup(path); + con->execAbsolute = allowAbsolute; + /*@-nullstate@*/ /* LCL: con->execPath can be NULL? */ + return; + /*@=nullstate@*/ +} + +static void invokeCallbacksPRE(poptContext con, const struct poptOption * opt) + /*@globals internalState@*/ + /*@modifies internalState@*/ +{ + if (opt != NULL) + for (; opt->longName || opt->shortName || opt->arg; opt++) { + if (opt->arg == NULL) continue; /* XXX program error. */ + if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { + /* Recurse on included sub-tables. */ + invokeCallbacksPRE(con, opt->arg); + } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && + (opt->argInfo & POPT_CBFLAG_PRE)) + { /*@-castfcnptr@*/ + poptCallbackType cb = (poptCallbackType)opt->arg; + /*@=castfcnptr@*/ + /* Perform callback. */ + /*@-moduncon -noeffectuncon @*/ + cb(con, POPT_CALLBACK_REASON_PRE, NULL, NULL, opt->descrip); + /*@=moduncon =noeffectuncon @*/ + } + } +} + +static void invokeCallbacksPOST(poptContext con, const struct poptOption * opt) + /*@globals internalState@*/ + /*@modifies internalState@*/ +{ + if (opt != NULL) + for (; opt->longName || opt->shortName || opt->arg; opt++) { + if (opt->arg == NULL) continue; /* XXX program error. */ + if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { + /* Recurse on included sub-tables. */ + invokeCallbacksPOST(con, opt->arg); + } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && + (opt->argInfo & POPT_CBFLAG_POST)) + { /*@-castfcnptr@*/ + poptCallbackType cb = (poptCallbackType)opt->arg; + /*@=castfcnptr@*/ + /* Perform callback. */ + /*@-moduncon -noeffectuncon @*/ + cb(con, POPT_CALLBACK_REASON_POST, NULL, NULL, opt->descrip); + /*@=moduncon =noeffectuncon @*/ + } + } +} + +static void invokeCallbacksOPTION(poptContext con, + const struct poptOption * opt, + const struct poptOption * myOpt, + /*@null@*/ const void * myData, int shorty) + /*@globals internalState@*/ + /*@modifies internalState@*/ +{ + const struct poptOption * cbopt = NULL; + + if (opt != NULL) + for (; opt->longName || opt->shortName || opt->arg; opt++) { + if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { + /* Recurse on included sub-tables. */ + if (opt->arg != NULL) /* XXX program error */ + invokeCallbacksOPTION(con, opt->arg, myOpt, myData, shorty); + } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK && + !(opt->argInfo & POPT_CBFLAG_SKIPOPTION)) { + /* Save callback info. */ + cbopt = opt; + } else if (cbopt != NULL && + ((myOpt->shortName && opt->shortName && shorty && + myOpt->shortName == opt->shortName) || + (myOpt->longName && opt->longName && + /*@-nullpass@*/ /* LCL: opt->longName != NULL */ + !strcmp(myOpt->longName, opt->longName))) + /*@=nullpass@*/ + ) + { /*@-castfcnptr@*/ + poptCallbackType cb = (poptCallbackType)cbopt->arg; + /*@=castfcnptr@*/ + const void * cbData = (cbopt->descrip ? cbopt->descrip : myData); + /* Perform callback. */ + if (cb != NULL) { /* XXX program error */ + /*@-moduncon -noeffectuncon @*/ + cb(con, POPT_CALLBACK_REASON_OPTION, myOpt, + con->os->nextArg, cbData); + /*@=moduncon =noeffectuncon @*/ + } + /* Terminate (unless explcitly continuing). */ + if (!(cbopt->argInfo & POPT_CBFLAG_CONTINUE)) + return; + } + } +} + +poptContext poptGetContext(const char * name, int argc, const char ** argv, + const struct poptOption * options, int flags) +{ + poptContext con = malloc(sizeof(*con)); + + if (con == NULL) return NULL; /* XXX can't happen */ + memset(con, 0, sizeof(*con)); + + con->os = con->optionStack; + con->os->argc = argc; + /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */ + con->os->argv = argv; + /*@=dependenttrans =assignexpose@*/ + con->os->argb = NULL; + + if (!(flags & POPT_CONTEXT_KEEP_FIRST)) + con->os->next = 1; /* skip argv[0] */ + + con->leftovers = calloc( (argc + 1), sizeof(*con->leftovers) ); + /*@-dependenttrans -assignexpose@*/ /* FIX: W2DO? */ + con->options = options; + /*@=dependenttrans =assignexpose@*/ + con->aliases = NULL; + con->numAliases = 0; + con->flags = flags; + con->execs = NULL; + con->numExecs = 0; + con->finalArgvAlloced = argc * 2; + con->finalArgv = calloc( con->finalArgvAlloced, sizeof(*con->finalArgv) ); + con->execAbsolute = 1; + con->arg_strip = NULL; + + if (getenv("POSIXLY_CORRECT") || getenv("POSIX_ME_HARDER")) + con->flags |= POPT_CONTEXT_POSIXMEHARDER; + + if (name) { + char * t = malloc(strlen(name) + 1); + if (t) con->appName = strcpy(t, name); + } + + /*@-internalglobs@*/ + invokeCallbacksPRE(con, con->options); + /*@=internalglobs@*/ + + return con; +} + +static void cleanOSE(/*@special@*/ struct optionStackEntry *os) + /*@uses os @*/ + /*@releases os->nextArg, os->argv, os->argb @*/ + /*@modifies os @*/ +{ + os->nextArg = _free(os->nextArg); + os->argv = _free(os->argv); + os->argb = PBM_FREE(os->argb); +} + +/*@-boundswrite@*/ +void poptResetContext(poptContext con) +{ + int i; + + if (con == NULL) return; + while (con->os > con->optionStack) { + cleanOSE(con->os--); + } + con->os->argb = PBM_FREE(con->os->argb); + con->os->currAlias = NULL; + con->os->nextCharArg = NULL; + con->os->nextArg = NULL; + con->os->next = 1; /* skip argv[0] */ + + con->numLeftovers = 0; + con->nextLeftover = 0; + con->restLeftover = 0; + con->doExec = NULL; + + if (con->finalArgv != NULL) + for (i = 0; i < con->finalArgvCount; i++) { + /*@-unqualifiedtrans@*/ /* FIX: typedef double indirection. */ + con->finalArgv[i] = _free(con->finalArgv[i]); + /*@=unqualifiedtrans@*/ + } + + con->finalArgvCount = 0; + con->arg_strip = PBM_FREE(con->arg_strip); + /*@-nullstate@*/ /* FIX: con->finalArgv != NULL */ + return; + /*@=nullstate@*/ +} +/*@=boundswrite@*/ + +/* Only one of longName, shortName should be set, not both. */ +/*@-boundswrite@*/ +static int handleExec(/*@special@*/ poptContext con, + /*@null@*/ const char * longName, char shortName) + /*@uses con->execs, con->numExecs, con->flags, con->doExec, + con->finalArgv, con->finalArgvAlloced, con->finalArgvCount @*/ + /*@modifies con @*/ +{ + poptItem item; + int i; + + if (con->execs == NULL || con->numExecs <= 0) /* XXX can't happen */ + return 0; + + for (i = con->numExecs - 1; i >= 0; i--) { + item = con->execs + i; + if (longName && !(item->option.longName && + !strcmp(longName, item->option.longName))) + continue; + else if (shortName != item->option.shortName) + continue; + break; + } + if (i < 0) return 0; + + + if (con->flags & POPT_CONTEXT_NO_EXEC) + return 1; + + if (con->doExec == NULL) { + con->doExec = con->execs + i; + return 1; + } + + /* We already have an exec to do; remember this option for next + time 'round */ + if ((con->finalArgvCount + 1) >= (con->finalArgvAlloced)) { + con->finalArgvAlloced += 10; + con->finalArgv = realloc(con->finalArgv, + sizeof(*con->finalArgv) * con->finalArgvAlloced); + } + + i = con->finalArgvCount++; + if (con->finalArgv != NULL) /* XXX can't happen */ + { char *s = malloc((longName ? strlen(longName) : 0) + 3); + if (s != NULL) { /* XXX can't happen */ + if (longName) + sprintf(s, "--%s", longName); + else + sprintf(s, "-%c", shortName); + con->finalArgv[i] = s; + } else + con->finalArgv[i] = NULL; + } + + /*@-nullstate@*/ /* FIX: con->finalArgv[] == NULL */ + return 1; + /*@=nullstate@*/ +} +/*@=boundswrite@*/ + +/* Only one of longName, shortName may be set at a time */ +static int handleAlias(/*@special@*/ poptContext con, + /*@null@*/ const char * longName, char shortName, + /*@exposed@*/ /*@null@*/ const char * nextCharArg) + /*@uses con->aliases, con->numAliases, con->optionStack, con->os, + con->os->currAlias, con->os->currAlias->option.longName @*/ + /*@modifies con @*/ +{ + poptItem item = con->os->currAlias; + int rc; + int i; + + if (item) { + if (longName && (item->option.longName && + !strcmp(longName, item->option.longName))) + return 0; + if (shortName && shortName == item->option.shortName) + return 0; + } + + if (con->aliases == NULL || con->numAliases <= 0) /* XXX can't happen */ + return 0; + + for (i = con->numAliases - 1; i >= 0; i--) { + item = con->aliases + i; + if (longName && !(item->option.longName && + !strcmp(longName, item->option.longName))) + continue; + else if (shortName != item->option.shortName) + continue; + break; + } + if (i < 0) return 0; + + if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH) + return POPT_ERROR_OPTSTOODEEP; + +/*@-boundsread@*/ + if (nextCharArg && *nextCharArg) + con->os->nextCharArg = nextCharArg; +/*@=boundsread@*/ + + con->os++; + con->os->next = 0; + con->os->stuffed = 0; + con->os->nextArg = NULL; + con->os->nextCharArg = NULL; + con->os->currAlias = con->aliases + i; + rc = poptDupArgv(con->os->currAlias->argc, con->os->currAlias->argv, + &con->os->argc, &con->os->argv); + con->os->argb = NULL; + + return (rc ? rc : 1); +} + +/*@-bounds -boundswrite @*/ +static int execCommand(poptContext con) + /*@globals internalState @*/ + /*@modifies internalState @*/ +{ + poptItem item = con->doExec; + const char ** argv; + int argc = 0; + int rc; + + if (item == NULL) /*XXX can't happen*/ + return POPT_ERROR_NOARG; + + if (item->argv == NULL || item->argc < 1 || + (!con->execAbsolute && strchr(item->argv[0], '/'))) + return POPT_ERROR_NOARG; + + argv = malloc(sizeof(*argv) * + (6 + item->argc + con->numLeftovers + con->finalArgvCount)); + if (argv == NULL) return POPT_ERROR_MALLOC; /* XXX can't happen */ + + if (!strchr(item->argv[0], '/') && con->execPath) { + char *s = alloca(strlen(con->execPath) + strlen(item->argv[0]) + sizeof("/")); + sprintf(s, "%s/%s", con->execPath, item->argv[0]); + argv[argc] = s; + } else { + argv[argc] = findProgramPath(item->argv[0]); + } + if (argv[argc++] == NULL) return POPT_ERROR_NOARG; + + if (item->argc > 1) { + memcpy(argv + argc, item->argv + 1, sizeof(*argv) * (item->argc - 1)); + argc += (item->argc - 1); + } + + if (con->finalArgv != NULL && con->finalArgvCount > 0) { + memcpy(argv + argc, con->finalArgv, + sizeof(*argv) * con->finalArgvCount); + argc += con->finalArgvCount; + } + + if (con->leftovers != NULL && con->numLeftovers > 0) { +#if 0 + argv[argc++] = "--"; +#endif + memcpy(argv + argc, con->leftovers, sizeof(*argv) * con->numLeftovers); + argc += con->numLeftovers; + } + + argv[argc] = NULL; + +#ifdef __hpux + rc = setresuid(getuid(), getuid(),-1); + if (rc) return POPT_ERROR_ERRNO; +#else +/* + * XXX " ... on BSD systems setuid() should be preferred over setreuid()" + * XXX sez' Timur Bakeyev <mc@bat.ru> + * XXX from Norbert Warmuth <nwarmuth@privat.circular.de> + */ +#if defined(HAVE_SETUID) + rc = setuid(getuid()); + if (rc) return POPT_ERROR_ERRNO; +#elif defined (HAVE_SETREUID) + rc = setreuid(getuid(), getuid()); /*hlauer: not portable to hpux9.01 */ + if (rc) return POPT_ERROR_ERRNO; +#else + ; /* Can't drop privileges */ +#endif +#endif + + if (argv[0] == NULL) + return POPT_ERROR_NOARG; + +#ifdef MYDEBUG +if (_popt_debug) + { const char ** avp; + fprintf(stderr, "==> execvp(%s) argv[%d]:", argv[0], argc); + for (avp = argv; *avp; avp++) + fprintf(stderr, " '%s'", *avp); + fprintf(stderr, "\n"); + } +#endif + + rc = execvp(argv[0], (char *const *)argv); + + return POPT_ERROR_ERRNO; +} +/*@=bounds =boundswrite @*/ + +/*@-boundswrite@*/ +/*@observer@*/ /*@null@*/ static const struct poptOption * +findOption(const struct poptOption * opt, /*@null@*/ const char * longName, + char shortName, + /*@null@*/ /*@out@*/ poptCallbackType * callback, + /*@null@*/ /*@out@*/ const void ** callbackData, + int singleDash) + /*@modifies *callback, *callbackData */ +{ + const struct poptOption * cb = NULL; + + /* This happens when a single - is given */ + if (singleDash && !shortName && (longName && *longName == '\0')) + shortName = '-'; + + for (; opt->longName || opt->shortName || opt->arg; opt++) { + + if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { + const struct poptOption * opt2; + + /* Recurse on included sub-tables. */ + if (opt->arg == NULL) continue; /* XXX program error */ + opt2 = findOption(opt->arg, longName, shortName, callback, + callbackData, singleDash); + if (opt2 == NULL) continue; + /* Sub-table data will be inheirited if no data yet. */ + if (!(callback && *callback)) return opt2; + if (!(callbackData && *callbackData == NULL)) return opt2; + /*@-observertrans -dependenttrans @*/ + *callbackData = opt->descrip; + /*@=observertrans =dependenttrans @*/ + return opt2; + } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_CALLBACK) { + cb = opt; + } else if (longName && opt->longName && + (!singleDash || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) && + /*@-nullpass@*/ /* LCL: opt->longName != NULL */ + !strcmp(longName, opt->longName)) + /*@=nullpass@*/ + { + break; + } else if (shortName && shortName == opt->shortName) { + break; + } + } + + if (!opt->longName && !opt->shortName) + return NULL; + /*@-modobserver -mods @*/ + if (callback) *callback = NULL; + if (callbackData) *callbackData = NULL; + if (cb) { + if (callback) + /*@-castfcnptr@*/ + *callback = (poptCallbackType)cb->arg; + /*@=castfcnptr@*/ + if (!(cb->argInfo & POPT_CBFLAG_INC_DATA)) { + if (callbackData) + /*@-observertrans@*/ /* FIX: typedef double indirection. */ + *callbackData = cb->descrip; + /*@=observertrans@*/ + } + } + /*@=modobserver =mods @*/ + + return opt; +} +/*@=boundswrite@*/ + +static const char * findNextArg(/*@special@*/ poptContext con, + unsigned argx, int delete_arg) + /*@uses con->optionStack, con->os, + con->os->next, con->os->argb, con->os->argc, con->os->argv @*/ + /*@modifies con @*/ +{ + struct optionStackEntry * os = con->os; + const char * arg; + + do { + int i; + arg = NULL; + while (os->next == os->argc && os > con->optionStack) os--; + if (os->next == os->argc && os == con->optionStack) break; + if (os->argv != NULL) + for (i = os->next; i < os->argc; i++) { + /*@-sizeoftype@*/ + if (os->argb && PBM_ISSET(i, os->argb)) + /*@innercontinue@*/ continue; + if (*os->argv[i] == '-') + /*@innercontinue@*/ continue; + if (--argx > 0) + /*@innercontinue@*/ continue; + arg = os->argv[i]; + if (delete_arg) { + if (os->argb == NULL) os->argb = PBM_ALLOC(os->argc); + if (os->argb != NULL) /* XXX can't happen */ + PBM_SET(i, os->argb); + } + /*@innerbreak@*/ break; + /*@=sizeoftype@*/ + } + if (os > con->optionStack) os--; + } while (arg == NULL); + return arg; +} + +/*@-boundswrite@*/ +static /*@only@*/ /*@null@*/ const char * +expandNextArg(/*@special@*/ poptContext con, const char * s) + /*@uses con->optionStack, con->os, + con->os->next, con->os->argb, con->os->argc, con->os->argv @*/ + /*@modifies con @*/ +{ + const char * a = NULL; + size_t alen; + char *t, *te; + size_t tn = strlen(s) + 1; + char c; + + te = t = malloc(tn);; + if (t == NULL) return NULL; /* XXX can't happen */ + while ((c = *s++) != '\0') { + switch (c) { +#if 0 /* XXX can't do this */ + case '\\': /* escape */ + c = *s++; + /*@switchbreak@*/ break; +#endif + case '!': + if (!(s[0] == '#' && s[1] == ':' && s[2] == '+')) + /*@switchbreak@*/ break; + /* XXX Make sure that findNextArg deletes only next arg. */ + if (a == NULL) { + if ((a = findNextArg(con, 1, 1)) == NULL) + /*@switchbreak@*/ break; + } + s += 3; + + alen = strlen(a); + tn += alen; + *te = '\0'; + t = realloc(t, tn); + te = t + strlen(t); + strncpy(te, a, alen); te += alen; + continue; + /*@notreached@*/ /*@switchbreak@*/ break; + default: + /*@switchbreak@*/ break; + } + *te++ = c; + } + *te = '\0'; + t = realloc(t, strlen(t) + 1); /* XXX memory leak, hard to plug */ + return t; +} +/*@=boundswrite@*/ + +static void poptStripArg(/*@special@*/ poptContext con, int which) + /*@uses con->arg_strip, con->optionStack @*/ + /*@defines con->arg_strip @*/ + /*@modifies con @*/ +{ + /*@-sizeoftype@*/ + if (con->arg_strip == NULL) + con->arg_strip = PBM_ALLOC(con->optionStack[0].argc); + if (con->arg_strip != NULL) /* XXX can't happen */ + PBM_SET(which, con->arg_strip); + /*@=sizeoftype@*/ + /*@-compdef@*/ /* LCL: con->arg_strip udefined? */ + return; + /*@=compdef@*/ +} + +int poptSaveLong(long * arg, int argInfo, long aLong) +{ + /* XXX Check alignment, may fail on funky platforms. */ + if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1))) + return POPT_ERROR_NULLARG; + + if (argInfo & POPT_ARGFLAG_NOT) + aLong = ~aLong; + switch (argInfo & POPT_ARGFLAG_LOGICALOPS) { + case 0: + *arg = aLong; + break; + case POPT_ARGFLAG_OR: + *arg |= aLong; + break; + case POPT_ARGFLAG_AND: + *arg &= aLong; + break; + case POPT_ARGFLAG_XOR: + *arg ^= aLong; + break; + default: + return POPT_ERROR_BADOPERATION; + /*@notreached@*/ break; + } + return 0; +} + +int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong) +{ + /* XXX Check alignment, may fail on funky platforms. */ + if (arg == NULL || (((unsigned long)arg) & (sizeof(*arg)-1))) + return POPT_ERROR_NULLARG; + + if (argInfo & POPT_ARGFLAG_NOT) + aLong = ~aLong; + switch (argInfo & POPT_ARGFLAG_LOGICALOPS) { + case 0: + *arg = aLong; + break; + case POPT_ARGFLAG_OR: + *arg |= aLong; + break; + case POPT_ARGFLAG_AND: + *arg &= aLong; + break; + case POPT_ARGFLAG_XOR: + *arg ^= aLong; + break; + default: + return POPT_ERROR_BADOPERATION; + /*@notreached@*/ break; + } + return 0; +} + +/*@-boundswrite@*/ +/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */ +int poptGetNextOpt(poptContext con) +{ + const struct poptOption * opt = NULL; + int done = 0; + + if (con == NULL) + return -1; + while (!done) { + const char * origOptString = NULL; + poptCallbackType cb = NULL; + const void * cbData = NULL; + const char * longArg = NULL; + int canstrip = 0; + int shorty = 0; + + while (!con->os->nextCharArg && con->os->next == con->os->argc + && con->os > con->optionStack) { + cleanOSE(con->os--); + } + if (!con->os->nextCharArg && con->os->next == con->os->argc) { + /*@-internalglobs@*/ + invokeCallbacksPOST(con, con->options); + /*@=internalglobs@*/ + if (con->doExec) return execCommand(con); + return -1; + } + + /* Process next long option */ + if (!con->os->nextCharArg) { + char * localOptString, * optString; + int thisopt; + + /*@-sizeoftype@*/ + if (con->os->argb && PBM_ISSET(con->os->next, con->os->argb)) { + con->os->next++; + continue; + } + /*@=sizeoftype@*/ + thisopt = con->os->next; + if (con->os->argv != NULL) /* XXX can't happen */ + origOptString = con->os->argv[con->os->next++]; + + if (origOptString == NULL) /* XXX can't happen */ + return POPT_ERROR_BADOPT; + + if (con->restLeftover || *origOptString != '-') { + if (con->flags & POPT_CONTEXT_POSIXMEHARDER) + con->restLeftover = 1; + if (con->flags & POPT_CONTEXT_ARG_OPTS) { + con->os->nextArg = xstrdup(origOptString); + return 0; + } + if (con->leftovers != NULL) /* XXX can't happen */ + con->leftovers[con->numLeftovers++] = origOptString; + continue; + } + + /* Make a copy we can hack at */ + localOptString = optString = + strcpy(alloca(strlen(origOptString) + 1), origOptString); + + if (optString[0] == '\0') + return POPT_ERROR_BADOPT; + + if (optString[1] == '-' && !optString[2]) { + con->restLeftover = 1; + continue; + } else { + char *oe; + int singleDash; + + optString++; + if (*optString == '-') + singleDash = 0, optString++; + else + singleDash = 1; + + /* XXX aliases with arg substitution need "--alias=arg" */ + if (handleAlias(con, optString, '\0', NULL)) + continue; + + if (handleExec(con, optString, '\0')) + continue; + + /* Check for "--long=arg" option. */ + for (oe = optString; *oe && *oe != '='; oe++) + {}; + if (*oe == '=') { + *oe++ = '\0'; + /* XXX longArg is mapped back to persistent storage. */ + longArg = origOptString + (oe - localOptString); + } + + opt = findOption(con->options, optString, '\0', &cb, &cbData, + singleDash); + if (!opt && !singleDash) + return POPT_ERROR_BADOPT; + } + + if (!opt) { + con->os->nextCharArg = origOptString + 1; + } else { + if (con->os == con->optionStack && + opt->argInfo & POPT_ARGFLAG_STRIP) + { + canstrip = 1; + poptStripArg(con, thisopt); + } + shorty = 0; + } + } + + /* Process next short option */ + /*@-branchstate@*/ /* FIX: W2DO? */ + if (con->os->nextCharArg) { + origOptString = con->os->nextCharArg; + + con->os->nextCharArg = NULL; + + if (handleAlias(con, NULL, *origOptString, origOptString + 1)) + continue; + + if (handleExec(con, NULL, *origOptString)) { + /* Restore rest of short options for further processing */ + origOptString++; + if (*origOptString != '\0') + con->os->nextCharArg = origOptString; + continue; + } + + opt = findOption(con->options, NULL, *origOptString, &cb, + &cbData, 0); + if (!opt) + return POPT_ERROR_BADOPT; + shorty = 1; + + origOptString++; + if (*origOptString != '\0') + con->os->nextCharArg = origOptString; + } + /*@=branchstate@*/ + + if (opt == NULL) return POPT_ERROR_BADOPT; /* XXX can't happen */ + if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) { + if (poptSaveInt((int *)opt->arg, opt->argInfo, 1L)) + return POPT_ERROR_BADOPERATION; + } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) { + if (opt->arg) { + if (poptSaveInt((int *)opt->arg, opt->argInfo, (long)opt->val)) + return POPT_ERROR_BADOPERATION; + } + } else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) { + con->os->nextArg = _free(con->os->nextArg); + /*@-usedef@*/ /* FIX: W2DO? */ + if (longArg) { + /*@=usedef@*/ + longArg = expandNextArg(con, longArg); + con->os->nextArg = longArg; + } else if (con->os->nextCharArg) { + longArg = expandNextArg(con, con->os->nextCharArg); + con->os->nextArg = longArg; + con->os->nextCharArg = NULL; + } else { + while (con->os->next == con->os->argc && + con->os > con->optionStack) { + cleanOSE(con->os--); + } + if (con->os->next == con->os->argc) { + if (!(opt->argInfo & POPT_ARGFLAG_OPTIONAL)) + /*@-compdef@*/ /* FIX: con->os->argv not defined */ + return POPT_ERROR_NOARG; + /*@=compdef@*/ + con->os->nextArg = NULL; + } else { + + /* + * Make sure this isn't part of a short arg or the + * result of an alias expansion. + */ + if (con->os == con->optionStack && + (opt->argInfo & POPT_ARGFLAG_STRIP) && + canstrip) { + poptStripArg(con, con->os->next); + } + + if (con->os->argv != NULL) { /* XXX can't happen */ + /* XXX watchout: subtle side-effects live here. */ + longArg = con->os->argv[con->os->next++]; + longArg = expandNextArg(con, longArg); + con->os->nextArg = longArg; + } + } + } + longArg = NULL; + + if (opt->arg) { + switch (opt->argInfo & POPT_ARG_MASK) { + case POPT_ARG_STRING: + /* XXX memory leak, hard to plug */ + *((const char **) opt->arg) = (con->os->nextArg) + ? xstrdup(con->os->nextArg) : NULL; + /*@switchbreak@*/ break; + + case POPT_ARG_INT: + case POPT_ARG_LONG: + { long aLong = 0; + char *end; + + if (con->os->nextArg) { + aLong = strtol(con->os->nextArg, &end, 0); + if (!(end && *end == '\0')) + return POPT_ERROR_BADNUMBER; + } + + if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_LONG) { + if (aLong == LONG_MIN || aLong == LONG_MAX) + return POPT_ERROR_OVERFLOW; + if (poptSaveLong((long *)opt->arg, opt->argInfo, aLong)) + return POPT_ERROR_BADOPERATION; + } else { + if (aLong > INT_MAX || aLong < INT_MIN) + return POPT_ERROR_OVERFLOW; + if (poptSaveInt((int *)opt->arg, opt->argInfo, aLong)) + return POPT_ERROR_BADOPERATION; + } + } /*@switchbreak@*/ break; + + case POPT_ARG_FLOAT: + case POPT_ARG_DOUBLE: + { double aDouble = 0.0; + char *end; + + if (con->os->nextArg) { + /*@-mods@*/ + int saveerrno = errno; + errno = 0; + aDouble = strtod(con->os->nextArg, &end); + if (errno == ERANGE) + return POPT_ERROR_OVERFLOW; + errno = saveerrno; + /*@=mods@*/ + if (*end != '\0') + return POPT_ERROR_BADNUMBER; + } + + if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_DOUBLE) { + *((double *) opt->arg) = aDouble; + } else { +#define _ABS(a) ((((a) - 0.0) < DBL_EPSILON) ? -(a) : (a)) + if ((_ABS(aDouble) - FLT_MAX) > DBL_EPSILON) + return POPT_ERROR_OVERFLOW; + if ((FLT_MIN - _ABS(aDouble)) > DBL_EPSILON) + return POPT_ERROR_OVERFLOW; + *((float *) opt->arg) = aDouble; + } + } /*@switchbreak@*/ break; + default: + fprintf(stdout, + POPT_("option type (%d) not implemented in popt\n"), + (opt->argInfo & POPT_ARG_MASK)); + exit(EXIT_FAILURE); + /*@notreached@*/ /*@switchbreak@*/ break; + } + } + } + + if (cb) { + /*@-internalglobs@*/ + invokeCallbacksOPTION(con, con->options, opt, cbData, shorty); + /*@=internalglobs@*/ + } else if (opt->val && ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_VAL)) + done = 1; + + if ((con->finalArgvCount + 2) >= (con->finalArgvAlloced)) { + con->finalArgvAlloced += 10; + con->finalArgv = realloc(con->finalArgv, + sizeof(*con->finalArgv) * con->finalArgvAlloced); + } + + if (con->finalArgv != NULL) + { char *s = malloc((opt->longName ? strlen(opt->longName) : 0) + 3); + if (s != NULL) { /* XXX can't happen */ + if (opt->longName) + sprintf(s, "%s%s", + ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), + opt->longName); + else + sprintf(s, "-%c", opt->shortName); + con->finalArgv[con->finalArgvCount++] = s; + } else + con->finalArgv[con->finalArgvCount++] = NULL; + } + + if (opt->arg && (opt->argInfo & POPT_ARG_MASK) == POPT_ARG_NONE) + /*@-ifempty@*/ ; /*@=ifempty@*/ + else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_VAL) + /*@-ifempty@*/ ; /*@=ifempty@*/ + else if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) { + if (con->finalArgv != NULL && con->os->nextArg) + con->finalArgv[con->finalArgvCount++] = + /*@-nullpass@*/ /* LCL: con->os->nextArg != NULL */ + xstrdup(con->os->nextArg); + /*@=nullpass@*/ + } + } + + return (opt ? opt->val : -1); /* XXX can't happen */ +} +/*@=boundswrite@*/ + +const char * poptGetOptArg(poptContext con) +{ + const char * ret = NULL; + /*@-branchstate@*/ + if (con) { + ret = con->os->nextArg; + con->os->nextArg = NULL; + } + /*@=branchstate@*/ + return ret; +} + +const char * poptGetArg(poptContext con) +{ + const char * ret = NULL; + if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers) + ret = con->leftovers[con->nextLeftover++]; + return ret; +} + +const char * poptPeekArg(poptContext con) +{ + const char * ret = NULL; + if (con && con->leftovers != NULL && con->nextLeftover < con->numLeftovers) + ret = con->leftovers[con->nextLeftover]; + return ret; +} + +/*@-boundswrite@*/ +const char ** poptGetArgs(poptContext con) +{ + if (con == NULL || + con->leftovers == NULL || con->numLeftovers == con->nextLeftover) + return NULL; + + /* some apps like [like RPM ;-) ] need this NULL terminated */ + con->leftovers[con->numLeftovers] = NULL; + + /*@-nullret -nullstate @*/ /* FIX: typedef double indirection. */ + return (con->leftovers + con->nextLeftover); + /*@=nullret =nullstate @*/ +} +/*@=boundswrite@*/ + +poptContext poptFreeContext(poptContext con) +{ + poptItem item; + int i; + + if (con == NULL) return con; + poptResetContext(con); + con->os->argb = _free(con->os->argb); + + if (con->aliases != NULL) + for (i = 0; i < con->numAliases; i++) { + item = con->aliases + i; + /*@-modobserver -observertrans -dependenttrans@*/ + item->option.longName = _free(item->option.longName); + item->option.descrip = _free(item->option.descrip); + item->option.argDescrip = _free(item->option.argDescrip); + /*@=modobserver =observertrans =dependenttrans@*/ + item->argv = _free(item->argv); + } + con->aliases = _free(con->aliases); + + if (con->execs != NULL) + for (i = 0; i < con->numExecs; i++) { + item = con->execs + i; + /*@-modobserver -observertrans -dependenttrans@*/ + item->option.longName = _free(item->option.longName); + item->option.descrip = _free(item->option.descrip); + item->option.argDescrip = _free(item->option.argDescrip); + /*@=modobserver =observertrans =dependenttrans@*/ + item->argv = _free(item->argv); + } + con->execs = _free(con->execs); + + con->leftovers = _free(con->leftovers); + con->finalArgv = _free(con->finalArgv); + con->appName = _free(con->appName); + con->otherHelp = _free(con->otherHelp); + con->execPath = _free(con->execPath); + con->arg_strip = PBM_FREE(con->arg_strip); + + con = _free(con); + return con; +} + +int poptAddAlias(poptContext con, struct poptAlias alias, + /*@unused@*/ int flags) +{ + poptItem item = alloca(sizeof(*item)); + memset(item, 0, sizeof(*item)); + item->option.longName = alias.longName; + item->option.shortName = alias.shortName; + item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN; + item->option.arg = 0; + item->option.val = 0; + item->option.descrip = NULL; + item->option.argDescrip = NULL; + item->argc = alias.argc; + item->argv = alias.argv; + return poptAddItem(con, item, 0); +} + +/*@-boundswrite@*/ +/*@-mustmod@*/ /* LCL: con not modified? */ +int poptAddItem(poptContext con, poptItem newItem, int flags) +{ + poptItem * items, item; + int * nitems; + + switch (flags) { + case 1: + items = &con->execs; + nitems = &con->numExecs; + break; + case 0: + items = &con->aliases; + nitems = &con->numAliases; + break; + default: + return 1; + /*@notreached@*/ break; + } + + *items = realloc((*items), ((*nitems) + 1) * sizeof(**items)); + if ((*items) == NULL) + return 1; + + item = (*items) + (*nitems); + + item->option.longName = + (newItem->option.longName ? xstrdup(newItem->option.longName) : NULL); + item->option.shortName = newItem->option.shortName; + item->option.argInfo = newItem->option.argInfo; + item->option.arg = newItem->option.arg; + item->option.val = newItem->option.val; + item->option.descrip = + (newItem->option.descrip ? xstrdup(newItem->option.descrip) : NULL); + item->option.argDescrip = + (newItem->option.argDescrip ? xstrdup(newItem->option.argDescrip) : NULL); + item->argc = newItem->argc; + item->argv = newItem->argv; + + (*nitems)++; + + return 0; +} +/*@=mustmod@*/ +/*@=boundswrite@*/ + +const char * poptBadOption(poptContext con, int flags) +{ + struct optionStackEntry * os = NULL; + + if (con != NULL) + os = (flags & POPT_BADOPTION_NOALIAS) ? con->optionStack : con->os; + + /*@-nullderef@*/ /* LCL: os->argv != NULL */ + return (os && os->argv ? os->argv[os->next - 1] : NULL); + /*@=nullderef@*/ +} + +const char *poptStrerror(const int error) +{ + switch (error) { + case POPT_ERROR_NOARG: + return POPT_("missing argument"); + case POPT_ERROR_BADOPT: + return POPT_("unknown option"); + case POPT_ERROR_BADOPERATION: + return POPT_("mutually exclusive logical operations requested"); + case POPT_ERROR_NULLARG: + return POPT_("opt->arg should not be NULL"); + case POPT_ERROR_OPTSTOODEEP: + return POPT_("aliases nested too deeply"); + case POPT_ERROR_BADQUOTE: + return POPT_("error in parameter quoting"); + case POPT_ERROR_BADNUMBER: + return POPT_("invalid numeric value"); + case POPT_ERROR_OVERFLOW: + return POPT_("number too large or too small"); + case POPT_ERROR_MALLOC: + return POPT_("memory allocation failed"); + case POPT_ERROR_ERRNO: + return strerror(errno); + default: + return POPT_("unknown error"); + } +} + +int poptStuffArgs(poptContext con, const char ** argv) +{ + int argc; + int rc; + + if ((con->os - con->optionStack) == POPT_OPTION_DEPTH) + return POPT_ERROR_OPTSTOODEEP; + + for (argc = 0; argv[argc]; argc++) + {}; + + con->os++; + con->os->next = 0; + con->os->nextArg = NULL; + con->os->nextCharArg = NULL; + con->os->currAlias = NULL; + rc = poptDupArgv(argc, argv, &con->os->argc, &con->os->argv); + con->os->argb = NULL; + con->os->stuffed = 1; + + return rc; +} + +const char * poptGetInvocationName(poptContext con) +{ + return (con->os->argv ? con->os->argv[0] : ""); +} + +/*@-boundswrite@*/ +int poptStrippedArgv(poptContext con, int argc, char ** argv) +{ + int numargs = argc; + int j = 1; + int i; + + /*@-sizeoftype@*/ + if (con->arg_strip) + for (i = 1; i < argc; i++) { + if (PBM_ISSET(i, con->arg_strip)) + numargs--; + } + + for (i = 1; i < argc; i++) { + if (con->arg_strip && PBM_ISSET(i, con->arg_strip)) + continue; + argv[j] = (j < numargs) ? argv[i] : NULL; + j++; + } + /*@=sizeoftype@*/ + + return numargs; +} +/*@=boundswrite@*/ diff --git a/distcc/popt/popt.h b/distcc/popt/popt.h new file mode 100644 index 0000000..04c9f65 --- /dev/null +++ b/distcc/popt/popt.h @@ -0,0 +1,541 @@ +/** \file popt/popt.h + * \ingroup popt + */ + +/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING + file accompanying popt source distributions, available from + ftp://ftp.rpm.org/pub/rpm/dist. */ + +#ifndef H_POPT +#define H_POPT + +#include <stdio.h> /* for FILE * */ + +#define POPT_OPTION_DEPTH 10 + +/** \ingroup popt + * \name Arg type identifiers + */ +/*@{*/ +#define POPT_ARG_NONE 0 /*!< no arg */ +#define POPT_ARG_STRING 1 /*!< arg will be saved as string */ +#define POPT_ARG_INT 2 /*!< arg will be converted to int */ +#define POPT_ARG_LONG 3 /*!< arg will be converted to long */ +#define POPT_ARG_INCLUDE_TABLE 4 /*!< arg points to table */ +#define POPT_ARG_CALLBACK 5 /*!< table-wide callback... must be + set first in table; arg points + to callback, descrip points to + callback data to pass */ +#define POPT_ARG_INTL_DOMAIN 6 /*!< set the translation domain + for this table and any + included tables; arg points + to the domain string */ +#define POPT_ARG_VAL 7 /*!< arg should take value val */ +#define POPT_ARG_FLOAT 8 /*!< arg will be converted to float */ +#define POPT_ARG_DOUBLE 9 /*!< arg will be converted to double */ + +#define POPT_ARG_MASK 0x0000FFFF +/*@}*/ + +/** \ingroup popt + * \name Arg modifiers + */ +/*@{*/ +#define POPT_ARGFLAG_ONEDASH 0x80000000 /*!< allow -longoption */ +#define POPT_ARGFLAG_DOC_HIDDEN 0x40000000 /*!< don't show in help/usage */ +#define POPT_ARGFLAG_STRIP 0x20000000 /*!< strip this arg from argv(only applies to long args) */ +#define POPT_ARGFLAG_OPTIONAL 0x10000000 /*!< arg may be missing */ + +#define POPT_ARGFLAG_OR 0x08000000 /*!< arg will be or'ed */ +#define POPT_ARGFLAG_NOR 0x09000000 /*!< arg will be nor'ed */ +#define POPT_ARGFLAG_AND 0x04000000 /*!< arg will be and'ed */ +#define POPT_ARGFLAG_NAND 0x05000000 /*!< arg will be nand'ed */ +#define POPT_ARGFLAG_XOR 0x02000000 /*!< arg will be xor'ed */ +#define POPT_ARGFLAG_NOT 0x01000000 /*!< arg will be negated */ +#define POPT_ARGFLAG_LOGICALOPS \ + (POPT_ARGFLAG_OR|POPT_ARGFLAG_AND|POPT_ARGFLAG_XOR) + +#define POPT_BIT_SET (POPT_ARG_VAL|POPT_ARGFLAG_OR) + /*!< set arg bit(s) */ +#define POPT_BIT_CLR (POPT_ARG_VAL|POPT_ARGFLAG_NAND) + /*!< clear arg bit(s) */ + +#define POPT_ARGFLAG_SHOW_DEFAULT 0x00800000 /*!< show default value in --help */ + +/*@}*/ + +/** \ingroup popt + * \name Callback modifiers + */ +/*@{*/ +#define POPT_CBFLAG_PRE 0x80000000 /*!< call the callback before parse */ +#define POPT_CBFLAG_POST 0x40000000 /*!< call the callback after parse */ +#define POPT_CBFLAG_INC_DATA 0x20000000 /*!< use data from the include line, + not the subtable */ +#define POPT_CBFLAG_SKIPOPTION 0x10000000 /*!< don't callback with option */ +#define POPT_CBFLAG_CONTINUE 0x08000000 /*!< continue callbacks with option */ +/*@}*/ + +/** \ingroup popt + * \name Error return values + */ +/*@{*/ +#define POPT_ERROR_NOARG -10 /*!< missing argument */ +#define POPT_ERROR_BADOPT -11 /*!< unknown option */ +#define POPT_ERROR_OPTSTOODEEP -13 /*!< aliases nested too deeply */ +#define POPT_ERROR_BADQUOTE -15 /*!< error in paramter quoting */ +#define POPT_ERROR_ERRNO -16 /*!< errno set, use strerror(errno) */ +#define POPT_ERROR_BADNUMBER -17 /*!< invalid numeric value */ +#define POPT_ERROR_OVERFLOW -18 /*!< number too large or too small */ +#define POPT_ERROR_BADOPERATION -19 /*!< mutually exclusive logical operations requested */ +#define POPT_ERROR_NULLARG -20 /*!< opt->arg should not be NULL */ +#define POPT_ERROR_MALLOC -21 /*!< memory allocation failed */ +/*@}*/ + +/** \ingroup popt + * \name poptBadOption() flags + */ +/*@{*/ +#define POPT_BADOPTION_NOALIAS (1 << 0) /*!< don't go into an alias */ +/*@}*/ + +/** \ingroup popt + * \name poptGetContext() flags + */ +/*@{*/ +#define POPT_CONTEXT_NO_EXEC (1 << 0) /*!< ignore exec expansions */ +#define POPT_CONTEXT_KEEP_FIRST (1 << 1) /*!< pay attention to argv[0] */ +#define POPT_CONTEXT_POSIXMEHARDER (1 << 2) /*!< options can't follow args */ +#define POPT_CONTEXT_ARG_OPTS (1 << 4) /*!< return args as options with value 0 */ +/*@}*/ + +/** \ingroup popt + */ +struct poptOption { +/*@observer@*/ /*@null@*/ const char * longName; /*!< may be NULL */ + char shortName; /*!< may be '\0' */ + int argInfo; +/*@shared@*/ /*@null@*/ void * arg; /*!< depends on argInfo */ + int val; /*!< 0 means don't return, just update flag */ +/*@observer@*/ /*@null@*/ const char * descrip; /*!< description for autohelp -- may be NULL */ +/*@observer@*/ /*@null@*/ const char * argDescrip; /*!< argument description for autohelp */ +}; + +/** \ingroup popt + * A popt alias argument for poptAddAlias(). + */ +struct poptAlias { +/*@owned@*/ /*@null@*/ const char * longName; /*!< may be NULL */ + char shortName; /*!< may be '\0' */ + int argc; +/*@owned@*/ const char ** argv; /*!< must be free()able */ +}; + +/** \ingroup popt + * A popt alias or exec argument for poptAddItem(). + */ +/*@-exporttype@*/ +typedef struct poptItem_s { + struct poptOption option; /*!< alias/exec name(s) and description. */ + int argc; /*!< (alias) no. of args. */ +/*@owned@*/ const char ** argv; /*!< (alias) args, must be free()able. */ +} * poptItem; +/*@=exporttype@*/ + +/** \ingroup popt + * \name Auto-generated help/usage + */ +/*@{*/ + +/** + * Empty table marker to enable displaying popt alias/exec options. + */ +/*@-exportvar@*/ +/*@unchecked@*/ /*@observer@*/ +extern struct poptOption poptAliasOptions[]; +/*@=exportvar@*/ +#define POPT_AUTOALIAS { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptAliasOptions, \ + 0, "Options implemented via popt alias/exec:", NULL }, + +/** + * Auto help table options. + */ +/*@-exportvar@*/ +/*@unchecked@*/ /*@observer@*/ +extern struct poptOption poptHelpOptions[]; +/*@=exportvar@*/ +#define POPT_AUTOHELP { NULL, '\0', POPT_ARG_INCLUDE_TABLE, poptHelpOptions, \ + 0, "Help options:", NULL }, + +#define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL } +/*@}*/ + +/** \ingroup popt + */ +/*@-exporttype@*/ +typedef /*@abstract@*/ struct poptContext_s * poptContext; +/*@=exporttype@*/ + +/** \ingroup popt + */ +#ifndef __cplusplus +/*@-exporttype -typeuse@*/ +typedef struct poptOption * poptOption; +/*@=exporttype =typeuse@*/ +#endif + +/*@-exportconst@*/ +enum poptCallbackReason { + POPT_CALLBACK_REASON_PRE = 0, + POPT_CALLBACK_REASON_POST = 1, + POPT_CALLBACK_REASON_OPTION = 2 +}; +/*@=exportconst@*/ + +#ifdef __cplusplus +extern "C" { +#endif +/*@-type@*/ + +/** \ingroup popt + * Table callback prototype. + * @param con context + * @param reason reason for callback + * @param opt option that triggered callback + * @param arg @todo Document. + * @param data @todo Document. + */ +typedef void (*poptCallbackType) (poptContext con, + enum poptCallbackReason reason, + /*@null@*/ const struct poptOption * opt, + /*@null@*/ const char * arg, + /*@null@*/ const void * data) + /*@*/; + +/** \ingroup popt + * Initialize popt context. + * @param name + * @param argc no. of arguments + * @param argv argument array + * @param options address of popt option table + * @param flags or'd POPT_CONTEXT_* bits + * @return initialized popt context + */ +/*@only@*/ /*@null@*/ poptContext poptGetContext( + /*@dependent@*/ /*@keep@*/ const char * name, + int argc, /*@dependent@*/ /*@keep@*/ const char ** argv, + /*@dependent@*/ /*@keep@*/ const struct poptOption * options, + int flags) + /*@*/; + +/** \ingroup popt + * Reinitialize popt context. + * @param con context + */ +/*@-exportlocal@*/ +void poptResetContext(/*@null@*/poptContext con) + /*@modifies con @*/; +/*@=exportlocal@*/ + +/** \ingroup popt + * Return value of next option found. + * @param con context + * @return next option val, -1 on last item, POPT_ERROR_* on error + */ +int poptGetNextOpt(/*@null@*/poptContext con) + /*@globals fileSystem, internalState @*/ + /*@modifies con, fileSystem, internalState @*/; + +/*@-redecl@*/ +/** \ingroup popt + * Return next option argument (if any). + * @param con context + * @return option argument, NULL if no more options are available + */ +/*@observer@*/ /*@null@*/ const char * poptGetOptArg(/*@null@*/poptContext con) + /*@modifies con @*/; + +/** \ingroup popt + * Return current option's argument. + * @param con context + * @return option argument, NULL if no more options are available + */ +/*@observer@*/ /*@null@*/ const char * poptGetArg(/*@null@*/poptContext con) + /*@modifies con @*/; + +/** \ingroup popt + * Peek at current option's argument. + * @param con context + * @return option argument + */ +/*@observer@*/ /*@null@*/ const char * poptPeekArg(/*@null@*/poptContext con) + /*@*/; + +/** \ingroup popt + * Return remaining arguments. + * @param con context + * @return argument array, terminated with NULL + */ +/*@observer@*/ /*@null@*/ const char ** poptGetArgs(/*@null@*/poptContext con) + /*@modifies con @*/; + +/** \ingroup popt + * Return the option which caused the most recent error. + * @param con context + * @param flags + * @return offending option + */ +/*@observer@*/ const char * poptBadOption(/*@null@*/poptContext con, int flags) + /*@*/; +/*@=redecl@*/ + +/** \ingroup popt + * Destroy context. + * @param con context + * @return NULL always + */ +/*@null@*/ poptContext poptFreeContext( /*@only@*/ /*@null@*/ poptContext con) + /*@modifies con @*/; + +/** \ingroup popt + * Add arguments to context. + * @param con context + * @param argv argument array, NULL terminated + * @return 0 on success, POPT_ERROR_OPTSTOODEEP on failure + */ +int poptStuffArgs(poptContext con, /*@keep@*/ const char ** argv) + /*@modifies con @*/; + +/** \ingroup popt + * Add alias to context. + * @todo Pass alias by reference, not value. + * @deprecated Use poptAddItem instead. + * @param con context + * @param alias alias to add + * @param flags (unused) + * @return 0 on success + */ +/*@unused@*/ +int poptAddAlias(poptContext con, struct poptAlias alias, int flags) + /*@modifies con @*/; + +/** \ingroup popt + * Add alias/exec item to context. + * @param con context + * @param newItem alias/exec item to add + * @param flags 0 for alias, 1 for exec + * @return 0 on success + */ +int poptAddItem(poptContext con, poptItem newItem, int flags) + /*@modifies con @*/; + +/** \ingroup popt + * Read configuration file. + * @param con context + * @param fn file name to read + * @return 0 on success, POPT_ERROR_ERRNO on failure + */ +int poptReadConfigFile(poptContext con, const char * fn) + /*@globals fileSystem, internalState @*/ + /*@modifies con->execs, con->numExecs, + fileSystem, internalState @*/; + +/** \ingroup popt + * Read default configuration from /etc/popt and $HOME/.popt. + * @param con context + * @param useEnv (unused) + * @return 0 on success, POPT_ERROR_ERRNO on failure + */ +int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv) + /*@globals fileSystem, internalState @*/ + /*@modifies con->execs, con->numExecs, + fileSystem, internalState @*/; + +/** \ingroup popt + * Duplicate an argument array. + * @note: The argument array is malloc'd as a single area, so only argv must + * be free'd. + * + * @param argc no. of arguments + * @param argv argument array + * @retval argcPtr address of returned no. of arguments + * @retval argvPtr address of returned argument array + * @return 0 on success, POPT_ERROR_NOARG on failure + */ +int poptDupArgv(int argc, /*@null@*/ const char **argv, + /*@null@*/ /*@out@*/ int * argcPtr, + /*@null@*/ /*@out@*/ const char *** argvPtr) + /*@modifies *argcPtr, *argvPtr @*/; + +/** \ingroup popt + * Parse a string into an argument array. + * The parse allows ', ", and \ quoting, but ' is treated the same as " and + * both may include \ quotes. + * @note: The argument array is malloc'd as a single area, so only argv must + * be free'd. + * + * @param s string to parse + * @retval argcPtr address of returned no. of arguments + * @retval argvPtr address of returned argument array + */ +int poptParseArgvString(const char * s, + /*@out@*/ int * argcPtr, /*@out@*/ const char *** argvPtr) + /*@modifies *argcPtr, *argvPtr @*/; + +/** \ingroup popt + * Parses an input configuration file and returns an string that is a + * command line. For use with popt. You must free the return value when done. + * + * Given the file: +\verbatim +# this line is ignored + # this one too +aaa + bbb + ccc +bla=bla + +this_is = fdsafdas + bad_line= + reall bad line + reall bad line = again +5555= 55555 + test = with lots of spaces +\endverbatim +* +* The result is: +\verbatim +--aaa --bbb --ccc --bla="bla" --this_is="fdsafdas" --5555="55555" --test="with lots of spaces" +\endverbatim +* +* Passing this to poptParseArgvString() yields an argv of: +\verbatim +'--aaa' +'--bbb' +'--ccc' +'--bla=bla' +'--this_is=fdsafdas' +'--5555=55555' +'--test=with lots of spaces' +\endverbatim + * + * @bug NULL is returned if file line is too long. + * @bug Silently ignores invalid lines. + * + * @param fp file handle to read + * @param *argstrp return string of options (malloc'd) + * @param flags unused + * @return 0 on success + * @see poptParseArgvString + */ +/*@-fcnuse@*/ +int poptConfigFileToString(FILE *fp, /*@out@*/ char ** argstrp, int flags) + /*@globals fileSystem @*/ + /*@modifies *fp, *argstrp, fileSystem @*/; +/*@=fcnuse@*/ + +/** \ingroup popt + * Return formatted error string for popt failure. + * @param error popt error + * @return error string + */ +/*@-redecl@*/ +/*@observer@*/ const char *poptStrerror(const int error) + /*@*/; +/*@=redecl@*/ + +/** \ingroup popt + * Limit search for executables. + * @param con context + * @param path single path to search for executables + * @param allowAbsolute absolute paths only? + */ +void poptSetExecPath(poptContext con, const char * path, int allowAbsolute) + /*@modifies con @*/; + +/** \ingroup popt + * Print detailed description of options. + * @param con context + * @param fp ouput file handle + * @param flags (unused) + */ +void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/; + +/** \ingroup popt + * Print terse description of options. + * @param con context + * @param fp ouput file handle + * @param flags (unused) + */ +void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/; + +/** \ingroup popt + * Provide text to replace default "[OPTION...]" in help/usage output. + * @param con context + * @param text replacement text + */ +/*@-fcnuse@*/ +void poptSetOtherOptionHelp(poptContext con, const char * text) + /*@modifies con @*/; +/*@=fcnuse@*/ + +/** \ingroup popt + * Return argv[0] from context. + * @param con context + * @return argv[0] + */ +/*@-redecl -fcnuse@*/ +/*@observer@*/ const char * poptGetInvocationName(poptContext con) + /*@*/; +/*@=redecl =fcnuse@*/ + +/** \ingroup popt + * Shuffle argv pointers to remove stripped args, returns new argc. + * @param con context + * @param argc no. of args + * @param argv arg vector + * @return new argc + */ +/*@-fcnuse@*/ +int poptStrippedArgv(poptContext con, int argc, char ** argv) + /*@modifies *argv @*/; +/*@=fcnuse@*/ + +/** + * Save a long, performing logical operation with value. + * @warning Alignment check may be too strict on certain platorms. + * @param arg integer pointer, aligned on int boundary. + * @param argInfo logical operation (see POPT_ARGFLAG_*) + * @param aLong value to use + * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION + */ +/*@-incondefs@*/ +int poptSaveLong(/*@null@*/ long * arg, int argInfo, long aLong) + /*@modifies *arg @*/ + /*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/; +/*@=incondefs@*/ + +/** + * Save an integer, performing logical operation with value. + * @warning Alignment check may be too strict on certain platorms. + * @param arg integer pointer, aligned on int boundary. + * @param argInfo logical operation (see POPT_ARGFLAG_*) + * @param aLong value to use + * @return 0 on success, POPT_ERROR_NULLARG/POPT_ERROR_BADOPERATION + */ +/*@-incondefs@*/ +int poptSaveInt(/*@null@*/ int * arg, int argInfo, long aLong) + /*@modifies *arg @*/ + /*@requires maxSet(arg) >= 0 /\ maxRead(arg) == 0 @*/; +/*@=incondefs@*/ + +/*@=type@*/ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/distcc/popt/poptconfig.c b/distcc/popt/poptconfig.c new file mode 100644 index 0000000..a600a92 --- /dev/null +++ b/distcc/popt/poptconfig.c @@ -0,0 +1,190 @@ +/** \ingroup popt + * \file popt/poptconfig.c + */ + +/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING + file accompanying popt source distributions, available from + ftp://ftp.rpm.org/pub/rpm/dist. */ + +#include "system.h" +#include "poptint.h" + +/*@-compmempass@*/ /* FIX: item->option.longName kept, not dependent. */ +static void configLine(poptContext con, char * line) + /*@modifies con @*/ +{ + /*@-type@*/ + int nameLength = strlen(con->appName); + /*@=type@*/ + const char * entryType; + const char * opt; + poptItem item = alloca(sizeof(*item)); + int i, j; + +/*@-boundswrite@*/ + memset(item, 0, sizeof(*item)); + + /*@-type@*/ + if (strncmp(line, con->appName, nameLength)) return; + /*@=type@*/ + + line += nameLength; + if (*line == '\0' || !isspace(*line)) return; + + while (*line != '\0' && isspace(*line)) line++; + entryType = line; + while (*line == '\0' || !isspace(*line)) line++; + *line++ = '\0'; + + while (*line != '\0' && isspace(*line)) line++; + if (*line == '\0') return; + opt = line; + while (*line == '\0' || !isspace(*line)) line++; + *line++ = '\0'; + + while (*line != '\0' && isspace(*line)) line++; + if (*line == '\0') return; + + /*@-temptrans@*/ /* FIX: line alias is saved */ + if (opt[0] == '-' && opt[1] == '-') + item->option.longName = opt + 2; + else if (opt[0] == '-' && opt[2] == '\0') + item->option.shortName = opt[1]; + /*@=temptrans@*/ + + if (poptParseArgvString(line, &item->argc, &item->argv)) return; + + /*@-modobserver@*/ + item->option.argInfo = POPT_ARGFLAG_DOC_HIDDEN; + for (i = 0, j = 0; i < item->argc; i++, j++) { + const char * f; + if (!strncmp(item->argv[i], "--POPTdesc=", sizeof("--POPTdesc=")-1)) { + f = item->argv[i] + sizeof("--POPTdesc="); + if (f[0] == '$' && f[1] == '"') f++; + item->option.descrip = f; + item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN; + j--; + } else + if (!strncmp(item->argv[i], "--POPTargs=", sizeof("--POPTargs=")-1)) { + f = item->argv[i] + sizeof("--POPTargs="); + if (f[0] == '$' && f[1] == '"') f++; + item->option.argDescrip = f; + item->option.argInfo &= ~POPT_ARGFLAG_DOC_HIDDEN; + item->option.argInfo |= POPT_ARG_STRING; + j--; + } else + if (j != i) + item->argv[j] = item->argv[i]; + } + if (j != i) { + item->argv[j] = NULL; + item->argc = j; + } + /*@=modobserver@*/ +/*@=boundswrite@*/ + + /*@-nullstate@*/ /* FIX: item->argv[] may be NULL */ + if (!strcmp(entryType, "alias")) + (void) poptAddItem(con, item, 0); + else if (!strcmp(entryType, "exec")) + (void) poptAddItem(con, item, 1); + /*@=nullstate@*/ +} +/*@=compmempass@*/ + +int poptReadConfigFile(poptContext con, const char * fn) +{ + const char * file, * chptr, * end; + char * buf; +/*@dependent@*/ char * dst; + int fd, rc; + off_t fileLength; + + fd = open(fn, O_RDONLY); + if (fd < 0) + return (errno == ENOENT ? 0 : POPT_ERROR_ERRNO); + + fileLength = lseek(fd, 0, SEEK_END); + if (fileLength == -1 || lseek(fd, 0, 0) == -1) { + rc = errno; + (void) close(fd); + /*@-mods@*/ + errno = rc; + /*@=mods@*/ + return POPT_ERROR_ERRNO; + } + + file = alloca(fileLength + 1); + if (read(fd, (char *)file, fileLength) != fileLength) { + rc = errno; + (void) close(fd); + /*@-mods@*/ + errno = rc; + /*@=mods@*/ + return POPT_ERROR_ERRNO; + } + if (close(fd) == -1) + return POPT_ERROR_ERRNO; + +/*@-boundswrite@*/ + dst = buf = alloca(fileLength + 1); + + chptr = file; + end = (file + fileLength); + /*@-infloops@*/ /* LCL: can't detect chptr++ */ + while (chptr < end) { + switch (*chptr) { + case '\n': + *dst = '\0'; + dst = buf; + while (*dst && isspace(*dst)) dst++; + if (*dst && *dst != '#') + configLine(con, dst); + chptr++; + /*@switchbreak@*/ break; + case '\\': + *dst++ = *chptr++; + if (chptr < end) { + if (*chptr == '\n') + dst--, chptr++; + /* \ at the end of a line does not insert a \n */ + else + *dst++ = *chptr++; + } + /*@switchbreak@*/ break; + default: + *dst++ = *chptr++; + /*@switchbreak@*/ break; + } + } + /*@=infloops@*/ +/*@=boundswrite@*/ + + return 0; +} + +int poptReadDefaultConfig(poptContext con, /*@unused@*/ int useEnv) +{ + char * fn, * home; + int rc; + + /*@-type@*/ + if (!con->appName) return 0; + /*@=type@*/ + + rc = poptReadConfigFile(con, "/etc/popt"); + if (rc) return rc; +#if defined(HAVE_GETUID) && defined(HAVE_GETEUID) + if (getuid() != geteuid()) return 0; +#endif + + if ((home = getenv("HOME"))) { + fn = alloca(strlen(home) + 20); + strcpy(fn, home); + strcat(fn, "/.popt"); + rc = poptReadConfigFile(con, fn); + if (rc) return rc; + } + + return 0; +} diff --git a/distcc/popt/popthelp.c b/distcc/popt/popthelp.c new file mode 100644 index 0000000..e12c908 --- /dev/null +++ b/distcc/popt/popthelp.c @@ -0,0 +1,742 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */ + +/*@-type@*/ +/** \ingroup popt + * \file popt/popthelp.c + */ + +/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING + file accompanying popt source distributions, available from + ftp://ftp.rpm.org/pub/rpm/dist. */ + +#include "system.h" +#include "poptint.h" + +/** + * Display arguments. + * @param con context + * @param foo (unused) + * @param key option(s) + * @param arg (unused) + * @param data (unused) + */ +static void displayArgs(poptContext con, + /*@unused@*/ enum poptCallbackReason foo, + struct poptOption * key, + /*@unused@*/ const char * arg, /*@unused@*/ void * data) + /*@globals fileSystem@*/ + /*@modifies fileSystem@*/ +{ + if (key->shortName == '?') + poptPrintHelp(con, stdout, 0); + else + poptPrintUsage(con, stdout, 0); + exit(0); +} + +#ifdef NOTYET +/*@unchecked@*/ +static int show_option_defaults = 0; +#endif + +/** + * Empty table marker to enable displaying popt alias/exec options. + */ +/*@observer@*/ /*@unchecked@*/ +struct poptOption poptAliasOptions[] = { + POPT_TABLEEND +}; + +/** + * Auto help table options. + */ +/*@-castfcnptr@*/ +/*@observer@*/ /*@unchecked@*/ +struct poptOption poptHelpOptions[] = { + { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL }, + { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL }, + { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL }, +#ifdef NOTYET + { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0, + N_("Display option defaults in message"), NULL }, +#endif + POPT_TABLEEND +} ; +/*@=castfcnptr@*/ + +/** + * @param table option(s) + */ +/*@observer@*/ /*@null@*/ static const char * +getTableTranslationDomain(/*@null@*/ const struct poptOption *table) + /*@*/ +{ + const struct poptOption *opt; + + if (table != NULL) + for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) { + if (opt->argInfo == POPT_ARG_INTL_DOMAIN) + return opt->arg; + } + return NULL; +} + +/** + * @param opt option(s) + * @param translation_domain translation domain + */ +/*@observer@*/ /*@null@*/ static const char * +getArgDescrip(const struct poptOption * opt, + /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */ + /*@null@*/ const char * translation_domain) + /*@=paramuse@*/ + /*@*/ +{ + if (!(opt->argInfo & POPT_ARG_MASK)) return NULL; + + if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2)) + if (opt->argDescrip) return POPT_(opt->argDescrip); + + if (opt->argDescrip) return D_(translation_domain, opt->argDescrip); + + switch (opt->argInfo & POPT_ARG_MASK) { + case POPT_ARG_NONE: return POPT_("NONE"); +#ifdef DYING + case POPT_ARG_VAL: return POPT_("VAL"); +#else + case POPT_ARG_VAL: return NULL; +#endif + case POPT_ARG_INT: return POPT_("INT"); + case POPT_ARG_LONG: return POPT_("LONG"); + case POPT_ARG_STRING: return POPT_("STRING"); + case POPT_ARG_FLOAT: return POPT_("FLOAT"); + case POPT_ARG_DOUBLE: return POPT_("DOUBLE"); + default: return POPT_("ARG"); + } +} + +/** + * Display default value for an option. + * @param lineLength + * @param opt option(s) + * @param translation_domain translation domain + * @return + */ +static /*@only@*/ /*@null@*/ char * +singleOptionDefaultValue(int lineLength, + const struct poptOption * opt, + /*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */ + /*@null@*/ const char * translation_domain) + /*@=paramuse@*/ + /*@*/ +{ + const char * defstr = D_(translation_domain, "default"); + char * le = malloc(4*lineLength + 1); + char * l = le; + + if (le == NULL) return NULL; /* XXX can't happen */ +/*@-boundswrite@*/ + *le = '\0'; + *le++ = '('; + strcpy(le, defstr); le += strlen(le); + *le++ = ':'; + *le++ = ' '; + if (opt->arg) /* XXX programmer error */ + switch (opt->argInfo & POPT_ARG_MASK) { + case POPT_ARG_VAL: + case POPT_ARG_INT: + { long aLong = *((int *)opt->arg); + le += sprintf(le, "%ld", aLong); + } break; + case POPT_ARG_LONG: + { long aLong = *((long *)opt->arg); + le += sprintf(le, "%ld", aLong); + } break; + case POPT_ARG_FLOAT: + { double aDouble = *((float *)opt->arg); + le += sprintf(le, "%g", aDouble); + } break; + case POPT_ARG_DOUBLE: + { double aDouble = *((double *)opt->arg); + le += sprintf(le, "%g", aDouble); + } break; + case POPT_ARG_STRING: + { const char * s = *(const char **)opt->arg; + if (s == NULL) { + strcpy(le, "null"); le += strlen(le); + } else { + size_t slen = 4*lineLength - (le - l) - sizeof("\"...\")"); + *le++ = '"'; + strncpy(le, s, slen); le[slen] = '\0'; le += strlen(le); + if (slen < strlen(s)) { + strcpy(le, "..."); le += strlen(le); + } + *le++ = '"'; + } + } break; + case POPT_ARG_NONE: + default: + l = _free(l); + return NULL; + /*@notreached@*/ break; + } + *le++ = ')'; + *le = '\0'; +/*@=boundswrite@*/ + + return l; +} + +/** + * Display help text for an option. + * @param fp output file handle + * @param maxLeftCol + * @param opt option(s) + * @param translation_domain translation domain + */ +static void singleOptionHelp(FILE * fp, int maxLeftCol, + const struct poptOption * opt, + /*@null@*/ const char * translation_domain) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/ +{ + int indentLength = maxLeftCol + 5; + int lineLength = 79 - indentLength; + const char * help = D_(translation_domain, opt->descrip); + const char * argDescrip = getArgDescrip(opt, translation_domain); + int helpLength; + char * defs = NULL; + char * left; + int nb = maxLeftCol + 1; + + /* Make sure there's more than enough room in target buffer. */ + if (opt->longName) nb += strlen(opt->longName); + if (argDescrip) nb += strlen(argDescrip); + +/*@-boundswrite@*/ + left = malloc(nb); + if (left == NULL) return; /* XXX can't happen */ + left[0] = '\0'; + left[maxLeftCol] = '\0'; + + if (opt->longName && opt->shortName) + sprintf(left, "-%c, %s%s", opt->shortName, + ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), + opt->longName); + else if (opt->shortName != '\0') + sprintf(left, "-%c", opt->shortName); + else if (opt->longName) + sprintf(left, "%s%s", + ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"), + opt->longName); + if (!*left) goto out; + + if (argDescrip) { + char * le = left + strlen(left); + + if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) + *le++ = '['; + + /* Choose type of output */ + /*@-branchstate@*/ + if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) { + defs = singleOptionDefaultValue(lineLength, opt, translation_domain); + if (defs) { + char * t = malloc((help ? strlen(help) : 0) + + strlen(defs) + sizeof(" ")); + if (t) { + char * te = t; + *te = '\0'; + if (help) { + strcpy(te, help); te += strlen(te); + } + *te++ = ' '; + strcpy(te, defs); + defs = _free(defs); + } + defs = t; + } + } + /*@=branchstate@*/ + + if (opt->argDescrip == NULL) { + switch (opt->argInfo & POPT_ARG_MASK) { + case POPT_ARG_NONE: + break; + case POPT_ARG_VAL: +#ifdef NOTNOW /* XXX pug ugly nerdy output */ + { long aLong = opt->val; + int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS); + int negate = (opt->argInfo & POPT_ARGFLAG_NOT); + + /* Don't bother displaying typical values */ + if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L)) + break; + *le++ = '['; + switch (ops) { + case POPT_ARGFLAG_OR: + *le++ = '|'; + /*@innerbreak@*/ break; + case POPT_ARGFLAG_AND: + *le++ = '&'; + /*@innerbreak@*/ break; + case POPT_ARGFLAG_XOR: + *le++ = '^'; + /*@innerbreak@*/ break; + default: + /*@innerbreak@*/ break; + } + *le++ = '='; + if (negate) *le++ = '~'; + /*@-formatconst@*/ + le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong); + /*@=formatconst@*/ + *le++ = ']'; + } +#endif + break; + case POPT_ARG_INT: + case POPT_ARG_LONG: + case POPT_ARG_FLOAT: + case POPT_ARG_DOUBLE: + case POPT_ARG_STRING: + *le++ = '='; + strcpy(le, argDescrip); le += strlen(le); + break; + default: + break; + } + } else { + *le++ = '='; + strcpy(le, argDescrip); le += strlen(le); + } + if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) + *le++ = ']'; + *le = '\0'; + } +/*@=boundswrite@*/ + + if (help) + fprintf(fp," %-*s ", maxLeftCol, left); + else { + fprintf(fp," %s\n", left); + goto out; + } + + left = _free(left); + if (defs) { + help = defs; defs = NULL; + } + + helpLength = strlen(help); +/*@-boundsread@*/ + while (helpLength > lineLength) { + const char * ch; + char format[16]; + + ch = help + lineLength - 1; + while (ch > help && !isspace(*ch)) ch--; + if (ch == help) break; /* give up */ + while (ch > (help + 1) && isspace(*ch)) ch--; + ch++; + + sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), indentLength); + /*@-formatconst@*/ + fprintf(fp, format, help, " "); + /*@=formatconst@*/ + help = ch; + while (isspace(*help) && *help) help++; + helpLength = strlen(help); + } +/*@=boundsread@*/ + + if (helpLength) fprintf(fp, "%s\n", help); + +out: + /*@-dependenttrans@*/ + defs = _free(defs); + /*@=dependenttrans@*/ + left = _free(left); +} + +/** + * @param opt option(s) + * @param translation_domain translation domain + */ +static int maxArgWidth(const struct poptOption * opt, + /*@null@*/ const char * translation_domain) + /*@*/ +{ + int max = 0; + int len = 0; + const char * s; + + if (opt != NULL) + while (opt->longName || opt->shortName || opt->arg) { + if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { + if (opt->arg) /* XXX program error */ + len = maxArgWidth(opt->arg, translation_domain); + if (len > max) max = len; + } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { + len = sizeof(" ")-1; + if (opt->shortName != '\0') len += sizeof("-X")-1; + if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1; + if (opt->longName) { + len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH) + ? sizeof("-")-1 : sizeof("--")-1); + len += strlen(opt->longName); + } + + s = getArgDescrip(opt, translation_domain); + if (s) + len += sizeof("=")-1 + strlen(s); + if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1; + if (len > max) max = len; + } + + opt++; + } + + return max; +} + +/** + * Display popt alias and exec help. + * @param fp output file handle + * @param items alias/exec array + * @param nitems no. of alias/exec entries + * @param left + * @param translation_domain translation domain + */ +static void itemHelp(FILE * fp, + /*@null@*/ poptItem items, int nitems, int left, + /*@null@*/ const char * translation_domain) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/ +{ + poptItem item; + int i; + + if (items != NULL) + for (i = 0, item = items; i < nitems; i++, item++) { + const struct poptOption * opt; + opt = &item->option; + if ((opt->longName || opt->shortName) && + !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) + singleOptionHelp(fp, left, opt, translation_domain); + } +} + +/** + * Display help text for a table of options. + * @param con context + * @param fp output file handle + * @param table option(s) + * @param left + * @param translation_domain translation domain + */ +static void singleTableHelp(poptContext con, FILE * fp, + /*@null@*/ const struct poptOption * table, int left, + /*@null@*/ const char * translation_domain) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/ +{ + const struct poptOption * opt; + const char *sub_transdom; + + if (table == poptAliasOptions) { + itemHelp(fp, con->aliases, con->numAliases, left, NULL); + itemHelp(fp, con->execs, con->numExecs, left, NULL); + return; + } + + if (table != NULL) + for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) { + if ((opt->longName || opt->shortName) && + !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) + singleOptionHelp(fp, left, opt, translation_domain); + } + + if (table != NULL) + for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) { + if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE) + continue; + sub_transdom = getTableTranslationDomain(opt->arg); + if (sub_transdom == NULL) + sub_transdom = translation_domain; + + if (opt->descrip) + fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip)); + + singleTableHelp(con, fp, opt->arg, left, sub_transdom); + } +} + +/** + * @param con context + * @param fp output file handle + */ +static int showHelpIntro(poptContext con, FILE * fp) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/ +{ + int len = 6; + const char * fn; + + fprintf(fp, POPT_("Usage:")); + if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) { +/*@-boundsread@*/ + /*@-nullderef@*/ /* LCL: wazzup? */ + fn = con->optionStack->argv[0]; + /*@=nullderef@*/ +/*@=boundsread@*/ + if (fn == NULL) return len; + if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1; + fprintf(fp, " %s", fn); + len += strlen(fn) + 1; + } + + return len; +} + +void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags) +{ + int leftColWidth; + + (void) showHelpIntro(con, fp); + if (con->otherHelp) + fprintf(fp, " %s\n", con->otherHelp); + else + fprintf(fp, " %s\n", POPT_("[OPTION...]")); + + leftColWidth = maxArgWidth(con->options, NULL); + singleTableHelp(con, fp, con->options, leftColWidth, NULL); +} + +/** + * @param fp output file handle + * @param cursor + * @param opt option(s) + * @param translation_domain translation domain + */ +static int singleOptionUsage(FILE * fp, int cursor, + const struct poptOption * opt, + /*@null@*/ const char *translation_domain) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/ +{ + int len = 4; + char shortStr[2] = { '\0', '\0' }; + const char * item = shortStr; + const char * argDescrip = getArgDescrip(opt, translation_domain); + + if (opt->shortName != '\0' && opt->longName != NULL) { + len += 2; + if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++; + len += strlen(opt->longName); + } else if (opt->shortName != '\0') { + len++; + shortStr[0] = opt->shortName; + shortStr[1] = '\0'; + } else if (opt->longName) { + len += strlen(opt->longName); + if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++; + item = opt->longName; + } + + if (len == 4) return cursor; + + if (argDescrip) + len += strlen(argDescrip) + 1; + + if ((cursor + len) > 79) { + fprintf(fp, "\n "); + cursor = 7; + } + + if (opt->longName && opt->shortName) { + fprintf(fp, " [-%c|-%s%s%s%s]", + opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"), + opt->longName, + (argDescrip ? " " : ""), + (argDescrip ? argDescrip : "")); + } else { + fprintf(fp, " [-%s%s%s%s]", + ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"), + item, + (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""), + (argDescrip ? argDescrip : "")); + } + + return cursor + len + 1; +} + +/** + * Display popt alias and exec usage. + * @param fp output file handle + * @param cursor + * @param item alias/exec array + * @param nitems no. of ara/exec entries + * @param translation_domain translation domain + */ +static int itemUsage(FILE * fp, int cursor, poptItem item, int nitems, + /*@null@*/ const char * translation_domain) + /*@globals fileSystem @*/ + /*@modifies *fp, fileSystem @*/ +{ + int i; + + /*@-branchstate@*/ /* FIX: W2DO? */ + if (item != NULL) + for (i = 0; i < nitems; i++, item++) { + const struct poptOption * opt; + opt = &item->option; + if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) { + translation_domain = (const char *)opt->arg; + } else if ((opt->longName || opt->shortName) && + !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { + cursor = singleOptionUsage(fp, cursor, opt, translation_domain); + } + } + /*@=branchstate@*/ + + return cursor; +} + +/** + * Keep track of option tables already processed. + */ +typedef struct poptDone_s { + int nopts; + int maxopts; + const void ** opts; +} * poptDone; + +/** + * Display usage text for a table of options. + * @param con context + * @param fp output file handle + * @param cursor + * @param opt option(s) + * @param translation_domain translation domain + * @param done tables already processed + * @return + */ +static int singleTableUsage(poptContext con, FILE * fp, int cursor, + /*@null@*/ const struct poptOption * opt, + /*@null@*/ const char * translation_domain, + /*@null@*/ poptDone done) + /*@globals fileSystem @*/ + /*@modifies *fp, done, fileSystem @*/ +{ + /*@-branchstate@*/ /* FIX: W2DO? */ + if (opt != NULL) + for (; (opt->longName || opt->shortName || opt->arg) ; opt++) { + if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) { + translation_domain = (const char *)opt->arg; + } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { + if (done) { + int i = 0; + for (i = 0; i < done->nopts; i++) { +/*@-boundsread@*/ + const void * that = done->opts[i]; +/*@=boundsread@*/ + if (that == NULL || that != opt->arg) + /*@innercontinue@*/ continue; + /*@innerbreak@*/ break; + } + /* Skip if this table has already been processed. */ + if (opt->arg == NULL || i < done->nopts) + continue; +/*@-boundswrite@*/ + if (done->nopts < done->maxopts) + done->opts[done->nopts++] = (const void *) opt->arg; +/*@=boundswrite@*/ + } + cursor = singleTableUsage(con, fp, cursor, opt->arg, + translation_domain, done); + } else if ((opt->longName || opt->shortName) && + !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { + cursor = singleOptionUsage(fp, cursor, opt, translation_domain); + } + } + /*@=branchstate@*/ + + return cursor; +} + +/** + * Return concatenated short options for display. + * @todo Sub-tables should be recursed. + * @param opt option(s) + * @param fp output file handle + * @retval str concatenation of short options + * @return length of display string + */ +static int showShortOptions(const struct poptOption * opt, FILE * fp, + /*@null@*/ char * str) + /*@globals fileSystem @*/ + /*@modifies *str, *fp, fileSystem @*/ +{ + char * s = alloca(300); /* larger then the ascii set */ + + s[0] = '\0'; + /*@-branchstate@*/ /* FIX: W2DO? */ + if (str == NULL) { + memset(s, 0, sizeof(s)); + str = s; + } + /*@=branchstate@*/ + +/*@-boundswrite@*/ + if (opt != NULL) + for (; (opt->longName || opt->shortName || opt->arg); opt++) { + if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK)) + str[strlen(str)] = opt->shortName; + else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) + if (opt->arg) /* XXX program error */ + (void) showShortOptions(opt->arg, fp, str); + } +/*@=boundswrite@*/ + + if (s != str || *s != '\0') + return 0; + + fprintf(fp, " [-%s]", s); + return strlen(s) + 4; +} + +void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags) +{ + poptDone done = memset(alloca(sizeof(*done)), 0, sizeof(*done)); + int cursor; + + done->nopts = 0; + done->maxopts = 64; + cursor = done->maxopts * sizeof(*done->opts); +/*@-boundswrite@*/ + done->opts = memset(alloca(cursor), 0, cursor); + done->opts[done->nopts++] = (const void *) con->options; +/*@=boundswrite@*/ + + cursor = showHelpIntro(con, fp); + cursor += showShortOptions(con->options, fp, NULL); + cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done); + cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL); + cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL); + + if (con->otherHelp) { + cursor += strlen(con->otherHelp) + 1; + if (cursor > 79) fprintf(fp, "\n "); + fprintf(fp, " %s", con->otherHelp); + } + + fprintf(fp, "\n"); +} + +void poptSetOtherOptionHelp(poptContext con, const char * text) +{ + con->otherHelp = _free(con->otherHelp); + con->otherHelp = xstrdup(text); +} +/*@=type@*/ diff --git a/distcc/popt/poptint.h b/distcc/popt/poptint.h new file mode 100644 index 0000000..5d308ef --- /dev/null +++ b/distcc/popt/poptint.h @@ -0,0 +1,116 @@ +/** \ingroup popt + * \file popt/poptint.h + */ + +/* (C) 1998-2000 Red Hat, Inc. -- Licensing details are in the COPYING + file accompanying popt source distributions, available from + ftp://ftp.rpm.org/pub/rpm/dist. */ + +#ifndef H_POPTINT +#define H_POPTINT + +/** + * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL. + * @param p memory to free + * @retval NULL always + */ +/*@unused@*/ static inline /*@null@*/ void * +_free(/*@only@*/ /*@null@*/ const void * p) + /*@modifies p @*/ +{ + if (p != NULL) free((void *)p); + return NULL; +} + +/* Bit mask macros. */ +/*@-exporttype -redef @*/ +typedef unsigned int __pbm_bits; +/*@=exporttype =redef @*/ +#define __PBM_NBITS (8 * sizeof (__pbm_bits)) +#define __PBM_IX(d) ((d) / __PBM_NBITS) +#define __PBM_MASK(d) ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS)) +/*@-exporttype -redef @*/ +typedef struct { + __pbm_bits bits[1]; +} pbm_set; +/*@=exporttype =redef @*/ +#define __PBM_BITS(set) ((set)->bits) + +#define PBM_ALLOC(d) calloc(__PBM_IX (d) + 1, sizeof(__pbm_bits)) +#define PBM_FREE(s) _free(s); +#define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d)) +#define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d)) +#define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0) + +struct optionStackEntry { + int argc; +/*@only@*/ /*@null@*/ + const char ** argv; +/*@only@*/ /*@null@*/ + pbm_set * argb; + int next; +/*@only@*/ /*@null@*/ + const char * nextArg; +/*@observer@*/ /*@null@*/ + const char * nextCharArg; +/*@dependent@*/ /*@null@*/ + poptItem currAlias; + int stuffed; +}; + +struct poptContext_s { + struct optionStackEntry optionStack[POPT_OPTION_DEPTH]; +/*@dependent@*/ + struct optionStackEntry * os; +/*@owned@*/ /*@null@*/ + const char ** leftovers; + int numLeftovers; + int nextLeftover; +/*@keep@*/ + const struct poptOption * options; + int restLeftover; +/*@only@*/ /*@null@*/ + const char * appName; +/*@only@*/ /*@null@*/ + poptItem aliases; + int numAliases; + int flags; +/*@owned@*/ /*@null@*/ + poptItem execs; + int numExecs; +/*@only@*/ /*@null@*/ + const char ** finalArgv; + int finalArgvCount; + int finalArgvAlloced; +/*@dependent@*/ /*@null@*/ + poptItem doExec; +/*@only@*/ + const char * execPath; + int execAbsolute; +/*@only@*/ + const char * otherHelp; +/*@null@*/ + pbm_set * arg_strip; +}; + +#ifdef HAVE_LIBINTL_H +#include <libintl.h> +#endif + +#if defined(HAVE_GETTEXT) && !defined(__LCLINT__) +#define _(foo) gettext(foo) +#else +#define _(foo) foo +#endif + +#if defined(HAVE_DCGETTEXT) && !defined(__LCLINT__) +#define D_(dom, str) dgettext(dom, str) +#define POPT_(foo) D_("popt", foo) +#else +#define D_(dom, str) str +#define POPT_(foo) foo +#endif + +#define N_(foo) foo + +#endif diff --git a/distcc/popt/poptparse.c b/distcc/popt/poptparse.c new file mode 100644 index 0000000..a0dea80 --- /dev/null +++ b/distcc/popt/poptparse.c @@ -0,0 +1,227 @@ +/** \ingroup popt + * \file popt/poptparse.c + */ + +/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING + file accompanying popt source distributions, available from + ftp://ftp.rpm.org/pub/rpm/dist. */ + +#include "system.h" + +#define POPT_ARGV_ARRAY_GROW_DELTA 5 + +/*@-boundswrite@*/ +int poptDupArgv(int argc, const char **argv, + int * argcPtr, const char *** argvPtr) +{ + size_t nb = (argc + 1) * sizeof(*argv); + const char ** argv2; + char * dst; + int i; + + if (argc <= 0 || argv == NULL) /* XXX can't happen */ + return POPT_ERROR_NOARG; + for (i = 0; i < argc; i++) { + if (argv[i] == NULL) + return POPT_ERROR_NOARG; + nb += strlen(argv[i]) + 1; + } + + dst = malloc(nb); + if (dst == NULL) /* XXX can't happen */ + return POPT_ERROR_MALLOC; + argv2 = (void *) dst; + dst += (argc + 1) * sizeof(*argv); + + /*@-branchstate@*/ + for (i = 0; i < argc; i++) { + argv2[i] = dst; + dst += strlen(strcpy(dst, argv[i])) + 1; + } + /*@=branchstate@*/ + argv2[argc] = NULL; + + if (argvPtr) { + *argvPtr = argv2; + } else { + free(argv2); + argv2 = NULL; + } + if (argcPtr) + *argcPtr = argc; + return 0; +} +/*@=boundswrite@*/ + +/*@-bounds@*/ +int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr) +{ + const char * src; + char quote = '\0'; + int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA; + const char ** argv = malloc(sizeof(*argv) * argvAlloced); + int argc = 0; + int buflen = strlen(s) + 1; + char * buf = memset(alloca(buflen), 0, buflen); + int rc = POPT_ERROR_MALLOC; + + if (argv == NULL) return rc; + argv[argc] = buf; + + for (src = s; *src != '\0'; src++) { + if (quote == *src) { + quote = '\0'; + } else if (quote != '\0') { + if (*src == '\\') { + src++; + if (!*src) { + rc = POPT_ERROR_BADQUOTE; + goto exit; + } + if (*src != quote) *buf++ = '\\'; + } + *buf++ = *src; + } else if (isspace(*src)) { + if (*argv[argc] != '\0') { + buf++, argc++; + if (argc == argvAlloced) { + argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA; + argv = realloc(argv, sizeof(*argv) * argvAlloced); + if (argv == NULL) goto exit; + } + argv[argc] = buf; + } + } else switch (*src) { + case '"': + case '\'': + quote = *src; + /*@switchbreak@*/ break; + case '\\': + src++; + if (!*src) { + rc = POPT_ERROR_BADQUOTE; + goto exit; + } + /*@fallthrough@*/ + default: + *buf++ = *src; + /*@switchbreak@*/ break; + } + } + + if (strlen(argv[argc])) { + argc++, buf++; + } + + rc = poptDupArgv(argc, argv, argcPtr, argvPtr); + +exit: + if (argv) free(argv); + return rc; +} +/*@=bounds@*/ + +/* still in the dev stage. + * return values, perhaps 1== file erro + * 2== line to long + * 3== umm.... more? + */ +int poptConfigFileToString(FILE *fp, char ** argstrp, /*@unused@*/ int flags) +{ + char line[999]; + char * argstr; + char * p; + char * q; + char * x; + int t; + int argvlen = 0; + size_t maxlinelen = sizeof(line); + size_t linelen; + int maxargvlen = 480; + int linenum = 0; + + *argstrp = NULL; + + /* | this_is = our_line + * p q x + */ + + if (fp == NULL) + return POPT_ERROR_NULLARG; + + argstr = calloc(maxargvlen, sizeof(*argstr)); + if (argstr == NULL) return POPT_ERROR_MALLOC; + + while (fgets(line, (int)maxlinelen, fp) != NULL) { + linenum++; + p = line; + + /* loop until first non-space char or EOL */ + while( *p != '\0' && isspace(*p) ) + p++; + + linelen = strlen(p); + if (linelen >= maxlinelen-1) + return POPT_ERROR_OVERFLOW; /* XXX line too long */ + + if (*p == '\0' || *p == '\n') continue; /* line is empty */ + if (*p == '#') continue; /* comment line */ + + q = p; + + while (*q != '\0' && (!isspace(*q)) && *q != '=') + q++; + + if (isspace(*q)) { + /* a space after the name, find next non space */ + *q++='\0'; + while( *q != '\0' && isspace((int)*q) ) q++; + } + if (*q == '\0') { + /* single command line option (ie, no name=val, just name) */ + q[-1] = '\0'; /* kill off newline from fgets() call */ + argvlen += (t = q - p) + (sizeof(" --")-1); + if (argvlen >= maxargvlen) { + maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; + argstr = realloc(argstr, maxargvlen); + if (argstr == NULL) return POPT_ERROR_MALLOC; + } + strcat(argstr, " --"); + strcat(argstr, p); + continue; + } + if (*q != '=') + continue; /* XXX for now, silently ignore bogus line */ + + /* *q is an equal sign. */ + *q++ = '\0'; + + /* find next non-space letter of value */ + while (*q != '\0' && isspace(*q)) + q++; + if (*q == '\0') + continue; /* XXX silently ignore missing value */ + + /* now, loop and strip all ending whitespace */ + x = p + linelen; + while (isspace(*--x)) + *x = 0; /* null out last char if space (including fgets() NL) */ + + /* rest of line accept */ + t = x - p; + argvlen += t + (sizeof("' --='")-1); + if (argvlen >= maxargvlen) { + maxargvlen = (t > maxargvlen) ? t*2 : maxargvlen*2; + argstr = realloc(argstr, maxargvlen); + if (argstr == NULL) return POPT_ERROR_MALLOC; + } + strcat(argstr, " --"); + strcat(argstr, p); + strcat(argstr, "=\""); + strcat(argstr, q); + strcat(argstr, "\""); + } + + *argstrp = argstr; + return 0; +} diff --git a/distcc/popt/system.h b/distcc/popt/system.h new file mode 100644 index 0000000..1d1b9da --- /dev/null +++ b/distcc/popt/system.h @@ -0,0 +1,76 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined (__GLIBC__) && defined(__LCLINT__) +/*@-declundef@*/ +/*@unchecked@*/ +extern __const __int32_t *__ctype_tolower; +/*@unchecked@*/ +extern __const __int32_t *__ctype_toupper; +/*@=declundef@*/ +#endif + +#include <ctype.h> + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> + +#if HAVE_MCHECK_H +#include <mcheck.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef __NeXT +/* access macros are not declared in non posix mode in unistd.h - + don't try to use posix on NeXTstep 3.3 ! */ +#include <libc.h> +#endif + +#if defined(__LCLINT__) +/*@-declundef -incondefs -redecl@*/ /* LCL: missing annotation */ +/*@only@*/ void * alloca (size_t __size) + /*@ensures MaxSet(result) == (__size - 1) @*/ + /*@*/; +/*@=declundef =incondefs =redecl@*/ +#endif + +/* AIX requires this to be the first thing in the file. */ +#ifndef __GNUC__ +# if HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifdef _AIX +#pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +#elif defined(__GNUC__) && defined(__STRICT_ANSI__) +#define alloca __builtin_alloca +#endif + +/*@-redecl -redef@*/ +/*@mayexit@*/ /*@only@*/ char * xstrdup (const char *str) + /*@*/; +/*@=redecl =redef@*/ + +#if HAVE_MCHECK_H && defined(__GNUC__) +#define vmefail() (fprintf(stderr, "virtual memory exhausted.\n"), exit(EXIT_FAILURE), NULL) +#define xstrdup(_str) (strcpy((malloc(strlen(_str)+1) ? : vmefail()), (_str))) +#else +#define xstrdup(_str) strdup(_str) +#endif /* HAVE_MCHECK_H && defined(__GNUC__) */ + + +#include "popt.h" diff --git a/distcc/src/access.c b/distcc/src/access.c new file mode 100644 index 0000000..9b15f96 --- /dev/null +++ b/distcc/src/access.c @@ -0,0 +1,125 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + /* + * They that forsake the law praise the wicked: but such + * as keep the law contend with them. + * -- Proverbs 28:4 + */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "types.h" +#include "distcc.h" +#include "trace.h" +#include "access.h" +#include "exitcode.h" + +/** + * @file + * + * Simple IP-based access-control system + */ + +static const in_addr_t allones = 0xffffffffUL; + + +/** + * Interpret a "HOST/BITS" mask specification. Return @p value and @p mask. + **/ +int dcc_parse_mask(const char *spec, + in_addr_t *value, + in_addr_t *mask) +{ + int value_len; + struct in_addr ia; + int mask_bits; + char *value_str; + int matched; + const char *mask_str; + + value_len = strcspn(spec, "/"); + + /* get bit before slash */ + value_str = strdup(spec); + value_str[value_len] = '\0'; + matched = inet_pton(AF_INET, value_str, &ia); + + /* extract and parse value part */ + if (!matched) { + rs_log_error("can't parse internet address \"%s\"", value_str); + free(value_str); + return EXIT_BAD_ARGUMENTS; + } + free(value_str); + *value = ia.s_addr; + + mask_str = &spec[value_len + 1]; + if (spec[value_len] && *mask_str) { + /* find mask length as a number of bits */ + mask_bits = atoi(mask_str); + if (mask_bits < 0 || mask_bits > 32) { + rs_log_error("invalid mask \"%s\"", mask_str); + return EXIT_BAD_ARGUMENTS; + } + + /* Make a network-endian mask with the top mask_bits set. */ + if (mask_bits == 32) + *mask = allones; + else + *mask = htonl(~(allones >> mask_bits)); + } else { + *mask = allones; + } + return 0; +} + + +/** + * Check whether a client ought to be allowed. + * + * @returns 0 for allowed, or EXIT_ACCESS_DENIED. + **/ +int dcc_check_address(in_addr_t client, + in_addr_t value, + in_addr_t mask) +{ + if ((client & mask) == (value & mask)) { + rs_trace("match client %#lx, value %#lx, mask %#lx", + (long) client, (long) value, (long) mask); + return 0; + } else { + rs_trace("deny client %#lx, value %#lx, mask %#lx", + (long) client, (long) value, (long) mask); + return EXIT_ACCESS_DENIED; + } +} diff --git a/distcc/src/access.h b/distcc/src/access.h new file mode 100644 index 0000000..fda5996 --- /dev/null +++ b/distcc/src/access.h @@ -0,0 +1,35 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* access.c */ +int dcc_parse_mask(const char *mask_spec, + in_addr_t *value, + in_addr_t *mask); + +int dcc_check_address(in_addr_t client, + in_addr_t value, + in_addr_t mask); + +struct dcc_allow_list { + in_addr_t addr, mask; + struct dcc_allow_list *next; +}; diff --git a/distcc/src/arg.c b/distcc/src/arg.c new file mode 100644 index 0000000..de37625 --- /dev/null +++ b/distcc/src/arg.c @@ -0,0 +1,390 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + /* "I have a bone to pick, and a few to break." */ + +/** + * @file + * + * Functions for understanding and manipulating argument vectors. + * + * The few options explicitly handled by the client are processed in its + * main(). At the moment, this is just --help and --version, so this function + * never has to worry about them. + * + * We recognize two basic forms "distcc gcc ..." and "distcc ...", with no + * explicit compiler name. This second one is used if you have a Makefile + * that can't manage two-word values for $CC; eventually it might support + * putting a link to distcc on your path as 'gcc'. We call this second one an + * implicit compiler. + * + * We need to distinguish the two by working out whether the first argument + * "looks like" a compiler name or not. I think the two cases in which we + * should assume it's implicit are "distcc -c hello.c" (starts with a hypen), + * and "distcc hello.c" (starts with a source filename.) + * + * In the case of implicit compilation "distcc --help" will always give you + * distcc's help, not gcc's, and similarly for --version. I don't see much + * that we can do about that. + * + * @todo We don't need to run the full argument scanner on the server, only + * something simple to recognize input and output files. That would perhaps + * make the function simpler, and also mean that if argument recognizer bugs + * are fixed in the future, they only need to be fixed on the client, not on + * the server. An even better solution is to have the client tell the server + * where to put the input and output files. + * + * @todo Perhaps make the argument parser driven by a data table. (Would that + * actually be clearer?) Perhaps use regexps to recognize strings. + * + * @todo We could also detect options like "-x cpp-output" or "-x + * assembler-with-cpp", because they should override language detection based + * on extension. I haven't seen anyone use them yet though. In fact, since + * we don't assemble remotely it is moot for the only reported case, the + * Darwin C library. We would also need to update the option when passing it + * to the server. + * + * @todo Perhaps assume that assembly code will not use both #include and + * .include, and therefore if we preprocess locally we can distribute the + * compilation? Assembling is so cheap that it's not necessarily worth + * distributing. + **/ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "exitcode.h" +#include "snprintf.h" + + +int dcc_argv_append(char **argv, char *toadd) +{ + int l = dcc_argv_len(argv); + argv[l] = toadd; + argv[l+1] = NULL; /* just make sure */ + return 0; +} + +static void dcc_note_compiled(const char *input_file, const char *output_file) +{ + const char *input_base, *output_base; + + input_base = dcc_find_basename(input_file); + output_base = dcc_find_basename(output_file); + + rs_log(RS_LOG_INFO|RS_LOG_NONAME, + "compile from %s to %s", input_base, output_base); +} + +/** + * Parse arguments, extract ones we care about, and also work out + * whether it will be possible to distribute this invocation remotely. + * + * This is a little hard because the cc argument rules are pretty complex, but + * the function still ought to be simpler than it already is. + * + * This code is called on both the client and the server, though they use the + * results differently. + * + * @returns 0 if it's ok to distribute this compilation, or an error code. + **/ +int dcc_scan_args(char *argv[], char **input_file, char **output_file, + char ***ret_newargv) +{ + int seen_opt_c = 0, seen_opt_s = 0; + int i; + char *a; + int ret; + + /* allow for -o foo.o */ + if ((ret = dcc_copy_argv(argv, ret_newargv, 2)) != 0) + return ret; + argv = *ret_newargv; + + /* FIXME: new copy of argv is leaked */ + + dcc_trace_argv("scanning arguments", argv); + + /* Things like "distcc -c hello.c" with an implied compiler are + * handled earlier on by inserting a compiler name. At this + * point, argv[0] should always be a compiler name. */ + if (argv[0][0] == '-') { + rs_log_error("unrecognized distcc option: %s", argv[0]); + exit(EXIT_BAD_ARGUMENTS); + } + + *input_file = *output_file = NULL; + + for (i = 0; (a = argv[i]); i++) { + if (a[0] == '-') { + if (!strcmp(a, "-E")) { + rs_trace("-E call for cpp must be local"); + return EXIT_DISTCC_FAILED; + } else if (!strcmp(a, "-MD") || !strcmp(a, "-MMD")) { + /* These two generate dependencies as a side effect. They + * should work with the way we call cpp. */ + } else if (!strcmp(a, "-MG") || !strcmp(a, "-MP")) { + /* These just modify the behaviour of other -M* options and do + * nothing by themselves. */ + } else if (!strcmp(a, "-MF") || !strcmp(a, "-MT") || + !strcmp(a, "-MQ")) { + /* as above but with extra argument */ + i++; + } else if (a[1] == 'M') { + /* -M(anything else) causes the preprocessor to + produce a list of make-style dependencies on + header files, either to stdout or to a local file. + It implies -E, so only the preprocessor is run, + not the compiler. There would be no point trying + to distribute it even if we could. */ + rs_trace("%s implies -E (maybe) and must be local", a); + return EXIT_DISTCC_FAILED; + } else if (str_startswith("-Wa,", a)) { + /* Look for assembler options that would produce output + * files and must be local. + * + * Writing listings to stdout could be supported but it might + * be hard to parse reliably. */ + if (strstr(a, ",-a") || strstr(a, "--MD")) { + rs_trace("%s must be local", a); + return EXIT_DISTCC_FAILED; + } + } else if (str_startswith("-specs=", a)) { + rs_trace("%s must be local", a); + return EXIT_DISTCC_FAILED; + } else if (!strcmp(a, "-S")) { + seen_opt_s = 1; + } else if (!strcmp(a, "-fprofile-arcs") + || !strcmp(a, "-ftest-coverage")) { + rs_log_info("compiler will emit profile info; must be local"); + return EXIT_DISTCC_FAILED; + } else if (!strcmp(a, "-frepo")) { + rs_log_info("compiler will emit .rpo files; must be local"); + return EXIT_DISTCC_FAILED; + } else if (str_startswith("-x", a)) { + rs_log_info("gcc's -x handling is complex; running locally"); + return EXIT_DISTCC_FAILED; + } else if (!strcmp(a, "-c")) { + seen_opt_c = 1; + } else if (!strcmp(a, "-o")) { + /* Whatever follows must be the output */ + a = argv[++i]; + goto GOT_OUTPUT; + } else if (str_startswith("-o", a)) { + a += 2; /* skip "-o" */ + goto GOT_OUTPUT; + } + } else { + if (dcc_is_source(a)) { + rs_trace("found input file \"%s\"", a); + if (*input_file) { + rs_log_info("do we have two inputs? i give up"); + return EXIT_DISTCC_FAILED; + } + *input_file = a; + } else if (str_endswith(".o", a)) { + GOT_OUTPUT: + rs_trace("found object/output file \"%s\"", a); + if (*output_file) { + rs_log_info("called for link? i give up"); + return EXIT_DISTCC_FAILED; + } + *output_file = a; + } + } + } + + /* TODO: ccache has the heuristic of ignoring arguments that are not + * extant files when looking for the input file; that's possibly + * worthwile. Of course we can't do that on the server. */ + + if (!seen_opt_c && !seen_opt_s) { + rs_log_info("compiler apparently called not for compile"); + return EXIT_DISTCC_FAILED; + } + + if (!*input_file) { + rs_log_info("no visible input file"); + return EXIT_DISTCC_FAILED; + } + + if (dcc_source_needs_local(*input_file)) + return EXIT_DISTCC_FAILED; + + if (!*output_file) { + /* This is a commandline like "gcc -c hello.c". They want + * hello.o, but they don't say so. For example, the Ethereal + * makefile does this. + * + * Note: this doesn't handle a.out, the other implied + * filename, but that doesn't matter because it would already + * be excluded by not having -c or -S. + */ + char *ofile; + + /* -S takes precedence over -c, because it means "stop after + * preprocessing" rather than "stop after compilation." */ + if (seen_opt_s) { + if (dcc_output_from_source(*input_file, ".s", &ofile)) + return EXIT_DISTCC_FAILED; + } else if (seen_opt_c) { + if (dcc_output_from_source(*input_file, ".o", &ofile)) + return EXIT_DISTCC_FAILED; + } else { + rs_log_crit("this can't be happening(%d)!", __LINE__); + return EXIT_DISTCC_FAILED; + } + rs_log_info("no visible output file, going to add \"-o %s\" at end", + ofile); + dcc_argv_append(argv, strdup("-o")); + dcc_argv_append(argv, ofile); + *output_file = ofile; + } + + dcc_note_compiled(*input_file, *output_file); + + if (strcmp(*output_file, "-") == 0) { + /* Different compilers may treat "-o -" as either "write to + * stdout", or "write to a file called '-'". We can't know, + * so we just always run it locally. Hopefully this is a + * pretty rare case. */ + rs_log_info("output to stdout? running locally"); + return EXIT_DISTCC_FAILED; + } + + return 0; +} + + + +/** + * Used to change "-c" or "-S" to "-E", so that we get preprocessed + * source. + **/ +int dcc_set_action_opt(char **a, const char *new_c) +{ + int gotone = 0; + + for (; *a; a++) + if (!strcmp(*a, "-c") || !strcmp(*a, "-S")) { + *a = strdup(new_c); + if (*a == NULL) { + rs_log_error("strdup failed"); + exit(EXIT_OUT_OF_MEMORY); + } + gotone = 1; + /* keep going; it's not impossible they wrote "gcc -c -c + * -c hello.c" */ + } + + if (!gotone) { + rs_log_error("failed to find -c or -S"); + return EXIT_DISTCC_FAILED; + } else { + return 0; + } +} + + + +/** + * Change object file or suffix of -o to @p ofname + * Frees the old value, if it exists. + * + * It's crucially important that in every case where an output file is + * detected by dcc_scan_args(), it's also correctly identified here. + * It might be better to make the code shared. + **/ +int dcc_set_output(char **a, char *ofname) +{ + int i; + + for (i = 0; a[i]; i++) + if (0 == strcmp(a[i], "-o") && a[i+1] != NULL) { + rs_trace("changed output from \"%s\" to \"%s\"", a[i+1], ofname); + free(a[i+1]); + a[i+1] = strdup(ofname); + if (a[i+1] == NULL) { + rs_log_crit("failed to allocate space for output parameter"); + return EXIT_OUT_OF_MEMORY; + } + dcc_trace_argv("command after", a); + return 0; + } else if (0 == strncmp(a[i], "-o", 2)) { + char *newptr; + rs_trace("changed output from \"%s\" to \"%s\"", a[i]+2, ofname); + free(a[i]); + if (asprintf(&newptr, "-o%s", ofname) == -1) { + rs_log_crit("failed to allocate space for output parameter"); + return EXIT_OUT_OF_MEMORY; + } + a[i] = newptr; + dcc_trace_argv("command after", a); + return 0; + } + + rs_log_error("failed to find \"-o\""); + return EXIT_DISTCC_FAILED; +} + +/** + * Change input file to a copy of @p ifname; called on compiler. + * Frees the old value. + * + * @todo Unify this with dcc_scan_args + * + * @todo Test this by making sure that when the modified arguments are + * run through scan_args, the new ifname is identified as the input. + **/ +int dcc_set_input(char **a, char *ifname) +{ + int i; + + for (i =0; a[i]; i++) + if (dcc_is_source(a[i])) { + rs_trace("changed input from \"%s\" to \"%s\"", a[i], ifname); + free(a[i]); + a[i] = strdup(ifname); + if (a[i] == NULL) { + rs_log_crit("failed to allocate space for input parameter"); + return EXIT_OUT_OF_MEMORY; + } + dcc_trace_argv("command after", a); + return 0; + } + + rs_log_error("failed to find input file"); + return EXIT_DISTCC_FAILED; +} diff --git a/distcc/src/argutil.c b/distcc/src/argutil.c new file mode 100644 index 0000000..1096f33 --- /dev/null +++ b/distcc/src/argutil.c @@ -0,0 +1,165 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + +/* + * Utilities for dealing with argv[]-style strings. + * + * These rules might not yet be consistently applied in distcc, but they + * should be in the future: + * + * For simplicity in managing memory we try to keep all argv structures + * malloc'd, without any shared structure. It is then possible to just free + * the whole thing whenever we're finished with it. + * + * One exception is of course the argv used to invoke the program, which is + * treated as read-only. + */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "exitcode.h" + + +/** + * Return true if argv contains needle as an argument. + **/ +int dcc_argv_search(char **a, + const char *needle) +{ + for (; *a; a++) + if (!strcmp(*a, needle)) + return 1; + return 0; +} + + +unsigned int dcc_argv_len(char **a) +{ + unsigned int i; + + for (i = 0; a[i]; i++) + ; + return i; +} + + +/* Free a malloc'd argv structure. Only safe when the array and all its + * components were malloc'd. */ +void dcc_free_argv(char **argv) +{ + char **a; + + for (a = argv; *a != NULL; a++) + free(*a); + free(argv); +} + + +/* Copy an argv array, adding extra NULL elements to the end to allow for + * adding more arguments later. + */ +int dcc_copy_argv(char **from, char ***out, int delta) +{ + char **b; + int l, i; + + l = dcc_argv_len(from); + b = malloc((l+1+delta) * (sizeof from[0])); + if (b == NULL) { + rs_log_error("failed to allocate copy of argv"); + exit(EXIT_OUT_OF_MEMORY); + } + for (i = 0; i < l; i++) { + if ((b[i] = strdup(from[i])) == NULL) { + rs_log_error("failed to duplicate element %d", i); + return EXIT_OUT_OF_MEMORY; + } + } + b[l] = NULL; + + *out = b; + + return 0; +} + + + +/** + * Convert an argv array to printable form for debugging output. + * + * @note The result is not necessarily properly quoted for passing to + * shells. + * + * @return newly-allocated string containing representation of + * arguments. + **/ +char *dcc_argv_tostr(char **a) +{ + int l, i; + char *s, *ss; + + /* calculate total length */ + for (l = 0, i = 0; a[i]; i++) { + l += strlen(a[i]) + 3; /* two quotes and space */ + } + + ss = s = malloc((size_t) l + 1); + if (!s) { + rs_log_crit("failed to allocate %d bytes", l+1); + exit(EXIT_OUT_OF_MEMORY); + } + + for (i = 0; a[i]; i++) { + /* kind of half-assed quoting; won't handle strings containing + * quotes properly, but good enough for debug messages for the + * moment. */ + int needs_quotes = (strpbrk(a[i], " \t\n\"\';") != NULL); + if (i) + *ss++ = ' '; + if (needs_quotes) + *ss++ = '"'; + strcpy(ss, a[i]); + ss += strlen(a[i]); + if (needs_quotes) + *ss++ = '"'; + } + *ss = '\0'; + + return s; +} + + diff --git a/distcc/src/backoff.c b/distcc/src/backoff.c new file mode 100644 index 0000000..45f88d4 --- /dev/null +++ b/distcc/src/backoff.c @@ -0,0 +1,110 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +/** + * @file + * + * Keep track of hosts which are, or are not, usable. + **/ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <time.h> + +#include <sys/stat.h> +#include <sys/file.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "exitcode.h" +#include "snprintf.h" +#include "lock.h" +#include "timefile.h" +#include "hosts.h" + + +const int dcc_backoff_period = 60; /* seconds */ + + +/** + * Remember that this host is working OK. + * + * For the moment this just means removing any backoff timer scored against + * it. + **/ +int dcc_enjoyed_host(const struct dcc_hostdef *host) +{ + return dcc_remove_timefile("backoff", host); +} + +int dcc_disliked_host(const struct dcc_hostdef *host) +{ + /* i hate you (but only for 60 seconds) */ + return dcc_mark_timefile("backoff", host); +} + + +static int dcc_check_backoff(struct dcc_hostdef *host) +{ + int ret; + time_t mtime; + + if ((ret = dcc_check_timefile("backoff", host, &mtime))) + return ret; + + if (difftime(time(NULL), mtime) < (double) dcc_backoff_period) { + rs_trace("still in backoff period for %s", host->hostdef_string); + return EXIT_BUSY; + } + + return 0; +} + + +/** + * Walk through @p hostlist and remove any hosts that are marked unavailable. + **/ +int dcc_remove_disliked(struct dcc_hostdef **hostlist) +{ + struct dcc_hostdef *h; + + while ((h = *hostlist) != NULL) { + if (dcc_check_backoff(h) != 0) { + rs_trace("remove %s from list", h->hostdef_string); + *hostlist = h->next; + free(h); + } else { + /* check next one */ + hostlist = &h->next; + } + } + + return 0; +} diff --git a/distcc/src/bulk.c b/distcc/src/bulk.c new file mode 100644 index 0000000..00583d0 --- /dev/null +++ b/distcc/src/bulk.c @@ -0,0 +1,367 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + /* "A new contraption to capture a dandelion in one + * piece has been put together by the crew." + * -- Boards of Canada, "Geogaddi" */ + + +/** + * @file + * + * Bulk file transfer, used for sending .i, .o files etc. + * + * Files are always sent in the standard IO format: stream name, + * length, bytes. This implies that we can deliver to a fifo (just + * keep writing), but we can't send from a fifo, because we wouldn't + * know how many bytes were coming. + * + * @note We don't time transmission of files: because the write returns when + * they've just been written into the OS buffer, we don't really get + * meaningful numbers except for files that are very large. + **/ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> +#include <sys/time.h> + +#include "distcc.h" +#include "trace.h" +#include "rpc.h" +#include "bulk.h" +#include "time.h" +#include "exitcode.h" +#include "timeval.h" + + +/** + * Open a file for read, and also put its size into @p fsize. + * + * If the file does not exist, then returns 0, but @p ifd is -1 and @p + * fsize is zero. If @p fsize is zero, the caller should not try to + * read from the file. + * + * This strange behaviour for ENOENT is useful because if there is + * e.g. no output file from the compiler, we don't want to abort, but + * rather just send nothing. The receiver has the corresponding + * behaviour of not creating zero-length files. + * + * Using fstat() helps avoid a race condition -- not a security issue, + * but possibly a failure. Shouldn't be very likely though. + * + * The caller is responsible for closing @p ifd. + **/ +int dcc_open_read(const char *fname, int *ifd, off_t *fsize) +{ + struct stat buf; + + *ifd = open(fname, O_RDONLY|O_BINARY); + if (*ifd == -1) { + int save_errno = errno; + if (save_errno == ENOENT) { + /* that's OK, just assume it's empty */ + *fsize = 0; + return 0; + } else { + rs_log_error("failed to open %s: %s", fname, strerror(save_errno)); + return EXIT_IO_ERROR; + } + } + + if (fstat(*ifd, &buf) == -1) { + rs_log_error("fstat %s failed: %s", fname, strerror(errno)); + dcc_close(*ifd); + return EXIT_IO_ERROR; + } + + *fsize = buf.st_size; + + return 0; +} + +void dcc_calc_rate(off_t size_out, + struct timeval *before, + struct timeval *after, + double *secs, + double *rate) +{ + struct timeval delta; + + /* FIXME: Protect against division by zero and other floating-point + * exceptions. */ + + timeval_subtract(&delta, after, before); + + *secs = (double) delta.tv_sec + (double) delta.tv_usec / 1e6; + + if (*secs == 0.0) + *rate = 0.0; + else + *rate = ((double) size_out / *secs) / 1024.0; +} + + +static int dcc_x_file_lzo1x(int out_fd, + int in_fd, + const char *token, + unsigned in_len) +{ + int ret; + char *out_buf = NULL; + size_t out_len; + + /* As a special case, send 0 as 0 */ + if (in_len == 0) { + if ((ret = dcc_x_token_int(out_fd, token, 0))) + goto out; + } else { + if ((ret = dcc_compress_file_lzo1x(in_fd, in_len, &out_buf, &out_len))) + goto out; + + if ((ret = dcc_x_token_int(out_fd, token, out_len))) + goto out; + + if ((ret = dcc_writex(out_fd, out_buf, out_len))) + goto out; + } + + ret = 0; + + out: + free(out_buf); + return ret; +} + + +/** + * Transmit from a local file to the network. Sends TOKEN, LENGTH, BODY, + * where the length is the appropriate compressed length. + * + * Does compression if needed. + * + * @param ofd File descriptor for the network connection. + * @param fname Name of the file to send. + * @param token Token for this file, e.g. "DOTO". + **/ +int dcc_x_file(int ofd, + const char *fname, + const char *token, + enum dcc_compress compression, + off_t *f_size_out) +{ + int ifd; + int ret; + off_t f_size; + + if (dcc_open_read(fname, &ifd, &f_size)) + return EXIT_IO_ERROR; + if (ifd == -1) + return EXIT_IO_ERROR; + if (f_size_out) + *f_size_out = f_size; + + rs_trace("send %lu byte file %s with token %s and compression %d", + (unsigned long) f_size, fname, token, compression); + + if (compression == DCC_COMPRESS_NONE) { + if ((ret = dcc_x_token_int(ofd, token, f_size))) + goto failed; + + /* FIXME: These could get truncated if the file was very large (>4G). + * That seems pretty unlikely. */ +#ifdef HAVE_SENDFILE + ret = dcc_pump_sendfile(ofd, ifd, (size_t) f_size); +#else + ret = dcc_pump_readwrite(ofd, ifd, (size_t) f_size); +#endif + } else if (compression == DCC_COMPRESS_LZO1X) { + ret = dcc_x_file_lzo1x(ofd, ifd, token, f_size); + } else { + rs_log_error("invalid compression"); + return EXIT_PROTOCOL_ERROR; + } + + if (ifd != -1) + dcc_close(ifd); + return 0; + + failed: + if (ifd != -1) + dcc_close(ifd); + return ret; +} + + +/** + * Receive a file stream from the network into a local file. + * Make all necessary directories if they don't exist. + * + * Can handle compression. + * + * @param len Compressed length of the incoming file. + * @param filename local filename to create. + **/ +int dcc_r_file(int ifd, const char *filename, + unsigned len, + enum dcc_compress compr) +{ + int ofd; + int ret, close_ret; + struct stat s; + + /* This is meant to behave similarly to the output routines in bfd/cache.c + * in gnu binutils, because makefiles or configure scripts may depend on + * it for edge cases. + * + * We try to remove the output file first, if its size is not 0. That + * should make the newly created file be owned by the current user; it + * might also help in the dangerous case of some other process still + * reading from the file. + * + * Checking for size 0 means that we won't unlink special files like + * /dev/null or fifos. + * + * However, failure to remove the file does not cause a warning; we may + * not have write permission on the directory, but +w for the file. + */ + + if (dcc_mk_tmp_ancestor_dirs(filename)) { + rs_log_error("failed to create path for '%s'", filename); + return EXIT_IO_ERROR; + } + + if (stat(filename, &s) == 0) { + if (s.st_size != 0) { + if (unlink(filename) && errno != ENOENT) { + rs_trace("failed to remove %s: %s", filename, strerror(errno)); + /* continue */ + } + } + } else { + if (errno != ENOENT) { + rs_trace("stat %s failed: %s", filename, strerror(errno)); + } + /* continue */ + } + + ofd = open(filename, O_TRUNC|O_WRONLY|O_CREAT|O_BINARY, 0666); + if (ofd == -1) { + rs_log_error("failed to create %s: %s", filename, strerror(errno)); + return EXIT_IO_ERROR; + } + + ret = 0; + if (len > 0) { + ret = dcc_r_bulk(ofd, ifd, len, compr); + } + close_ret = dcc_close(ofd); + + if (!ret && !close_ret) { + rs_trace("received %d bytes to file %s", len, filename); + return 0; + } + + rs_trace("failed to receive %s, removing it", filename); + if (unlink(filename)) { + rs_log_error("failed to unlink %s after failed transfer: %s", + filename, strerror(errno)); + } + return EXIT_IO_ERROR; +} + + + +/** + * Receive a file and print timing statistics. Only used for big files. + * + * Wrapper around dcc_r_file(). + **/ +int dcc_r_file_timed(int ifd, const char *fname, unsigned size, + enum dcc_compress compr) +{ + struct timeval before, after; + int ret; + + if (gettimeofday(&before, NULL)) + rs_log_warning("gettimeofday failed"); + + ret = dcc_r_file(ifd, fname, size, compr); + + if (gettimeofday(&after, NULL)) { + rs_log_warning("gettimeofday failed"); + } else { + double secs, rate; + + dcc_calc_rate(size, &before, &after, &secs, &rate); + rs_log_info("%ld bytes received in %.6fs, rate %.0fkB/s", + (long) size, secs, rate); + } + + return ret; +} + +int dcc_r_token_file(int in_fd, + const char *token, + const char *fname, + enum dcc_compress compr) +{ + int ret; + unsigned i_size; + + if ((ret = dcc_r_token_int(in_fd, token, &i_size))) + return ret; + + if ((ret = dcc_r_file_timed(in_fd, fname, (size_t) i_size, compr))) + return ret; + + return 0; +} + +int dcc_copy_file_to_fd(const char *in_fname, int out_fd) +{ + off_t len; + int ifd; + int ret; + + if ((ret = dcc_open_read(in_fname, &ifd, &len))) + return ret; + +#ifdef HAVE_SENDFILE + ret = dcc_pump_sendfile(out_fd, ifd, (size_t) len); +#else + ret = dcc_pump_readwrite(out_fd, ifd, (size_t) len); +#endif + + if (ret) { + close(ifd); + return ret; + } + return 0; +} diff --git a/distcc/src/bulk.h b/distcc/src/bulk.h new file mode 100644 index 0000000..7f37109 --- /dev/null +++ b/distcc/src/bulk.h @@ -0,0 +1,51 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +int dcc_r_file(int ifd, const char *filename, unsigned, + enum dcc_compress); +int dcc_r_fifo(int ifd, const char *fifo_name, size_t len); + +int dcc_x_file(int ofd, const char *fname, const char *token, + enum dcc_compress compression, + off_t *); + +int dcc_r_file_timed(int ifd, const char *fname, unsigned size, + enum dcc_compress); + +int dcc_r_token_file(int ifd, + const char *token, + const char *fname, + enum dcc_compress compr); + +int dcc_open_read(const char *fname, int *ifd, off_t *fsize); +int dcc_copy_file_to_fd(const char *in_fname, int out_fd); + +/* clirpc.c */ +int dcc_x_many_files(int ofd, + unsigned int n_files, + char **fnames); + +/* srvrpc.c */ +int dcc_r_many_files(int in_fd, + const char *dirname, + enum dcc_compress compr); + diff --git a/distcc/src/cleanup.c b/distcc/src/cleanup.c new file mode 100644 index 0000000..8a25552 --- /dev/null +++ b/distcc/src/cleanup.c @@ -0,0 +1,163 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + /* "I have not come through fire and death to bandy crooked + * words with a serving-man until the lightning falls!" + * -- Gandalf (BBC LoTR radio play) */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> +#include <sys/types.h> + +#include "distcc.h" +#include "exitcode.h" +#include "trace.h" +#include "util.h" + +/** + * A list of files that need to be cleaned up on exit. + * + * Volatile because it can be read from signal handlers. + **/ +char *volatile *volatile cleanups = 0; /* Dynamically allocated array. */ +volatile int cleanups_size = 0; /* The length of the array. */ +volatile int n_cleanups = 0; /* The number of entries used. */ + +static void dcc_cleanup_tempfiles_inner(int from_signal_handler); + +void dcc_cleanup_tempfiles(void) +{ + dcc_cleanup_tempfiles_inner(0); +} + +void dcc_cleanup_tempfiles_from_signal_handler(void) +{ + dcc_cleanup_tempfiles_inner(1); +} + +/* + * You can call this at any time, or hook it into atexit(). It is + * safe to call repeatedly. + * + * If from_signal_handler (a boolean) is non-zero, it means that + * we're being called from a signal handler, so we need to be + * careful not to call malloc() or free() or any other functions + * that might not be async-signal-safe. + * (We do call the tracing functions, which is perhaps unsafe + * because they call sprintf() if DISCC_VERBOSE=1 is enabled. + * But in that case it is probably worth the very small risk + * of a crash to get the full tracing output.) + * + * If $DISTCC_SAVE_TEMPS is set to "1", then files are not actually + * deleted, which can be good for debugging. However, we still need + * to remove them from the list, otherwise it will eventually overflow + * in prefork mode. + */ +static void dcc_cleanup_tempfiles_inner(int from_signal_handler) +{ + int i; + int done = 0; + int save = dcc_getenv_bool("DISTCC_SAVE_TEMPS", 0); + + /* do the unlinks from the last to the first file. + * This way, directories get deleted after their files. */ + + /* tempus fugit */ + for (i = n_cleanups - 1; i >= 0; i--) { + if (save) { + rs_trace("skip cleanup of %s", cleanups[i]); + } else { + /* Try removing it as a directory first, and + * if that fails, try removing is as a file. + * Report the error from removing-as-a-file + * if both fail. */ + if ((rmdir(cleanups[i]) == -1) && + (unlink(cleanups[i]) == -1) && + (errno != ENOENT)) { + rs_log_notice("cleanup %s failed: %s", cleanups[i], + strerror(errno)); + } + done++; + } + n_cleanups = i; + if (from_signal_handler) { + /* It's not safe to call free() in this case. + * Don't worry about the memory leak - we're about + * to exit the process anyway. */ + } else { + free(cleanups[i]); + } + cleanups[i] = NULL; + } + + rs_trace("deleted %d temporary files", done); +} + + +/** + * Add to the list of files to delete on exit. + * If it runs out of memory, it returns non-zero. + */ +int dcc_add_cleanup(const char *filename) +{ + char *new_filename; + int new_n_cleanups = n_cleanups + 1; + + /* Increase the size of the cleanups array, if needed. + * We avoid using realloc() here, to ensure that 'cleanups' remains + * valid at all times - we might get a signal in the middle here + * that could call dcc_cleanup_tempfiles_from_signal_handler(). */ + if (new_n_cleanups > cleanups_size) { + char **old_cleanups; + int new_cleanups_size = (cleanups_size == 0 ? 10 : cleanups_size * 3); + char **new_cleanups = malloc(new_cleanups_size * sizeof(char *)); + if (new_cleanups == NULL) { + rs_log_crit("malloc failed - too many cleanups"); + return EXIT_OUT_OF_MEMORY; + } + memcpy(new_cleanups, (char **)cleanups, cleanups_size * sizeof(char *)); + old_cleanups = (char **)cleanups; + cleanups = new_cleanups; /* Atomic assignment. */ + cleanups_size = new_cleanups_size; /* Atomic assignment. */ + free(old_cleanups); + } + + new_filename = strdup(filename); + if (new_filename == NULL) { + rs_log_crit("strdup failed - too many cleanups"); + return EXIT_OUT_OF_MEMORY; + } + + cleanups[new_n_cleanups - 1] = new_filename; /* Atomic assignment. */ + n_cleanups = new_n_cleanups; /* Atomic assignment. */ + + return 0; +} diff --git a/distcc/src/climasq.c b/distcc/src/climasq.c new file mode 100644 index 0000000..217e008 --- /dev/null +++ b/distcc/src/climasq.c @@ -0,0 +1,131 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + /* + * And the magicians did so with their enchantments, + * and brought up frogs upon the land of Egypt. + * -- Exodus 8:7 + */ + + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include "distcc.h" +#include "util.h" +#include "trace.h" +#include "exitcode.h" + +/** + * For masquerade mode, change the path to remove the directory containing the + * distcc mask, so that invoking the same name will find the underlying + * compiler instead. + * + * @param progname basename under which distcc was introduced. If we reached + * this point, then it's the same as the name of the real compiler, e.g. "cc". + * + * @param did_masquerade specifies an integer that will be set to 1 if the + * path was changed. + * + * @return 0 or standard error. + **/ +int dcc_support_masquerade(char *argv[], char *progname, int *did_masquerade) +{ + const char *envpath, *findpath, *p, *n; + char *buf; + size_t len; + size_t findlen; + + if (!(envpath = getenv("PATH"))) + /* strange but true*/ + return 0; + + if (!(buf = malloc(strlen(envpath)+1+strlen(progname)+1))) { + rs_log_error("failed to allocate buffer for new PATH"); + return EXIT_OUT_OF_MEMORY; + } + + /* Filter PATH to contain only the part that is past our dir. + * If we were called explicitly, find the named dir on the PATH. */ + if (progname != argv[0]) { + findpath = dcc_abspath(argv[0], progname - argv[0] - 1); + findlen = strlen(findpath); + } else { + findpath = NULL; + findlen = 0; + } + + for (n = p = envpath; *n; p = n) { + /* Find the length of this component of the path */ + n = strchr(p, ':'); + if (n) + len = n++ - p; + else { + len = strlen(p); + n = p + len; + } + + if (findpath) { + /* Looking for a component in the path equal to findpath */ + + /* FIXME: This won't catch paths that are in fact the same, but + * that are not the same string. This might happen if you have + * multiple slashes, or dots, or symlinks... */ + if (len != findlen || strncmp(p, findpath, findlen) != 0) + continue; + } else { + /* Looking for a component in the path containing a file + * progname. */ + + /* FIXME: This gets a false match if you have a subdirectory that + * happens to be of the right name, e.g. /usr/bin/distcc... */ + strncpy(buf, p, (size_t) len); + sprintf(buf + len, "/%s", progname); + if (access(buf, X_OK) != 0) + continue; + } + /* Set p to the part of the path past our match. */ + p = n; + break; + } + + if (*p != '\0') { + int ret = dcc_set_path(p); + if (ret) + return ret; + *did_masquerade = 1; + } + else { + rs_trace("not modifying PATH"); + *did_masquerade = 0; + } + + free(buf); + return 0; +} diff --git a/distcc/src/clinet.c b/distcc/src/clinet.c new file mode 100644 index 0000000..c817d9c --- /dev/null +++ b/distcc/src/clinet.c @@ -0,0 +1,201 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + /* I just wish I could get caller-IQ on my phones... + -- The Purple People-Eater, NANAE */ + + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> + +#include <sys/poll.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> + +#include <netdb.h> + +#include "types.h" +#include "distcc.h" +#include "trace.h" +#include "exitcode.h" +#include "clinet.h" +#include "util.h" +#include "netutil.h" + +#ifndef h_errno +extern int h_errno; +#endif + + +const int dcc_connect_timeout = 4; /* seconds */ + +/* + * Client-side networking. + * + * These are called with an alarm set so we get a single timeout over the + * whole resolution and connection process. + * + * TODO: In error messages, show the name of the relevant host. + * Should do this even in readx(), etc. + * + * TODO: After connecting, perhaps try to read 0 bytes to see if there's an + * error. + */ + + +/* + * Connect to a host given its binary address, with a timeout. + * + * host and port are only here to aid printing debug messages. + */ +int dcc_connect_by_addr(struct sockaddr *sa, size_t salen, + int *p_fd) +{ + int fd; + int ret; + char *s; + int failed; + int tries = 3; + + dcc_sockaddr_to_string(sa, salen, &s); + + rs_trace("started connecting to %s", s); + + if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) == -1) { + rs_log_error("failed to create socket: %s", strerror(errno)); + ret = EXIT_CONNECT_FAILED; + goto out_failed; + } + + dcc_set_nonblocking(fd); + + /* start the nonblocking connect... */ + do + failed = connect(fd, sa, salen); + while (failed == -1 && + (errno == EINTR || + (errno == EAGAIN && tries-- && poll(NULL, 0, 500) == 0))); + + if (failed == -1 && errno != EINPROGRESS) { + rs_log(RS_LOG_ERR|RS_LOG_NONAME, + "failed to connect to %s: %s", s, strerror(errno)); + ret = EXIT_CONNECT_FAILED; + goto out_failed; + } + + if ((ret = dcc_select_for_write(fd, dcc_connect_timeout))) { + rs_log(RS_LOG_ERR|RS_LOG_NONAME, + "timeout while connecting to %s", s); + goto out_failed; + } + + *p_fd = fd; + free(s); + return 0; + +out_failed: + free(s); + return ret; +} + + +#if defined(ENABLE_RFC2553) + +/** + * Open a socket to a tcp remote host with the specified port. + **/ +int dcc_connect_by_name(const char *host, int port, int *p_fd) +{ + struct addrinfo hints; + struct addrinfo *res; + int error; + int ret; + char portname[20]; + + rs_trace("connecting to %s port %d", host, port); + + /* Unfortunately for us, getaddrinfo wants the port (service) as a string */ + snprintf(portname, sizeof portname, "%d", port); + + memset(&hints, 0, sizeof(hints)); + /* set-up hints structure */ + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(host, portname, &hints, &res); + if (error) { + rs_log_error("failed to resolve host %s port %d: %s", host, port, + gai_strerror(error)); + return EXIT_CONNECT_FAILED; + } + + /* Try each of the hosts possible addresses. */ + do { + ret = dcc_connect_by_addr(res->ai_addr, res->ai_addrlen, p_fd); + } while (ret != 0 && (res = res->ai_next)); + + return ret; +} + + +#else /* not ENABLE_RFC2553 */ + +/** + * Open a socket to a tcp remote host with the specified port. + * + * @todo Don't try for too long to connect. + **/ +int dcc_connect_by_name(const char *host, int port, int *p_fd) +{ + struct sockaddr_in sock_out; + struct hostent *hp; + + /* FIXME: "warning: gethostbyname() leaks memory. Use gethostbyname_r + * instead!" (or indeed perhaps use getaddrinfo?) */ + hp = gethostbyname(host); + if (!hp) { + rs_log_error("failed to look up host \"%s\": %s", host, + hstrerror(h_errno)); + return EXIT_CONNECT_FAILED; + } + + memcpy(&sock_out.sin_addr, hp->h_addr, (size_t) hp->h_length); + sock_out.sin_port = htons((in_port_t) port); + sock_out.sin_family = PF_INET; + + return dcc_connect_by_addr((struct sockaddr *) &sock_out, + sizeof sock_out, p_fd); +} + +#endif /* not ENABLE_RFC2553 */ diff --git a/distcc/src/clinet.h b/distcc/src/clinet.h new file mode 100644 index 0000000..81a3f3e --- /dev/null +++ b/distcc/src/clinet.h @@ -0,0 +1,33 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +struct sockaddr; + +int dcc_connect_by_name(const char *host, + int port, + int *p_fd); + +int dcc_connect_by_addr(struct sockaddr *sa, + size_t salen, + int *p_fd); + + diff --git a/distcc/src/clirpc.c b/distcc/src/clirpc.c new file mode 100644 index 0000000..43e2fda --- /dev/null +++ b/distcc/src/clirpc.c @@ -0,0 +1,281 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "distcc.h" +#include "trace.h" +#include "exec.h" +#include "rpc.h" +#include "exitcode.h" +#include "util.h" +#include "clinet.h" +#include "bulk.h" +#include "hosts.h" +#include "state.h" +#include "include_server_if.h" +#include "emaillog.h" + +/** + * @file + * + * @brief Client-side RPC functions. + **/ + +/* + * Transmit header for whole request. + */ +int dcc_x_req_header(int fd, + enum dcc_protover protover) +{ + return dcc_x_token_int(fd, "DIST", protover); +} + + + +/** + * Transmit an argv array. + **/ +int dcc_x_argv(int fd, char **argv) +{ + int i; + int ret; + int argc; + + argc = dcc_argv_len(argv); + + if (dcc_x_token_int(fd, "ARGC", (unsigned) argc)) + return EXIT_PROTOCOL_ERROR; + + for (i = 0; i < argc; i++) { + if ((ret = dcc_x_token_string(fd, "ARGV", argv[i]))) + return ret; + } + + return 0; +} + +/** + * Transmit the current working directory + */ +int dcc_x_cwd(int fd) +{ + int ret; + char cwd[MAXPATHLEN + 1]; + char * cwd_ret; + cwd_ret = getcwd(cwd, MAXPATHLEN); + if (cwd_ret == NULL) { + return 0; + } + ret = dcc_x_token_string(fd, "CDIR", cwd); + return ret; +} + +/** + * Read the "DONE" token from the network that introduces a response. + **/ +int dcc_r_result_header(int ifd, + enum dcc_protover expect_ver) +{ + unsigned vers; + int ret; + + if ((ret = dcc_r_token_int(ifd, "DONE", &vers))) + return ret; + + if (vers != expect_ver) { + rs_log_error("got version %d not %d in response from server", + vers, expect_ver); + return EXIT_PROTOCOL_ERROR; + } + + rs_trace("got response header"); + + return 0; +} + + +int dcc_r_cc_status(int ifd, int *status) +{ + unsigned u_status; + int ret; + + ret = dcc_r_token_int(ifd, "STAT", &u_status); + *status = u_status; + return ret; +} + + +/** + * The second half of the client protocol: retrieve all results from the server. + **/ +int dcc_retrieve_results(int net_fd, + int *status, + const char *output_fname, + const char *deps_fname, + const char *server_stderr_fname, + struct dcc_hostdef *host) +{ + unsigned len; + int ret; + unsigned o_len; + + if ((ret = dcc_r_result_header(net_fd, host->protover))) + return ret; + + /* We've started to see the response, so the server is done + * compiling. */ + dcc_note_state(DCC_PHASE_RECEIVE, NULL, NULL); + + if ((ret = dcc_r_cc_status(net_fd, status))) + return ret; + + if ((ret = dcc_r_token_int(net_fd, "SERR", &len))) + return ret; + + /* Save the server-side errors into a file. This way, we can + decide later whether we want to report them to the user + or not. We don't want to report them to the user if + we are going to redo the compilation locally, because then + the local errors are going to appear. + Always put the server-side errors in the email we will + send to the maintainers, though. + */ + + if ((ret = dcc_r_file(net_fd, server_stderr_fname, len, host->compr))) + return ret; + + if (dcc_add_file_to_log_email("server-side stderr", server_stderr_fname)) + return ret; + + if ((ret = dcc_r_token_int(net_fd, "SOUT", &len)) + || (ret = dcc_r_bulk(STDOUT_FILENO, net_fd, len, host->compr)) + || (ret = dcc_r_token_int(net_fd, "DOTO", &o_len))) + return ret; + + + /* If the compiler succeeded, then we always retrieve the result, + * even if it's 0 bytes. */ + if (*status == 0) { + if ((ret = dcc_r_file_timed(net_fd, output_fname, o_len, host->compr))) + return ret; + if (host->cpp_where == DCC_CPP_ON_SERVER) { + if ((ret = dcc_r_token_int(net_fd, "DOTD", &len) == 0) + && deps_fname != NULL) { + ret = dcc_r_file_timed(net_fd, deps_fname, len, host->compr); + return ret; + } + } + } else if (o_len != 0) { + rs_log_error("remote compiler failed but also returned output: " + "I don't know what to do"); + } + + return 0; +} + +/* points_to must be at least MAXPATHLEN + 1 long */ +static int dcc_read_link(const char* fname, char *points_to) +{ + int len; + if ((len = readlink(fname, points_to, MAXPATHLEN)) == -1) { + rs_log_error("readlink '%s' failed: %s", fname, strerror(errno)); + return EXIT_IO_ERROR; + } + points_to[len] = '\0'; + return 0; +} + +static int dcc_is_link(const char *fname, int *is_link) +{ + struct stat buf; + + if (lstat(fname, &buf) == -1) { + rs_log_error("stat '%s' failed: %s", fname, strerror(errno)); + return EXIT_IO_ERROR; + } + + *is_link = ((buf.st_mode & S_IFLNK) == S_IFLNK); + return 0; +} + +/* Send to @p ofd @p n_files whose names are in @p fnames. + * @fnames must be null-terminated. + * The names can be coming from the include server, so + * we consult dcc_get_original_fname to get the real names. + * Always uses lzo compression. + */ +/* TODO: This code is highly specific to DCC_VER_3; it assumes + lzo compression is on, and that the include server has + actually compressed the files. */ +int dcc_x_many_files(int ofd, + unsigned int n_files, + char **fnames) +{ + int ret; + char link_points_to[MAXPATHLEN + 1]; + int is_link; + const char *fname; + char *original_fname; + + dcc_x_token_int(ofd, "NFIL", n_files); + + for (; *fnames != NULL; ++fnames) { + fname = *fnames; + ret = dcc_get_original_fname(fname, &original_fname); + if (ret) return ret; + + if ((ret = dcc_is_link(fname, &is_link))) { + return ret; + } + + if (is_link) { + if ((ret = dcc_read_link(fname, link_points_to)) || + (ret = dcc_x_token_string(ofd, "NAME", original_fname)) || + (ret = dcc_x_token_string(ofd, "LINK", link_points_to))) { + return ret; + } + } else { + ret = dcc_x_token_string(ofd, "NAME", original_fname); + if (ret) return ret; + /* File should be compressed already. + If we ever support non-compressed server-side-cpp, + we should have some checks here and then uncompress + the file if it is compressed. */ + ret = dcc_x_file(ofd, fname, "FILE", DCC_COMPRESS_NONE, + NULL); + if (ret) return ret; + } + } + return 0; +} diff --git a/distcc/src/compile.c b/distcc/src/compile.c new file mode 100644 index 0000000..1d47c1b --- /dev/null +++ b/distcc/src/compile.c @@ -0,0 +1,687 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#include <ctype.h> + +#ifdef HAVE_FNMATCH_H + #include <fnmatch.h> +#endif + +#include <sys/time.h> +#include <time.h> +#include <limits.h> +#include <assert.h> + +#include "distcc.h" +#include "trace.h" +#include "exitcode.h" +#include "util.h" +#include "hosts.h" +#include "bulk.h" +#include "implicit.h" +#include "exec.h" +#include "where.h" +#include "lock.h" +#include "timeval.h" +#include "compile.h" +#include "include_server_if.h" +#include "emaillog.h" +#include "dotd.h" + + +static const int max_discrepancies_before_demotion = 1; + +static const char *const include_server_port_suffix = "/socket"; +static const char *const discrepancy_suffix = "/discrepancy_counter"; + +/** + * Return in @param filename the name of the file we use as unary counter of + * discrepancies (a compilation failing on the server, but succeeding + * locally. This function may return NULL in @param filename if the name cannot + * be determined. + **/ +int ddc_discrepancy_filename(char **filename) +{ + const char *include_server_port = getenv("INCLUDE_SERVER_PORT"); + *filename = NULL; + if (include_server_port == NULL) { + return 0; + } else if (str_endswith(include_server_port_suffix, + include_server_port)) { + /* We're going to make a longer string from include_server_port: one + * that replaces include_server_port_suffix with discrepancy_suffix. */ + int delta = strlen(discrepancy_suffix) - + strlen(include_server_port_suffix); + assert (delta > 0); + *filename = malloc(strlen(include_server_port) + delta); + if (!*filename) { + rs_log_error("failed to allocate space for filename"); + return EXIT_OUT_OF_MEMORY; + } + strcpy(*filename, include_server_port); + int slash_pos = strlen(include_server_port) + - strlen(include_server_port_suffix); + /* Because include_server_port_suffix is a suffix of include_server_port + * we expect to find a '/' at slash_pos in filename. */ + assert((*filename)[slash_pos] == '/'); + strcpy(*filename + slash_pos, discrepancy_suffix); + return 0; + } else + return 0; +} + + +/** + * Return the length of the @param discrepancy_filename in newly allocated + * memory; return 0 if it's not possible to determine the length (if + * e.g. @param discrepancy_filename is NULL). + **/ +static int dcc_read_number_discrepancies(const char *discrepancy_filename) +{ + if (!discrepancy_filename) return 0; + struct stat stat_record; + if (stat(discrepancy_filename, &stat_record) == 0) { + size_t size = stat_record.st_size; + /* Does size fit in an 'int'? */ + if ((((size_t) (int) size) == size) && + ((int) size) > 0) + return ((int) size); + else + return INT_MAX; + } else + return 0; +} + + +/** + * Lengthen the file whose name is @param discrepancy_filename by one byte. Or, + * do nothing, if @param discrepancy_filename is NULL. + **/ +static int dcc_note_discrepancy(const char *discrepancy_filename) +{ + FILE *discrepancy_file; + if (!discrepancy_filename) return 0; + if (!(discrepancy_file = fopen(discrepancy_filename, "a"))) { + rs_log_error("failed to open discrepancy_filename file: %s: %s", + discrepancy_filename, + strerror(errno)); + return EXIT_IO_ERROR; + } + if (fputc('@', discrepancy_file) == EOF) { + rs_log_error("failed to write to discrepancy_filename file: %s", + discrepancy_filename); + fclose(discrepancy_file); + return EXIT_IO_ERROR; + } + if (dcc_read_number_discrepancies(discrepancy_filename) == + max_discrepancies_before_demotion) { + /* Give up on using distcc-pump. Print this warning just once. */ + rs_log_warning("now using plain distcc, possibly due to " + "inconsistent file system changes during build"); + } + fclose(discrepancy_file); + return 0; +} + + +/** + * In some cases, it is ill-advised to preprocess on the server. Check for such + * situations. If they occur, then change protocol version. + **/ +static void dcc_perhaps_adjust_cpp_where_and_protover( + char *input_fname, + struct dcc_hostdef *host, + char *discrepancy_filename) +{ + /* It's unfortunate that the variable that controls preprocessing is in the + "host" datastructure. See elaborate complaint in dcc_build_somewhere. */ + + /* Check whether there has been too much trouble running distcc-pump during + this build. */ + if (dcc_read_number_discrepancies(discrepancy_filename) >= + max_discrepancies_before_demotion) { + /* Give up on using distcc-pump */ + host->cpp_where = DCC_CPP_ON_CLIENT; + dcc_get_protover_from_features(host->compr, + host->cpp_where, + &host->protover); + } + + /* Don't do anything silly for already preprocessed files. */ + if (dcc_is_preprocessed(input_fname)) { + /* Don't subject input file to include analysis. */ + rs_log_warning("cannot use distcc_pump on already preprocessed file" + " (such as emitted by ccache)"); + host->cpp_where = DCC_CPP_ON_CLIENT; + dcc_get_protover_from_features(host->compr, + host->cpp_where, + &host->protover); + } + /* Environment variables CPATH and two friends are hidden ways of passing + * -I's. Beware! */ + if (getenv("CPATH") || getenv("C_INCLUDE_PATH") + || getenv("CPLUS_INCLUDE_PATH")) { + rs_log_warning("cannot use distcc_pump with any of environment" + " variables CPATH, C_INCLUDE_PATH or CPLUS_INCLUDE_PATH" + " set, preprocessing locally"); + host->cpp_where = DCC_CPP_ON_CLIENT; + dcc_get_protover_from_features(host->compr, + host->cpp_where, + &host->protover); + } +} + + + +/** + * Do a time analysis of dependencies in dotd file. First, if @param dotd_fname + * is created before @param reference_time, then return NULL in result. Second, + * if one of the files mentioned in the @param dotd_fname is modified after time + * @param reference_time, then return non-NULL in result. Otherwise return NULL + * in result. A non-NULL value in result is a pointer to a newly allocated + * string describing the offending dependency. + + * If @param exclude_pattern is not NULL, then files matching the glob @param + * exclude_pattern are not considered in the above comparison. + * + * This function is not declared static --- for purposes of testing. + **/ +int dcc_fresh_dependency_exists(const char *dotd_fname, + const char *exclude_pattern, + time_t reference_time, + char **result) +{ + struct stat stat_dotd; + off_t dotd_fname_size = 0; + FILE *fp; + char c; + int res; + char *dep_name; + + *result = NULL; + /* Allocate buffer for dotd contents and open it. */ + res = stat(dotd_fname, &stat_dotd); + if (res) { + rs_trace("could not stat \"%s\": %s", dotd_fname, strerror(errno)); + return 0; + } + if (stat_dotd.st_mtime < reference_time) { + /* That .d file appears to be too old; don't trust it for this + * analysis. */ + rs_trace("old dotd file \"%s\"", dotd_fname); + return 0; + } + dotd_fname_size = stat_dotd.st_size; + /* Is dotd_fname_size representable as a size_t value ? */ + if ((off_t) (size_t) dotd_fname_size == dotd_fname_size) { + dep_name = malloc((size_t) dotd_fname_size); + if (!dep_name) { + rs_log_error("failed to allocate space for dotd file"); + return EXIT_OUT_OF_MEMORY; + } + } else { /* This is exceedingly unlikely. */ + rs_trace("file \"%s\" is too big", dotd_fname); + return 0; + } + if ((fp = fopen(dotd_fname, "r")) == NULL) { + rs_trace("could not open \"%s\": %s", dotd_fname, strerror(errno)); + free(dep_name); + return 0; + } + + /* Find ':'. */ + while ((c = getc(fp)) != EOF && c != ':'); + if (c != ':') goto return_0; + + /* Process dependencies. */ + while (c != EOF) { + struct stat stat_dep; + int i = 0; + /* Skip whitespaces and backslashes. */ + while ((c = getc(fp)) != EOF && (isspace(c) || c == '\\')); + /* Now, we're at start of file name. */ + ungetc(c, fp); + while ((c = getc(fp)) != EOF && + (!isspace(c) || c == '\\')) { + if (i >= dotd_fname_size) { + /* Impossible */ + rs_log_error("not enough room for dependency name"); + goto return_0; + } + if (c == '\\') { + /* Skip the newline. */ + if ((c = getc(fp)) != EOF) + if (c != '\n') ungetc(c, fp); + } + else dep_name[i++] = c; + } + if (i != 0) { + dep_name[i] = '\0'; +#ifdef HAVE_FNMATCH_H + if (exclude_pattern == NULL || + fnmatch(exclude_pattern, dep_name, 0) == FNM_NOMATCH) { +#else + /* Tautology avoids compiler warning about unused variable. */ + if (exclude_pattern == exclude_pattern) { +#endif + /* The dep_name is not excluded; now verify that it is not too + * young. */ + rs_log_info("Checking dependency: %s", dep_name); + res = stat(dep_name, &stat_dep); + if (res) goto return_0; + if (stat_dep.st_ctime >= reference_time) { + fclose(fp); + *result = realloc(dep_name, strlen(dep_name) + 1); + if (*result == NULL) { + rs_log_error("realloc failed"); + return EXIT_OUT_OF_MEMORY; + } + return 0; + } + } + } + } + return_0: + fclose(fp); + free(dep_name); + return 0; +} + + +/** + * Invoke a compiler locally. This is, obviously, the alternative to + * dcc_compile_remote(). + * + * The server does basically the same thing, but it doesn't call this + * routine because it wants to overlap execution of the compiler with + * copying the input from the network. + * + * This routine used to exec() the compiler in place of distcc. That + * is slightly more efficient, because it avoids the need to create, + * schedule, etc another process. The problem is that in that case we + * can't clean up our temporary files, and (not so important) we can't + * log our resource usage. + * + * This is called with a lock on localhost already held. + **/ +static int dcc_compile_local(char *argv[], + char *input_name) +{ + pid_t pid; + int ret; + int status; + + dcc_note_execution(dcc_hostdef_local, argv); + dcc_note_state(DCC_PHASE_COMPILE, input_name, "localhost"); + + /* We don't do any redirection of file descriptors when running locally, + * so if for example cpp is being used in a pipeline we should be fine. */ + if ((ret = dcc_spawn_child(argv, &pid, NULL, NULL, NULL)) != 0) + return ret; + + if ((ret = dcc_collect_child("cc", pid, &status, timeout_null_fd))) + return ret; + + return dcc_critique_status(status, "compile", input_name, + dcc_hostdef_local, 1); +} + + + /* Make the decision to send email about @param input_name, but only after a + * little further investgation. + * + * We avoid sending email if there's a fresh dependency. To find out, we need + * @param deps_fname, a .d file, created during the build. We check each + * dependency described there. If just one changed after the build started, + * then we really don't want to hear about distcc-pump errors, because + * dependencies shouldn't change. The files generated during the build are + * exceptions. To disregard these, the distcc user may specify a glob pattern + * in environment variable DISTCC_EXCLUDE_FRESH_FILES. + * + * Also, if there has been too many discrepancies (where the build has + * succeeded remotely but failed locally), then we need to stop using + * distcc-pump for the remainder of the build. The present function + * contributes to this logic: if it is determined that email must be sent, then + * the count of such situations is incremented using the file @param + * discrepancy_filename. + */ +static int dcc_please_send_email_after_investigation( + const char *input_fname, + const char *deps_fname, + const char *discrepancy_filename) { + + int ret; + char *fresh_dependency; + const char *include_server_port = getenv("INCLUDE_SERVER_PORT"); + struct stat stat_port; + rs_log_warning("remote compilation of '%s' failed, retried locally " + "and got a different result.", input_fname); + if ((include_server_port != NULL) && + (stat(include_server_port, &stat_port)) == 0) { + time_t build_start = stat_port.st_ctime; + if (deps_fname) { + const char *exclude_pattern = + getenv("DISTCC_EXCLUDE_FRESH_FILES"); + + if ((ret = dcc_fresh_dependency_exists(deps_fname, + exclude_pattern, + build_start, + &fresh_dependency))) { + return ret; + } + if (fresh_dependency) { + rs_log_warning("file '%s', a dependency of %s, " + "changed during the build", fresh_dependency, + input_fname); + free(fresh_dependency); + return dcc_note_discrepancy(discrepancy_filename); + } + } + } + dcc_please_send_email(); + return dcc_note_discrepancy(discrepancy_filename); +} + +/** + * Execute the commands in argv remotely or locally as appropriate. + * + * We may need to run cpp locally; we can do that in the background + * while trying to open a remote connection. + * + * This function is slightly inefficient when it falls back to running + * gcc locally, because cpp may be run twice. Perhaps we could adjust + * the command line to pass in the .i file. On the other hand, if + * something has gone wrong, we should probably take the most + * conservative course and run the command unaltered. It should not + * be a big performance problem because this should occur only rarely. + * + * @param argv Command to execute. Does not include 0='distcc'. + * Treated as read-only, because it is a pointer to the program's real + * argv. + * + * @param status On return, contains the waitstatus of the compiler or + * preprocessor. This function can succeed (in running the compiler) even if + * the compiler itself fails. If either the compiler or preprocessor fails, + * @p status is guaranteed to hold a failure value. + **/ +static int +dcc_build_somewhere(char *argv[], + int sg_level, + int *status) +{ + char *input_fname = NULL, *output_fname, *cpp_fname, *deps_fname = NULL; + char **files; + char **server_side_argv = NULL; + char *server_stderr_fname = NULL; + int needs_dotd = 0; + int sets_dotd_target = 0; + pid_t cpp_pid = 0; + int cpu_lock_fd, local_cpu_lock_fd; + int ret; + int remote_ret = 0; + struct dcc_hostdef *host = NULL; + char *discrepancy_filename; + + if ((ret = ddc_discrepancy_filename(&discrepancy_filename))) + return ret; + + if (sg_level) + goto run_local; + + /* TODO: Perhaps tidy up these gotos. */ + + if (dcc_scan_args(argv, &input_fname, &output_fname, &argv) != 0) { + /* we need to scan the arguments even if we already know it's + * local, so that we can pick up distcc client options. */ + goto lock_local; + } +#if 0 + /* turned off because we never spend long in this state. */ + dcc_note_state(DCC_PHASE_STARTUP, input_fname, NULL); +#endif + if ((ret = dcc_make_tmpnam("distcc_server_stderr", ".txt", + &server_stderr_fname))) { + // So we are failing locally to make a temp file to store the + // server-side errors in; it's unlikely anything else will + // work, but let's try the compilation locally. + // FIXME: this will blame the server for a failure that is + // local. However, we don't make any distrinction between + // all the reasons dcc_compile_remote can fail either; + // and some of those reasons are local. + goto fallback; + } + + if ((ret = dcc_lock_local_cpp(&local_cpu_lock_fd)) != 0) { + goto fallback; + } + + if ((ret = dcc_pick_host_from_list(&host, &cpu_lock_fd)) != 0) { + /* Doesn't happen at the moment: all failures are masked by + returning localhost. */ + goto fallback; + } + + if (host->mode == DCC_MODE_LOCAL) + /* We picked localhost and already have a lock on it so no + * need to lock it now. */ + goto run_local; + + if (host->cpp_where == DCC_CPP_ON_SERVER) { + /* Perhaps it is not a good idea to preprocess on the server. */ + dcc_perhaps_adjust_cpp_where_and_protover(input_fname, host, + discrepancy_filename); + } + if (host->cpp_where == DCC_CPP_ON_SERVER) { + if ((ret = dcc_talk_to_include_server(argv, &files))) { + /* Fallback to doing cpp locally */ + /* It's unfortunate that the variable that controls that is in the + * "host" datastructure, even though in this case it's the client + * that fails to support it, but "host" is what gets passed + * around in the client code. We are, in essense, throwing away + * the host's capability to do cpp, so if this code was to execute + * again (it won't, not in the same process) we wouldn't know if + * the server supports it or not. + */ + rs_log_warning("failed to get includes from include server, " + "preprocessing locally"); + if (dcc_getenv_bool("DISTCC_TESTING_INCLUDE_SERVER", 0)) + dcc_exit(ret); + host->cpp_where = DCC_CPP_ON_CLIENT; + dcc_get_protover_from_features(host->compr, + host->cpp_where, + &host->protover); + } else { + // done "preprocessing" + dcc_unlock(local_cpu_lock_fd); + // don't try to unlock again in dcc_compile_remote + local_cpu_lock_fd = 0; + } + } + + if (host->cpp_where == DCC_CPP_ON_CLIENT) { + files = NULL; + + if ((ret = dcc_cpp_maybe(argv, input_fname, &cpp_fname, &cpp_pid) != 0)) + goto fallback; + + if ((ret = dcc_strip_local_args(argv, &server_side_argv))) + goto fallback; + } else { + char *dotd_target = NULL; + cpp_fname = NULL; + cpp_pid = 0; + dcc_get_dotd_info(argv, &deps_fname, &needs_dotd, + &sets_dotd_target, &dotd_target); + if ((ret = dcc_copy_argv(argv, &server_side_argv, 2))) + goto fallback; + if (needs_dotd && !sets_dotd_target) { + dcc_argv_append(server_side_argv, strdup("-MT")); + if (dotd_target == NULL) + dcc_argv_append(server_side_argv, strdup(output_fname)); + else + dcc_argv_append(server_side_argv, strdup(dotd_target)); + } + } + if ((ret = dcc_compile_remote(server_side_argv, + input_fname, + cpp_fname, + files, + output_fname, + needs_dotd ? deps_fname : NULL, + server_stderr_fname, + cpp_pid, local_cpu_lock_fd, + host, status)) != 0) { + /* Returns zero if we successfully ran the compiler, even if + * the compiler itself bombed out. */ + goto fallback; + } + + dcc_enjoyed_host(host); + + dcc_unlock(cpu_lock_fd); + + ret = dcc_critique_status(*status, "compile", input_fname, host, 1); + if (ret == 0) { + // Try to copy the server-side errors on stderr. + // If that fails, even though the compilation succeeded, + // we haven't managed to give these errors to the user, + // so we have to try again. + // FIXME: Just like in the attempt to make a temporary file, this + // is unlikely to fail, if it does it's unlikely any other + // operation will work, and this makes the mistake of + // blaming the server for what is (clearly?) a local failure. + if ((dcc_copy_file_to_fd(server_stderr_fname, STDERR_FILENO))) { + rs_log_warning("Could not show server-side errors"); + goto fallback; + } + goto clean_up; + } + if (ret < 128) { + /* Remote compile just failed, e.g. with syntax error. + It may be that the remote compilation failed because + the file has an error, or because we did something + wrong (e.g. we did not send all the necessary files.) + Retry locally. If the local compilation also fails, + then we know it's the program that has the error, + and it doesn't really matter that we recompile, because + this is rare. + If the local compilation succeeds, then we know it's our + fault, and we should do something about it later. + (Currently, we send email to an appropriate email address). + */ + rs_log_warning("remote compilation of '%s' failed, retrying locally", + input_fname); + remote_ret = ret; + goto fallback; + } + + + fallback: + if (host) + dcc_disliked_host(host); + + if (!dcc_getenv_bool("DISTCC_FALLBACK", 1)) { + rs_log_warning("failed to distribute and fallbacks are disabled"); + // Try copying any server-side error message to stderr; + // If we fail the user will miss all the messages from the server; so + // we pretend we failed remotely. + if ((dcc_copy_file_to_fd(server_stderr_fname, STDERR_FILENO))) { + rs_log_error("Could not print error messages from '%s'", + server_stderr_fname); + } + goto clean_up; + } + + // At this point, we can abandon the remote errors. + + /* "You guys are so lazy! Do I have to do all the work myself??" */ + if (host) { + rs_log(RS_LOG_WARNING|RS_LOG_NONAME, + "failed to distribute %s to %s, running locally instead", + input_fname ? input_fname : "(unknown)", + host->hostdef_string); + } else { + rs_log_warning("failed to distribute, running locally instead"); + } + + lock_local: + dcc_lock_local(&cpu_lock_fd); + + run_local: + /* Either compile locally, after remote failure, or simply do other cc tasks + as assembling, linking, etc. */ + ret = dcc_compile_local(argv, input_fname); + if (remote_ret != 0 && remote_ret != ret) { + /* Oops! it seems what we did remotely is not the same as what we did + locally. We normally send email in such situations (if emailing is + enabled), but we attempt an a time analysis of source files in order + to avoid doing so in case source files we changed during the build. + */ + (void) dcc_please_send_email_after_investigation( + input_fname, + deps_fname, + discrepancy_filename); + } + + clean_up: + free(server_side_argv); + free(discrepancy_filename); + return ret; +} + + +int dcc_build_somewhere_timed(char *argv[], + int sg_level, + int *status) +{ + struct timeval before, after, delta; + int ret; + + if (gettimeofday(&before, NULL)) + rs_log_warning("gettimeofday failed"); + + ret = dcc_build_somewhere(argv, sg_level, status); + + if (gettimeofday(&after, NULL)) { + rs_log_warning("gettimeofday failed"); + } else { + /* TODO: Show rate based on cpp size? Is that meaningful? */ + timeval_subtract(&delta, &after, &before); + + rs_log(RS_LOG_INFO|RS_LOG_NONAME, + "elapsed compilation time %ld.%06lds", + delta.tv_sec, delta.tv_usec); + } + + return ret; +} diff --git a/distcc/src/compile.h b/distcc/src/compile.h new file mode 100644 index 0000000..f2c37a4 --- /dev/null +++ b/distcc/src/compile.h @@ -0,0 +1,46 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* remote.c */ +int dcc_compile_remote(char **argv, + char *input_fname, + char *cpp_fname, + char **file_names, + char *output_fname, + char *deps_fname, + char *server_stderr_fname, + pid_t cpp_pid, + int local_cpu_lock_fd, + struct dcc_hostdef *host, + int *status); + +int dcc_build_somewhere_timed(char *argv[], + int sg_level, + int *status); + +/* Declared here for testing purposes. */ +int dcc_fresh_dependency_exists(const char *dotd_fname, + const char *exlude_pat, + time_t reference_time, + char **fresh_dependency); + +int ddc_discrepancy_filename(char **filename); diff --git a/distcc/src/compress.c b/distcc/src/compress.c new file mode 100644 index 0000000..88ebdfc --- /dev/null +++ b/distcc/src/compress.c @@ -0,0 +1,254 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003, 2004 by Martin Pool <mbp@sourcefrog.net> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + /* I think that I can safely speak for the + * whole troll community when I say "I like + * watching train wrecks". -- AC */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/socket.h> +#ifdef HAVE_SYS_MMAN_H +# include <sys/mman.h> +#endif + +#include <netinet/in.h> +#include <netinet/tcp.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "exitcode.h" +#include "minilzo.h" + + +static char work_mem[LZO1X_1_MEM_COMPRESS]; + +/** + * @file + * + * Compressed bulk data transfer for distcc. + * + * lzo doesn't have any detectable magic at the start in the raw form. (lzop + * the command-line tool adds some.) Therefore we indicate in the request + * header (the protocol version) whether compression is on or off. If it is + * on, all bulk data in both directions is compressed. metadata whether the + * transfer is compressed or not. + * + * It might be nice to unify this code with that in pump.c, which deals with + * uncompressed files. There are some parallels between the routines. + * However the details are rather different, because with compressed files we + * do not know ahead of time how big the expanded form will be. This affects + * sending, where we need to make a large-enough temporary buffer to compress + * into. It also affects receipt, where we need to allow extra space for data + * coming in. So for the moment they remain separate. + * + * We used to use mmap here, but it complicated the code (and caused a bug in + * 2.14) without being clearly any faster. So it's out again. + * + * The chunk header gives the number of compressed bytes. The number of + * plaintext bytes isn't transmitted, and so for decompression we might need + * to scale up the buffer. + */ + + +/* + * Compress from a file to a newly malloc'd block. + */ +int dcc_compress_file_lzo1x(int in_fd, + size_t in_len, + char **out_buf, + size_t *out_len) +{ + char *in_buf = NULL; + int ret; + + if ((in_buf = malloc(in_len)) == NULL) { + rs_log_error("allocation of %ld byte buffer failed", + (long) in_len); + ret = EXIT_OUT_OF_MEMORY; + goto out; + } + + if ((ret = dcc_readx(in_fd, in_buf, in_len))) + goto out; + + if ((ret = dcc_compress_lzo1x_alloc(in_buf, in_len, out_buf, out_len))) + goto out; + + out: + if (in_buf != NULL) { + free(in_buf); + } + + return ret; +} + + +/** + * Send LZO-compressed bulk data. + * + * The most straighforward method for miniLZO is to just send everything in + * one big chunk. So we just read the whole input into a buffer, build the + * output in a buffer, and send it once its complete. + **/ +int dcc_compress_lzo1x_alloc(const char *in_buf, + size_t in_len, + char **out_buf_ret, + size_t *out_len_ret) +{ + int ret = 0, lzo_ret; + char *out_buf = NULL; + size_t out_size; + lzo_uint out_len; + + /* NOTE: out_size is the buffer size, out_len is the amount of actual + * data. */ + + /* In the unlikely worst case, LZO can cause the input to expand a bit. */ + out_size = in_len + in_len/64 + 16 + 3; + if ((out_buf = malloc(out_size)) == NULL) { + rs_log_error("failed to allocate compression buffer"); + return EXIT_OUT_OF_MEMORY; + } + + out_len = out_size; + lzo_ret = lzo1x_1_compress((lzo_byte*)in_buf, in_len, + (lzo_byte*)out_buf, &out_len, + work_mem); + if (lzo_ret != LZO_E_OK) { + rs_log_error("LZO1X1 compression failed: %d", lzo_ret); + free(out_buf); + return EXIT_IO_ERROR; + } + + *out_buf_ret = out_buf; + *out_len_ret = out_len; + + rs_trace("compressed %ld bytes to %ld bytes: %d%%", + (long) in_len, (long) out_len, + (int) (in_len ? 100*out_len / in_len : 0)); + + return ret; +} + + + +/** + * Receive @p in_len compressed bytes from @p in_fd, and write the + * decompressed form to @p out_fd. + * + * There's no way for us to know how big the uncompressed form will be, and + * there is also no way to grow the decompression buffer if it turns out to + * initially be too small. So we assume a ratio of 10x. If it turns out to + * be too small, we increase the buffer and try again. Typical compression of + * source or object is about 2x to 4x. On modern Unix we should be able to + * allocate (and not touch) many megabytes at little cost, since it will just + * turn into an anonymous map. + * + * LZO doesn't have any way to decompress part of the input and then break to + * get more output space, so our buffer needs to be big enough in the first + * place or we would waste time repeatedly decompressing it. + **/ +int dcc_r_bulk_lzo1x(int out_fd, int in_fd, + unsigned in_len) +{ + int ret, lzo_ret; + char *in_buf = NULL, *out_buf = NULL; + size_t out_size = 0; + lzo_uint out_len; + + /* NOTE: out_size is the buffer size, out_len is the amount of actual + * data. */ + + if (in_len == 0) + return 0; /* just check */ + + if ((in_buf = malloc(in_len)) == NULL) { + rs_log_error("failed to allocate decompression input"); + ret = EXIT_OUT_OF_MEMORY; + goto out; + } + + if ((ret = dcc_readx(in_fd, in_buf, in_len)) != 0) + goto out; + +#if 0 + /* Initial estimate for output buffer. This is intentionally quite low to + * exercise the resizing code -- if it works OK then we can scale this + * up. */ + out_size = 2 * in_len; +#else + out_size = 8 * in_len; +#endif + + try_again_with_a_bigger_buffer: + + if ((out_buf = malloc(out_size)) == NULL) { + rs_log_error("failed to allocate decompression buffer"); + ret = EXIT_OUT_OF_MEMORY; + goto out; + } + + out_len = out_size; + lzo_ret = lzo1x_decompress_safe((lzo_byte*)in_buf, in_len, + (lzo_byte*)out_buf, &out_len, work_mem); + + if (lzo_ret == LZO_E_OK) { + rs_trace("decompressed %ld bytes to %ld bytes: %d%%", + (long) in_len, (long) out_len, + (int) (out_len ? 100*in_len / out_len : 0)); + + ret = dcc_writex(out_fd, out_buf, out_len); + + goto out; + } else if (lzo_ret == LZO_E_OUTPUT_OVERRUN) { + free(out_buf); + out_buf = 0; + out_size *= 2; + /* FIXME: Make sure this doesn't overflow memory size? */ + rs_trace("LZO_E_OUTPUT_OVERRUN, trying again with %lu byte buffer", + (unsigned long) out_size); + goto try_again_with_a_bigger_buffer; + } else { + rs_log_error("LZO1X1 decompression failed: %d", lzo_ret); + ret = EXIT_IO_ERROR; + goto out; + } + +out: + free(in_buf); + free(out_buf); + + return ret; +} diff --git a/distcc/src/cpp.c b/distcc/src/cpp.c new file mode 100644 index 0000000..f82c8a3 --- /dev/null +++ b/distcc/src/cpp.c @@ -0,0 +1,103 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/** + * @file + * + * Run the preprocessor. Client-side only. + **/ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include "distcc.h" +#include "trace.h" +#include "exitcode.h" +#include "util.h" +#include "implicit.h" +#include "exec.h" + + +/** + * If the input filename is a plain source file rather than a + * preprocessed source file, then preprocess it to a temporary file + * and return the name in @p cpp_fname. + * + * The preprocessor may still be running when we return; you have to + * wait for @p cpp_fid to exit before the output is complete. This + * allows us to overlap opening the TCP socket, which probably doesn't + * use many cycles, with running the preprocessor. + **/ +int dcc_cpp_maybe(char **argv, char *input_fname, char **cpp_fname, + pid_t *cpp_pid) +{ + char **cpp_argv; + int ret; + char *input_exten; + const char *output_exten; + + *cpp_pid = 0; + + if (dcc_is_preprocessed(input_fname)) { + /* TODO: Perhaps also consider the option that says not to use cpp. + * Would anyone do that? */ + rs_trace("input is already preprocessed"); + + /* already preprocessed, great. */ + if (!(*cpp_fname = strdup(input_fname))) { + rs_log_error("couldn't duplicate string"); + return EXIT_OUT_OF_MEMORY; + } + return 0; + } + + input_exten = dcc_find_extension(input_fname); + output_exten = dcc_preproc_exten(input_exten); + if ((ret = dcc_make_tmpnam("distcc", output_exten, cpp_fname))) + return ret; + + /* We strip the -o option and allow cpp to write to stdout, which is + * caught in a file. Sun cc doesn't understand -E -o, and gcc screws up + * -MD -E -o. + * + * There is still a problem here with -MD -E -o, gcc writes dependencies + * to a file determined by the source filename. We could fix it by + * generating a -MF option, but that would break compilation with older + * versions of gcc. This is only a problem for people who have the source + * and objects in different directories, and who don't specify -MF. They + * can fix it by specifying -MF. */ + + if ((ret = dcc_strip_dasho(argv, &cpp_argv)) + || (ret = dcc_set_action_opt(cpp_argv, "-E"))) + return ret; + + /* FIXME: cpp_argv is leaked */ + + return dcc_spawn_child(cpp_argv, cpp_pid, + "/dev/null", *cpp_fname, NULL); +} + + diff --git a/distcc/src/daemon.c b/distcc/src/daemon.c new file mode 100644 index 0000000..a7bdc1c --- /dev/null +++ b/distcc/src/daemon.c @@ -0,0 +1,306 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + /* "Just like distributed.net, only useful!" */ + +/** + * @file + * + * distcc volunteer server. Accepts and serves requests to compile + * files. + * + * May be run from inetd (default if stdin is a socket), or as a + * daemon by itself. + * + * distcc has an adequate but perhaps not optimal system for deciding + * where to send files. The general principle is that the server + * should say how many jobs it is willing to accept, rather than the + * client having to know. This is probably good in two ways: it + * allows for people in the future to impose limits on how much work + * their contributed machine will do, and secondly it seems better to + * put this information in one place rather than on every client. + **/ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <syslog.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> + +#ifdef HAVE_ARPA_NAMESER_H +# include <arpa/nameser.h> +#endif + +#include <arpa/inet.h> + + +#include "exitcode.h" +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "dopt.h" +#include "srvnet.h" +#include "daemon.h" +#include "types.h" + + +/* for trace.c */ +char const *rs_program_name = "distccd"; + + +static int dcc_inetd_server(void); +static void dcc_setup_real_log(void); + + +/** + * Errors during startup (e.g. bad options) need to be reported somewhere, + * although we have not yet parsed the options to work out where the user + * wants them. + * + * In inetd mode, we can't write to stderr because that will corrupt the + * stream, so if it looks like stderr is a socket we go to syslog instead. + **/ +static int dcc_setup_startup_log(void) +{ + rs_trace_set_level(RS_LOG_INFO); + if (!is_a_socket(STDERR_FILENO)) { + rs_add_logger(rs_logger_file, RS_LOG_DEBUG, 0, STDERR_FILENO); + } else { + openlog("distccd", LOG_PID, LOG_DAEMON); + rs_add_logger(rs_logger_syslog, RS_LOG_DEBUG, NULL, 0); + } + + return 0; +} + + +static int dcc_should_be_inetd(void) +{ + /* Work out if we ought to serve stdin or be a standalone daemon */ + if (opt_inetd_mode) + return 1; + else if (opt_daemon_mode) + return 0; + else if (is_a_socket(STDIN_FILENO)) { + rs_log_info("stdin is socket; assuming --inetd mode"); + return 1; + } else if (isatty(STDIN_FILENO)) { + rs_log_info("stdin is a tty; assuming --daemon mode"); + return 0; + } else { + rs_log_info("stdin is neither a tty nor a socket; assuming --daemon mode"); + return 0; + } +} + + +static int dcc_setup_daemon_path(void) +{ + int ret; + const char *path; + + if ((path = getenv("DISTCCD_PATH")) != NULL) { + if ((ret = dcc_set_path(path))) + return ret; + + return 0; + } else { + path = getenv("PATH"); + rs_log_info("daemon's PATH is %s", path ? path : "(NULL)"); + return 0; + } +} + + +/** + * distcc daemon. May run from inetd, or standalone. Accepts + * requests from clients to compile files. + **/ +int main(int argc, char *argv[]) +{ + int ret; + const char *tmp; + + dcc_setup_startup_log(); + + if (distccd_parse_options(argc, (const char **) argv)) + dcc_exit(EXIT_DISTCC_FAILED); + + /* check this before redirecting the logs, so that it's really obvious */ + if (!dcc_should_be_inetd()) + if (opt_allowed == NULL) { + rs_log_error("--allow option is now mandatory; " + "you must specify which clients are allowed to connect"); + ret = EXIT_BAD_ARGUMENTS; + goto out; + } + + if ((ret = dcc_set_lifetime()) != 0) + dcc_exit(ret); + + /* do this before giving away root */ + if (nice(opt_niceness) == -1) { + rs_log_warning("nice %d failed: %s", opt_niceness, + strerror(errno)); + /* continue anyhow */ + } + + if ((ret = dcc_discard_root()) != 0) + dcc_exit(ret); + + /* Discard privileges before opening log so that if it's created, it has + * the right ownership. */ + dcc_setup_real_log(); + + /* Do everything from root directory. Allows start directory to be + * unmounted, should make accidental writing of local files cause a + * failure... */ + if ((ret = dcc_get_tmp_top(&tmp))) + goto out; + + if (chdir(tmp) == -1) { + rs_log_error("failed to chdir to %s: %s", tmp, strerror(errno)); + ret = EXIT_IO_ERROR; + goto out; + } else { + rs_trace("chdir to %s", tmp); + } + + if ((ret = dcc_setup_daemon_path())) + goto out; + + if (dcc_should_be_inetd()) + ret = dcc_inetd_server(); + else + ret = dcc_standalone_server(); + + out: + dcc_exit(ret); +} + + +/** + * If a --lifetime options was specified, set up a timer that will kill the + * daemon when it expires. + **/ +int dcc_set_lifetime(void) +{ + if (opt_lifetime) { + alarm(opt_lifetime); +/* rs_trace("set alarm for %+d seconds", opt_lifetime); */ + } + return 0; +} + + +/** + * Set log to the final destination after options have been read. + **/ +static void dcc_setup_real_log(void) +{ + int fd; + + /* Even in inetd mode, we might want to log to stderr, because that will + * work OK for ssh connections. */ + + if (opt_log_stderr) { + rs_remove_all_loggers(); + rs_add_logger(rs_logger_file, opt_log_level_num, 0, STDERR_FILENO); + return; + } + + if (arg_log_file) { + /* Don't remove loggers yet, in case this fails and needs to go to the + * default. */ + if ((fd = open(arg_log_file, O_CREAT|O_APPEND|O_WRONLY, 0666)) == -1) { + rs_log_error("failed to open %s: %s", arg_log_file, + strerror(errno)); + /* continue and use syslog */ + } else { + rs_remove_all_loggers(); + rs_add_logger(rs_logger_file, opt_log_level_num, NULL, fd); + return; + } + } + + rs_remove_all_loggers(); + openlog("distccd", LOG_PID, LOG_DAEMON); + rs_add_logger(rs_logger_syslog, opt_log_level_num, NULL, 0); +} + + +int dcc_log_daemon_started(const char *role) +{ + rs_log_info("%s started (%s %s, built %s %s)", + role, + PACKAGE_VERSION, + GNU_HOST, + __DATE__, __TIME__); + + return 0; +} + + +/** + * Serve a single file on stdin, and then exit. + **/ +static int dcc_inetd_server(void) +{ + int ret, close_ret; + struct dcc_sockaddr_storage ss; + struct sockaddr *psa = (struct sockaddr *) &ss; + socklen_t len = sizeof ss; + + dcc_log_daemon_started("inetd server"); + + if ((getpeername(STDIN_FILENO, psa, &len) == -1)) { + /* This can fail with ENOTSOCK if e.g. sshd has started us on a pipe, + * not on a socket. I think it's harmless. */ + rs_log_notice("failed to get peer name: %s", strerror(errno)); + psa = NULL; /* make sure we don't refer to uninitialized mem */ + len = 0; + } + + ret = dcc_service_job(STDIN_FILENO, STDOUT_FILENO, psa, len); + + close_ret = dcc_close(STDIN_FILENO); + + if (ret) + return ret; + else + return close_ret; +} + diff --git a/distcc/src/daemon.h b/distcc/src/daemon.h new file mode 100644 index 0000000..438e08b --- /dev/null +++ b/distcc/src/daemon.h @@ -0,0 +1,56 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +/* daemon.c */ +int dcc_refuse_root(void); +int dcc_set_lifetime(void); +int dcc_log_daemon_started(const char *role); + + +/* dsignal.c */ +void dcc_ignore_sighup(void); +void dcc_daemon_catch_signals(void); + +/* dparent.c */ +int dcc_standalone_server(void); +void dcc_remove_pid(void); +void dcc_reap_kids(int must_reap); + + +/* prefork.c */ +int dcc_preforking_parent(int listen_fd); + + +/* serve.c */ +struct sockaddr; +int dcc_service_job(int in_fd, int out_fd, struct sockaddr *, int); + +/* setuid.c */ +int dcc_discard_root(void); +extern const char *opt_user; + + +extern int dcc_max_kids; +extern int dcc_nkids; + +extern volatile pid_t dcc_master_pid; diff --git a/distcc/src/distcc.c b/distcc/src/distcc.c new file mode 100644 index 0000000..2bf4b52 --- /dev/null +++ b/distcc/src/distcc.c @@ -0,0 +1,221 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + /* 4: The noise of a multitude in the + * mountains, like as of a great people; a + * tumultuous noise of the kingdoms of nations + * gathered together: the LORD of hosts + * mustereth the host of the battle. + * -- Isaiah 13 */ + + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> + +#include "distcc.h" +#include "trace.h" +#include "exitcode.h" +#include "util.h" +#include "hosts.h" +#include "bulk.h" +#include "implicit.h" +#include "compile.h" +#include "emaillog.h" + + +/* Name of this program, for trace.c */ +const char *rs_program_name = "distcc"; + + +/** + * @file + * + * Entry point for the distcc client. + * + * There are three methods of use for distcc: explicit (distcc gcc -c + * foo.c), implicit (distcc -c foo.c) and masqueraded (gcc -c foo.c, + * where gcc is really a link to distcc). + * + * Detecting these is relatively easy by examining the first one or + * two words of the command. We also need to make sure that when we + * go to run the compiler, we run the one intended by the user. + * + * In particular, for masqueraded mode, we want to make sure that we + * don't invoke distcc recursively. + **/ + +static void dcc_show_usage(void) +{ + dcc_show_version("distcc"); + printf( +"Usage:\n" +" distcc [COMPILER] [compile options] -o OBJECT -c SOURCE\n" +" distcc --help\n" +"\n" +"Options:\n" +" COMPILER defaults to \"cc\"\n" +" --help explain usage and exit\n" +" --version show version and exit\n" +"\n" +"Environment variables:\n" +" See the manual page for a complete list.\n" +" DISTCC_VERBOSE=1 give debug messages\n" +" DISTCC_LOG send messages to file, not stderr\n" +" DISTCC_SSH command to run to open SSH connections\n" +" DISTCC_DIR directory for host list and locks\n" +"\n" +"Server specification:\n" +"A list of servers is taken from the environment variable $DISTCC_HOSTS, or\n" +"$DISTCC_DIR/hosts, or ~/.distcc/hosts, or %s/distcc/hosts.\n" +"Each host can be given in any of these forms, see the manual for details:\n" +"\n" +" localhost run in place\n" +" HOST TCP connection, port %d\n" +" HOST:PORT TCP connection, specified port\n" +" @HOST SSH connection\n" +" USER@HOST SSH connection to specified host\n" +" --randomize Randomize the server list before execution\n" +"\n" +"distcc distributes compilation jobs across volunteer machines running\n" +"distccd. Jobs that cannot be distributed, such as linking or \n" +"preprocessing are run locally. distcc should be used with make's -jN\n" +"option to execute in parallel on several machines.\n", + SYSCONFDIR, + DISTCC_DEFAULT_PORT); +} + + +static RETSIGTYPE dcc_client_signalled (int whichsig) +{ + signal(whichsig, SIG_DFL); + +#ifdef HAVE_STRSIGNAL + rs_log_info("%s", strsignal(whichsig)); +#else + rs_log_info("terminated by signal %d", whichsig); +#endif + + dcc_cleanup_tempfiles_from_signal_handler(); + + raise(whichsig); + +} + + +static void dcc_client_catch_signals(void) +{ + signal(SIGTERM, &dcc_client_signalled); + signal(SIGINT, &dcc_client_signalled); + signal(SIGHUP, &dcc_client_signalled); +} + + + +/** + * distcc client entry point. + * + * This is typically called by make in place of the real compiler. + * + * Performs basic setup and checks for distcc arguments, and then kicks off + * dcc_build_somewhere(). + **/ +int main(int argc, char **argv) +{ + int status, sg_level, tweaked_path = 0; + char **compiler_args; + char *compiler_name; + int ret; + + dcc_client_catch_signals(); + atexit(dcc_cleanup_tempfiles); + atexit(dcc_remove_state_file); + + dcc_set_trace_from_env(); + dcc_setup_log_email(); + + dcc_trace_version(); + + compiler_name = (char *) dcc_find_basename(argv[0]); + + /* Ignore SIGPIPE; we consistently check error codes and will + * see the EPIPE. */ + dcc_ignore_sigpipe(1); + + sg_level = dcc_recursion_safeguard(); + + rs_trace("compiler name is \"%s\"", compiler_name); + + if (strstr(compiler_name, "distcc") != NULL) { + /* Either "distcc -c hello.c" or "distcc gcc -c hello.c" */ + if (argc <= 1 || !strcmp(argv[1], "--help")) { + dcc_show_usage(); + ret = 0; + goto out; + } + if (!strcmp(argv[1], "--version")) { + dcc_show_version("distcc"); + ret = 0; + goto out; + } + + dcc_find_compiler(argv, &compiler_args); + /* compiler_args is now respectively either "cc -c hello.c" or + * "gcc -c hello.c" */ + +#if 0 + /* I don't think we need to call this: if we reached this + * line, our invocation name is something like 'distcc', and + * that's never a problem for masquerading loops. */ + if ((ret = dcc_trim_path(compiler_name)) != 0) + goto out; +#endif + } else { + /* Invoked as "cc -c hello.c", with masqueraded path */ + if ((ret = dcc_support_masquerade(argv, compiler_name, + &tweaked_path)) != 0) + goto out; + + dcc_copy_argv(argv, &compiler_args, 0); + compiler_args[0] = compiler_name; + } + + if (sg_level - tweaked_path > 0) { + rs_log_crit("distcc seems to have invoked itself recursively!"); + ret = EXIT_RECURSION; + goto out; + } + + ret = dcc_build_somewhere_timed(compiler_args, sg_level, &status); + + out: + dcc_maybe_send_email(); + dcc_exit(ret); +} diff --git a/distcc/src/distcc.h b/distcc/src/distcc.h new file mode 100644 index 0000000..c0686a7 --- /dev/null +++ b/distcc/src/distcc.h @@ -0,0 +1,336 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* distcc.h -- common internal-use header file */ + +#include <sys/types.h> + + +#ifdef NORETURN +/* nothing */ +#elif defined(__GNUC__) +# define NORETURN __attribute__((noreturn)) +#elif defined(__LCLINT__) +# define NORETURN /*@noreturn@*/ x +#else /* !__GNUC__ && !__LCLINT__ */ +# define NORETURN +#endif /* !__GNUC__ && !__LCLINT__ */ + +#ifdef UNUSED +/* nothing */ +#elif defined(__GNUC__) +# define UNUSED(x) UNUSED_ ## x __attribute__((unused)) +#elif defined(__LCLINT__) +# define UNUSED(x) /*@unused@*/ x +#else /* !__GNUC__ && !__LCLINT__ */ +# define UNUSED(x) x +#endif /* !__GNUC__ && !__LCLINT__ */ + + +#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)) +/* This works on Gentoo's (patched?) gcc 3.3.3 but not 3.2.3, and not Debian's + * 3.3.4. It should be standard on 3.4. */ +# define WARN_UNUSED __attribute__((warn_unused_result)) +#else +# define WARN_UNUSED +#endif + + +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +#endif + + +struct dcc_hostdef; + + + +#include "state.h" + + + + +enum dcc_compress { + /* wierd values to catch errors */ + DCC_COMPRESS_NONE = 69, + DCC_COMPRESS_LZO1X +}; + +enum dcc_cpp_where { + /* wierd values to catch errors */ + DCC_CPP_ON_CLIENT = 42, + DCC_CPP_ON_SERVER +}; + +enum dcc_protover { + DCC_VER_1 = 1, /**< vanilla */ + DCC_VER_2 = 2, /**< LZO sprinkles */ + DCC_VER_3 = 3 /**< server-side cpp */ +}; + + + + + +int str_endswith(const char *tail, const char *tiger); + + + + +/* A macro so that we get the right __FUNCTION__ in the trace message. + * + * We condition on rs_trace_enabled so that we don't do the to-string + * conversion unless the user will actually see the result, because it's a + * little expensive. */ +#define dcc_trace_argv(_message, _argv) \ + if (rs_trace_enabled()) { \ + char *_astr; \ + _astr = dcc_argv_tostr(_argv); \ + rs_trace("%s: %s", _message, _astr); \ + free(_astr); \ + } else {} + + +/* help.c */ +int dcc_trace_version(void); +int dcc_show_version(const char *prog); + + +/* hosts.c */ +int dcc_parse_hosts_env(struct dcc_hostdef **ret_list, + int *ret_nhosts); +int dcc_parse_hosts(const char *where, const char *source_name, + struct dcc_hostdef **ret_list, + int *ret_nhosts); + +/* ncpu.c */ +int dcc_ncpus(int *); + +/* ssh.c */ +int dcc_ssh_connect(char *ssh_cmd, char *user, + char *machine, char *path, + int *f_in, int *f_out, + pid_t *ssh_pid); + +/* safeguard.c */ +int dcc_increment_safeguard(void); +int dcc_recursion_safeguard(void); + +/* clirpc.c */ +int dcc_x_req_header(int fd, + enum dcc_protover protover); +int dcc_x_argv(int fd, char **argv); +int dcc_x_cwd(int fd); + +/* srvrpc.c */ +int dcc_r_cwd(int ifd, char **cwd); + +/* remote.c */ +int dcc_send_job_corked(int net_fd, + char **argv, + pid_t cpp_pid, + int *status, + const char *, + const char *cpp_fname, + struct dcc_hostdef *); + +int dcc_retrieve_results(int net_fd, + int *status, + const char *output_fname, + const char *deps_fname, + const char *server_stderr_fname, + struct dcc_hostdef *); + +/* climasq.c */ +int dcc_support_masquerade(char *argv[], char *progname, int *); + + +/* backoff.c */ +int dcc_enjoyed_host(const struct dcc_hostdef *host); +int dcc_disliked_host(const struct dcc_hostdef *host); +int dcc_remove_disliked(struct dcc_hostdef **hostlist); + + + +#define DISTCC_DEFAULT_PORT 3632 +#define DISTCC_DEFAULT_STATS_ENABLED 0 +#define DISTCC_DEFAULT_STATS_PORT 3633 + + + +#ifndef WAIT_ANY +# define WAIT_ANY (-1) +#endif + + +/* If --enable-rfc2553 was given, then we will try to enable compile-time IPv6 + * support. This means we must have a sockaddr_storage large enough to hold + * IPv6 addresses. If not, we'll just use a plain sockaddr, which is more + * likely to compile correctly. */ +#ifdef ENABLE_RFC2553 +# ifndef HAVE_SOCKADDR_STORAGE +# error You can't use RFC2553 because you don't have a sockaddr_storage type +# endif /* HAVE_SOCKADDR_STORAGE */ +# define dcc_sockaddr_storage sockaddr_storage +#else /* !ENABLE_RFC2553 */ +# define dcc_sockaddr_storage sockaddr +#endif /* !ENABLE_RFC2553 */ + +#ifndef O_BINARY +# define O_BINARY 0 +#endif + + +void dcc_set_trace_from_env(void); + + +/* compress.c */ +int dcc_r_bulk_lzo1x(int outf_fd, + int in_fd, + unsigned in_len); + + + +int dcc_compress_file_lzo1x(int in_fd, + size_t in_len, + char **out_buf, + size_t *out_len); + +int dcc_compress_lzo1x_alloc(const char *in_buf, + size_t in_len, + char **out_buf_ret, + size_t *out_len_ret); + + + +/* bulk.h */ +void dcc_calc_rate(off_t size_out, + struct timeval *before, + struct timeval *after, + double *secs, + double *rate); + +/* arg.c */ +int dcc_set_action_opt(char **, const char *); +int dcc_set_output(char **, char *); +int dcc_set_input(char **, char *); +int dcc_scan_args(char *argv[], /*@out@*/ /*@relnull@*/ char **orig_o, + char **orig_i, char ***ret_newargv); + +/* argutil.c */ +unsigned int dcc_argv_len(char **a); +int dcc_argv_search(char **a, const char *); +int dcc_copy_argv(char **argv, char ***out_argv, int extra_args); +int dcc_argv_append(char **argv, char *toadd); +char *dcc_argv_tostr(char **a); +void dcc_free_argv(char **argv); + +/* tempfile.c */ +int dcc_get_tempdir(const char **); +int dcc_make_tmpnam(const char *, const char *suffix, char **); +int dcc_get_new_tmpdir(char **tmpdir); +int dcc_mk_tmpdir(const char *path); +int dcc_mkdir(const char *path); + +int dcc_get_lock_dir(char **path_ret) WARN_UNUSED; +int dcc_get_state_dir(char **path_ret) WARN_UNUSED; +int dcc_get_top_dir(char **path_ret) WARN_UNUSED; +int dcc_get_tmp_top(const char **p_ret) WARN_UNUSED; + +int dcc_mk_tmp_ancestor_dirs(const char* file); + +/* cleanup.c */ +void dcc_cleanup_tempfiles(void); +void dcc_cleanup_tempfiles_from_signal_handler(void); +int dcc_add_cleanup(const char *filename) WARN_UNUSED; + +/* strip.c */ +int dcc_strip_local_args(char **from, char ***out_argv); +int dcc_strip_dasho(char **from, char ***out_argv); + +/* cpp.c */ +int dcc_cpp_maybe(char **argv, char *input_fname, char **cpp_fname, + pid_t *cpp_pid); + +/* filename.c */ +int dcc_is_source(const char *sfile); +int dcc_is_preprocessed(const char *sfile); +int dcc_is_object(const char *filename); +int dcc_source_needs_local(const char *); + +char * dcc_find_extension(char *sfile); +int dcc_output_from_source(const char *sfile, const char *out_extn, + char **ofile); + +const char * dcc_preproc_exten(const char *e); +const char * dcc_find_basename(const char *sfile); +void dcc_truncate_to_dirname(char *file); + + +/* io.c */ + +int dcc_writex(int fd, const void *buf, size_t len); + +int dcc_r_token(int ifd, char *token); + +int dcc_readx(int fd, void *buf, size_t len); +int dcc_pump_sendfile(int ofd, int ifd, size_t n); +int dcc_r_str_alloc(int fd, unsigned len, char **buf); + +int tcp_cork_sock(int fd, int corked); +int dcc_close(int fd); +int dcc_want_mmap(void); + + +int dcc_select_for_write(int fd, int timeout); +int dcc_select_for_read(int fd, int timeout); + +/* loadfile.c */ +int dcc_load_file_string(const char *filename, + char **retbuf); + + +extern const int dcc_connect_timeout, dcc_io_timeout; + + +/* pump.c */ +int dcc_r_bulk(int ofd, + int ifd, + unsigned f_size, + enum dcc_compress compression); + +int dcc_pump_readwrite(int ofd, int ifd, size_t n); + +/* mapfile.c */ +int dcc_map_input_file(int in_fd, off_t in_size, char **buf_ret); + +/* XXX: Kind of kludgy, we should do dynamic allocation. But this will do for + * now. */ +#ifndef MAXPATHLEN +#define MAXPATHLEN 4096 +#endif + + +#ifndef WCOREDUMP +# define WCOREDUMP(status) 0 +#endif diff --git a/distcc/src/dopt.c b/distcc/src/dopt.c new file mode 100644 index 0000000..ed89771 --- /dev/null +++ b/distcc/src/dopt.c @@ -0,0 +1,278 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +/* dopt.c -- Parse and apply server options. */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <popt.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "types.h" +#include "distcc.h" +#include "trace.h" +#include "dopt.h" +#include "exitcode.h" +#include "daemon.h" +#include "access.h" +#include "exec.h" + +int opt_niceness = 5; /* default */ + +/** + * Number of children running jobs on this machine. If zero (recommended), + * then dynamically set from the number of CPUs. + **/ +int arg_max_jobs = 0; + +int arg_port = DISTCC_DEFAULT_PORT; +int arg_stats = DISTCC_DEFAULT_STATS_ENABLED; +int arg_stats_port = DISTCC_DEFAULT_STATS_PORT; + +/** If true, serve all requests directly from listening process + without forking. Better for debugging. **/ +int opt_no_fork = 0; + +int opt_daemon_mode = 0; +int opt_inetd_mode = 0; +int opt_no_fifo = 0; + +/** If non-NULL, listen on only this address. **/ +char *opt_listen_addr = NULL; + +struct dcc_allow_list *opt_allowed = NULL; + +/** + * If true, don't detach from the parent. This is probably necessary + * for use with daemontools or other monitoring programs, and is also + * used by the test suite. + **/ +int opt_no_detach = 0; + +int opt_log_stderr = 0; + +int opt_log_level_num = RS_LOG_NOTICE; + +/** + * Daemon exits after this many seconds. Intended mainly for testing, to make + * sure daemons don't persist for too long. + */ +int opt_lifetime = 0; + +const char *arg_pid_file = NULL; +const char *arg_log_file = NULL; + +int opt_job_lifetime = 0; + +/* Enumeration values for options that don't have single-letter name. These + * must be numerically above all the ascii letters. */ +enum { + opt_log_to_file = 300, + opt_log_level +}; + + +const struct poptOption options[] = { + { "allow", 'a', POPT_ARG_STRING, 0, 'a', 0, 0 }, + { "jobs", 'j', POPT_ARG_INT, &arg_max_jobs, 'j', 0, 0 }, + { "daemon", 0, POPT_ARG_NONE, &opt_daemon_mode, 0, 0, 0 }, + { "help", 0, POPT_ARG_NONE, 0, '?', 0, 0 }, + { "inetd", 0, POPT_ARG_NONE, &opt_inetd_mode, 0, 0, 0 }, + { "lifetime", 0, POPT_ARG_INT, &opt_lifetime, 0, 0, 0 }, + { "listen", 0, POPT_ARG_STRING, &opt_listen_addr, 0, 0, 0 }, + { "log-file", 0, POPT_ARG_STRING, &arg_log_file, 0, 0, 0 }, + { "log-level", 0, POPT_ARG_STRING, 0, opt_log_level, 0, 0 }, + { "log-stderr", 0, POPT_ARG_NONE, &opt_log_stderr, 0, 0, 0 }, + { "job-lifetime", 0, POPT_ARG_INT, &opt_job_lifetime, 'l', 0, 0 }, + { "nice", 'N', POPT_ARG_INT, &opt_niceness, 0, 0, 0 }, + { "no-detach", 0, POPT_ARG_NONE, &opt_no_detach, 0, 0, 0 }, + { "no-fifo", 0, POPT_ARG_NONE, &opt_no_fifo, 0, 0, 0 }, + { "no-fork", 0, POPT_ARG_NONE, &opt_no_fork, 0, 0, 0 }, + { "pid-file", 'P', POPT_ARG_STRING, &arg_pid_file, 0, 0, 0 }, + { "port", 'p', POPT_ARG_INT, &arg_port, 0, 0, 0 }, + { "user", 0, POPT_ARG_STRING, &opt_user, 'u', 0, 0 }, + { "verbose", 0, POPT_ARG_NONE, 0, 'v', 0, 0 }, + { "version", 0, POPT_ARG_NONE, 0, 'V', 0, 0 }, + { "wizard", 'W', POPT_ARG_NONE, 0, 'W', 0, 0 }, + { "stats", 0, POPT_ARG_NONE, &arg_stats, 0, 0, 0 }, + { "stats-port", 0, POPT_ARG_INT, &arg_stats_port, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 } +}; + + +static void distccd_show_usage(void) +{ + dcc_show_version("distccd"); + printf ( +"Usage:\n" +" distccd [OPTIONS]\n" +"\n" +"Options:\n" +" --help explain usage and exit\n" +" --version show version and exit\n" +" -P, --pid-file FILE save daemon process id to file\n" +" -N, --nice LEVEL lower priority, 20=most nice\n" +" --user USER if run by root, change to this persona\n" +" --jobs, -j LIMIT maximum tasks at any time\n" +" --job-lifetime SECONDS maximum lifetime of a compile request\n" +" Networking:\n" +" -p, --port PORT TCP port to listen on\n" +" --listen ADDRESS IP address to listen on\n" +" -a, --allow IP[/BITS] client address access control\n" +" --stats enable statistics reporting via HTTP server\n" +" --stats-port PORT TCP port to listen on for statistics requests\n" +" Debug and trace:\n" +" --log-level=LEVEL set detail level for log file\n" +" levels: critical, error, warning, notice, info, debug\n" +" --verbose set log level to \"debug\"\n" +" --no-detach don't detach from parent (for daemontools, etc)\n" +" --log-file=FILE send messages here instead of syslog\n" +" --log-stderr send messages to stderr\n" +" --wizard for running under gdb\n" +" Mode of operation:\n" +" --inetd serve client connected to stdin\n" +" --daemon bind and listen on socket\n" +"\n" +"distccd runs either from inetd or as a standalone daemon to compile\n" +"files submitted by the distcc client.\n" +"\n" +"distccd should only run on trusted networks.\n" +); +} + + +int distccd_parse_options(int argc, const char **argv) +{ + poptContext po; + int po_err, exitcode; + + po = poptGetContext("distccd", argc, argv, options, 0); + + while ((po_err = poptGetNextOpt(po)) != -1) { + switch (po_err) { + case '?': + distccd_show_usage(); + exitcode = 0; + goto out_exit; + + case 'a': { + /* TODO: Allow this to be a hostname, which is resolved to an address. */ + /* TODO: Split this into a small function. */ + struct dcc_allow_list *new; + new = malloc(sizeof *new); + if (!new) { + rs_log_crit("malloc failed"); + exitcode = EXIT_OUT_OF_MEMORY; + goto out_exit; + } + new->next = opt_allowed; + opt_allowed = new; + if ((exitcode = dcc_parse_mask(poptGetOptArg(po), &new->addr, &new->mask))) + goto out_exit; + } + break; + + case 'j': + if (arg_max_jobs < 1 || arg_max_jobs > 200) { + rs_log_error("--jobs argument must be between 1 and 200"); + exitcode = EXIT_BAD_ARGUMENTS; + goto out_exit; + } + break; + + case 'l': + if (opt_job_lifetime < 0) { + opt_job_lifetime = 0; + } + dcc_job_lifetime = opt_job_lifetime; + break; + + case 'u': + if (getuid() != 0 && geteuid() != 0) { + rs_log_warning("--user is ignored when distccd is not run by root"); + /* continue */ + } + break; + + case 'V': + dcc_show_version("distccd"); + exitcode = EXIT_SUCCESS; + goto out_exit; + + case opt_log_level: + { + int level; + const char *level_name; + + level_name = poptGetOptArg(po); + level = rs_loglevel_from_name(level_name); + if (level == -1) { + rs_log_warning("invalid --log-level argument \"%s\"", + level_name); + } else { + rs_trace_set_level(level); + opt_log_level_num = level; + } + } + break; + + case 'v': + rs_trace_set_level(RS_LOG_DEBUG); + opt_log_level_num = RS_LOG_DEBUG; + break; + + case 'W': + /* catchall for running under gdb */ + opt_log_stderr = 1; + opt_daemon_mode = 1; + opt_no_detach = 1; + opt_no_fork = 1; + opt_no_fifo = 1; + rs_trace_set_level(RS_LOG_DEBUG); + break; + + default: /* bad? */ + rs_log(RS_LOG_NONAME|RS_LOG_ERR|RS_LOG_NO_PID, "%s: %s", + poptBadOption(po, POPT_BADOPTION_NOALIAS), + poptStrerror(po_err)); + exitcode = EXIT_BAD_ARGUMENTS; + goto out_exit; + } + } + + poptFreeContext(po); + return 0; + + out_exit: + poptFreeContext(po); + exit(exitcode); +} diff --git a/distcc/src/dopt.h b/distcc/src/dopt.h new file mode 100644 index 0000000..21cf1ea --- /dev/null +++ b/distcc/src/dopt.h @@ -0,0 +1,44 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +/* dopt.c */ +extern struct dcc_allow_list *opt_allowed; +int distccd_parse_options(int argc, const char *argv[]); + +extern int arg_port; +extern int arg_stats; +extern int arg_stats_port; +extern int opt_log_level_num; +extern int arg_max_jobs; +extern const char *arg_pid_file; +extern int opt_no_fork; +extern int opt_no_prefork; +extern int opt_no_detach; +extern int opt_daemon_mode, opt_inetd_mode; +extern int opt_job_lifetime; +extern const char *arg_log_file; +extern int opt_no_fifo; +extern int opt_log_stderr; +extern int opt_lifetime; +extern char *opt_listen_addr; +extern int opt_niceness; diff --git a/distcc/src/dotd.c b/distcc/src/dotd.c new file mode 100644 index 0000000..2115084 --- /dev/null +++ b/distcc/src/dotd.c @@ -0,0 +1,251 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "distcc.h" +#include "exitcode.h" +#include "dotd.h" + +/* The dotd file is compiler generated, + * so it should not have lines with more than + * twice the length of the maximum path length. + */ +#define MAX_DOTD_LINE_LEN (MAXPATHLEN * 2) + +/* Replaces the first occurrence of needle in haystack with + new_needle. haystack must be of at least hay_size, + and hay_size must be large enough to hold the string + after the replacement. + new_needle should not overlap with the haystack. + Returns 0 if all goes well, 1 otherwise. +*/ +static int dcc_strgraft(char *haystack, size_t hay_size, + const char *needle, const char *new_needle) +{ + char *found; + size_t needle_len = 0; + size_t new_needle_len = 0; + + found = strstr(haystack, needle); + if (found == NULL) + return 0; + + needle_len = strlen(needle); + new_needle_len = strlen(new_needle); + + if (strlen(haystack) - needle_len + new_needle_len + 1 > hay_size) + return 1; + + /* make some room in the haystack for the new needle */ + memmove(found + new_needle_len, + found + needle_len, + strlen(found + needle_len) + 1); + memcpy(found, new_needle, new_needle_len); + + return 0; +} + +/* Given the name of a dotd file, and the name of the directory + * masquerading as root, write a @p new_dotd file that + * contains everything in dotd, but with the "root" directory removed. + * It will also substitute client_out_name for server_out_name, + * rewriting the dependency target. + */ +int dcc_cleanup_dotd(const char *dotd_fname, + char **new_dotd_fname, + const char *root_dir, + const char *client_out_name, + const char *server_out_name) +{ + // When we do the substitution of server-side output name to + // client-side output name, we may end up with a line that + // longer than the longest line we expect from the compiler. + char buf[2 * MAX_DOTD_LINE_LEN]; + + FILE *dotd, *tmp_dotd; + char *found; + int ret; + + dotd = fopen(dotd_fname, "r"); + if (dotd == NULL) { + return 1; + } + ret = dcc_make_tmpnam(dcc_find_basename(dotd_fname), + ".d", new_dotd_fname); + + if (ret) { + fclose(dotd); + return ret; + } + + tmp_dotd = fopen(*new_dotd_fname, "w"); + if ((tmp_dotd == NULL)) { + fclose(dotd); + return 1; + } + + while (fgets(buf, MAX_DOTD_LINE_LEN, dotd)) { + if ((strchr(buf, '\n') == NULL) && !feof(dotd)) { + /* Line length must have exceeded MAX_DOTD_LINE_LEN: bail out. */ + fclose(dotd); + fclose(tmp_dotd); + return 1; + } + + /* First, the dependency target substitution */ + if (dcc_strgraft(buf, sizeof(buf), + server_out_name, client_out_name)) { + fclose(dotd); + fclose(tmp_dotd); + return 1; + } + + /* Second, the trimming of the "root" directory" */ + found = strstr(buf, root_dir); + while (found) { + char *rest_of_buf = found + strlen(root_dir); + memmove(found, rest_of_buf, strlen(rest_of_buf) + 1); + found = strstr(found, root_dir); + } + if (fprintf(tmp_dotd, "%s", buf) < 0) { + fclose(dotd); + fclose(tmp_dotd); + return 1; + } + } + if (ferror(dotd) || ferror(tmp_dotd)) { + return 1; + } + fclose(dotd); + if (fclose(tmp_dotd) < 0) { + return 1; + } + return 0; +} + +/* Go through arguments (in @p argv), and relevant environment variables, and + * find out where the dependencies output should go. Return that location in a + * newly allocated string in @p dotd_fname. @p needs_dotd is set to true if the + * compilation command line and environent imply that a .d file must be + * produced. @p sets_dotd_target is set to true if there is a -MQ or -MT + * option. This is to be used on the client, so that the client knows where to + * put the .d file it gets from the server. @p dotd_target is set only if + * @needs_dotd is true and @sets_dotd_target is false and the target is given in + * the DEPENDENCIES_OUTPUT environment variable. + * + * Note: -M is not handled here, because this option implies -E. + * + * TODO(manos): it does not support SUNPRO_DEPENDENCIES. + */ +int dcc_get_dotd_info(char **argv, char **dotd_fname, + int *needs_dotd, int *sets_dotd_target, + char **dotd_target) +{ + char *deps_output = 0; + + char *input_file; + char *output_file; + char **new_args; // will throw this away + int has_dash_o = 0; + char *env_var = 0; + int ret; + int i; + char *a; + + *needs_dotd = 0; + *sets_dotd_target = 0; + *dotd_target = NULL; + + env_var = getenv("DEPENDENCIES_OUTPUT"); + + if (env_var != NULL) { + *needs_dotd = 1; + } + + for (i = 0; (a = argv[i]); i++) { + if (strcmp(a, "-MT") == 0) { + *sets_dotd_target = 1; + ++i; + continue; + } + if (strcmp(a, "-MQ") == 0) { + *sets_dotd_target = 1; + ++i; + continue; + } + // Catch-all for all -MD, -MMD, etc, options. + // -MQ and -MT do not imply a deps file is expected. + if (strncmp(a, "-M", 2) == 0) { + *needs_dotd = 1; + } + if (strcmp(a, "-MF") == 0) { + ++i; + deps_output = argv[i]; + } else if (strcmp(a, "-o") == 0) { + has_dash_o = 1; + } + } + + if (deps_output) { + *dotd_fname = strdup(deps_output); + if (*dotd_fname == NULL) { + return EXIT_OUT_OF_MEMORY; + } else { + return 0; + } + } + + /* ok, so there is no explicit setting of the deps filename. */ + deps_output = env_var; + if (deps_output) { + char *space; + *dotd_fname = strdup(deps_output); + if (*dotd_fname == NULL) { + return EXIT_OUT_OF_MEMORY; + } + space = strchr(*dotd_fname, ' '); + if (space != NULL) { + *space = '\0'; + *dotd_target = space + 1; + } + + return 0; + } + + /* and it's not set explicitly in the variable */ + + { /* Call dcc_scan_args to find the input/output files in order to calculate + a name for the .d file.*/ + + char *extension; + char *tmp_dotd_fname; + ret = dcc_scan_args(argv, &input_file, &output_file, &new_args); + /* if .o is set, just append .d. + * otherwise, take the basename of the input, and set the suffix to .d */ + if (has_dash_o) + tmp_dotd_fname = strdup(output_file); + else + tmp_dotd_fname = strdup(input_file); + if (tmp_dotd_fname == NULL) return EXIT_OUT_OF_MEMORY; + extension = dcc_find_extension(tmp_dotd_fname); + /* Whether derived from input or output filename, we peel the extension + off (if it exists). */ + if (extension) { + /* dcc_find_extension guarantees that there is space for 'd'. */ + extension[1] = 'd'; + extension[2] = '\0'; + *dotd_fname = tmp_dotd_fname; + } + else { /* There is no extension (or name ends with a "."). */ + if (tmp_dotd_fname[strlen(tmp_dotd_fname) - 1] == '.') + asprintf(dotd_fname, "%s%s", tmp_dotd_fname, "d"); + else + asprintf(dotd_fname, "%s%s", tmp_dotd_fname, ".d"); + if (*dotd_fname == NULL) { + return EXIT_OUT_OF_MEMORY; + } + free(tmp_dotd_fname); + } + return 0; + } +} diff --git a/distcc/src/dotd.h b/distcc/src/dotd.h new file mode 100755 index 0000000..c476ea5 --- /dev/null +++ b/distcc/src/dotd.h @@ -0,0 +1,9 @@ +int dcc_cleanup_dotd(const char *dotd_fname, + char **new_dotd_fname, + const char *root_dir, + const char *client_out_name, + const char *server_out_name); + +int dcc_get_dotd_info(char **argv, char **dotd_fname, + int *needs_dotd, int *sets_dotd_target, + char **dotd_target); diff --git a/distcc/src/dparent.c b/distcc/src/dparent.c new file mode 100644 index 0000000..d026757 --- /dev/null +++ b/distcc/src/dparent.c @@ -0,0 +1,353 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + /* Near is thy forgetfulness of all things; and near the + * forgetfulness of thee by all. + * -- Marcus Aurelius + */ + + +/** + * @file + * + * Daemon parent. Accepts connections, forks, etc. + * + * @todo Quite soon we need load management. Basically when we think + * we're "too busy" we should stop accepting connections. This could + * be because of the load average, or because too many jobs are + * running, or perhaps just because of a signal from the administrator + * of this machine. In that case we want to do a blocking wait() to + * find out when the current jobs are done, or perhaps a sleep() if + * we're waiting for the load average to go back down. However, we + * probably ought to always keep at least one job running so that we + * can make progress through the queue. If you don't want any work + * done, you should kill the daemon altogether. + **/ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <syslog.h> +#include <signal.h> +#include <fcntl.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include "exitcode.h" +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "dopt.h" +#include "exec.h" +#include "srvnet.h" +#include "types.h" +#include "daemon.h" +#include "netutil.h" + +static void dcc_nofork_parent(int listen_fd) NORETURN; +static void dcc_detach(void); +static void dcc_save_pid(pid_t); +int dcc_nkids = 0; + + +/** + * In forking or prefork mode, the maximum number of connections we want to + * allow at any time. + **/ +int dcc_max_kids = 0; + + +/** + * Be a standalone server, with responsibility for sockets and forking + * children. Puts the daemon in the background and detaches from the + * controlling tty. + **/ +int dcc_standalone_server(void) +{ + int listen_fd; + int n_cpus; + int ret; + + if ((ret = dcc_socket_listen(arg_port, &listen_fd, opt_listen_addr)) != 0) + return ret; + + dcc_defer_accept(listen_fd); + + set_cloexec_flag(listen_fd, 1); + + if (dcc_ncpus(&n_cpus) == 0) + rs_log_info("%d CPU%s online on this server", n_cpus, n_cpus == 1 ? "" : "s"); + + /* By default, allow one job per CPU, plus two for the pot. The extra + * ones are started to allow for a bit of extra concurrency so that the + * machine is not idle waiting for disk or network IO. */ + if (arg_max_jobs) + dcc_max_kids = arg_max_jobs; + else + dcc_max_kids = 2 + n_cpus; + + rs_log_info("allowing up to %d active jobs", dcc_max_kids); + + if (!opt_no_detach) { + /* Don't go into the background until we're listening and + * ready. This is useful for testing -- when the daemon + * detaches, we know we can go ahead and try to connect. */ + dcc_detach(); + } else { + /* Still create a new process group, even if not detached */ + rs_trace("not detaching"); + if ((ret = dcc_new_pgrp()) != 0) + return ret; + dcc_save_pid(getpid()); + } + + /* Don't catch signals until we've detached or created a process group. */ + dcc_daemon_catch_signals(); + + /* This is called in the master daemon, whether that is detached or + * not. */ + dcc_master_pid = getpid(); + + if (opt_no_fork) { + dcc_log_daemon_started("non-forking daemon"); + dcc_nofork_parent(listen_fd); + } else { + dcc_log_daemon_started("preforking daemon"); + return dcc_preforking_parent(listen_fd); + } +} + + + +static void dcc_log_child_exited(pid_t kid, + int status) +{ + if (WIFSIGNALED(status)) { + int sig = WTERMSIG(status); + int severity = sig == SIGTERM ? RS_LOG_INFO : RS_LOG_ERR; + + rs_log(severity, "child %d: signal %d (%s)", (int) kid, sig, + WCOREDUMP(status) ? "core dumped" : "no core"); + } else if (WIFEXITED(status)) { + rs_log_info("child %d exited: exit status %d", + (int) kid, WEXITSTATUS(status)); + } +} + + + +/** + * @sa dcc_wait_child(), which is used by a process that wants to do a blocking + * wait for some task like cpp or gcc. + * + * @param must_reap If True, don't return until at least one child has been + * collected. Used when e.g. all our process slots are full. In either case + * we keep going until all outstanding zombies are collected. + * + * FIXME: Are blocking waits meant to collect all of them, or just one? At + * the moment it waits until all children have exited. + **/ +void dcc_reap_kids(int must_reap) +{ + while (1) { + int status; + pid_t kid; + + kid = waitpid(WAIT_ANY, &status, must_reap ? 0 : WNOHANG); + if (kid == 0) { + /* nobody has exited */ + break; + } else if (kid != -1) { + /* child exited */ + --dcc_nkids; + rs_trace("down to %d children", dcc_nkids); + + dcc_log_child_exited(kid, status); + } else if (errno == ECHILD) { + /* No children left? That's ok, we'll go back to waiting + * for new connections. */ + break; + } else if (errno == EINTR) { + /* If we got a SIGTERM or something, then on the next pass + * through the loop we'll find no children done, and we'll + * return to the top loop at which point we'll exit. So + * no special action is required here. */ + continue; /* loop again */ + } else { + rs_log_error("wait failed: %s", strerror(errno)); + /* e.g. too many open files; nothing we can do */ + dcc_exit(EXIT_DISTCC_FAILED); + } + + /* If there are more children keep looking, but don't block once we've + * collected at least one. */ + must_reap = FALSE; + } +} + + +/** + * Main loop for no-fork mode. + * + * Much slower and may leak. Should only be used when you want to run gdb on + * distccd. + **/ +static void dcc_nofork_parent(int listen_fd) +{ + while (1) { + int acc_fd; + struct dcc_sockaddr_storage cli_addr; + socklen_t cli_len; + + rs_log_info("waiting to accept connection"); + + cli_len = sizeof cli_addr; + acc_fd = accept(listen_fd, + (struct sockaddr *) &cli_addr, &cli_len); + if (acc_fd == -1 && errno == EINTR) { + ; + } else if (acc_fd == -1) { + rs_log_error("accept failed: %s", strerror(errno)); + dcc_exit(EXIT_CONNECT_FAILED); + } else { + dcc_service_job(acc_fd, acc_fd, (struct sockaddr *) &cli_addr, cli_len); + dcc_close(acc_fd); + } + } +} + + +/** + * Save the pid of the child process into the pid file, if any. + * + * This is called from the parent so that we have the invariant that + * the pid file exists before the parent exits, hich is useful for + * test harnesses. Otherwise, there is a race where the parent has + * exited and they try to go ahead and read the child's pid, but it's + * not there yet. + **/ +static void dcc_save_pid(pid_t pid) +{ + FILE *fp; + + if (!arg_pid_file) + return; + + if (!(fp = fopen(arg_pid_file, "wt"))) { + rs_log_error("failed to open pid file: %s: %s", arg_pid_file, + strerror(errno)); + return; + } + + fprintf(fp, "%ld\n", (long) pid); + + if (fclose(fp) == -1) { + rs_log_error("failed to close pid file: %s: %s", arg_pid_file, + strerror(errno)); + return; + } + + atexit(dcc_remove_pid); +} + + +/** + * Remove our pid file on exit. + * + * Must be reentrant -- called from signal handler. + **/ +void dcc_remove_pid(void) +{ + if (!arg_pid_file) + return; + + if (unlink(arg_pid_file)) { + rs_log_warning("failed to remove pid file %s: %s", + arg_pid_file, strerror(errno)); + } +} + + +/** + * Become a daemon, discarding the controlling terminal. + * + * Borrowed from rsync. + * + * This function returns in the child, but not in the parent. + **/ +static void dcc_detach(void) +{ + int i; + pid_t pid; + pid_t sid; + + dcc_ignore_sighup(); + + if ((pid = fork()) == -1) { + rs_log_error("fork failed: %s", strerror(errno)); + exit(EXIT_DISTCC_FAILED); + } else if (pid != 0) { + /* In the parent. This guy is about to go away so as to + * detach from the controlling process, but first save the + * child's pid. */ + dcc_save_pid(pid); + _exit(0); + } + + /* This is called in the detached child */ + + /* detach from the terminal */ +#ifdef HAVE_SETSID + if ((sid = setsid()) == -1) { + rs_log_error("setsid failed: %s", strerror(errno)); + } else { + rs_trace("setsid to session %d", (int) sid); + } +#else /* no HAVE_SETSID */ +#ifdef TIOCNOTTY + i = open("/dev/tty", O_RDWR); + if (i >= 0) { + ioctl(i, (int) TIOCNOTTY, (char *)0); + close(i); + } +#endif /* TIOCNOTTY */ +#endif /* not HAVE_SETSID */ + + /* make sure that stdin, stdout an stderr don't stuff things + up (library functions, for example) */ + for (i=0;i<3;i++) { + close(i); + open("/dev/null", O_RDWR); + } + + /* If there's a lifetime limit on this server (for testing) then it needs + * to apply after detaching as well. */ + dcc_set_lifetime(); +} diff --git a/distcc/src/dsignal.c b/distcc/src/dsignal.c new file mode 100644 index 0000000..f887682 --- /dev/null +++ b/distcc/src/dsignal.c @@ -0,0 +1,138 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + /* + * A servant will not be corrected by words: for + * though he understand he will not answer. + * -- Proverbs 29:19 + */ + +/** + * @file + * @brief Daemon signal handling. + * + * Signals are handled differently in the daemon parent and its children. + * + * When the parent is killed, the entire process group is shut down, and the + * pid file (if any) is removed. + * + * For both cases any temporary files created by the process are removed. + **/ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <signal.h> + +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/socket.h> + +#include "exitcode.h" +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "dopt.h" +#include "exec.h" +#include "daemon.h" + + +/* This stores the pid of the parent daemon. It's used to make sure + * that we only run the whole-group cleanup from inside the parent. + * Remains 0 before parent initialization is complete and when run + * from inetd. */ +volatile pid_t dcc_master_pid = 0; + +static RETSIGTYPE dcc_daemon_terminate(int); + +/** + * Catch all relevant termination signals. Set up in parent and also + * applies to children. + **/ +void dcc_daemon_catch_signals(void) +{ + /* SIGALRM is caught to allow for built-in timeouts when running test + * cases. */ + + signal(SIGTERM, &dcc_daemon_terminate); + signal(SIGINT, &dcc_daemon_terminate); + signal(SIGHUP, &dcc_daemon_terminate); + signal(SIGALRM, &dcc_daemon_terminate); +} + + + +/** + * Ignore hangup signal. + * + * This is only used in detached mode to make sure the daemon does not + * quit when whoever started it closes their terminal. In nondetached + * mode, the signal is logged and causes an exit as normal. + **/ +void dcc_ignore_sighup(void) +{ + signal(SIGHUP, SIG_IGN); + + rs_trace("ignoring SIGHUP"); +} + + + +/** + * Just log, remove pidfile, and exit. + * + * Called when a daemon gets a fatal signal. + * + * Some cleanup is done only if we're the master/parent daemon. + **/ +static RETSIGTYPE dcc_daemon_terminate(int whichsig) +{ + int am_parent; + + /* Make sure to remove handler before re-raising signal */ + signal(whichsig, SIG_DFL); + + am_parent = getpid() == dcc_master_pid; + + if (am_parent) { +#ifdef HAVE_STRSIGNAL + rs_log_info("%s", strsignal(whichsig)); +#else + rs_log_info("terminated by signal %d", whichsig); +#endif + } + + dcc_cleanup_tempfiles_from_signal_handler(); + + if (am_parent) { + dcc_remove_pid(); + + /* kill whole group */ + kill(0, whichsig); + } + + raise(whichsig); +} diff --git a/distcc/src/emaillog.c b/distcc/src/emaillog.c new file mode 100644 index 0000000..91b3f4b --- /dev/null +++ b/distcc/src/emaillog.c @@ -0,0 +1,130 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> + +#include <string.h> +#include <unistd.h> + +#include "emaillog.h" +#include "distcc.h" +#include "util.h" +#include "trace.h" +#include "bulk.h" + +/* if never_send_email is true, we won't send email + even if should_send_email is true */ +static int should_send_email = 0; +static int never_send_email = 0; +static char *email_fname; +static int email_fileno = -1; +static int email_errno; + +static const char logmailer[] = "/bin/mail"; +static const char email_subject[] = "distcc-pump email" ; +static const char cant_send_message_format[] = + "Please notify %s that distcc tried to send them email but failed"; +static const char will_send_message_format[] = "Will send an email to %s"; + +static const char dcc_emaillog_whom_to_blame[] = DCC_EMAILLOG_WHOM_TO_BLAME; + +void dcc_please_send_email(void) { + should_send_email = 1; +} + +void dcc_setup_log_email(void) { + never_send_email = !dcc_getenv_bool("DISTCC_ENABLE_DISCREPANCY_EMAIL", 0); + if (never_send_email) + return; + + /* email_fname lives until the program exits. + The file itself will eventually get unlinked by dcc_cleanup_tempfiles(), + but email_fileno survives until after we send email, so the file won't + get removed until the emailing (child) process is done. + */ + + dcc_make_tmpnam("distcc_error_log", "txt", &email_fname); + + email_fileno = open(email_fname, O_RDWR | O_TRUNC); + if (email_fileno >= 0) { + rs_add_logger(rs_logger_file, RS_LOG_DEBUG, NULL, email_fileno); + rs_trace_set_level(RS_LOG_DEBUG); + } else { + email_errno = errno; + } +} + +int dcc_add_file_to_log_email(const char *description, + const char *fname) { + char begin[] = "\nBEGIN "; + char end[] = "\nEND "; + int in_fd = 0; + off_t fsize; + + if (never_send_email) return 0; + + if (dcc_open_read(fname, &in_fd, &fsize)) + return 1; + + write(email_fileno, begin, strlen(begin)); + write(email_fileno, description, strlen(description)); + write(email_fileno, "\n", 1); + + dcc_pump_readwrite(email_fileno, in_fd, fsize); + + write(email_fileno, end, strlen(end)); + write(email_fileno, description, strlen(description)); + write(email_fileno, "\n", 1); + + close(in_fd); + + return 0; +} + +void dcc_maybe_send_email(void) { + int child_pid = 0; + const char *whom_to_blame; + if ((whom_to_blame = getenv("DISTCC_EMAILLOG_WHOM_TO_BLAME")) + != NULL) { + whom_to_blame = dcc_emaillog_whom_to_blame; + } + char *will_send_message_to; + char *cant_send_message_to; + + if (should_send_email == 0) return; + if (never_send_email) return; + + asprintf(&will_send_message_to, will_send_message_format, whom_to_blame); + asprintf(&cant_send_message_to, cant_send_message_format, whom_to_blame); + + rs_log_warning(will_send_message_to); + free(will_send_message_to); + + if (email_fileno < 0) { + errno = email_errno; + perror(cant_send_message_to); + free(cant_send_message_to); + return; + } + + child_pid = fork(); + if (child_pid == 0) { + if (dup2(email_fileno, 0) == -1 || + lseek(email_fileno, 0, SEEK_SET) == -1 || + execl(logmailer, + logmailer, "-s", email_subject, whom_to_blame, + (char*)NULL) == -1) { + perror(cant_send_message_to); + /* The fork succeeded but we didn't get to exec, or the exec + failed. We need to exit immediately, otherwise the cleanup + code will get executed twice. + */ + _exit(1); + } + } else if (child_pid < 0) { + perror(cant_send_message_to); + } + free(cant_send_message_to); +} diff --git a/distcc/src/emaillog.h b/distcc/src/emaillog.h new file mode 100644 index 0000000..c94fc6f --- /dev/null +++ b/distcc/src/emaillog.h @@ -0,0 +1,11 @@ +#ifndef DCC_EMAILLOG_H +#define DCC_EMAILLOG_H + +/* See also include_server/basics.py */ +#define DCC_EMAILLOG_WHOM_TO_BLAME "distcc-pump-errors" +void dcc_please_send_email(void); +void dcc_setup_log_email(void); +void dcc_maybe_send_email(void); +int dcc_add_file_to_log_email(const char *description, const char *fname); + +#endif /* EMAILLOG_H */ diff --git a/distcc/src/exec.c b/distcc/src/exec.c new file mode 100644 index 0000000..460c067 --- /dev/null +++ b/distcc/src/exec.c @@ -0,0 +1,459 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + /* 18 Their bows also shall dash the young men + * to pieces; and they shall have no pity on + * the fruit of the womb; their eyes shall not + * spare children. + * -- Isaiah 13 */ + +/** + * @file + * + * Run compilers or preprocessors. + * + * The whole server is run in a separate process group and normally in a + * separate session. (It is not a separate session in --no-detach debug + * mode.) This allows us to cleanly kill off all children and all compilers + * when the parent is terminated. + * + * @todo On Cygwin, fork() must be emulated and therefore will be + * slow. It would be faster to just use their spawn() call, rather + * than fork/exec. + **/ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> + +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/poll.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "exitcode.h" +#include "exec.h" +#include "lock.h" +#include "hosts.h" +#include "dopt.h" + +const int timeout_null_fd = -1; +int dcc_job_lifetime = 0; + +static void dcc_inside_child(char **argv, + const char *stdin_file, + const char *stdout_file, + const char *stderr_file) NORETURN; + + +static void dcc_execvp(char **argv) NORETURN; + +void dcc_note_execution(struct dcc_hostdef *host, char **argv) +{ + char *astr; + + astr = dcc_argv_tostr(argv); + rs_log(RS_LOG_INFO|RS_LOG_NONAME, "exec on %s: %s", + host->hostdef_string, astr); + free(astr); +} + + +/** + * Redirect stdin/out/err. Filenames may be NULL to leave them untouched. + * + * This is called when running a job remotely, but *not* when running + * it locally, because people might e.g. want cpp to read from stdin. + **/ +int dcc_redirect_fds(const char *stdin_file, + const char *stdout_file, + const char *stderr_file) +{ + int ret; + + if (stdin_file) + if ((ret = dcc_redirect_fd(STDIN_FILENO, stdin_file, O_RDONLY))) + return ret; + + if (stdout_file) { + if ((ret = dcc_redirect_fd(STDOUT_FILENO, stdout_file, + O_WRONLY | O_CREAT | O_TRUNC))) + return ret; + } + + if (stderr_file) { + /* Open in append mode, because the server will dump its own error + * messages into the compiler's error file. */ + if ((ret = dcc_redirect_fd(STDERR_FILENO, stderr_file, + O_WRONLY | O_CREAT | O_APPEND))) + return ret; + } + + return 0; +} + + +/** + * Replace this program with another in the same process. + * + * Does not return, either execs the compiler in place, or exits with + * a message. + **/ +static void dcc_execvp(char **argv) +{ + char *slash; + + execvp(argv[0], argv); + + /* If we're still running, the program was not found on the path. One + * thing that might have happened here is that the client sent an absolute + * compiler path, but the compiler's located somewhere else on the server. + * In the absence of anything better to do, we search the path for its + * basename. + * + * Actually this code is called on both the client and server, which might + * cause unintnded behaviour in contrived cases, like giving a full path + * to a file that doesn't exist. I don't think that's a problem. */ + + slash = strrchr(argv[0], '/'); + if (slash) + execvp(slash + 1, argv); + + /* shouldn't be reached */ + rs_log_error("failed to exec %s: %s", argv[0], strerror(errno)); + + dcc_exit(EXIT_COMPILER_MISSING); /* a generalization, i know */ +} + + + +/** + * Called inside the newly-spawned child process to execute a command. + * Either executes it, or returns an appropriate error. + * + * This routine also takes a lock on localhost so that it's counted + * against the process load. That lock will go away when the process + * exits. + * + * In this current version locks are taken without regard to load limitation + * on the current machine. The main impact of this is that cpp running on + * localhost will cause jobs to be preferentially distributed away from + * localhost, but it should never cause the machine to deadlock waiting for + * localhost slots. + * + * @param what Type of process to be run here (cpp, cc, ...) + **/ +static void dcc_inside_child(char **argv, + const char *stdin_file, + const char *stdout_file, + const char *stderr_file) +{ + int ret; + + if ((ret = dcc_ignore_sigpipe(0))) + goto fail; /* set handler back to default */ + + /* Ignore failure */ + dcc_increment_safeguard(); + + /* do this last, so that any errors from previous operations are + * visible */ + if ((ret = dcc_redirect_fds(stdin_file, stdout_file, stderr_file))) + goto fail; + + dcc_execvp(argv); + + ret = EXIT_DISTCC_FAILED; + + fail: + dcc_exit(ret); +} + + +int dcc_new_pgrp(void) +{ + /* If we're a session group leader, then we are not able to call + * setpgid(). However, setsid will implicitly have put us into a new + * process group, so we don't have to do anything. */ + + /* Does everyone have getpgrp()? It's in POSIX.1. We used to call + * getpgid(0), but that is not available on BSD/OS. */ + if (getpgrp() == getpid()) { + rs_trace("already a process group leader"); + return 0; + } + + if (setpgid(0, 0) == 0) { + rs_trace("entered process group"); + return 0; + } else { + rs_trace("setpgid(0, 0) failed: %s", strerror(errno)); + return EXIT_DISTCC_FAILED; + } +} + + +/** + * Run @p argv in a child asynchronously. + * + * stdin, stdout and stderr are redirected as shown, unless those + * filenames are NULL. In that case they are left alone. + * + * @warning When called on the daemon, where stdin/stdout may refer to random + * network sockets, all of the standard file descriptors must be redirected! + **/ +int dcc_spawn_child(char **argv, pid_t *pidptr, + const char *stdin_file, + const char *stdout_file, + const char *stderr_file) +{ + pid_t pid; + + dcc_trace_argv("forking to execute", argv); + + pid = fork(); + if (pid == -1) { + rs_log_error("failed to fork: %s", strerror(errno)); + return EXIT_OUT_OF_MEMORY; /* probably */ + } else if (pid == 0) { + /* If this is a remote compile, + * put the child in a new group, so we can + * kill it and all its descendents without killing distccd + * FIXME: if you kill distccd while it's compiling, and + * the compiler has an infinite loop bug, the new group + * will run forever until you kill it. + */ + if (stdout_file != NULL) { + if (dcc_new_pgrp() != 0) + rs_trace("Unable to start a new group\n"); + } + dcc_inside_child(argv, stdin_file, stdout_file, stderr_file); + /* !! NEVER RETURN FROM HERE !! */ + } else { + *pidptr = pid; + rs_trace("child started as pid%d", (int) pid); + return 0; + } +} + + +void dcc_reset_signal(int whichsig) +{ + struct sigaction act_dfl; + + memset(&act_dfl, 0, sizeof act_dfl); + act_dfl.sa_handler = SIG_DFL; + sigaction(whichsig, &act_dfl, NULL); + /* might be called from signal handler, therefore no IO to log a + * message */ +} + + +static int sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) +{ + + /* Prefer use waitpid to wait4 for non-blocking wait with WNOHANG option */ +#ifdef HAVE_WAITPID + /* Just doing getrusage(children) is not sufficient, because other + * children may have exited previously. */ + memset(rusage, 0, sizeof *rusage); + return waitpid(pid, status, options); +#elif HAVE_WAIT4 + return wait4(pid, status, options, rusage); +#else +#error Please port this +#endif +} + + +/** + * Blocking wait for a child to exit. This is used when waiting for + * cpp, gcc, etc. + * + * This is not used by the daemon-parent; it has its own + * implementation in dcc_reap_kids(). They could be unified, but the + * parent only waits when it thinks a child has exited; the child + * waits all the time. + **/ +int dcc_collect_child(const char *what, pid_t pid, + int *wait_status, int in_fd) +{ + struct rusage ru; + pid_t ret_pid; + + int ret; + int wait_timeout_sec; + fd_set fds,readfds; + + wait_timeout_sec = dcc_job_lifetime; + + FD_ZERO(&readfds); + if (in_fd != timeout_null_fd){ + FD_SET(in_fd,&readfds); + } + + + while (!dcc_job_lifetime || wait_timeout_sec-- >= 0) { + + /* If we're called with a socket, break out of the loop if the socket disconnects. + * To do that, we need to block in select, not in sys_wait4. + * (Only waitpid uses WNOHANG to mean don't block ever, so I've modified + * sys_wait4 above to preferentially call waitpid.) + */ + int flags = (in_fd == timeout_null_fd) ? 0 : WNOHANG; + ret_pid = sys_wait4(pid, wait_status, flags, &ru); + + if (ret_pid == -1) { + if (errno == EINTR) { + rs_trace("wait4 was interrupted; retrying"); + } else { + rs_log_error("sys_wait4(pid=%d) borked: %s", (int) pid, strerror(errno)); + return EXIT_DISTCC_FAILED; + } + } else if (ret_pid != 0) { + /* This is not the main user-visible message; that comes from + * critique_status(). */ + rs_trace("%s child %ld terminated with status %#x", + what, (long) ret_pid, *wait_status); + rs_log_info("%s times: user %ld.%06lds, system %ld.%06lds, " + "%ld minflt, %ld majflt", + what, + ru.ru_utime.tv_sec, ru.ru_utime.tv_usec, + ru.ru_stime.tv_sec, ru.ru_stime.tv_usec, + ru.ru_minflt, ru.ru_majflt); + + return 0; + } + + /* check timeout */ + if (in_fd != timeout_null_fd){ + struct timeval timeout; + + /* If client disconnects, the socket will become readable, + * and a read should return -1 and set errno to EPIPE. + */ + fds = readfds; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + ret = select(in_fd+1,&fds,NULL,NULL,&timeout); + if (ret == 1) { + char buf; + int nread = read(in_fd, &buf, 1); + if ((nread == -1) && (errno == EWOULDBLOCK)) { + /* spurious wakeup, ignore */ + ; + } else if (nread == 0) { + rs_log_error("Client fd disconnected, killing job"); + /* If killpg fails, it might means the child process is not + * in a new group, so, just kill the child process */ + if (killpg(pid,SIGTERM)!=0) + kill(pid, SIGTERM); + return EXIT_IO_ERROR; + } else if (nread == 1) { + rs_log_error("Bug! Read from fd succeeded when checking whether client disconnected!"); + } else + rs_log_error("Bug! nread %d, errno %d checking whether client disconnected!", nread, errno); + } + } else + poll(NULL, 0, 1000); + } + /* If timeout, also kill the child process */ + if (killpg(pid,SIGTERM) !=0 ) + kill(pid, SIGTERM); + rs_log_error("Compilation takes too long, timeout."); + + return EXIT_TIMEOUT; +} + + + +/** + * Analyze and report to the user on a command's exit code. + * + * @param command short human-readable description of the command (perhaps + * argv[0]) + * + * @returns 0 if the command succeeded; 128+SIGNAL if it stopped on a + * signal; otherwise the command's exit code. + **/ +int dcc_critique_status(int status, + const char *command, + const char *input_fname, + struct dcc_hostdef *host, + int verbose) +{ + int logmode; + + /* verbose mode is only used for executions that the user is likely to + * particularly need to know about */ + if (verbose) + logmode = RS_LOG_ERR | RS_LOG_NONAME; + else + logmode = RS_LOG_INFO | RS_LOG_NONAME; + + if (WIFSIGNALED(status)) { +#ifdef HAVE_STRSIGNAL + rs_log(logmode, + "%s %s on %s:%s %s", + command, input_fname, host->hostdef_string, + strsignal(WTERMSIG(status)), + WCOREDUMP(status) ? " (core dumped)" : ""); +#else + rs_log(logmode, + "%s %s on %s terminated by signal %d%s", + command, input_fname, host->hostdef_string, + WTERMSIG(status), + WCOREDUMP(status) ? " (core dumped)" : ""); +#endif + /* Unix convention is to return 128+signal when a subprocess crashes. */ + return 128 + WTERMSIG(status); + } else if (WEXITSTATUS(status) == 1) { + /* Normal failure gives exit code 1, so handle that specially */ + rs_log(logmode, "%s %s on %s failed", command, input_fname, host->hostdef_string); + return WEXITSTATUS(status); + } else if (WEXITSTATUS(status)) { + /* This is a tough call; we don't really want to clutter the client's + * error stream, but if we don't say where the compilation failed then + * people may find it hard to work things out. */ + + rs_log(logmode, + "%s %s on %s failed with exit code %d", + command, input_fname, host->hostdef_string, WEXITSTATUS(status)); + return WEXITSTATUS(status); + } else { + rs_log(RS_LOG_INFO|RS_LOG_NONAME, + "%s %s on %s completed ok", command, input_fname, host->hostdef_string); + return 0; + } +} diff --git a/distcc/src/exec.h b/distcc/src/exec.h new file mode 100644 index 0000000..bab48b2 --- /dev/null +++ b/distcc/src/exec.h @@ -0,0 +1,50 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* exec.c */ +extern const int timeout_null_fd; +extern int dcc_job_lifetime; + +int dcc_redirect_fds(const char *stdin_file, + const char *stdout_file, + const char *stderr_file); + +int dcc_spawn_child(char **argv, pid_t *pidptr, + const char *, const char *, const char *); + +/* if in_fd is timeout_null_fd, means this parameter is not used */ +int dcc_collect_child(const char *what, pid_t pid, + int *wait_status, int in_fd); +int dcc_critique_status(int s, + const char *, + const char *, + struct dcc_hostdef *host, + int verbose); +void dcc_note_execution(struct dcc_hostdef *host, char **argv); + +int dcc_new_pgrp(void); +void dcc_reset_signal(int whichsig); + +#ifndef W_EXITCODE +# define W_EXITCODE(exit, signal) ((exit)<<8 | (signal)) +#endif + diff --git a/distcc/src/exitcode.h b/distcc/src/exitcode.h new file mode 100644 index 0000000..29a595a --- /dev/null +++ b/distcc/src/exitcode.h @@ -0,0 +1,61 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef _DISTCC_EXITCODE_H +#define _DISTCC_EXITCODE_H + +/** + * @file + * + * Common exit codes. + **/ + +/** + * Common exit codes for both client and server. + * + * These need to be in [1,255] so that they can be used as exit() + * codes. + **/ +enum dcc_exitcode { + EXIT_DISTCC_FAILED = 100, /**< General failure */ + EXIT_BAD_ARGUMENTS = 101, + EXIT_BIND_FAILED = 102, + EXIT_CONNECT_FAILED = 103, + EXIT_COMPILER_CRASHED = 104, + EXIT_OUT_OF_MEMORY = 105, + EXIT_BAD_HOSTSPEC = 106, + EXIT_IO_ERROR = 107, + EXIT_TRUNCATED = 108, + EXIT_PROTOCOL_ERROR = 109, + EXIT_COMPILER_MISSING = 110, /**< Compiler executable not found */ + EXIT_RECURSION = 111, /**< distcc called itself */ + EXIT_SETUID_FAILED = 112, /**< Failed to discard privileges */ + EXIT_ACCESS_DENIED = 113, /**< Network access denied */ + EXIT_BUSY = 114, /**< In use by another process. */ + EXIT_NO_SUCH_FILE = 115, + EXIT_NO_HOSTS = 116, + EXIT_GONE = 117, /**< No longer relevant */ + EXIT_TIMEOUT = 118 +}; + + +#endif /* _DISTCC_EXITCODE_H */ diff --git a/distcc/src/filename.c b/distcc/src/filename.c new file mode 100644 index 0000000..bd78f69 --- /dev/null +++ b/distcc/src/filename.c @@ -0,0 +1,315 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "exitcode.h" + + + +/** + * @file + * + * Everything we know about C filenames. + * + * We need to have some heuristics about input and output filenames to + * understand command lines, because that's what cc does. + * + * @note As of 0.10, .s and .S files are never distributed, because + * they might contain '.include' pseudo-operations, which are resolved + * by the assembler. + */ + + + +/** + * Return a pointer to the extension, including the dot, or NULL. + **/ +char * dcc_find_extension(char *sfile) +{ + char *dot; + + dot = strrchr(sfile, '.'); + if (dot == NULL || dot[1] == '\0') { + /* make sure there's space for one more character after the + * dot */ + return NULL; + } + return dot; +} + + +/** + * Return a pointer to the basename of the file (everything after the + * last slash.) If there is no slash, return the whole filename, + * which is presumably in the current directory. + **/ +const char * dcc_find_basename(const char *sfile) +{ + char *slash; + + if (!sfile) + return sfile; + + slash = strrchr(sfile, '/'); + + if (slash == NULL || slash[1] == '\0') + return sfile; + + return slash+1; +} + +/** Truncate the filename to its dirname (everything before the last slash). + * If the filename ends with a slash, just lop off the last slash. + * Note: this is destructive. + */ +void dcc_truncate_to_dirname(char *file) +{ + char *slash = 0; + + slash = strrchr(file, '/'); + + if (slash == NULL) { + file[0] = '\0'; + } else { + *slash = '\0'; + } +} + + +static int dcc_set_file_extension(const char *sfile, + const char *new_ext, + char **ofile) +{ + char *dot, *o; + + o = strdup(sfile); + dot = dcc_find_extension((char *) o); + if (!dot) { + rs_log_error("couldn't find extension in \"%s\"", o); + return EXIT_DISTCC_FAILED; + } + if (strlen(dot) < strlen(new_ext)) { + rs_log_error("not enough space for new extension"); + return EXIT_DISTCC_FAILED; + } + strcpy(dot, new_ext); + *ofile = o; + + return 0; +} + + +/* + * Apple extensions: + * file.mm, file.M + * Objective-C++ source code which must be preprocessed. (APPLE ONLY) + * + * file.mii Objective-C++ source code which should not be + * preprocessed. (APPLE ONLY) + * + * http://developer.apple.com/techpubs/macosx/DeveloperTools/gcc3/gcc/Overall-Options.html + */ + + + +/** + * If you preprocessed a file with extension @p e, what would you get? + * + * @param e original extension (e.g. ".c") + * + * @returns preprocessed extension, (e.g. ".i"), or NULL if + * unrecognized. + **/ +const char * dcc_preproc_exten(const char *e) +{ + if (e[0] != '.') + return NULL; + e++; + if (!strcmp(e, "i") || !strcmp(e, "c")) { + return ".i"; + } else if (!strcmp(e, "c") || !strcmp(e, "cc") + || !strcmp(e, "cpp") || !strcmp(e, "cxx") + || !strcmp(e, "cp") || !strcmp(e, "c++") + || !strcmp(e, "C") || !strcmp(e, "ii")) { + return ".ii"; + } else if(!strcmp(e,"mi") || !strcmp(e, "m")) { + return ".mi"; + } else if(!strcmp(e,"mii") || !strcmp(e,"mm") + || !strcmp(e,"M")) { + return ".mii"; + } else if (!strcasecmp(e, "s")) { + return ".s"; + } else { + return NULL; + } +} + + +/** + * Does the extension of this file indicate that it is already + * preprocessed? + **/ +int dcc_is_preprocessed(const char *sfile) +{ + const char *dot, *ext; + dot = dcc_find_extension((char *) sfile); + if (!dot) + return 0; + ext = dot+1; + + switch (ext[0]) { +#ifdef ENABLE_REMOTE_ASSEMBLE + case 's': + /* .S needs to be run through cpp; .s does not */ + return !strcmp(ext, "s"); +#endif + case 'i': + return !strcmp(ext, "i") + || !strcmp(ext, "ii"); + case 'm': + return !strcmp(ext, "mi") + || !strcmp(ext, "mii"); + default: + return 0; + } +} + + +/** + * Work out whether @p sfile is source based on extension + **/ +int dcc_is_source(const char *sfile) +{ + const char *dot, *ext; + dot = dcc_find_extension((char *) sfile); + if (!dot) + return 0; + ext = dot+1; + + /* you could expand this out further into a RE-like set of case + * statements, but i'm not sure it's that important. */ + + switch (ext[0]) { + case 'i': + return !strcmp(ext, "i") + || !strcmp(ext, "ii"); + case 'c': + return !strcmp(ext, "c") + || !strcmp(ext, "cc") + || !strcmp(ext, "cpp") + || !strcmp(ext, "cxx") + || !strcmp(ext, "cp") + || !strcmp(ext, "c++"); + case 'C': + return !strcmp(ext, "C"); + case 'm': + return !strcmp(ext,"m") + || !strcmp(ext,"mm") + || !strcmp(ext,"mi") + || !strcmp(ext,"mii"); + case 'M': + return !strcmp(ext, "M"); +#ifdef ENABLE_REMOTE_ASSEMBLE + case 's': + return !strcmp(ext, "s"); + case 'S': + return !strcmp(ext, "S"); +#endif + default: + return 0; + } +} + + + +/** + * Decide whether @p filename is an object file, based on its + * extension. + **/ +int dcc_is_object(const char *filename) +{ + const char *dot; + dot = dcc_find_extension((char *) filename); + if (!dot) + return 0; + + return !strcmp(dot, ".o"); +} + + +/* Some files should always be built locally... */ +int +dcc_source_needs_local(const char *filename) +{ + const char *p; + + p = dcc_find_basename(filename); + + if (str_startswith("conftest.", p) || str_startswith("tmp.conftest.", p)) { + rs_trace("autoconf tests are run locally: %s", filename); + return EXIT_DISTCC_FAILED; + } + + return 0; +} + + + +/** + * Work out the default object file name the compiler would use if -o + * was not specified. We don't need to worry about "a.out" because + * we've already determined that -c or -S was specified. + * + * However, the compiler does put the output file in the current + * directory even if the source file is elsewhere, so we need to strip + * off all leading directories. + * + * @param sfile Source filename. Assumed to match one of the + * recognized patterns, otherwise bad things might happen. + **/ +int dcc_output_from_source(const char *sfile, + const char *out_extn, + char **ofile) +{ + char *slash; + + if ((slash = strrchr(sfile, '/'))) + sfile = slash+1; + if (strlen(sfile) < 3) { + rs_log_error("source file %s is bogus", sfile); + return EXIT_DISTCC_FAILED; + } + + return dcc_set_file_extension(sfile, out_extn, ofile); +} + diff --git a/distcc/src/fix_debug_info.c b/distcc/src/fix_debug_info.c new file mode 100644 index 0000000..e78637d --- /dev/null +++ b/distcc/src/fix_debug_info.c @@ -0,0 +1,450 @@ +/* Copyright 2007 Google Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* Author: Fergus Henderson */ + +/* + * fix_debug_info.cc: + * Performs search-and-replace in the debug info section of an ELF file. + */ + +#include "config.h" + +#include <assert.h> +#include <stdio.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> +#ifdef HAVE_ELF_H + #include <elf.h> +#endif + +#include <sys/stat.h> +#ifdef HAVE_SYS_MMAN_H + #include <sys/mman.h> +#endif + +#include "trace.h" +#include "fix_debug_info.h" + +#ifdef HAVE_ELF_H +/* + * Search for an ELF section of the specified name and type. + * Given an ELF file that has been mmapped (or read) into memory starting + * at @p elf_mapped_base, find the section with the desired name and type, + * and return (via the parameters) its start point and size. + * Returns 1 if found, 0 otherwise. + */ +static int FindElfSection(const void *elf_mapped_base, off_t elf_size, + const char *desired_section_name, + const void **section_start, int *section_size) { + const unsigned char *elf_base = (const unsigned char *) elf_mapped_base; + const Elf32_Ehdr *elf32_header = (const Elf32_Ehdr *) (elf_base); + unsigned int i; + unsigned int num_sections; + + assert(elf_mapped_base); + assert(section_start); + assert(section_size); + + *section_start = NULL; + *section_size = 0; + + /* + * There are two kinds of ELF files, 32-bit and 64-bit. They have similar + * but slightly different file structures. It's OK to use the elf32_header + * structure at this point, prior to checking whether this file is a 32 or + * 64 bit ELF file, so long as we only access the e_ident field, because + * the layout of the e_ident field is the same for both kinds: it's the + * first field in the struct, so its offset is zero, and its size is the + * same for both 32 and 64 bit ELF files. + * + * The magic number which identifies an ELF file is stored in the + * first few bytes of the e_ident field, which is also the first few + * bytes of the file. + */ + + if (elf_size < SELFMAG || memcmp(elf32_header, ELFMAG, SELFMAG) != 0) { + rs_trace("object file is not an ELF file"); + return 0; + } + + /* + * The ELF file layouts are defined using fixed-size data structures + * in <elf.h>, so we don't need to worry about the host computer's + * word size. But we do need to worry about the host computer's + * enddianness, because ELF header fields use the same endianness + * as the target computer. When cross-compiling to a target with + * a different endianness, we would need to byte-swap all the fields + * that we use. Right now we don't handle that case. + * + * TODO(fergus): + * handle object files with different endianness than the host. + */ +#if WORDS_BIGENDIAN + if (elf32_header->e_ident[EI_DATA] != ELFDATA2MSB) { + rs_trace("sorry, not fixing debug info: " + "distcc server host is big-endian, object file is not"); + return 0; + } +#else + if (elf32_header->e_ident[EI_DATA] != ELFDATA2LSB) { + rs_trace("sorry, not fixing debug info: " + "distcc server host is little-endian, object file is not"); + return 0; + } +#endif + + /* + * Warning: the following code section is duplicated: + * once for 32-bit ELF files, and again for 64-bit ELF files. + * Please be careful to keep them consistent! + */ + if (elf32_header->e_ident[EI_CLASS] == ELFCLASS32) { + const Elf32_Ehdr *elf_header = elf32_header; + const Elf32_Shdr *sections = + (const Elf32_Shdr *) (elf_base + elf_header->e_shoff); + const Elf32_Shdr *string_section = sections + elf_header->e_shstrndx; + const Elf32_Shdr *desired_section = NULL; + + if (elf_size < (off_t) sizeof(*elf_header)) { + rs_trace("object file is too small for ELF header; maybe got truncated?"); + return 0; + } + if (elf_header->e_shoff <= 0 || + elf_header->e_shoff > elf_size - sizeof(Elf32_Shdr)) { + rs_trace("invalid e_shoff value in ELF header"); + return 0; + } + if (elf_header->e_shstrndx == SHN_UNDEF) { + rs_trace("object file has no section name string table" + " (e_shstrndx == SHN_UNDEF)"); + return 0; + } + // Special case for more sections than will fit in e_shstrndx. + if (elf_header->e_shstrndx == SHN_XINDEX) { + string_section = sections + sections[0].sh_link; + } + num_sections = elf_header->e_shnum; + // Special case for more sections than will fit in e_shnum. + if (num_sections == 0) { + num_sections = sections[0].sh_size; + } + for (i = 0; i < num_sections; ++i) { + const char *section_name = (char*)(elf_base + + string_section->sh_offset + + sections[i].sh_name); + if (!strcmp(section_name, desired_section_name)) { + desired_section = §ions[i]; + break; + } + } + if (desired_section != NULL && desired_section->sh_size > 0) { + int desired_section_size = desired_section->sh_size; + *section_start = elf_base + desired_section->sh_offset; + *section_size = desired_section_size; + return 1; + } else { + return 0; + } + } else if (elf32_header->e_ident[EI_CLASS] == ELFCLASS64) { + const Elf64_Ehdr *elf_header = (const Elf64_Ehdr *) elf_base; + const Elf64_Shdr *sections = + (const Elf64_Shdr *) (elf_base + elf_header->e_shoff); + const Elf64_Shdr *string_section = sections + elf_header->e_shstrndx; + const Elf64_Shdr *desired_section = NULL; + + if (elf_size < (off_t) sizeof(*elf_header)) { + rs_trace("object file is too small for ELF header; maybe got truncated?"); + return 0; + } + if (elf_header->e_shoff <= 0 || + elf_header->e_shoff > elf_size - sizeof(Elf64_Shdr)) { + rs_trace("invalid e_shoff value in ELF header"); + return 0; + } + if (elf_header->e_shstrndx == SHN_UNDEF) { + rs_trace("object file has no section name string table" + " (e_shstrndx == SHN_UNDEF)"); + return 0; + } + // Special case for more sections than will fit in e_shstrndx. + if (elf_header->e_shstrndx == SHN_XINDEX) { + string_section = sections + sections[0].sh_link; + } + num_sections = elf_header->e_shnum; + if (num_sections == 0) { + // Special case for more sections than will fit in e_shnum. + num_sections = sections[0].sh_size; + } + for (i = 0; i < num_sections; ++i) { + const char *section_name = (char*)(elf_base + + string_section->sh_offset + + sections[i].sh_name); + if (!strcmp(section_name, desired_section_name)) { + desired_section = §ions[i]; + break; + } + } + if (desired_section != NULL && desired_section->sh_size > 0) { + int desired_section_size = desired_section->sh_size; + *section_start = elf_base + desired_section->sh_offset; + *section_size = desired_section_size; + return 1; + } else { + return 0; + } + } else { + rs_trace("unknown ELF class - neither ELFCLASS32 nor ELFCLASS64"); + return 0; + } +} + +/* + * Search in a memory buffer (starting at @p base and of size @p size) + * for a string (@p search), and replace @p search with @p replace + * in all null-terminated strings that contain @p search. + */ +static int replace_string(void *base, size_t size, + const char *search, const char *replace) { + char *start = (char *) base; + char *end = (char *) base + size; + int count = 0; + char *p; + size_t search_len = strlen(search); + size_t replace_len = strlen(replace); + + assert(replace_len == search_len); + + if (size < search_len + 1) + return 0; + for (p = start; p < end - search_len - 1; p++) { + if (memcmp(p, search, search_len) == 0) { + memcpy(p, replace, replace_len); + count++; + } + } + return count; +} + +/* + * Map the specified file into memory with MAP_SHARED. + * Returns the mapped address, and stores the file descriptor in @p p_fd. + * It also fstats the file and stores the results in @p st. + * Logs an error message and returns NULL on failure. + */ +static void *mmap_file(const char *path, int *p_fd, struct stat *st) { + int fd; + void *base; + + fd = open(path, O_RDWR); + if (fd < 0) { + rs_log_error("error opening file '%s': %s", path, strerror(errno)); + return NULL; + } + + if (fstat(fd, st) != 0) { + rs_log_error("fstat of file '%s' failed: %s", path, strerror(errno)); + close(fd); + return NULL; + } + + if (st->st_size <= 0) { + rs_log_error("file '%s' has invalid file type or size", path); + close(fd); + return NULL; + } + +#ifdef HAVE_SYS_MMAP_H + base = mmap(NULL, st->st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (base == MAP_FAILED) { + rs_log_error("mmap of file '%s' failed: %s", path, strerror(errno)); + close(fd); + return NULL; + } +#else + base = malloc(st->st_size); + if (base == NULL) { + rs_log_error("can't allocate buffer for %s: malloc failed", path); + close(fd); + return NULL; + } + errno = 0; + if (read(fd, base, st->st_size) != st->st_size) { + rs_log_error("can't read %ld bytes from %s: %s", (long) st->st_size, path, + strerror(errno)); + close(fd); + return NULL; + } +#endif + *p_fd = fd; + return base; +} + +static int munmap_file(void *base, const char *path, int fd, + const struct stat *st) { + int status = 0; +#ifdef HAVE_SYS_MMAP_H + if (munmap(base, st->st_size) != 0) { + rs_log_error("munmap of file '%s' failed: %s", path, strerror(errno)); + status = 1; + } +#else + errno = 0; + if (lseek(fd, 0, SEEK_SET) == -1) { + rs_log_error("can't seek to start of %s: %s", path, strerror(errno)); + status = 1; + } else if (write(fd, base, st->st_size) != st->st_size) { + rs_log_error("can't write %ld bytes to %s: %s", (long) st->st_size, path, + strerror(errno)); + status = 1; + } +#endif + if (close(fd) != 0) { + rs_log_error("close of file '%s' failed: %s", path, strerror(errno)); + status = 1; + } + return status; +} + +/* + * Update the ELF file residing at @p path, replacing all occurrences + * of @p search with @p replace in the section named @p desired_section_name. + * The replacement string must be the same length or shorter than + * the search string. + */ +static void update_section(const char *path, + const void *base, + off_t size, + const char *desired_section_name, + const char *search, + const char *replace) { + const void *desired_section = NULL; + int desired_section_size = 0; + + if (FindElfSection(base, size, desired_section_name, + &desired_section, &desired_section_size) + && desired_section_size > 0) { + int count = replace_string((void *) desired_section, desired_section_size, + search, replace); + if (count == 0) { + rs_trace("\"%s\" section of file %s has no occurrences of \"%s\"", + desired_section_name, path, search); + } else { + rs_log_info("updated \"%s\" section of file \"%s\": " + "replaced %d occurrences of \"%s\" with \"%s\"", + desired_section_name, path, count, search, replace); + if (count > 1) { + rs_log_warning("only expected to replace one occurrence!"); + } + } + } else { + rs_trace("file %s has no \"%s\" section", desired_section_name, path); + } +} + +/* + * Update the ELF file residing at @p path, replacing all occurrences + * of @p search with @p replace in that file's ".debug_info" or + * ".debug_str" section. + * The replacement string must be the same length or shorter than + * the search string. + * Returns 0 on success (whether or not ".debug_info" section was + * found or updated). + * Returns 1 on serious error that should cause distcc to fail. + */ +static int update_debug_info(const char *path, const char *search, + const char *replace) { + struct stat st; + int fd; + void *base; + + base = mmap_file(path, &fd, &st); + if (base == NULL) { + return 0; + } + + update_section(path, base, st.st_size, ".debug_info", search, replace); + update_section(path, base, st.st_size, ".debug_str", search, replace); + + return munmap_file(base, path, fd, &st); +} +#endif /* HAVE_ELF_H */ + +/* + * Edit the ELF file residing at @p path, changing all occurrences of + * the path @p server_path to @p client_path in the debugging info. + * + * We're a bit sloppy about that; rather than properly parsing + * the DWARF debug info, finding the DW_AT_comp_dir (compilation working + * directory) field and the DW_AT_name (source file name) field, + * we just do a search-and-replace in the ".debug_info" and ".debug_str" + * sections. But this is good enough. + * + * Returns 0 on success (whether or not the ".debug_info" and ".debug_str" + * sections were found or updated). + * Returns 1 on serious error that should cause distcc to fail. + */ +int dcc_fix_debug_info(const char *path, const char *client_path, + const char *server_path) +{ +#ifndef HAVE_ELF_H + rs_trace("no <elf.h>, so can't change %s to %s in debug info for %s", + server_path, client_path, path); + return 0; +#else + /* + * We can only safely replace a string with another of exactly + * the same length. (Replacing a string with a shorter string + * results in errors from gdb.) + * So we append trailing slashes on the client side path. + */ + size_t client_path_len = strlen(client_path); + size_t server_path_len = strlen(server_path); + assert(client_path_len <= server_path_len); + char *client_path_plus_slashes = malloc(server_path_len + 1); + if (!client_path_plus_slashes) { + rs_log_crit("failed to allocate memory"); + return 1; + } + strcpy(client_path_plus_slashes, client_path); + while (client_path_len < server_path_len) { + client_path_plus_slashes[client_path_len++] = '/'; + } + client_path_plus_slashes[client_path_len] = '\0'; + rs_log_info("client_path_plus_slashes = %s", client_path_plus_slashes); + return update_debug_info(path, server_path, client_path_plus_slashes); +#endif +} + +#ifdef TEST +const char *rs_program_name; + +int main(int argc, char **argv) { + rs_program_name = argv[0]; + rs_add_logger(rs_logger_file, RS_LOG_DEBUG, NULL, STDERR_FILENO); + rs_trace_set_level(RS_LOG_DEBUG); + if (argc != 4) { + rs_log_error("Usage: %s <filename> <client-path> <server-path>", + rs_program_name); + exit(1); + } + return dcc_fix_debug_info(argv[1], argv[2], argv[3]); +} +#endif diff --git a/distcc/src/fix_debug_info.h b/distcc/src/fix_debug_info.h new file mode 100644 index 0000000..b71ae5d --- /dev/null +++ b/distcc/src/fix_debug_info.h @@ -0,0 +1,26 @@ +/* Copyright 2007 Google Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* Author: Fergus Henderson */ + +#ifndef DISTCC_FIX_DEBUG_INFO_H__ +#define DISTCC_FIX_DEBUG_INFO_H__ + +int dcc_fix_debug_info(const char *path, const char *client_cwd, + const char *server_cwd); + +#endif // DISTCC_FIX_DEBUG_INFO_H__ diff --git a/distcc/src/h_argvtostr.c b/distcc/src/h_argvtostr.c new file mode 100644 index 0000000..27cca7c --- /dev/null +++ b/distcc/src/h_argvtostr.c @@ -0,0 +1,59 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * $Header: /data/cvs/distcc/src/h_argvtostr.c,v 1.4 2003/07/13 08:08:02 mbp Exp $ + * + * Copyright (C) 2002 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" + +const char *rs_program_name = __FILE__; + + +/** + * @file + * + * Test argv-to-string converter. + **/ + + +int main(int argc, char *argv[]) +{ + rs_trace_set_level(RS_LOG_WARNING); + + if (argc < 2) { + rs_log_error("usage: h_scanargs COMMAND ARG...\n"); + return 1; + } + + printf("%s\n", dcc_argv_tostr(&argv[1])); + + return 0; +} diff --git a/distcc/src/h_compile.c b/distcc/src/h_compile.c new file mode 100644 index 0000000..7ed6ac7 --- /dev/null +++ b/distcc/src/h_compile.c @@ -0,0 +1,106 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * $Header: /data/cvs/distcc/src/h_exten.c,v 1.7 2003/07/13 08:08:02 mbp Exp $ + * + * Copyright (C) 2002 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/** + * Test harness for functions in compile.c. (Only one so far.) + **/ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "compile.h" + + +#define USAGE \ +"usage: h_compile COMMAND ARGS...\n" \ +"where\n" \ +" COMMAND is dcc_fresh_dependency_exists,\n" \ +" with ARGS being DOTD_FNAME EXCL_PAT REF_TIME\n" \ +"or\n" \ +" COMMAND is ddc_discrepancy_filename\n" + +const char *rs_program_name = __FILE__; + + +int main(int argc, char *argv[]) +{ + rs_trace_set_level(RS_LOG_DEBUG); + rs_add_logger(rs_logger_file, RS_LOG_DEBUG, NULL, STDERR_FILENO); + if (argc < 2) { + rs_log_error(USAGE); + return 1; + } + + if (strcmp(argv[1], "dcc_fresh_dependency_exists") == 0) { + if (argc != 5) { + rs_log_error("dcc_fresh_dependency_exists expects DOTD_FNAME " + "EXCL_PAT REF_TIME"); + return 1; + } + errno = 0; + char *ptr; + time_t ref_time = (time_t)strtol(argv[4], &ptr, 0); + if (errno || (*ptr != '\0')) { + rs_log_error("strtol failed"); + return 1; + } else { + char *result; + int ret; + ret = dcc_fresh_dependency_exists((const char *)argv[2], + (const char *)argv[3], + ref_time, + &result); + if (ret) + printf("h_compile.c: UNEXPECTED RETURN VALUE\n"); + else + printf("result %s\n", result ? result : "(NULL)"); + if (result) free(result); + } + } else if (strcmp(argv[1], "ddc_discrepancy_filename") == 0) { + if (argc != 2) { + rs_log_error("dcc_discrepancy_filename expects no arguments"); + return 1; + } + char *result; + int ret = ddc_discrepancy_filename(&result); + if (ret) + printf("h_compile.c: UNEXPECTED RETURN VALUE\n"); + else + printf("%s", result ? result : "(NULL)"); + } else { + rs_log_error(USAGE); + return 1; + } + return 0; +} diff --git a/distcc/src/h_dotd.c b/distcc/src/h_dotd.c new file mode 100644 index 0000000..d689761 --- /dev/null +++ b/distcc/src/h_dotd.c @@ -0,0 +1,73 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +/** + * @file + * + * Test harness for dotd.c. + **/ + + +#include "config.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include "dotd.h" +#include "trace.h" + +#define USAGE \ +"usage: h_dotd COMMAND ARGS...\n" \ + "where\n" \ + " COMMAND is dcc_get_dotd_info, ARGS is NAME\n" + +const char *rs_program_name = __FILE__; + + +int main(int argc, char *argv[]) +{ + rs_trace_set_level(RS_LOG_WARNING); + + if (argc < 2) { + rs_log_error(USAGE); + return 1; + } + + if (strcmp(argv[1], "dcc_get_dotd_info") == 0) { + char *dotd_fname; + int needs_dotd, sets_dotd_target; + char *dotd_target; + dcc_get_dotd_info(argv + 2, &dotd_fname, &needs_dotd, &sets_dotd_target, + &dotd_target); + /* Print out in a format easily digested in Python. */ + printf("{'dotd_fname':'%s', 'needs_dotd':%d, 'sets_dotd_target':%d," + " 'dotd_target':'%s'}", + dotd_fname, needs_dotd, sets_dotd_target, + dotd_target ? dotd_target : "None"); + } else { + rs_log_error(USAGE); + return 1; + } + return 0; +} diff --git a/distcc/src/h_exten.c b/distcc/src/h_exten.c new file mode 100644 index 0000000..23782c9 --- /dev/null +++ b/distcc/src/h_exten.c @@ -0,0 +1,60 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * $Header: /data/cvs/distcc/src/h_exten.c,v 1.7 2003/07/13 08:08:02 mbp Exp $ + * + * Copyright (C) 2002 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" + + + +const char *rs_program_name = __FILE__; + +/** + * Test harness that makes sure the filename extension manipulation + * stuff works OK. + **/ +int main(int argc, char *argv[]) +{ + char *ex; + + if (argc != 2) { + rs_log_error("usage: h_exten FILENAME"); + return 1; + } + + printf("%s", (ex = dcc_find_extension(argv[1])) ? ex : "(NULL)"); + + return 0; +} diff --git a/distcc/src/h_hosts.c b/distcc/src/h_hosts.c new file mode 100644 index 0000000..cb7cea2 --- /dev/null +++ b/distcc/src/h_hosts.c @@ -0,0 +1,111 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * $Header: /data/cvs/distcc/src/h_hosts.c,v 1.13 2004/01/30 12:39:14 mbp Exp $ + * + * Copyright (C) 2002, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +/** + * @file + * + * Test harness for hosts.c. + * + * Precondition: DISTCC_HOSTS set in the environment. + * + * Action: calls the environment parser. + * + * Output: on the first line, the number of hosts. Then, one per + * line, either + * + * "ssh" USER HOST COMMAND + * "tcp" HOST PORT + **/ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <time.h> + +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "hosts.h" +#include "exitcode.h" + +const char *rs_program_name = "h_hosts"; + +int main(int UNUSED(argc), char **argv) +{ + struct dcc_hostdef *list, *e; + int nhosts, i; + int ret; + + rs_add_logger(rs_logger_file, RS_LOG_DEBUG, NULL, STDERR_FILENO); + + if (argv[1] && !strcmp(argv[1], "-v")) { + rs_trace_set_level(RS_LOG_DEBUG); + } + + if ((ret = dcc_get_hostlist(&list, &nhosts)) != 0) { + rs_log_error("failed to parse \"%s\"", getenv("DISTCC_HOSTS")); + exit(ret); + } + + printf("%d\n", nhosts); + for (i = 0, e = list; i < nhosts; i++, e = e->next) { + if (!e) { + rs_log_error("entry %d is NULL", i); + exit(1); + } + + printf("%4d ", e->n_slots); + + if (e->mode == DCC_MODE_LOCAL) { + printf("LOCAL\n"); + } else if (e->mode == DCC_MODE_SSH) { + printf("SSH %s %s %s\n", + e->user ? e->user : "(no-user)", + e->hostname ? e->hostname : "(no-hostname)", + e->ssh_command ? e->ssh_command : "(no-command)"); + } else if (e->mode == DCC_MODE_TCP) { + printf("TCP %s %d\n", + e->hostname ? e->hostname : "(no-hostname)", + e->port); + } else { + printf("BOGUS %d\n", e->mode); + } + } + if (e) { + rs_log_error("extra entries in list!"); + exit(EXIT_BAD_HOSTSPEC); + } + + exit(0); +} diff --git a/distcc/src/h_issource.c b/distcc/src/h_issource.c new file mode 100644 index 0000000..84ce152 --- /dev/null +++ b/distcc/src/h_issource.c @@ -0,0 +1,59 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * $Header: /data/cvs/distcc/src/h_issource.c,v 1.7 2003/07/13 08:08:02 mbp Exp $ + * + * Copyright (C) 2002 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" + + +const char *rs_program_name = __FILE__; + + +/** + * Test harness: determine whether a file is source, and is preprocessed. + **/ +int main(int argc, char *argv[]) +{ + if (argc != 2) { + rs_log_error("usage: %s FILENAME", argv[0]); + return 1; + } + + printf("%s %s\n", + dcc_is_source(argv[1]) ? "source" : "not-source", + dcc_is_preprocessed(argv[1]) ? "preprocessed" : "not-preprocessed"); + + return 0; +} diff --git a/distcc/src/h_parsemask.c b/distcc/src/h_parsemask.c new file mode 100644 index 0000000..90525ec --- /dev/null +++ b/distcc/src/h_parsemask.c @@ -0,0 +1,66 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include "config.h" + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "types.h" +#include "distcc.h" +#include "trace.h" +#include "exitcode.h" +#include "access.h" + +const char * rs_program_name = "h_parsemask"; + +int main(int argc, char **argv) +{ + int ret; + in_addr_t value, mask; + struct in_addr client_ia; + + rs_add_logger(rs_logger_file, RS_LOG_DEBUG, NULL, STDERR_FILENO); + rs_trace_set_level(RS_LOG_INFO); + + if (argc != 3) { + rs_log_error("usage: h_parsemask MASK CLIENT"); + return EXIT_BAD_ARGUMENTS; + } + + ret = dcc_parse_mask(argv[1], &value, &mask); + if (ret) + return ret; + + if (!inet_aton(argv[2], &client_ia)) { + rs_log_error("can't parse client address \"%s\"", argv[2]); + return EXIT_BAD_ARGUMENTS; + } + + return dcc_check_address(client_ia.s_addr, value, mask); +} diff --git a/distcc/src/h_sa2str.c b/distcc/src/h_sa2str.c new file mode 100644 index 0000000..1d3f015 --- /dev/null +++ b/distcc/src/h_sa2str.c @@ -0,0 +1,75 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * $Header: /data/cvs/distcc/src/h_sa2str.c,v 1.1 2004/01/10 23:15:32 mbp Exp $ + * + * Copyright (C) 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <netdb.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/un.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> + + +#include "types.h" +#include "exitcode.h" +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "srvnet.h" +#include "access.h" +#include "netutil.h" +#include "snprintf.h" + +const char *rs_program_name = "h_sa2str"; + +/* Try to print out a sockaddr */ +int main(void) +{ + struct sockaddr_in sa; + char *buf; + int ret; + + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = (in_addr_t) htonl(0x01020304); + sa.sin_port = 4200; + + if ((ret = dcc_sockaddr_to_string((struct sockaddr *) &sa, sizeof sa, &buf))) + return ret; + puts(buf); + free(buf); + + return 0; +} diff --git a/distcc/src/h_scanargs.c b/distcc/src/h_scanargs.c new file mode 100644 index 0000000..c6fbf33 --- /dev/null +++ b/distcc/src/h_scanargs.c @@ -0,0 +1,72 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * $Header: /data/cvs/distcc/src/h_scanargs.c,v 1.9 2003/07/13 08:08:02 mbp Exp $ + * + * Copyright (C) 2002 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "implicit.h" + +const char *rs_program_name = __FILE__; + + +/** + * Test harness: make argument-parsing code accessible from the + * command line so that it can be tested. + **/ +int main(int argc, char *argv[]) +{ + int result; + char *infname, *outfname; + char **newargv, **outargv; + + rs_trace_set_level(RS_LOG_DEBUG); + + if (argc < 2) { + rs_log_error("usage: h_scanargs COMMAND ARG...\n"); + return 1; + } + + result = dcc_find_compiler(argv, &newargv); + + if (result) + return result; + + result = dcc_scan_args(newargv, &infname, &outfname, &outargv); + + printf("%s %s %s\n", + result == 0 ? "distribute" : "local", + infname ? infname : "(NULL)", outfname ? outfname : "(NULL)"); + + return 0; +} diff --git a/distcc/src/h_strip.c b/distcc/src/h_strip.c new file mode 100644 index 0000000..7b84ecc --- /dev/null +++ b/distcc/src/h_strip.c @@ -0,0 +1,63 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * $Header: /data/cvs/distcc/src/h_strip.c,v 1.4 2003/07/13 08:08:02 mbp Exp $ + * + * Copyright (C) 2002 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" + +const char *rs_program_name = __FILE__; + + +/** + * Test harness: determine whether a file is source, and is preprocessed. + **/ +int main(int argc, char *argv[]) +{ + char **new_args; + int ret; + + if (argc < 2) { + rs_log_error("usage: %s ARGS...", argv[0]); + return 1; + } + + if ((ret = dcc_strip_local_args(argv + 1, &new_args))) { + return ret; + } + + printf("%s\n", dcc_argv_tostr(new_args)); + + return 0; +} diff --git a/distcc/src/help.c b/distcc/src/help.c new file mode 100644 index 0000000..0e66540 --- /dev/null +++ b/distcc/src/help.c @@ -0,0 +1,74 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + /* + * Tell me what you need, and I'll tell you how to + * get along without it. -- Dilbert + */ + +#include "config.h" + + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include "distcc.h" +#include "trace.h" + + +int dcc_trace_version(void) +{ + rs_trace("%s %s %s; built %s %s", + rs_program_name, PACKAGE_VERSION, GNU_HOST, + __DATE__, __TIME__); + return 0; +} + + +int dcc_show_version(const char *prog) +{ + /* The "built" message is the time this file was built, which may not be + * completely accurate for the program as a whole unless you do "make + * clean". + * + * Message looks like the one from "gcc --version". */ + printf("%s %s %s\n" + " (protocols 1, 2 and 3) (default port %d)\n" + " built %s %s\n" +"Copyright (C) 2002, 2003, 2004 by Martin Pool.\n" +"Includes miniLZO (C) 1996-2002 by Markus Franz Xaver Johannes Oberhumer.\n" +"Portions Copyright (C) 2007-2008 Google.\n" +"\n" +"distcc comes with ABSOLUTELY NO WARRANTY. distcc is free software, and\n" +"you may use, modify and redistribute it under the terms of the GNU \n" +"General Public License version 2 or later.\n" +"\n" +"Please report bugs to %s\n" +"\n" + , + prog, PACKAGE_VERSION, GNU_HOST, DISTCC_DEFAULT_PORT, + __DATE__, __TIME__, PACKAGE_BUGREPORT); + return 0; +} diff --git a/distcc/src/history.c b/distcc/src/history.c new file mode 100644 index 0000000..a36edfb --- /dev/null +++ b/distcc/src/history.c @@ -0,0 +1,68 @@ +/* -*- c-file-style: "k&r"; c-basic-offset: 4; indent-tabs-mode: nil; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +#include "config.h" +#include <stdlib.h> + +#include "distcc.h" +#include "mon.h" +#include "trace.h" + +/* Number of previous states to retain for drawing history. */ +const int dcc_max_history_queue = 200; + + +void +dcc_history_push(struct dcc_history *history, + enum dcc_phase new_state) +{ + history->now = (history->now + 1) % history->len; + history->past_phases[history->now] = new_state; +} + + +struct dcc_history* +dcc_history_new(void) +{ + struct dcc_history *history; + int i; + + history = malloc(sizeof *history); + if (!history) { + rs_log_crit("allocation failed!"); + return NULL; + } + history->len = dcc_max_history_queue; + history->now = 0; + history->past_phases = malloc(history->len * (sizeof *history->past_phases)); + if (!history->past_phases) { + rs_log_crit("history allocation failed"); + return NULL; + } + + for (i = 0; i < history->len; i++) + history->past_phases[i] = DCC_PHASE_DONE; + + return history; +} + diff --git a/distcc/src/hostfile.c b/distcc/src/hostfile.c new file mode 100644 index 0000000..6511d49 --- /dev/null +++ b/distcc/src/hostfile.c @@ -0,0 +1,67 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "exitcode.h" +#include "hosts.h" + +/* TODO: Perhaps in the future allow filenames to be given in environment + * variables to cause other files to be "included". */ + + + +/** + * Return a hostlist read from fname (possibly recursively.) + **/ +int dcc_parse_hosts_file(const char *fname, + struct dcc_hostdef **ret_list, + int *ret_nhosts) +{ + char *body; + int ret; + + rs_trace("load hosts from %s", fname); + + if ((ret = dcc_load_file_string(fname, &body)) != 0) + return ret; + + ret = dcc_parse_hosts(body, fname, ret_list, ret_nhosts); + + free(body); + + return ret; +} diff --git a/distcc/src/hosts.c b/distcc/src/hosts.c new file mode 100644 index 0000000..80cfc9d --- /dev/null +++ b/distcc/src/hosts.c @@ -0,0 +1,654 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* dcc_randomize_host_list() and friends: + * Copyright (C) 2004 by Google + * + * Author: Josh Hyman <joshh@google.com> + */ + + + /* The lyf so short, the craft so long to lerne. + * -- Chaucer */ + + + +/** + * @file + * + * Routines to parse <tt>$DISTCC_HOSTS</tt>. Actual decisions about + * where to run a job are in where.c. + * + * The grammar of this variable is, informally: + * + DISTCC_HOSTS = HOSTSPEC ... + HOSTSPEC = LOCAL_HOST | SSH_HOST | TCP_HOST | OLDSTYLE_TCP_HOST + | GLOBAL_OPTION + LOCAL_HOST = localhost[/LIMIT] + SSH_HOST = [USER]@HOSTID[/LIMIT][:COMMAND][OPTIONS] + TCP_HOST = HOSTID[:PORT][/LIMIT][OPTIONS] + OLDSTYLE_TCP_HOST = HOSTID[/LIMIT][:PORT][OPTIONS] + HOSTID = HOSTNAME | IPV4 + OPTIONS = ,OPTION[OPTIONS] + OPTION = lzo | cpp + GLOBAL_OPTION = --randomize + * + * Any amount of whitespace may be present between hosts. + * + * The command specified for SSH defines the location of the remote + * server, e.g. "/usr/local/bin/distccd". This is provided as a + * convenience who have trouble getting their PATH set correctly for + * sshd to find distccd, and should not normally be needed. + * + * If you need to specify special options for ssh, they should be put + * in ~/.ssh/config and referenced by the hostname. + * + * The TCP port defaults to 3632 and should not normally need to be + * overridden. + * + * IPv6 literals are not supported yet. They will need to be + * surrounded by square brackets because they may contain a colon, + * which would otherwise be ambiguous. This is consistent with other + * URL-like schemes. + */ + + +/* + Alexandre Oliva writes + + I take this opportunity to plead people to consider such issues when + proposing additional syntax for DISTCC_HOSTS: if it was possible to + handle DISTCC_HOSTS as a single shell word (perhaps after turning + blanks into say commas), without the risk of any shell active + characters such as {, }, ~, $, quotes getting in the way, outputting + distcc commands that override DISTCC_HOSTS would be far + simpler. + + TODO: Perhaps entries in the host list that "look like files" (start + with '/' or '~') should be read in as files? This could even be + recursive. +*/ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <time.h> +#include <ctype.h> +#include <sys/time.h> +#include <sys/types.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "hosts.h" +#include "exitcode.h" +#include "snprintf.h" + +const int dcc_default_port = DISTCC_DEFAULT_PORT; + +/*** + * A simple container which would hold a host -> rand int pair + ***/ +struct rand_container { + struct dcc_hostdef *host; + int rand; +}; + +int dcc_randomize_host_list(struct dcc_hostdef **host_list, int length); + +int dcc_compare_container(const void *a, const void *b); + + +#ifndef HAVE_STRNDUP +/** + * Copy at most @p size characters from @p src, plus a terminating nul. + * + * Really this needs to be in util.c, but it's only used here. + **/ +static char *strndup(const char *src, size_t size) +{ + char *dst; + + dst = malloc(size + 1); + if (dst == NULL) + return NULL; + strncpy(dst, src, size); + dst[size] = '\0'; + + return dst; +} +#endif + +/** + * Get a list of hosts to use. + * + * Hosts are taken from DISTCC_HOSTS, if that exists. Otherwise, they are + * taken from $DISTCC_DIR/hosts, if that exists. Otherwise, they are taken + * from ${sysconfdir}/distcc/hosts, if that exists. Otherwise, we fail. + **/ +int dcc_get_hostlist(struct dcc_hostdef **ret_list, + int *ret_nhosts) +{ + char *env; + char *path, *top; + int ret; + + if ((env = getenv("DISTCC_HOSTS")) != NULL) { + rs_trace("read hosts from environment"); + return dcc_parse_hosts(env, "$DISTCC_HOSTS", ret_list, ret_nhosts); + } + + /* $DISTCC_DIR or ~/.distcc */ + if ((ret = dcc_get_top_dir(&top)) == 0) { + /* if we failed to get it, just warn */ + + asprintf(&path, "%s/hosts", top); + if (access(path, R_OK) == 0) { + ret = dcc_parse_hosts_file(path, ret_list, ret_nhosts); + free(path); + return ret; + } else { + rs_trace("not reading %s: %s", path, strerror(errno)); + free(path); + } + } + + asprintf(&path, "%s/distcc/hosts", SYSCONFDIR); + if (access(path, R_OK) == 0) { + ret = dcc_parse_hosts_file(path, ret_list, ret_nhosts); + free(path); + return ret; + } else { + rs_trace("not reading %s: %s", path, strerror(errno)); + free(path); + } + + /* FIXME: Clearer message? */ + rs_log_warning("no hostlist is set; can't distribute work"); + + return EXIT_BAD_HOSTSPEC; +} + + +/** + * Parse an optionally present multiplier. + * + * *psrc is the current parse cursor; it is advanced over what is read. + * + * If a multiplier is present, *psrc points to a substring starting with '/'. + * The host defintion is updated to the numeric value following. Otherwise + * the hostdef is unchanged. + **/ +static int dcc_parse_multiplier(const char **psrc, struct dcc_hostdef *hostdef) +{ + const char *token = *psrc; + + if ((*psrc)[0] == '/' || (*psrc)[0] == '=') { + int val; + (*psrc)++; + val = atoi(*psrc); + if (val == 0) { + rs_log_error("bad multiplier \"%s\" in host specification", token); + return EXIT_BAD_HOSTSPEC; + } + while (isdigit(**psrc)) + (*psrc)++; + hostdef->n_slots = val; + } + return 0; +} + + +/** + * Parse an optionally present option string. + * + * At the moment the only two options we have is "lzo" for compression, + * and "cpp" if the server supports doing the preprocessing there, also. + **/ +static int dcc_parse_options(const char **psrc, + struct dcc_hostdef *host) +{ + const char *started = *psrc, *p = *psrc; + + host->compr = DCC_COMPRESS_NONE; + host->cpp_where = DCC_CPP_ON_CLIENT; + + while (p[0] == ',') { + p++; + if (str_startswith("lzo", p)) { + rs_trace("got LZO option"); + host->compr = DCC_COMPRESS_LZO1X; + p += 3; + } else if (str_startswith("down", p)) { + /* if "hostid,down", mark it down, and strip down from hostname */ + host->is_up = 0; + p += 4; + } else if (str_startswith("cpp", p)) { + rs_trace("got CPP option"); + host->cpp_where = DCC_CPP_ON_SERVER; + p += 3; + } else { + rs_log_warning("unrecognized option in host specification %s", + started); + return EXIT_BAD_HOSTSPEC; + } + } + dcc_get_protover_from_features(host->compr, host->cpp_where, + &host->protover); + + *psrc = p; + + return 0; +} + +static int dcc_parse_ssh_host(struct dcc_hostdef *hostdef, + const char *token_start) +{ + int ret; + const char *token = token_start; + + /* Everything up to '@' is the username */ + if ((ret = dcc_dup_part(&token, &hostdef->user, "@")) != 0) + return ret; + + if (token[0] != '@') { + rs_log_error("expected '@' to start ssh token"); + return EXIT_BAD_HOSTSPEC; + } + + token++; + + if ((ret = dcc_dup_part(&token, &hostdef->hostname, "/: \t\n\r\f,")) != 0) + return ret; + + if (!hostdef->hostname) { + rs_log_error("hostname is required in SSH host specification \"%s\"", + token_start); + return EXIT_BAD_HOSTSPEC; + } + + if ((ret = dcc_parse_multiplier(&token, hostdef)) != 0) + return ret; + + if (token[0] == ':') { + token++; + if ((ret = dcc_dup_part(&token, &hostdef->ssh_command, " \t\n\r\f,"))) + return ret; + } + + if ((ret = dcc_parse_options(&token, hostdef))) + return ret; + + hostdef->mode = DCC_MODE_SSH; + return 0; +} + + +static int dcc_parse_tcp_host(struct dcc_hostdef *hostdef, + const char * const token_start) +{ + int ret; + const char *token = token_start; + + if ((ret = dcc_dup_part(&token, &hostdef->hostname, "/: \t\n\r\f,"))) + return ret; + + if (!hostdef->hostname) { + rs_log_error("hostname is required in tcp host specification \"%s\"", + token_start); + return EXIT_BAD_HOSTSPEC; + } + + if ((ret = dcc_parse_multiplier(&token, hostdef)) != 0) + return ret; + + hostdef->port = dcc_default_port; + if (token[0] == ':') { + char *tail; + + token++; + + hostdef->port = strtol(token, &tail, 10); + if (*tail != '\0' && !isspace(*tail) && *tail != '/' && *tail != ',') { + rs_log_error("invalid tcp port specification in \"%s\"", token); + return EXIT_BAD_HOSTSPEC; + } else { + token = tail; + } + } + + if ((ret = dcc_parse_multiplier(&token, hostdef)) != 0) + return ret; + + if ((ret = dcc_parse_options(&token, hostdef))) + return ret; + + hostdef->mode = DCC_MODE_TCP; + return 0; +} + + +static int dcc_parse_localhost(struct dcc_hostdef *hostdef, + const char * token_start) +{ + const char *token = token_start + strlen("localhost"); + + hostdef->mode = DCC_MODE_LOCAL; + hostdef->hostname = strdup("localhost"); + + /* Run only two tasks on localhost by default. + * + * It might be nice to run more if there are more CPUs, but determining + * the number of CPUs on Linux is a bit expensive since it requires + * examining mtab and /proc/stat. Anyone lucky enough to have a >2 CPU + * machine can specify a number in the host list. + */ + hostdef->n_slots = 2; + + return dcc_parse_multiplier(&token, hostdef); +} + +/** Given a host with its protover fields set, set + * its feature fields appropriately. Returns 0 if the protocol + * is known, non-zero otherwise. + */ +int dcc_get_features_from_protover(enum dcc_protover protover, + enum dcc_compress *compr, + enum dcc_cpp_where *cpp_where) +{ + if (protover > 1) { + *compr = DCC_COMPRESS_LZO1X; + } else { + *compr = DCC_COMPRESS_NONE; + } + if (protover > 2) { + *cpp_where = DCC_CPP_ON_SERVER; + } else { + *cpp_where = DCC_CPP_ON_CLIENT; + } + + if (protover == 0 || protover > 3) { + return 1; + } else { + return 0; + } +} + +/** Given a host with its feature fields set, set + * its protover appropriately. Return the protover, + * or -1 on error. + */ +int dcc_get_protover_from_features(enum dcc_compress compr, + enum dcc_cpp_where cpp_where, + enum dcc_protover *protover) +{ + *protover = -1; + + if (compr == DCC_COMPRESS_NONE && + cpp_where == DCC_CPP_ON_CLIENT) { + *protover = DCC_VER_1; + } + + if (compr == DCC_COMPRESS_LZO1X && + cpp_where == DCC_CPP_ON_SERVER) { + *protover = DCC_VER_3; + } + if (compr == DCC_COMPRESS_LZO1X && + cpp_where == DCC_CPP_ON_CLIENT) { + *protover = DCC_VER_2; + } + + return *protover; +} + + +/** + * @p where is the host list, taken either from the environment or file. + * + * @return 0 if parsed successfully; nonzero if there were any errors, + * or if no hosts were defined. + **/ +int dcc_parse_hosts(const char *where, const char *source_name, + struct dcc_hostdef **ret_list, + int *ret_nhosts) +{ + int ret, flag_randomize = 0; + struct dcc_hostdef *prev, *curr; + + /* TODO: Check for '/' in places where it might cause trouble with + * a lock file name. */ + + prev = NULL; + *ret_list = NULL; + *ret_nhosts = 0; + /* A simple, hardcoded scanner. Some of the GNU routines might be + * useful here, but they won't work on less capable systems. + * + * We repeatedly attempt to extract a whitespace-delimited host + * definition from the string until none remain. Allocate an + * entry; hook to previous entry. We then determine if there is a + * '@' in it, which tells us whether it is an SSH or TCP + * definition. We then duplicate the relevant subcomponents into + * the relevant fields. */ + while (1) { + int token_len; + const char *token_start; + int has_at; + + if (where[0] == '\0') + break; /* end of string */ + + /* skip over comments */ + if (where[0] == '#') { + do + where++; + while (where[0] != '\n' && where[0] != '\r' && where[0] != '\0'); + continue; + } + + if (isspace(where[0])) { + where++; /* skip space */ + continue; + } + + token_start = where; + token_len = strcspn(where, " #\t\n\f\r"); + + /* intercept keywords which are not actually hosts */ + if (!strncmp(token_start, "--randomize", 11)) { + flag_randomize = 1; + where = token_start + token_len; + continue; + } + + if(!strncmp(token_start, "--localslots_cpp", 16)) { + const char *ptr; + ptr = token_start + 16; + if(dcc_parse_multiplier(&ptr, dcc_hostdef_local_cpp) == 0) { + where = token_start + token_len; + continue; + } + } + + if(!strncmp(token_start, "--localslots", 12)) { + const char *ptr; + ptr = token_start + 12; + if(dcc_parse_multiplier(&ptr, dcc_hostdef_local) == 0) { + where = token_start + token_len; + continue; + } + } + + /* Allocate new list item */ + curr = calloc(1, sizeof(struct dcc_hostdef)); + if (!curr) { + rs_log_crit("failed to allocate host definition"); + return EXIT_OUT_OF_MEMORY; + } + + /* by default, mark the host up */ + curr->is_up = 1; + + /* Store verbatim hostname */ + if (!(curr->hostdef_string = strndup(token_start, (size_t) token_len))) { + rs_log_crit("failed to allocate hostdef_string"); + return EXIT_OUT_OF_MEMORY; + } + + /* Link into list */ + if (prev) { + prev->next = curr; + } else { + *ret_list = curr; /* first */ + } + + /* Default task limit. A bit higher than the local limit to allow for + * some files in transit. */ + curr->n_slots = 4; + + curr->protover = DCC_VER_1; /* default */ + curr->compr = DCC_COMPRESS_NONE; + + has_at = (memchr(token_start, '@', (size_t) token_len) != NULL); + + if (!strncmp(token_start, "localhost", 9) + && (token_len == 9 || token_start[9] == '/')) { + rs_trace("found localhost token \"%.*s\"", token_len, token_start); + if ((ret = dcc_parse_localhost(curr, token_start)) != 0) + return ret; + } else if (has_at) { + rs_trace("found ssh token \"%.*s\"", token_len, token_start); + if ((ret = dcc_parse_ssh_host(curr, token_start)) != 0) + return ret; + } else { + rs_trace("found tcp token \"%.*s\"", token_len, token_start); + if ((ret = dcc_parse_tcp_host(curr, token_start)) != 0) + return ret; + } + + if (!curr->is_up) { + rs_trace("host %s is down", curr->hostdef_string); + } + + /* continue to next token if any */ + where = token_start + token_len; + prev = curr; + (*ret_nhosts)++; + } + + if (*ret_nhosts) { + if (flag_randomize) + if ((ret = dcc_randomize_host_list(ret_list, *ret_nhosts)) != 0) + return ret; + return 0; + } else { + rs_log_warning("%s contained no hosts; can't distribute work", source_name); + return EXIT_BAD_HOSTSPEC; + } +} + + +int dcc_compare_container(const void *a, const void *b) +{ + struct rand_container *i, *j; + i = (struct rand_container *) a; + j = (struct rand_container *) b; + + if (i->rand == j->rand) + return 0; + else if (i->rand > j->rand) + return 1; + else + return -1; +} + +int dcc_randomize_host_list(struct dcc_hostdef **host_list, int length) +{ + int i; + unsigned int rand_val; + struct dcc_hostdef *curr; + struct rand_container *c; + + c = malloc(length * sizeof(struct rand_container)); + if (!c) { + rs_log_crit("failed to allocate host definition"); + return EXIT_OUT_OF_MEMORY; + } +/* +{ +#ifdef HAVE_GETTIMEOFDAY + int ret; + struct timeval tv; + if ((ret = gettimeofday(&tv, NULL)) == 0) + rand_val = (unsigned int) tv.tv_usec; + else +#else + rand_val = (unsigned int) time(NULL) ^ (unsigned int) getpid(); +#endif +} +*/ + rand_val = (unsigned int) getpid(); + + /* create pairs of hosts -> random numbers */ + srand(rand_val); + curr = *host_list; + for (i = 0; i < length; i++) { + c[i].host = curr; + c[i].rand = rand(); + curr = curr->next; + } + + /* sort */ + qsort(c, length, sizeof(struct rand_container), &dcc_compare_container); + + /* reorder the list */ + for (i = 0; i < length; i++) { + if (i != length - 1) + c[i].host->next = c[i+1].host; + else + c[i].host->next = NULL; + } + + /* move the start of the list */ + *host_list = c[0].host; + + free(c); + return 0; +} + +int dcc_free_hostdef(struct dcc_hostdef *host) +{ + /* ANSI C requires free() to accept NULL */ + + free(host->user); + free(host->hostname); + free(host->ssh_command); + free(host->hostdef_string); + memset(host, 0xf1, sizeof *host); + free(host); + + return 0; +} diff --git a/distcc/src/hosts.h b/distcc/src/hosts.h new file mode 100644 index 0000000..674ac85 --- /dev/null +++ b/distcc/src/hosts.h @@ -0,0 +1,87 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/** + * @file + * + * Declarations for distcc host selection stuff. + **/ + +/** + * A simple linked list of host definitions. All strings are mallocd. + **/ +struct dcc_hostdef { + enum { + DCC_MODE_TCP = 1, + DCC_MODE_SSH, + DCC_MODE_LOCAL + } mode; + char * user; + char * hostname; + int port; + char * ssh_command; + + /** Mark the host as up == 1, by default, or down == 0, if !hostname */ + int is_up; + + /** Number of tasks that can be dispatched concurrently to this machine. */ + int n_slots; + + /** The full name of this host, taken verbatim from the host + * definition. **/ + char * hostdef_string; + + enum dcc_protover protover; + + /** The kind of compression to use for this host */ + enum dcc_compress compr; + + /** Where are we doing preprocessing? */ + enum dcc_cpp_where cpp_where; + + struct dcc_hostdef *next; +}; + +/** Static definition of localhost **/ +extern struct dcc_hostdef *dcc_hostdef_local; +extern struct dcc_hostdef *dcc_hostdef_local_cpp; + +/* hosts.c */ +int dcc_get_hostlist(struct dcc_hostdef **ret_list, + int *ret_nhosts); + +int dcc_free_hostdef(struct dcc_hostdef *host); + +int dcc_get_features_from_protover(enum dcc_protover protover, + enum dcc_compress *compr, + enum dcc_cpp_where *cpp_where); + +int dcc_get_protover_from_features(enum dcc_compress compr, + enum dcc_cpp_where cpp_where, + enum dcc_protover *protover); + +/* hostfile.c */ +int dcc_parse_hosts_file(const char *fname, + struct dcc_hostdef **ret_list, + int *ret_nhosts); + + diff --git a/distcc/src/implicit.c b/distcc/src/implicit.c new file mode 100644 index 0000000..603699b --- /dev/null +++ b/distcc/src/implicit.c @@ -0,0 +1,95 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + /* "I do not trouble myself to be understood. I see + * that the elementary laws never apologize." + * -- Whitman, "Song of Myself". */ + + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> + +#include "distcc.h" +#include "trace.h" +#include "exitcode.h" +#include "util.h" +#include "implicit.h" + + + +/** + * @file + * + * Handle invocations where the compiler name is implied rather than + * specified. That is, "distcc -c foo.c". + * + * This method of invocation is less transparent than the masquerade system, + * and less explicit than giving the real compiler name. But it is pretty + * simple, and is retained for that reason. + * + * This is used on the client only. The compiler name is always passed (as + * argv[0]) to the server. + * + * The current implementation determines that no compiler name has been + * specified by checking whether the first argument is either an option, or a + * source or object file name. If not, it is assumed to be the name of the + * compiler to use. + * + * At the moment the default compiler name is always "cc", but this could + * change to come from an environment variable. That's not supported at the + * moment, and may never be. If you need that level of control, using a + * different invocation method is recommended. + **/ + + +/** + * Find the compiler for non-masquerade use. + * + * If we're invoked with no compiler name, insert one. + * + * We can tell there's no compiler name because argv[1] will be either + * a source filename or an object filename or an option. I don't + * think anything else is possible. + **/ +int dcc_find_compiler(char **argv, char ***out_argv) +{ + if (argv[1][0] == '-' + || dcc_is_source(argv[1]) + || dcc_is_object(argv[1])) { + dcc_copy_argv(argv, out_argv, 0); + + /* change "distcc -c foo.c" -> "cc -c foo.c" */ + (*out_argv)[0] = strdup("cc"); + return 0; + } else { + /* skip "distcc", point to "gcc -c foo.c" */ + *out_argv = argv+1; + return 0; + } +} diff --git a/distcc/src/implicit.h b/distcc/src/implicit.h new file mode 100644 index 0000000..371657d --- /dev/null +++ b/distcc/src/implicit.h @@ -0,0 +1,25 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * $Header: /data/cvs/distcc/src/implicit.h,v 1.3 2002/09/18 06:57:45 mbp Exp $ + * + * Copyright (C) 2002 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +int dcc_find_compiler(char **argv, char ***); + diff --git a/distcc/src/include_server_if.c b/distcc/src/include_server_if.c new file mode 100644 index 0000000..76c557d --- /dev/null +++ b/distcc/src/include_server_if.c @@ -0,0 +1,161 @@ +/* Copyright 2007 Google Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +// Author: Manos Renieris + +#include <string.h> +#include <stdlib.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> + +#include "distcc.h" +#include "trace.h" +#include "rpc.h" +#include "clinet.h" +#include "exitcode.h" +#include "util.h" +#include "include_server_if.h" + +/* The include server puts all files in its own special directory, + * which is n path components long, where n = INCLUDE_SERVER_DIR_DEPTH + */ +#define INCLUDE_SERVER_DIR_DEPTH 3 + +/** Talks to the include server, over the AF_UNIX socket specified + * in env variable INCLUDE_SERVER_PORT. If all goes well, + * it returns the array of files in @p files and returns 0; + * if anything goes wrong, it returns a non-zero value. + */ + +int dcc_talk_to_include_server(char **argv, char ***files) +{ + char *include_server_port; + int fd; + struct sockaddr_un sa; + + int ret; + char *stub; + + /* for testing purposes, if INCLUDE_SERVER_STUB is set, + use its value rather than the include server */ + stub = getenv("INCLUDE_SERVER_STUB"); + if (stub != NULL) { + ret = dcc_tokenize_string(stub, files); + rs_log_warning("INCLUDE_SERVER_STUB is set to '%s'; " + "ignoring include server", + dcc_argv_tostr(*files)); + return ret; + } + + include_server_port = getenv("INCLUDE_SERVER_PORT"); + if (include_server_port == NULL) { + rs_log_warning("INCLUDE_SERVER_PORT not set"); + return 1; + } + + if (strlen(include_server_port) >= ((int)sizeof(sa.sun_path) - 1)) { + rs_log_warning("$INCLUDE_SERVER_PORT is longer than %d characters", + (sizeof(sa.sun_path) - 1)); + return 1; + } + + strcpy(sa.sun_path, include_server_port); + sa.sun_family = AF_UNIX; + + if (dcc_connect_by_addr((struct sockaddr *) &sa, sizeof(sa), &fd)) + return 1; + + /* the following code uses dcc_r_arg to receive an array of strings + * which are NOT command line arguments. TODO: implement dcc_r_argv + * on top a generic array-of-strings function */ + if (dcc_x_cwd(fd) || + dcc_x_argv(fd, argv) || + dcc_r_argv(fd, files)) { + rs_log_warning("failed to talk to include server '%s'", + include_server_port); + dcc_close(fd); + /* We are failing anyway, so we can ignore + the return value of dcc_close() */ + return 1; + } + + if (dcc_close(fd)) { + return 1; + } + + if (dcc_argv_len(*files) == 0) { + rs_log_warning("include server gave up analyzing"); + return 1; + } + return 0; +} + +/* The include server puts all files in its own special directory, + * which is n path components long, where n = INCLUDE_SERVER_DIR_DEPTH + * The original file should drop those components. + * Also, we need to strip the .lzo and .lzo.abs suffixes. + */ +int dcc_get_original_fname(const char *fname, char **original_fname) +{ + int i; + char *work, *alloced_work, *extension; + + alloced_work = work = strdup(fname); + if (work == NULL) + return EXIT_OUT_OF_MEMORY; + + /* Since all names are supposed to be absolute, they start with + * a slash. We are trying to drop INCLUDE_SERVER_DIR_DEPTH path + * components, so we start right after the first slash, and we look + * for a slash, and then we skip that slash and look for a slash, etc. + */ + + for (i = 0; i < INCLUDE_SERVER_DIR_DEPTH; ++i) { + work = strchr(work + 1, '/'); + if (work == NULL) { + return 1; + } + } + + /* This code removes an abs extension if it's there, and + then a .lzo extension if it's there. As a result + a .lzo.abs extension is removed, but not a .abs.lzo + extension. + */ + extension = dcc_find_extension(work); + if (extension && (strcmp(extension, ".abs") == 0)) { + *extension = '\0'; + } + extension = dcc_find_extension(work); + if (extension && (strcmp(extension, ".lzo") == 0)) { + *extension = '\0'; + } + + *original_fname = strdup(work); + if (*original_fname == NULL) { + free(alloced_work); + return EXIT_OUT_OF_MEMORY; + } + free(alloced_work); + return 0; +} diff --git a/distcc/src/include_server_if.h b/distcc/src/include_server_if.h new file mode 100755 index 0000000..3d8a893 --- /dev/null +++ b/distcc/src/include_server_if.h @@ -0,0 +1,21 @@ +/* Copyright 2007 Google Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +// Author: Manos Renieris + +int dcc_talk_to_include_server(char **argv, char ***files); +int dcc_get_original_fname(const char *fname, char **original_fname); diff --git a/distcc/src/io.c b/distcc/src/io.c new file mode 100644 index 0000000..ad404b2 --- /dev/null +++ b/distcc/src/io.c @@ -0,0 +1,272 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +/** + * @file + * + * Common low-level IO utilities. + * + * This code is not meant to know about our protocol, only to provide + * a more comfortable layer on top of Unix IO. + * + * @todo Perhaps write things out using writev() to reduce the number + * of system calls, and the risk of small packets when not using + * TCP_CORK. + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/socket.h> +#ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +#endif +#include <sys/time.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "exitcode.h" + + + +/** Timeout for all IO other than opening connections. Much longer, because + * compiling files can take a long time. **/ +const int dcc_io_timeout = 300; /* seconds */ + + +/** + * @todo Perhaps only apply the timeout for initial connections, not when + * doing regular IO. + **/ +int dcc_select_for_read(int fd, + int timeout) +{ + fd_set fds; + int rs; + struct timeval tv; + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + while (1) { + FD_ZERO(&fds); + FD_SET(fd, &fds); + + /* Linux updates the timeval to reflect the remaining time, but other + * OSs may not. So on other systems, we may wait a bit too long if + * the client is interrupted -- but that won't happen very often so + * it's no big deal. + */ + + rs_trace("select for read on fd%d for %ds", fd, (int) tv.tv_sec); + rs = select(fd+1, &fds, NULL, NULL, &tv); + if (rs == -1 && errno == EINTR) { + rs_trace("select was interrupted"); + continue; + } else if (rs == -1) { + rs_log_error("select() failed: %s", strerror(errno)); + return EXIT_IO_ERROR; + } else if (rs == 0) { + rs_log_error("IO timeout"); + return EXIT_IO_ERROR; + } else if (!FD_ISSET(fd, &fds)) { + rs_log_error("how did fd not get set?"); + continue; + } else { + break; /* woot */ + } + } + return 0; +} + + +/* + * Calls select() to block until the specified fd becomes writeable + * or has an error condition, or the timeout expires. + */ +int dcc_select_for_write(int fd, int timeout) +{ + fd_set write_fds; + fd_set except_fds; + int rs; + + struct timeval tv; + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + while (1) { + FD_ZERO(&write_fds); + FD_ZERO(&except_fds); + FD_SET(fd, &write_fds); + FD_SET(fd, &except_fds); + rs_trace("select for write on fd%d", fd); + + rs = select(fd + 1, NULL, &write_fds, &except_fds, &tv); + + if (rs == -1 && errno == EINTR) { + rs_trace("select was interrupted"); + continue; + } else if (rs == -1) { + rs_log_error("select failed: %s", strerror(errno)); + return EXIT_IO_ERROR; + } else { + if (FD_ISSET(fd, &except_fds)) { + rs_trace("error condition on fd%d", fd); + /* + * Don't fail here; we couldn't give a good error + * message, because we don't know what the error + * condition is. Instead just return 0 (success), + * indicating that the select has successfully finished. + * The next call to write() for that fd will fail but + * will also set errno properly so that we can give a + * good error message at that point. + */ + } + return 0; + } + } +} + + + +/** + * Read exactly @p len bytes from a file. + **/ +int dcc_readx(int fd, void *buf, size_t len) +{ + ssize_t r; + int ret; + + while (len > 0) { + r = read(fd, buf, len); + + if (r == -1 && errno == EAGAIN) { + if ((ret = dcc_select_for_read(fd, dcc_io_timeout))) + return ret; + else + continue; + } else if (r == -1 && errno == EAGAIN) { + continue; + } else if (r == -1) { + rs_log_error("failed to read: %s", strerror(errno)); + return EXIT_IO_ERROR; + } else if (r == 0) { + rs_log_error("unexpected eof on fd%d", fd); + return EXIT_TRUNCATED; + } else { + buf = &((char *) buf)[r]; + len -= r; + } + } + + return 0; +} + + +/** + * Write bytes to an fd. Keep writing until we're all done or something goes + * wrong. + * + * @returns 0 or exit code. + **/ +int dcc_writex(int fd, const void *buf, size_t len) +{ + ssize_t r; + int ret; + + while (len > 0) { + r = write(fd, buf, len); + + if (r == -1 && errno == EAGAIN) { + if ((ret = dcc_select_for_write(fd, dcc_io_timeout))) + return ret; + else + continue; + } else if (r == -1 && errno == EINTR) { + continue; + } else if (r == -1) { + rs_log_error("failed to write: %s", strerror(errno)); + return EXIT_IO_ERROR; + } else if (r == 0) { + rs_log_error("unexpected eof on fd%d", fd); + return EXIT_TRUNCATED; + } else { + buf = &((char *) buf)[r]; + len -= r; + } + } + + return 0; +} + + +/** + * Stick a TCP cork in the socket. It's not clear that this will help + * performance, but it might. + * + * This is a no-op if we don't think this platform has corks. + **/ +int tcp_cork_sock(int fd, int corked) +{ +#ifdef TCP_CORK + if (!dcc_getenv_bool("DISTCC_TCP_CORK", 1)) + return 0; + + if (setsockopt(fd, SOL_TCP, TCP_CORK, &corked, sizeof corked) == -1) { + if (errno == ENOSYS || errno == ENOTSUP) { + if (corked) + rs_trace("no corks allowed on fd%d", fd); + /* no need to complain about not uncorking */ + } else { + rs_log_warning("setsockopt(corked=%d) failed: %s", + corked, strerror(errno)); + /* continue anyhow */ + } + } +#endif /* def TCP_CORK */ + return 0; +} + + + +int dcc_close(int fd) +{ + if (close(fd) != 0) { + rs_log_error("failed to close fd%d: %s", fd, strerror(errno)); + return EXIT_IO_ERROR; + } + return 0; +} diff --git a/distcc/src/loadfile.c b/distcc/src/loadfile.c new file mode 100644 index 0000000..fc4b5c9 --- /dev/null +++ b/distcc/src/loadfile.c @@ -0,0 +1,113 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "exitcode.h" + + + +/** + * Load a whole file into a new string in a malloc'd memory buffer. + * + * Files larger than a certain reasonableness limit are not loaded, because + * this is only used for reasonably short text files. + * + * Files that do not exist cause EXIT_NO_SUCH_FILE, but no error message. + * (This suits our case of loading configuration files. It could be made + * optional.) + **/ +int dcc_load_file_string(const char *filename, + char **retbuf) +{ + int fd; + int ret; + ssize_t read_bytes; + struct stat sb; + char *buf; + + /* Open the file */ + if ((fd = open(filename, O_RDONLY)) == -1) { + if (errno == EEXIST) + return EXIT_NO_SUCH_FILE; + else { + rs_log_warning("failed to open %s: %s", filename, + strerror(errno)); + return EXIT_IO_ERROR; + } + } + + /* Find out how big the file is */ + if (fstat(fd, &sb) == -1) { + rs_log_error("fstat %s failed: %s", filename, strerror(errno)); + ret = EXIT_IO_ERROR; + goto out_close; + } + + if (sb.st_size > 1<<20) { + rs_log_error("%s is too large to load (%ld bytes)", filename, + (long) sb.st_size); + ret = EXIT_OUT_OF_MEMORY; + goto out_close; + } + + /* Allocate a buffer, allowing space for a nul. */ + if ((*retbuf = buf = malloc((size_t) sb.st_size + 1)) == NULL) { + rs_log_error("failed to allocate %ld byte file buffer", (long) sb.st_size); + ret = EXIT_OUT_OF_MEMORY; + goto out_close; + } + + /* Read everything */ + if ((read_bytes = read(fd, buf, (size_t) sb.st_size)) == -1) { + rs_log_error("failed to read %s: %s", filename, strerror(errno)); + ret = EXIT_IO_ERROR; + goto out_free; + } + + /* Null-terminate. It's OK if we read a bit less than we expected to. */ + buf[read_bytes] = '\0'; + ret = 0; + + out_close: + dcc_close(fd); + return ret; + + out_free: + free(*retbuf); + dcc_close(fd); + return ret; +} diff --git a/distcc/src/lock.c b/distcc/src/lock.c new file mode 100644 index 0000000..dfebf85 --- /dev/null +++ b/distcc/src/lock.c @@ -0,0 +1,271 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + /* Power is nothing without control + * -- Pirelli tyre advertisment. */ + + +/** + * @file + * + * @brief Manage lockfiles. + * + * distcc uses a simple disk-based lockfile system to keep track of how many + * jobs are queued on various machines. These locks might be used for + * something else in the future. + * + * We use locks rather than e.g. a database or a central daemon because we + * want to make sure that the lock will be removed if the client terminates + * unexpectedly. + * + * The files themselves (as opposed to the lock on them) are never cleaned up; + * since locking & creation is nonatomic I can't think of a clean way to do + * it. There shouldn't be many of them, and dead ones will be caught by the + * tmpreaper. In any case they're zero bytes. + * + * Sys V semaphores might work well here, but the interface is a bit ugly and + * they are probably not portable to Cygwin. In particular they can leak if + * the process is abruptly terminated, which is likely to happen to distcc. + */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <time.h> + +#include <sys/stat.h> +#include <sys/file.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "hosts.h" +#include "lock.h" +#include "exitcode.h" +#include "snprintf.h" + + +struct dcc_hostdef _dcc_local = { + DCC_MODE_LOCAL, + NULL, + (char *) "localhost", + 0, + NULL, + 1, /* host is_up */ + 4, /* number of tasks */ + (char *)"localhost", /* verbatim string */ + DCC_VER_1, /* protocol (ignored) */ + DCC_COMPRESS_NONE, /* compression (ignored) */ + DCC_CPP_ON_CLIENT, /* where to cpp (ignored) */ + NULL +}; + +struct dcc_hostdef *dcc_hostdef_local = &_dcc_local; + +struct dcc_hostdef _dcc_local_cpp = { + DCC_MODE_LOCAL, + NULL, + (char *) "localhost", + 0, + NULL, + 1, /* host is_up */ + 8, /* number of tasks */ + (char *)"localhost", /* verbatim string */ + DCC_VER_1, /* protocol (ignored) */ + DCC_COMPRESS_NONE, /* compression (ignored) */ + DCC_CPP_ON_CLIENT, /* where to cpp (ignored) */ + NULL +}; + +struct dcc_hostdef *dcc_hostdef_local_cpp = &_dcc_local_cpp; + + + +/** + * Returns a newly allocated buffer. + **/ +int dcc_make_lock_filename(const char *lockname, + const struct dcc_hostdef *host, + int iter, + char **filename_ret) +{ + char * buf; + int ret; + char *lockdir; + + if ((ret = dcc_get_lock_dir(&lockdir))) + return ret; + + if (host->mode == DCC_MODE_LOCAL) { + if (asprintf(&buf, "%s/%s_localhost_%d", lockdir, lockname, + iter) == -1) + return EXIT_OUT_OF_MEMORY; + } else if (host->mode == DCC_MODE_TCP) { + if (asprintf(&buf, "%s/%s_tcp_%s_%d_%d", lockdir, lockname, + host->hostname, + host->port, iter) == -1) + return EXIT_OUT_OF_MEMORY; + } else if (host->mode == DCC_MODE_SSH) { + if (asprintf(&buf, "%s/%s_ssh_%s_%d", lockdir, lockname, + host->hostname, iter) == -1) + return EXIT_OUT_OF_MEMORY; + } else { + rs_log_crit("oops"); + return EXIT_PROTOCOL_ERROR; + } + + *filename_ret = buf; + return 0; +} + + +/** + * Get an exclusive, non-blocking lock on a file using whatever method + * is available on this system. + * + * @retval 0 if we got the lock + * @retval -1 with errno set if the file is already locked. + **/ +static int sys_lock(int fd, int block) +{ +#if defined(F_SETLK) + struct flock lockparam; + + lockparam.l_type = F_WRLCK; + lockparam.l_whence = SEEK_SET; + lockparam.l_start = 0; + lockparam.l_len = 0; /* whole file */ + + return fcntl(fd, block ? F_SETLKW : F_SETLK, &lockparam); +#elif defined(HAVE_FLOCK) + return flock(fd, LOCK_EX | (block ? 0 : LOCK_NB)); +#elif defined(HAVE_LOCKF) + return lockf(fd, block ? F_LOCK : F_TLOCK, 0); +#else +# error "No supported lock method. Please port this code." +#endif +} + + + +int dcc_unlock(int lock_fd) +{ + rs_trace("release lock fd%d", lock_fd); + /* All our current locks can just be closed */ + if (close(lock_fd)) { + rs_log_error("close failed: %s", strerror(errno)); + return EXIT_IO_ERROR; + } + return 0; +} + + +/** + * Open a lockfile, creating if it does not exist. + **/ +int dcc_open_lockfile(const char *fname, int *plockfd) +{ + /* Create if it doesn't exist. We don't actually do anything with + * the file except lock it. + * + * The file is created with the loosest permissions allowed by the user's + * umask, to give the best chance of avoiding problems if they should + * happen to use a shared lock dir. */ + /* FIXME: If we fail to open with EPERM or something similar, try deleting + * the file and try again. That might fix problems with root-owned files + * in user home directories. */ + *plockfd = open(fname, O_WRONLY|O_CREAT, 0666); + if (*plockfd == -1 && errno != EEXIST) { + rs_log_error("failed to creat %s: %s", fname, strerror(errno)); + return EXIT_IO_ERROR; + } + + return 0; +} + + +/** + * Lock a server slot, in either blocking or nonblocking mode. + * + * In blocking mode, this function will not return until either the lock has + * been acquired, or an error occured. In nonblocking mode, it will instead + * return EXIT_BUSY if some other process has this slot locked. + * + * @param slot 0-based index of available slots on this host. + * @param block True for blocking mode. + * + * @param lock_fd On return, contains the lock file descriptor to allow + * it to be closed. + **/ +int dcc_lock_host(const char *lockname, + const struct dcc_hostdef *host, + int slot, int block, + int *lock_fd) +{ + char *fname; + int ret; + + /* if host is down, return EXIT_BUSY */ + if (!host->is_up) + return EXIT_BUSY; + + if ((ret = dcc_make_lock_filename(lockname, host, slot, &fname))) + return ret; + + if ((ret = dcc_open_lockfile(fname, lock_fd)) != 0) { + free(fname); + return ret; + } + + if (sys_lock(*lock_fd, block) == 0) { + rs_trace("got %s lock on %s slot %d as fd%d", lockname, + host->hostdef_string, slot, *lock_fd); + free(fname); + return 0; + } else { + switch (errno) { +#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + case EAGAIN: + case EACCES: /* HP-UX and Cygwin give this for exclusion */ + rs_trace("%s is busy", fname); + ret = EXIT_BUSY; + break; + default: + rs_log_error("lock %s failed: %s", fname, strerror(errno)); + ret = EXIT_IO_ERROR; + break; + } + + dcc_close(*lock_fd); + free(fname); + return ret; + } +} diff --git a/distcc/src/lock.h b/distcc/src/lock.h new file mode 100644 index 0000000..64320da --- /dev/null +++ b/distcc/src/lock.h @@ -0,0 +1,36 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +int dcc_lock_host(const char *lockname, + const struct dcc_hostdef *host, int slot, int block, + int *lock_fd); + +int dcc_unlock(int lock_fd); + +int dcc_make_lock_filename(const char *lockname, + const struct dcc_hostdef *host, + int iter, + char **); + +int dcc_open_lockfile(const char *fname, int *plockfd); + + diff --git a/distcc/src/lsdistcc.c b/distcc/src/lsdistcc.c new file mode 100644 index 0000000..42e8cd6 --- /dev/null +++ b/distcc/src/lsdistcc.c @@ -0,0 +1,1034 @@ +/* + * lsdistcc -- A simple distcc server discovery program + * Assumes all distcc servers are in DNS and are named distcc1...distccN. + * + * Copyright (C) 2005, 2006, 2007 by Google + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * Program to autodetect listening distcc servers by looking in DNS + * for hosts named according to a given format. + * hosts are considered good servers based solely on whether their + * name fits the format and whether they are listening on the right port + * (and optionally whether they respond when you send them a compile job). + * Stops looking for servers after the first one it doesn't find in DNS. + * Prints results to stdout. + * Terminates with error status if no servers found. + * + * Examples: + * + * In your build script, add the lines + * DISTCC_HOSTS=`lsdistcc` + * export DISTCC_HOSTS + * before the line that invokes make. + * + * Or, in your Makefile, add the lines + * export DISTCC_HOSTS = $(shell lsdistcc) + * + * Changelog: + * + * Wed Jun 20 2007 - Manos Renieris, Google + * Added -P option. + * + * Mon Jun 4 2007 - Manos Renieris, Google + * Reformatted in 80 columns. + * + * Tue Jan 31 2006 - Dan Kegel, Google + * Added -x option to list down hosts with ,down suffix (since + * in sharded server cache mode, the hash space is partitioned + * over all servers regardless of whether they're up or down at the moment) + * + * Thu Jan 5 2006 - Dan Kegel, Google + * Actually read the output from the server and partially parse it. + * + * Sat Nov 26 2005 - Dan Kegel, Google + * Added -l option, improved -v output + * + * Tue Nov 22 2005 - Dan Kegel & Dongmin Zhang, Google + * added -pcc option to check that server actually responds when you send + * it a job + * added -c0 option to disable connect check + * + * Thu Oct 13 2005 - Dan Kegel, Google + * use rslave to do asynchronous-ish hostname lookup, do all connects + * in parallel + * + * Wed Oct 5 2005 - Dan Kegel, Google + * Added -d, -m options + * + * Fri Sep 16 2005 - Dan Kegel, Google + * Created + * Added -v option +--------------------------------------------------------------------------*/ + +#include <netdb.h> +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <signal.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/poll.h> +#include <sys/time.h> +#include <netinet/in.h> + +#include "distcc.h" +#include "clinet.h" +#include "netutil.h" +#include "util.h" +#include "trace.h" +#include "rslave.h" +#include "../lzo/minilzo.h" + +enum status_e { STATE_LOOKUP = 0, + STATE_CONNECT, + STATE_CONNECTING, + STATE_READ_DONEPKT, + STATE_READ_STATPKT, + STATE_READ_REST, + STATE_CLOSE, + STATE_DONE}; + +struct state_s { + rslave_request_t req; + rslave_result_t res; + struct timeval start; + struct timeval deadline; + char curhdrbuf[12]; + int curhdrlen; + enum status_e status; + int ntries; + int fd; + int up; /* default is 0, set to 1 on success */ +}; +typedef struct state_s state_t; + +/* Default parameters */ +#define DEFAULT_FORMAT "distcc%d" /* hostname format */ +#define DEFAULT_PORT 3632 /* TCP port to connect to */ +#define DEFAULT_PROTOCOL 1 /* protocol we'll try to speak */ +#define DEFAULT_BIGTIMEOUT 7 /* max total runtime, seconds */ +#define DEFAULT_DNSTIMEOUT_MS 500 /* individual DNS timeout, msec */ +#define DEFAULT_CONNTIMEOUT_MS 900 /* individual connect timeout, msec */ +#define DEFAULT_COMPTIMEOUT_MS 1500 /* individual compile timeout, msec + (FIXME: should be lower) */ +#define DEFAULT_OVERLAP 1 /* number of simultaneous DNS queries -1 */ +#define DEFAULT_DNSGAP 0 /* number of missing hosts in DNS before + we stop looking */ +#define DEFAULT_COMPILER "none" + +char canned_query[1000]; +size_t canned_query_len = 0; + +int opt_latency = 0; +int opt_numeric = 0; +int opt_overlap = DEFAULT_OVERLAP; +int opt_dnsgap = DEFAULT_DNSGAP; +int opt_port = DEFAULT_PORT; +int opt_protocol = DEFAULT_PROTOCOL; +int opt_bigtimeout_sec = DEFAULT_BIGTIMEOUT; +int opt_conntimeout_ms = DEFAULT_CONNTIMEOUT_MS; +int opt_comptimeout_ms = DEFAULT_COMPTIMEOUT_MS; +int opt_dnstimeout_ms = DEFAULT_DNSTIMEOUT_MS; +int opt_verbose = 0; +int opt_domain = 0; +int opt_match = 0; +int opt_bang_down = 0; +const char *opt_compiler = NULL; + + +const char *protocol_suffix[] = { NULL, /* to make the rest 1-based */ + "", + ",lzo", + ",lzo,cpp" }; + +#define MAXHOSTS 500 +#define MAXTRIES 5 /* this constant can't be changed without + changing some code */ +#define MAXFDS (MAXHOSTS+2) + +/* just plain globals */ +int fd2state[MAXHOSTS+1000]; /* kludge - fragile */ +int nok; +int ndone; + +/* globals used by other compilation units */ +const char *rs_program_name = "lsdistcc"; + +/* Forward declarations (solely to prevent compiler warnings) */ +void usage(void); +int bitcompare(const unsigned char *a, const unsigned char *b, int nbits); +void timeout_handler(int x); +void get_thename(const char**sformat, const char *domain_name, + int i, char *thename); +int detect_distcc_servers(const char **argv, int argc, int opti, + int bigtimeout, int dnstimeout, int matchbits, + int overlap, int dnsgap); +void server_read_packet_header(state_t *sp); +void server_handle_event(state_t *sp); + +void usage(void) { + printf("Usage: lsdistcc [-tTIMEOUT] [-mBITS] [-nvd] [format]\n\ +Uses 'for i=1... sprintf(format, i)' to construct names of servers,\n\ +stops after %d seconds or at second server that doesn't resolve,\n\ +prints the names of all such servers listening on distcc's port.\n\ +Default format is %s. \n\ +If a list of host names are given in the command line,\n\ +lsdistcc will only check those hosts. \n\ +Options:\n\ +-l Output latency in milliseconds after each hostname\n\ + (not including DNS latency)\n\ +-n Print IP address rather than name\n\ +-x Append ,down to down hosts in host list\n\ +-tTIMEOUT Set number of seconds to stop searching after [%d]\n\ +-hHTIMEOUT Set number of milliseconds before retrying gethostbyname [%d]\n\ +-cCTIMEOUT Set number of milliseconds before giving up on connect [%d]\n\ + (0 to inhibit connect)\n\ +-kKTIMEOUT Set number of milliseconds before giving up on compile [%d]\n\ + (0 to inhibit compile)\n\ +-mBITS Set number of bits of address that must match first host found [0]\n\ +-oOVERLAP Set number of extra DNS requests to send [%d]\n\ +-gDNSGAP Set number of missing DNS entries to tolerate [%d]\n\ +-rPORT Port to connect to [%d]\n\ +-PPROTOCOL Protocol version to use (1-3) [%d]\n\ +-pCOMPILER Name of compiler to use [%s]\n\ +-d Append DNS domain name to format\n\ +-v Verbose\n\ +\n\ +Example:\n\ +lsdistcc -l -p$COMPILER\n\ +lsdistcc -p$COMPILER hosta somehost hostx hosty\n\ +", DEFAULT_BIGTIMEOUT, + DEFAULT_FORMAT, + DEFAULT_BIGTIMEOUT, + DEFAULT_DNSTIMEOUT_MS, + DEFAULT_CONNTIMEOUT_MS, + DEFAULT_COMPTIMEOUT_MS, + DEFAULT_OVERLAP, + DEFAULT_DNSGAP, + DEFAULT_PORT, + DEFAULT_PROTOCOL, + DEFAULT_COMPILER); + exit(1); +} + + +/* Compare first nbits of a[] and b[] + * If nbits is 1, only compares the MSB of a[0] and b[0] + * Return 0 on equal, nonzero on nonequal + */ +int bitcompare(const unsigned char *a, const unsigned char *b, int nbits) +{ + int fullbytes = nbits/8; + int leftoverbits = nbits & 7; + + if (fullbytes) { + int d = memcmp((char *)a, (char *)b, (size_t) fullbytes); + if (d) + return d; + } + + if (leftoverbits) { + int mask = 0; + int i; + for (i=0; i<leftoverbits; i++) + mask |= (1 << (7-i)); + /* printf("mask %x, a[%d] %x, b[%d] %x\n", mask, + fullbytes, a[fullbytes], fullbytes, b[fullbytes]); */ + return ((a[fullbytes] ^ b[fullbytes]) & mask); + } + return 0; +} + +#if 0 +#include <assert.h> +main() +{ + assert(bitcompare("0", "0", 8) == 0); + assert(bitcompare("0", "1", 8) != 0); + assert(bitcompare("0", "1", 7) == 0); +} +#endif + + +/* On timeout, silently terminate program */ +void timeout_handler(int x) +{ + (void) x; + + if (opt_verbose > 0) + fprintf(stderr, "Timeout!\n"); + + /* FIXME: is it legal to call exit here? */ + exit(0); +} + +static void generate_query(void) +{ + const char* program = "int foo(){return 0;}"; + unsigned char lzod_program[1000]; + unsigned char lzo_work_mem[LZO1X_1_MEM_COMPRESS]; + size_t lzod_program_len; + + lzo1x_1_compress((const unsigned char *)program, strlen(program), + lzod_program, &lzod_program_len, + lzo_work_mem); + + switch (opt_protocol) { + case 1: { + static const char canned_query_fmt_protocol_1[]= + "DIST00000001" + "ARGC00000005" + "ARGV%08x%s" + "ARGV00000002-c" + "ARGV00000007hello.c" + "ARGV00000002-o" + "ARGV00000007hello.o" + "DOTI%08x%s"; + sprintf(canned_query, + canned_query_fmt_protocol_1, + (unsigned)strlen(opt_compiler), opt_compiler, + (unsigned)strlen(program), program); + canned_query_len = strlen(canned_query); + break; + } + + case 2: { + static const char canned_query_fmt_protocol_2[]= + "DIST00000002" + "ARGC00000005" + "ARGV%08x%s" + "ARGV00000002-c" + "ARGV00000007hello.c" + "ARGV00000002-o" + "ARGV00000007hello.o" + "DOTI%08x"; + sprintf(canned_query, + canned_query_fmt_protocol_2, + (unsigned)strlen(opt_compiler), + opt_compiler, + (unsigned)lzod_program_len); + + canned_query_len = strlen(canned_query) + lzod_program_len; + memcpy(canned_query + strlen(canned_query), + lzod_program, lzod_program_len); + + break; + } + + case 3: { + static const char canned_query_fmt_protocol_3[]= + "DIST00000003" + "CDIR00000001/" + "ARGC00000005" + "ARGV%08x%s" + "ARGV00000002-c" + "ARGV00000007hello.c" + "ARGV00000002-o" + "ARGV00000007hello.o" + "NFIL00000001" + "NAME00000008/hello.c" + "FILE%08x"; + + sprintf(canned_query, + canned_query_fmt_protocol_3, + (unsigned)strlen(opt_compiler), + opt_compiler, + (unsigned)lzod_program_len); + + canned_query_len = strlen(canned_query) + lzod_program_len; + memcpy(canned_query + strlen(canned_query), + lzod_program, lzod_program_len); + break; + } + } +} + +/* Try reading a protocol packet header */ +void server_read_packet_header(state_t *sp) +{ + int arg; + int nread; + + nread = read(sp->fd, sp->curhdrbuf + sp->curhdrlen, + (size_t)(12 - sp->curhdrlen)); + if (nread == 0) { + /* A nonblocking read returning zero bytes means EOF. + * FIXME: it may mean this only on the first read after poll said + * bytes were ready, so beware of false EOFs here? + */ + if (opt_verbose > 0) + fprintf(stderr, "lsdistcc: premature EOF while waiting for " + "result from server %s\n", + sp->req.hname); + sp->status = STATE_CLOSE; + return; + } + + if (nread > 0) + sp->curhdrlen += nread; + + if (sp->curhdrlen < 12) + return; + + arg = (int)strtol(sp->curhdrbuf+4, NULL, 16); + + if (opt_verbose > 2) { + int i; + printf("Got hdr '%12.12s' = ", sp->curhdrbuf); + for (i=0; i < sp->curhdrlen; i++) + printf("%2x", sp->curhdrbuf[i]); + printf("\n"); + } + + /* Parse and validate the packet header, move on to next state */ + switch (sp->status) { + case STATE_READ_DONEPKT: + if (memcmp(sp->curhdrbuf, "DONE", 4) != 0) { + if (opt_verbose > 1) + fprintf(stderr, + "%s wrong protocol; expected DONE, got %4.4s!\n", + sp->req.hname, sp->curhdrbuf); + sp->status = STATE_CLOSE; + break; + } + if (arg != opt_protocol) { + if (opt_verbose > 1) + fprintf(stderr, + "%s wrong protocol, expected %d got %d!\n", + sp->req.hname, + opt_protocol, + arg); + sp->status = STATE_CLOSE; + break; + } + /* No body to this type. Read next packet. */ + sp->curhdrlen = 0; + sp->status = STATE_READ_STATPKT; + break; + + case STATE_READ_STATPKT: + if (memcmp(sp->curhdrbuf, "STAT", 4) != 0) { + if (opt_verbose > 1) + fprintf(stderr, + "%s wrong protocol! Expected STAT, got %4.4s\n", + sp->req.hname, sp->curhdrbuf); + sp->status = STATE_CLOSE; + break; + } + if (arg != 0) { + if (opt_verbose > 1) { + /* FIXME: only conditional because my server uses load shedding */ + fprintf(stderr, + "lsdistcc: warning: test compile on %s failed! " + "status 0x%x\n", + sp->req.hname, arg); + } + sp->status = STATE_CLOSE; + break; + } + /* No body to this type. Read next packet. */ + sp->curhdrlen = 0; + sp->status = STATE_READ_REST; + break; + + default: + fprintf(stderr, "bug\n"); + exit(1); + } +} + +/* Grind state machine for a single server */ +/* Take one transition through the state machine, unless that takes you + to STATE_CLOSE, in which case go through that state too, into STATE_DONE + */ + +void server_handle_event(state_t *sp) +{ + struct timeval now; + gettimeofday(&now, 0); + + do { + struct sockaddr_in sa; + + if (opt_verbose > 2) + fprintf(stderr, + "now %ld %ld: server_handle_event: %s: state %d\n", + now.tv_sec, now.tv_usec/1000, sp->req.hname, sp->status); + + switch (sp->status) { + case STATE_CONNECT: + if (opt_conntimeout_ms == 0) { + sp->fd = -1; + sp->up = 1; + sp->status = STATE_CLOSE; + break; + } + + /* Now do a nonblocking connect to that address */ + memset(&sa, 0, sizeof sa); + sa.sin_family = AF_INET; + sa.sin_port = htons(opt_port); + memcpy(&sa.sin_addr, sp->res.addr, 4); + + if ((sp->fd = socket(sa.sin_family, SOCK_STREAM, 0)) == -1) { + fprintf(stderr, "failed to create socket: %s", strerror(errno)); + sp->status = STATE_DONE; + } else { + dcc_set_nonblocking(sp->fd); + /* start the nonblocking connect... */ + if (opt_verbose > 0) + fprintf(stderr, + "now %ld %ld: Connecting to %s\n", + now.tv_sec, now.tv_usec/1000, sp->req.hname); + if (connect(sp->fd, (struct sockaddr *)&sa, sizeof(sa)) + && errno != EINPROGRESS) { + if (opt_verbose > 0) + fprintf(stderr, "failed to connect socket: %s", + strerror(errno)); + sp->status = STATE_CLOSE; + } else { + sp->status = STATE_CONNECTING; + fd2state[sp->fd] = sp->res.id; + gettimeofday(&now, 0); + sp->start = now; + sp->deadline = now; + sp->deadline.tv_usec += 1000 * opt_conntimeout_ms; + sp->deadline.tv_sec += sp->deadline.tv_usec / 1000000; + sp->deadline.tv_usec = sp->deadline.tv_usec % 1000000; + } + } + break; + case STATE_CONNECTING: + { + int connecterr; + socklen_t len = sizeof(connecterr); + int nsend; + int nsent; + + if (getsockopt(sp->fd, SOL_SOCKET, SO_ERROR, + (char *)&connecterr, &len) < 0) { + fprintf(stderr, "getsockopt SO_ERROR failed?!"); + sp->status = STATE_CLOSE; + break; + } + if (connecterr) { + if (opt_verbose > 0) + fprintf(stderr, + "now %ld %ld: Connecting to %s failed " + "with errno %d = %s\n", + now.tv_sec, now.tv_usec/1000, sp->req.hname, + connecterr, strerror(connecterr)); + sp->status = STATE_CLOSE; /* not listening */ + break; + } + if (opt_comptimeout_ms == 0 || !opt_compiler) { + /* connect succeeded, don't need to compile */ + sp->up = 1; + sp->status = STATE_CLOSE; + break; + } + if (opt_verbose > 0) + fprintf(stderr, + "now %ld %ld: %s: sending compile request\n", + now.tv_sec, now.tv_usec/1000, sp->req.hname); + nsend = canned_query_len; + nsent = write(sp->fd, canned_query, nsend); + if (nsent != nsend) { + if (opt_verbose > 1) { + if (nsent == -1) + fprintf(stderr, + "now %ld %ld: Sending to %s failed, " + "errno %d\n", + now.tv_sec, now.tv_usec/1000, sp->req.hname, + connecterr); + else + fprintf(stderr, + "now %ld %ld: Sending to %s failed, " + "nsent %d != nsend %d\n", + now.tv_sec, now.tv_usec/1000, + sp->req.hname, nsent, nsend); + } + /* ??? remote disconnect? Buffer too small? */ + sp->status = STATE_CLOSE; + break; + } + sp->status=STATE_READ_DONEPKT; + sp->curhdrlen = 0; + sp->deadline = now; + sp->deadline.tv_usec += 1000 * opt_comptimeout_ms; + sp->deadline.tv_sec += sp->deadline.tv_usec / 1000000; + sp->deadline.tv_usec = sp->deadline.tv_usec % 1000000; + } + break; + + case STATE_READ_DONEPKT: + case STATE_READ_STATPKT: + server_read_packet_header(sp); + break; + + case STATE_READ_REST: + { + char buf[1000]; + int nread; + nread = read(sp->fd, buf, sizeof(buf)); + if (nread == 0) { + /* A nonblocking read returning zero bytes means EOF. + * FIXME: it may mean this only on the first read after + * poll said bytes were ready, so beware of false EOFs here? + */ + sp->up = 1; + sp->status = STATE_CLOSE; + } + } + break; + + case STATE_CLOSE: + if (sp->fd != -1) { + close(sp->fd); + sp->fd = -1; + } + + if (opt_bang_down || sp->up) { + if (opt_numeric) + printf("%d.%d.%d.%d", sp->res.addr[0], sp->res.addr[1], + sp->res.addr[2], sp->res.addr[3]); + else + printf("%s", sp->req.hname); + + printf("%s", protocol_suffix[opt_protocol]); + + if (opt_bang_down && !sp->up) + printf(",down"); + + if (opt_latency) { + int latency_ms; + gettimeofday(&now, 0); + latency_ms = (now.tv_usec - sp->start.tv_usec) / + 1000 + 1000 * (now.tv_sec - sp->start.tv_sec); + printf(" %d", latency_ms); + } + putchar('\n'); + if (opt_verbose) + fflush(stdout); + } + nok++; + sp->status = STATE_DONE; + ndone++; + break; + + case STATE_DONE: + ; + default: + ; + } + } while (sp->status == STATE_CLOSE); +} + +/* Get the name based on the sformat. If the first element in sformat is a + * format, ignore the rest, and use the format to generate the series of names; + * otherwise, copy the name from sformat. Attach domain_name if needed. + */ +void get_thename(const char**sformat, const char *domain_name, int i, + char *thename) +{ + if (strstr(sformat[0], "%d") != NULL) + sprintf(thename, sformat[0], i); + else + strcpy(thename, sformat[i-1]); + if (opt_domain) { + strcat(thename, "."); + strcat(thename, domain_name); + } +} + +/* Detect all listening distcc servers and print their names to stdout. + * Looks for servers numbered 1 through infinity, stops at + * first server that doesn't resolve in DNS, or after 'timeout' seconds, + * whichever comes first. + * On entry: + * sformat: format of names of distcc servers to check + * bigtimeout: how many seconds to terminate slow run after + * dnstimeout: how many milliseconds before retrying a particular + * gethostbyname call + * matchbits: top matchbits of address must match first host found, + else stop searching + * overlap: how many extra DNS queries to keep in flight normally + * dnsgap: how many missing DNS entries to tolerate + * On exit: + * returns number of servers found. + */ +int detect_distcc_servers(const char **argv, int argc, int opti, + int bigtimeout, int dnstimeout, + int matchbits, int overlap, int dnsgap) +{ + unsigned char firstipaddr[4]; + int dnstimeout_usec = dnstimeout * 1000; /* how long before + resending gethostbyname */ + int n = MAXHOSTS; + int i; + char thename[256]; + struct pollfd pollfds[MAXFDS]; + + struct state_s states[MAXHOSTS+1]; + int ngotaddr; + int nbaddns; + int nwithtries[MAXTRIES+1]; + int nfds; + + struct rslave_s rs; + + const char **sformat; + const char *domain_name; + if (opt_domain) { + if (dcc_get_dns_domain(&domain_name)) { + fprintf(stderr, "Can't get domain name\n"); + exit(1); + } + } + + if (opti < argc) { + if (strstr(argv[opti], "%d") != NULL) { + sformat = &argv[opti++]; + } else { + /* A list of host names can be given in the command line */ + n = argc-opti; + sformat = &argv[opti++]; + } + } else { + const char *format = DEFAULT_FORMAT; + sformat = &format; + } + + /* Don't run longer than bigtimeout seconds */ + signal(SIGALRM, timeout_handler); + alarm((unsigned) bigtimeout); + + if (rslave_init(&rs)) + return 0; + + ngotaddr = 0; + memset(nwithtries, 0, sizeof(nwithtries)); + memset(pollfds, 0, sizeof(pollfds)); + memset(states, 0, sizeof(states)); + + /* all hosts start off in state 'sent 0' */ + for (i=1; i<=n; i++) { + rslave_request_t *req = &states[i].req; + get_thename(sformat, domain_name, i, thename); + rslave_request_init(req, thename, i); + states[i].status = STATE_LOOKUP; + states[i].ntries = 0; + nwithtries[0]++; + } + + ndone = 0; + nok = 0; + nbaddns = 0; + /* Loop until we're done finding distcc servers */ + while (ndone < n) { + struct state_s *sp; + int nready; + int found; + struct timeval now; + + /* See which sockets have any events */ + nfds = 0; + pollfds[nfds].fd = rslave_getfd_fromSlaves(&rs); + pollfds[nfds++].events = POLLIN; + pollfds[nfds].fd = rslave_getfd_toSlaves(&rs); + /* Decide if we want to be notified if slaves are ready to handle + * a DNS request. + * To avoid sending too many DNS requests, we avoid sending more if + * the number of first tries is greater than 'overlap' + * or the number of outstanding DNS requests plus the number of + * already satisfied ones would be greater than or equal to the max + * number of hosts we're looking for. + */ + pollfds[nfds++].events = ((nwithtries[1] <= overlap) && + (nwithtries[1]+ + nwithtries[2]+ + nwithtries[3]+ + nwithtries[4]+ + ngotaddr < n)) ? POLLOUT : 0; + /* Set interest bits. + * When connecting, we want to know if we can write (aka if the + * connect has finished); when waiting for a compile to finish, + * we want to know if we can read. + */ + for (i=1; i<=n; i++) { + switch (states[i].status) { + case STATE_CONNECTING: + pollfds[nfds].fd = states[i].fd; + pollfds[nfds++].events = POLLOUT; + break; + case STATE_READ_DONEPKT: + case STATE_READ_STATPKT: + case STATE_READ_REST: + pollfds[nfds].fd = states[i].fd; + pollfds[nfds++].events = POLLIN; + break; + default: ; + } + } + /* When polling, wait for no more than 50 milliseconds. + * Anything lower doesn't help performance much. + * Anything higher would inflate all our timeouts, + * cause retries not to be sent as soon as they should, + * and make the program take longer than it should. + */ + nready = poll(pollfds, (unsigned)nfds, 50); + gettimeofday(&now, 0); + + + /***** Check for timeout events *****/ + sp = NULL; + found = FALSE; + for (i=1; i<=n; i++) { + sp = &states[i]; + if (sp->status == STATE_LOOKUP + && sp->ntries > 0 && sp->ntries < MAXTRIES + && (sp->deadline.tv_sec < now.tv_sec || + (sp->deadline.tv_sec == now.tv_sec && + sp->deadline.tv_usec < now.tv_usec))) { + found = TRUE; + nwithtries[sp->ntries]--; + sp->ntries++; + nwithtries[sp->ntries]++; + if (opt_verbose > 0) + fprintf(stderr, + "now %ld %ld: Resending %s because " + "deadline was %ld %ld\n", + now.tv_sec, now.tv_usec/1000, sp->req.hname, + sp->deadline.tv_sec, sp->deadline.tv_usec/1000); + break; + } + + if (sp->status == STATE_CONNECTING + && (sp->deadline.tv_sec < now.tv_sec || + (sp->deadline.tv_sec == now.tv_sec && + sp->deadline.tv_usec < now.tv_usec))) { + sp->status = STATE_CLOSE; + server_handle_event(sp); + if (opt_verbose > 0) + fprintf(stderr, + "now %ld %ld: %s timed out while connecting\n", + now.tv_sec, now.tv_usec/1000, sp->req.hname); + } + if ((sp->status == STATE_READ_DONEPKT || + sp->status == STATE_READ_STATPKT || + sp->status == STATE_READ_REST) + && (sp->deadline.tv_sec < now.tv_sec || + (sp->deadline.tv_sec == now.tv_sec && + sp->deadline.tv_usec < now.tv_usec))) { + sp->status = STATE_CLOSE; + server_handle_event(sp); + if (opt_verbose > 0) + fprintf(stderr, + "now %ld %ld: %s timed out while compiling\n", + now.tv_sec, now.tv_usec/1000, sp->req.hname); + } + } + if (!found && (nwithtries[1] <= overlap) && + (pollfds[1].revents & POLLOUT)) { + /* Look for a fresh record to send */ + for (i=1; i<=n; i++) { + sp = &states[i]; + if (sp->status == STATE_LOOKUP && sp->ntries == 0) { + found = TRUE; + nwithtries[sp->ntries]--; + sp->ntries++; + nwithtries[sp->ntries]++; + break; + } + } + } + /* If we found a record to send or resend, send it, + and mark its timeout. */ + if (found) { + if (opt_verbose) + fprintf(stderr, "now %ld %ld: Looking up %s\n", + now.tv_sec, now.tv_usec/1000, sp->req.hname); + rslave_writeRequest(&rs, &sp->req); + sp->deadline = now; + sp->deadline.tv_usec += dnstimeout_usec; + sp->deadline.tv_sec += sp->deadline.tv_usec / 1000000; + sp->deadline.tv_usec = sp->deadline.tv_usec % 1000000; + } + + /***** Check poll results for DNS results *****/ + if (pollfds[0].revents & POLLIN) { + /* A reply is ready, huzzah! */ + rslave_result_t result; + if (rslave_readResult(&rs, &result)) { + printf("bug: can't read from pipe\n"); + } else { + /* Find the matching state_t, save the result, + and mark it as done */ + /* printf("result.id %d\n", result.id); fflush(stdout); */ + assert(result.id > 0 && result.id <= n); + sp = &states[result.id]; + if (sp->status == STATE_LOOKUP) { + nwithtries[sp->ntries]--; + sp->res = result; + ngotaddr++; + if (matchbits > 0) { + if (ngotaddr == 1) { + memcpy(firstipaddr, result.addr, 4); + } else { + /* break if new server on a 'different network' + than first server */ + if (bitcompare(firstipaddr, result.addr, matchbits)) + result.err = -1; + } + } + + if (result.err) { + if (opt_verbose) + fprintf(stderr, "now %ld %ld: %s not found\n", + now.tv_sec, now.tv_usec/1000, + sp->req.hname); + sp->status = STATE_DONE; + ndone++; + nbaddns++; + if (nbaddns > dnsgap) { + int highest = 0; + /* start no more lookups */ + for (i=1; i <= n; i++) + if (states[i].ntries > 0) + highest = i; + assert(highest <= n); + if (opt_verbose && n != highest) + fprintf(stderr, + "Already searching up to host %d, " + "won't search any higher\n", + highest); + n = highest; + assert(n <= MAXHOSTS); + } + } else { + sp->status = STATE_CONNECT; + server_handle_event(sp); + } + } + } + } + + /***** Grind state machine for each remote server *****/ + for (i=2; i<nfds && i < MAXFDS; i++) { + sp = states + fd2state[pollfds[i].fd]; /* FIXME */ + if (pollfds[i].revents) + server_handle_event(sp); + } + } + return nok; +} + +int main(int argc, char **argv) +{ + int opti; + int nfound; + + for (opti = 1; opti < argc && argv[opti][0] == '-'; opti++) { + switch (argv[opti][1]) { + case 'm': + opt_match = atoi(argv[opti]+2); + if (opt_match > 31 || opt_match < 0) + usage(); + break; + case 't': + opt_bigtimeout_sec = atoi(argv[opti]+2); + if (opt_bigtimeout_sec < 0) + usage(); + break; + case 'h': + opt_dnstimeout_ms = atoi(argv[opti]+2); + if (opt_dnstimeout_ms < 0) + usage(); + break; + case 'c': + opt_conntimeout_ms = atoi(argv[opti]+2); + if (opt_conntimeout_ms < 0) + usage(); + break; + case 'k': + opt_comptimeout_ms = atoi(argv[opti]+2); + if (opt_comptimeout_ms < 0) + usage(); + break; + case 'o': + opt_overlap = atoi(argv[opti]+2); + if (opt_overlap < 0) + usage(); + break; + case 'g': + opt_dnsgap = atoi(argv[opti]+2); + if (opt_dnsgap < 0) + usage(); + break; + case 'P': + opt_protocol = atoi(argv[opti]+2); + if (opt_protocol <= 0 || opt_protocol > 3) { + usage(); + } + break; + case 'p': + opt_compiler = argv[opti]+2; + if (! *opt_compiler) + usage(); + break; + case 'r': + opt_port = atoi(argv[opti]+2); + if (opt_port <= 0) + usage(); + break; + case 'l': + opt_latency = 1; + break; + case 'n': + opt_numeric = 1; + break; + case 'x': + opt_bang_down = 1; + break; + case 'v': + opt_verbose++; + break; + case 'd': + opt_domain++; + break; + default: + usage(); + } + } + + if (opt_compiler) + generate_query(); + + nfound = detect_distcc_servers((const char **)argv, argc, opti, + opt_bigtimeout_sec, + opt_dnstimeout_ms, + opt_match, + opt_overlap, + opt_dnsgap); + + /* return failure if no servers found */ + return (nfound > 0) ? 0 : 1; +} diff --git a/distcc/src/mon-gnome.c b/distcc/src/mon-gnome.c new file mode 100644 index 0000000..376fcc0 --- /dev/null +++ b/distcc/src/mon-gnome.c @@ -0,0 +1,673 @@ +/* -*- c-file-style: "k&r"; c-basic-offset: 4; indent-tabs-mode: nil; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* + * @file + * + * Gnome 2.x monitor for distcc. + * + * For each slot we have a record in a tree model, including an array + * indicating the past states. This is stored in the "history" column + * of the TreeMode for that slot. + * + * The renderer knows how to walk over the queue and draw state + * rectangles for the values it finds. The queue is implemented as a + * circular array, whose values are initialized to idle. + * + * Starved jobs are currently not shown in the chart view. + * + * Colors should perhaps be customizable with reasonable defaults. + */ + +/* FIXME: When the dialogs are dismissed, they seem to get destroyed. + We need to make sure that they just get hidden and can be summoned + again. */ + + +/* last one using chart drawingarea is 1.43.2.37 */ + +#include "config.h" + +#include <sys/types.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <pwd.h> +#include <unistd.h> + +#ifdef HAVE_SYS_LOADAVG_H +# include <sys/loadavg.h> +#endif + +#ifdef WITH_GNOME +# include <gnome.h> +#endif + +#include <gtk/gtk.h> + +#include "types.h" +#include "distcc.h" +#include "rpc.h" +#include "trace.h" +#include "exitcode.h" +#include "mon.h" +#include "renderer.h" + + +const char *rs_program_name = "distccmon-gnome"; + + +static GtkWidget *chart_treeview; + + + +static GtkListStore *chart_model; + + + +/* Note: these must match the types given in order in the call to + gtk_list_store_new() */ +enum { + COLUMN_HOST, + COLUMN_SLOT, + COLUMN_FILE, + COLUMN_STATE, + COLUMN_HISTORY, +}; + + +/** + * Graphics contexts to be used to draw each particular state into the + * model. + **/ +GdkGC *dcc_phase_gc[DCC_PHASE_DONE]; + + +#if 0 +/* shades of red */ +const GdkColor task_color[] = { + { 0, 0x2222, 0, 0 }, /* DCC_PHASE_STARTUP, */ + { 0, 0x4444, 0, 0 }, /* DCC_PHASE_BLOCKED, */ + { 0, 0x6666, 0, 0 }, /* DCC_PHASE_CONNECT, */ + { 0, 0x8888, 0, 0 }, /* DCC_PHASE_CPP, */ + { 0, 0xaaaa, 0, 0 }, /* DCC_PHASE_SEND, */ + { 0, 0xcccc, 0, 0 }, /* DCC_PHASE_COMPILE, */ + { 0, 0xeeee, 0, 0 }, /* DCC_PHASE_RECEIVE, */ + { 0, 0xffff, 0xffff, 0 }, /* DCC_PHASE_DONE */ +}; +#endif + +/* + * Colors used for drawing different state stripes. First GdkColor + * field is the assigned color index and zero here. + * + * These color names are from the GNOME standard palette. + */ +const GdkColor task_color[] = { + { 0, 0x9999, 0, 0 }, /* DCC_PHASE_STARTUP, accent red dark */ + { 0, 0x9999, 0, 0 }, /* DCC_PHASE_BLOCKED, accent red dark */ + { 0, 0xc1c1, 0x6666, 0x5a5a }, /* DCC_PHASE_CONNECT, red medium */ + { 0, 0x8888, 0x7f7f, 0xa3a3 }, /* DCC_PHASE_CPP, purple medium*/ + { 0, 0xe0e0, 0xc3c3, 0x9e9e }, /* DCC_PHASE_SEND, face skin medium*/ + { 0, 0x8383, 0xa6a6, 0x7f7f }, /* DCC_PHASE_COMPILE, green medium */ + { 0, 0x7575, 0x9090, 0xaeae }, /* DCC_PHASE_RECEIVE, blue medium*/ + { 0, 0, 0, 0 }, /* DCC_PHASE_DONE */ +}; + + +static void +dcc_setup_tree_model (void) +{ + /* Create a table for process status */ + chart_model = gtk_list_store_new (5, + G_TYPE_STRING, /* host */ + G_TYPE_INT, /* slot */ + G_TYPE_STRING, /* file */ + G_TYPE_STRING, /* state */ + G_TYPE_POINTER /* history */ + ); +} + + +static void +dcc_row_history_push (GtkListStore *model, + GtkTreeIter *tree_iter, + enum dcc_phase new_state) +{ + struct dcc_history *history; + + gtk_tree_model_get(GTK_TREE_MODEL (model), tree_iter, + COLUMN_HISTORY, &history, + -1); + + dcc_history_push(history, new_state); + + /* Perhaps we should call gtk_tree_model_row_changed(), but at the + moment every call to this is associated with some other change to + the model so I don't think there's any need. */ +} + + + +static void +dcc_set_row_from_task (GtkListStore *model, + GtkTreeIter *tree_iter, + struct dcc_task_state *task) +{ + dcc_row_history_push (model, tree_iter, task->curr_phase); + + gtk_list_store_set (model, tree_iter, + COLUMN_HOST, task->host, + COLUMN_SLOT, task->slot, + COLUMN_FILE, task->file, + COLUMN_STATE, dcc_get_phase_name(task->curr_phase), + -1); +} + + +static void +dcc_insert_row_from_task (GtkListStore *model, + GtkTreeIter *tree_iter, + GtkTreeIter *insert_before, + struct dcc_task_state *task_iter) +{ + struct dcc_history *history; + + history = dcc_history_new(); + + dcc_history_push(history, task_iter->curr_phase); + + gtk_list_store_insert_before(chart_model, tree_iter, insert_before); + + gtk_list_store_set(model, tree_iter, + COLUMN_HOST, task_iter->host, + COLUMN_SLOT, task_iter->slot, + COLUMN_FILE, task_iter->file, + COLUMN_STATE, dcc_get_phase_name(task_iter->curr_phase), + COLUMN_HISTORY, history, + -1); +} + + +static void +dcc_set_row_idle(GtkListStore *model, + GtkTreeIter *tree_iter) +{ + struct dcc_history *history; + + gtk_tree_model_get(GTK_TREE_MODEL (model), tree_iter, + COLUMN_HISTORY, &history, + -1); + + /* only write to the treemodel if it was previously non-idle */ + if (history->past_phases[history->now] != DCC_PHASE_DONE) { + gtk_list_store_set (model, tree_iter, + COLUMN_FILE, NULL, + COLUMN_STATE, NULL, + -1); + } else { + /* it still changed... */ + GtkTreePath *path; + + path = gtk_tree_model_get_path(GTK_TREE_MODEL(model), tree_iter); + gtk_tree_model_row_changed(GTK_TREE_MODEL(model), path, tree_iter); + gtk_tree_path_free(path); + } + + dcc_history_push(history, DCC_PHASE_DONE); +} + + +/** + * + * We update the list model in place by looking for slots which have a + * different state to last time we polled. + * + * mon.c always returns state records to us in a consistent order, + * sorted by hostname and then by slot. The list model is always held + * in the same order. Over time some slots may become empty, or some + * new slots may be used. + * + * Walking through the task list and the tree store in order makes it + * fairly easy to see where tasks have been inserted, removed, or + * changed. + * + * When there is no task for a row, we don't remove the row from the + * list model. This is for two reasons: one is that it stops rows + * bouncing around too much when they're not fully loaded. In the + * future when we draw a state history, this will allow rows to + * persist showing what they did in the past, even if they're doing + * nothing now. + * + * Every time through, we update each table row exactly once, whether + * that is adding new state, settting it back to idle, or inserting + * it. In particular, on each pass we add one value to the start of + * every state history. + **/ +static void +dcc_update_store_from_tasks (struct dcc_task_state *task_list) +{ + struct dcc_task_state *task_iter; + GtkTreeIter tree_iter[1]; + gboolean tree_valid; + int cmp; + GtkTreeModel *tree_model = GTK_TREE_MODEL (chart_model); + + tree_valid = gtk_tree_model_get_iter_first (tree_model, tree_iter); + + for (task_iter = task_list; + task_iter != NULL && tree_valid; + ) + { + gchar *row_host; + int row_slot; + + if (task_iter->curr_phase == DCC_PHASE_DONE + || task_iter->host[0] == '\0' + || task_iter->file[0] == '\0') + { + /* skip this */ + task_iter = task_iter->next; + continue; + } + + gtk_tree_model_get (tree_model, tree_iter, + COLUMN_HOST, &row_host, + COLUMN_SLOT, &row_slot, + -1); + + cmp = strcmp (task_iter->host, row_host); + if (cmp == 0) + cmp = task_iter->slot - row_slot; + g_free(row_host); + +/* g_message ("host %s, slot %d, file %s -> cmp=%d", */ +/* task_iter->host, task_iter->slot, task_iter->file, cmp); */ + + /* What is the relative order of the task and the row, based on + host and slot? */ + if (cmp == 0) + { + /* If the task and row match, then update the row from the + task if necessary */ + dcc_set_row_from_task (chart_model, tree_iter, task_iter); + /* Proceed to next task and row */ + task_iter = task_iter->next; + } + else if (cmp < 0) + { + /* If this task comes before the row, then the task must be + on a slot that is not yet on the table store. Insert + a row. */ +/* g_message ("insert row for host %s, slot %d", */ +/* task_iter->host, task_iter->slot); */ + dcc_insert_row_from_task (chart_model, tree_iter, tree_iter, + task_iter); + /* Proceed to next task and the row after the one we just + inserted. */ + task_iter = task_iter->next; + } + else /* cmp > 0 */ + { + /* If this row comes before the current task, then the row + must be for a slot that's no longer in use. Clear the + row */ + dcc_set_row_idle (chart_model, tree_iter); + /* Compare next row against the same task */ + } + + tree_valid = gtk_tree_model_iter_next (tree_model, tree_iter); + } + + /* If we finished the tree before we finished the task list, then + just insert all the others at the end. */ + for (; + task_iter != NULL; + task_iter = task_iter->next) + { + if (task_iter->curr_phase == DCC_PHASE_DONE) + continue; + if (task_iter->host[0] == '\0' + || task_iter->file[0] == '\0') + continue; + +/* g_message ("append row for host %s, slot %d", */ +/* task_iter->host, task_iter->slot); */ + + dcc_insert_row_from_task (chart_model, tree_iter, + NULL, /* insert at end */ + task_iter); + } + + /* If we finished the task list before we finished the rows, clear all + the others. */ + for (; + tree_valid; + tree_valid = gtk_tree_model_iter_next (tree_model, tree_iter)) + { +/* g_message ("clobber row"); */ + dcc_set_row_idle (chart_model, tree_iter); + } +} + + + +/** + * Callback when the timer triggers, causing a refresh. Loads the + * current state from the state monitor and puts it into the table + * model, which should then redraw itself. + **/ +static gint dcc_gnome_update_cb (gpointer UNUSED(view_void)) +{ + struct dcc_task_state *task_list; + + if (dcc_mon_poll (&task_list)) + { + rs_log_warning("poll failed"); + return TRUE; + } + + dcc_update_store_from_tasks (task_list); + + dcc_task_state_free (task_list); + + return TRUE; /* please call again */ +} + + +static gchar *dcc_gnome_get_title (void) +{ + char host[256]; + const char *user; + struct passwd *pw; + + if (gethostname(host, sizeof host) == -1) + strcpy (host, "localhost"); + + /* We need to look up from our pid rather than using $LOGIN or $USER because + that's consistent with the monitor routines. Otherwise you might + get strange results from "sudo distccmon-gnome". */ + user = NULL; + pw = getpwuid (getuid ()); + if (pw) + user = pw->pw_name; + if (!user) + user = ""; + + return g_strdup_printf ("distcc Monitor - %s@%s", + user, host); +} + + +static gint dcc_gnome_load_update_cb (gpointer data) +{ + gchar message[200]; + double loadavg[3]; + guint context_id; + + if (getloadavg (loadavg, 3) == -1) + { + rs_log_error ("getloadavg failed: %s", strerror (errno)); + return FALSE; /* give up */ + } + + snprintf (message, sizeof message, + "Load average: %.2f, %.2f, %.2f", + loadavg[0], loadavg[1], loadavg[2]); + + context_id = gtk_statusbar_get_context_id(GTK_STATUSBAR (data), "load"); + + gtk_statusbar_pop(GTK_STATUSBAR (data), context_id); + gtk_statusbar_push(GTK_STATUSBAR (data), context_id, message); + + return TRUE; /* please call again */ +} + + +/** + * Initialize graphics context for drawing into a widget in the right + * color for each state. + **/ +static void +dcc_create_state_gcs (GtkWidget *widget) +{ + enum dcc_phase i_state; + + for (i_state = 0; i_state < DCC_PHASE_DONE; i_state++) + { + dcc_phase_gc[i_state] = gdk_gc_new (widget->window); + gdk_gc_set_rgb_fg_color (dcc_phase_gc[i_state], + (GdkColor *) &task_color[i_state]); + + } +} + + +/** + * Configure GtkTreeView with the right columns bound to + * renderers, and a data model. + **/ +static void dcc_gnome_make_proc_view (GtkTreeModel *proc_model, + GtkWidget **align_return) +{ + GtkCellRenderer *text_renderer, *chart_renderer; + GtkTreeSelection *selection; + GtkTreeViewColumn *column; + GtkWidget *align, *proc_scroll; + + chart_treeview = gtk_tree_view_new_with_model (proc_model); + gtk_object_set (GTK_OBJECT (chart_treeview), + "headers-visible", TRUE, + NULL); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (chart_treeview)); + + gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE); + + /* we can't create the gcs until the widget is first realized */ + g_signal_connect_after (chart_treeview, "realize", + G_CALLBACK (dcc_create_state_gcs), NULL); + + text_renderer = gtk_cell_renderer_text_new (); + chart_renderer = dcc_cell_renderer_chart_new (); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (chart_treeview)); + + gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE); + + /* Host */ + column = gtk_tree_view_column_new_with_attributes + ("Host", text_renderer, + "text", COLUMN_HOST, + NULL); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (chart_treeview), column); +/* gtk_tree_view_column_set_sort_column_id (column, COLUMN_HOST); */ + + column = gtk_tree_view_column_new_with_attributes + ("Slot", text_renderer, + "text", COLUMN_SLOT, + NULL); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (chart_treeview), column); + + /* File */ + column = gtk_tree_view_column_new_with_attributes + ("File", text_renderer, + "text", COLUMN_FILE, + NULL); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (chart_treeview), column); + + column = gtk_tree_view_column_new_with_attributes + ("State", text_renderer, + "text", COLUMN_STATE, + NULL); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (chart_treeview), column); + + /* Tasks - for each cell, rebind the stock-id property onto that + value from the table model */ + column = gtk_tree_view_column_new_with_attributes + ("Tasks", chart_renderer, + "history", COLUMN_HISTORY, + NULL); + gtk_tree_view_column_set_resizable (column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (chart_treeview), column); + + proc_scroll = gtk_scrolled_window_new (NULL, NULL); + + /* no horizontal scrolling; let the table stretch */ + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (proc_scroll), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + gtk_container_add (GTK_CONTAINER (proc_scroll), chart_treeview); + + /* Expands to fill all space */ + align = gtk_alignment_new (0.0, 0.0, 1.0, 1.0); + gtk_container_add (GTK_CONTAINER (align), proc_scroll); + + *align_return = align; +} + + +static GtkWidget * dcc_gnome_make_load_bar (void) +{ + GtkWidget *bar; + gint context_id; + + bar = gtk_statusbar_new (); + context_id = gtk_statusbar_get_context_id(GTK_STATUSBAR (bar), "load"); + + gtk_statusbar_push(GTK_STATUSBAR (bar), context_id, "Load: "); + + g_timeout_add (2000, /* ms */ + dcc_gnome_load_update_cb, + bar); + + dcc_gnome_load_update_cb (bar); + + return bar; +} + + +static GtkWidget * dcc_gnome_make_mainwin (void) +{ + GtkWidget *mainwin; + + mainwin = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + { + char *title; + title = dcc_gnome_get_title (); + + gtk_window_set_title (GTK_WINDOW (mainwin), + title); + free (title); + } + + /* Set a reasonable default size that allows all columns and a few + rows to be seen with a typical theme */ + gtk_window_set_default_size (GTK_WINDOW (mainwin), 500, 300); + + /* Quit when it's closed */ + g_signal_connect (GTK_OBJECT(mainwin), "delete-event", + G_CALLBACK (gtk_main_quit), NULL); + g_signal_connect (GTK_OBJECT(mainwin), "destroy", + G_CALLBACK (gtk_main_quit), NULL); + +#if GTK_CHECK_VERSION(2,2,0) + gtk_window_set_icon_from_file (GTK_WINDOW (mainwin), + PKGDATADIR "/distccmon-gnome-icon.png", + NULL); +#endif + + return mainwin; +} + + +static int dcc_gnome_make_app (void) +{ + GtkWidget *topbox, *proc_align, *load_bar; + GtkWidget *mainwin; + + /* Create the main window */ + mainwin = dcc_gnome_make_mainwin (); + + /* Create a vbox for the contents */ + topbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (mainwin), + topbox); + + load_bar = dcc_gnome_make_load_bar (); + + dcc_setup_tree_model (); + dcc_gnome_make_proc_view (GTK_TREE_MODEL (chart_model), + &proc_align); + gtk_container_add (GTK_CONTAINER (topbox), + proc_align); + + gtk_box_pack_end (GTK_BOX (topbox), + load_bar, + FALSE, /* expand */ + FALSE, + 0); + + g_timeout_add_full (G_PRIORITY_HIGH_IDLE, + 500, /* ms */ + dcc_gnome_update_cb, + NULL, + NULL); + /* Show the application window */ + gtk_widget_show_all (mainwin); + + return 0; +} + + + +int main(int argc, char **argv) +{ + /* We don't want to take too much time away from the real work of + * compilation */ + nice(5); + +#if defined(WITH_GNOME) + gnome_program_init ("distccmon-gnome", PACKAGE_VERSION, + LIBGNOMEUI_MODULE, + argc, argv, NULL); +#elif defined(WITH_GTK) + gtk_init (&argc, &argv); +#else +# error This program must be built with either WITH_GTK or WITH_GNOME +#endif + + /* do our own initialization */ + dcc_gnome_make_app (); + + /* Keep running until quit */ + gtk_main (); + + return 0; +} diff --git a/distcc/src/mon-notify.c b/distcc/src/mon-notify.c new file mode 100644 index 0000000..8691e7f --- /dev/null +++ b/distcc/src/mon-notify.c @@ -0,0 +1,125 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include "config.h" + +#include <sys/types.h> +#include <sys/stat.h> + +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> + +#include <dirent.h> + +#include "types.h" +#include "rpc.h" +#include "distcc.h" +#include "trace.h" +#include "exitcode.h" +#include "snprintf.h" +#include "mon.h" +#include "util.h" +#include "netutil.h" + + + + +static volatile int pipe_fd[2]; + + +static void dcc_mon_siginfo_handler (int UNUSED (whatsig)) +{ + /* Just ignore any errors. If people aren't listening or the pipe + * is full, too bad. */ + write (pipe_fd[1], "*", 1); +} + + +/* + * Try to setup dnotify on the state directory. This returns the + * descriptor of a pipe in @p dummy_fd. Every time the state changes, + * a single byte is written to this pipe. A caller who select()s on + * the pipe will therefore be woken every time there is a change. + * + * If we can do dnotify, create the dummy pipe and turn it on. + * + * @fixme One problem here is that if the state directory is deleted + * and recreated, then we'll never notice and find the new one. I + * don't know of any good fix, other than perhaps polling every so + * often. So just don't do that. + * + * @fixme If this function is called repeatedly it will leak FDs. + * + * @todo Reimplement this on top of kevent for BSD. + */ +int dcc_mon_setup_notify (int *dummy_fd) +{ +#ifdef F_NOTIFY + char *state_dir; + int ret; + int fd; + + if (signal (SIGIO, dcc_mon_siginfo_handler) == SIG_ERR) { + rs_log_error ("signal(SIGINFO) failed: %s", strerror(errno)); + return EXIT_IO_ERROR; + } + + if (pipe ((int *) pipe_fd) == -1) { + rs_log_error ("pipe failed: %s", strerror (errno)); + return EXIT_IO_ERROR; + } + + *dummy_fd = pipe_fd[0]; /* read end */ + + dcc_set_nonblocking (pipe_fd[0]); + dcc_set_nonblocking (pipe_fd[1]); + + if ((ret = dcc_get_state_dir (&state_dir))) + return ret; + + if ((fd = open (state_dir, O_RDONLY)) == -1) { + rs_log_error ("failed to open %s: %s", state_dir, strerror (errno)); + free (state_dir); + return EXIT_IO_ERROR; + } + + /* CAUTION! Signals can start arriving immediately. Be ready. */ + + if (fcntl (fd, F_NOTIFY, DN_RENAME|DN_DELETE|DN_MULTISHOT) == -1) { + rs_log_warning ("setting F_NOTIFY failed: %s", + strerror (errno)); + free (state_dir); + return EXIT_IO_ERROR; + } + + return 0; +#else /* F_NOTIFY */ + return EXIT_IO_ERROR; +#endif /* F_NOTIFY */ +} + diff --git a/distcc/src/mon-text.c b/distcc/src/mon-text.c new file mode 100644 index 0000000..ed31854 --- /dev/null +++ b/distcc/src/mon-text.c @@ -0,0 +1,115 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +#include "types.h" +#include "distcc.h" +#include "rpc.h" +#include "trace.h" +#include "exitcode.h" +#include "snprintf.h" +#include "mon.h" + + +/** + * @file + * + * Plain text monitor program. Just prints out the state once, or + * repeatedly, kind of like Linux vmstat. + */ + + +const char *rs_program_name = "distccmon-text"; + + +static void usage(void) +{ + fprintf(stderr, "usage: distccmon-text [DELAY]\n" +"\n" +"Displays current compilation jobs in text form.\n" +"\n" +"If delay is specified, repeatedly updates after that many (fractional)\n" +"seconds. Otherwise, runs just once.\n"); +} + +int main(int argc, char *argv[]) +{ + struct dcc_task_state *list; + int ret; + float delay; + char *end; + + dcc_set_trace_from_env(); + + if (argc == 1) + delay = 0.0; + else if (argc == 2) { + delay = strtod(argv[1], &end); + if (*end) { + usage(); + return 1; + } + } else { + usage(); + return 1; + } + + /* We might be writing to e.g. a pipe that's being read by some + * other program, so make sure we're always line buffered. */ + setvbuf (stdout, NULL, _IOLBF, BUFSIZ); + + do { + struct dcc_task_state *i; + + if ((ret = dcc_mon_poll(&list))) + return ret; + + for (i = list; i; i = i->next) { +#if 1 + if (i->curr_phase == DCC_PHASE_DONE) + continue; +#endif + /* Assume 80 cols = */ + printf("%6ld %-10.10s %-30.30s %24.24s[%d]\n", + (long) i->cpid, + dcc_get_phase_name(i->curr_phase), + i->file, i->host, i->slot); + } + + printf("\n"); + + /* XXX: usleep() is probably not very portable */ + usleep(delay * 1000000); + + dcc_task_state_free(list); + } while (delay); + + return 0; +} diff --git a/distcc/src/mon.c b/distcc/src/mon.c new file mode 100644 index 0000000..90e5605 --- /dev/null +++ b/distcc/src/mon.c @@ -0,0 +1,368 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include "config.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> + +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> + +#include <dirent.h> + +#include "types.h" +#include "distcc.h" +#include "rpc.h" +#include "trace.h" +#include "exitcode.h" +#include "snprintf.h" +#include "mon.h" +#include "util.h" + + +/** + * @file + * + * Common routines for monitoring compiler state. + * + * Every time the client wants an update, it can call dcc_mon_poll(), + * which returns a newly allocated list of all running processes. + * + * The list is returned sorted by hostname and then by slot, so tasks + * will be more stable from one call to the next. + **/ + + +/* TODO: Shouldn't fail if the directory doesn't exist at the moment + * it's called. + */ + + +/* + * State files older than this are assumed to be leftovers from + * compilers that died off. It's possible for a remote compilation to + * take a very long time, and combined with the check that the process + * exists we can allow this to be reasonably large. + */ +const int dcc_phase_max_age = 60; + + +/** + * Check if the state file @p fd is too old to be believed -- probably + * because it was left over from a client that was killed. + * + * If so, close @p fd, unlink the file, and return EXIT_GONE. + * + * fd is closed on failure. + **/ +static int dcc_mon_kill_old(int fd, + char *fullpath) +{ + struct stat st; + time_t now; + + /* Check if the file is old. */ + if (fstat(fd, &st) == -1) { + dcc_close(fd); + rs_log_warning("error statting %s: %s", fullpath, strerror(errno)); + return EXIT_IO_ERROR; + } + time(&now); + + /* Time you hear the siren / it's already too late */ + if (now - st.st_mtime > dcc_phase_max_age) { + dcc_close(fd); /* close first for windoze */ + rs_trace("unlink %s", fullpath); + if (unlink(fullpath) == -1) { + rs_log_warning("unlink %s failed: %s", fullpath, strerror(errno)); + return EXIT_IO_ERROR; + } + return EXIT_GONE; + } + + return 0; +} + + +static int dcc_mon_read_state(int fd, char *fullpath, + struct dcc_task_state *lp) +{ + int nread; + + /* Don't use dcc_readx(), because not being able to read it is not + * a big deal. */ + nread = read(fd, lp, sizeof *lp); + if (nread == -1) { + rs_trace("failed to read state from %s: %s", + fullpath, strerror(errno)); + return EXIT_IO_ERROR; + } else if (nread == 0) { + /* empty file; just bad timing. */ + return EXIT_IO_ERROR; + } else if (nread != sizeof *lp) { + rs_trace("short read getting state from %s", + fullpath); + return EXIT_IO_ERROR; + } + + /* sanity-check some fields */ + + if (lp->magic != DCC_STATE_MAGIC) { + rs_log_warning("wrong magic number: %s", + fullpath); + return EXIT_IO_ERROR; + } + + if (lp->struct_size != sizeof (struct dcc_task_state)) { + rs_log_warning("wrong structure size: %s: version mismatch?", + fullpath); + return EXIT_IO_ERROR; + } + + lp->file[sizeof lp->file - 1] = '\0'; + lp->host[sizeof lp->host - 1] = '\0'; + if (lp->curr_phase > DCC_PHASE_DONE) { + lp->curr_phase = DCC_PHASE_COMPILE; + } + + lp->next = 0; + + return 0; +} + + +/** + * Check that the process named by the file still exists; if not, + * return EXIT_GONE. + **/ +static int dcc_mon_check_orphans(struct dcc_task_state *monl) +{ + /* signal 0 just checks if it exists */ + if (!kill(monl->cpid, 0)) { + return 0; /* it's here */ + } else if (errno == EPERM) { + /* It's here, but it's not ours. Assume it's still a real + * distcc process. */ + return 0; + } else if (errno == ESRCH) { + return EXIT_GONE; /* no such pid */ + } else { + rs_log_warning("kill %ld, 0 failed: %s", (long) monl->cpid, + strerror(errno)); + return EXIT_GONE; + } +} + + +/** + * Read state. If loaded successfully, store a pointer to the newly + * allocated structure into *ppl. + */ +static int dcc_mon_load_state(int fd, + char *fullpath, + struct dcc_task_state **ppl) +{ + int ret; + struct dcc_task_state *tl; + + tl = calloc(1, sizeof *tl); + if (!tl) { + rs_log_crit("failed to allocate dcc_task_state"); + return EXIT_OUT_OF_MEMORY; + } + + ret = dcc_mon_read_state(fd, fullpath, tl); + if (ret) { + dcc_task_state_free(tl); + *ppl = NULL; + return ret; + } + + if (tl->curr_phase != DCC_PHASE_DONE) { + ret = dcc_mon_check_orphans(tl); + if (ret) { + dcc_task_state_free(tl); + *ppl = NULL; + return ret; + } + } + + *ppl = tl; + + return ret; +} + + +/* Free the whole list */ +int dcc_task_state_free(struct dcc_task_state *lp) +{ + struct dcc_task_state *next; + + while (lp) { + next = lp->next; /* save from clobbering */ + + free(lp); + + /* nothing dynamically allocated in them anymore */ + lp = next; + } + + return 0; +} + + +/** + * Read in @p filename from inside @p dirname, and try to parse it as + * a status file. + * + * If a new entry is read, a pointer to it is returned in @p lp. + **/ +static int dcc_mon_do_file(char *dirname, char *filename, + struct dcc_task_state **lp) +{ + int fd; + char *fullpath; + int ret; + + *lp = NULL; + + /* Is this a file we want to see */ + if (!str_startswith(dcc_state_prefix, filename)) { +/* rs_trace("skipped"); */ + return 0; + } + + asprintf(&fullpath, "%s/%s", dirname, filename); + rs_trace("process %s", fullpath); + + /* Remember that the file might disappear at any time, so open it + * now so that we can hang on. */ + if ((fd = open(fullpath, O_RDONLY|O_BINARY, 0)) == -1) { + if (errno == ENOENT) { + rs_trace("%s disappeared", fullpath); + ret = 0; + goto out_free; + } else { /* hm */ + rs_log_warning("failed to open %s: %s", + fullpath, strerror(errno)); + ret = EXIT_IO_ERROR; + goto out_free; + } + } + + if ((ret = dcc_mon_kill_old(fd, fullpath))) { + /* closes fd on failure */ + goto out_free; + } + + ret = dcc_mon_load_state(fd, fullpath, lp); + + dcc_close(fd); + + out_free: + free(fullpath); + return ret; /* ok */ +} + + +/** + * Insert @p new into the list at the appropriate sorted position. + **/ +static void dcc_mon_insert_sorted(struct dcc_task_state **list, + struct dcc_task_state *new) +{ + int s; + struct dcc_task_state *i; + + for (; (i = *list) != NULL; list = &i->next) { + /* Should we go before *list? If the hostname comes first, or + * the name is the same and the slot is lower. */ + s = strcmp(i->host, new->host); + + if (s > 0) { + /* new's host is earlier */ + break; + } else if (s == 0) { + /* same host; compare slots */ + if (new->slot < i->slot) + break; + } + } + + /* OK, insert it before the current contents of *list, which may + * be NULL */ + *list = new; + new->next = i; +} + + +/** + * Read through the state directory and return information about all + * processes we find there. + * + * This function has to handle any files in there that happen to be + * corrupt -- that can easily happen if e.g. a client crashes or is + * interrupted, or is even just in the middle of writing its file. + **/ +int dcc_mon_poll(struct dcc_task_state **p_list) +{ + int ret; + char *dirname; + DIR *d; + struct dirent *de; + + *p_list = NULL; + + if ((ret = dcc_get_state_dir(&dirname))) + return ret; + + if ((d = opendir(dirname)) == NULL) { + rs_log_error("failed to opendir %s: %s", dirname, strerror(errno)); + ret = EXIT_IO_ERROR; + return ret; + } + + while ((de = readdir(d)) != NULL) { + struct dcc_task_state *pthis; + if (dcc_mon_do_file(dirname, de->d_name, &pthis) == 0 + && pthis) { + /* We can succeed without getting a new entry back, but it + * turns out that this time we did get one. So insert it + * intot he right point on the list. */ + dcc_mon_insert_sorted(p_list, pthis); + } + } + + closedir(d); + + return 0; +} + + diff --git a/distcc/src/mon.h b/distcc/src/mon.h new file mode 100644 index 0000000..c2fd331 --- /dev/null +++ b/distcc/src/mon.h @@ -0,0 +1,266 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003, 2004 by Martin Pool <mbp@samba.org> + * Copyright (C) 2003 by Frerich Raabe <raabe@kde.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +#ifndef _DISTCC_MON_H +#define _DISTCC_MON_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + + Writing Monitors for distcc + --------------------------- + + It is possible for third party developers to write monitoring + software for distcc clusters, and you are encouranged to do + so. This appendix attempts to provide you with all the information + you'll need to write a distcc monitor, but just like all other + software, distcc is not perfect; in case you are stuck, can't seem + to get your monitor working, or just think a particular quirk in + the way a monitor was to be written is worth being pointed out, + don't hesitate to subscribe to the list (http://lists.samba.org/) + and present your problem. + + + Limitations on monitoring + ------------------------- + + As of distcc 2.11, monitoring information is only available for + currently running jobs originating from your machine and account. + There is no direct interface available for finding out about jobs + scheduled onto your machine by other users. + + The state information is stored as files in the $DISTCC_DIR + (typically ~/.distcc/state), which are updated by client processes + as they run. The goal of the design is to be adequately secure and + not to reduce the performance of compilation, which is after all + the whole point. + + If you have permission to read the state files of some other users, + you can run a monitor on them by setting DISTCC_DIR before running + the monitor. + + distcc does not maintain a history of tasks that have completed. + Your monitor program must do that if you want to present that + information. mon-gnome.c has a simple implementation of this. + + + + Possible Approaches + ------------------- + + + Right now, there are two general approaches which developers can + follow to develop distcc monitors: + + 1 - Writing a program which parses the output of the distccmon-text + monitor. This is the most flexible solution, since it poses very + little requirements for the monitor - you are free to use whatever + programming language you prefer, and the only requirement your + software has is that the distccmon-text monitor exists on the user + systems, and that its output is compatible with the output of the + distccmon-text monitor you developed your software with. + + Alas, the latter also embodies a problem, since parsing a programs + text output is fragile, and it's not guaranteed that the output format + of the distccmon-text monitor won't change in the future. + + + 2 - Writing a program which links against distcc. This is the + cleaner solution from a software engineer's point of view, since + you retrieve the status information from distcc via, more or less + typesafe, data structures, and don't have to bother parsing text + output. The distcc functions and data types which your monitor will + probably want to use are declared in the header files exitcode.h, + mon.h and state.h. + + Unfortunately, this requires that you use a programming language + which is able to link against the relevant distcc source files + (i.e. C or C++), and that the system which builds your monitor has + the distcc sources installed. Also, it's currently not guaranteed + that the interface established by these three header files + maintains source or binary compatibility between distcc releases. + + Since only the second approach requires detailed knowledge about the + interface to distcc's monitoring facilities, only the second approach + will be documented in this chapter. For the first approach, consult + your programming manuals for how to parse the stdout output of + external processes. + + + The C Interface Provided by distcc + ---------------------------------- + + In case you decide to let your monitor link directly against + distcc, you will get exposed to the interface which distcc offers + to provide your monitor with status information about the + cluster. The general concept behind this interface is that you + should poll distcc regularly for status information, and it will + return a list of jobs which are currently being processed on the + network. In practice, this interface is made up of the following + function: + + int dcc_mon_poll(struct dcc_task_state **ppl) + + This function, declared in the mon.h header file, allows you to + poll a list of jobs which are currently being processed on the + distcc cluster. It returns 0 in case the poll was successful, + otherwise one of the errors declared in the exitcode.h header + file. The "ppl" list is a single-linked list of dcc_task_state + structs, which represent the "jobs" being worked on. The + dcc_task_state struct is declared in the state.h header file. + + + int dcc_task_state_free(struct dcc_history *) + + Call this method and pass it the list of dcc_task_state structs you + acquired by calling dcc_mon_poll in order to free the resources + allocated by the list. + + + So generally, the algorithm you will employ is: + + - Acquire a list of jobs by calling dcc_mon_poll. + + - Process the list of jobs, displaying results to the user. + + - Free the resources allocated by the list of jobs by calling + dcc_task_state_free. + + For being able to do the second of the three steps listed above, you + will need to know what information the dcc_task_state struct (which + represents a job) provides. For a full list of properties, refer to + the state.h header file, for convenience here is a list of noteworthy + properties: + + unsigned long cpid + + The process ID of the compiler process for this job (on the remote + host). + + char file[128] + + The name of the input file of this job. + + char host[128] + + The name of the remote host this job is being processed on. + + int slot + + The CPU slot which is occupied by this job on the remote hosts. + + enum dcc_phase curr_phase + + This variable holds the current state of the job (i.e. preprocess, + compile, send, receive etc.). Refer to the state.h header file for the + complete list of values declared in the dcc_phase enumeration. + + Note that there's a convenience function const char + *dcc_get_state_name(enum dcc_phase state) declared in the state.h + header file which lets you retrieve a descriptive string + representation of the given enum, suitable for display to the user. + + struct dcc_task_state *next + + A pointer to the next dcc_task_state struct in the list, or NULL if this + job is the last in the list. + +*/ + + + + +/** + * Read the list of running processes for this user. + * + * @param ppl On return, recieves a pointer to the start of a list of + * status elements, representing the running processes. *ppl will be + * NULL if there are no processes running. + * + * @return 0 for success or an error from exitcode.h. + * + * The list is not sorted in any particular order, but it will tend to + * remain stable from one call to the next. + * + * The caller should free the list through dcc_task_state_free(). + **/ +int dcc_mon_poll(struct dcc_task_state **ppl); + +/** + * Free a list of dcc_task_state elements, including all their contents. + **/ +int dcc_task_state_free(struct dcc_task_state *); + + +/* A circular buffer of the history of a particular slot. The most + * recent record is in past_phases[now]; the previous one is in + * past_phases[(len+now-1) % len]. All of the data is always valid - + * it is initialized to idle. */ +struct dcc_history { + int now; + int len; + enum dcc_phase *past_phases; +}; + +void dcc_history_push(struct dcc_history *history, enum dcc_phase new_state); +struct dcc_history* dcc_history_new(void); + + +#if 0 +/* Disabled because we don't use dnotify at the moment. + * + * It turns out that being notified of every change is in fact not a + * very desirable thing: the state can change many times per second + * frequently when several clients are running, and waking up the + * monitor each time is expensive. */ + +/** + * Set up to notify the monitor when the compiler state changes. + * + * On successful return, @p dummy_fd receives the file descriptor of a + * pipe. When the state changes, a single byte will be written to + * that pipe. By including the pipe fd in a select() or poll() set, + * the monitor will be woken when the state has changed. + * + * The client should do a nonblocking read from the pipe to empty it + * out each time a notification is received. + * + * This is currently only implemented on Linux. + * + * @return 0 for success or an exitcode.h value. In particular, + * returns EXIT_IO_ERROR if notifications are not available on this + * system. + **/ +int dcc_mon_setup_notify (int *dummy_fd); +#endif /* 0 */ + +#ifdef __cplusplus +} +#endif + +#endif /* _DISTCC_MON_H */ diff --git a/distcc/src/ncpus.c b/distcc/src/ncpus.c new file mode 100644 index 0000000..d29bcd1 --- /dev/null +++ b/distcc/src/ncpus.c @@ -0,0 +1,154 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* Thanks to Dimitri PAPADOPOULOS-ORFANOS for researching many of the methods + * in this file. */ + +#include "config.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <sys/stat.h> + +#include "distcc.h" +#include "trace.h" +#include "exitcode.h" + +/** + * Determine number of processors online. + * + * We will in the future use this to gauge how many concurrent tasks + * should run on this machine. Obviously this is only very rough: the + * correct number needs to take into account disk buffers, IO + * bandwidth, other tasks, etc. +**/ + +#if defined(__hpux__) || defined(__hpux) + +#include <sys/param.h> +#include <sys/pstat.h> + +int dcc_ncpus(int *ncpus) +{ + struct pst_dynamic psd; + if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) != -1) { + *ncpus = psd.psd_proc_cnt; + return 0; + } else { + rs_log_error("pstat_getdynamic failed: %s", strerror(errno)); + *ncpus = 1; + return EXIT_DISTCC_FAILED; + } +} + + +#elif defined(__VOS__) + +#ifdef __GNUC__ +#define $shortmap +#endif + +#include <module_info.h> + +extern void s$get_module_info (char_varying *module_name, void *mip, + short int *code); + +int dcc_ncpus(int *ncpus) +{ +short int code; +module_info mi; +char_varying(66) module_name; + + strcpy_vstr_nstr (&module_name, ""); + mi.version = MODULE_INFO_VERSION_1; + s$get_module_info ((char_varying *)&module_name, (void *)&mi, &code); + if (code != 0) + *ncpus = 1; /* safe guess... */ + else *ncpus = mi.n_user_cpus; + return 0; +} + +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) || defined(__bsdi__) + +/* http://www.FreeBSD.org/cgi/man.cgi?query=sysctl&sektion=3&manpath=FreeBSD+4.6-stable + http://www.openbsd.org/cgi-bin/man.cgi?query=sysctl&sektion=3&manpath=OpenBSD+Current + http://www.tac.eu.org/cgi-bin/man-cgi?sysctl+3+NetBSD-current +*/ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/sysctl.h> +int dcc_ncpus(int *ncpus) +{ + int mib[2]; + size_t len = sizeof(*ncpus); + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + if (sysctl(mib, 2, ncpus, &len, NULL, 0) == 0) + return 0; + else { + rs_log_error("sysctl(CTL_HW:HW_NCPU) failed: %s", + strerror(errno)); + *ncpus = 1; + return EXIT_DISTCC_FAILED; + } +} + +#else /* every other system */ + +/* + http://www.opengroup.org/onlinepubs/007904975/functions/sysconf.html + http://docs.sun.com/?p=/doc/816-0213/6m6ne38dd&a=view + http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V40G_HTML/MAN/MAN3/0629____.HTM + http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=0650&db=man&fname=/usr/share/catman/p_man/cat3c/sysconf.z +*/ + +int dcc_ncpus(int *ncpus) +{ +#if defined(_SC_NPROCESSORS_ONLN) + /* Linux, Solaris, Tru64, UnixWare 7, and Open UNIX 8 */ + *ncpus = sysconf(_SC_NPROCESSORS_ONLN); +#elif defined(_SC_NPROC_ONLN) + /* IRIX */ + *ncpus = sysconf(_SC_NPROC_ONLN); +#else +#warning "Please port this function" + *ncpus = -1; /* unknown */ +#endif + + if (*ncpus == -1) { + rs_log_error("sysconf(_SC_NPROCESSORS_ONLN) failed: %s", + strerror(errno)); + *ncpus = 1; + return EXIT_DISTCC_FAILED; + } else if (*ncpus == 0) { + /* if there are no cpus, what are we running on? But it has + * apparently been observed to happen on ARM Linux */ + *ncpus = 1; + } + + return 0; +} +#endif diff --git a/distcc/src/netutil.c b/distcc/src/netutil.c new file mode 100644 index 0000000..a8c513e --- /dev/null +++ b/distcc/src/netutil.c @@ -0,0 +1,214 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <netdb.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/un.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> + +#ifdef HAVE_ARPA_NAMESER_H +# include <arpa/nameser.h> +#endif + +#include <arpa/inet.h> + +#ifdef HAVE_RESOLV_H +# include <resolv.h> +#endif + +#include <netdb.h> + +#include "types.h" +#include "exitcode.h" +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "srvnet.h" +#include "access.h" +#include "netutil.h" +#include "snprintf.h" + + +/* work out what fcntl flag to use for non-blocking */ +#ifdef O_NONBLOCK +# define NONBLOCK_FLAG O_NONBLOCK +#elif defined(SYSV) +# define NONBLOCK_FLAG O_NDELAY +#else +# define NONBLOCK_FLAG FNDELAY +#endif + +#ifndef AF_UNIX +# define AF_UNIX AF_LOCAL +#endif + + +#ifndef HAVE_HSTRERROR +/* Missing on e.g. Solaris 2.6 */ +const char *hstrerror(int err) { + switch (err) { + case HOST_NOT_FOUND: + return "Host not found"; + case TRY_AGAIN: + return "Name server not contacted"; + case NO_RECOVERY: + return "Non-recoverable error"; + case NO_ADDRESS: + return "No IP address for host"; + default: + return "Unknown error"; + } +} +#endif + + +/** + * Set a fd into blocking mode + **/ +void dcc_set_blocking(int fd) +{ + int val; + + if ((val = fcntl(fd, F_GETFL, 0)) == -1) + return; + if (val & NONBLOCK_FLAG) { + val &= ~NONBLOCK_FLAG; + fcntl(fd, F_SETFL, val); + } +} + + +/** + * Set a fd into nonblocking mode + **/ +void dcc_set_nonblocking(int fd) +{ + int val; + + if ((val = fcntl(fd, F_GETFL, 0)) == -1) + return; + if (!(val & NONBLOCK_FLAG)) { + val |= NONBLOCK_FLAG; + fcntl(fd, F_SETFL, val); + } +} + + +/* Ask for the server not to be awakened until some data has arrived + * on the socket. This works for our protocol because the client + * sends a request immediately after connection without waiting for + * anything from the server. */ +void dcc_defer_accept(int listen_fd) +{ +#ifdef TCP_DEFER_ACCEPT + int val = 1; + + if (!dcc_getenv_bool("DISTCC_TCP_DEFER_ACCEPT", 1)) { + rs_trace("TCP_DEFER_ACCEPT disabled"); + return; + } + + if (setsockopt(listen_fd, SOL_TCP, TCP_DEFER_ACCEPT, &val, sizeof val) == -1) { + rs_log_warning("failed to set TCP_DEFER_ACCEPT: %s", strerror(errno)); + } else { + rs_trace("TCP_DEFER_ACCEPT turned on"); + } +#endif +} + + + +#ifdef ENABLE_RFC2553 +/* TODO: Make the returned strings consistent with the other + * implementation. */ +int dcc_sockaddr_to_string(struct sockaddr *sa, + size_t salen, + char **p_buf) +{ + int err; + char host[1024]; + char port[32]; + + if (!sa) { + *p_buf = strdup("NOTSOCKET"); + return 0; + } else if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) { + err = getnameinfo(sa, salen, + host, sizeof host, + port, sizeof port, + NI_NUMERICHOST | NI_NUMERICSERV); + if (err) { + rs_log_warning("getnameinfo failed: %s", gai_strerror(err)); + *p_buf = strdup("(UNKNOWN)"); + return 0; /* it's still a valid string */ + } + + asprintf(p_buf, "%s:%s", host, port); + } else if (sa->sa_family == AF_UNIX) { + /* NB: The word 'sun' is predefined on Solaris */ + struct sockaddr_un *sa_un = (struct sockaddr_un *) sa; + asprintf(p_buf, "UNIX-DOMAIN %s", sa_un->sun_path); + } else { + asprintf(p_buf, "UNKNOWN-FAMILY %d", sa->sa_family); + } + + return 0; +} +#else /* ndef ENABLE_RFC2553 */ +int dcc_sockaddr_to_string(struct sockaddr *sa, + size_t UNUSED(salen), + char **p_buf) +{ + if (!sa) { + *p_buf = strdup("NOTSOCKET"); + return 0; + } else if (sa->sa_family == AF_INET) { + struct sockaddr_in *sain = (struct sockaddr_in *) sa; + + asprintf(p_buf, "%s:%d", inet_ntoa(sain->sin_addr), + ntohs(sain->sin_port)); + } else if (sa->sa_family == AF_UNIX) { + /* NB: The word 'sun' is predefined on Solaris */ + struct sockaddr_un *sa_un = (struct sockaddr_un *) sa; + asprintf(p_buf, "UNIX-DOMAIN %s", sa_un->sun_path); + } else { + asprintf(p_buf, "UNKNOWN-FAMILY %d", sa->sa_family); + } + + return 0; +} +#endif /* ndef ENABLE_RFC2553 */ diff --git a/distcc/src/netutil.h b/distcc/src/netutil.h new file mode 100644 index 0000000..5b2ea83 --- /dev/null +++ b/distcc/src/netutil.h @@ -0,0 +1,37 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +struct sockaddr; +int dcc_sockaddr_to_string(struct sockaddr *sa, + size_t salen, + char **p_buf); + +void dcc_set_nonblocking(int fd); +void dcc_set_blocking(int fd); + + +#ifndef HAVE_HSTRERROR +/* Missing on e.g. Solaris 2.6 */ +const char *hstrerror(int err); +#endif + +void dcc_defer_accept(int); diff --git a/distcc/src/prefork.c b/distcc/src/prefork.c new file mode 100644 index 0000000..2b01311 --- /dev/null +++ b/distcc/src/prefork.c @@ -0,0 +1,195 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + /* The dead cry out with joy when their books are reprinted + */ + + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <syslog.h> +#include <signal.h> +#include <fcntl.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/select.h> + +#include "exitcode.h" +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "dopt.h" +#include "exec.h" +#include "srvnet.h" +#include "types.h" +#include "daemon.h" +#include "netutil.h" +#include "stats.h" + +void dcc_manage_kids(int listen_fd); +static void dcc_sigchld_handler(int sig); +static void dcc_create_kids(int listen_fd); +static int dcc_preforked_child(int listen_fd); + +/** + * Main loop for the parent process with the new preforked implementation. + * The parent is just responsible for keeping a pool of children and they + * accept connections themselves. + **/ +int dcc_preforking_parent(int listen_fd) +{ + int ret; + /* use sigaction instead of signal() because we need persistant handler, not oneshot */ + struct sigaction act_child; + memset(&act_child, 0, sizeof act_child); + act_child.sa_handler = dcc_sigchld_handler; + sigaction(SIGCHLD, &act_child, NULL); + + if (arg_stats) { + + ret = dcc_stats_init(); + if (ret) return ret; + + dcc_create_kids(listen_fd); + + /* Start the stats collection and web server */ + return dcc_stats_server(listen_fd); + } else { + while (1) { + dcc_create_kids(listen_fd); + + /* wait for any children to exit, and then start some more */ + dcc_reap_kids(TRUE); + + /* Another little safety brake here: since children should not exit + * too quickly, pausing before starting them should be harmless. */ + sleep(1); + } + } +} + + +static void dcc_sigchld_handler(int UNUSED(sig)) { + /* Do nothing. Only here to break out of select() in dcc_stats_server() + * and select() in dcc_collect_child(). */ +} + + +/** + * Functions in the parent can call this to clean up and maintain the pool of + * children + **/ +void dcc_manage_kids(int listen_fd) { + dcc_reap_kids(FALSE); + dcc_create_kids(listen_fd); +} + +/** + * Fork children until we have dcc_max_kids of them + **/ +static void dcc_create_kids(int listen_fd) { + pid_t kid; + + while (dcc_nkids < dcc_max_kids) { + if ((kid = fork()) == -1) { + rs_log_error("fork failed: %s", strerror(errno)); + dcc_exit(EXIT_OUT_OF_MEMORY); /* probably */ + } else if (kid == 0) { + dcc_stats_init_kid(); + dcc_exit(dcc_preforked_child(listen_fd)); + } else { + /* in parent */ + ++dcc_nkids; + rs_trace("up to %d children", dcc_nkids); + } + + /* Don't start them too quickly, or we might overwhelm a machine + * that's having trouble. */ + sleep(1); + } +} + + + +/** + * Fork a child to repeatedly accept and handle incoming connections. + * + * To protect against leaks, we quit after 50 requests and let the parent + * recreate us. + **/ +static int dcc_preforked_child(int listen_fd) +{ + int ireq; + const int child_lifetime = 50; + + for (ireq = 0; ireq < child_lifetime; ireq++) { + int acc_fd; + struct dcc_sockaddr_storage cli_addr; + socklen_t cli_len; + + cli_len = sizeof cli_addr; + + /* Cancel any previously scheduled alarm */ + if (dcc_job_lifetime) + alarm(0); + + do { + acc_fd = accept(listen_fd, (struct sockaddr *) &cli_addr, + &cli_len); + } while (acc_fd == -1 && errno == EINTR); + + /* Kill this process if the compile job takes too long. + * The synchronous timeout should happen first, so this alarm + * should fire only if the client stops transferring network data without disconnecting. + */ + if (dcc_job_lifetime) + alarm(dcc_job_lifetime+30); + + + if (acc_fd == -1) { + rs_log_error("accept failed: %s", strerror(errno)); + dcc_exit(EXIT_CONNECT_FAILED); + } + + dcc_stats_event(STATS_TCP_ACCEPT); + + dcc_service_job(acc_fd, acc_fd, + (struct sockaddr *) &cli_addr, cli_len); + + dcc_close(acc_fd); + } + + rs_log_info("worn out"); + + return 0; +} diff --git a/distcc/src/pump.c b/distcc/src/pump.c new file mode 100644 index 0000000..e8ea8c7 --- /dev/null +++ b/distcc/src/pump.c @@ -0,0 +1,152 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003, 2004 by Martin Pool + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +/* pump.c - Transfer of bulk data (source, object code) */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/socket.h> +#ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +#endif +#include <sys/time.h> +#ifdef HAVE_SYS_MMAN_H +# include <sys/mman.h> +#endif + +#include <netinet/in.h> +#include <netinet/tcp.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "exitcode.h" + + +/* + * Receive either compressed or uncompressed bulk data. + */ +int dcc_r_bulk(int ofd, + int ifd, + unsigned f_size, + enum dcc_compress compression) +{ + if (f_size == 0) + return 0; /* don't decompress nothing */ + + if (compression == DCC_COMPRESS_NONE) { + return dcc_pump_readwrite(ofd, ifd, f_size); + } else if (compression == DCC_COMPRESS_LZO1X) { + return dcc_r_bulk_lzo1x(ofd, ifd, f_size); + } else { + rs_log_error("impossible compression %d", compression); + return EXIT_PROTOCOL_ERROR; + } +} + + + +/** + * Copy @p n bytes from @p ifd to @p ofd. + * + * Does not use sendfile(), so either one may be a socket. + * + * In the current code at least one of the files will always be a regular + * (disk) file, even though it may not be mmapable. That should mean that + * writes to it will always complete immediately. That in turn means that on + * each pass through the main loop we ought to either completely fill our + * buffer, or completely drain it, depending on which one is the disk. + * + * In future we may put back the ability to feed the compiler from a fifo, in + * which case it may be that the writes don't complete. + * + * We might try selecting on both buffers and handling whichever is ready. + * This would require some approximation to a circular buffer though, which + * might be more complex. + **/ +int +dcc_pump_readwrite(int ofd, int ifd, size_t n) +{ + static char buf[262144]; /* we're not recursive */ + char *p; + ssize_t r_in, r_out, wanted; + int ret; + + while (n > 0) { + wanted = (n > sizeof buf) ? (sizeof buf) : n; + r_in = read(ifd, buf, (size_t) wanted); + + if (r_in == -1 && errno == EAGAIN) { + if ((ret = dcc_select_for_read(ifd, dcc_io_timeout)) != 0) + return ret; + else + continue; + } else if (r_in == -1 && errno == EINTR) { + continue; + } else if (r_in == -1) { + rs_log_error("failed to read %ld bytes: %s", + (long) wanted, strerror(errno)); + return EXIT_IO_ERROR; + } else if (r_in == 0) { + rs_log_error("unexpected eof on fd%d", ifd); + return EXIT_IO_ERROR; + } + + n -= r_in; + p = buf; + + /* We now have r_in bytes waiting to go out, starting at p. Keep + * going until they're all written out. */ + + while (r_in > 0) { + r_out = write(ofd, p, (size_t) r_in); + + if (r_out == -1 && errno == EAGAIN) { + if ((ret = dcc_select_for_write(ofd, dcc_io_timeout)) != 0) + return ret; + else + continue; + } else if (r_out == -1 && errno == EINTR) { + continue; + } else if (r_out == -1 || r_out == 0) { + rs_log_error("failed to write: %s", strerror(errno)); + return EXIT_IO_ERROR; + } + r_in -= r_out; + p += r_out; + } + } + + return 0; +} + diff --git a/distcc/src/remote.c b/distcc/src/remote.c new file mode 100644 index 0000000..970891e --- /dev/null +++ b/distcc/src/remote.c @@ -0,0 +1,301 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* + * Send a compilation request to a remote server. + */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/time.h> + +#include "distcc.h" +#include "trace.h" +#include "rpc.h" +#include "exitcode.h" +#include "util.h" +#include "clinet.h" +#include "hosts.h" +#include "exec.h" +#include "lock.h" +#include "compile.h" +#include "bulk.h" + + +/* + * TODO: If cpp finishes early and fails then perhaps break out of + * trying to connect. + * + * TODO: If we abort, perhaps kill the SSH child rather than closing + * the socket. Closing while a lot of stuff has been written through + * might make us block until the other side reads all the data. + */ + +/** + * Open a connection using either a TCP socket or SSH. Return input + * and output file descriptors (which may or may not be different.) + **/ +static int dcc_remote_connect(struct dcc_hostdef *host, + int *to_net_fd, + int *from_net_fd, + pid_t *ssh_pid) +{ + int ret; + + if (host->mode == DCC_MODE_TCP) { + *ssh_pid = 0; + if ((ret = dcc_connect_by_name(host->hostname, host->port, + to_net_fd)) != 0) + return ret; + *from_net_fd = *to_net_fd; + return 0; + } else if (host->mode == DCC_MODE_SSH) { + if ((ret = dcc_ssh_connect(NULL, host->user, host->hostname, + host->ssh_command, + from_net_fd, to_net_fd, + ssh_pid))) + return ret; + return 0; + } else { + rs_log_crit("impossible host mode"); + return EXIT_DISTCC_FAILED; + } +} + + +static int dcc_wait_for_cpp(pid_t cpp_pid, + int *status, + const char *input_fname) +{ + int ret; + + if (cpp_pid) { + dcc_note_state(DCC_PHASE_CPP, NULL, NULL); + /* Wait for cpp to finish (if not already done), check the + * result, then send the .i file */ + + if ((ret = dcc_collect_child("cpp", cpp_pid, status, timeout_null_fd))) + return ret; + + /* Although cpp failed, there is no need to try running the command + * locally, because we'd presumably get the same result. Therefore + * critique the command and log a message and return an indication + * that compilation is complete. */ + if (dcc_critique_status(*status, "cpp", input_fname, dcc_hostdef_local, 0)) + return 0; + } + return 0; +} + + +/* Send a request across to the already-open server. + * + * CPP_PID is the PID of the preprocessor running in the background. + * We wait for it to complete before reading its output. + */ +static int +dcc_send_header(int net_fd, + char **argv, + struct dcc_hostdef *host) +{ + int ret; + + tcp_cork_sock(net_fd, 1); + + if ((ret = dcc_x_req_header(net_fd, host->protover))) + return ret; + if (host->cpp_where == DCC_CPP_ON_SERVER) { + if ((ret = dcc_x_cwd(net_fd))) + return ret; + } + if ((ret = dcc_x_argv(net_fd, argv))) + return ret; + + return 0; +} + + +/** + * Pass a compilation across the network. + * + * When this function is called, the preprocessor has already been + * started in the background. It may have already completed, or it + * may still be running. The goal is that preprocessing will overlap + * with setting up the network connection, which may take some time + * but little CPU. + * + * If this function fails, compilation will be retried on the local + * machine. + * + * @param argv Compiler command to run. + * + * @param cpp_fname Filename of preprocessed source. May not be complete yet, + * depending on @p cpp_pid. + * + * @param files If we are doing preprocessing on the server, the names of + * all the files needed; otherwise, NULL. + * + * @param output_fname File that the object code should be delivered to. + * + * @param cpp_pid If nonzero, the pid of the preprocessor. Must be + * allowed to complete before we send the input file. + * + * @param host Definition of host to send this job to. + * + * @param status on return contains the wait-status of the remote + * compiler. + * + * Returns 0 on success, otherwise error. Returning nonzero does not + * necessarily imply the remote compiler itself succeeded, only that + * there were no communications problems. + */ +int dcc_compile_remote(char **argv, + char *input_fname, + char *cpp_fname, + char **files, + char *output_fname, + char *deps_fname, + char *server_stderr_fname, + pid_t cpp_pid, + int local_cpu_lock_fd, + struct dcc_hostdef *host, + int *status) +{ + int to_net_fd = -1, from_net_fd = -1; + int ret; + pid_t ssh_pid = 0; + int ssh_status; + off_t doti_size; + struct timeval before, after; + unsigned int n_files; + + if (gettimeofday(&before, NULL)) + rs_log_warning("gettimeofday failed"); + + dcc_note_execution(host, argv); + dcc_note_state(DCC_PHASE_CONNECT, input_fname, host->hostname); + + /* For ssh support, we need to allow for separate fds writing to and + * reading from the network, because our connection to the ssh client may + * be over pipes, which are one-way connections. */ + + *status = 0; + if ((ret = dcc_remote_connect(host, &to_net_fd, &from_net_fd, &ssh_pid))) + goto out; + + dcc_note_state(DCC_PHASE_SEND, NULL, NULL); + + if (host->cpp_where == DCC_CPP_ON_SERVER) { + if ((ret = dcc_send_header(to_net_fd, argv, host))) { + goto out; + } + + n_files = dcc_argv_len(files); + if ((ret = dcc_x_many_files(to_net_fd, n_files, files))) { + goto out; + } + } else { + /* This waits for cpp and puts its status in *status. If cpp failed, + * then the connection will have been dropped and we need not bother + * trying to get any response from the server. */ + + if ((ret = dcc_send_header(to_net_fd, argv, host))) { + goto out; + } + + if ((ret = dcc_wait_for_cpp(cpp_pid, status, input_fname))) + goto out; + + + /* We are done preprocessing. Unlock to allow someone else to + start preprocessing */ + if(local_cpu_lock_fd) { dcc_unlock(local_cpu_lock_fd); } + + if (*status != 0) + goto out; + + if ((ret = dcc_x_file(to_net_fd, cpp_fname, "DOTI", host->compr, + &doti_size))) + goto out; + } + + rs_trace("client finished sending request to server"); + tcp_cork_sock(to_net_fd, 0); + /* but it might not have been read in by the server yet; there's + * 100kB or more of buffers in the two kernels. */ + + /* OK, now all of the source has at least made it into the + * client's TCP transmission queue, sometime soon the server will + * start compiling it. */ + dcc_note_state(DCC_PHASE_COMPILE, NULL, host->hostname); + + /* If cpp failed, just abandon the connection, without trying to + * receive results. */ + if (ret == 0 && *status == 0) { + ret = dcc_retrieve_results(from_net_fd, status, output_fname, + deps_fname, server_stderr_fname, host); + } + + if (gettimeofday(&after, NULL)) { + rs_log_warning("gettimeofday failed"); + } else if (host->cpp_where == DCC_CPP_ON_CLIENT) { + double secs, rate; + + dcc_calc_rate(doti_size, &before, &after, &secs, &rate); + rs_log(RS_LOG_INFO|RS_LOG_NONAME, + "%lu bytes from %s compiled on %s in %.4fs, rate %.0fkB/s", + (unsigned long) doti_size, input_fname, host->hostname, + secs, rate); + } + + out: + /* Close socket so that the server can terminate, rather than + * making it wait until we've finished our work. */ + if (to_net_fd != from_net_fd) { + if (to_net_fd != -1) + dcc_close(to_net_fd); + } + if (from_net_fd != -1) + dcc_close(from_net_fd); + + /* Collect the SSH child. Strictly this is unnecessary; it might slow the + * client down a little when things could otherwise be proceeding in the + * background. But it helps make sure that we don't assume we succeeded + * when something possibly went wrong, and it allows us to account for the + * cost of the ssh child. */ + if (ssh_pid) { + dcc_collect_child("ssh", ssh_pid, &ssh_status, timeout_null_fd); /* ignore failure */ + } + + return ret; +} + + diff --git a/distcc/src/renderer.c b/distcc/src/renderer.c new file mode 100644 index 0000000..5560921 --- /dev/null +++ b/distcc/src/renderer.c @@ -0,0 +1,299 @@ +/* -*- c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/** + * @file + * + * GtkCellRenderer subclass for drawing strip charts. + * + * Based on the example of gtkcellrendererpixbuf and hacked up. + * + * Each table cell corresponds to one execution slot for the client. + * Each host can have several slots. At most one task can run on each + * slot at any time. Therefore we can draw the history of tasks in + * this slot as a set of rectangles that do not overlap in time. + * + * The renderer looks directly at the list of running tasks to find + * the ones in its slot. It accesses the list through a global + * variable. This is pretty gross in terms of the Gtk object system, + * but it avoids worrying about memory management and filtering the + * tasks to put them on the right view of the model. + **/ + + + +#include "config.h" + +#include <sys/types.h> +#include <sys/time.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <pwd.h> +#include <unistd.h> + +#include <glib.h> +#include <gtk/gtk.h> + +#include "types.h" +#include "distcc.h" +#include "rpc.h" +#include "trace.h" +#include "exitcode.h" +#include "mon.h" + +#include "netutil.h" +#include "renderer.h" + + +struct _DccCellRendererChart +{ + GtkCellRenderer parent; + + /** History of tasks for this slot. Exposed through the "history" + * property. */ + struct dcc_history *history; +}; + +struct _DccCellRendererChartClass +{ + GtkCellRendererClass parent_class; +}; + + +enum { + PROP_ZERO, + PROP_HISTORY +}; + + + + +/** + * Create a new cell renderer to display a chart of compilation jobs. + **/ +GtkCellRenderer * +dcc_cell_renderer_chart_new (void) +{ + return g_object_new (DCC_TYPE_CELL_RENDERER_CHART, NULL); +} + + +static void +dcc_cell_renderer_chart_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + DccCellRendererChart *renderer; + + renderer = DCC_CELL_RENDERER_CHART (object); + + switch (prop_id) + { + case PROP_HISTORY: + renderer->history = g_value_get_pointer (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +static void +dcc_cell_renderer_chart_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + DccCellRendererChart *renderer; + + renderer = DCC_CELL_RENDERER_CHART (object); + + switch (prop_id) + { + case PROP_HISTORY: + g_value_set_pointer (value, renderer->history); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + + + +/** + * Actually draw one cell (one strip chart) into a widget. + * + * I tried checking against the expose area to see whether we needed + * to repaint the whole thing, but it does not seem to help very much. + * GTK+ always tells us the whole cell is exposed when it updates the + * table, even if part of the cell is actually obscured by some other + * window. The refresh events are the performance-critical ones for + * us; the others don't matter nearly so much. + **/ +static void +dcc_cell_renderer_chart_render (GtkCellRenderer *cell, + GdkWindow *window, + GtkWidget *UNUSED(widget), + GdkRectangle *UNUSED(background_area), + GdkRectangle *cell_area, + GdkRectangle *UNUSED(expose_area), + GtkCellRendererState UNUSED(flags)) +{ + const struct dcc_history *history; + enum dcc_phase state; + int x1, y1; + int bar_height; + int bar_width; + int i; + const enum dcc_phase *phases; + + DccCellRendererChart *cellchart = (DccCellRendererChart *) cell; + + history = cellchart->history; + g_return_if_fail (history); /* Perhaps we should just ignore this.. */ + + x1 = cell_area->x + cell->xpad; + y1 = cell_area->y + cell->ypad; + bar_height = cell_area->height - (2 * cell->ypad); + + /* bar width is chosen such that the history roughly fills the cell + (but it must be at least 1). We use the full history, not just + the amount we currently have. Round up. */ + bar_width = (cell_area->width + history->len - 1) / history->len; + if (bar_width < 1) + bar_width = 1; + + phases = history->past_phases; + for (i = 0; i < history->len; i++) + { + state = phases[(history->len + history->now - i) % history->len]; + + g_return_if_fail (state <= DCC_PHASE_DONE); + + if (state != DCC_PHASE_DONE) + { + gdk_draw_rectangle (window, + dcc_phase_gc[state], + TRUE, /* fill */ + x1, y1, bar_width, bar_height); + } + + x1 += bar_width; + } +} + + + +/** + * Measure the size that we want to have allocated for this cell. + */ +static void +dcc_cell_renderer_chart_get_size (GtkCellRenderer *UNUSED(cell), + GtkWidget *UNUSED (widget), + GdkRectangle *UNUSED (cell_area), + gint *UNUSED (x_offset), + gint *UNUSED (y_offset), + gint *UNUSED (width), + gint *UNUSED (height)) +{ + /* default is fine */ +} + + + + +static void +dcc_cell_renderer_chart_class_init (DccCellRendererChartClass *class) +{ + GParamSpec *spec; + + GObjectClass *object_class = G_OBJECT_CLASS (class); + GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class); + + object_class->get_property = dcc_cell_renderer_chart_get_property; + object_class->set_property = dcc_cell_renderer_chart_set_property; + + cell_class->render = dcc_cell_renderer_chart_render; + cell_class->get_size = dcc_cell_renderer_chart_get_size; + + spec = g_param_spec_pointer ("history", + "Slot history", + "", + G_PARAM_READABLE | G_PARAM_WRITABLE); + + g_object_class_install_property (object_class, + PROP_HISTORY, + spec); +} + + +/* Instance initialization */ +static void +dcc_cell_renderer_chart_init (DccCellRendererChart *cell) +{ + cell->history = NULL; +} + + + + +/** + * Return metaobject info to GObject system. Or something. + **/ +GType +dcc_cell_renderer_chart_get_type (void) +{ + static GType cell_chart_type = 0; + + if (!cell_chart_type) + { + static const GTypeInfo cell_chart_info = + { + sizeof (DccCellRendererChartClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) dcc_cell_renderer_chart_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (DccCellRendererChart), + 0, /* n_preallocs */ + (GInstanceInitFunc) dcc_cell_renderer_chart_init, + NULL /* value_table */ + }; + + cell_chart_type = + g_type_register_static (GTK_TYPE_CELL_RENDERER, + "DccCellRendererChart", + &cell_chart_info, 0); + } + + return cell_chart_type; +} diff --git a/distcc/src/renderer.h b/distcc/src/renderer.h new file mode 100644 index 0000000..d74c95e --- /dev/null +++ b/distcc/src/renderer.h @@ -0,0 +1,48 @@ +/* -*- c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +/** + * @file + * + * Implementation of a GtkCellRenderer subclass that draws a little + * chart of programs that have run in that slot. + **/ + + +#define DCC_TYPE_CELL_RENDERER_CHART (dcc_cell_renderer_chart_get_type ()) +#define DCC_CELL_RENDERER_CHART(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DCC_TYPE_CELL_RENDERER_CHART, DccCellRendererChart)) +#define DCC_CELL_RENDERER_CHART_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DCC_TYPE_CELL_RENDERER_CHART, DccCellRendererChartClass)) +#define DCC_IS_CELL_RENDERER_CHART(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DCC_TYPE_CELL_RENDERER_CHART)) +#define DCC_IS_CELL_RENDERER_CHART_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DCC_TYPE_CELL_RENDERER_CHART)) +#define DCC_CELL_RENDERER_CHART_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DCC_TYPE_CELL_RENDERER_CHART, DccCellRendererChartClass)) + +typedef struct _DccCellRendererChart DccCellRendererChart; +typedef struct _DccCellRendererChartClass DccCellRendererChartClass; + +GType dcc_cell_renderer_chart_get_type (void); +GtkCellRenderer *dcc_cell_renderer_chart_new (void); + + +extern GdkGC *dcc_phase_gc[DCC_PHASE_DONE]; + +extern const guint dcc_max_history_queue; diff --git a/distcc/src/rpc.c b/distcc/src/rpc.c new file mode 100644 index 0000000..93c1f2d --- /dev/null +++ b/distcc/src/rpc.c @@ -0,0 +1,343 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + /* 15 Every one that is found shall be thrust + * through; and every one that is joined unto + * them shall fall by the sword. + * -- Isaiah 13 */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <ctype.h> + +#include <sys/stat.h> + +#include "distcc.h" +#include "trace.h" +#include "exitcode.h" +#include "rpc.h" +#include "snprintf.h" + + +/** + * @file + * + * Very simple RPC-like layer. Requests and responses are build of + * little packets each containing a 4-byte ascii token, an 8-byte hex + * value or length, and optionally data corresponding to the length. + * + * 'x' means transmit, and 'r' means receive. + * + * This builds on top of io.c and is called by the various routines + * that handle communication. + **/ + + +/** + * Transmit token name (4 characters) and value (32-bit int, as 8 hex + * characters). + **/ +int dcc_x_token_int(int ofd, const char *token, unsigned param) +{ + char buf[13]; + int shift; + char *p; + const char *hex = "0123456789abcdef"; + + if (strlen(token) != 4) { + rs_log_crit("token \"%s\" seems wrong", token); + return EXIT_PROTOCOL_ERROR; + } + memcpy(buf, token, 4); + + /* Quick and dirty int->hex. The only standard way is to call snprintf + * (?), which is undesirably slow for such a frequently-called + * function. */ + for (shift=28, p = &buf[4]; + shift >= 0; + shift -= 4, p++) { + *p = hex[(param >> shift) & 0xf]; + } + buf[12] = '\0'; + + rs_trace("send %s", buf); + return dcc_writex(ofd, buf, 12); +} + + +/** + * Send start of a result: DONE <version> + **/ +int dcc_x_result_header(int ofd, + enum dcc_protover protover) +{ + return dcc_x_token_int(ofd, "DONE", protover); +} + + +int dcc_x_cc_status(int ofd, int status) +{ + return dcc_x_token_int(ofd, "STAT", (unsigned) status); +} + + +int dcc_r_token(int ifd, char *buf) +{ + return dcc_readx(ifd, buf, 4); +} + + +/** + * We got a mismatch on a token, which indicates either a bug in distcc, or + * that somebody (inetd?) is interfering with our network stream, or perhaps + * some other network problem. Whatever's happened, a bit more debugging + * information would be handy. + **/ +int dcc_explain_mismatch(const char *buf, + size_t buflen, + int ifd) +{ + ssize_t ret; + char extrabuf[200]; + char *p; + size_t l; + + memcpy(extrabuf, buf, buflen); + + /* Read a bit more context, and find the printable prefix. */ + ret = read(ifd, extrabuf + buflen, sizeof extrabuf - 1 - buflen); + if (ret == -1) { + ret = 0; /* pah, use what we've got */ + } + + l = buflen + ret; + + extrabuf[l] = '\0'; + for (p = extrabuf; *p; p++) + if (!(isprint(*p) || *p == ' ' || *p == '\t')) { + *p = '\0'; + break; + } + + rs_log_error("error context: \"%s\"", extrabuf); + + return 0; /* i just feel really sad... */ +} + + +/** + * Read a token and value. The receiver always knows what token name + * is expected next -- indeed the names are really only there as a + * sanity check and to aid debugging. + * + * @param ifd fd to read from + * @param expected 4-char token that is expected to come in next + * @param val receives the parameter value + **/ +int dcc_r_token_int(int ifd, const char *expected, unsigned *val) +{ + char buf[13], *bum; + int ret; + + if (strlen(expected) != 4) { + rs_log_error("expected token \"%s\" seems wrong", expected); + return EXIT_PROTOCOL_ERROR; + } + + if ((ret = dcc_readx(ifd, buf, 12))) { + rs_log_error("read failed while waiting for token \"%s\"", + expected); + return ret; + } + + if (memcmp(buf, expected, 4)) { + rs_log_error("protocol derailment: expected token \"%s\"", expected); + dcc_explain_mismatch(buf, 12, ifd); + return EXIT_PROTOCOL_ERROR; + } + + buf[12] = '\0'; /* terminate */ + + *val = strtoul(&buf[4], &bum, 16); + if (bum != &buf[12]) { + rs_log_error("failed to parse parameter of token \"%s\"", + expected); + dcc_explain_mismatch(buf, 12, ifd); + return EXIT_PROTOCOL_ERROR; + } + + rs_trace("got %s", buf); + + return 0; +} + +/** + * Read a token and value. Fill in both token and value; + * unlike dcc_r_token_int this is for the case when we do not know what + * the next token will be. + * + * @param ifd fd to read from + * @param token receives the 4-char token + * @param val receives the parameter value + **/ +int dcc_r_sometoken_int(int ifd, char *token, unsigned *val) +{ + char buf[13], *bum; + int ret; + + if ((ret = dcc_readx(ifd, buf, 12))) { + rs_log_error("read failed while waiting for some token"); + return ret; + } + + strncpy(token, buf, 4); + token[4] = '\0'; + + buf[12] = '\0'; /* terminate */ + + *val = strtoul(&buf[4], &bum, 16); + if (bum != &buf[12]) { + rs_log_error("failed to parse parameter of token \"%s\"", + token); + dcc_explain_mismatch(buf, 12, ifd); + return EXIT_PROTOCOL_ERROR; + } + + rs_trace("got %s", buf); + + return 0; +} + +/** + * Read a byte string of length @p l into a newly allocated buffer, returned in @p buf. + **/ +int dcc_r_str_alloc(int fd, unsigned l, char **buf) +{ + char *s; + +#if 0 + /* never true */ + if (l < 0) { + rs_log_crit("oops, l < 0"); + return EXIT_PROTOCOL_ERROR; + } +#endif + +/* rs_trace("read %d byte string", l); */ + + s = *buf = malloc((size_t) l + 1); + if (!s) + rs_log_error("malloc failed"); + if (dcc_readx(fd, s, (size_t) l)) + return EXIT_OUT_OF_MEMORY; + + s[l] = 0; + + return 0; +} + + +/** + * Write a token, and then the string @p buf. + * + * The length of buf is determined by its nul delimiter, but the \0 is not sent. + **/ +int dcc_x_token_string(int fd, + const char *token, + const char *buf) +{ + int ret; + size_t len; + + len = strlen(buf); + if ((ret = dcc_x_token_int(fd, token, (unsigned) len))) + return ret; + if ((ret = dcc_writex(fd, buf, len))) + return ret; + rs_trace("send string '%s'", buf); + return 0; +} + + +int dcc_r_token_string(int ifd, const char *expect_token, + char **p_str) +{ + unsigned a_len; + int ret; + + if ((ret = dcc_r_token_int(ifd, expect_token, &a_len))) + return ret; + + if ((ret = dcc_r_str_alloc(ifd, a_len, p_str))) + return ret; + + rs_trace("got '%s'", *p_str); + + return 0; +} + +/** + * Read an argv[] vector from the network. + **/ +int dcc_r_argv(int ifd, /*@out@*/ char ***argv) +{ + unsigned i; + unsigned argc; + char **a; + int ret; + + *argv = NULL; + + if (dcc_r_token_int(ifd, "ARGC", &argc)) + return EXIT_PROTOCOL_ERROR; + + rs_trace("reading %d arguments from job submission", argc); + + /* Have to make the argv one element too long, so that it can be + * terminated by a null element. */ + *argv = a = (char **) calloc((size_t) argc+1, sizeof a[0]); + if (a == NULL) { + rs_log_error("alloc failed"); + return EXIT_OUT_OF_MEMORY; + } + a[argc] = NULL; + + for (i = 0; i < argc; i++) { + if ((ret = dcc_r_token_string(ifd, "ARGV", &a[i]))) + return ret; + + rs_trace("argv[%d] = \"%s\"", i, a[i]); + } + + dcc_trace_argv("got arguments", a); + + return 0; +} + diff --git a/distcc/src/rpc.h b/distcc/src/rpc.h new file mode 100644 index 0000000..fb47964 --- /dev/null +++ b/distcc/src/rpc.h @@ -0,0 +1,48 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + /* His hand is stretched out, and who shall turn it back? + * -- Isaiah 14:27 */ + +int dcc_x_result_header(int ofd, enum dcc_protover); +int dcc_r_result_header(int ofd, enum dcc_protover); + +int dcc_x_cc_status(int, int); +int dcc_r_cc_status(int, int *); + +int dcc_x_token_int(int ofd, const char *token, unsigned param); +int dcc_r_token_int(int ifd, const char *expected, unsigned int *val); + +int dcc_x_token_string(int fd, + const char *token, + const char *buf); + +int dcc_r_token_string(int ifd, const char *expect_token, + char **p_str); +int dcc_r_sometoken_int(int ifd, char *token, unsigned *val); + +int dcc_explain_mismatch(const char *buf, size_t buflen, int ifd); + +/* srvrpc.c */ +int dcc_r_request_header(int ifd, enum dcc_protover *); +int dcc_r_argv(int ifd, /*@out@*/ char ***argv); + diff --git a/distcc/src/rslave.c b/distcc/src/rslave.c new file mode 100644 index 0000000..8541a93 --- /dev/null +++ b/distcc/src/rslave.c @@ -0,0 +1,166 @@ +/* Copyright (C) 2005 by Google + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* don't blame me, I was in a hurry */ + +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <unistd.h> +#include <netdb.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/poll.h> +#include <sys/time.h> + +#include "rslave.h" + +/*-------------------------------------------------------------------------- + Class to provide asynchronous DNS lookup. + To use, first call rslave_init() very early in your program to fork the + dns slave processes. + Then call rslave_write() any time you need a DNS name resolved + and rslave_read() to retrieve the next result. Order of lookup requests + is not preserved. + Call rslave_getfd() and select on that fd for readability if you + want to only call rslave_read() once it won't block. + The slaves will shut down when their input file descriptor is closed, + which normally happens when your program exits. +--------------------------------------------------------------------------*/ + +int rslave_getfd_fromSlaves(struct rslave_s *rslave) +{ + return rslave->pipeFromSlaves[0]; +} + +int rslave_getfd_toSlaves(struct rslave_s *rslave) +{ + return rslave->pipeToSlaves[1]; +} + +void rslave_request_init(struct rslave_request_s *buf, const char *hostname, int id) +{ + memset(buf, 0, sizeof(*buf)); + strncpy(buf->hname, hostname, rslave_HOSTLEN); + buf->id = id; +} + +int rslave_writeRequest(struct rslave_s *rslave, const struct rslave_request_s *req) +{ + if (write(rslave->pipeToSlaves[1], req, sizeof(*req)) != sizeof(*req)) + return -1; + return 0; +} + +int rslave_gethostbyname(struct rslave_s *rslave, const char *hostname, int id) +{ + struct rslave_request_s buf; + rslave_request_init(&buf, hostname, id); + return rslave_writeRequest(rslave, &buf); +} + +int rslave_readRequest(struct rslave_s *rslave, struct rslave_request_s *req) +{ + if (read(rslave->pipeToSlaves[0], req, sizeof(*req)) != sizeof(*req)) + return -1; + return 0; +} + +int rslave_writeResult(struct rslave_s *rslave, struct rslave_result_s *result) +{ + if (write(rslave->pipeFromSlaves[1], result, sizeof(*result)) != sizeof(*result)) + return -1; + return 0; +} + +int rslave_readResult(struct rslave_s *rslave, struct rslave_result_s *result) +{ + if (read(rslave->pipeFromSlaves[0], result, sizeof(*result)) != sizeof(*result)) + return -1; + return 0; +} + +void be_a_dnsslave(struct rslave_s *rslave); +void be_a_dnsslave(struct rslave_s *rslave) +{ + struct rslave_request_s req; + while (rslave_readRequest(rslave, &req) == 0) { + struct rslave_result_s result; + struct hostent *h; + //fprintf(stderr, "Calling gethostbyname on %s\n", req.hname); + h = gethostbyname(req.hname); + memset(&result, 0, sizeof(result)); + result.id = req.id; + result.err = h_errno; + if (h && (h->h_length == sizeof(result.addr))) { + memcpy(result.addr, h->h_addr_list[0], (unsigned) h->h_length); + result.err = 0; + } + if (rslave_writeResult(rslave, &result)) + break; + } + exit(0); +} + +/*-------------------------------------------------------------------------- + Initialize an rslave_s and fork slave processes. + Returns 0 on success, -1 on error. +--------------------------------------------------------------------------*/ + +int rslave_init(struct rslave_s *rslave) +{ + int err; + int i; + int nslaves = rslave_NSLAVES; + + memset(rslave, 0, sizeof(*rslave)); + err = pipe(rslave->pipeToSlaves); + if (err == -1) + return -1; + err = pipe(rslave->pipeFromSlaves); + if (err == -1) + return -1; + + for (i=0; i<nslaves; i++) { + pid_t childpid; + childpid = fork(); + switch (childpid) { + case -1: + return -1; + break; + + case 0: /* child */ + close(rslave->pipeToSlaves[1]); + close(rslave->pipeFromSlaves[0]); + be_a_dnsslave(rslave); + break; + default: /* parent */ + rslave->pids[i] = childpid; /* Save pid so we can kill it later */ + break; + } + } + close(rslave->pipeToSlaves[0]); + close(rslave->pipeFromSlaves[1]); + + rslave->nslaves = nslaves; + return 0; +} + +/* TODO: add rslave_shutdown() that kills all the slaves by iterating through rslave->pids[] */ + diff --git a/distcc/src/rslave.h b/distcc/src/rslave.h new file mode 100644 index 0000000..6ed8ea2 --- /dev/null +++ b/distcc/src/rslave.h @@ -0,0 +1,65 @@ +/* Copyright (C) 2005 by Google + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ +#ifndef rslave_H +#define rslave_H + +/* don't blame me, I was in a hurry */ + +#include <unistd.h> /* for pid_t */ + +/* maximum length of hostname */ +#define rslave_HOSTLEN 200 + +/* Number of DNS slave processes. Emperically I've found that I need + * for up to about 50 servers, you need 1 for main lookup plus two spares for retries; + * for up to about 150 servers, you need 2 for main lookup plus a few spares for retries. + * Six seems like it should be enough for most sites. + */ +#define rslave_NSLAVES 6 + +struct rslave_s { + int nslaves; + int pipeToSlaves[2]; + int pipeFromSlaves[2]; + pid_t pids[rslave_NSLAVES]; +}; + +struct rslave_request_s { + int id; + char hname[rslave_HOSTLEN+1]; +}; +typedef struct rslave_request_s rslave_request_t; + +struct rslave_result_s { + int id; + int err; + unsigned char addr[4]; +}; +typedef struct rslave_result_s rslave_result_t; + +int rslave_init(struct rslave_s *rslave); +int rslave_gethostbyname(struct rslave_s *rslave, const char *hostname, int id); +void rslave_request_init(struct rslave_request_s *buf, const char *hostname, int id); +int rslave_readRequest(struct rslave_s *rslave, struct rslave_request_s *req); +int rslave_writeRequest(struct rslave_s *rslave, const struct rslave_request_s *req); +int rslave_writeResult(struct rslave_s *rslave, struct rslave_result_s *result); +int rslave_readResult(struct rslave_s *rslave, struct rslave_result_s *result); +int rslave_getfd_fromSlaves(struct rslave_s *rslave); +int rslave_getfd_toSlaves(struct rslave_s *rslave); + +#endif diff --git a/distcc/src/safeguard.c b/distcc/src/safeguard.c new file mode 100644 index 0000000..204484e --- /dev/null +++ b/distcc/src/safeguard.c @@ -0,0 +1,81 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "exitcode.h" + + +/** + * @file + * @brief Protect against unbounded recursion. + * + * It would be fairly easy for somebody to get confused in masquerade mode and + * try to get distcc to invoke itself in a loop. We can't always work out the + * right thing to do but we can at least flag an error. + * + * This environment variable is set to guard against distcc accidentally + * recursively invoking itself, thinking it's the real compiler. + **/ + +static const char dcc_safeguard_name[] = "_DISTCC_SAFEGUARD"; +static char dcc_safeguard_set[] = "_DISTCC_SAFEGUARD=1"; +static int dcc_safeguard_level; + +int dcc_recursion_safeguard(void) +{ + char *env = getenv(dcc_safeguard_name); + + if (env) { + rs_trace("safeguard: %s", env); + if (!(dcc_safeguard_level = atoi(env))) + dcc_safeguard_level = 1; + } + else + dcc_safeguard_level = 0; + rs_trace("safeguard level=%d", dcc_safeguard_level); + + return dcc_safeguard_level; +} + + +int dcc_increment_safeguard(void) +{ + if (dcc_safeguard_level > 0) + dcc_safeguard_set[sizeof dcc_safeguard_set-2] = dcc_safeguard_level+'1'; + rs_trace("setting safeguard: %s", dcc_safeguard_set); + if ((putenv(strdup(dcc_safeguard_set)) == -1)) { + rs_log_error("putenv failed"); + /* and continue */ + } + + return 0; +} diff --git a/distcc/src/sendfile.c b/distcc/src/sendfile.c new file mode 100644 index 0000000..794d294 --- /dev/null +++ b/distcc/src/sendfile.c @@ -0,0 +1,212 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + /* "I've always wanted to use sendfile(), but + * never had a reason until now" + * -- mbp */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> +#ifdef HAVE_SYS_SENDFILE_H +# include <sys/sendfile.h> +#endif /* !HAVE_SYS_SENDFILE_H */ +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "exitcode.h" + + + +/* + * Could also use sendfilev() on Solaris >= 8: + * + * http://docs.sun.com/db/doc/816-0217/6m6nhtaps?a=view + */ + + +#ifdef HAVE_SENDFILE +/* If you don't have it, just use dcc_pump_readwrite */ + +/** + * sys_sendfile maps all the different implementations of sendfile() into + * something like the Linux interface. + * + * Our sockets are never non-blocking, so that seems to me to say that + * the kernel will never return EAGAIN -- we will always either send + * the whole thing or get an error. Is that really true? + * + * How nice to have the function parameters reversed between platforms + * in a way that will not give a compiler warning. + * + * @param offset offset in input to start writing; updated on return + * to reflect the number of bytes sent. + * + * sys_sendfile returns the number of bytes sent, if transmission succeeded. + * If there was an error, it returns -1 with errno set. It should never + * return 0. + **/ + + +#if defined(__FreeBSD__) +static ssize_t sys_sendfile(int ofd, int ifd, off_t *offset, size_t size) +{ + off_t sent_bytes; + int ret; + + /* According to the manual, this can never partially complete on a + * socket open for blocking IO. */ + ret = sendfile(ifd, ofd, *offset, size, 0, &sent_bytes, 0); + if (ret == -1) { + /* http://cvs.apache.org/viewcvs.cgi/apr/network_io/unix/sendrecv.c?rev=1.95&content-type=text/vnd.viewcvs-markup */ + if (errno == EAGAIN) { + if (sent_bytes == 0) { + /* Didn't send anything. Return error with errno == EAGAIN. */ + return -1; + } else { + /* We sent some bytes, but they we would block. Treat this as + * success for now. */ + *offset += sent_bytes; + return sent_bytes; + } + } else { + /* some other error */ + return -1; + } + } else if (ret == 0) { + *offset += size; + return size; + } else { + rs_log_error("don't know how to handle return %d from BSD sendfile", + ret); + return -1; + } +} +#elif defined(linux) +static ssize_t sys_sendfile(int ofd, int ifd, off_t *offset, size_t size) +{ + return sendfile(ofd, ifd, offset, size); +} +#elif defined(__hpux) || defined(__hpux__) +/* HP cc in ANSI mode defines __hpux; gcc defines __hpux__ */ +static ssize_t sys_sendfile(int ofd, int ifd, off_t *offset, size_t size) +{ + ssize_t ret; + + ret = sendfile(ofd, ifd, *offset, size, NULL, 0); + if (ret == -1) { + return -1; + } else if (ret > 0) { + *offset += ret; + return ret; + } else { + rs_log_error("don't know how to handle return %ld from HP-UX sendfile", + (long) ret); + return -1; + } +} +#else +#warning "Please write a sendfile implementation for this system" +static ssize_t sys_sendfile(int ofd, int ifd, off_t *offset, size_t size) +{ + rs_log_warning("no sendfile implementation on this platform"); + errno = ENOSYS; + return -1; +} +#endif /* !(__FreeBSD__) && !def(linux) */ + + +/* + * Transmit the body of a file using sendfile(). + * + * Linux at the moment requires the input be page-based -- ie a disk file, and + * only on particular filesystems. If the sendfile() call fails in a way that + * makes us think that regular IO might work, then we try that instead. For + * example, the /tmp filesystem may not support sendfile(). + */ +int +dcc_pump_sendfile(int ofd, int ifd, size_t size) +{ + ssize_t sent; + off_t offset = 0; + int ret; + + while (size) { + /* Handle possibility of partial transmission, e.g. if + * sendfile() is interrupted by a signal. size is decremented + * as we go. */ + + sent = sys_sendfile(ofd, ifd, &offset, size); + if (sent == -1) { + if ((errno == ENOSYS || errno == EINVAL) && offset == 0) { + /* The offset==0 tests is because we may be part way through + * the file. We can't just naively go back to read/write + * because sendfile() does not update the file pointer: we + * would need to lseek() first. That case is not handled at + * the moment because it's unlikely that sendfile() would + * suddenly be unsupported while we're using it. A failure + * halfway through probably indicates a genuine error.*/ + + rs_log_info("decided to use read/write rather than sendfile"); + return dcc_pump_readwrite(ofd, ifd, size); + } else if (errno == EAGAIN) { + /* Sleep until we're able to write out more data. */ + if ((ret = dcc_select_for_write(ofd, dcc_io_timeout)) != 0) + return ret; + rs_trace("select() returned, continuing to write"); + } else if (errno == EINTR) { + rs_trace("sendfile() interrupted, continuing"); + } else { + rs_log_error("sendfile failed: %s", strerror(errno)); + return EXIT_IO_ERROR; + } + } else if (sent == 0) { + rs_log_error("sendfile returned 0? can't cope"); + return EXIT_IO_ERROR; + } else if (sent != (ssize_t) size) { + /* offset is automatically updated by sendfile. */ + size -= sent; + rs_log_notice("sendfile: partial transmission of %ld bytes; retrying %ld @%ld", + (long) sent, (long) size, (long) offset); + } else { + /* normal case, everything was sent. */ + break; + } + } + return 0; +} +#endif /* def HAVE_SENDFILE */ + diff --git a/distcc/src/serve.c b/distcc/src/serve.c new file mode 100644 index 0000000..fc71235 --- /dev/null +++ b/distcc/src/serve.c @@ -0,0 +1,781 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + /* He who waits until circumstances completely favour * + * his undertaking will never accomplish anything. * + * -- Martin Luther */ + + +/** + * @file + * + * Actually serve remote requests. Called from daemon.c. + * + * @todo Make sure wait statuses are packed in a consistent format + * (exit<<8 | signal). Is there any platform that doesn't do this? + * + * @todo The server should catch signals, and terminate the compiler process + * group before handling them. + * + * @todo It might be nice to detect that the client has dropped the + * connection, and then kill the compiler immediately. However, we probably + * won't notice that until we try to do IO. SIGPIPE won't help because it's + * not triggered until we try to do IO. I don't think it matters a lot, + * though, because the client's not very likely to do that. The main case is + * probably somebody getting bored and interrupting compilation. + * + * What might help is to select() on the network socket while we're waiting + * for the child to complete, allowing SIGCHLD to interrupt the select() when + * the child completes. However I'm not sure if it's really worth the trouble + * of doing that just to handle a fairly marginal case. + **/ + + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <setjmp.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> +#include <time.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#ifdef HAVE_SYS_SIGNAL_H +# include <sys/signal.h> +#endif /* HAVE_SYS_SIGNAL_H */ +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "stats.h" +#include "rpc.h" +#include "exitcode.h" +#include "snprintf.h" +#include "dopt.h" +#include "bulk.h" +#include "exec.h" +#include "srvnet.h" +#include "hosts.h" +#include "daemon.h" +#include "stringmap.h" +#include "dotd.h" +#include "fix_debug_info.h" + +/** + * We copy all serious distccd messages to this file, as well as sending the + * compiler errors there, so they're visible to the client. + **/ +static int dcc_compile_log_fd = -1; + +static int dcc_run_job(int in_fd, int out_fd); + + +/** + * Copy all server messages to the error file, so that they can be + * echoed back to the client if necessary. + **/ +static int dcc_add_log_to_file(const char *err_fname) +{ + if (dcc_compile_log_fd != -1) { + rs_log_crit("compile log already open?"); + return 0; /* continue? */ + } + + dcc_compile_log_fd = open(err_fname, O_WRONLY|O_CREAT|O_TRUNC, 0600); + if (dcc_compile_log_fd == -1) { + rs_log_error("failed to open %s: %s", err_fname, strerror(errno)); + return EXIT_IO_ERROR; + } + + /* Only send fairly serious errors back */ + rs_add_logger(rs_logger_file, RS_LOG_WARNING, NULL, dcc_compile_log_fd); + + return 0; +} + + + +static int dcc_remove_log_to_file(void) +{ + if (dcc_compile_log_fd == -1) { + rs_log_warning("compile log not open?"); + return 0; /* continue? */ + } + + /* must exactly match call in dcc_add_log_to_file */ + rs_remove_logger(rs_logger_file, RS_LOG_WARNING, NULL, + dcc_compile_log_fd); + + dcc_close(dcc_compile_log_fd); + + dcc_compile_log_fd = -1; + + return 0; +} + + + +/* Read and execute a job to/from socket. This is the common entry point no + * matter what mode the daemon is running in: preforked, nonforked, or + * ssh/inetd. + */ +int dcc_service_job(int in_fd, + int out_fd, + struct sockaddr *cli_addr, + int cli_len) +{ + int ret; + + dcc_job_summary_clear(); + + /* Log client name and check access if appropriate. For ssh connections + * the client comes from a unix-domain socket and that's always + * allowed. */ + if ((ret = dcc_check_client(cli_addr, cli_len, opt_allowed)) != 0) + goto out; + + ret = dcc_run_job(in_fd, out_fd); + + dcc_job_summary(); + +out: + return ret; +} + + +static int dcc_input_tmpnam(char * orig_input, + char **tmpnam_ret) +{ + const char *input_exten; + + rs_trace("input file %s", orig_input); + input_exten = dcc_find_extension(orig_input); + if (input_exten) + input_exten = dcc_preproc_exten(input_exten); + if (!input_exten) /* previous line might return NULL */ + input_exten = ".tmp"; + return dcc_make_tmpnam("distccd", input_exten, tmpnam_ret); +} + + + +/** + * Check argv0 against a list of allowed commands, and possibly map it to a new value. + * If *compiler_name is changed, the original value is free'd, and a new value is malloc'd. + * + * If the environment variable DISTCC_CMDLIST is set, + * load a list of supported commands from the file named by DISTCC_CMDLIST, and + * refuse to serve any command whose last DISTCC_CMDLIST_NUMWORDS last words + * don't match those of a command in that list. + * Each line of the file is simply a filename. + * This is chiefly useful for those few installations which have so many + * compilers available such that the compiler must be specified with an absolute pathname. + * + * Example: if the compilers are installed in a different location on + * this server, e.g. if they've been copied from a shared NFS directory onto a + * local hard drive, you might have lines like + * /local/tools/blort/sh4-linux/gcc-3.3.3-glibc-2.2.5/bin/sh4-linux-gcc + * /local/tools/blort/sh4-linux/gcc-2.95.3-glibc-2.2.5/bin/sh4-linux-gcc + * and set DISTCC_CMDLIST_NUMWORDS=3; that way e.g. any of the commands + * /local/tools/gcc-3.3.3-glibc-2.2.5/bin/sh4-linux-gcc + * /shared/tools/gcc-3.3.3-glibc-2.2.5/bin/sh4-linux-gcc + * /zounds/gcc-3.3.3-glibc-2.2.5/bin/sh4-linux-gcc + * will invoke + * /local/tools/blort/sh4-linux/gcc-3.3.3-glibc-2.2.5/bin/sh4-linux-gcc + * + * Returns 0 (which will abort the compile) if compiler not in list. + * (This is because the list is intended to be complete, + * and any attempt to use a command not in the list indicates a confused user. + * FIXME: should probably give user the option of changing this + * behavior at runtime, so normal command lookup can continue even if command + * not found in table.) + **/ +static int dcc_remap_compiler(char **compiler_name) +{ + static int cmdlist_checked=0; + static stringmap_t *map=0; + const char *newname; + + /* load file if not already */ + if (!cmdlist_checked) { + char *filename; + cmdlist_checked = 1; + filename = getenv("DISTCC_CMDLIST"); + if (filename) { + const char *nw = getenv("DISTCC_CMDLIST_NUMWORDS"); + int numFinalWordsToMatch=1; + if (nw) + numFinalWordsToMatch = atoi(nw); + map = stringmap_load(filename, numFinalWordsToMatch); + if (map) { + rs_trace("stringmap_load(%s, %d) found %d commands", filename, numFinalWordsToMatch, map->n); + } else { + rs_log_error("stringmap_load(%s, %d) failed: %s", filename, numFinalWordsToMatch, strerror(errno)); + return EXIT_IO_ERROR; + } + } + } + + if (!map) + return 1; /* no list of allowed names, so ok */ + + /* Find what this compiler maps to */ + newname = stringmap_lookup(map, *compiler_name); + if (!newname) { + rs_log_warning("lookup of %s in DISTCC_CMDLIST failed", *compiler_name); + return 0; /* not in list, so forbidden. FIXME: make failure an option */ + } + + /* If mapping is not the identity mapping, replace the original name */ + if (strcmp(newname, *compiler_name)) { + rs_trace("changed compiler from %s to %s", *compiler_name, newname); + free(*compiler_name); + *compiler_name = strdup(newname); + } + return 1; +} + + +/** + * Find the absolute path for the first occurrence of @p compiler_name on the + * PATH. Print a warning if it looks like a symlink to distcc. + * + * We want to guard against somebody accidentally running the server with a + * masqueraded compiler on its $PATH. The worst that's likely to happen here + * is wasting some time running a distcc or ccache client that does nothing, + * so it's not a big deal. (This could be easy to do if it's on the default + * PATH and they start the daemon from the command line.) + * + * At the moment we don't look for the compiler too. + **/ +static int dcc_check_compiler_masq(char *compiler_name) +{ + const char *envpath, *p, *n; + char *buf = NULL; + struct stat sb; + int len; + char linkbuf[MAXPATHLEN]; + + if (compiler_name[0] == '/') + return 0; + + if (!(envpath = getenv("PATH"))) { + rs_trace("PATH seems not to be defined"); + return 0; + } + + for (n = p = envpath; *n; p = n) { + n = strchr(p, ':'); + if (n) + len = n++ - p; + else { + len = strlen(p); + n = p + len; + } + if (asprintf(&buf, "%.*s/%s", len, p, compiler_name) == -1) { + rs_log_crit("asprintf failed"); + return EXIT_DISTCC_FAILED; + } + + if (lstat(buf, &sb) == -1) + continue; /* ENOENT, EACCESS, etc */ + if (!S_ISLNK(sb.st_mode)) { + rs_trace("%s is not a symlink", buf); + break; /* found it */ + } + if ((len = readlink(buf, linkbuf, sizeof linkbuf)) <= 0) + continue; + linkbuf[len] = '\0'; + + if (strstr(linkbuf, "distcc")) { + rs_log_warning("%s on distccd's path is %s and really a link to %s", + compiler_name, buf, linkbuf); + break; /* but use it anyhow */ + } else { + rs_trace("%s is a safe symlink to %s", buf, linkbuf); + break; /* found it */ + } + } + + free(buf); + return 0; +} + +static const char *include_options[] = { + "-I", + "-include", + "-imacros", + "-idirafter", + "-iprefix", + "-iwithprefix", + "-iwithprefixbefore", + "-isystem", + "-iquote", + NULL +}; + + +/** + * Prepend @p root_dir string to source file if absolute. + **/ +static int tweak_input_argument_for_server(char **argv, + const char *root_dir) +{ + unsigned i; + /* Look for the source file and act if absolute. Note: dcc_scan_args + * rejects compilations with more than one source file. */ + for (i=0; argv[i]; i++) + if (dcc_is_source(argv[i]) && argv[i][0]=='/') { + unsigned j = 0; + char *prefixed_name; + while (argv[i][j] == '/') j++; + if (asprintf(&prefixed_name, "%s/%s", + root_dir, + argv[i] + j) == -1) { + rs_log_crit("asprintf failed"); + return EXIT_OUT_OF_MEMORY; + } + rs_trace("changed input from \"%s\" to \"%s\"", argv[i], + prefixed_name); + free(argv[i]); + argv[i] = prefixed_name; + dcc_trace_argv("command after", argv); + return 0; + } + return 0; +} + + +/** + * Prepend @p root_dir to arguments of include options that are absolute. + **/ +static int tweak_include_arguments_for_server(char **argv, + const char *root_dir) +{ + int index_of_first_filename_char = 0; + const char *include_option; + unsigned int i, j; + for (i = 0; argv[i]; ++i) { + for (j = 0; include_options[j]; ++j) { + if (str_startswith(include_options[j], argv[i])) { + if (strcmp(argv[i], include_options[j]) == 0) { + // "-I foo" , change the next argument + ++i; + include_option = ""; + index_of_first_filename_char = 0; + } else { + // "-Ifoo", change this argument + include_option = include_options[j]; + index_of_first_filename_char = strlen(include_option); + } + if (argv[i] != NULL) { // in case of a dangling -I + if (argv[i][index_of_first_filename_char] == '/') { + char *buf; + asprintf(&buf, "%s%s%s", + include_option, + root_dir, + argv[i] + index_of_first_filename_char); + if (buf == NULL) { + return EXIT_OUT_OF_MEMORY; + } + free(argv[i]); + argv[i] = buf; + } + } + break; // from the inner loop; go look at the next argument + } + } + } + return 0; +} + +/* The -MT command line flag does not work as advertised for distcc: + * it augments, rather than replace, the list of targets in the dotd file. + * The behavior we want though, is the replacing behavior. + * So here we delete the "-MT target" arguments, and we return the target, + * for use in the .d rewritting in dotd.c. + */ +static int dcc_convert_mt_to_dotd_target(char **argv, char **dotd_target) +{ + int i; + *dotd_target = NULL; + + for (i = 0; argv[i]; ++i) { + if (strcmp(argv[i], "-MT") == 0) { + break; + } + } + + // if we reached the end without finding -MT, fine. + if (argv[i] == NULL) + return 0; + + // if we find -MT but only at the very end, that's an error. + if (argv[i+1] == NULL) { + rs_trace("found -MF at the end of the command line"); + return 1; + } + + // the dotd_target is the argument of -MT + *dotd_target = argv[i+1]; + + // copy the next-next argument on top of this. + for (; argv[i+2]; ++i) { + argv[i] = argv[i+2]; + } + + // and then put the terminal null in. + argv[i] = argv[i+2]; + + return 0; +} + + +/** + * Add -MMD and -MF to get a .d file. + * Find what the dotd target should be (if any). + * Prepend @p root_dir to every command + * line argument that refers to a file/dir by an absolute name. + **/ +static int tweak_arguments_for_server(char **argv, + const char *root_dir, + const char *deps_fname, + char **dotd_target, + char ***tweaked_argv) +{ + int ret; + *dotd_target = 0; + if ((ret = dcc_copy_argv(argv, tweaked_argv, 3))) + return 1; + + if ((ret = dcc_convert_mt_to_dotd_target(*tweaked_argv, dotd_target))) + return 1; + + dcc_argv_append(*tweaked_argv, strdup("-MMD")); + dcc_argv_append(*tweaked_argv, strdup("-MF")); + dcc_argv_append(*tweaked_argv, strdup(deps_fname)); + + tweak_include_arguments_for_server(*tweaked_argv, root_dir); + tweak_input_argument_for_server(*tweaked_argv, root_dir); + return 0; +} + + +/** + * Read the client working directory from in_fd socket, + * and set up the server side directory corresponding to that. + * Inputs: + * @p in_fd: the file descriptor for the socket. + * Outputs: + * @p temp_dir: a temporary directory on the server, + * corresponding to the client's root directory (/), + * @p client_side_cwd: the current directory on the client + * @p server_side_cwd: the corresponding directory on the server; + * server_side_cwd = temp_dir + client_side_cwd + **/ +static int make_temp_dir_and_chdir_for_cpp(int in_fd, + char **temp_dir, char **client_side_cwd, char **server_side_cwd) +{ + + int ret = 0; + + if ((ret = dcc_get_new_tmpdir(temp_dir))) + return ret; + if ((ret = dcc_r_cwd(in_fd, client_side_cwd))) + return ret; + + asprintf(server_side_cwd, "%s%s", *temp_dir, *client_side_cwd); + if (*server_side_cwd == NULL) { + ret = EXIT_OUT_OF_MEMORY; + } else if ((ret = dcc_mk_tmp_ancestor_dirs(*server_side_cwd))) { + ; // leave ret the way it is + } else if ((ret = dcc_mk_tmpdir(*server_side_cwd))) { + ; // leave ret the way it is + } else if (chdir(*server_side_cwd) == -1) { + ret = EXIT_IO_ERROR; + } + return ret; +} + + +/** + * Read a request, run the compiler, and send a response. + **/ +static int dcc_run_job(int in_fd, + int out_fd) +{ + char **argv = NULL; + char **tweaked_argv = NULL; + int status = 0; + char *temp_i = NULL, *temp_o = NULL; + char *err_fname = NULL, *out_fname = NULL, *deps_fname = NULL; + char *temp_dir = NULL; /* for receiving multiple files */ + int ret = 0, compile_ret = 0; + char *orig_input = NULL, *orig_output = NULL; + char *orig_input_tmp, *orig_output_tmp; + char *dotd_target = NULL; + pid_t cc_pid; + enum dcc_protover protover; + enum dcc_compress compr; + struct timeval start, end; + int time_ms; + char *time_str; + int job_result = -1; + enum dcc_cpp_where cpp_where; + char *server_cwd = NULL; + char *client_cwd = NULL; + + gettimeofday(&start, NULL); + + if ((ret = dcc_make_tmpnam("distcc", ".deps", &deps_fname))) + goto out_cleanup; + if ((ret = dcc_make_tmpnam("distcc", ".stderr", &err_fname))) + goto out_cleanup; + if ((ret = dcc_make_tmpnam("distcc", ".stdout", &out_fname))) + goto out_cleanup; + + dcc_remove_if_exists(deps_fname); + dcc_remove_if_exists(err_fname); + dcc_remove_if_exists(out_fname); + + /* Capture any messages relating to this compilation to the same file as + * compiler errors so that they can all be sent back to the client. */ + dcc_add_log_to_file(err_fname); + + /* Ignore SIGPIPE; we consistently check error codes and will see the + * EPIPE. Note that it is set back to the default behaviour when spawning + * a child, to handle cases like the assembler dying while its being fed + * from the compiler */ + dcc_ignore_sigpipe(1); + + /* Allow output to accumulate into big packets. */ + tcp_cork_sock(out_fd, 1); + + if ((ret = dcc_r_request_header(in_fd, &protover))) + goto out_cleanup; + + dcc_get_features_from_protover(protover, &compr, &cpp_where); + + if (cpp_where == DCC_CPP_ON_SERVER) + if ((ret = make_temp_dir_and_chdir_for_cpp(in_fd, + &temp_dir, &client_cwd, &server_cwd))) + goto out_cleanup; + + if ((ret = dcc_r_argv(in_fd, &argv)) + || (ret = dcc_scan_args(argv, &orig_input_tmp, &orig_output_tmp, + &tweaked_argv))) + goto out_cleanup; + + /* The orig_input_tmp and orig_output_tmp values returned by dcc_scan_args() + * are aliased with some element of tweaked_argv. We need to copy them, + * because the calls to dcc_set_input() and dcc_set_output() below will + * free those elements. */ + orig_input = strdup(orig_input_tmp); + orig_output = strdup(orig_output_tmp); + if (orig_input == NULL || orig_output == NULL) { + ret = EXIT_OUT_OF_MEMORY; + goto out_cleanup; + } + + /* Our new argv is what dcc_scan_args put into tweaked_argv */ + /* Put tweaked_argv into argv, and free old argv */ + dcc_free_argv(argv); + argv = tweaked_argv; + tweaked_argv = NULL; + + rs_trace("output file %s", orig_output); + if ((ret = dcc_make_tmpnam("distccd", ".o", &temp_o))) + goto out_cleanup; + + /* if the protocol is multi-file, then we need to do the following + * in a loop. + */ + if (cpp_where == DCC_CPP_ON_SERVER) { + if (dcc_r_many_files(in_fd, temp_dir, compr) + || dcc_set_output(argv, temp_o) + || tweak_arguments_for_server(argv, temp_dir, deps_fname, + &dotd_target, &tweaked_argv)) + goto out_cleanup; + /* Repeat the switcharoo trick a few lines above. */ + dcc_free_argv(argv); + argv = tweaked_argv; + tweaked_argv = NULL; + } else { + if ((ret = dcc_input_tmpnam(orig_input, &temp_i))) + goto out_cleanup; + if ((ret = dcc_r_token_file(in_fd, "DOTI", temp_i, compr)) + || (ret = dcc_set_input(argv, temp_i)) + || (ret = dcc_set_output(argv, temp_o))) + goto out_cleanup; + } + + if (!dcc_remap_compiler(&argv[0])) + goto out_cleanup; + + if ((ret = dcc_check_compiler_masq(argv[0]))) + goto out_cleanup; + + if ((compile_ret = dcc_spawn_child(argv, &cc_pid, + "/dev/null", out_fname, err_fname)) + || (compile_ret = dcc_collect_child("cc", cc_pid, &status, in_fd))) { + /* We didn't get around to finding a wait status from the actual + * compiler */ + status = W_EXITCODE(compile_ret, 0); + } + + if ((ret = dcc_x_result_header(out_fd, protover)) + || (ret = dcc_x_cc_status(out_fd, status)) + || (ret = dcc_x_file(out_fd, err_fname, "SERR", compr, NULL)) + || (ret = dcc_x_file(out_fd, out_fname, "SOUT", compr, NULL)) + || WIFSIGNALED(status) + || WEXITSTATUS(status)) { + /* Something went wrong, so send DOTO 0 */ + dcc_x_token_int(out_fd, "DOTO", 0); + + if (job_result == -1) + job_result = STATS_COMPILE_ERROR; + } else { + if (cpp_where == DCC_CPP_ON_SERVER) { + rs_trace("fixing up debug info"); + /* + * We update the debugging information, replacing all occurrences + * of temp_dir (the server temp directory that corresponds to the + * client's root directory) with "/", to convert server path + * names to client path names. This is safe to do only because + * temp_dir is of the form "/var/tmp/distccd-XXXXXX" where XXXXXX + * is randomly chosen by mkdtemp(), which makes it inconceivably + * unlikely that this pattern could occur in the debug info by + * chance. + */ + if ((ret = dcc_fix_debug_info(temp_o, "/", temp_dir))) + goto out_cleanup; + } + if ((ret = dcc_x_file(out_fd, temp_o, "DOTO", compr, NULL))) + goto out_cleanup; + + if (cpp_where == DCC_CPP_ON_SERVER) { + char *cleaned_dotd; + ret = dcc_cleanup_dotd(deps_fname, + &cleaned_dotd, + temp_dir, + dotd_target ? dotd_target : orig_output, + temp_o); + if (ret) goto out_cleanup; + ret = dcc_x_file(out_fd, cleaned_dotd, "DOTD", compr, NULL); + free(cleaned_dotd); + } + + job_result = STATS_COMPILE_OK; + } + + if (compile_ret == EXIT_IO_ERROR) { + job_result = STATS_CLI_DISCONN; + } else if (compile_ret == EXIT_TIMEOUT) { + job_result = STATS_COMPILE_TIMEOUT; + } + + dcc_critique_status(status, argv[0], orig_input, dcc_hostdef_local, + 0); + tcp_cork_sock(out_fd, 0); + + rs_log(RS_LOG_INFO|RS_LOG_NONAME, "job complete"); + +out_cleanup: + + switch (ret) { + case EXIT_BUSY: /* overloaded */ + job_result = STATS_REJ_OVERLOAD; + break; + case EXIT_IO_ERROR: /* probably client disconnected */ + job_result = STATS_CLI_DISCONN; + break; + case EXIT_PROTOCOL_ERROR: + job_result = STATS_REJ_BAD_REQ; + break; + default: + if (job_result != STATS_COMPILE_ERROR + && job_result != STATS_COMPILE_OK + && job_result != STATS_CLI_DISCONN + && job_result != STATS_COMPILE_TIMEOUT) { + job_result = STATS_OTHER; + } + } + + gettimeofday(&end, NULL); + time_ms = (end.tv_sec - start.tv_sec) * 1000 + (end.tv_usec - start.tv_usec) / 1000; + + dcc_job_summary_append(" "); + dcc_job_summary_append(stats_text[job_result]); + + if (job_result == STATS_COMPILE_OK) { + /* special case, also log compiler, file and time */ + dcc_stats_compile_ok(argv[0], orig_input, time_ms); + } else { + dcc_stats_event(job_result); + } + + asprintf(&time_str, " exit:%d sig:%d core:%d ret:%d time:%dms ", WEXITSTATUS(status), WTERMSIG(status), WCOREDUMP(status), ret, time_ms); + dcc_job_summary_append(time_str); + free(time_str); + + /* append compiler and input file info */ + if (job_result == STATS_COMPILE_ERROR + || job_result == STATS_COMPILE_OK) { + dcc_job_summary_append(argv[0]); + dcc_job_summary_append(" "); + dcc_job_summary_append(orig_input); + } + + dcc_remove_log_to_file(); + dcc_cleanup_tempfiles(); + + free(orig_input); + free(orig_output); + + if (argv) + dcc_free_argv(argv); + if (tweaked_argv) + dcc_free_argv(tweaked_argv); + + free(temp_dir); + free(temp_i); + free(temp_o); + + free(deps_fname); + free(err_fname); + free(out_fname); + + free(client_cwd); + free(server_cwd); + + return ret; +} diff --git a/distcc/src/setuid.c b/distcc/src/setuid.c new file mode 100644 index 0000000..d929a53 --- /dev/null +++ b/distcc/src/setuid.c @@ -0,0 +1,138 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include "config.h" + +#include <stdlib.h> +#include <unistd.h> +#include <pwd.h> +#include <grp.h> +#include <errno.h> +#include <string.h> + +#include "distcc.h" +#include "trace.h" +#include "daemon.h" +#include "exitcode.h" + + +const char *opt_user = "distcc"; + + +/** + * @file + * + * Functions for setting the daemon's persona. + * + * It is better to create separate userids for daemons rather than to just use + * "nobody". + * + * Personas may be specified either as a name or an ID. + **/ + +/** + * Try to find an appropriate uid,gid to change to. + * + * In order, we try "distcc" or the user on the command line, or "nobody", or + * failing that the traditional value for nobody of 65534. + */ +static int dcc_preferred_user(uid_t *puid, gid_t *pgid) +{ + struct passwd *pw; + + if ((pw = getpwnam(opt_user))) { + *puid = pw->pw_uid; + *pgid = pw->pw_gid; + return 0; /* cool */ + } + /* Note getpwnam() does not set errno */ + rs_log_warning("no such user as \"%s\"", opt_user); + /* try something else */ + + if ((pw = getpwnam("nobody"))) { + *puid = pw->pw_uid; + *pgid = pw->pw_gid; + return 0; /* cool */ + } + + /* just use traditional value */ + *puid = *pgid = 65534; + return 0; +} + + +/** + * Make sure that distccd never runs as root, by discarding privileges if we + * have them. + * + * This used to also check gid!=0, but on BSD that is group wheel and is + * apparently common for daemons or users. + * + * This is run before dissociating from the calling terminal so any errors go + * to stdout. + **/ +int dcc_discard_root(void) +{ + uid_t uid; + gid_t gid; + int ret; + + if (getuid() != 0 && geteuid() != 0) { + /* Already not root. No worries. */ + return 0; + } + + if ((ret = dcc_preferred_user(&uid, &gid)) != 0) + return ret; + + /* GNU C Library Manual says that when run by root, setgid() and setuid() + * permanently discard privileges: both the real and effective uid are + * set. */ + + if (setgid(gid)) { + rs_log_error("setgid(%d) failed: %s", (int) gid, strerror(errno)); + return EXIT_SETUID_FAILED; + } + +#ifdef HAVE_SETGROUPS + /* Get rid of any supplementary groups this process might have + * inherited. */ + /* XXX: OS X Jaguar broke setgroups so that setting it to 0 fails. */ + if (setgroups(1, &gid)) { + rs_log_error("setgroups failed: %s", strerror(errno)); + return EXIT_SETUID_FAILED; + } +#endif + + if (setuid(uid)) { + rs_log_error("setuid(%d) failed: %s", (int) uid, strerror(errno)); + return EXIT_SETUID_FAILED; + } + + if (getuid() == 0 || geteuid() == 0) { + rs_log_crit("still have root privileges after trying to discard them!"); + return EXIT_SETUID_FAILED; + } + + rs_trace("discarded root privileges, changed to uid=%d gid=%d", (int) uid, (int) gid); + return 0; +} diff --git a/distcc/src/snprintf.c b/distcc/src/snprintf.c new file mode 100644 index 0000000..f7885db --- /dev/null +++ b/distcc/src/snprintf.c @@ -0,0 +1,1016 @@ +/* + * NOTE: If you change this file, please merge it into rsync, samba, etc. + */ + +/* + * Copyright Patrick Powell 1995 + * This code is based on code written by Patrick Powell (papowell@astart.com) + * It may be used for any purpose as long as this notice remains intact + * on all source code distributions + */ + +/************************************************************** + * Original: + * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 + * A bombproof version of doprnt (dopr) included. + * Sigh. This sort of thing is always nasty do deal with. Note that + * the version here does not include floating point... + * + * snprintf() is used instead of sprintf() as it does limit checks + * for string length. This covers a nasty loophole. + * + * The other functions are there to prevent NULL pointers from + * causing nast effects. + * + * More Recently: + * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43 + * This was ugly. It is still ugly. I opted out of floating point + * numbers, but the formatter understands just about everything + * from the normal C string format, at least as far as I can tell from + * the Solaris 2.5 printf(3S) man page. + * + * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1 + * Ok, added some minimal floating point support, which means this + * probably requires libm on most operating systems. Don't yet + * support the exponent (e,E) and sigfig (g,G). Also, fmtint() + * was pretty badly broken, it just wasn't being exercised in ways + * which showed it, so that's been fixed. Also, formated the code + * to mutt conventions, and removed dead code left over from the + * original. Also, there is now a builtin-test, just compile with: + * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm + * and run snprintf for results. + * + * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i + * The PGP code was using unsigned hexadecimal formats. + * Unfortunately, unsigned formats simply didn't work. + * + * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8 + * The original code assumed that both snprintf() and vsnprintf() were + * missing. Some systems only have snprintf() but not vsnprintf(), so + * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. + * + * Andrew Tridgell (tridge@samba.org) Oct 1998 + * fixed handling of %.0f + * added test for HAVE_LONG_DOUBLE + * + * tridge@samba.org, idra@samba.org, April 2001 + * got rid of fcvt code (twas buggy and made testing harder) + * added C99 semantics + * + * date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0 + * actually print args for %g and %e + * + * date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0 + * Since includes.h isn't included here, VA_COPY has to be defined here. I don't + * see any include file that is guaranteed to be here, so I'm defining it + * locally. Fixes AIX and Solaris builds. + * + * date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13 + * put the ifdef for HAVE_VA_COPY in one place rather than in lots of + * functions + * + * date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4 + * Fix usage of va_list passed as an arg. Use __va_copy before using it + * when it exists. + * + * date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14 + * Fix incorrect zpadlen handling in fmtfp. + * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it. + * few mods to make it easier to compile the tests. + * addedd the "Ollie" test to the floating point ones. + * + * Martin Pool (mbp@samba.org) April 2003 + * Remove NO_CONFIG_H so that the test case can be built within a source + * tree with less trouble. + * Remove unnecessary SAFE_FREE() definition. + * Update ifdefs to make sure that this file compiles to an (almost) empty + * object file on systems that already have all the functions we need. + **************************************************************/ + +#ifndef NO_CONFIG_H +#include "config.h" +#else +#define NULL 0 +#endif + +#ifdef TEST_SNPRINTF /* need math library headers for testing */ + +/* In test mode, we pretend that this system doesn't have any snprintf + * functions, regardless of what config.h says. */ +# undef HAVE_SNPRINTF +# undef HAVE_VSNPRINTF +# undef HAVE_C99_VSNPRINTF +# undef HAVE_ASPRINTF +# undef HAVE_VASPRINTF +# include <math.h> +#endif /* TEST_SNPRINTF */ + +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#ifdef HAVE_CTYPE_H +#include <ctype.h> +#endif +#include <sys/types.h> +#include <stdarg.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF) \ + && defined(HAVE_VASPRINTF) && defined(HAVE_ASPRINTF) +/* This ifdef switches on or off basically the whole contents of the file. */ +/* Make the compiler happy with an empty file */ + void dummy_snprintf(void); + void dummy_snprintf(void) {} +#else + +#include "snprintf.h" + +#ifdef HAVE_LONG_DOUBLE +#define LDOUBLE long double +#else +#define LDOUBLE double +#endif + +#ifdef HAVE_LONG_LONG +#define LLONG long long +#else +#define LLONG long +#endif + +#ifndef VA_COPY +#ifdef HAVE_VA_COPY +#define VA_COPY(dest, src) __va_copy(dest, src) +#else +#define VA_COPY(dest, src) (dest) = (src) +#endif /* ! HAVE_VA_COPY */ +#endif /* ndef VA_COPY */ + +static size_t dopr(char *buffer, size_t maxlen, const char *format, + va_list args_in); +static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max); +static void fmtint(char *buffer, size_t *currlen, size_t maxlen, + long value, int base, int min, int max, int flags); +static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, + LDOUBLE fvalue, int min, int max, int flags); +static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); + +/* + * dopr(): poor man's version of doprintf + */ + +/* format read states */ +#define DP_S_DEFAULT 0 +#define DP_S_FLAGS 1 +#define DP_S_MIN 2 +#define DP_S_DOT 3 +#define DP_S_MAX 4 +#define DP_S_MOD 5 +#define DP_S_CONV 6 +#define DP_S_DONE 7 + +/* format flags - Bits */ +#define DP_F_MINUS (1 << 0) +#define DP_F_PLUS (1 << 1) +#define DP_F_SPACE (1 << 2) +#define DP_F_NUM (1 << 3) +#define DP_F_ZERO (1 << 4) +#define DP_F_UP (1 << 5) +#define DP_F_UNSIGNED (1 << 6) + +/* Conversion Flags */ +#define DP_C_SHORT 1 +#define DP_C_LONG 2 +#define DP_C_LDOUBLE 3 +#define DP_C_LLONG 4 + +#define char_to_int(p) ((p)- '0') +#ifndef MAX +#define MAX(p,q) (((p) >= (q)) ? (p) : (q)) +#endif + +static size_t dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) +{ + char ch; + LLONG value; + LDOUBLE fvalue; + char *strvalue; + int min; + int max; + int state; + int flags; + int cflags; + size_t currlen; + va_list args; + + VA_COPY(args, args_in); + + state = DP_S_DEFAULT; + currlen = flags = cflags = min = 0; + max = -1; + ch = *format++; + + while (state != DP_S_DONE) { + if (ch == '\0') + state = DP_S_DONE; + + switch(state) { + case DP_S_DEFAULT: + if (ch == '%') + state = DP_S_FLAGS; + else + dopr_outch (buffer, &currlen, maxlen, ch); + ch = *format++; + break; + case DP_S_FLAGS: + switch (ch) { + case '-': + flags |= DP_F_MINUS; + ch = *format++; + break; + case '+': + flags |= DP_F_PLUS; + ch = *format++; + break; + case ' ': + flags |= DP_F_SPACE; + ch = *format++; + break; + case '#': + flags |= DP_F_NUM; + ch = *format++; + break; + case '0': + flags |= DP_F_ZERO; + ch = *format++; + break; + default: + state = DP_S_MIN; + break; + } + break; + case DP_S_MIN: + if (isdigit((unsigned char)ch)) { + min = 10*min + char_to_int (ch); + ch = *format++; + } else if (ch == '*') { + min = va_arg (args, int); + ch = *format++; + state = DP_S_DOT; + } else { + state = DP_S_DOT; + } + break; + case DP_S_DOT: + if (ch == '.') { + state = DP_S_MAX; + ch = *format++; + } else { + state = DP_S_MOD; + } + break; + case DP_S_MAX: + if (isdigit((unsigned char)ch)) { + if (max < 0) + max = 0; + max = 10*max + char_to_int (ch); + ch = *format++; + } else if (ch == '*') { + max = va_arg (args, int); + ch = *format++; + state = DP_S_MOD; + } else { + state = DP_S_MOD; + } + break; + case DP_S_MOD: + switch (ch) { + case 'h': + cflags = DP_C_SHORT; + ch = *format++; + break; + case 'l': + cflags = DP_C_LONG; + ch = *format++; + if (ch == 'l') { /* It's a long long */ + cflags = DP_C_LLONG; + ch = *format++; + } + break; + case 'L': + cflags = DP_C_LDOUBLE; + ch = *format++; + break; + default: + break; + } + state = DP_S_CONV; + break; + case DP_S_CONV: + switch (ch) { + case 'd': + case 'i': + if (cflags == DP_C_SHORT) + value = va_arg (args, int); + else if (cflags == DP_C_LONG) + value = va_arg (args, long int); + else if (cflags == DP_C_LLONG) + value = va_arg (args, LLONG); + else + value = va_arg (args, int); + fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + break; + case 'o': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg (args, unsigned int); + else if (cflags == DP_C_LONG) + value = (long)va_arg (args, unsigned long int); + else if (cflags == DP_C_LLONG) + value = (long)va_arg (args, unsigned LLONG); + else + value = (long)va_arg (args, unsigned int); + fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); + break; + case 'u': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg (args, unsigned int); + else if (cflags == DP_C_LONG) + value = (long)va_arg (args, unsigned long int); + else if (cflags == DP_C_LLONG) + value = (LLONG)va_arg (args, unsigned LLONG); + else + value = (long)va_arg (args, unsigned int); + fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + break; + case 'X': + flags |= DP_F_UP; + case 'x': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg (args, unsigned int); + else if (cflags == DP_C_LONG) + value = (long)va_arg (args, unsigned long int); + else if (cflags == DP_C_LLONG) + value = (LLONG)va_arg (args, unsigned LLONG); + else + value = (long)va_arg (args, unsigned int); + fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); + break; + case 'f': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg (args, LDOUBLE); + else + fvalue = va_arg (args, double); + /* um, floating point? */ + fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); + break; + case 'E': + flags |= DP_F_UP; + case 'e': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg (args, LDOUBLE); + else + fvalue = va_arg (args, double); + fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); + break; + case 'G': + flags |= DP_F_UP; + case 'g': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg (args, LDOUBLE); + else + fvalue = va_arg (args, double); + fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); + break; + case 'c': + dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); + break; + case 's': + strvalue = va_arg (args, char *); + if (!strvalue) strvalue = "(NULL)"; + if (max == -1) { + max = strlen(strvalue); + } + if (min > 0 && max >= 0 && min > max) max = min; + fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); + break; + case 'p': + strvalue = va_arg (args, void *); + fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); + break; + case 'n': + if (cflags == DP_C_SHORT) { + short int *num; + num = va_arg (args, short int *); + *num = currlen; + } else if (cflags == DP_C_LONG) { + long int *num; + num = va_arg (args, long int *); + *num = (long int)currlen; + } else if (cflags == DP_C_LLONG) { + LLONG *num; + num = va_arg (args, LLONG *); + *num = (LLONG)currlen; + } else { + int *num; + num = va_arg (args, int *); + *num = currlen; + } + break; + case '%': + dopr_outch (buffer, &currlen, maxlen, ch); + break; + case 'w': + /* not supported yet, treat as next char */ + ch = *format++; + break; + default: + /* Unknown, skip */ + break; + } + ch = *format++; + state = DP_S_DEFAULT; + flags = cflags = min = 0; + max = -1; + break; + case DP_S_DONE: + break; + default: + /* hmm? */ + break; /* some picky compilers need this */ + } + } + if (maxlen != 0) { + if (currlen < maxlen - 1) + buffer[currlen] = '\0'; + else if (maxlen > 0) + buffer[maxlen - 1] = '\0'; + } + + return currlen; +} + +static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max) +{ + int padlen, strln; /* amount to pad */ + int cnt = 0; + +#ifdef DEBUG_SNPRINTF + printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value); +#endif + if (value == 0) { + value = "<NULL>"; + } + + for (strln = 0; value[strln]; ++strln); /* strlen */ + padlen = min - strln; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justify */ + + while ((padlen > 0) && (cnt < max)) { + dopr_outch (buffer, currlen, maxlen, ' '); + --padlen; + ++cnt; + } + while (*value && (cnt < max)) { + dopr_outch (buffer, currlen, maxlen, *value++); + ++cnt; + } + while ((padlen < 0) && (cnt < max)) { + dopr_outch (buffer, currlen, maxlen, ' '); + ++padlen; + ++cnt; + } +} + +/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ + +static void fmtint(char *buffer, size_t *currlen, size_t maxlen, + long value, int base, int min, int max, int flags) +{ + int signvalue = 0; + unsigned long uvalue; + char convert[20]; + int place = 0; + int spadlen = 0; /* amount to space pad */ + int zpadlen = 0; /* amount to zero pad */ + int caps = 0; + + if (max < 0) + max = 0; + + uvalue = value; + + if(!(flags & DP_F_UNSIGNED)) { + if( value < 0 ) { + signvalue = '-'; + uvalue = -value; + } else { + if (flags & DP_F_PLUS) /* Do a sign (+/i) */ + signvalue = '+'; + else if (flags & DP_F_SPACE) + signvalue = ' '; + } + } + + if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ + + do { + convert[place++] = + (caps? "0123456789ABCDEF":"0123456789abcdef") + [uvalue % (unsigned)base ]; + uvalue = (uvalue / (unsigned)base ); + } while(uvalue && (place < 20)); + if (place == 20) place--; + convert[place] = 0; + + zpadlen = max - place; + spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); + if (zpadlen < 0) zpadlen = 0; + if (spadlen < 0) spadlen = 0; + if (flags & DP_F_ZERO) { + zpadlen = MAX(zpadlen, spadlen); + spadlen = 0; + } + if (flags & DP_F_MINUS) + spadlen = -spadlen; /* Left Justifty */ + +#ifdef DEBUG_SNPRINTF + printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", + zpadlen, spadlen, min, max, place); +#endif + + /* Spaces */ + while (spadlen > 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + --spadlen; + } + + /* Sign */ + if (signvalue) + dopr_outch (buffer, currlen, maxlen, signvalue); + + /* Zeros */ + if (zpadlen > 0) { + while (zpadlen > 0) { + dopr_outch (buffer, currlen, maxlen, '0'); + --zpadlen; + } + } + + /* Digits */ + while (place > 0) + dopr_outch (buffer, currlen, maxlen, convert[--place]); + + /* Left Justified spaces */ + while (spadlen < 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + ++spadlen; + } +} + +static LDOUBLE abs_val(LDOUBLE value) +{ + LDOUBLE result = value; + + if (value < 0) + result = -value; + + return result; +} + +static LDOUBLE POW10(int exp) +{ + LDOUBLE result = 1; + + while (exp) { + result *= 10; + exp--; + } + + return result; +} + +static LLONG ROUND(LDOUBLE value) +{ + LLONG intpart; + + intpart = (LLONG)value; + value = value - intpart; + if (value >= 0.5) intpart++; + + return intpart; +} + +/* a replacement for modf that doesn't need the math library. Should + be portable, but slow */ +static double my_modf(double x0, double *iptr) +{ + int i; + long l; + double x = x0; + double f = 1.0; + + for (i=0;i<100;i++) { + l = (long)x; + if (l <= (x+1) && l >= (x-1)) break; + x *= 0.1; + f *= 10.0; + } + + if (i == 100) { + /* yikes! the number is beyond what we can handle. What do we do? */ + (*iptr) = 0; + return 0; + } + + if (i != 0) { + double i2; + double ret; + + ret = my_modf(x0-l*f, &i2); + (*iptr) = l*f + i2; + return ret; + } + + (*iptr) = l; + return x - (*iptr); +} + + +static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, + LDOUBLE fvalue, int min, int max, int flags) +{ + int signvalue = 0; + double ufvalue; + char iconvert[311]; + char fconvert[311]; + int iplace = 0; + int fplace = 0; + int padlen = 0; /* amount to pad */ + int zpadlen = 0; + int caps = 0; + int index; + double intpart; + double fracpart; + double temp; + + /* + * AIX manpage says the default is 0, but Solaris says the default + * is 6, and sprintf on AIX defaults to 6 + */ + if (max < 0) + max = 6; + + ufvalue = abs_val (fvalue); + + if (fvalue < 0) { + signvalue = '-'; + } else { + if (flags & DP_F_PLUS) { /* Do a sign (+/i) */ + signvalue = '+'; + } else { + if (flags & DP_F_SPACE) + signvalue = ' '; + } + } + +#if 0 + if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ +#endif + +#if 0 + if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */ +#endif + + /* + * Sorry, we only support 16 digits past the decimal because of our + * conversion method + */ + if (max > 16) + max = 16; + + /* We "cheat" by converting the fractional part to integer by + * multiplying by a factor of 10 + */ + + temp = ufvalue; + my_modf(temp, &intpart); + + fracpart = ROUND((POW10(max)) * (ufvalue - intpart)); + + if (fracpart >= POW10(max)) { + intpart++; + fracpart -= POW10(max); + } + + + /* Convert integer part */ + do { + temp = intpart*0.1; + my_modf(temp, &intpart); + index = (int) ((temp -intpart +0.05)* 10.0); + /* index = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */ + /* printf ("%llf, %f, %x\n", temp, intpart, index); */ + iconvert[iplace++] = + (caps? "0123456789ABCDEF":"0123456789abcdef")[index]; + } while (intpart && (iplace < 311)); + if (iplace == 311) iplace--; + iconvert[iplace] = 0; + + /* Convert fractional part */ + if (fracpart) + { + do { + temp = fracpart*0.1; + my_modf(temp, &fracpart); + index = (int) ((temp -fracpart +0.05)* 10.0); + /* index = (int) ((((temp/10) -fracpart) +0.05) *10); */ + /* printf ("%lf, %lf, %ld\n", temp, fracpart, index); */ + fconvert[fplace++] = + (caps? "0123456789ABCDEF":"0123456789abcdef")[index]; + } while(fracpart && (fplace < 311)); + if (fplace == 311) fplace--; + } + fconvert[fplace] = 0; + + /* -1 for decimal point, another -1 if we are printing a sign */ + padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); + zpadlen = max - fplace; + if (zpadlen < 0) zpadlen = 0; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justifty */ + + if ((flags & DP_F_ZERO) && (padlen > 0)) { + if (signvalue) { + dopr_outch (buffer, currlen, maxlen, signvalue); + --padlen; + signvalue = 0; + } + while (padlen > 0) { + dopr_outch (buffer, currlen, maxlen, '0'); + --padlen; + } + } + while (padlen > 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + --padlen; + } + if (signvalue) + dopr_outch (buffer, currlen, maxlen, signvalue); + + while (iplace > 0) + dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); + +#ifdef DEBUG_SNPRINTF + printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen); +#endif + + /* + * Decimal point. This should probably use locale to find the correct + * char to print out. + */ + if (max > 0) { + dopr_outch (buffer, currlen, maxlen, '.'); + + while (zpadlen > 0) { + dopr_outch (buffer, currlen, maxlen, '0'); + --zpadlen; + } + + while (fplace > 0) + dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); + } + + while (padlen < 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + ++padlen; + } +} + +static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) +{ + if (*currlen < maxlen) { + buffer[(*currlen)] = c; + } + (*currlen)++; +} + +/* yes this really must be a ||. Don't muck with this (tridge) */ +#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) + int vsnprintf (char *str, size_t count, const char *fmt, va_list args) +{ + return dopr(str, count, fmt, args); +} +#endif + +/* yes this really must be a ||. Don't muck wiith this (tridge) + * + * The logic for these two is that we need our own definition if the + * OS *either* has no definition of *sprintf, or if it does have one + * that doesn't work properly according to the autoconf test. Perhaps + * these should really be smb_snprintf to avoid conflicts with buggy + * linkers? -- mbp + */ +#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF) + int snprintf(char *str,size_t count,const char *fmt,...) +{ + size_t ret; + va_list ap; + + va_start(ap, fmt); + ret = vsnprintf(str, count, fmt, ap); + va_end(ap); + return ret; +} +#endif +#endif /* HAVE_SNPRINTF, and everything */ + +#ifndef HAVE_VASPRINTF + int vasprintf(char **ptr, const char *format, va_list ap) +{ + int ret; + va_list ap2; + + VA_COPY(ap2, ap); + + ret = vsnprintf(NULL, 0, format, ap2); + if (ret <= 0) return ret; + + (*ptr) = (char *)malloc(ret+1); + if (!*ptr) return -1; + + VA_COPY(ap2, ap); + + ret = vsnprintf(*ptr, ret+1, format, ap2); + + return ret; +} +#endif /* HAVE_VASPRINTF */ + + +#ifndef HAVE_ASPRINTF + int asprintf(char **ptr, const char *format, ...) +{ + va_list ap; + int ret; + + *ptr = NULL; + va_start(ap, format); + ret = vasprintf(ptr, format, ap); + va_end(ap); + + return ret; +} +#endif /* HAVE_ASPRINTF */ + +#ifdef TEST_SNPRINTF + + int sprintf(char *str,const char *fmt,...); + + int main (void) +{ + char buf1[1024]; + char buf2[1024]; + char *fp_fmt[] = { + "%1.1f", + "%-1.5f", + "%1.5f", + "%123.9f", + "%10.5f", + "% 10.5f", + "%+22.9f", + "%+4.9f", + "%01.3f", + "%4f", + "%3.1f", + "%3.2f", + "%.0f", + "%f", + "-16.16f", + NULL + }; + double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, + 0.9996, 1.996, 4.136, 5.030201, 0.00205, + /* END LIST */ 0}; + char *int_fmt[] = { + "%-1.5d", + "%1.5d", + "%123.9d", + "%5.5d", + "%10.5d", + "% 10.5d", + "%+22.33d", + "%01.3d", + "%4d", + "%d", + NULL + }; + long int_nums[] = { -1, 134, 91340, 341, 0203, 0}; + char *str_fmt[] = { + "10.5s", + "5.10s", + "10.1s", + "0.10s", + "10.0s", + "1.10s", + "%s", + "%.1s", + "%.10s", + "%10s", + NULL + }; + char *str_vals[] = {"hello", "a", "", "a longer string", NULL}; + int x, y; + int fail = 0; + int num = 0; + + printf ("Testing snprintf format codes against system sprintf...\n"); + + for (x = 0; fp_fmt[x] ; x++) { + for (y = 0; fp_nums[y] != 0 ; y++) { + int l1 = snprintf(NULL, 0, fp_fmt[x], fp_nums[y]); + int l2 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]); + sprintf (buf2, fp_fmt[x], fp_nums[y]); + if (strcmp (buf1, buf2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", + fp_fmt[x], buf1, buf2); + fail++; + } + if (l1 != l2) { + printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, fp_fmt[x]); + fail++; + } + num++; + } + } + + for (x = 0; int_fmt[x] ; x++) { + for (y = 0; int_nums[y] != 0 ; y++) { + int l1 = snprintf(NULL, 0, int_fmt[x], int_nums[y]); + int l2 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]); + sprintf (buf2, int_fmt[x], int_nums[y]); + if (strcmp (buf1, buf2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", + int_fmt[x], buf1, buf2); + fail++; + } + if (l1 != l2) { + printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, int_fmt[x]); + fail++; + } + num++; + } + } + + for (x = 0; str_fmt[x] ; x++) { + for (y = 0; str_vals[y] != 0 ; y++) { + int l1 = snprintf(NULL, 0, str_fmt[x], str_vals[y]); + int l2 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]); + sprintf (buf2, str_fmt[x], str_vals[y]); + if (strcmp (buf1, buf2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf = [%s]\n\t sprintf = [%s]\n", + str_fmt[x], buf1, buf2); + fail++; + } + if (l1 != l2) { + printf("snprintf l1 != l2 (%d %d) %s\n", l1, l2, str_fmt[x]); + fail++; + } + num++; + } + } + + printf ("%d tests failed out of %d.\n", fail, num); + + printf("seeing how many digits we support\n"); + { + double v0 = 0.12345678901234567890123456789012345678901; + for (x=0; x<100; x++) { + double p = pow(10, x); + double r = v0*p; + snprintf(buf1, sizeof(buf1), "%1.1f", r); + sprintf(buf2, "%1.1f", r); + if (strcmp(buf1, buf2)) { + printf("we seem to support %d digits\n", x-1); + break; + } + } + } + + return 0; +} +#endif /* TEST_SNPRINTF */ diff --git a/distcc/src/snprintf.h b/distcc/src/snprintf.h new file mode 100644 index 0000000..fe3b387 --- /dev/null +++ b/distcc/src/snprintf.h @@ -0,0 +1,30 @@ +#include <stdarg.h> + +#ifdef __GNUC__ +/** Use gcc attribute to check printf fns. a1 is the 1-based index of + * the parameter containing the format, and a2 the index of the first + * argument. **/ +#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2))) +#else +#define PRINTF_ATTRIBUTE(a1, a2) +#endif + + +/* Note that the HAVE_DECL macros are defined to 0 if the declaration + * is not present, rather than being undefined as is the case for most + * autoconf tests. */ + + +#if !HAVE_DECL_VASPRINTF +int vasprintf(char **ptr, const char *format, va_list ap); +#endif +#if !HAVE_DECL_SNPRINTF +int snprintf(char *,size_t ,const char *, ...) PRINTF_ATTRIBUTE(3,4); +#endif +#if !HAVE_DECL_ASPRINTF +int asprintf(char **,const char *, ...) PRINTF_ATTRIBUTE(2,3); +#endif + +#if !HAVE_DECL_VSNPRINTF +int vsnprintf(char *, size_t, const char *, va_list); +#endif diff --git a/distcc/src/srvnet.c b/distcc/src/srvnet.c new file mode 100644 index 0000000..4759181 --- /dev/null +++ b/distcc/src/srvnet.c @@ -0,0 +1,290 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + /* "Happy is the man who finds wisdom, and the man who + * gets understanding; for the gain from it is better + * than gain from silver and its profit better than + * gold." -- Proverbs 3:13 */ + + +/** + * @file + * + * Server-side networking. + **/ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <netdb.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <netinet/tcp.h> + +#ifdef HAVE_ARPA_NAMESER_H +# include <arpa/nameser.h> +#endif + +#include <arpa/inet.h> + +#ifdef HAVE_RESOLV_H +# include <resolv.h> +#endif + +#include "types.h" +#include "exitcode.h" +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "srvnet.h" +#include "access.h" +#include "netutil.h" +#include "dopt.h" + +/* + * Listen on a predetermined address (often the passive address). The way in + * which we get the address depends on the resolver API in use. + **/ +static int dcc_listen_by_addr(int fd, + struct sockaddr *sa, + size_t salen) +{ + int one = 1; + char *sa_buf = NULL; + + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)); + + dcc_sockaddr_to_string(sa, salen, &sa_buf); + + /* now we've got a socket - we need to bind it */ + if (bind(fd, sa, salen) == -1) { + rs_log_error("bind of %s failed: %s", sa_buf ? sa_buf : "UNKNOWN", + strerror(errno)); + free(sa_buf); + close(fd); + return EXIT_BIND_FAILED; + } + + rs_log_info("listening on %s", sa_buf ? sa_buf : "UNKNOWN"); + free(sa_buf); + + if (listen(fd, 10)) { + rs_log_error("listen failed: %s", strerror(errno)); + close(fd); + return EXIT_BIND_FAILED; + } + + return 0; +} + + + +#if defined(ENABLE_RFC2553) +/* This version uses getaddrinfo. It will probably use IPv6 if that's + * supported by your configuration, kernel, and library. */ +int dcc_socket_listen(int port, int *fd_out, const char *listen_addr) +{ + char portname[20]; + struct addrinfo hints; + struct addrinfo *res, *ai; + int error; + int ret; + + /* getaddrinfo() ought to check for this, but some versions do not. + * (Debian Bug#192876.) */ + if (port < 1 || port > 65535) { + rs_log_error("port number out of range: %d", port); + return EXIT_BAD_ARGUMENTS; + } + + /* getaddrinfo wants a string for the service name */ + snprintf(portname, sizeof portname, "%d", port); + + /* Set-up hints structure. */ + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + + if (listen_addr == NULL) + hints.ai_flags = AI_PASSIVE; /* bind all */ + + error = getaddrinfo(listen_addr, portname, &hints, &res); + + if (error) { + rs_log_error("getaddrinfo failed for host %s service %s: %s", + listen_addr ? listen_addr : "(passive)", + portname, gai_strerror(error)); + return EXIT_BIND_FAILED; + } + + /* The first sockaddr returned will typically be an IPv6 socket. Some + * kernels might not support that. */ + for (ai = res; ai; ai=ai->ai_next) { + int af = ai->ai_addr->sa_family; + if ((*fd_out = socket(af, SOCK_STREAM, 0)) == -1) { + if (errno == EAFNOSUPPORT) { + rs_log_notice("socket address family %d not supported", af); + continue; + } else { + rs_log_error("socket creation failed: %s", strerror(errno)); + return EXIT_BIND_FAILED; + } + } else { + ret = dcc_listen_by_addr(*fd_out, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + return ret; + } + } + + rs_log_error("failed to find any supported socket family"); + return EXIT_BIND_FAILED; +} + +#else /* ndef ENABLE_RFC2553 */ + +/* This version uses inet_aton */ +int dcc_socket_listen(int port, int *listen_fd, const char *listen_addr) +{ + struct sockaddr_in sock; + + if (port < 1 || port > 65535) { + /* htons() will truncate, not check */ + rs_log_error("port number out of range: %d", port); + return EXIT_BAD_ARGUMENTS; + } + + memset((char *) &sock, 0, sizeof(sock)); + sock.sin_port = htons(port); + sock.sin_family = PF_INET; + + if (listen_addr) { + if (!inet_aton(listen_addr, &sock.sin_addr)) { + rs_log_error("listen address \"%s\" is not a valid IPv4 address", + listen_addr); + return EXIT_BAD_ARGUMENTS; + } + } else { + sock.sin_addr.s_addr = INADDR_ANY; + } + + if ((*listen_fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { + rs_log_error("socket creation failed: %s", strerror(errno)); + return EXIT_BIND_FAILED; + } + + return dcc_listen_by_addr(*listen_fd, (struct sockaddr *) &sock, + sizeof sock); +} +#endif /* ndef ENABLE_RFC2553 */ + + +/** + * Determine if a file descriptor is in fact a socket + **/ +int is_a_socket(int fd) +{ + int v; + socklen_t len = sizeof(int); + return (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *) &v, &len) == 0); +} + + +/** + * Log client IP address and perform access control checks. + * + * Note that PSA may be NULL if the sockaddr is unknown. + **/ +int dcc_check_client(struct sockaddr *psa, + int salen, + struct dcc_allow_list *allowed) +{ + char *client_ip; + struct dcc_allow_list *l; + int ret; + + if ((ret = dcc_sockaddr_to_string(psa, salen, &client_ip)) != 0) + return ret; + + rs_log_info("connection from %s", client_ip); + dcc_job_summary_append("client: "); + dcc_job_summary_append(client_ip); + + if (!psa) { + /* if no sockaddr, must be a pipe or something. */ + free(client_ip); + return 0; + } + + if (!allowed) { + /* if no ACL, default open */ + free(client_ip); + return 0; + } + + for (l = allowed; l; l = l->next) { + if (psa->sa_family == AF_INET) { + in_addr_t cli_inaddr; + cli_inaddr = ((struct sockaddr_in *) psa)->sin_addr.s_addr; + + if ((ret = dcc_check_address(cli_inaddr, l->addr, l->mask)) == 0) + break; +#ifdef ENABLE_RFC2553 + } else if (psa->sa_family == AF_INET6) { + const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *) psa; + const struct in6_addr *a6 = &sa6->sin6_addr; + const in_addr_t *a4; + + if (IN6_IS_ADDR_V4MAPPED(a6) || IN6_IS_ADDR_V4COMPAT(a6)) { + a4 = (const in_addr_t *) &a6->s6_addr[12]; + if ((ret = dcc_check_address(*a4, l->addr, l->mask)) == 0) + break; + } else { + rs_log_notice("ipv6 ACLs not implemented"); + free(client_ip); + return EXIT_ACCESS_DENIED; + } +#endif + } else { + ret = EXIT_ACCESS_DENIED; + rs_log_notice("access denied from unknown address family %d", + psa->sa_family); + break; + } + } + + if (ret != 0) { + rs_log_error("connection from client '%s' denied by access list", + client_ip); + } + free(client_ip); + return ret; +} diff --git a/distcc/src/srvnet.h b/distcc/src/srvnet.h new file mode 100644 index 0000000..5a4ee90 --- /dev/null +++ b/distcc/src/srvnet.h @@ -0,0 +1,28 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* srvnet.c */ +int dcc_socket_listen(int port, int *fd, const char *listen_addr); +int is_a_socket(int fd); +struct dcc_allow_list; +int dcc_check_client(struct sockaddr *, int, struct dcc_allow_list *); + diff --git a/distcc/src/srvrpc.c b/distcc/src/srvrpc.c new file mode 100644 index 0000000..3a3e9eb --- /dev/null +++ b/distcc/src/srvrpc.c @@ -0,0 +1,181 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + +/** + * @file + * + * Server-specific RPC code. + **/ + + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "rpc.h" +#include "exitcode.h" +#include "dopt.h" +#include "hosts.h" +#include "bulk.h" + +int dcc_r_request_header(int ifd, + enum dcc_protover *ver_ret) +{ + unsigned vers; + int ret; + + if ((ret = dcc_r_token_int(ifd, "DIST", &vers)) != 0) { + rs_log_error("client did not provide distcc magic fairy dust"); + return ret; + } + + if (vers > DCC_VER_3) { + rs_log_error("can't handle requested protocol version is %d", vers); + return EXIT_PROTOCOL_ERROR; + } + + *ver_ret = (enum dcc_protover) vers; + + return 0; +} + + + /** + * Receive the working directory from the client + */ +int dcc_r_cwd(int ifd, char **cwd) +{ + return dcc_r_token_string(ifd, "CDIR", cwd); +} + +/* @p path must be point to malloc'ed memory + * Replaces **path with a pointer to a string containing + * dirname + path. + * path must be absolute. + */ +static int prepend_dir_to_name(const char *dirname, char **path) +{ + char *buf; + asprintf(&buf, "%s%s", dirname, *path); + if (buf == NULL) { + return EXIT_OUT_OF_MEMORY; + } + free(*path); + *path = buf; + return 0; +} + +int dcc_r_many_files(int in_fd, + const char *dirname, + enum dcc_compress compr) +{ + int ret = 0; + unsigned int n_files; + unsigned int i; + char *name = 0; + char *link_target = 0; + char token[5]; + + if ((ret = dcc_r_token_int(in_fd, "NFIL", &n_files))) + return ret; + + for (i = 0; i < n_files; ++i) { + // like dcc_r_argv + unsigned int link_or_file_len; + + if ((ret = dcc_r_token_string(in_fd, "NAME", &name))) + goto out_cleanup; + + if ((ret = prepend_dir_to_name(dirname, &name))) + goto out_cleanup; + + if ((ret = dcc_r_sometoken_int(in_fd, token, &link_or_file_len))) + goto out_cleanup; + + // Must prepend the dirname for the file name, a link's target name. + if (strncmp(token, "LINK", 4) == 0) { + + if ((ret = dcc_r_str_alloc(in_fd, link_or_file_len, &link_target))){ + goto out_cleanup; + } + if (link_target[0] == '/') { + if ((ret = prepend_dir_to_name(dirname, &link_target))) { + goto out_cleanup; + } + } + if ((ret = dcc_mk_tmp_ancestor_dirs(name))) { + goto out_cleanup; + } + if (symlink(link_target, name) != 0) { + rs_log_error("failed to create path for %s: %s", name, + strerror(errno)); + ret = 1; + goto out_cleanup; + } + if ((ret = dcc_add_cleanup(name))) { + // bailing out + unlink(name); + goto out_cleanup; + } + } else if (strncmp(token, "FILE", 4) == 0) { + if ((ret = dcc_r_file(in_fd, name, link_or_file_len, compr))) { + goto out_cleanup; + } + if ((ret = dcc_add_cleanup(name))) { + // bailing out + unlink(name); + goto out_cleanup; + } + } else { + char buf[4 + sizeof(link_or_file_len)]; + // unexpected token + rs_log_error("protocol derailment: expected token FILE or LINK"); + // We should explain what happened here, but we have already read + // a few more bytes. + strncpy(buf, token, 4); + // TODO(manos): this is probably not kosher + memcpy(&buf[4], &link_or_file_len, sizeof(link_or_file_len)); + dcc_explain_mismatch(buf, 12, in_fd); + ret = EXIT_PROTOCOL_ERROR; + goto out_cleanup; + } + +out_cleanup: + free(name); + name = NULL; + free(link_target); + link_target = NULL; + if (ret) + break; + } + return ret; +} diff --git a/distcc/src/ssh.c b/distcc/src/ssh.c new file mode 100644 index 0000000..3f9809f --- /dev/null +++ b/distcc/src/ssh.c @@ -0,0 +1,228 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2001-2004 by Martin Pool + * Copyright (C) 1996-2001 by Andrew Tridgell + * Copyright (C) 1996 by Paul Mackerras + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +/* + * ssh.c -- Open a connection a server over ssh or something similar. + * + * The ssh connection always opens immediately from distcc's point of view, + * because the local socket/pipe to the child is ready. If the remote + * connection failed or is slow, distcc will only know when it tries to read + * or write. (And in fact the first page or more written will go out + * immediately too...) + * + * This file always uses nonblocking ssh, which has proven in rsync to be the + * better solution for ssh. It may cause trouble with ancient proprietary rsh + * implementations which can't handle their input being in nonblocking mode. + * rsync has a configuration option for that, but I don't support it here, + * because there's no point using rsh, you might as well use the native + * protocol. + */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/socket.h> + +#include "distcc.h" +#include "trace.h" +#include "exitcode.h" +#include "util.h" +#include "exec.h" +#include "snprintf.h" +#include "netutil.h" + +const char *dcc_default_ssh = "ssh"; + + + + +/** + * Create a file descriptor pair - like pipe() but use socketpair if + * possible (because of blocking issues on pipes). + * + * Always set non-blocking. + */ +static int fd_pair(int fd[2]) +{ + int ret; + +#if HAVE_SOCKETPAIR + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fd); +#else + ret = pipe(fd); +#endif + + if (ret == 0) { + dcc_set_nonblocking(fd[0]); + dcc_set_nonblocking(fd[1]); + } + + return ret; +} + + +/** + * Create a child connected to use on stdin/stdout. + * + * This is derived from CVS code + * + * Note that in the child STDIN is set to blocking and STDOUT is set to + * non-blocking. This is necessary as rsh relies on stdin being blocking and + * ssh relies on stdout being non-blocking + **/ +static int dcc_run_piped_cmd(char **argv, + int *f_in, + int *f_out, + pid_t * child_pid) +{ + pid_t pid; + int to_child_pipe[2]; + int from_child_pipe[2]; + + dcc_trace_argv("execute", argv); + + if (fd_pair(to_child_pipe) < 0) { + rs_log_error("fd_pair: %s", strerror(errno)); + return EXIT_IO_ERROR; + } + + if (fd_pair(from_child_pipe) < 0) { + dcc_close(to_child_pipe[0]); + dcc_close(to_child_pipe[1]); + rs_log_error("fd_pair: %s", strerror(errno)); + return EXIT_IO_ERROR; + } + + *child_pid = pid = fork(); + if (pid == -1) { + rs_log_error("fork failed: %s", strerror(errno)); + dcc_close(to_child_pipe[0]); + dcc_close(to_child_pipe[1]); + dcc_close(from_child_pipe[0]); + dcc_close(from_child_pipe[1]); + return EXIT_IO_ERROR; + } + + if (pid == 0) { + if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 || + close(to_child_pipe[1]) < 0 || + close(from_child_pipe[0]) < 0 || + dup2(from_child_pipe[1], STDOUT_FILENO) < 0) { + rs_log_error("dup/close: %s", strerror(errno)); + return EXIT_IO_ERROR; + } + if (to_child_pipe[0] != STDIN_FILENO) + close(to_child_pipe[0]); + if (from_child_pipe[1] != STDOUT_FILENO) + close(from_child_pipe[1]); + dcc_set_blocking(STDIN_FILENO); + + execvp(argv[0], (char **) argv); + rs_log_error("failed to exec %s: %s", argv[0], strerror(errno)); + return EXIT_IO_ERROR; + } + + if (dcc_close(from_child_pipe[1]) || dcc_close(to_child_pipe[0])) { + rs_log_error("failed to close pipes"); + return EXIT_IO_ERROR; + } + + *f_in = from_child_pipe[0]; + *f_out = to_child_pipe[1]; + + return 0; +} + + + +/** + * Open a connection to a remote machine over ssh. + * + * Based on code in rsync, but rewritten. + * + * @note The tunnel command is always opened directly using execvp(), not + * through a shell. So you cannot pass shell operators like redirections, and + * at the moment you cannot specify additional options. Perhaps it would be + * nice for us to parse it into an argv[] string by splitting on + * wildcards/quotes, but at the moment this seems redundant. It can be done + * adequately using .ssh/config I think. + **/ +int dcc_ssh_connect(char *ssh_cmd, + char *user, + char *machine, + char *path, + int *f_in, int *f_out, + pid_t *ssh_pid) +{ + pid_t ret; + char *child_argv[10]; + int i; + + /* We need to cast away constness. I promise the strings in the argv[] + * will not be modified. */ + + if (!ssh_cmd) + ssh_cmd = getenv("DISTCC_SSH"); + if (!ssh_cmd) + ssh_cmd = (char *) dcc_default_ssh; + + if (!machine) { + rs_log_crit("no machine defined!"); + return EXIT_DISTCC_FAILED; + } + if (!path) + path = (char *) "distccd"; + + i = 0; + child_argv[i++] = ssh_cmd; + if (user) { + child_argv[i++] = (char *) "-l"; + child_argv[i++] = user; + } + child_argv[i++] = machine; + child_argv[i++] = path; + child_argv[i++] = (char *) "--inetd"; + child_argv[i++] = NULL; + + rs_trace("connecting to %s using %s", machine, ssh_cmd); + + /* TODO: If we're verbose, perhaps make the server verbose too, and send + * its log to our stderr? */ + /* child_argv[i++] = (char *) "--log-stderr"; */ + + ret = dcc_run_piped_cmd(child_argv, f_in, f_out, ssh_pid); + + return ret; +} diff --git a/distcc/src/state.c b/distcc/src/state.c new file mode 100644 index 0000000..aac34c7 --- /dev/null +++ b/distcc/src/state.c @@ -0,0 +1,257 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include "config.h" + +#include <sys/time.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> + +#include "types.h" +#include "distcc.h" +#include "rpc.h" +#include "trace.h" +#include "exitcode.h" +#include "snprintf.h" +#include "util.h" + +const char *dcc_state_prefix = "binstate_"; + + +struct dcc_task_state my_state; + + +/** + * @file + * + * This file provides a way for distcc processes to make little notes + * about what they're up to that can be read by a monitor process. + * + * State is stored as follows. + * + * Within our temporary directory, we create a subdirectory called "state". + * + * Each process creates a file named "binstate%d", for its pid. We + * always rewrite this file from the beginning. + * + * Inside each of these, we store a binary struct in the native host + * encoding. Ugly, but quick and easy both in code and CPU time. + * + * Any process reading these files needs to handle the fact that they may be + * truncated or otherwise incorrect. + * + * When the process exits, it removes its state file. If you didn't + * notice it already, it's too late now. + * + * In addition, if the process identified by the file no longer + * exists, then the file must be orphaned by a process that suddenly + * terminated. The file is ignored and can be deleted by the first + * process that notices it. + * + * The reader interface for these files is in mon.c + * + * These files are considered a private format, and they may change + * between distcc releases. The only supported way to read them is + * through mon.c. + **/ + + +/** + * Return newly allocated buffer holding the name of this process's state file. + * + * (This can't reliably be static because we might fork...) + **/ +static int dcc_get_state_filename(char **fname) +{ + int ret; + char *dir; + + if ((ret = dcc_get_state_dir(&dir))) + return ret; + + if (asprintf(fname, "%s/%s%ld", + dir, dcc_state_prefix, (long) getpid()) == -1) { + return EXIT_OUT_OF_MEMORY; + } + + return 0; +} + + +const char *dcc_get_phase_name(enum dcc_phase phase) +{ + switch (phase) { + case DCC_PHASE_STARTUP: + return "Startup"; + case DCC_PHASE_BLOCKED: + return "Blocked"; + case DCC_PHASE_COMPILE: + return "Compile"; + case DCC_PHASE_CPP: + return "Preprocess"; + case DCC_PHASE_CONNECT: + return "Connect"; + case DCC_PHASE_SEND: + return "Send"; + case DCC_PHASE_RECEIVE: + return "Receive"; + case DCC_PHASE_DONE: + return "Done"; + default: + return "Unknown"; + } +} + + +/** + * Get a file descriptor for writing to this process's state file. + * file. + **/ +static int dcc_open_state(int *p_fd, + const char *fname) +{ + int fd; + + fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, 0666); + if (fd == -1) { + rs_log_error("failed to open %s: %s", fname, strerror(errno)); + return EXIT_IO_ERROR; + } + + *p_fd = fd; + return 0; +} + + +/** + * Remove the state file for this process. + * + * This can be called from atexit(). + **/ +void dcc_remove_state_file (void) +{ + char *fname; + int ret; + + if ((ret = dcc_get_state_filename(&fname))) + return; + + if (unlink(fname) == -1) { + /* It's OK if we never created it */ + if (errno != ENOENT) { + rs_log_warning("failed to unlink %s: %s", fname, strerror(errno)); + ret = EXIT_IO_ERROR; + } + } + + free(fname); + + (void) ret; +} + + +static int dcc_write_state(int fd) +{ + int ret; + + /* Write out as one big blob. fd is positioned at the start of + * the file. */ + + if ((ret = dcc_writex(fd, &my_state, sizeof my_state))) + return ret; + + return 0; +} + + +/** + * Record the state of this process. + * + * The filename is trimmed down to its basename. + * + * If the source_file or host are NULL, then are left unchanged from + * their previous value. + **/ +int dcc_note_state(enum dcc_phase state, + const char *source_file, + const char *host) +{ + int fd; + int ret; + char *fname; + struct timeval tv; + + my_state.struct_size = sizeof my_state; + my_state.magic = DCC_STATE_MAGIC; + my_state.cpid = (unsigned long) getpid(); + + if ((ret = dcc_get_state_filename(&fname))) + return ret; + + source_file = dcc_find_basename(source_file); + if (source_file) { + strlcpy(my_state.file, source_file, sizeof my_state.file); + } + + if (host) { + strlcpy(my_state.host, host, sizeof my_state.host); + } + + if (gettimeofday(&tv, NULL) == -1) { + rs_log_error("gettimeofday failed: %s", strerror(errno)); + return EXIT_DISTCC_FAILED; + } + my_state.curr_phase = state; + + rs_trace("note state %d, file \"%s\", host \"%s\"", + state, + source_file ? source_file : "(NULL)", + host ? host : "(NULL)"); + + if ((ret = dcc_open_state(&fd, fname))) { + free(fname); + return ret; + } + + if ((ret = dcc_write_state(fd))) { + dcc_close(fd); + free(fname); + return ret; + } + + dcc_close(fd); + free(fname); + + return 0; +} + + +void dcc_note_state_slot(int slot) +{ + my_state.slot = slot; +} diff --git a/distcc/src/state.h b/distcc/src/state.h new file mode 100644 index 0000000..63486fe --- /dev/null +++ b/distcc/src/state.h @@ -0,0 +1,91 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef _DISTCC_STATE_H +#define _DISTCC_STATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +int dcc_get_state_dir (char **p); +int dcc_open_state_file (int *p_fd); + + +/* Note that these must be in the order in which they are encountered + * for the state file to work properly. It's OK if some are skipped + * though. */ +enum dcc_phase { + DCC_PHASE_STARTUP, + DCC_PHASE_BLOCKED, + DCC_PHASE_CONNECT, + DCC_PHASE_CPP, + DCC_PHASE_SEND, + DCC_PHASE_COMPILE, /**< or unknown */ + DCC_PHASE_RECEIVE, + DCC_PHASE_DONE /**< MUST be last */ +}; + + +int dcc_note_state (enum dcc_phase state, + const char *file, + const char *host); +void dcc_remove_state_file (void); + + +extern const char *dcc_state_prefix; + + +#define DCC_STATE_MAGIC 0x44494800 /* DIH\0 */ + +/** + * State and history of a distcc process. Used in memory and also in native + * format for binary state files. + * + * This should be <4kB, so that it will normally be written out + * atomically. + **/ +struct dcc_task_state { + size_t struct_size; + unsigned long magic; + unsigned long cpid; /**< Client pid */ + char file[128]; /**< Input filename */ + char host[128]; /**< Destination host description */ + int slot; /**< Which CPU slot for this host */ + + enum dcc_phase curr_phase; + + /** In memory, point to the next in a list of all tasks. In the + * file, undefined. */ + struct dcc_task_state *next; +}; + + +const char *dcc_get_phase_name(enum dcc_phase); + +void dcc_note_state_slot(int slot); + +#ifdef __cplusplus +} +#endif + +#endif /* _DISTCC_STATE_H */ diff --git a/distcc/src/stats.c b/distcc/src/stats.c new file mode 100644 index 0000000..e6a92ba --- /dev/null +++ b/distcc/src/stats.c @@ -0,0 +1,415 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2005 by Google + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +// Author: Thomas Kho + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <string.h> +#include <time.h> + +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/statvfs.h> + +#include "exitcode.h" +#include "distcc.h" +#include "trace.h" +#include "dopt.h" +#include "stats.h" +#include "srvnet.h" +#include "util.h" +#include "netutil.h" +#include "fcntl.h" +#include "daemon.h" + +int dcc_statspipe[2]; + +#define MAX_FILENAME_LEN 1024 + +/* in prefork.c */ +void dcc_manage_kids(int listen_fd); + +struct stats_s { + int counters[STATS_ENUM_MAX]; + int longest_job_time; + char longest_job_name[MAX_FILENAME_LEN]; + char longest_job_compiler[MAX_FILENAME_LEN]; + int io_rate; /* read/write sectors per second */ + + int compile_timeseries[300]; /* 300 3-sec time intervals */ +} dcc_stats; + +struct statsdata { + enum stats_e type; + + /* used only for STATS_COMPILE_OK */ + int time; + char filename[MAX_FILENAME_LEN]; + char compiler[MAX_FILENAME_LEN]; +}; + +const char *stats_text[20] = { "TCP_ACCEPT", "REJ_BAD_REQ", "REJ_OVERLOAD", + "COMPILE_OK", "COMPILE_ERROR", "COMPILE_TIMEOUT", "CLI_DISCONN", + "OTHER" }; + +/* Call this to initialize stats */ +int dcc_stats_init() { + if (arg_stats) { + if (pipe(dcc_statspipe) == -1) { + return -1; + } + } + memset(&dcc_stats, 0, sizeof(dcc_stats)); + return 0; +} + + +/* In the preforking model call this to initialize stats for forked children */ +void dcc_stats_init_kid() { + if (arg_stats) { + close(dcc_statspipe[0]); + } +} + + +/** + * Logs countable event of type e to stats server + **/ +void dcc_stats_event(enum stats_e e) { + if (arg_stats) { + struct statsdata sd; + memset(&sd, 0, sizeof(sd)); + sd.type = e; + write(dcc_statspipe[1], &sd, sizeof(sd)); + } +} + + +/** + * Logs a completed job to stats server + **/ +void dcc_stats_compile_ok(char *compiler, char *filename, int time_usec) { + if (arg_stats) { + struct statsdata sd; + memset(&sd, 0, sizeof(sd)); + + sd.type = STATS_COMPILE_OK; + /* also send compiler, filename & runtime */ + sd.time = time_usec; + strncpy(sd.filename, filename, MAX_FILENAME_LEN); + strncpy(sd.compiler, compiler, MAX_FILENAME_LEN); + write(dcc_statspipe[1], &sd, sizeof(sd)); + } +} + + +/* + * Updates a running total of compiles in the last 1, 5, 15 minutes + * + * Returns the oldest slot + */ +static int dcc_stats_update_running_total(int increment) { + static int prev_slot; + static time_t last = 0; + static int total = 0; + int i; + int cur_slot; + int *const cts = dcc_stats.compile_timeseries; + time_t now = time(NULL); + + cur_slot = (now / 3) % 300; + + if (last + 900 < now) { + /* reset all stats; last call was >15 min ago */ + for (i = 0; i < 300; i++) + cts[i] = total; + prev_slot = cur_slot; + } + + if (prev_slot != cur_slot) { + /* different timeslot, so set the interval [prev, cur) */ + for (i = (prev_slot)%300; i != cur_slot; i = (i+1)%300) { + cts[i] = total; + } + prev_slot = cur_slot; + } + + total += increment; + last = now; + + return cur_slot; +} + + +static int *dcc_stats_get_compile_totals(void) { + int cur_slot; + static int ct[3]; /* 1, 5, 15 min compile totals */ + int *const cts = dcc_stats.compile_timeseries; + + cur_slot = dcc_stats_update_running_total(0); + + ct[0] = cts[(cur_slot + 299)%300] - cts[(cur_slot+280)%300]; + ct[1] = cts[(cur_slot + 299)%300] - cts[(cur_slot+200)%300]; + ct[2] = cts[(cur_slot + 299)%300] - cts[(cur_slot+1)%300]; + + return ct; +} + + +/* Sets dcc_stats.io_rate at most 50 secs */ +static void dcc_stats_minutely_update(void) { + static int prev_io_tot = -1; + static time_t last = 0; + int n_reads, n_writes; + time_t now = time(NULL); + + if (last + 50 < now) { + dcc_get_disk_io_stats(&n_reads, &n_writes); + + if (prev_io_tot == -1) + dcc_stats.io_rate = -1; + else + dcc_stats.io_rate = (n_reads + n_writes - prev_io_tot) / (now - last); + + prev_io_tot = n_reads + n_writes; + last = now; + } +} + +static long dcc_get_tmpdirinfo(void) { + const char *tmp_dir; + struct statvfs buf; + + if (dcc_get_tmp_top(&tmp_dir) != 0) + return -1; + + if (statvfs(tmp_dir, &buf) != 0) + return -1; + + if (buf.f_bsize >= 1024) + return buf.f_bavail * (buf.f_bsize / 1024) / 1024; + else + return (buf.f_bavail * buf.f_bsize) / (1024 * 1024); +} + +/** + * Accept a connection on the stats port and send the reply, regardless of data + * that the client sends us. + **/ +static void dcc_service_stats_request(int http_fd) { + int acc_fd; + int *ct; + int num_D; + int max_RSS; + char *max_RSS_name; + size_t reply_len; + char challenge[1024]; + char reply[2048]; + struct dcc_sockaddr_storage cli_addr; + socklen_t cli_len = sizeof(cli_addr); + double loadavg[3]; + int free_space_mb; + + const char replytemplate[] = "\ +HTTP/1.0 200 OK\n\ +Content-Type: text/plain\n\ +Connection: close\n\n\ +argv /distccd\n\ +<distccstats>\n\ +dcc_tcp_accept %d\n\ +dcc_rej_bad_req %d\n\ +dcc_rej_overload %d\n\ +dcc_compile_ok %d\n\ +dcc_compile_error %d\n\ +dcc_compile_timeout %d\n\ +dcc_cli_disconnect %d\n\ +dcc_other %d\n\ +dcc_longest_job %s\n\ +dcc_longest_job_compiler %s\n\ +dcc_longest_job_time_msecs %d\n\ +dcc_max_kids %d\n\ +dcc_current_load %d\n\ +dcc_load1 %1.2lf\n\ +dcc_load2 %1.2lf\n\ +dcc_load3 %1.2lf\n\ +dcc_num_compiles1 %d\n\ +dcc_num_compiles2 %d\n\ +dcc_num_compiles3 %d\n\ +dcc_num_procstate_D %d\n\ +dcc_max_RSS %d\n\ +dcc_max_RSS_name %s\n\ +dcc_io_rate %d\n\ +dcc_free_space %d MB\n\ +</distccstats>\n"; + + dcc_stats_minutely_update(); /* force update to get fresh disk io data */ + ct = dcc_stats_get_compile_totals(); + dcc_getloadavg(loadavg); + + free_space_mb = dcc_get_tmpdirinfo(); + dcc_get_proc_stats(&num_D, &max_RSS, &max_RSS_name); + + if (dcc_stats.longest_job_name[0] == 0) + strcpy(dcc_stats.longest_job_name, "none"); + if (dcc_stats.longest_job_compiler[0] == 0) + strcpy(dcc_stats.longest_job_compiler, "none"); + + acc_fd = accept(http_fd, (struct sockaddr *) &cli_addr, &cli_len); + if (dcc_check_client((struct sockaddr *)&cli_addr, + (int) cli_len, + opt_allowed) == 0) { + reply_len = snprintf(reply, 2048, replytemplate, + dcc_stats.counters[STATS_TCP_ACCEPT], + dcc_stats.counters[STATS_REJ_BAD_REQ], + dcc_stats.counters[STATS_REJ_OVERLOAD], + dcc_stats.counters[STATS_COMPILE_OK], + dcc_stats.counters[STATS_COMPILE_ERROR], + dcc_stats.counters[STATS_COMPILE_TIMEOUT], + dcc_stats.counters[STATS_CLI_DISCONN], + dcc_stats.counters[STATS_OTHER], + dcc_stats.longest_job_name, + dcc_stats.longest_job_compiler, + dcc_stats.longest_job_time, + dcc_max_kids, + dcc_getcurrentload(), + loadavg[0], loadavg[1], loadavg[2], + ct[0], ct[1], ct[2], + num_D, max_RSS, max_RSS_name, + dcc_stats.io_rate, + free_space_mb); + dcc_set_nonblocking(acc_fd); + read(acc_fd, challenge, 1024); /* empty the receive queue */ + write(acc_fd, reply, reply_len); + } + + /* Don't think we need this to prevent RST anymore, since we read() now */ + //shutdown(acc_fd, SHUT_WR); /* prevent connection reset */ + dcc_close(acc_fd); +} + + +/** + * Process a packet of stats data + **/ +static void dcc_stats_process(struct statsdata *sd) { + if (sd->type > STATS_ENUM_MAX) { + /* Got a bad message */ + return; + } + + switch (sd->type) { + + case STATS_TCP_ACCEPT: + case STATS_REJ_BAD_REQ: + case STATS_REJ_OVERLOAD: + break; + case STATS_COMPILE_OK: + /* Record file with longest runtime */ + if (dcc_stats.longest_job_time < sd->time) { + dcc_stats.longest_job_time = sd->time; + strncpy(dcc_stats.longest_job_name, sd->filename, + MAX_FILENAME_LEN); + strncpy(dcc_stats.longest_job_compiler, sd->compiler, + MAX_FILENAME_LEN); + } + case STATS_COMPILE_ERROR: + case STATS_COMPILE_TIMEOUT: + case STATS_CLI_DISCONN: + /* We want to update the running compile total for all jobs that + * non-trivially tax the CPU */ + dcc_stats_update_running_total(1); + default: ; + } + + dcc_stats.counters[sd->type]++; +} + + +/** + * Collect runtime statistics from kids and serve them via HTTP + * Also, maintains the pool of kids. + **/ +int dcc_stats_server(int listen_fd) +{ + int http_fd, max_fd; + int i, ret; + fd_set fds, fds_master; + struct statsdata sd; + struct timeval timeout; + + /* clear stats data */ + for (i = 0; i < STATS_ENUM_MAX; i++) + dcc_stats.counters[i] = 0; + dcc_stats.longest_job_time = -1; + dcc_stats.longest_job_name[0] = 0; + dcc_stats.io_rate = -1; + + if ((ret = dcc_socket_listen(arg_stats_port, &http_fd, + opt_listen_addr)) != 0) { + return ret; + } + rs_log_info("HTTP server started on port %d\n", arg_stats_port); + + /* We don't want children to inherit this FD */ + fcntl(http_fd, F_SETFD, FD_CLOEXEC); + + max_fd = (http_fd > dcc_statspipe[0]) ? (http_fd + 1) + : (dcc_statspipe[0] + 1); + + FD_ZERO(&fds_master); + FD_SET(dcc_statspipe[0], &fds_master); + FD_SET(http_fd, &fds_master); + + while (1) { + dcc_stats_minutely_update(); + + timeout.tv_sec = 60; + timeout.tv_usec = 0; + fds = fds_master; + ret = select(max_fd, &fds, NULL, NULL, &timeout); + if (ret != -1) { + if (FD_ISSET(dcc_statspipe[0], &fds)) { + /* Received stats report from a child */ + if (read(dcc_statspipe[0], &sd, sizeof(sd)) != -1) { + dcc_stats_process(&sd); + } + } + + if (FD_ISSET(http_fd, &fds)) { + /* Received request on stats reporting port */ + dcc_service_stats_request(http_fd); + } + } else { + if (errno == EINTR) { + /* Interrupted -- SIGCHLD? */ + } + } + + dcc_manage_kids(listen_fd); + } +} diff --git a/distcc/src/stats.h b/distcc/src/stats.h new file mode 100644 index 0000000..34e4371 --- /dev/null +++ b/distcc/src/stats.h @@ -0,0 +1,46 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2005 by Google (Thomas Kho <tkho at google.com>) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef _DISTCC_STATS_H +#define _DISTCC_STATS_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum stats_e { STATS_TCP_ACCEPT, STATS_REJ_BAD_REQ, STATS_REJ_OVERLOAD, + STATS_COMPILE_OK, STATS_COMPILE_ERROR, STATS_COMPILE_TIMEOUT, + STATS_CLI_DISCONN, STATS_OTHER, STATS_ENUM_MAX }; + +const char *stats_text[20]; + +int dcc_stats_init(void); +void dcc_stats_init_kid(void); +int dcc_stats_server(int listen_fd); +void dcc_stats_event(enum stats_e e); +void dcc_stats_compile_ok(char *compiler, char *filename, int time_usec); + +#ifdef __cplusplus +} +#endif + +#endif /* _DISTCC_STATS_H */ diff --git a/distcc/src/stringmap.c b/distcc/src/stringmap.c new file mode 100644 index 0000000..2c3d26f --- /dev/null +++ b/distcc/src/stringmap.c @@ -0,0 +1,116 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <assert.h> +#include "stringmap.h" + +#ifndef NULL +#define NULL 0 +#endif + +/* Load the given list of strings into the key/value map. + * The key for each string is the numFinalWordsToMatch of the string; + * the value for each string is the entire string. + * FIXME: doesn't work for utf-8 strings, since it scans raw chars for / + */ +stringmap_t *stringmap_load(const char *filename, int numFinalWordsToMatch) +{ + stringmap_t *result = calloc(1, sizeof(*result)); + FILE *fp = fopen(filename, "r"); + char buf[2*PATH_MAX]; + int n; + + result->numFinalWordsToMatch = numFinalWordsToMatch; + if (!fp) + return NULL; + n=0; + while (fgets(buf, sizeof(buf), fp)) + n++; + result->n = n; + result->map = malloc(n * sizeof(result->map[0])); + + rewind(fp); + n=0; + while (fgets(buf, sizeof(buf), fp)) { + int pos, w; + + int len = strlen(buf); + /* strip trailing \n */ + if (len > 0 && buf[len-1] == '\n') { + buf[len-1] = 0; + len--; + } + /* set pos to the start of the significant part of the string */ + for (pos=len-1, w=0; pos>0; pos--) { + if (buf[pos] == '/') { + w++; + if (w >= numFinalWordsToMatch) + break; + } + } + + result->map[n].value = strdup(buf); + result->map[n].key = strdup(buf+pos); + n++; + } fclose(fp); + return result; +} + +const char *stringmap_lookup(const stringmap_t *map, const char *string) +{ + int i, w; + int len = strlen(string); + int pos; + for (pos=len-1, w=0; pos>0; pos--) { + if (string[pos] == '/') { + w++; + if (w >= map->numFinalWordsToMatch) + break; + } + } + for (i=0; i<map->n; i++) { + /*printf("Comparing %s and %s\n", map->map[i].key, string+pos);*/ + if (!strcmp(map->map[i].key, string+pos)) + return map->map[i].value; + } + return NULL; +} + +#if 0 + +void dumpMap(stringmap_t *sm) +{ + int i; + printf("map has %d elements, and numFinalWordsToMatch is %d\n", sm->n, sm->numFinalWordsToMatch); + for (i=0; i < sm->n; i++) { + printf("row %d: key %s, value %s\n", i, sm->map[i].key, sm->map[i].value); + } +} + +#define verifyMap(sm, a, b) { \ + const char *c = stringmap_lookup(sm, a); \ + if (!b) \ + assert(!c); \ + else { \ + assert(c); \ + assert(!strcmp(b, c)); } } + +main(int argc, char **argv) +{ + FILE *fp; + stringmap_t *sm; + + fp = fopen("stringmap_test.dat", "w"); + fprintf(fp, "/foo/bar/bletch\n"); + fclose(fp); + + + sm = stringmap_load("stringmap_test.dat", 1); + dumpMap(sm); + verifyMap(sm, "/bar/bletch", "/foo/bar/bletch"); + verifyMap(sm, "bletch", NULL); + verifyMap(sm, "/foo/bar/bletch", "/foo/bar/bletch"); +} + +#endif diff --git a/distcc/src/stringmap.h b/distcc/src/stringmap.h new file mode 100644 index 0000000..f13fbb0 --- /dev/null +++ b/distcc/src/stringmap.h @@ -0,0 +1,27 @@ +#ifndef STRINGMAP_H +#define STRINGMAP_H + +typedef struct { + /* the strings, and what they map to */ + struct { + char *key; + char *value; + } *map; + + /* number of elements in map */ + int n; + + /* if nonzero, ignore all but this many trailing words, + * where words are separated by the '/' char + * Example: + * comparison num=1 num=2 num=3 + * a/b/z =? 1/y/z match no no + * a/b/z =? 1/b/z match match no + */ + int numFinalWordsToMatch; +} stringmap_t; + +stringmap_t *stringmap_load(const char *filename, int numFinalWordsToMatch); +const char *stringmap_lookup(const stringmap_t *map, const char *string); + +#endif diff --git a/distcc/src/strip.c b/distcc/src/strip.c new file mode 100644 index 0000000..09ce76e --- /dev/null +++ b/distcc/src/strip.c @@ -0,0 +1,178 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <sys/stat.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "exitcode.h" + +/** + * Strip arguments like -D and -I from a command line, because they do + * not need to be passed across the wire. This covers options for + * both the preprocess and link phases, since they should never happen + * remotely. + * + * In the case where we inadvertently do cause preprocessing to happen + * remotely, it is possible that omitting these options will make + * failure more obvious and avoid false success. + * + * Giving -L on a compile-only command line is a bit wierd, but it is + * observed to happen in Makefiles that are not strict about CFLAGS vs + * LDFLAGS, etc. + * + * NOTE: gcc-3.2's manual in the "preprocessor options" section + * describes some options, such as -d, that only take effect when + * passed directly to cpp. When given to gcc they have different + * meanings. + **/ +int dcc_strip_local_args(char **from, char ***out_argv) +{ + char **to; + int from_i, to_i; + int from_len; + + from_len = dcc_argv_len(from); + *out_argv = to = malloc((from_len + 1) * sizeof (char *)); + + if (!to) { + rs_log_error("failed to allocate space for arguments"); + return EXIT_OUT_OF_MEMORY; + } + + /* skip through argv, copying all arguments but skipping ones that + * ought to be omitted */ + for (from_i = to_i = 0; from[from_i]; from_i++) { + if (str_equal("-D", from[from_i]) + || str_equal("-I", from[from_i]) + || str_equal("-U", from[from_i]) + || str_equal("-L", from[from_i]) + || str_equal("-l", from[from_i]) + || str_equal("-MF", from[from_i]) + || str_equal("-MT", from[from_i]) + || str_equal("-MQ", from[from_i]) + || str_equal("-include", from[from_i]) + || str_equal("-imacros", from[from_i]) + || str_equal("-iprefix", from[from_i]) + || str_equal("-iwithprefix", from[from_i]) + || str_equal("-isystem", from[from_i]) + || str_equal("-iwithprefixbefore", from[from_i]) + || str_equal("-idirafter", from[from_i])) { + /* skip next word, being option argument */ + if (from[from_i+1]) + from_i++; + } + else if (str_startswith("-Wp,", from[from_i]) + || str_startswith("-Wl,", from[from_i]) + || str_startswith("-D", from[from_i]) + || str_startswith("-U", from[from_i]) + || str_startswith("-I", from[from_i]) + || str_startswith("-l", from[from_i]) + || str_startswith("-L", from[from_i])) { + /* Something like "-DNDEBUG" or + * "-Wp,-MD,.deps/nsinstall.pp". Just skip this word */ + ; + } + else if (str_equal("-undef", from[from_i]) + || str_equal("-nostdinc", from[from_i]) + || str_equal("-nostdinc++", from[from_i]) + || str_equal("-MD", from[from_i]) + || str_equal("-MMD", from[from_i]) + || str_equal("-MG", from[from_i]) + || str_equal("-MP", from[from_i])) { + /* Options that only affect cpp; skip */ + ; + } + else { + to[to_i++] = from[from_i]; + } + } + + /* NULL-terminate */ + to[to_i] = NULL; + + dcc_trace_argv("result", to); + + return 0; +} + + + +/** + * Remove "-o" options from argument list. + * + * This is used when running the preprocessor, when we just want it to write + * to stdout, which is the default when no -o option is specified. + * + * Structurally similar to dcc_strip_local_args() + **/ +int dcc_strip_dasho(char **from, char ***out_argv) +{ + char **to; + int from_i, to_i; + int from_len; + + from_len = dcc_argv_len(from); + *out_argv = to = malloc((from_len + 1) * sizeof (char *)); + + if (!to) { + rs_log_error("failed to allocate space for arguments"); + return EXIT_OUT_OF_MEMORY; + } + + /* skip through argv, copying all arguments but skipping ones that + * ought to be omitted */ + for (from_i = to_i = 0; from[from_i]; ) { + if (!strcmp(from[from_i], "-o")) { + /* skip "-o FILE" */ + from_i += 2; + } + else if (str_startswith("-o", from[from_i])) { + /* skip "-oFILE" */ + from_i++; + } + else { + to[to_i++] = from[from_i++]; + } + } + + /* NULL-terminate */ + to[to_i] = NULL; + + dcc_trace_argv("result", to); + + return 0; +} + + + diff --git a/distcc/src/tempfile.c b/distcc/src/tempfile.c new file mode 100644 index 0000000..fb6eb2e --- /dev/null +++ b/distcc/src/tempfile.c @@ -0,0 +1,412 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + /* "More computing sins are committed in the name of + * efficiency (without necessarily achieving it) than + * for any other single reason - including blind + * stupidity." -- W.A. Wulf + */ + + + +#include "config.h" + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/time.h> + +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "snprintf.h" +#include "exitcode.h" + + + +/** + * @file + * + * Routines for naming, generating and removing temporary files. + * + * Temporary files are stored under $TMPDIR or /tmp. + * + * From 2.10 on, our lock and state files are not stored in there. + * + * It would be nice if we could use a standard function, but I don't + * think any of them are adequate: we need to control the extension + * and know the filename. tmpfile() does not give back the filename. + * tmpnam() is insecure. mkstemp() does not allow us to set the + * extension. + * + * It sucks that there is no standard function. The implementation + * below is inspired by the __gen_tempname() code in glibc; hopefully + * it will be secure on all platforms. + * + * We need to touch the filename before running commands on it, + * because we cannot be sure that the compiler will create it + * securely. + * + * Even with all this, we are not necessarily secure in the presence + * of a tmpreaper if the attacker can play timing tricks. However, + * since we are not setuid and since there is no completely safe way + * to write tmpreapers, this is left alone for now. + * + * If you're really paranoid, you should just use per-user TMPDIRs. + * + * @sa http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/avoid-race.html#TEMPORARY-FILES + **/ + +/** + * Create the directory @p path, and register it for deletion when this + * compilation finished. If it already exists as a directory + * we succeed, but we don't register the directory for deletion. + **/ +int dcc_mk_tmpdir(const char *path) +{ + struct stat buf; + int ret; + + if (stat(path, &buf) == -1) { + if (mkdir(path, 0777) == -1) { + return EXIT_IO_ERROR; + } + if ((ret = dcc_add_cleanup(path))) { + // bailing out + rmdir(path); + return ret; + } + } else { + /* we could stat the file successfully; if it's a directory, + * all is well, but we should not it delete later, since we did + * not make it. + */ + if ((buf.st_mode & S_IFDIR) == S_IFDIR) { + return 0; + } else { + rs_log_error("mkdir '%s' failed: %s", path, strerror(errno)); + return EXIT_IO_ERROR; + } + } + return 0; +} + +/** + * Create the directory @p path. If it already exists as a directory + * we succeed. + **/ +int dcc_mkdir(const char *path) +{ + if ((mkdir(path, 0777) == -1) && (errno != EEXIST)) { + rs_log_error("mkdir '%s' failed: %s", path, strerror(errno)); + return EXIT_IO_ERROR; + } + + return 0; +} + + +/* This function creates a temporary directory, to be used for + * all (input) files during one compilation. + * The name of the directory is stored in @p tempdir, which is + * malloc'ed here. The caller is responsible for freeing it. + * The format of the directory name is TMPTOP/randomnumber + * Returns the new temp dir in tempdir. + */ +int dcc_get_new_tmpdir(char **tempdir) +{ + int ret; + const char *tmp_top; + char *s; + if ((ret = dcc_get_tmp_top(&tmp_top))) { + return ret; + } + if (asprintf(&s, "%s/distccd_XXXXXX", tmp_top) == -1) + return EXIT_OUT_OF_MEMORY; + if ((*tempdir = mkdtemp(s)) == 0) { + return EXIT_IO_ERROR; + } + if ((ret = dcc_add_cleanup(s))) { + // bailing out + rmdir(s); + return ret; + } + return 0; +} + + +int dcc_get_tmp_top(const char **p_ret) +{ + const char *d; + + d = getenv("TMPDIR"); + + if (!d || d[0] == '\0') { + *p_ret = "/tmp"; + return 0; + } else { + *p_ret = d; + return 0; + } +} + +/** + * Create the full @path. If it already exists as a directory + * we succeed. + */ +int dcc_mk_tmp_ancestor_dirs(const char *path) +{ + char *copy = 0; + char *p; + int ret; + + copy = strdup(path); + if (copy == NULL) { + return EXIT_OUT_OF_MEMORY; + } + + dcc_truncate_to_dirname(copy); + if (copy[0] == '\0') { + free(copy); + return 0; + } + + /* First, let's try and see if all parent directories + * exist already */ + if ((ret = dcc_mk_tmpdir(copy)) == 0) { + free(copy); + return 0; + } + + /* This is the "pessimistic" algorithm for making directories, + * which assumes that most directories that it's asked to create + * do not exist. It's expensive for very deep directories; + * it tries to make all the directories from the root to that + * dir. However, it only gets called if we tried to make a dir + * in a directory and failed; which means we only get called + * once per directory. + */ + // Body of this loop does not execute when *p=='\0'; + // therefore the very last component of the directory does not + // get created here. + for (p = copy; *p != '\0'; ++p) { + if (*p == '/' && p != copy) { + *p = '\0'; + if ((ret = dcc_mk_tmpdir(copy))) { + free(copy); + return ret; + } + *p = '/'; + } + } + ret = dcc_mk_tmpdir(copy); + free(copy); + return ret; +} + +/** + * Return a static string holding DISTCC_DIR, or ~/.distcc. + * The directory is created if it does not exist. + **/ +int dcc_get_top_dir(char **path_ret) +{ + char *env; + static char *cached; + int ret; + + if (cached) { + *path_ret = cached; + return 0; + } + + if ((env = getenv("DISTCC_DIR"))) { + if ((cached = strdup(env)) == NULL) { + return EXIT_OUT_OF_MEMORY; + } else { + *path_ret = cached; + return 0; + } + } + + if ((env = getenv("HOME")) == NULL) { + rs_log_warning("HOME is not set; can't find distcc directory"); + return EXIT_BAD_ARGUMENTS; + } + + if (asprintf(path_ret, "%s/.distcc", env) == -1) { + rs_log_error("asprintf failed"); + return EXIT_OUT_OF_MEMORY; + } + + ret = dcc_mkdir(*path_ret); + if (ret == 0) + cached = *path_ret; + return ret; +} + + +/** + * Return a subdirectory of the DISTCC_DIR of the given name, making + * sure that the directory exists. + **/ +static int dcc_get_subdir(const char *name, + char **dir_ret) +{ + int ret; + char *topdir; + + if ((ret = dcc_get_top_dir(&topdir))) + return ret; + + if (asprintf(dir_ret, "%s/%s", topdir, name) == -1) { + rs_log_error("asprintf failed"); + return EXIT_OUT_OF_MEMORY; + } + + return dcc_mkdir(*dir_ret); +} + +int dcc_get_lock_dir(char **dir_ret) +{ + static char *cached; + int ret; + + if (cached) { + *dir_ret = cached; + return 0; + } else { + ret = dcc_get_subdir("lock", dir_ret); + if (ret == 0) + cached = *dir_ret; + return ret; + } +} + +int dcc_get_state_dir(char **dir_ret) +{ + static char *cached; + int ret; + + if (cached) { + *dir_ret = cached; + return 0; + } else { + ret = dcc_get_subdir("state", dir_ret); + if (ret == 0) + cached = *dir_ret; + return ret; + } +} + + + +/** + * Create a file inside the temporary directory and register it for + * later cleanup, and return its name. + * + * The file will be reopened later, possibly in a child. But we know + * that it exists with appropriately tight permissions. + **/ +int dcc_make_tmpnam(const char *prefix, + const char *suffix, + char **name_ret) +{ + char *s = NULL; + const char *tempdir; + int ret; + unsigned long random_bits; + int fd; + + if ((ret = dcc_get_tmp_top(&tempdir))) + return ret; + + if (access(tempdir, W_OK|X_OK) == -1) { + rs_log_error("can't use TMPDIR \"%s\": %s", tempdir, strerror(errno)); + return EXIT_IO_ERROR; + } + + random_bits = (unsigned long) getpid() << 16; + +# if HAVE_GETTIMEOFDAY + { + struct timeval tv; + gettimeofday(&tv, NULL); + random_bits ^= tv.tv_usec << 16; + random_bits ^= tv.tv_sec; + } +# else + random_bits ^= time(NULL); +# endif + +#if 0 + random_bits = 0; /* FOR TESTING */ +#endif + + do { + free(s); + + if (asprintf(&s, "%s/%s_%08lx%s", + tempdir, + prefix, + random_bits & 0xffffffffUL, + suffix) == -1) + return EXIT_OUT_OF_MEMORY; + + /* Note that if the name already exists as a symlink, this + * open call will fail. + * + * The permissions are tight because nobody but this process + * and our children should do anything with it. */ + fd = open(s, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd == -1) { + /* try again */ + rs_trace("failed to create %s: %s", s, strerror(errno)); + random_bits += 7777; /* fairly prime */ + continue; + } + + if (close(fd) == -1) { /* huh? */ + rs_log_warning("failed to close %s: %s", s, strerror(errno)); + return EXIT_IO_ERROR; + } + + break; + } while (1); + + if ((ret = dcc_add_cleanup(s))) { + // bailing out + unlink(s); + free(s); + return ret; + } + + *name_ret = s; + return 0; +} diff --git a/distcc/src/timefile.c b/distcc/src/timefile.c new file mode 100644 index 0000000..bce8c87 --- /dev/null +++ b/distcc/src/timefile.c @@ -0,0 +1,159 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +/** + * @file + * + * @brief Track timeouts by setting the mtime of a file. + * + * distcc needs to set timeouts to backoff from unreachable hosts. As a very + * simple and robust way of keeping track of this, we simply touch a file in + * our state directory, whenever we fail to connect. Future invocations can + * look at how recently the host failed when deciding whether to use it again. + **/ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <time.h> + +#include <sys/stat.h> +#include <sys/file.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "exitcode.h" +#include "snprintf.h" +#include "lock.h" +#include "timefile.h" + + +/** + * Record the current time against the specified function and host. + **/ +int dcc_mark_timefile(const char *lockname, + const struct dcc_hostdef *host) +{ + char *filename; + int fd; + int ret; + + if ((ret = dcc_make_lock_filename(lockname, host, 0, &filename))) + return ret; + + if ((ret = dcc_open_lockfile(filename, &fd))) { + free(filename); + return ret; + } + + /* Merely opening it with O_WRONLY is not necessarily enough to set its + * mtime to the current time. */ + if (write(fd, "x", 1) != 1) { + rs_log_error("write to %s failed: %s", lockname, strerror(errno)); + dcc_close(fd); + return EXIT_IO_ERROR; + } + + dcc_close(fd); + + rs_trace("mark %s", filename); + + free(filename); + + return 0; +} + + + +/** + * Remove the specified timestamp. + **/ +int dcc_remove_timefile(const char *lockname, + const struct dcc_hostdef *host) +{ + char *filename; + int ret = 0; + + if ((ret = dcc_make_lock_filename(lockname, host, 0, &filename))) + return ret; + + if (unlink(filename) == 0) { + rs_trace("remove %s", filename); + } else { + if (errno == ENOENT) { + /* it's ok if somebody else already removed it */ + } else { + rs_log_error("unlink %s failed: %s", filename, strerror(errno)); + ret = EXIT_IO_ERROR; + } + } + + free(filename); + + return 0; +} + + + +/** + * Return the mtime for a timestamp file. + * + * If the timestamp doesn't exist then we count it as time zero. + **/ +int dcc_check_timefile(const char *lockname, + const struct dcc_hostdef *host, + time_t *mtime) +{ + char *filename; + struct stat sb; + int ret; + + if ((ret = dcc_make_lock_filename(lockname, host, 0, &filename))) + return ret; + + if (stat(filename, &sb) == -1) { + *mtime = (time_t) 0; + if (errno == ENOENT) { + /* just no record for this file; that's fine. */ + free(filename); + return 0; + } else { + rs_log_error("stat %s failed: %s", filename, strerror(errno)); + free(filename); + return EXIT_IO_ERROR; + } + } + + *mtime = sb.st_mtime; + + free(filename); + + return 0; +} diff --git a/distcc/src/timefile.h b/distcc/src/timefile.h new file mode 100644 index 0000000..8abbfe6 --- /dev/null +++ b/distcc/src/timefile.h @@ -0,0 +1,33 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +/* timefile.c */ +int dcc_mark_timefile(const char *lockname, + const struct dcc_hostdef *host); + +int dcc_remove_timefile(const char *lockname, + const struct dcc_hostdef *host); + +int dcc_check_timefile(const char *lockname, + const struct dcc_hostdef *host, + time_t *mtime); diff --git a/distcc/src/timeval.c b/distcc/src/timeval.c new file mode 100644 index 0000000..5106b98 --- /dev/null +++ b/distcc/src/timeval.c @@ -0,0 +1,36 @@ +/* from the GNU libc manual */ + +#include <sys/time.h> +#include <time.h> + +#include "timeval.h" + +/* Subtract the `struct timeval' values X and Y, + storing the result in RESULT. + Return 1 if the difference is negative, otherwise 0. */ + +int +timeval_subtract(struct timeval *result, + struct timeval *x, + struct timeval *y) +{ + /* Perform the carry for the later subtraction by updating Y. */ + if (x->tv_usec < y->tv_usec) { + int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; + y->tv_usec -= 1000000 * nsec; + y->tv_sec += nsec; + } + if (x->tv_usec - y->tv_usec > 1000000) { + int nsec = (x->tv_usec - y->tv_usec) / 1000000; + y->tv_usec += 1000000 * nsec; + y->tv_sec -= nsec; + } + + /* Compute the time remaining to wait. + `tv_usec' is certainly positive. */ + result->tv_sec = x->tv_sec - y->tv_sec; + result->tv_usec = x->tv_usec - y->tv_usec; + + /* Return 1 if result is negative. */ + return x->tv_sec < y->tv_sec; +} diff --git a/distcc/src/timeval.h b/distcc/src/timeval.h new file mode 100644 index 0000000..3781269 --- /dev/null +++ b/distcc/src/timeval.h @@ -0,0 +1,4 @@ +int +timeval_subtract(struct timeval *result, + struct timeval *x, + struct timeval *y); diff --git a/distcc/src/trace.c b/distcc/src/trace.c new file mode 100644 index 0000000..9ec7858 --- /dev/null +++ b/distcc/src/trace.c @@ -0,0 +1,433 @@ +/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- + * + * ecolog - Reusable application logging library. + * + * Copyright (C) 2000 - 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + /* + | Finality is death. + | Perfection is finality. + | Nothing is perfect. + | There are lumps in it. + */ + + +#include "config.h" + +#include <unistd.h> +#include <stdio.h> +#include <sys/file.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#include <stdarg.h> +#include <syslog.h> + +#include "trace.h" +#include "snprintf.h" + +struct rs_logger_list { + rs_logger_fn *fn; + void *private_ptr; + int private_int; + int max_level; + struct rs_logger_list *next; +}; + +static struct rs_logger_list *logger_list = NULL; + + +int rs_trace_level = RS_LOG_NOTICE; + +#ifdef UNUSED +/* nothing */ +#elif defined(__GNUC__) +# define UNUSED(x) x __attribute__((unused)) +#elif defined(__LCLINT__) +# define UNUSED(x) /*@unused@*/ x +#else /* !__GNUC__ && !__LCLINT__ */ +# define UNUSED(x) x +#endif /* !__GNUC__ && !__LCLINT__ */ + + +static void rs_log_va(int level, char const *fn, char const *fmt, va_list va); + +#if SIZEOF_SIZE_T > SIZEOF_LONG +# warning size_t is larger than a long integer, values in trace messages may be wrong +#endif + + +/** + * Log severity strings, if any. Must match ordering in + * ::rs_loglevel. + */ +static const char *rs_severities[] = { + "EMERGENCY! ", "ALERT! ", "CRITICAL! ", "ERROR: ", "Warning: ", + "", "", "" +}; + + +/********************************************************************** + * Functions for manipulating the list of loggers + **********************************************************************/ + +void rs_remove_all_loggers(void) +{ + struct rs_logger_list *l, *next; + + for (l = logger_list; l; l = next) { + next = l -> next; /* save before destruction */ + free(l); + } + logger_list = NULL; +} + + +void rs_add_logger(rs_logger_fn fn, + int max_level, + void *private_ptr, + int private_int) +{ + struct rs_logger_list *l; + + if ((l = malloc(sizeof *l)) == NULL) + return; + + l->fn = fn; + l->max_level = max_level; + l->private_ptr = private_ptr; + l->private_int = private_int; + + l->next = logger_list; + logger_list = l; +} + + +/** + * Remove only the logger that exactly matches the specified parameters + **/ +void rs_remove_logger(rs_logger_fn fn, + int max_level, + void *private_ptr, + int private_int) +{ + struct rs_logger_list *l, **pl; + + for (pl = &logger_list; *pl; pl = &((*pl)->next)) { + l = *pl; + if (l->fn == fn + && l->max_level == max_level + && l->private_ptr == private_ptr + && l->private_int == private_int) { + /* unhook from list by adjusting whoever points to this. */ + *pl = l->next; + free(l); + return; + } + } +} + + +/** + * Set the least important (i.e. largest) message severity that + * will be output. + */ +void +rs_trace_set_level(rs_loglevel level) +{ + rs_trace_level = level; +} + + + +/** + * Work out a log level from a string name. + * + * Returns -1 for invalid names. + */ +int +rs_loglevel_from_name(const char *name) +{ + if (!strcmp(name, "emerg") || !strcmp(name, "emergency")) + return RS_LOG_EMERG; + else if (!strcmp(name, "alert")) + return RS_LOG_ALERT; + else if (!strcmp(name, "critical") || !strcmp(name, "crit")) + return RS_LOG_CRIT; + else if (!strcmp(name, "error") || !strcmp(name, "err")) + return RS_LOG_ERR; + else if (!strcmp(name, "warning") || !strcmp(name, "warn")) + return RS_LOG_WARNING; + else if (!strcmp(name, "notice") || !strcmp(name, "note")) + return RS_LOG_NOTICE; + else if (!strcmp(name, "info")) + return RS_LOG_INFO; + else if (!strcmp(name, "debug")) + return RS_LOG_DEBUG; + + return -1; +} + + +/** + * If you don't initialize a logger before first logging, then we + * write to stderr by default. + **/ +static void rs_lazy_default(void) +{ + static int called; + + if (called) + return; + + called = 1; + if (logger_list == NULL) + rs_add_logger(rs_logger_file, RS_LOG_WARNING, NULL, STDERR_FILENO); +} + + +/* Heart of the matter */ +static void +rs_log_va(int flags, char const *caller_fn_name, char const *fmt, va_list va) + + +{ + int level = flags & RS_LOG_PRIMASK; + struct rs_logger_list *l; + + rs_lazy_default(); + + if (level <= rs_trace_level) + for (l = logger_list; l; l = l->next) + if (level <= l->max_level) + l->fn(flags, caller_fn_name, + fmt, va, l->private_ptr, l->private_int); +} + + +void rs_format_msg(char *buf, + size_t buf_len, + int flags, + const char *fn, + const char *fmt, + va_list va) +{ + unsigned level = flags & RS_LOG_PRIMASK; + int len; + const char *sv; + + *buf = '\0'; + len = 0; + + if (!(flags & RS_LOG_NO_PROGRAM)) { + strcpy(buf, rs_program_name); + len = strlen(buf); + } + + if (!(flags & RS_LOG_NO_PID)) { + /* You might like to cache the pid, but that would cause trouble when we fork. */ + sprintf(buf+len, "[%d] ", (int) getpid()); + } else if (~flags & RS_LOG_NO_PROGRAM) { + strcat(buf+len, ": "); + } + len = strlen(buf); + + if (!(flags & RS_LOG_NONAME) && fn) { + sprintf(buf+len, "(%s) ", fn); + len = strlen(buf); + } + + sv = rs_severities[level]; + if (*sv) { + strcpy(buf + len, sv); + len = strlen(buf); + } + + vsnprintf(buf + len, buf_len - len, fmt, va); +} + + + +/** + * Called by a macro, used on platforms where we can't determine the + * calling function name. + */ +void +rs_log0_nofn(int level, char const *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + rs_log_va(level, NULL, fmt, va); + va_end(va); +} + + +void rs_log0(int level, char const *fn, char const *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + rs_log_va(level, fn, fmt, va); + va_end(va); +} + + +void +rs_logger_syslog(int flags, const char *fn, char const *fmt, va_list va, + void * UNUSED(private_ptr), int UNUSED(private_int)) +{ + /* NOTE NO TRAILING NUL */ + char buf[4090]; + + /* you're never going to want program or pid in a syslog message, + * because it's redundant. */ + rs_format_msg(buf, sizeof buf, + flags | RS_LOG_NO_PROGRAM | RS_LOG_NO_PID, + fn, fmt, va); + syslog(flags & RS_LOG_PRIMASK, "%s", buf); +} + + +void +rs_logger_file(int flags, const char *fn, char const *fmt, va_list va, + void * UNUSED(private_ptr), int log_fd) +{ + /* NOTE NO TRAILING NUL */ + char buf[4090]; + size_t len; + + rs_format_msg(buf, sizeof buf, flags, fn, fmt, va); + + len = strlen(buf); + if (len > (int) sizeof buf - 2) + len = (int) sizeof buf - 2; + strcpy(&buf[len], "\n"); + + (void) write(log_fd, buf, len+1); +} + + + +/* ======================================================================== */ +/* functions for handling compilers without varargs macros */ + +/* This is called directly if the machine doesn't allow varargs + * macros. */ +void +rs_log_error_nofn(char const *s, ...) +{ + va_list va; + + va_start(va, s); + rs_log_va(RS_LOG_ERR, NULL, s, va); + va_end(va); +} + +/* This is called directly if the machine doesn't allow varargs + * macros. */ +void +rs_log_warning_nofn(char const *s, ...) +{ + va_list va; + + va_start(va, s); + rs_log_va(RS_LOG_WARNING, NULL, s, va); + va_end(va); +} + + +/* This is called directly if the machine doesn't allow varargs + * macros. */ +void +rs_log_critical_nofn(char const *s, ...) +{ + va_list va; + + va_start(va, s); + rs_log_va(RS_LOG_CRIT, NULL, s, va); + va_end(va); +} + +/* This is called directly if the machine doesn't allow varargs + * macros. */ +void +rs_log_info_nofn(char const *s, ...) +{ + va_list va; + + va_start(va, s); + rs_log_va(RS_LOG_INFO, NULL, s, va); + va_end(va); +} + + +/* This is called directly if the machine doesn't allow varargs + * macros. */ +void +rs_log_notice_nofn(char const *s, ...) +{ + va_list va; + + va_start(va, s); + rs_log_va(RS_LOG_NOTICE, NULL, s, va); + va_end(va); +} + + +/* This is called directly if the machine doesn't allow varargs + * macros. */ +void +rs_log_trace_nofn(char const *s, ...) +{ + va_list va; + + va_start(va, s); + rs_log_va(RS_LOG_DEBUG, NULL, s, va); + va_end(va); +} + + +/** + * Return true if the library contains trace code; otherwise false. + * If this returns false, then trying to turn trace on will achieve + * nothing. + */ +int +rs_supports_trace(void) +{ +#ifdef DO_RS_TRACE + return 1; +#else + return 0; +#endif /* !DO_RS_TRACE */ +} + + +static char job_summary[4096]; +void dcc_job_summary_clear(void) { + job_summary[0] = 0; +} + +void dcc_job_summary(void) { + rs_log_notice("%s", job_summary); +} + +void dcc_job_summary_append(const char *s) { + strncat(job_summary, s, 4096-strlen(job_summary)); +} diff --git a/distcc/src/trace.h b/distcc/src/trace.h new file mode 100644 index 0000000..0d99e0f --- /dev/null +++ b/distcc/src/trace.h @@ -0,0 +1,230 @@ +/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- + * + * librsync -- generate and apply network deltas + * + * Copyright (C) 2000, 2001, 2002, 2003, 2004 by Martin Pool + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +/** + * @file + * + * Reusable trace library. + * + * @todo A function like perror that includes strerror output. Apache + * does this by adding flags as well as the severity level which say + * whether such information should be included. + * + * @todo Also check in configure for the C9X predefined identifier `_function', or + * whatever it's called. + **/ + +/* Provide simple macro statement wrappers (adapted from glib, and originally from Perl): + * RS_STMT_START { statements; } RS_STMT_END; + * can be used as a single statement, as in + * if (x) RS_STMT_START { ... } RS_STMT_END; else ... + * + * For gcc we will wrap the statements within `({' and `})' braces. + * For SunOS they will be wrapped within `if (1)' and `else (void) 0', + * and otherwise within `do' and `while (0)'. + */ +#if !(defined (RS_STMT_START) && defined (RS_STMT_END)) +# if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus) +# define RS_STMT_START (void)( +# define RS_STMT_END ) +# else +# if (defined (sun) || defined (__sun__)) +# define RS_STMT_START if (1) +# define RS_STMT_END else (void)0 +# else +# define RS_STMT_START do +# define RS_STMT_END while (0) +# endif +# endif +#endif + + +#include <stdarg.h> + +/* unconditionally on */ +#define DO_RS_TRACE + +/** + * Log severity levels. + * + * These have the same numeric values as the levels for syslog, at + * least in glibc. + * + * Trace may be turned off. + * + * Error is always on, but you can return and continue in some way. + */ +typedef enum { + RS_LOG_EMERG = 0, /**< System is unusable */ + RS_LOG_ALERT = 1, /**< Action must be taken immediately */ + RS_LOG_CRIT = 2, /**< Critical conditions */ + RS_LOG_ERR = 3, /**< Error conditions */ + RS_LOG_WARNING = 4, /**< Warning conditions */ + RS_LOG_NOTICE = 5, /**< Normal but significant condition */ + RS_LOG_INFO = 6, /**< Informational */ + RS_LOG_DEBUG = 7 /**< Debug-level messages */ +} rs_loglevel; + +int rs_loglevel_from_name(const char *name); + +enum { + RS_LOG_PRIMASK = 7, /**< Mask to extract priority + part. \internal */ + + RS_LOG_NONAME = 8, /**< \b Don't show function name in + message. */ + + RS_LOG_NO_PROGRAM = 16, + RS_LOG_NO_PID = 32 +}; + + +/** + * \typedef rs_logger_fn + * \brief Callback to write out log messages. + * \param level a syslog level. + * \param msg message to be logged. + * + * \param private Opaque data passed in when logger was added. For + * example, pointer to file descriptor. + */ +typedef void rs_logger_fn(int flags, const char *fn, + char const *msg, va_list, + void *private_ptr, int private_int); + +void rs_format_msg(char *buf, size_t, int, const char *, + const char *fmt, va_list); + +void rs_trace_set_level(rs_loglevel level); + +void rs_add_logger(rs_logger_fn *, int level, void *, int); +void rs_remove_logger(rs_logger_fn *, int level, void *, int); +void rs_remove_all_loggers(void); + + +void rs_logger_file(int level, const char *fn, char const *fmt, va_list va, + void *, int); + +void rs_logger_syslog(int level, const char *fn, char const *fmt, va_list va, + void *, int); + +/** Check whether the library was compiled with debugging trace suport. */ +int rs_supports_trace(void); + +void rs_log0(int level, char const *fn, char const *fmt, ...) +#if defined(__GNUC__) + __attribute__ ((format(printf, 3, 4))) +#endif /* __GNUC__ */ + ; + + + /* TODO: Check for the __FUNCTION__ thing, rather than gnuc */ +#if defined(HAVE_VARARG_MACROS) && defined(__GNUC__) + +#if 1 || defined(DO_RS_TRACE) +# define rs_trace(fmt, arg...) \ + do { rs_log0(RS_LOG_DEBUG, __FUNCTION__, fmt , ##arg); \ + } while (0) +#else +# define rs_trace(s, str...) +#endif /* !DO_RS_TRACE */ + +#define rs_log(l, s, str...) do { \ + rs_log0((l), __FUNCTION__, (s) , ##str); \ + } while (0) + + +#define rs_log_crit(s, str...) do { \ + rs_log0(RS_LOG_CRIT, __FUNCTION__, (s) , ##str); \ + } while (0) + +#define rs_log_error(s, str...) do { \ + rs_log0(RS_LOG_ERR, __FUNCTION__, (s) , ##str); \ + } while (0) + +#define rs_log_notice(s, str...) do { \ + rs_log0(RS_LOG_NOTICE, __FUNCTION__, (s) , ##str); \ + } while (0) + +#define rs_log_warning(s, str...) do { \ + rs_log0(RS_LOG_WARNING, __FUNCTION__, (s) , ##str); \ + } while (0) + +#define rs_log_info(s, str...) do { \ + rs_log0(RS_LOG_INFO, __FUNCTION__, (s) , ##str); \ + } while (0) + +#else /* not defined HAVE_VARARG_MACROS */ + +/* If we don't have gcc vararg macros, then we fall back to making the + * log routines just plain functions. On platforms without gcc (boo + * hiss!) this means at least you get some messages, but not the nice + * function names etc. */ +#define rs_log rs_log0_nofn + +#define rs_trace rs_log_trace_nofn +#define rs_log_info rs_log_info_nofn +#define rs_log_notice rs_log_notice_nofn +#define rs_log_warning rs_log_warning_nofn +#define rs_log_error rs_log_error_nofn +#define rs_log_crit rs_log_critical_nofn +#endif /* HAVE_VARARG_MACROS */ + + + +void rs_log_trace_nofn(char const *s, ...); +void rs_log_info_nofn(char const *, ...); +void rs_log_notice_nofn(char const *, ...); +void rs_log_warning_nofn(char const *s, ...); +void rs_log_error_nofn(char const *s, ...); +void rs_log_critical_nofn(char const *, ...); + +void rs_log0_nofn(int level, char const *fmt, ...); + + + +/** + * \macro rs_trace_enabled() + * + * Call this before putting too much effort into generating trace + * messages. + */ + +extern int rs_trace_level; + +#ifdef DO_RS_TRACE +# define rs_trace_enabled() ((rs_trace_level & RS_LOG_PRIMASK) >= RS_LOG_DEBUG) +#else +# define rs_trace_enabled() 0 +#endif + +/** + * Name of the program, to be included in log messages. + * + * @note This must be defined exactly once in each program that links to + * trace.c + **/ +extern const char *rs_program_name; + +void dcc_job_summary_clear(void); +void dcc_job_summary(void); +void dcc_job_summary_append(const char *s); diff --git a/distcc/src/traceenv.c b/distcc/src/traceenv.c new file mode 100644 index 0000000..2a60858 --- /dev/null +++ b/distcc/src/traceenv.c @@ -0,0 +1,93 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> + +#include "distcc.h" +#include "trace.h" +#include "exitcode.h" +#include "util.h" + + +/** + * Setup client error/trace output. + * + * Trace goes to the file specified by DISTCC_LOG, if any. Otherwise, it goes + * to stderr, except that UNCACHED_ERR_FD can redirect it elsewhere, for use + * under ccache. + * + * The exact setting of log level is a little strange, but for a good + * reason: if you ask for verbose, you get everything. Otherwise, if + * you set a file, you get INFO and above. Otherwise, you only get + * WARNING messages. In practice this seems to be a nice balance. + **/ +void dcc_set_trace_from_env(void) +{ + const char *logfile, *logfd_name; + int fd; + int failed_to_open_logfile = 0; + int save_errno = 0; + int level = RS_LOG_WARNING; /* by default, warnings only */ + + /* let the decision on what to log rest on the loggers */ + /* the email-an-error functionality in emaillog.c depends on this */ + rs_trace_set_level(RS_LOG_DEBUG); + + if ((logfile = getenv("DISTCC_LOG")) && logfile[0]) { + fd = open(logfile, O_WRONLY|O_APPEND|O_CREAT, 0666); + if (fd != -1) { + /* asked for a file, and we can open that file: + include info messages */ + level = RS_LOG_INFO; + } else { + /* asked for a file, can't use it; use stderr instead */ + fd = STDERR_FILENO; + save_errno = errno; + failed_to_open_logfile = 1; + } + } else { + /* not asked for file */ + if ((logfd_name = getenv("UNCACHED_ERR_FD")) == NULL || + (fd = atoi(logfd_name)) == 0) { + fd = STDERR_FILENO; + } + } + + if (dcc_getenv_bool("DISTCC_VERBOSE", 0)) { + level = RS_LOG_DEBUG; + } + + rs_add_logger(rs_logger_file, level, NULL, fd); + + if (failed_to_open_logfile) { + rs_log_error("failed to open logfile %s: %s", + logfile, strerror(save_errno)); + } +} diff --git a/distcc/src/types.h b/distcc/src/types.h new file mode 100644 index 0000000..6f57bf5 --- /dev/null +++ b/distcc/src/types.h @@ -0,0 +1,36 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef HAVE_IN_PORT_T +#define HAVE_IN_PORT_T +typedef int in_port_t; +#endif + +#ifndef HAVE_IN_ADDR_T +/* Seems to be equivalent to ulong on FreeBSD 3.3, where it is missing. + * http://www.freebsd.org/cgi/man.cgi?query=inet_aton&apropos=0&sektion=0&manpath=FreeBSD+3.3-RELEASE&format=html + * + * On Linux it is uint32. + */ +#define HAVE_IN_ADDR_T +typedef unsigned long in_addr_t; +#endif diff --git a/distcc/src/util.c b/distcc/src/util.c new file mode 100644 index 0000000..16c803e --- /dev/null +++ b/distcc/src/util.c @@ -0,0 +1,769 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include "config.h" + +#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> +#include <netdb.h> +#include <ctype.h> + +#include <sys/stat.h> +#include <sys/time.h> + +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif + +#ifdef HAVE_SYS_LOADAVG_H +#include <sys/loadavg.h> +#endif + +#include <sys/param.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "exitcode.h" +#include "snprintf.h" + + /* I will make a man more precious than fine + * gold; even a man than the golden wedge of + * Ophir. + * -- Isaiah 13:12 */ + + +void dcc_exit(int exitcode) +{ + struct rusage self_ru, children_ru; + + if (getrusage(RUSAGE_SELF, &self_ru)) { + rs_log_warning("getrusage(RUSAGE_SELF) failed: %s", strerror(errno)); + memset(&self_ru, 0, sizeof self_ru); + } + if (getrusage(RUSAGE_CHILDREN, &children_ru)) { + rs_log_warning("getrusage(RUSAGE_CHILDREN) failed: %s", strerror(errno)); + memset(&children_ru, 0, sizeof children_ru); + } + + /* NB fields must match up for microseconds */ + rs_log(RS_LOG_INFO, + "exit: code %d; self: %d.%06d user %d.%06d sys; children: %d.%06d user %d.%06d sys", + exitcode, + (int) self_ru.ru_utime.tv_sec, (int) self_ru.ru_utime.tv_usec, + (int) self_ru.ru_stime.tv_sec, (int) self_ru.ru_stime.tv_usec, + (int) children_ru.ru_utime.tv_sec, (int) children_ru.ru_utime.tv_usec, + (int) children_ru.ru_stime.tv_sec, (int) children_ru.ru_stime.tv_usec); + + exit(exitcode); +} + + +int str_endswith(const char *tail, const char *tiger) +{ + size_t len_tail = strlen(tail); + size_t len_tiger = strlen(tiger); + + if (len_tail > len_tiger) + return 0; + + return !strcmp(tiger + len_tiger - len_tail, tail); +} + + +int str_startswith(const char *head, const char *worm) +{ + return !strncmp(head, worm, strlen(head)); +} + + + +/** + * Skim through NULL-terminated @p argv, looking for @p s. + **/ +int argv_contains(char **argv, const char *s) +{ + while (*argv) { + if (!strcmp(*argv, s)) + return 1; + argv++; + } + return 0; +} + + +/** + * Redirect a file descriptor into (or out of) a file. + * + * Used, for example, to catch compiler error messages into a + * temporary file. + **/ +int dcc_redirect_fd(int fd, const char *fname, int mode) +{ + int newfd; + + /* ignore errors */ + close(fd); + + newfd = open(fname, mode, 0666); + if (newfd == -1) { + rs_log_crit("failed to reopen fd%d onto %s: %s", + fd, fname, strerror(errno)); + return EXIT_IO_ERROR; + } else if (newfd != fd) { + rs_log_crit("oops, reopened fd%d onto fd%d?", fd, newfd); + return EXIT_IO_ERROR; + } + + return 0; +} + + + +char *dcc_gethostname(void) +{ + static char myname[100] = "\0"; + + if (!myname[0]) { + if (gethostname(myname, sizeof myname - 1) == -1) + strcpy(myname, "UNKNOWN"); + } + + return myname; +} + + +/** + * Look up a boolean environment option, which must be either "0" or + * "1". The default, if it's not set or is empty, is @p default. + **/ +int dcc_getenv_bool(const char *name, int default_value) +{ + const char *e; + + e = getenv(name); + if (!e || !*e) + return default_value; + if (!strcmp(e, "1")) + return 1; + else if (!strcmp(e, "0")) + return 0; + else + return default_value; +} + + +#define IS_LEGAL_DOMAIN_CHAR(c) (isalnum(c) || ((c) == '-') || ((c) == '.')) + +/* Copy domain part of hostname to static buffer. + * If hostname has no domain part, returns -1. + * If domain lookup fails, returns -1. + * Otherwise places pointer to domain in *domain_name and returns 0. + * + * This should yield the same result as the linux command + * 'dnsdomainname' or 'hostname -d'. + **/ +int dcc_get_dns_domain(const char **domain_name) +{ +#if 0 /* Too expensive */ + + static char host_name[1024]; + struct hostent *h; + int ret; + + ret = gethostname(host_name, sizeof(host_name)); + if (ret != 0) + return -1; + + h = gethostbyname(host_name); + if (h == NULL) { + rs_log_error("failed to look up self \"%s\": %s", host_name, + hstrerror(h_errno)); + return -1; + } + + strncpy(host_name, h->h_name, sizeof(host_name)); + *domain_name = strchr(h->h_name, '.'); + +#else /* cheaper */ + const char *envh, *envh2; + int i; + const int MAXDOMAINLEN = 512; + + /* Kludge for speed: Try to retrieve FQDN from environment. + * This can save many milliseconds on a network that's busy and lossy + * (glibc retries DNS operations very slowly). + */ + + /* Solaris, BSD tend to put it in HOST. + * (Some flavors of Linux put the non-qualified hostname in HOST, + * so ignore this if it doesn't have a dot in it.) + */ + envh = getenv("HOST"); + if (envh && !strchr(envh, '.')) + envh = NULL; + + /* Some flavors of Linux put the FQDN in HOSTNAME when + * logged in interactively, but not when ssh'd in noninteractively. + * Ubuntu's bash puts it in HOSTNAME but doesn't export it! + */ + envh2 = getenv("HOSTNAME"); + if (envh2 && !strchr(envh2, '.')) + envh2 = NULL; + + /* Pick the 'better' of the two. Longer is usually better. */ + if (envh2 && (!envh || (strlen(envh) < strlen(envh2)))) + envh = envh2; + + /* If the above didn't work out, fall back to the real way. */ + if (!envh || !strchr(envh, '.')) { + static char host_name[1024]; + struct hostent *h; + int ret; + + ret = gethostname(host_name, sizeof(host_name)); + if (ret != 0) + return -1; + + /* If hostname has a dot in it, assume it's the DNS address */ + if (!strchr(host_name, '.')) { + /* Otherwise ask DNS what our full hostname is */ + h = gethostbyname(host_name); + if (h == NULL) { + rs_log_error("failed to look up self \"%s\": %s", host_name, + hstrerror(h_errno)); + return -1; + } + strncpy(host_name, h->h_name, sizeof(host_name)); + } + envh = host_name; + } + + /* validate to avoid possible errors from bad chars or huge value */ + for (i=0; envh[i] != '\0'; i++) { + if (i > MAXDOMAINLEN || !IS_LEGAL_DOMAIN_CHAR(envh[i])) { + rs_log_error("HOST/HOSTNAME present in environment but illegal: '%s'", envh); + return -1; + } + } + *domain_name = strchr(envh, '.'); +#endif + + if (*domain_name == NULL) + return -1; + + (*domain_name)++; + /* Return 0 on success, or -1 if the domain name is illegal, e.g. empty */ + return ((*domain_name)[0] == '\0') ? -1 : 0; +} + + + +/** + * Set the `FD_CLOEXEC' flag of DESC if VALUE is nonzero, + * or clear the flag if VALUE is 0. + * + * From the GNU C Library examples. + * + * @returns 0 on success, or -1 on error with `errno' set. + **/ +int set_cloexec_flag (int desc, int value) +{ + int oldflags = fcntl (desc, F_GETFD, 0); + /* If reading the flags failed, return error indication now. */ + if (oldflags < 0) + return oldflags; + /* Set just the flag we want to set. */ + if (value != 0) + oldflags |= FD_CLOEXEC; + else + oldflags &= ~FD_CLOEXEC; + /* Store modified flag word in the descriptor. */ + return fcntl (desc, F_SETFD, oldflags); +} + + +/** + * Ignore or unignore SIGPIPE. + * + * The server and child ignore it, because distcc code wants to see + * EPIPE errors if something goes wrong. However, for invoked + * children it is set back to the default value, because they may not + * handle the error properly. + **/ +int dcc_ignore_sigpipe(int val) +{ + if (signal(SIGPIPE, val ? SIG_IGN : SIG_DFL) == SIG_ERR) { + rs_log_warning("signal(SIGPIPE, %s) failed: %s", + val ? "ignore" : "default", + strerror(errno)); + return EXIT_DISTCC_FAILED; + } + return 0; +} + +/** + * Search through the $PATH looking for a directory containing a file called + * @p compiler_name, which is a symbolic link containing the string "distcc". + * + * Trim the path to just after the *last* such directory. + * + * If we find a distcc masquerade dir on the PATH, remove all the dirs up + * to that point. + **/ +int dcc_trim_path(const char *compiler_name) +{ + const char *envpath, *newpath, *p, *n; + char linkbuf[MAXPATHLEN], *buf; + struct stat sb; + size_t len; + + if (!(envpath = getenv("PATH"))) { + rs_trace("PATH seems not to be defined"); + return 0; + } + + rs_trace("original PATH %s", envpath); + rs_trace("looking for \"%s\"", compiler_name); + + /* Allocate a buffer that will let us append "/cc" onto any PATH + * element, even if there is only one item in the PATH. */ + if (!(buf = malloc(strlen(envpath)+1+strlen(compiler_name)+1))) { + rs_log_error("failed to allocate buffer for PATH munging"); + return EXIT_OUT_OF_MEMORY; + } + + for (n = p = envpath, newpath = NULL; *n; p = n) { + n = strchr(p, ':'); + if (n) + len = n++ - p; + else { + len = strlen(p); + n = p + len; + } + strncpy(buf, p, len); + + sprintf(buf + len, "/%s", compiler_name); + if (lstat(buf, &sb) == -1) + continue; /* ENOENT, EACCESS, etc */ + if (!S_ISLNK(sb.st_mode)) + break; + if ((len = readlink(buf, linkbuf, sizeof linkbuf)) <= 0) + continue; + linkbuf[len] = '\0'; + if (strstr(linkbuf, "distcc")) { + /* Set newpath to the part of the PATH past our match. */ + newpath = n; + } + } + + if (newpath) { + int ret = dcc_set_path(newpath); + if (ret) + return ret; + } else + rs_trace("not modifying PATH"); + + free(buf); + return 0; +} + +/* Set the PATH environment variable to the indicated value. */ +int dcc_set_path(const char *newpath) +{ + char *buf; + + if (asprintf(&buf, "PATH=%s", newpath) <= 0 || !buf) { + rs_log_error("failed to allocate buffer for new PATH"); + return EXIT_OUT_OF_MEMORY; + } + rs_trace("setting %s", buf); + if (putenv(buf) < 0) { + rs_log_error("putenv PATH failed"); + return EXIT_FAILURE; + } + /* We must leave "buf" allocated. */ + return 0; +} + +/* Return the supplied path with the current-working directory prefixed (if + * needed) and all "dir/.." references removed. Supply path_len if you want + * to use only a substring of the path string, otherwise make it 0. */ +char *dcc_abspath(const char *path, int path_len) +{ + static char buf[MAXPATHLEN]; + unsigned len; + char *p, *slash; + + if (*path == '/') + len = 0; + else { +#ifdef HAVE_GETCWD + getcwd(buf, sizeof buf); +#else + getwd(buf); +#endif + len = strlen(buf); + if (len >= sizeof buf) { + rs_log_crit("getwd overflowed in dcc_abspath()"); + } + buf[len++] = '/'; + } + if (path_len <= 0) + path_len = strlen(path); + if (path_len >= 2 && *path == '.' && path[1] == '/') { + path += 2; + path_len -= 2; + } + if (len + (unsigned)path_len >= sizeof buf) { + rs_log_error("path overflowed in dcc_abspath()"); + exit(EXIT_OUT_OF_MEMORY); + } + strncpy(buf + len, path, path_len); + buf[len + path_len] = '\0'; + for (p = buf+len-(len > 0); (p = strstr(p, "/../")) != NULL; p = slash) { + *p = '\0'; + if (!(slash = strrchr(buf, '/'))) + slash = p; + strcpy(slash, p+3); + } + return buf; +} + +/* Return the current number of running processes. */ +int dcc_getcurrentload(void) { +#if defined(linux) + double stats[3]; + int running; + int total; + int last_pid; + int retval; + + FILE *f = fopen("/proc/loadavg", "r"); + if (NULL == f) + return -1; + + retval = fscanf(f, "%lf %lf %lf %d/%d %d", &stats[0], &stats[1], &stats[2], + &running, &total, &last_pid); + fclose(f); + + if (6 != retval) + return -1; + + return running; +#else + return -1; +#endif +} + +/** + * Wrapper for getloadavg() that tries to return all 3 samples, and reports + * -1 for those samples that are not available. + * + * Averages are over the last 1, 5, and 15 minutes, respectively. + **/ +void dcc_getloadavg(double loadavg[3]) { + int num; + int i; + +#if defined(HAVE_GETLOADAVG) + num = getloadavg(loadavg, 3); +#else + num = 0; +#endif + + /* If getloadavg() didn't return 3 we want to fill + * in the invalid elements with -1 */ + if (num < 0) + num = 0; + + for (i=num; i < 3; ++i) + loadavg[i] = -1; +} + + +/** + * Duplicate the part of the string @p psrc up to a character in @p sep + * (or end of string), storing the result in @p pdst. @p psrc is updated to + * point to the terminator. (If the terminator is not found it will + * therefore point to \0. + * + * If there is no more string, then @p pdst is instead set to NULL, no + * memory is allocated, and @p psrc is not advanced. + **/ +int dcc_dup_part(const char **psrc, char **pdst, const char *sep) +{ + size_t len; + + len = strcspn(*psrc, sep); + if (len == 0) { + *pdst = NULL; + } else { + if (!(*pdst = malloc(len + 1))) { + rs_log_error("failed to allocate string duplicate: %d", (int) len); + return EXIT_OUT_OF_MEMORY; + } + strncpy(*pdst, *psrc, len); + (*pdst)[len] = '\0'; + (*psrc) += len; + } + + return 0; +} + + + +int dcc_remove_if_exists(const char *fname) +{ + if (unlink(fname) && errno != ENOENT) { + rs_log_warning("failed to unlink %s: %s", fname, + strerror(errno)); + return EXIT_IO_ERROR; + } + return 0; +} + + +/* Returns the number of processes in state D, the max non-cc/c++ RSS in kb and + * the max RSS program's name */ +void dcc_get_proc_stats(int *num_D, int *max_RSS, char **max_RSS_name) { +#if defined(linux) + DIR *proc = opendir("/proc"); + struct dirent *procsubdir; + static int pagesize = -1; + static char RSS_name[1024]; + char statfile[1024]; + FILE *f; + char name[1024]; + char state; + int pid; + int rss_size; + int l; + char *c; + int isCC; + + /* If this doesn't cut it for you, see how CVS does it: + * http://savannah.nongnu.org/cgi-bin/viewcvs/cvs/ccvs/lib/getpagesize.h */ + if (pagesize == -1) { +#if HAVE_GETPAGESIZE + pagesize = getpagesize(); +#else + pagesize = 8192; +#endif + } + + *num_D = 0; + *max_RSS = 0; + *max_RSS_name = RSS_name; + RSS_name[0] = 0; + + while ((procsubdir = readdir(proc)) != NULL) { + if (sscanf(procsubdir->d_name, "%d", &pid) != 1) + continue; + + strcpy(statfile, "/proc/"); + strcat(statfile, procsubdir->d_name); + strcat(statfile, "/stat"); + + f = fopen(statfile, "r"); + if (f == NULL) + continue; + + if (fscanf(f, "%*d %s %c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d", + name, &state, &rss_size) != 3) { + fclose(f); + continue; + } + + rss_size = (rss_size * pagesize) / 1024; /* get rss_size in KB */ + + if (state == 'D') { + (*num_D)++; + } + + l = strlen(RSS_name); + c = RSS_name; + + /* check for .*{++,cc} */ + isCC = (l >= 2) && ((c[l-1] == 'c' && c[l-2] == 'c') + || (c[l-1] == '+' && c[l-2] == '+')); + if ((rss_size > *max_RSS) && !isCC) { + *max_RSS = rss_size; + strncpy(RSS_name, name, 1024); + } + + fclose(f); + } + + closedir(proc); +#else + *num_D = -1; + *max_RSS = -1; + *max_RSS_name = "none"; +#endif +} + + +/* Returns the number of sector read/writes since boot */ +void dcc_get_disk_io_stats(int *n_reads, int *n_writes) { +#if defined(linux) + int retval; + int kernel26 = 1; + FILE *f; + int reads, writes, minor; + char dev[100]; + char tmp[1024]; + + *n_reads = 0; + *n_writes = 0; + + f = fopen("/proc/diskstats", "r"); + if (f == NULL) { + if (errno != ENOENT) + return; + + /* /proc/diskstats does not exist. probably a 2.4 kernel, so try reading + * /proc/partitions */ + f = fopen("/proc/partitions", "r"); + if (f == NULL) + return; + kernel26 = 0; + } + + if (!kernel26) /* blast away 2 header lines in /proc/partitions */ + fscanf(f, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s"); + + while (1) { + if (kernel26) + retval = fscanf(f, " %*d %d %s", &minor, dev); + else + retval = fscanf(f, " %*d %d %*d %s", &minor, dev); + + if (retval == EOF || retval != 2) + break; + + if (minor % 64 == 0 + && ((dev[0] == 'h' && dev[1] == 'd' && dev[2] == 'a') + || (dev[0] == 's' && dev[1] == 'd' && dev[2] == 'a'))) { + /* disk stats */ + retval = fscanf(f, " %*d %*d %d %*d %*d %*d %d %*d %*d %*d %*d", + &reads, &writes); + if (retval == EOF || retval != 2) + break; + + /* only add stats for disks, so we don't double count */ + *n_reads += reads; + *n_writes += writes; + } else { + /* individual parition stats */ + //retval = fscanf(f, " %*d %d %*d %d", &reads, &writes); + //if (retval == EOF || retval != 2) + // break; + /* assume the lines aren't longer that 1024 characters */ + fgets(tmp, 1024, f); + } + } + + fclose(f); +#else + *n_reads = 0; + *n_writes = 0; +#endif +} + + +#ifndef HAVE_STRLCPY +/* like strncpy but does not 0 fill the buffer and always null + terminates. bufsize is the size of the destination buffer */ + size_t strlcpy(char *d, const char *s, size_t bufsize) +{ + size_t len = strlen(s); + size_t ret = len; + if (bufsize <= 0) return 0; + if (len >= bufsize) len = bufsize-1; + memcpy(d, s, len); + d[len] = 0; + return ret; +} +#endif + +/* Given a string @p input, this function fills a + a newly-allocated array of strings with copies of + the input's whitespace-separated parts. + Returns 0 on success, 1 on error. + */ +int dcc_tokenize_string(const char *input, char ***argv_ptr) +{ + size_t n_spaces = 0; + char *for_count; + char **ap; + char *input_copy; + + // First of all, make a copy of the input string; + // this way, we can destroy the copy. + input_copy = strdup(input); + if (input_copy == NULL) + return 1; + + // Count the spaces in the string. + for (for_count = input_copy; *for_count; for_count++) + if (isspace(*for_count)) + n_spaces++; + + // The maximum number of space-delimited strings we + // can have is n_spaces + 1, and we need to add another 1 for + // the null-termination. + *argv_ptr = malloc(sizeof(char*) * (n_spaces + 1 + 1)); + if (*argv_ptr == NULL) { + free(input_copy); + return 1; + } + + ap = *argv_ptr; + while((*ap = strsep(&input_copy, " \t\n")) != NULL) { + + // If the field is empty, do nothing + if (**ap == '\0') + continue; + + *ap = strdup(*ap); + if (*ap == NULL) { + char **p; + for (p = *argv_ptr; *p; p++) { + free(*p); + } + free(*argv_ptr); + free(input_copy); + return 1; + } + + ap++; + } + free(input_copy); + return 0; +} diff --git a/distcc/src/util.h b/distcc/src/util.h new file mode 100644 index 0000000..e2aefed --- /dev/null +++ b/distcc/src/util.h @@ -0,0 +1,55 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include <setjmp.h> + +/* util.c */ +int dcc_getcurrentload(void); +void dcc_getloadavg(double loadavg[3]); +int argv_contains(char **argv, const char *s); +int dcc_redirect_fd(int, const char *fname, int); +int str_startswith(const char *head, const char *worm); +char *dcc_gethostname(void); +void dcc_exit(int exitcode) NORETURN; +int dcc_getenv_bool(const char *name, int def_value); +int set_cloexec_flag (int desc, int value); +int dcc_ignore_sigpipe(int val); +int dcc_remove_if_exists(const char *fname); +int dcc_trim_path(const char *compiler_name); +int dcc_set_path(const char *newpath); +char *dcc_abspath(const char *path, int path_len); +int dcc_get_dns_domain(const char **domain_name); + +#define str_equal(a, b) (!strcmp((a), (b))) + + +void dcc_get_proc_stats(int *num_D, int *max_RSS, char **max_RSS_name); +void dcc_get_disk_io_stats(int *n_reads, int *n_writes); + + +int dcc_dup_part(const char **psrc, char **pdst, const char *sep); + +#ifndef HAVE_STRLCPY +size_t strlcpy(char *d, const char *s, size_t bufsize); +#endif + +int dcc_tokenize_string(const char *in, char ***argv_ptr); diff --git a/distcc/src/where.c b/distcc/src/where.c new file mode 100644 index 0000000..de71647 --- /dev/null +++ b/distcc/src/where.c @@ -0,0 +1,197 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + /* I put the shotgun in an Adidas bag and padded it + * out with four pairs of tennis socks, not my style + * at all, but that was what I was aiming for: If they + * think you're crude, go technical; if they think + * you're technical, go crude. I'm a very technical + * boy. So I decided to get as crude as possible. + * These days, though, you have to be pretty technical + * before you can even aspire to crudeness. + * -- William Gibson, "Johnny Mnemonic" */ + + +/** + * @file + * + * Routines to decide on which machine to run a distributable job. + * + * The current algorithm (new in 1.2 and subject to change) is as follows. + * + * CPU lock is held until the job is complete. + * + * Once the request has been transmitted, the lock is released and a second + * job can be sent. + * + * Servers which wish to limit their load can defer accepting jobs, and the + * client will block with that lock held. + * + * cpp is probably cheap enough that we can allow it to run unlocked. However + * that is not true for local compilation or linking. + * + * @todo Write a test harness for the host selection algorithm. Perhaps a + * really simple simulation of machines taking different amounts of time to + * build stuff? + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <time.h> + +#include <sys/stat.h> +#include <sys/file.h> + +#include "distcc.h" +#include "trace.h" +#include "util.h" +#include "hosts.h" +#include "lock.h" +#include "where.h" +#include "exitcode.h" + + +static int dcc_lock_one(struct dcc_hostdef *hostlist, + struct dcc_hostdef **buildhost, + int *cpu_lock_fd); + + +int dcc_pick_host_from_list(struct dcc_hostdef **buildhost, + int *cpu_lock_fd) +{ + struct dcc_hostdef *hostlist; + int ret; + int n_hosts; + + if ((ret = dcc_get_hostlist(&hostlist, &n_hosts)) != 0) { + return EXIT_NO_HOSTS; + } + + if ((ret = dcc_remove_disliked(&hostlist))) + return ret; + + if (!hostlist) { + return EXIT_NO_HOSTS; + } + + return dcc_lock_one(hostlist, buildhost, cpu_lock_fd); + + /* FIXME: Host list is leaked? */ +} + + +static void dcc_lock_pause(void) +{ + /* This could do with some tuning. + * + * My assumption basically is that polling a little too often is + * relatively cheap; sleeping when we should be working is bad. However, + * if we hit this code at all we're overloaded, so sleeping a while is + * perhaps OK. + * + * We don't use exponential backoff, because that would tend to prefer + * later arrivals and penalize jobs that have been waiting for a long + * time. This would mean more compiler processes hanging around than is + * really necessary, and also by making jobs complete very-out-of-order is + * more likely to find Makefile bugs. */ + + unsigned pause_time = 1; + + dcc_note_state(DCC_PHASE_BLOCKED, NULL, NULL); + + rs_trace("nothing available, sleeping %us...", pause_time); + + sleep(pause_time); +} + + +/** + * Find a host that can run a distributed compilation by examining local state. + * It can be either a remote server or localhost (if that is in the list). + * + * This function does not return (except for errors) until a host has been + * selected. If necessary it sleeps until one is free. + * + * @todo We don't need transmit locks for local operations. + **/ +static int dcc_lock_one(struct dcc_hostdef *hostlist, + struct dcc_hostdef **buildhost, + int *cpu_lock_fd) +{ + struct dcc_hostdef *h; + int i_cpu; + int ret; + + while (1) { + for (i_cpu = 0; i_cpu < 50; i_cpu++) { + for (h = hostlist; h; h = h->next) { + if (i_cpu >= h->n_slots) + continue; + + ret = dcc_lock_host("cpu", h, i_cpu, 0, cpu_lock_fd); + + if (ret == 0) { + *buildhost = h; + dcc_note_state_slot(i_cpu); + return 0; + } else if (ret == EXIT_BUSY) { + continue; + } else { + rs_log_error("failed to lock"); + return ret; + } + } + } + + dcc_lock_pause(); + } +} + + + +/** + * Lock localhost. Used to get the right balance of jobs when some of + * them must be local. + **/ +int dcc_lock_local(int *cpu_lock_fd) +{ + struct dcc_hostdef *chosen; + + return dcc_lock_one(dcc_hostdef_local, &chosen, cpu_lock_fd); +} + +int dcc_lock_local_cpp(int *cpu_lock_fd) +{ + int ret; + struct dcc_hostdef *chosen; + ret = dcc_lock_one(dcc_hostdef_local_cpp, &chosen, cpu_lock_fd); + dcc_note_state(DCC_PHASE_CPP, NULL, chosen->hostname); + return ret; +} + diff --git a/distcc/src/where.h b/distcc/src/where.h new file mode 100644 index 0000000..d4c8dcd --- /dev/null +++ b/distcc/src/where.h @@ -0,0 +1,29 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* where.c */ +int dcc_pick_host_from_list(struct dcc_hostdef **, + int *cpu_lock_fd); + +int dcc_lock_local(int *cpu_lock_fd); + +int dcc_lock_local_cpp(int *cpu_lock_fd); diff --git a/distcc/survey.txt b/distcc/survey.txt new file mode 100644 index 0000000..5fc84d9 --- /dev/null +++ b/distcc/survey.txt @@ -0,0 +1,35 @@ +If you find distcc useful, please take a little time to fill out this +survey and mail it to {mbp at samba org}. + +Don't stress too much about getting scientifically rigorous numbers: +rough numbers are more useful than none at all. Ideally, complete the +survey for one large application that you work on, where compile speed +is important. + +If after installing distcc you find that it makes your compile slower, +or not as much faster as you would be expect, then please write to +{distcc at lists.samba.org} instead of filling in the survery, and +we'll try to resolve the problem. + + +0. What version of distcc are you using? + +1. Your name and email address: + +2. OK to publish this? + - yes + - yes, but without my identifying details + - yes, but without my email address + - no, for your eyes only + +3. Your codebase: lines of code (by wc -l), and language: + +4. Your machines: number, OS, processor, memory, network connectivity: + +5. Time to compile, with and without distcc: + +6. Any other observations: + + +Thanks! +Martin diff --git a/distcc/test/comfychair.py b/distcc/test/comfychair.py new file mode 100755 index 0000000..522f9be --- /dev/null +++ b/distcc/test/comfychair.py @@ -0,0 +1,445 @@ +#! /usr/bin/env python + +# Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> +# Copyright (C) 2003 by Tim Potter <tpot@samba.org> +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA + +"""comfychair: a Python-based instrument of software torture. + +Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> +Copyright (C) 2003 by Tim Potter <tpot@samba.org> + +This is a test framework designed for testing programs written in +Python, or (through a fork/exec interface) any other language. + +For more information, see the file README.comfychair. + +To run a test suite based on ComfyChair, just run it as a program. +""" + +import sys, re + + +class TestCase: + """A base class for tests. This class defines required functions which + can optionally be overridden by subclasses. It also provides some + utility functions for""" + + def __init__(self): + self.test_log = "" + self.background_pids = [] + self._cleanups = [] + self._enter_rundir() + self._save_environment() + self.add_cleanup(self.teardown) + + + # -------------------------------------------------- + # Save and restore directory + def _enter_rundir(self): + import os + self.basedir = os.getcwd() + self.add_cleanup(self._restore_directory) + self.rundir = os.path.join(self.basedir, + 'testtmp', + self.__class__.__name__) + self.tmpdir = os.path.join(self.rundir, 'tmp') + os.system("rm -fr %s" % self.rundir) + os.makedirs(self.tmpdir) + os.system("mkdir -p %s" % self.rundir) + os.chdir(self.rundir) + + def _restore_directory(self): + import os + os.chdir(self.basedir) + + # -------------------------------------------------- + # Save and restore environment + def _save_environment(self): + import os + self._saved_environ = os.environ.copy() + self.add_cleanup(self._restore_environment) + + def _restore_environment(self): + import os + os.environ.clear() + os.environ.update(self._saved_environ) + + + def setup(self): + """Set up test fixture.""" + pass + + def teardown(self): + """Tear down test fixture.""" + pass + + def runtest(self): + """Run the test.""" + pass + + + def add_cleanup(self, c): + """Queue a cleanup to be run when the test is complete.""" + self._cleanups.append(c) + + + def fail(self, reason = ""): + """Say the test failed.""" + raise AssertionError(reason) + + + ############################################################# + # Requisition methods + + def require(self, predicate, message): + """Check a predicate for running this test. + +If the predicate value is not true, the test is skipped with a message explaining +why.""" + if not predicate: + raise NotRunError, message + + def require_root(self): + """Skip this test unless run by root.""" + import os + self.require(os.getuid() == 0, + "must be root to run this test") + + ############################################################# + # Assertion methods + + def assert_(self, expr, reason = ""): + if not expr: + raise AssertionError(reason) + + def assert_equal(self, a, b): + if not a == b: + raise AssertionError("assertEquals failed: %s" % `(a, b)`) + + def assert_notequal(self, a, b): + if a == b: + raise AssertionError("assertNotEqual failed: %s" % `(a, b)`) + + def assert_re_match(self, pattern, s): + """Assert that a string matches a particular pattern + + Inputs: + pattern string: regular expression + s string: to be matched + + Raises: + AssertionError if not matched + """ + if not re.match(pattern, s): + raise AssertionError("string does not match regexp\n" + " string: %s\n" + " re: %s" % (`s`, `pattern`)) + + def assert_re_search(self, pattern, s): + """Assert that a string *contains* a particular pattern + + Inputs: + pattern string: regular expression + s string: to be searched + + Raises: + AssertionError if not matched + """ + if not re.search(pattern, s): + raise AssertionError("string does not contain regexp\n" + " string: %s\n" + " re: %s" % (`s`, `pattern`)) + + + def assert_no_file(self, filename): + import os.path + assert not os.path.exists(filename), ("file exists but should not: %s" % filename) + + + ############################################################# + # Methods for running programs + + def runcmd_background(self, cmd): + import os + self.test_log = self.test_log + "Run in background:\n" + `cmd` + "\n" + pid = os.fork() + if pid == 0: + # child + try: + os.execvp("/bin/sh", ["/bin/sh", "-c", cmd]) + finally: + os._exit(127) + self.test_log = self.test_log + "pid: %d\n" % pid + return pid + + + def runcmd(self, cmd, expectedResult = 0): + """Run a command, fail if the command returns an unexpected exit + code. Return the output produced.""" + rc, output, stderr = self.runcmd_unchecked(cmd) + if rc != expectedResult: + raise AssertionError("""command returned %d; expected %s: \"%s\" +stdout: +%s +stderr: +%s""" % (rc, expectedResult, cmd, output, stderr)) + + return output, stderr + + + def run_captured(self, cmd): + """Run a command, capturing stdout and stderr. + + Based in part on popen2.py + + Returns (waitstatus, stdout, stderr).""" + import os, types + pid = os.fork() + if pid == 0: + # child + try: + pid = os.getpid() + openmode = os.O_WRONLY|os.O_CREAT|os.O_TRUNC + + outfd = os.open('%d.out' % pid, openmode, 0666) + os.dup2(outfd, 1) + os.close(outfd) + + errfd = os.open('%d.err' % pid, openmode, 0666) + os.dup2(errfd, 2) + os.close(errfd) + + if isinstance(cmd, types.StringType): + cmd = ['/bin/sh', '-c', cmd] + + os.execvp(cmd[0], cmd) + finally: + os._exit(127) + else: + # parent + exited_pid, waitstatus = os.waitpid(pid, 0) + stdout = open('%d.out' % pid).read() + stderr = open('%d.err' % pid).read() + return waitstatus, stdout, stderr + + + def runcmd_unchecked(self, cmd, skip_on_noexec = 0): + """Invoke a command; return (exitcode, stdout, stderr)""" + import os + waitstatus, stdout, stderr = self.run_captured(cmd) + assert not os.WIFSIGNALED(waitstatus), \ + ("%s terminated with signal %d" % (`cmd`, os.WTERMSIG(waitstatus))) + rc = os.WEXITSTATUS(waitstatus) + self.test_log = self.test_log + ("""Run command: %s +Wait status: %#x (exit code %d, signal %d) +stdout: +%s +stderr: +%s""" % (cmd, waitstatus, os.WEXITSTATUS(waitstatus), os.WTERMSIG(waitstatus), + stdout, stderr)) + if skip_on_noexec and rc == 127: + # Either we could not execute the command or the command + # returned exit code 127. According to system(3) we can't + # tell the difference. + raise NotRunError, "could not execute %s" % `cmd` + return rc, stdout, stderr + + + def explain_failure(self, exc_info = None): + print "test_log:" + print self.test_log + + + def log(self, msg): + """Log a message to the test log. This message is displayed if + the test fails, or when the runtests function is invoked with + the verbose option.""" + self.test_log = self.test_log + msg + "\n" + + +class NotRunError(Exception): + """Raised if a test must be skipped because of missing resources""" + def __init__(self, value = None): + self.value = value + + +def _report_error(case, debugger): + """Ask the test case to explain failure, and optionally run a debugger + + Input: + case TestCase instance + debugger if true, a debugger function to be applied to the traceback +""" + import sys + ex = sys.exc_info() + print "-----------------------------------------------------------------" + if ex: + import traceback + traceback.print_exc(file=sys.stdout) + case.explain_failure() + print "-----------------------------------------------------------------" + + if debugger: + tb = ex[2] + debugger(tb) + + +def runtests(test_list, verbose = 0, debugger = None): + """Run a series of tests. + + Inputs: + test_list sequence of TestCase classes + verbose print more information as testing proceeds + debugger debugger object to be applied to errors + + Returns: + unix return code: 0 for success, 1 for failures, 2 for test failure + """ + import traceback + ret = 0 + for test_class in test_list: + print "%-30s" % _test_name(test_class), + # flush now so that long running tests are easier to follow + sys.stdout.flush() + + obj = None + try: + try: # run test and show result + obj = test_class() + obj.setup() + obj.runtest() + print "OK" + except KeyboardInterrupt: + print "INTERRUPT" + _report_error(obj, debugger) + ret = 2 + break + except NotRunError, msg: + print "NOTRUN, %s" % msg.value + except: + print "FAIL" + _report_error(obj, debugger) + ret = 1 + finally: + while obj and obj._cleanups: + try: + apply(obj._cleanups.pop()) + except KeyboardInterrupt: + print "interrupted during teardown" + _report_error(obj, debugger) + ret = 2 + break + except: + print "error during teardown" + _report_error(obj, debugger) + ret = 1 + # Display log file if we're verbose + if ret == 0 and verbose: + obj.explain_failure() + + return ret + + +def _test_name(test_class): + """Return a human-readable name for a test class. + """ + try: + return test_class.__name__ + except: + return `test_class` + + +def print_help(): + """Help for people running tests""" + import sys + print """%s: software test suite based on ComfyChair + +usage: + To run all tests, just run this program. To run particular tests, + list them on the command line. + +options: + --help show usage message + --list list available tests + --verbose, -v show more information while running tests + --post-mortem, -p enter Python debugger on error +""" % sys.argv[0] + + +def print_list(test_list): + """Show list of available tests""" + for test_class in test_list: + print " %s" % _test_name(test_class) + + +def main(tests, extra_tests=[]): + """Main entry point for test suites based on ComfyChair. + + inputs: + tests Sequence of TestCase subclasses to be run by default. + extra_tests Sequence of TestCase subclasses that are available but + not run by default. + +Test suites should contain this boilerplate: + + if __name__ == '__main__': + comfychair.main(tests) + +This function handles standard options such as --help and --list, and +by default runs all tests in the suggested order. + +Calls sys.exit() on completion. +""" + from sys import argv + import getopt, sys + + opt_verbose = 0 + debugger = None + + opts, args = getopt.getopt(argv[1:], 'pv', + ['help', 'list', 'verbose', 'post-mortem']) + for opt, opt_arg in opts: + if opt == '--help': + print_help() + return + elif opt == '--list': + print_list(tests + extra_tests) + return + elif opt == '--verbose' or opt == '-v': + opt_verbose = 1 + elif opt == '--post-mortem' or opt == '-p': + import pdb + debugger = pdb.post_mortem + + if args: + all_tests = tests + extra_tests + by_name = {} + for t in all_tests: + by_name[_test_name(t)] = t + which_tests = [] + for name in args: + which_tests.append(by_name[name]) + else: + which_tests = tests + + sys.exit(runtests(which_tests, verbose=opt_verbose, + debugger=debugger)) + + +if __name__ == '__main__': + print __doc__ diff --git a/distcc/test/onetest.py b/distcc/test/onetest.py new file mode 100755 index 0000000..ec743da --- /dev/null +++ b/distcc/test/onetest.py @@ -0,0 +1,37 @@ +#!/usr/bin/python2.4 +# +# Copyright 2007 Google Inc. All Rights Reserved. + +"""Usage: onetest.py [--valgrind[=command]] [--lzo] [--pump] TESTNAME + +This command runs a single test case. +TESTNAME should be the name of one of the test cases from testdistcc.py. +""" + +__author__ = 'fergus@google.com (Fergus Henderson)' + +import testdistcc +import comfychair +import sys + +if __name__ == '__main__': + while len(sys.argv) > 1 and sys.argv[1].startswith("--"): + if sys.argv[1] == "--valgrind": + testdistcc._valgrind_command = "valgrind --quiet " + del sys.argv[1] + elif sys.argv[1].startswith("--valgrind="): + testdistcc._valgrind_command = sys.argv[1][len("--valgrind="):] + " " + del sys.argv[1] + elif sys.argv[1] == "--lzo": + testdistcc._server_options = ",lzo" + del sys.argv[1] + elif sys.argv[1] == "--pump": + testdistcc._server_options = ",lzo,cpp" + del sys.argv[1] + + if len(sys.argv) > 1: + testname = sys.argv[1] + del sys.argv[1] + comfychair.main([eval('testdistcc.' + testname)]) + else: + sys.exit(__doc__) diff --git a/distcc/test/testdistcc.py b/distcc/test/testdistcc.py new file mode 100755 index 0000000..2d12e00 --- /dev/null +++ b/distcc/test/testdistcc.py @@ -0,0 +1,1708 @@ +#! /usr/bin/env python2.2 + +# Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA + +"""distcc test suite, using comfychair + +This script is called with $PATH pointing to the appropriate location +for the built (or installed) programs to be tested. + +Options: + --valgrind[=command] Run the tests under valgrind. + Every program invocation will be prefixed + with the valgrind command, which defaults to + "valgrind --quiet". + --lzo Run the server tests with lzo compression enabled. + --pump Run the server tests with remote preprocessing + enabled. +Example: + PATH="`pwd`:$PATH" + python test/testdistcc.py --valgrind="valgrind --quiet --num-callers=20" +""" + + +# There are pretty strong hierarchies of test cases: ones to do with +# running a daemon, compiling a file and so on. This nicely maps onto +# a hierarchy of object classes. + +# It seems to work best if an instance of the class corresponds to an +# invocation of a test: this means each method runs just once and so +# object state is not very useful, but nevermind. + +# Having a complicated pattens of up and down-calls within the class +# methods seems to make things more complicated. It may be better if +# abstract superclasses just provide methods that can be called, +# rather than establishing default behaviour. + +# TODO: Run the server in a different directory from the clients + +# TODO: Some kind of direct test of the host selection algorithm. + +# TODO: Test host files containing \r. + +# TODO: Test that ccache correctly caches compilations through distcc: +# make up a random file so it won't hit, then compile once and compile +# twice and examine the log file to make sure we got a hit. Also +# check that the binary works properly. + +# TODO: Test cpp from stdin + +# TODO: Do all this with malloc debugging on. + +# TODO: Redirect daemon output to a file so that we can more easily +# check it. Is there a straightforward way to test that it's also OK +# when send through syslogd? + +# TODO: Check behaviour when children are killed off. + +# TODO: Test compiling over IPv6 + +# TODO: Argument scanning tests should be run with various hostspecs, +# because that makes a big difference to how the client handles them. + +# TODO: Test that ccache gets hits when calling distcc. Presumably +# this is skipped if we can't find ccache. Need to parse `ccache -s`. + +# TODO: Set TMPDIR to be inside the working directory, and perhaps +# also set DISTCC_SAVE_TEMPS. Might help for debugging. + +# Check that without DISTCC_SAVE_TEMPS temporary files are cleaned up. + +# TODO: Test compiling a really large source file that produces a +# large object file. Perhaps need to generate it at run time -- just +# one big array? + +# TODO: Perhaps redirect stdout, stderr to a temporary file while +# running? Use os.open(), os.dup2(). + +# TODO: Test "distcc gcc -c foo.c bar.c". gcc would actually compile +# both of them. We could split it into multiple compiler invocations, +# but this is so rare that it's probably not worth the complexity. So +# at the moment is just handled locally. + +# TODO: Test crazy option arguments like "distcc -o -output -c foo.c" + +# TODO: Test attempt to compile a nonexistent file. + +# TODO: Add test harnesses that just exercise the bulk file transfer +# routines. + +# TODO: Test -MD, -MMD, -M, etc. + +# TODO: Test using '.include' in an assembly file, and make sure that +# it is resolved on the client, not on the server. + +# TODO: Run "sleep" as a compiler, then kill the client and make sure +# that the server and "sleep" promptly terminate. + +# TODO: Set umask 0, then check that the files are created with mode +# 0644. + +# TODO: Perhaps have a little compiler that crashes. Check that the +# signal gets properly reported back. + +# TODO: Have a little compiler that takes a very long time to run. +# Try interrupting the connection and see if the compiler is cleaned +# up in a reasonable time. + +# TODO: Try to build a nonexistent source file. Check that we only +# get one error message -- if there were two, we would incorrectly +# have tried to build the program both remotely and locally. + +# TODO: Test compiling a 0-byte source file. This should be allowed. + +# TODO: Test a compiler that produces 0 byte output. I don't know an +# easy way to get that out of gcc aside from the Apple port though. + +# TODO: Test a compiler that sleeps for a long time; try killing the +# server and make sure it goes away. + +# TODO: Set LANG=C before running all tests, to try to make sure that +# localizations don't break attempts to parse error messages. Is +# setting LANG enough, or do we also need LC_*? (Thanks to Oscar +# Esteban.) + +# TODO: Test scheduler. Perhaps run really slow jobs to make things +# deterministic, and test that they're dispatched in a reasonable way. + +# TODO: Test generating dependencies with -MD. Possibly can't be +# done. + +# TODO: Test a nasty cpp that always writes to stdout regardless of +# -o. + +# TODO: Test giving up privilege using --user. Difficult -- we may +# need root privileges to run meaningful tests. + +# TODO: Test that recursion safeguard works. + +# TODO: Test masquerade mode. Requires us to create symlinks in a +# special directory on the path. + +# TODO: Test SSH mode. May need to skip if we can't ssh to this +# machine. Perhaps provide a little null-ssh. + +# TODO: Test path stripping. + +# TODO: Test backoff from downed hosts. + +# TODO: Check again in --no-prefork mode. + +# TODO: Test lzo is parsed properly + +# TODO: Test with DISTCC_DIR set, and not set. + + +import time, sys, string, os, types, re, popen2, pprint, socket +import signal, os.path, string, glob +import comfychair + +from stat import * # this is safe + +EXIT_DISTCC_FAILED = 100 +EXIT_BAD_ARGUMENTS = 101 +EXIT_BIND_FAILED = 102 +EXIT_CONNECT_FAILED = 103 +EXIT_COMPILER_CRASHED = 104 +EXIT_OUT_OF_MEMORY = 105 +EXIT_BAD_HOSTSPEC = 106 +EXIT_COMPILER_MISSING = 110 +EXIT_ACCESS_DENIED = 113 + +_gcc = None # full path to gcc +_valgrind_command = "" # Command to invoke valgrind (or other + # similar debugging tool). + # e.g. "valgrind --quiet --num-callsers=20 " +_server_options = "" # Distcc host options to use for the server. + # Should be "", ",lzo", or ",lzo,cpp". + +class SimpleDistCC_Case(comfychair.TestCase): + '''Abstract base class for distcc tests''' + def setup(self): + self.stripEnvironment() + + def stripEnvironment(self): + """Remove all DISTCC variables from the environment, so that + the test is not affected by the development environment.""" + for key in os.environ.keys(): + if key[:7] == 'DISTCC_': + # NOTE: This only works properly on Python 2.2: on + # earlier versions, it does not call unsetenv() and so + # subprocesses may get confused. + del os.environ[key] + os.environ['TMPDIR'] = self.tmpdir + ddir = os.path.join(self.tmpdir, 'distccdir') + os.mkdir(ddir) + os.environ['DISTCC_DIR'] = ddir + + def valgrind(self): + return _valgrind_command; + + def distcc(self): + return self.valgrind() + "distcc " + + def distccd(self): + return self.valgrind() + "distccd " + + def distcc_with_fallback(self): + return "DISTCC_FALLBACK=1 " + self.distcc() + + def distcc_without_fallback(self): + return "DISTCC_FALLBACK=0 " + self.distcc() + + +class WithDaemon_Case(SimpleDistCC_Case): + """Start the daemon, and then run a command locally against it. + +The daemon doesn't detach until it has bound the network interface, so +as soon as that happens we can go ahead and start the client.""" + + def setup(self): + import random + SimpleDistCC_Case.setup(self) + self.daemon_pidfile = os.path.join(os.getcwd(), "daemonpid.tmp") + self.daemon_logfile = os.path.join(os.getcwd(), "distccd.log") + self.server_port = 42000 # random.randint(42000, 43000) + self.startDaemon() + self.setupEnv() + + def setupEnv(self): + os.environ['DISTCC_HOSTS'] = ('127.0.0.1:%d%s' % + (self.server_port, _server_options)) + os.environ['DISTCC_LOG'] = os.path.join(os.getcwd(), 'distcc.log') + os.environ['DISTCC_VERBOSE'] = '1' + + + def teardown(self): + SimpleDistCC_Case.teardown(self) + + + def killDaemon(self): + import signal, time + + try: + pid = int(open(self.daemon_pidfile, 'rt').read()) + except IOError: + # the daemon probably already exited, perhaps because of a timeout + return + os.kill(pid, signal.SIGTERM) + + # We can't wait on it, because it detached. So just keep + # pinging until it goes away. + while 1: + try: + os.kill(pid, 0) + except OSError: + break + time.sleep(0.2) + + + def daemon_command(self): + """Return command to start the daemon""" + return (self.distccd() + + "--verbose --lifetime=%d --daemon --log-file %s " + "--pid-file %s --port %d --allow 127.0.0.1" + % (self.daemon_lifetime(), + self.daemon_logfile, self.daemon_pidfile, self.server_port)) + + def daemon_lifetime(self): + # Enough for most tests, even on a fairly loaded machine. + # Might need more for long-running tests. + return 60 + + def startDaemon(self): + """Start a daemon in the background, return its pid""" + # The daemon detaches once it has successfully bound the + # socket, so if something goes wrong at startup we ought to + # find out straight away. If it starts successfully, then we + # can go ahead and try to connect. + # We run the daemon in a 'daemon' subdirectory to make + # sure that it has a different directory than the client. + old_tmpdir = os.environ['TMPDIR'] + daemon_tmpdir = old_tmpdir + "/daemon_tmp" + os.mkdir(daemon_tmpdir) + os.environ['TMPDIR'] = daemon_tmpdir + os.mkdir("daemon") + os.chdir("daemon") + try: + while 1: + cmd = self.daemon_command() + result, out, err = self.runcmd_unchecked(cmd) + if result == 0: + break + elif result == EXIT_BIND_FAILED: + self.server_port += 1 + continue + else: + self.fail("failed to start daemon: %d" % result) + self.add_cleanup(self.killDaemon) + finally: + os.environ['TMPDIR'] = old_tmpdir + os.chdir("..") + +class StartStopDaemon_Case(WithDaemon_Case): + def runtest(self): + pass + + +class VersionOption_Case(SimpleDistCC_Case): + """Test that --version returns some kind of version string. + + This is also a good test that the programs were built properly and are + executable.""" + def runtest(self): + import string + for prog in 'distcc', 'distccd': + out, err = self.runcmd("%s --version" % prog) + assert out[-1] == '\n' + out = out[:-1] + line1,line2,trash = string.split(out, '\n', 2) + self.assert_re_match(r'^%s [\w.-]+ [.\w-]+$' + % prog, line1) + self.assert_re_match(r'^[ \t]+\(protocol.*\) \(default port 3632\)$' + , line2) + + +class HelpOption_Case(SimpleDistCC_Case): + """Test --help is reasonable.""" + def runtest(self): + for prog in 'distcc', 'distccd': + out, err = self.runcmd(prog + " --help") + self.assert_re_search("Usage:", out) + + +class BogusOption_Case(SimpleDistCC_Case): + """Test handling of --bogus-option. + + Now that we support implicit compilers, this is passed to gcc, which returns 1.""" + def runtest(self): + self.runcmd(self.distcc() + _gcc + " --bogus-option", 1) + self.runcmd(self.distccd() + _gcc + " --bogus-option", + EXIT_BAD_ARGUMENTS) + + +class GccOptionsPassed_Case(SimpleDistCC_Case): + """Test that options following the compiler name are passed to the compiler.""" + def runtest(self): + out, err = self.runcmd("DISTCC_HOSTS=localhost " + + self.distcc() + + _gcc + " --help") + if re.search('distcc', out): + raise ("gcc help contains \"distcc\": \"%s\"" % out) + self.assert_re_match(r"^Usage: gcc", out) + + +class StripArgs_Case(SimpleDistCC_Case): + """Test -D and -I arguments are removed""" + def runtest(self): + cases = (("gcc -c hello.c", "gcc -c hello.c"), + ("cc -Dhello hello.c -c", "cc hello.c -c"), + ("gcc -g -O2 -W -Wall -Wshadow -Wpointer-arith -Wcast-align -c -o h_strip.o h_strip.c", + "gcc -g -O2 -W -Wall -Wshadow -Wpointer-arith -Wcast-align -c -o h_strip.o h_strip.c"), + # invalid but should work + ("cc -c hello.c -D", "cc -c hello.c"), + ("cc -c hello.c -D -D", "cc -c hello.c"), + ("cc -c hello.c -I ../include", "cc -c hello.c"), + ("cc -c -I ../include hello.c", "cc -c hello.c"), + ("cc -c -I. -I.. -I../include -I/home/mbp/garnome/include -c -o foo.o foo.c", + "cc -c -c -o foo.o foo.c"), + ("cc -c -DDEBUG -DFOO=23 -D BAR -c -o foo.o foo.c", + "cc -c -c -o foo.o foo.c"), + + # New options stripped in 0.11 + ("cc -o nsinstall.o -c -DOSTYPE=\"Linux2.4\" -DOSARCH=\"Linux\" -DOJI -D_BSD_SOURCE -I../dist/include -I../dist/include -I/home/mbp/work/mozilla/mozilla-1.1/dist/include/nspr -I/usr/X11R6/include -fPIC -I/usr/X11R6/include -Wall -W -Wno-unused -Wpointer-arith -Wcast-align -pedantic -Wno-long-long -pthread -pipe -DDEBUG -D_DEBUG -DDEBUG_mbp -DTRACING -g -I/usr/X11R6/include -include ../config-defs.h -DMOZILLA_CLIENT -Wp,-MD,.deps/nsinstall.pp nsinstall.c", + "cc -o nsinstall.o -c -fPIC -Wall -W -Wno-unused -Wpointer-arith -Wcast-align -pedantic -Wno-long-long -pthread -pipe -g nsinstall.c"), + ) + for cmd, expect in cases: + o, err = self.runcmd("h_strip %s" % cmd) + if o[-1] == '\n': o = o[:-1] + self.assert_equal(o, expect) + + +class IsSource_Case(SimpleDistCC_Case): + def runtest(self): + """Test distcc's method for working out whether a file is source""" + cases = (( "hello.c", "source", "not-preprocessed" ), + ( "hello.cc", "source", "not-preprocessed" ), + ( "hello.cxx", "source", "not-preprocessed" ), + ( "hello.cpp", "source", "not-preprocessed" ), + ( "hello.c++", "source", "not-preprocessed" ), + # ".m" is Objective-C; ".M" and ".mm" are Objective-C++ + ( "hello.m", "source", "not-preprocessed" ), + ( "hello.M", "source", "not-preprocessed" ), + ( "hello.mm", "source", "not-preprocessed" ), + # ".mi" and ".mii" are preprocessed Objective-C/Objective-C++. + ( "hello.mi", "source", "preprocessed" ), + ( "hello.mii", "source", "preprocessed" ), + ( "hello.2.4.4.i", "source", "preprocessed" ), + ( ".foo", "not-source", "not-preprocessed" ), + ( "gcc", "not-source", "not-preprocessed" ), + ( "hello.ii", "source", "preprocessed" ), + ( "boot.s", "not-source", "not-preprocessed" ), + ( "boot.S", "not-source", "not-preprocessed" )) + for f, issrc, iscpp in cases: + o, err = self.runcmd("h_issource '%s'" % f) + expected = ("%s %s\n" % (issrc, iscpp)) + if o != expected: + raise AssertionError("issource %s gave %s, expected %s" % + (f, `o`, `expected`)) + + + +class ScanArgs_Case(SimpleDistCC_Case): + '''Test understanding of gcc command lines.''' + def runtest(self): + cases = [("gcc -c hello.c", "distribute", "hello.c", "hello.o"), + ("gcc hello.c", "local"), + ("gcc -o /tmp/hello.o -c ../src/hello.c", "distribute", "../src/hello.c", "/tmp/hello.o"), + ("gcc -DMYNAME=quasibar.c bar.c -c -o bar.o", "distribute", "bar.c", "bar.o"), + ("gcc -ohello.o -c hello.c", "distribute", "hello.c", "hello.o"), + ("ccache gcc -c hello.c", "distribute", "hello.c", "hello.o"), + ("gcc hello.o", "local"), + ("gcc -o hello.o hello.c", "local"), + ("gcc -o hello.o -c hello.s", "local"), + ("gcc -o hello.o -c hello.S", "local"), + ("gcc -fprofile-arcs -ftest-coverage -c hello.c", "local", "hello.c", "hello.o"), + ("gcc -S hello.c", "distribute", "hello.c", "hello.s"), + ("gcc -c -S hello.c", "distribute", "hello.c", "hello.s"), + ("gcc -S -c hello.c", "distribute", "hello.c", "hello.s"), + ("gcc -M hello.c", "local"), + ("gcc -ME hello.c", "local"), + + ("gcc -MD -c hello.c", "distribute", "hello.c", "hello.o"), + ("gcc -MMD -c hello.c", "distribute", "hello.c", "hello.o"), + + # Assemble to stdout (thanks Alexandre). + ("gcc -S foo.c -o -", "local"), + ("-S -o - foo.c", "local"), + ("-c -S -o - foo.c", "local"), + ("-S -c -o - foo.c", "local"), + + # dasho syntax + ("gcc -ofoo.o foo.c -c", "distribute", "foo.c", "foo.o"), + ("gcc -ofoo foo.o", "local"), + + # tricky this one -- no dashc + ("foo.c -o foo.o", "local"), + ("foo.c -o foo.o -c", "distribute", "foo.c", "foo.o"), + + # Produce assembly listings + ("gcc -Wa,-alh,-a=foo.lst -c foo.c", "local"), + ("gcc -Wa,--MD -c foo.c", "local"), + ("gcc -Wa,-xarch=v8 -c foo.c", "distribute", "foo.c", "foo.o"), + + # Produce .rpo files + ("g++ -frepo foo.C", "local"), + + ("gcc -xassembler-with-cpp -c foo.c", "local"), + ("gcc -x assembler-with-cpp -c foo.c", "local"), + + ("gcc -specs=foo.specs -c foo.c", "local"), + ] + for tup in cases: + apply(self.checkScanArgs, tup) + + def checkScanArgs(self, ccmd, mode, input=None, output=None): + o, err = self.runcmd("h_scanargs %s" % ccmd) + o = o[:-1] # trim \n + os = string.split(o) + if mode != os[0]: + self.fail("h_scanargs %s gave %s mode, expected %s" % + (ccmd, os[0], mode)) + if mode == 'distribute': + if os[1] <> input: + self.fail("h_scanargs %s gave %s input, expected %s" % + (ccmd, os[1], input)) + if os[2] <> output: + self.fail("h_scanargs %s gave %s output, expected %s" % + (ccmd, os[2], output)) + + +class DotD_Case(SimpleDistCC_Case): + '''Test the mechanism for calculating .d file names''' + + def runtest(self): + # Each case specifies: + # + # - A compilation command. + # + # - A glob expression supposed to match exactly one file, the dependency + # file (which is not always a .d file, btw). The glob expression is + # our human intuition, based on our reading of the gcc manual pages, + # of the range of possible dependency names actually produced. + # + # - Whether 0 or 1 such dependency files exist. + # + # - The expected target name (or None). + # + + # The dotd_name is thus divined by examination of the compilation + # directory where we actually run gcc. + + cases = [ + ("foo.c -o hello.o -MD", "*.d", 1, None), + ("foo.c -o hello.. -MD", "*.d", 1, None), + ("foo.c -o hello.bar.foo -MD", "*.d", 1, None), + ("foo.c -o hello.o", "*.d", 0, None), + ("foo.cpp -o hello.o", "*.d", 0, None), + ("foo.cpp -o hello", "*.d", 0, None), + ("foo.c -o hello.bar.foo -MD", "*.d", 1, None), + ("foo.c -MD", "*.d", 1, None), + ("foo.c -o hello. -MD", "*.d", 1, None), + ("foo.c -o hello.D -MD -MT tootoo", "hello.*d", 1, "tootoo"), + ("foo.c -o hello. -MD -MT tootoo", "hello.*d", 1, "tootoo"), + ("foo.c -o hello.o -MD -MT tootoo", "hello.*d", 1, "tootoo"), + ] + + def _eval(out): + map_out = eval(out) + return (map_out['dotd_fname'], + map_out['needs_dotd'], + map_out['sets_dotd_target'], + map_out['dotd_target']) + + for (args, dep_glob, how_many, target) in cases: + + # Determine what gcc says. + dotd_result = [] # prepare for some imperative style value passing + class TempCompile_Case(Compilation_Case): + def source(self): + return """ +int main(char **argv) {}; +""" + def sourceFilename(self): + return args.split()[0] + def compileCmd(self): + return _gcc + " " + args + def runtest(self): + self.compile() + glob_result = glob.glob(dep_glob) + dotd_result.extend(glob_result) + + comfychair.runtests([TempCompile_Case]) + + self.assert_equal(len(dotd_result), how_many) + if how_many == 1: + expected_dep_file = dotd_result[0] + + # Determine what dcc_get_dotd_info says. + out, _err = self.runcmd("h_dotd dcc_get_dotd_info gcc -c %s" % args) + dotd_fname, needs_dotd, sets_dotd_target, dotd_target = _eval(out) + assert dotd_fname + assert needs_dotd in [0,1] + # Assert that "needs_dotd == 1" if and only if "how_many == 1". + assert needs_dotd == how_many + # Assert that "needs_dotd == 1" implies names by gcc and our routine + # are the same. + if needs_dotd: + self.assert_equal(expected_dep_file, dotd_fname) + + self.assert_equal(sets_dotd_target == 1, target != None) + if target: + # A little convoluted: because target is set in command line, + # and the command line is passed already, the dotd_target is not + # set. + self.assert_equal(dotd_target, "None") + + + # Now some fun with DEPENDENCIES_OUTPUT variable. + try: + os.environ["DEPENDENCIES_OUTPUT"] = "xxx.d yyy" + out, _err = self.runcmd("h_dotd dcc_get_dotd_info gcc -c foo.c") + dotd_fname, needs_dotd, sets_dotd_target, dotd_target = _eval(out) + assert dotd_fname == "xxx.d" + assert needs_dotd + assert not sets_dotd_target + assert dotd_target == "yyy" + + os.environ["DEPENDENCIES_OUTPUT"] = "zzz.d" + out, _err = self.runcmd("h_dotd dcc_get_dotd_info gcc -c foo.c") + dotd_fname, needs_dotd, sets_dotd_target, dotd_target = _eval(out) + assert dotd_fname == "zzz.d" + assert needs_dotd + assert not sets_dotd_target + assert dotd_target == "None" + + finally: + del os.environ["DEPENDENCIES_OUTPUT"] + + +class Compile_c_Case(SimpleDistCC_Case): + """Unit tests for source file 'compile.c.' + + Currently, only the functions dcc_fresh_dependency_exists() and + ddc_discrepancy_filename() are tested. + """ + + def getDep(self, line): + """Parse line to yield dependency name. From say: + "src/h_compile.c[21010] (dcc_fresh_dependency_exists) Checking dependency: bar_bar" + return "bar_bar". + """ + m_obj = re.search(r"Checking dependency: ((\w|[.])*)", line) + assert m_obj + return m_obj.group(1) + + def makeFile(self, f): + fd = open(f, "w") + fd.close() + + def makeFiles(self, files): + for f in files: + self.makeFile(f) + + def runtest(self): + + # Test dcc_discrepancy_filename + # ******************************** + os.environ['INCLUDE_SERVER_PORT'] = "abc/socket" + out, err = self.runcmd( + "h_compile ddc_discrepancy_filename") + self.assert_equal(out, "abc/discrepancy_counter") + + os.environ['INCLUDE_SERVER_PORT'] = "socket" + out, err = self.runcmd( + "h_compile ddc_discrepancy_filename") + self.assert_equal(out, "(NULL)") + + # os.environ will be cleaned out at start of next test. + + # Test dcc_fresh_dependency_exists + # ******************************** + dotd_cases = [(""" +foo.o: foo\ +bar.h bar.h notthisone.h bar.h\ +""", + ["foobar.h", "bar.h"]), + ( + """foo_foo :\ +bar_bar \ +foo_bar""", + ["bar_bar", "foo_bar"]), + (":", []), + ("\n", []), + ("", []), + ("foo.o:", []), + ] + + for dotd_contents, deps in dotd_cases: + self.makeFiles(deps) + # Now postulate the time that is the beginning of build. This time + # is after that of all the dependencies. + time_ref = time.time() + 1 + # Let real-time advance to time_ref. + while time.time() < time_ref: + time.sleep(1) + # Create .d file now, so that it appears to be no older than + # time_ref. + dotd_fd = open("dotd", "w") + dotd_fd.write(dotd_contents) + dotd_fd.close() + # Check: no fresh files here! + out, err = self.runcmd( + "h_compile dcc_fresh_dependency_exists dotd '%s' %i" % + ("*notthis*", time_ref)) + self.assert_equal(out.split()[1], "(NULL)"); + checked_deps = set([]) + for line in err.split("\n"): + if re.search("[^ ]", line): + # Line is non-blank + checked_deps.add(self.getDep(line)) + self.assert_equal(checked_deps, set(deps)) + + # Let's try to touch, say the last dep file. Then, we should expect + # the name of that very file as the output because there's a fresh + # file. We'll have to advance real time beyond time_ref before doing + # this. + while time.time() <= time_ref: + time.sleep(1) + if deps: + self.makeFile(deps[-1]) + out, err = self.runcmd( + "h_compile dcc_fresh_dependency_exists dotd '' %i" % + time_ref) + self.assert_equal(out.split()[1], deps[-1]) + + +class ImplicitCompilerScan_Case(ScanArgs_Case): + '''Test understanding of commands with no compiler''' + def runtest(self): + cases = [("-c hello.c", "distribute", "hello.c", "hello.o"), + ("hello.c -c", "distribute", "hello.c", "hello.o"), + ("-o hello.o -c hello.c", "distribute", "hello.c", "hello.o"), + ] + for tup in cases: + # NB use "apply" rather than new syntax for compatibility with + # venerable Pythons. + apply(self.checkScanArgs, tup) + + +class ExtractExtension_Case(SimpleDistCC_Case): + def runtest(self): + """Test extracting extensions from filenames""" + for f, e in (("hello.c", ".c"), + ("hello.cpp", ".cpp"), + ("hello.2.4.4.4.c", ".c"), + (".foo", ".foo"), + ("gcc", "(NULL)")): + out, err = self.runcmd("h_exten '%s'" % f) + assert out == e + + +class DaemonBadPort_Case(SimpleDistCC_Case): + def runtest(self): + """Test daemon invoked with invalid port number""" + self.runcmd(self.distccd() + + "--log-file=distccd.log --lifetime=10 --port 80000", + EXIT_BAD_ARGUMENTS) + self.assert_no_file("daemonpid.tmp") + + +class InvalidHostSpec_Case(SimpleDistCC_Case): + def runtest(self): + """Test various invalid DISTCC_HOSTS + + See also test_parse_host_spec, which tests valid specifications.""" + for spec in ["", " ", "\t", " @ ", ":", "mbp@", "angry::", ":4200"]: + self.runcmd(("DISTCC_HOSTS=\"%s\" " % spec) + self.valgrind() + + "h_hosts -v", + EXIT_BAD_HOSTSPEC) + + +class ParseHostSpec_Case(SimpleDistCC_Case): + def runtest(self): + """Check operation of dcc_parse_hosts_env. + + Passes complex environment variables to h_hosts, which is a C wrapper + that calls the appropriate tests.""" + spec="""localhost 127.0.0.1 @angry ted@angry + \t@angry:/home/mbp/bin/distccd angry:4204 + ipv4-localhost + angry/44 + angry:300/44 + angry/44:300 + angry,lzo + angry:3000,lzo # some comment + angry/44,lzo + @angry,lzo#asdasd + # oh yeah nothing here + @angry:/usr/sbin/distccd,lzo + localhostbutnotreally + """ + + expected="""16 + 2 LOCAL + 4 TCP 127.0.0.1 3632 + 4 SSH (no-user) angry (no-command) + 4 SSH ted angry (no-command) + 4 SSH (no-user) angry /home/mbp/bin/distccd + 4 TCP angry 4204 + 4 TCP ipv4-localhost 3632 + 44 TCP angry 3632 + 44 TCP angry 300 + 44 TCP angry 300 + 4 TCP angry 3632 + 4 TCP angry 3000 + 44 TCP angry 3632 + 4 SSH (no-user) angry (no-command) + 4 SSH (no-user) angry /usr/sbin/distccd + 4 TCP localhostbutnotreally 3632 +""" + out, err = self.runcmd(("DISTCC_HOSTS=\"%s\" " % spec) + self.valgrind() + + "h_hosts") + assert out == expected, "expected %s\ngot %s" % (`expected`, `out`) + + +class Compilation_Case(WithDaemon_Case): + '''Test distcc by actually compiling a file''' + def setup(self): + WithDaemon_Case.setup(self) + self.createSource() + + def runtest(self): + self.compile() + self.link() + self.checkBuiltProgram() + + def createSource(self): + filename = self.sourceFilename() + f = open(filename, 'w') + f.write(self.source()) + f.close() + filename = self.headerFilename() + f = open(filename, 'w') + f.write(self.headerSource()) + f.close() + + def sourceFilename(self): + return "testtmp.c" # default + + def headerFilename(self): + return "testhdr.h" # default + + def headerSource(self): + return "" # default + + def compile(self): + cmd = self.compileCmd() + out, err = self.runcmd(cmd) + if out != '': + self.fail("compiler command %s produced output:\n%s" % (`cmd`, out)) + if err != '': + self.fail("compiler command %s produced error:\n%s" % (`cmd`, err)) + + def link(self): + cmd = self.linkCmd() + out, err = self.runcmd(cmd) + if out != '': + self.fail("command %s produced output:\n%s" % (`cmd`, `out`)) + if err != '': + self.fail("command %s produced error:\n%s" % (`cmd`, `err`)) + + def compileCmd(self): + """Return command to compile source and run tests""" + return self.distcc_without_fallback() + \ + _gcc + " -o testtmp.o -c %s" % (self.sourceFilename()) + + def linkCmd(self): + return self.distcc() + \ + _gcc + " -o testtmp testtmp.o" + + def checkCompileMsgs(self, msgs): + if msgs <> '': + self.fail("expected no compiler messages, got \"%s\"" + % msgs) + + def checkBuiltProgram(self): + '''Check compile results. By default, just try to execute.''' + msgs, errs = self.runcmd("./testtmp") + self.checkBuiltProgramMsgs(msgs) + self.assert_equal(errs, '') + + def checkBuiltProgramMsgs(self, msgs): + pass + + +class CompileHello_Case(Compilation_Case): + """Test the simple case of building a program that works properly""" + + def headerSource(self): + return """ +#define HELLO_WORLD "hello world" +""" + + def source(self): + return """ +#include <stdio.h> +#include "testhdr.h" +int main(void) { + puts(HELLO_WORLD); + return 0; +} +""" + + def checkBuiltProgramMsgs(self, msgs): + self.assert_equal(msgs, "hello world\n") + + +class ObjectiveC_Case(Compilation_Case): + """Test building an Objective-C program.""" + + def sourceFilename(self): + return "testtmp.m" + + def headerSource(self): + return """ +#define HELLO_WORLD "hello world" +""" + + def source(self): + return """ +#import <stdio.h> +#import "testhdr.h" + +int main(void) { + puts(HELLO_WORLD); + return 0; +} +""" + +class ObjectiveCPlusPlus_Case(Compilation_Case): + """Test building an Objective-C++ program.""" + + def sourceFilename(self): + return "testtmp.mm" + + def headerSource(self): + return """ +#define HELLO_WORLD "hello world" +""" + + def source(self): + return """ +#import <iostream> +#import "testhdr.h" + +int main(void) { + std::cout << HELLO_WORLD << endl; + return 0; +} +""" + + def checkBuiltProgramMsgs(self, msgs): + self.assert_equal(msgs, "hello world\n") + + +class Gdb_Case(CompileHello_Case): + """Test that distcc generates correct debugging information.""" + + def sourceFilename(self): + try: + os.mkdir("src") + except: + pass + return "src/testtmp.c" + + def compiler(self): + """Command for compiling and linking.""" + return _gcc + " -g "; + + def compileCmd(self): + """Return command to compile source and run tests""" + os.mkdir("obj") + return self.distcc_without_fallback() + self.compiler() + \ + " -o obj/testtmp.o -I. -c %s" % (self.sourceFilename()) + + def link(self): + """ + We do the linking in a subdirectory, so that the 'compilation + directory' field of the debug info set by the link step (which + will be done locally, not remotely) does NOT influence the + behaviour of gdb. We want gdb to use the 'compilation directory' + value set by the compilation. + """ + os.mkdir('link') + cmd = self.distcc() + self.compiler() + " -o link/testtmp obj/testtmp.o" + out, err = self.runcmd(cmd) + if out != '': + self.fail("command %s produced output:\n%s" % (`cmd`, `out`)) + if err != '': + self.fail("command %s produced error:\n%s" % (`cmd`, `err`)) + + def checkBuiltProgram(self): + # Run gdb and verify that it is able to correctly locate the + # testtmp.c source file. + out, errs = self.runcmd("gdb --batch " + + "-ex 'break main' -ex 'run' -ex 'step' link/testtmp </dev/null") + self.assert_equal(errs, '') + self.assert_re_search('puts\\(HELLO_WORLD\\);', out) + self.assert_re_search('testtmp.c:5', out) + + # Now do the same, but in a subdirectory. + # This tests that the "compilation directory" field + # of the object file is set correctly. + os.mkdir('run') + os.chdir('run') + self.runcmd("cp ../link/testtmp ./testtmp") + msgs, errs = self.runcmd("gdb --batch " + + "-ex 'break main' -ex 'run' -ex 'step' ./testtmp </dev/null") + self.assert_equal(errs, '') + self.assert_re_search('puts\\(HELLO_WORLD\\);', out) + self.assert_re_search('testtmp.c:5', out) + os.chdir('..') + + # Now recompile and relink the executable using ordinary + # gcc rather than distcc; strip both executables; + # and check that the executable generated with ordinary + # gcc is bit-for-bit identical to the executable that was + # generated by distcc. This is just to double-check + # that we didn't modify anything other than the ".debug_info" + # section. + self.runcmd(self.compiler() + " -o obj/testtmp.o -I. -c %s" % + self.sourceFilename()) + self.runcmd(self.compiler() + " -o link/testtmp obj/testtmp.o") + self.runcmd("strip link/testtmp && strip run/testtmp") + self.runcmd("cmp link/testtmp run/testtmp") + +class GdbOpt1_Case(Gdb_Case): + def compiler(self): + """Command for compiling and linking.""" + return _gcc + " -g -O1 "; + +class GdbOpt2_Case(Gdb_Case): + def compiler(self): + """Command for compiling and linking.""" + return _gcc + " -g -O2 "; + +class GdbOpt3_Case(Gdb_Case): + def compiler(self): + """Command for compiling and linking.""" + return _gcc + " -g -O3 "; + +class CompressedCompile_Case(CompileHello_Case): + """Test compilation with compression. + + The source needs to be moderately large to make sure compression and mmap + is turned on.""" + + def source(self): + return """ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "testhdr.h" +int main(void) { + printf("%s\\n", HELLO_WORLD); + return 0; +} +""" + + def setupEnv(self): + Compilation_Case.setupEnv(self) + os.environ['DISTCC_HOSTS'] = '127.0.0.1:%d,lzo' % self.server_port + +class DashONoSpace_Case(CompileHello_Case): + def compileCmd(self): + return self.distcc_without_fallback() + \ + _gcc + " -otesttmp.o -c %s" % (self.sourceFilename()) + + def runtest(self): + if sys.platform == 'sunos5': + raise comfychair.NotRunError ('Sun assembler wants space after -o') + elif sys.platform.startswith ('osf1'): + raise comfychair.NotRunError ('GCC mips-tfile wants space after -o') + else: + CompileHello_Case.runtest (self) + +class WriteDevNull_Case(CompileHello_Case): + def runtest(self): + self.compile() + + def compileCmd(self): + return self.distcc_without_fallback() + _gcc + \ + " -c -o /dev/null -c %s" % (self.sourceFilename()) + + +class MultipleCompile_Case(Compilation_Case): + """Test compiling several files from one line""" + def setup(self): + WithDaemon_Case.setup(self) + open("test1.c", "w").write("const char *msg = \"hello foreigner\";") + open("test2.c", "w").write("""#include <stdio.h> + +int main(void) { + extern const char *msg; + puts(msg); + return 0; +} +""") + + def runtest(self): + self.runcmd(self.distcc() + + _gcc + " -c test1.c test2.c") + self.runcmd(self.distcc() + + _gcc + " -o test test1.o test2.o") + + + +class CppError_Case(CompileHello_Case): + """Test failure of cpp""" + def source(self): + return '#error "not tonight dear"\n' + + def runtest(self): + cmd = self.distcc() + _gcc + " -c testtmp.c" + msgs, errs = self.runcmd(cmd, expectedResult=1) + self.assert_re_search("not tonight dear", errs) + self.assert_equal(msgs, '') + + +class BadInclude_Case(Compilation_Case): + """Handling of error running cpp""" + def source(self): + return """#include <nosuchfilehere.h> +""" + + def runtest(self): + self.runcmd(self.distcc() + + _gcc + " -o testtmp.o -c testtmp.c", 1) + + +class PreprocessPlainText_Case(Compilation_Case): + """Try using cpp on something that's not C at all""" + def setup(self): + self.stripEnvironment() + self.createSource() + + def source(self): + return """#define FOO 3 +#if FOO < 10 +small foo! +#else +large foo! +#endif +/* comment ca? */ +""" + + def runtest(self): + # -P means not to emit linemarkers + self.runcmd(self.distcc() + + _gcc + " -E testtmp.c -o testtmp.out") + out = open("testtmp.out").read() + # It's a bit hard to know the exact value, because different versions of + # GNU cpp seem to handle the whitespace differently. + self.assert_re_search("small foo!", out) + + def teardown(self): + # no daemon is run for this test + pass + + +class NoDetachDaemon_Case(CompileHello_Case): + """Test the --no-detach option.""" + def startDaemon(self): + # FIXME: This does not work well if it happens to get the same + # port as an existing server, because we can't catch the error. + cmd = (self.distccd() + + "--no-detach --daemon --verbose --log-file %s --pid-file %s " + "--port %d --allow 127.0.0.1" % + (self.daemon_logfile, self.daemon_pidfile, self.server_port)) + self.pid = self.runcmd_background(cmd) + self.add_cleanup(self.killDaemon) + # Wait until the server is ready for connections. + sock = socket.socket() + while sock.connect_ex(('127.0.0.1', self.server_port)) != 0: + time.sleep(0.2) + + def killDaemon(self): + import signal + os.kill(self.pid, signal.SIGTERM) + pid, ret = os.wait() + self.assert_equal(self.pid, pid) + + +class ImplicitCompiler_Case(CompileHello_Case): + """Test giving no compiler works""" + def compileCmd(self): + return self.distcc() + "-c testtmp.c" + + def linkCmd(self): + # FIXME: Mozilla uses something like "distcc testtmp.o -o testtmp", + # but that's broken at the moment. + return self.distcc() + "-o testtmp testtmp.o " + + def runtest(self): + if sys.platform != 'hp-ux10': + CompileHello_Case.runtest (self) + else: + raise comfychair.NotRunError ('HP-UX bundled C compiler non-ANSI') + + +class DashD_Case(Compilation_Case): + """Test preprocessor arguments""" + def source(self): + return """ +#include <stdio.h> + +int main(void) { + printf("%s\\n", MESSAGE); + return 0; +} +""" + + def compileCmd(self): + # quoting is hairy because this goes through the shell + return self.distcc() + _gcc + \ + " -c -o testtmp.o '-DMESSAGE=\"hello world\"' testtmp.c" + + def checkBuiltProgramMsgs(self, msgs): + self.assert_equal(msgs, "hello world\n") + + +class AbsSourceFilename_Case(CompileHello_Case): + """Test remote compilation of files with absolute names.""" + + def compileCmd(self): + return (self.distcc() + + _gcc + + " -c -o testtmp.o %s/testtmp.c" + % os.getcwd()) + + +class ThousandFold_Case(CompileHello_Case): + """Try repeated simple compilations""" + def daemon_lifetime(self): + return 120 + + def runtest(self): + # may take about a minute or so + for i in xrange(1000): + self.runcmd(self.distcc() + + _gcc + " -o testtmp.o -c testtmp.c") + + +class Concurrent_Case(CompileHello_Case): + """Try many compilations at the same time""" + def daemon_lifetime(self): + return 120 + + def runtest(self): + # may take about a minute or so + pids = {} + for i in xrange(50): + kid = self.runcmd_background(self.distcc() + + _gcc + " -o testtmp.o -c testtmp.c") + pids[kid] = kid + while len(pids): + pid, status = os.wait() + if status: + self.fail("child %d failed with status %#x" % (pid, status)) + del pids[pid] + + +class BigAssFile_Case(Compilation_Case): + """Test compilation of a really big C file + + This will take a while to run""" + def createSource(self): + """Create source file""" + f = open("testtmp.c", 'wt') + + # We want a file of many, which will be a few megabytes of + # source. Picking the size is kind of hard -- something that + # will properly exercise distcc may be too big for small/old + # machines. + + f.write("int main() {}\n") + for i in xrange(200000): + f.write("int i%06d = %d;\n" % (i, i)) + f.close() + + def runtest(self): + self.runcmd(self.distcc() + _gcc + " -c %s" % "testtmp.c") + self.runcmd(self.distcc() + _gcc + " -o testtmp testtmp.o") + + + def daemon_lifetime(self): + return 300 + + + +class BinFalse_Case(Compilation_Case): + """Compiler that fails without reading input. + + This is an interesting case when the server is using fifos, + because it has to cope with the open() on the fifo being + interrupted. + + distcc doesn't know that 'false' is not a compiler, but it does + need a command line that looks like a compiler invocation. + + We have to use a .i file so that distcc does not try to preprocess it. + """ + def createSource(self): + open("testtmp.i", "wt").write("int main() {}") + + def runtest(self): + # On Solaris and IRIX 6, 'false' returns exit status 255 + if sys.platform == 'sunos5' or \ + sys.platform.startswith ('irix6'): + self.runcmd(self.distcc() + + "false -c testtmp.i", 255) + else: + self.runcmd(self.distcc() + + "false -c testtmp.i", 1) + + +class BinTrue_Case(Compilation_Case): + """Compiler that succeeds without reading input. + + This is an interesting case when the server is using fifos, + because it has to cope with the open() on the fifo being + interrupted. + + distcc doesn't know that 'true' is not a compiler, but it does + need a command line that looks like a compiler invocation. + + We have to use a .i file so that distcc does not try to preprocess it. + """ + def createSource(self): + open("testtmp.i", "wt").write("int main() {}") + + def runtest(self): + self.runcmd(self.distcc() + + "true -c testtmp.i", 0) + + +class SBeatsC_Case(CompileHello_Case): + """-S overrides -c in gcc. + + If both options are given, we have to make sure we imply the + output filename in the same way as gcc.""" + # XXX: Are other compilers the same? + def runtest(self): + self.runcmd(self.distcc() + + _gcc + " -c -S testtmp.c") + if os.path.exists("testtmp.o"): + self.fail("created testtmp.o but should not have") + if not os.path.exists("testtmp.s"): + self.fail("did not create testtmp.s but should have") + + +class NoServer_Case(CompileHello_Case): + """Invalid server name""" + def setup(self): + self.stripEnvironment() + os.environ['DISTCC_HOSTS'] = 'no.such.host.here' + self.distcc_log = 'distcc.log' + os.environ['DISTCC_LOG'] = self.distcc_log + self.createSource() + + def runtest(self): + self.runcmd(self.distcc() + + _gcc + " -c -o testtmp.o testtmp.c") + msgs = open(self.distcc_log, 'r').read() + self.assert_re_search(r'failed to distribute.*running locally instead', + msgs) + + +class ImpliedOutput_Case(CompileHello_Case): + """Test handling absence of -o""" + def compileCmd(self): + return self.distcc() + _gcc + " -c testtmp.c" + + +class SyntaxError_Case(Compilation_Case): + """Test building a program containing syntax errors, so it won't build + properly.""" + def source(self): + return """not C source at all +""" + + def compile(self): + rc, msgs, errs = self.runcmd_unchecked(self.compileCmd()) + self.assert_notequal(rc, 0) + # XXX: Need to also handle "syntax error" from gcc-2.95.3 + self.assert_re_match(r'testtmp.c:1: .*error', errs) + self.assert_equal(msgs, '') + + def runtest(self): + self.compile() + + if os.path.exists("testtmp") or os.path.exists("testtmp.o"): + self.fail("compiler produced output, but should not have done so") + + +class NoHosts_Case(CompileHello_Case): + """Test running with no hosts defined. + + We expect compilation to succeed, but with a warning that it was + run locally.""" + def runtest(self): + import os + + # WithDaemon_Case sets this to point to the local host, but we + # don't want that. Note that you cannot delete environment + # keys in Python1.5, so we need to just set them to the empty + # string. + os.environ['DISTCC_HOSTS'] = '' + os.environ['DISTCC_LOG'] = '' + self.runcmd('printenv') + msgs, errs = self.runcmd(self.compileCmd()) + + # We expect only one message, a warning from distcc + self.assert_re_search(r"Warning.*\$DISTCC_HOSTS.*can't distribute work", + errs) + + def compileCmd(self): + """Return command to compile source and run tests""" + return self.distcc_with_fallback() + \ + _gcc + " -o testtmp.o -c %s" % (self.sourceFilename()) + + + +class MissingCompiler_Case(CompileHello_Case): + """Test compiler missing from server.""" + # Another way to test this would be to break the server's PATH + def sourceFilename(self): + # must be preprocessed, so that we don't need to run the compiler + # on the client + return "testtmp.i" + + def source(self): + return """int foo;""" + + def runtest(self): + msgs, errs = self.runcmd(self.distcc_without_fallback() + + "nosuchcc -c testtmp.i", + expectedResult=EXIT_COMPILER_MISSING) + self.assert_re_search(r'failed to exec', errs) + + + +class RemoteAssemble_Case(WithDaemon_Case): + """Test remote assembly of a .s file.""" + + # We have a rather tricky method for testing assembly code when we + # don't know what platform we're on. I think this one will work + # everywhere, though perhaps not. + asm_source = """ + .file "foo.c" +.globl msg +.section .rodata +.LC0: + .string "hello world" +.data + .align 4 + .type msg,@object + .size msg,4 +msg: + .long .LC0 +""" + + asm_filename = 'test2.s' + + def setup(self): + WithDaemon_Case.setup(self) + open(self.asm_filename, 'wt').write(self.asm_source) + + def compile(self): + # Need to build both the C file and the assembly file + self.runcmd(self.distcc() + _gcc + " -o test2.o -c test2.s") + + + +class PreprocessAsm_Case(WithDaemon_Case): + """Run preprocessor locally on assembly, then compile locally.""" + asm_source = """ +#define MSG "hello world" +gcc2_compiled.: +.globl msg +.section .rodata +.LC0: + .string MSG +.data + .align 4 + .type msg,@object + .size msg,4 +msg: + .long .LC0 +""" + + def setup(self): + WithDaemon_Case.setup(self) + open('test2.S', 'wt').write(self.asm_source) + + def compile(self): + if sys.platform == 'linux2': + self.runcmd(self.distcc() + + "-o test2.o -c test2.S") + + def runtest(self): + self.compile() + + + + +class ModeBits_Case(CompileHello_Case): + """Check distcc obeys umask""" + def runtest(self): + self.runcmd("umask 0; distcc " + _gcc + " -c testtmp.c") + self.assert_equal(S_IMODE(os.stat("testtmp.o")[ST_MODE]), 0666) + + +class CheckRoot_Case(SimpleDistCC_Case): + """Stub case that checks this is run by root. Not used by default.""" + def setup(self): + self.require_root() + + +class EmptySource_Case(Compilation_Case): + """Check compilation of empty source file + + It must be treated as preprocessed source, otherwise cpp will + insert a # line, which will give a false pass. """ + + def source(self): + return '' + + def runtest(self): + self.compile() + + def compile(self): + self.runcmd(self.distcc() + + _gcc + " -c %s" % self.sourceFilename()) + + def sourceFilename(self): + return "testtmp.i" + +class BadLogFile_Case(SimpleDistCC_Case): + def runtest(self): + self.runcmd("touch distcc.log") + self.runcmd("chmod 0 distcc.log") + msgs, errs = self.runcmd("DISTCC_LOG=distcc.log " + \ + self.distcc() + \ + _gcc + " -c foo.c", expectedResult=1) + self.assert_re_search("failed to open logfile", errs) + + +class AccessDenied_Case(CompileHello_Case): + """Run the daemon, but don't allow access from this host. + + Make sure that compilation falls back to localhost with a warning.""" + def daemon_command(self): + return (self.distccd() + + "--verbose --lifetime=%d --daemon --log-file %s " + "--pid-file %s --port %d --allow 127.0.0.2" + % (self.daemon_lifetime(), + self.daemon_logfile, self.daemon_pidfile, self.server_port)) + + def compileCmd(self): + """Return command to compile source and run tests""" + return self.distcc_with_fallback() + \ + _gcc + " -o testtmp.o -c %s" % (self.sourceFilename()) + + + def runtest(self): + self.compile() + errs = open('distcc.log').read() + self.assert_re_search(r'failed to distribute', errs) + + +class ParseMask_Case(comfychair.TestCase): + """Test code for matching IP masks.""" + values = [ + ('127.0.0.1', '127.0.0.1', 0), + ('127.0.0.1', '127.0.0.0', EXIT_ACCESS_DENIED), + ('127.0.0.1', '127.0.0.2', EXIT_ACCESS_DENIED), + ('127.0.0.1/8', '127.0.0.2', 0), + ('10.113.0.0/16', '10.113.45.67', 0), + ('10.113.0.0/16', '10.11.45.67', EXIT_ACCESS_DENIED), + ('10.113.0.0/16', '127.0.0.1', EXIT_ACCESS_DENIED), + ('1.2.3.4/0', '4.3.2.1', 0), + ('1.2.3.4/40', '4.3.2.1', EXIT_BAD_ARGUMENTS), + ('1.2.3.4.5.6.7/8', '127.0.0.1', EXIT_BAD_ARGUMENTS), + ('1.2.3.4/8', '4.3.2.1', EXIT_ACCESS_DENIED), + ('192.168.1.64/28', '192.168.1.70', 0), + ('192.168.1.64/28', '192.168.1.7', EXIT_ACCESS_DENIED), + ] + def runtest(self): + for mask, client, expected in ParseMask_Case.values: + cmd = "h_parsemask %s %s" % (mask, client) + ret, msgs, err = self.runcmd_unchecked(cmd) + if ret != expected: + self.fail("%s gave %d, expected %d" % (cmd, ret, expected)) + + +class HostFile_Case(CompileHello_Case): + def setup(self): + CompileHello_Case.setup(self) + del os.environ['DISTCC_HOSTS'] + self.save_home = os.environ['HOME'] + os.environ['HOME'] = os.getcwd() + # DISTCC_DIR is set to 'distccdir' + open(os.environ['DISTCC_DIR'] + '/hosts', 'w').write('127.0.0.1:%d%s' % + (self.server_port, _server_options)) + + def teardown(self): + os.environ['HOME'] = self.save_home + CompileHello_Case.teardown(self) + + +class Lsdistcc_Case(WithDaemon_Case): + """Check lsdistcc""" + + def lsdistccCmd(self): + """Return command to run lsdistcc""" + return "lsdistcc -r%d" % self.server_port + + def runtest(self): + lsdistcc = self.lsdistccCmd() + + # Test "lsdistcc --help" output is reasonable. + # (Note: "lsdistcc --help" ought to return exit status 0, really, + # but currently it returns 1, so that's what we test for.) + rc, out, err = self.runcmd_unchecked(lsdistcc + " --help") + self.assert_re_search("Usage:", out) + self.assert_equal(err, "") + self.assert_equal(rc, 1) + + # Test "lsdistcc host1 host2 host3". + out, err = self.runcmd(lsdistcc + " localhost 127.0.0.1 127.0.0.2 " + + " anInvalidHostname") + out_list = out.split() + out_list.sort() + expected = ["127.0.0.1", "127.0.0.2", "localhost"] + self.assert_equal(out_list, expected) + self.assert_equal(err, "") + + # Test "lsdistcc host%d". + out, err = self.runcmd(lsdistcc + " 127.0.0.%d") + self.assert_equal(err, "") + self.assert_re_search("127.0.0.1\n", out) + self.assert_re_search("127.0.0.2\n", out) + self.assert_re_search("127.0.0.3\n", out) + self.assert_re_search("127.0.0.4\n", out) + self.assert_re_search("127.0.0.5\n", out) + +# When invoking compiler, use absolute path so distccd can find it +for path in os.environ['PATH'].split (':'): + abs_path = os.path.join (path, 'gcc') + + if os.path.isfile (abs_path): + _gcc = abs_path + break + +# All the tests defined in this suite +tests = [ + CompileHello_Case, + # Support for Objective C in distcc-pump is currently disabled. + ### ObjectiveC_Case, + # I couldn't test the Objective C++ case, + # because I couldn't figure out how to install + # GNU Objective C++. So this test is disabled for now. + ### ObjectiveCPlusPlus_Case, + Gdb_Case, + GdbOpt1_Case, + GdbOpt2_Case, + GdbOpt3_Case, + Lsdistcc_Case, + BadLogFile_Case, + ScanArgs_Case, + ParseMask_Case, + DotD_Case, + Compile_c_Case, + ImplicitCompilerScan_Case, + StripArgs_Case, + StartStopDaemon_Case, + CompressedCompile_Case, + DashONoSpace_Case, + WriteDevNull_Case, + CppError_Case, + BadInclude_Case, + PreprocessPlainText_Case, + NoDetachDaemon_Case, + SBeatsC_Case, + DashD_Case, + BinFalse_Case, + BinTrue_Case, + VersionOption_Case, + HelpOption_Case, + BogusOption_Case, + MultipleCompile_Case, + GccOptionsPassed_Case, + IsSource_Case, + ExtractExtension_Case, + ImplicitCompiler_Case, + DaemonBadPort_Case, + AccessDenied_Case, + NoServer_Case, + InvalidHostSpec_Case, + ParseHostSpec_Case, + ImpliedOutput_Case, + SyntaxError_Case, + NoHosts_Case, + MissingCompiler_Case, + RemoteAssemble_Case, + PreprocessAsm_Case, + ModeBits_Case, + EmptySource_Case, + HostFile_Case, + AbsSourceFilename_Case, + # slow tests below here + Concurrent_Case, + ThousandFold_Case, + BigAssFile_Case] + + +if __name__ == '__main__': + while len(sys.argv) > 1 and sys.argv[1].startswith("--"): + if sys.argv[1] == "--valgrind": + _valgrind_command = "valgrind --quiet " + del sys.argv[1] + elif sys.argv[1].startswith("--valgrind="): + _valgrind_command = sys.argv[1][len("--valgrind="):] + " " + del sys.argv[1] + elif sys.argv[1] == "--lzo": + _server_options = ",lzo" + del sys.argv[1] + elif sys.argv[1] == "--pump": + _server_options = ",lzo,cpp" + del sys.argv[1] + + comfychair.main(tests) diff --git a/include_server/Makefile.in b/include_server/Makefile.in new file mode 100644 index 0000000..ad9661d --- /dev/null +++ b/include_server/Makefile.in @@ -0,0 +1,114 @@ +distcc_srcdir := $(shell make --directory=../distcc --no-print-directory \ + --silent echo_srcdir) +srcdir := $(shell cd $(distcc_srcdir)/../include_server && pwd) +builddir := $(shell pwd)/build + +# Autoconf configuration variables. +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datadir = @datadir@ +testdir = $(builddir)/testdir +INSTALL = @INSTALL@ +DESTDIR = / +PYTHON = @PYTHON@ + +.PHONY: all +all: build + +.PHONY: build +build: + cd $(srcdir) && \ + BUILDDIR=$(builddir) $(PYTHON) ./setup.py \ + build \ + --build-base=$(builddir) \ + --build-temp=$(builddir) + +.PHONY: install +install: + cd $(srcdir) && \ + BUILDDIR=$(builddir) $(PYTHON) ./setup.py \ + build \ + --build-base=$(builddir) \ + --build-temp=$(builddir) \ + install \ + --prefix=$(prefix) \ + --record=$(PYTHON_INSTALL_RECORD) \ + --root=$(DESTDIR) + +# Below we delete the link and then we recreate it. Otherwise, a second link +# will be created the second time install-for-tests is run! That's because the +# link name would now be resolved as a target directory (third form according to +# 'man ln'). As a result a link to the test_data directory would be inserted +# into the test_data directory under the name 'test_data'. +.PHONY: install-for-tests +install-for-tests: + mkdir -p $(testdir) + if [ -h $(testdir)/test_data ]; then \ + rm -f $(testdir)/test_data; \ + fi + ln -s $(realpath $(srcdir)/test_data) \ + $(testdir)/test_data + cd $(srcdir) && \ + BUILDDIR=$(builddir) $(PYTHON) ./setup.py \ + build -f \ + --build-base=$(testdir) \ + --build-temp=$(testdir) \ + install \ + --install-lib=$(testdir)/python \ + --install-scripts=$(testdir)/python + + +.PHONY: check maintainer-check +check maintainer-check: test + +.PHONY: test +test: install-for-tests \ + c_extensions_test include_server_test macro_eval_test mirror_path_test\ + parse_command_test parse_file_test \ + include_analyzer_test include_analyzer_memoizing_node_test \ + basics_test + +.PHONY: c_extensions_test +c_extensions_test: install-for-tests + cd $(testdir) && PYTHONPATH=$(testdir)/python/include_server $(PYTHON) $(testdir)/python/include_server/c_extensions_test.py \ + > c_extensions_test.out 2>&1 + @echo Filtering c_extensions_test.out + @cd $(testdir) && cat c_extensions_test.out \ + | grep -v 'distcc_include_server\[.*\] (dcc_r_token_int) ERROR: protocol derailment: expected token "XXXX"' \ + | grep -v 'distcc_include_server\[.*\] (dcc_explain_mismatch) ERROR: error context: "ARGC 2ARGV 6tomatoARGV 7potatos"' +.PHONY: include_server_test +include_server_test: install-for-tests + cd $(testdir) && PYTHONPATH=$(testdir)/python/include_server $(PYTHON) $(testdir)/python/include_server/include_server_test.py +.PHONY: macro_eval_test +macro_eval_test: install-for-tests + cd $(testdir) && PYTHONPATH=$(testdir)/python/include_server $(PYTHON) $(testdir)/python/include_server/macro_eval_test.py +.PHONY: mirror_path_test +mirror_path_test: install-for-tests + cd $(testdir) && PYTHONPATH=$(testdir)/python/include_server $(PYTHON) $(testdir)/python/include_server/mirror_path_test.py +.PHONY: parse_command_test +parse_command_test: install-for-tests + cd $(testdir) && PYTHONPATH=$(testdir)/python/include_server $(PYTHON) $(testdir)/python/include_server/parse_command_test.py +.PHONY: parse_file_test +parse_file_test: install-for-tests + cd $(testdir) && PYTHONPATH=$(testdir)/python/include_server $(PYTHON) $(testdir)/python/include_server/parse_file_test.py +.PHONY: include_analyzer_test +include_analyzer_test: install-for-tests + cd $(testdir) && PYTHONPATH=$(testdir)/python/include_server $(PYTHON) $(testdir)/python/include_server/include_analyzer_test.py +.PHONY: include_analyzer_memoizing_node_test +include_analyzer_memoizing_node_test: install-for-tests + cd $(testdir) && PYTHONPATH=$(testdir)/python/include_server $(PYTHON) $(testdir)/python/include_server/include_analyzer_memoizing_node_test.py +.PHONY: basics_test +basics_test: install-for-tests + cd $(testdir) && PYTHONPATH=$(testdir)/python/include_server $(PYTHON) $(testdir)/python/include_server/basics_test.py + +Makefile: Makefile.in config.status + ./config.status + +.PHONY: clean +clean: + $(PYTHON) $(srcdir)/setup.py clean \ + --build-base=$(builddir) \ + --build-temp=$(builddir) + rm -rf $(testdir) + diff --git a/include_server/__init__.py b/include_server/__init__.py new file mode 100755 index 0000000..e69de29 --- /dev/null +++ b/include_server/__init__.py diff --git a/include_server/basics.py b/include_server/basics.py new file mode 100755 index 0000000..597313d --- /dev/null +++ b/include_server/basics.py @@ -0,0 +1,339 @@ +#! /usr/bin/python2.4 +# +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +"""Common and low-level stuff for include server.""" + +__author__ = "Nils Klarlund" + +import sys +import tempfile +import os.path +import signal +import resource + +# MISCELLANEOUS CONSTANTS + +# Place for creation of temporary directories. +client_tmp = None +# And, the current such temporary directory. +client_root = None + +# This constant is embedded in names of client root directories. +INCLUDE_SERVER_NAME = "include_server" + +def InitializeClientTmp(): + """Determine the tmp directory to use. + + Use the RAM disk-like /dev/shm as default place to store compressed files if + available.""" + + global client_tmp + if "DISTCC_CLIENT_TMP" in os.environ: + client_tmp = os.environ["DISTCC_CLIENT_TMP"] + elif os.path.isdir("/dev/shm") and os.access("/dev/shm", + os.X_OK + os.W_OK + os.R_OK): + client_tmp = "/dev/shm" + else: + client_tmp = "/tmp" + if not client_tmp or client_tmp[0] != '/': + sys.exit("DISTCC_CLIENT_TMP must start with '/'.") + client_tmp = client_tmp.rstrip('/') + # The protocol between the include server and distcc client stipulates + # that the top three directories constitute the prefix prepended to absolute + # file paths. To have room to make a temp directory, we'll need to have less + # than two levels at this point. + # Note: "/a/b".split('/') == ["", "a", "b']. + if len(client_tmp.split('/')) > 3: + sys.exit("DISTCC_CLIENT_TMP must have at most two directory levels.") + + +def InitializeClientRoot(generation): + """Make a client directory for a generation of compressed files. + + Arguments: + generation: a natural number, usually 1 or slightly bigger; this number, + minus 1, indicates how many times a reset of the caches has taken place. + """ + assert client_tmp + global client_root + try: + # Create a unique identifier that will never repeat. Use pid as suffix for + # cleanout mechanism that wipes files not associated with a running pid. + client_root = tempfile.mkdtemp(".%s-%s-%d" % + (INCLUDE_SERVER_NAME, + os.getpid(), generation), + dir=client_tmp) + number_missing_levels = 3 - len(client_tmp.split('/')) + # Stuff client_root path until we have exactly three levels in all. + for i in range(number_missing_levels): + client_root = client_root + "/padding" + os.mkdir(client_root) + except (IOError, OSError), why: + sys.exit("Could not create client root directory %s: %s" % + (client_root, why)) + + +# For automated emails, see also distcc/src/emaillog.h. +DCC_EMAILLOG_WHOM_TO_BLAME = os.getenv("DISTCC_EMAILLOG_WHOM_TO_BLAME", + "distcc-pump-errors") +EMAIL_SUBJECT = "distcc-pump include server email" +CANT_SEND_MESSAGE = """Please notify %s that the distcc-pump include server +tried to send them email but failed.""" % DCC_EMAILLOG_WHOM_TO_BLAME +MAX_EMAILS_TO_SEND = 3 + +# The maximum user time the include server is allowed handling one request. This +# is a critical parameter because all caches are reset if this time is +# exceeded. And if all caches are reset, then the next request may take much +# longer time, possibly again exceeding the quota. The parameter is also of +# importance to builds that involve compilations that distcc-pump does not grok: +# an amount of time roughly equal to this quota is wasted before CPP is invoked +# instead. +USER_TIME_QUOTA = 3.8 # seconds + +# How often the following question is answered: has too much user time been +# spent in the include handler servicing the current request? +# +# FIXME(klarlund): SIGALRM should not be raised in code that has I/O. Fix +# include server so that this is guaranteed not to happen. Until then, we are +# careful to wait a full 4 s before issuing SIGALRM. +USER_TIME_QUOTA_CHECK_INTERVAL_TIME = 4 # seconds, an integer + +# ALGORITHMS + +SIMPLE = 0 # not implemented +MEMOIZING = 1 # only one currently implemented +ALGORITHMS = [ SIMPLE, MEMOIZING ] + + +# FLAGS FOR COMMAND LINE OPTIONS + +opt_debug_pattern = 1 # see DEBUG below +opt_verify = False # whether to compare calculated include closure to that + # produced by compiler +opt_exact_analysis = False # use CPP instead of include analyzer +opt_write_include_closure = False # write include closures to file +opt_statistics = False +opt_algorithm = MEMOIZING +opt_stat_reset_triggers = {} +opt_simple_algorithm = False +opt_print_times = False +opt_send_email = False +opt_email_bound = MAX_EMAILS_TO_SEND +opt_realpath_warning_re = None + + +# HELPER FUNCTION FOR STAT_RESET_TRIGGERS + +def Stamp(path): + """Return a stamp characterizing a file and its modification time.""" + try: + st_inf = os.stat(path) + # The inode and device identify a file uniquely. + return (st_inf.st_mtime, st_inf.st_ino, st_inf.st_dev) + except OSError: + return None + + +# REALPATH WARNINGS + +BAD_REALPATH_WARNING_MSG = ( + "For translation unit '%s' while processing '%s': lookup of file '%s' " + + "resolved to '%s' whose realpath is '%s'.") + + +# LANGUAGES AND FILE EXTENSIONS + +# The languages that we recognize. +# +# TODO: add "objective-c" and "objective-c++". +# Currently we try to compute the default include path for all +# languages at startup, and barf if it fails. We need to fix that +# before enabling objective-c or objective-c++. +# So Objective C and Objective C++ support is disabled for now. +# +# (Also, I couldn't test the Objective C++ case, because I couldn't figure +# out how to install GNU Objective C++. We need to test it before +# enabling it.) +# To enable, uncomment the code below and the test case +# ObjectiveC(PlusPlus)_Case in ../distcc/test/testdistcc.py.) + +LANGUAGES = set(["c", "c++"]) +#LANGUAGES = set(["c", "c++", "objective-c", "objective-c++"]) + +# The suffixes, following last period, used for source files and +# preprocessed files, each with their corresponding source language. +TRANSLATION_UNIT_MAP = { + # C + "c":"c", "i":"c", + # C++ + "cc":"c++", "cpp":"c++", "cxx":"c++", "C":"c++", "CXX":"c++", "ii":"c++", + # Objective C + # "m":"objective-c", "mi":"objective-c" + # Objective C++ + # "mm":"objective-c++", "M":"objective-c++", "mii":"objective-c++", + } + +# All languages are described by suffixes. +assert set(TRANSLATION_UNIT_MAP.values()) == LANGUAGES + + +# DEBUG + +# Debugging is controlled by the 5 least significant bits of +# opt_debug_pattern. +DEBUG_WARNING = 1 # For warnings +DEBUG_TRACE = 2 # For tracing functions (upper level) +DEBUG_TRACE1 = 4 # For tracing functions (medium level) +DEBUG_TRACE2 = 8 # For tracing functions (lower level) +DEBUG_DATA = 16 # For printing data +DEBUG_NUM_BITS = 5 # The cardinality of {1,2,4,8,16} + +def Debug(trigger_pattern, message, *params): + triggered = opt_debug_pattern & trigger_pattern + if triggered: + i = 1 + for unused_j in range(DEBUG_NUM_BITS): + if i & DEBUG_WARNING & triggered: + print >> sys.stderr, "WARNING include server:", message % params + if i & DEBUG_TRACE & triggered: + print >> sys.stderr, "TRACE:", message % params + elif i & DEBUG_TRACE1 & triggered: + print >> sys.stderr, "TRACE1:", message % params + elif i & DEBUG_TRACE2 & triggered: + print >> sys.stderr, "TRACE2:", message % params + elif i & DEBUG_DATA & triggered: + print >> sys.stderr, "DATA:", message % params + i *= 2 + sys.stderr.flush() + + +# EXCEPTIONS + +class Error(Exception): + pass + +class NotCoveredError(Error): + """Exception for included file not covered by include processing.""" + + def __init__(self, message, + source_file=None, + line_number=None, + send_email=True): + """Constructor. + + Arguments: + message: text of error message + source_file: name of source_file if known + line_number: an integer, if known + send_email: a Boolean, if False then never send email + + These arguments are all stored in the exception. However, the source_file + and line_number are appended, in a syntax defined here, to the message + before it is stored as self.args[0] through invocation of the Error + constructor.""" + assert not line_number or source_file + self.source_file = None + self.line_number = None + self.send_email = send_email + if source_file: + # Mark this exception as mentioning the source_file. + self.source_file = source_file + # Line numbers are not currently used. + if line_number: + self.line_number = line_number + message = "File: '%s', line: %s: %s" % ( + source_file, line_number, message) + else: + message = "File: '%s': %s" % (source_file, message) + # Message, a string, becomes self.args[0] + Error.__init__(self, message) + + +class NotCoveredTimeOutError(NotCoveredError): + """An instance of this class is raised when the include server has spent too + much time analyzing dependencies.""" + pass + + +class IncludeAnalyzerTimer(object): + """Start a timer that limits the amount of CPU time the include analyzer may + spend servicing a single request. + + We use user time so that a network hiccup will not entail a cache reset if, + say, we are using NFS. + + An object of this class must be instantiated so that, no matter what, the Cancel + method is eventually called. This reinstates the original timer (if present). + """ + def __init__(self): + self.start_utime = resource.getrusage(resource.RUSAGE_SELF).ru_utime + self.old = signal.signal(signal.SIGALRM, self._TimeIsUp) + signal.alarm(USER_TIME_QUOTA_CHECK_INTERVAL_TIME) + + def _TimeIsUp(self, _sig_number, _frame): + """Check CPU time spent and raise exception or reschedule.""" + if (resource.getrusage(resource.RUSAGE_SELF).ru_utime + > self.start_utime + USER_TIME_QUOTA): + raise NotCoveredTimeOutError(("Bailing out because include server " + + "spent more than %3.1fs user time " + + "handling request") % + USER_TIME_QUOTA) + else: + # Reschedule ourselves. + signal.alarm(USER_TIME_QUOTA_CHECK_INTERVAL_TIME) + + def Stop(self): + signal.alarm(0) + + def Start(self): + signal.alarm(USER_TIME_QUOTA_CHECK_INTERVAL_TIME) + + def Cancel(self): + """Must be called eventually. See class documentation.""" + sys.stdout.flush() + signal.alarm(0) + signal.signal(signal.SIGALRM, self.old) + + +class SignalSIGTERM(Error): + pass + + +def RaiseSignalSIGTERM(*_args): + """Raise SignalSIGTERM. + + Use signal.signal for binding this function to SIGTERM. + """ + raise SignalSIGTERM + + +# COMMON FUNCTIONS + +def SafeNormPath(path): + """Safe, but limited, version of os.path.normpath. + + Python's os.path.normpath is an unsafe operation; the result may not point to + the same file as the argument. Instead, this function just removes + initial './'s and a final '/'s if present.""" + if path == ".": + return "" + else: + while path.startswith("./"): + path = path[2:] + return path.rstrip("/") diff --git a/include_server/basics_test.py b/include_server/basics_test.py new file mode 100755 index 0000000..7b7308c --- /dev/null +++ b/include_server/basics_test.py @@ -0,0 +1,65 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +__author__ = "Nils Klarlund" + +import os +import os.path +import unittest + +import basics + +class BasicsTest(unittest.TestCase): + + def setUp(self): + + basics.opt_debug_pattern = 1 + + def tearDown(self): + pass + + def test_InitializeClientTmp(self): + os.environ['DISTCC_CLIENT_TMP'] = 'to/be' + self.assertRaises(SystemExit, basics.InitializeClientTmp) + os.environ['DISTCC_CLIENT_TMP'] = '/to/be/or' + self.assertRaises(SystemExit, basics.InitializeClientTmp) + try: + os_mkdir = os.mkdir + + def Mock_os_mkdir(f, *args): + if not f.startswith('/to/'): + raise Exception, f + os.mkdir = Mock_os_mkdir + + os.environ['DISTCC_CLIENT_TMP'] = '/to/be' + basics.InitializeClientTmp() + basics.InitializeClientRoot(1) + self.assertEqual(os.path.dirname(basics.client_root), "/to/be") + os.environ['DISTCC_CLIENT_TMP'] = '/to' + basics.InitializeClientTmp() + basics.InitializeClientRoot(2) + self.assertEqual(os.path.dirname( + os.path.dirname(basics.client_root)), "/to") + self.assertEqual(os.path.basename(basics.client_root), "padding") + self.assertEqual(len( + [ None for ch in basics.client_root if ch == '/' ]), 3) + finally: + os.mkdir = os_mkdir + +unittest.main() diff --git a/include_server/c_extensions/distcc_pump_c_extensions_module.c b/include_server/c_extensions/distcc_pump_c_extensions_module.c new file mode 100644 index 0000000..e7477dd --- /dev/null +++ b/include_server/c_extensions/distcc_pump_c_extensions_module.c @@ -0,0 +1,381 @@ +/* Copyright 2007 Google Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. +*/ + +// Author: Nils Klarlund + +/* distcc_pump_c_extensions_module.c -- Python bindings for distcc-pump + * extensions */ + +#include "Python.h" + +static char *version = ".01"; + +/* To suppress compiler warnings */ +#define UNUSED(v) ((void)&v) + +char *rs_program_name = "distcc_include_server"; + +#include "distcc.h" +#include "rpc.h" + +static PyObject *distcc_pump_c_extensionsError; + + +/*********************************************************************** +CompressFileLZO1Z + ***********************************************************************/ + +static char CompressLzo1xAlloc_doc__[] = +"CompressFileLZO1Z__(in_buf):\n" +"Compress file according to distcc lzo protocol.\n" +"\n" +" Arguments:\n" +" in_buf: a string\n" +" Raises:\n" +" distcc_pump_c_extensions.Error\n" +" Returns:\n" + " a string, compressed according to distcc protocol\n."; + +static PyObject * +CompressLzo1xAlloc(PyObject *dummy, PyObject *args) { + PyObject *string_object; + const char *in_buf; + int in_len; + char *out_buf; + size_t out_len; + UNUSED(dummy); + if (!PyArg_ParseTuple(args, "s#", &in_buf, &in_len)) + return NULL; + if (in_len < 0) + return NULL; + if (dcc_compress_lzo1x_alloc(in_buf, in_len, &out_buf, &out_len)) { + PyErr_SetString(distcc_pump_c_extensionsError, + "Couldn't compress that."); + return NULL; + } + string_object = PyString_FromStringAndSize(out_buf, out_len); + free(out_buf); + return string_object; +} + + + +/*********************************************************************** +Token protocol +************************************************************************/ + +static char RCwd_doc__[] = +"Rcwd_doc__(ifd):\n" +" Read value of current directory.\n" +"\n" +" Arguments:\n" +" ifd: an integer file descriptor\n" +" Raises:\n" +" distcc_pump_c_extensions.Error\n" +; +static PyObject * +RCwd(PyObject *dummy, PyObject *args) { + int ifd; + char *value_str; + UNUSED(dummy); + if (!PyArg_ParseTuple(args, "i", &ifd)) + return NULL; + if (dcc_r_cwd(ifd, &value_str)) { + PyErr_SetString(distcc_pump_c_extensionsError, + "Couldn't read token string."); + return NULL; + } + return PyString_FromString(value_str); +} + + +static char RTokenString_doc__[] = +"RTokenString(ifd, expect_token):\n" +" Read value of expected token.\n" +"\n" +" Arguments:\n" +" ifd: an integer file descriptor\n" +" expect_token: a four-character string\n" +" Raises:\n" +" distcc_pump_c_extensions.Error\n" +; +static PyObject * +RTokenString(PyObject *dummy, PyObject *args) { + int ifd; + char *expect_token; + char *value_str; + UNUSED(dummy); + if (!PyArg_ParseTuple(args, "is", &ifd, &expect_token)) + return NULL; + if (dcc_r_token_string(ifd, expect_token, &value_str)) { + PyErr_SetString(distcc_pump_c_extensionsError, + "Couldn't read token string."); + return NULL; + } + return PyString_FromString(value_str); +} + + +static char RArgv_doc__[] = +"Rargv(ifd):\n" +" Read argv values.\n" +"\n" +" Arguments:\n" +" ifd: an integer file descriptor\n" +" Raises:\n" +" distcc_pump_c_extensions.Error\n" + +; +static PyObject * +RArgv(PyObject *dummy, PyObject *args) { + int i = 0; + PyObject *list_object = NULL; + int ifd; + PyObject *string_object = NULL; + char **argv; + UNUSED(dummy); + if (!PyArg_ParseTuple(args, "i", &ifd)) + return NULL; + if (dcc_r_argv(ifd, &argv)) { + PyErr_SetString(distcc_pump_c_extensionsError, "Couldn't read that."); + goto error; + } + if ((list_object = PyList_New(0)) == NULL) goto error; + for (; argv[i]; i++) { + string_object = PyString_FromString(argv[i]); + free(argv[i]); + if (!string_object) { + goto error; + } + if (PyList_Append(list_object, string_object) < 0) + goto error; + Py_XDECREF(string_object); + } + free(argv); + return list_object; + error: + Py_XDECREF(list_object); + Py_XDECREF(string_object); + for (i = i + 1; argv[i]; i++) + free(argv[i]); + free(argv); + return NULL; +} + + +static char XArgv_doc__[] = +"XArgv(ifd, argv)\n" +" Transmit list argv.\n" +"\n" +" Arguments:\n" +" ifd: integer file descriptor\n" +" argv: a list of strings\n" +; + +static PyObject * +XArgv(PyObject *dummy, PyObject *args) { + int i; + char **ptr; + PyObject *list_object; + int ifd; + int len; + int ret; + char **argv; + UNUSED(dummy); + if (!PyArg_ParseTuple(args, "iO!", &ifd, &PyList_Type, &list_object)) + return NULL; + len = PyList_Size(list_object); + argv = ptr = (char **) calloc((size_t) len + 1, sizeof (char *)); + if (ptr == NULL) { + return PyErr_NoMemory(); + } + argv[len] = NULL; + for (i = 0; i < len; i++) { + PyObject *string_object; + string_object = PyList_GetItem(list_object, i); /* borrowed ref */ + argv[i] = PyString_AsString(string_object); /* does not increase + ref count */ + } + ret = dcc_x_argv(ifd, argv); + free(argv); + if (ret == 0) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + + + +/*********************************************************************** +OsPathExists +************************************************************************/ + +static /* const */ char OsPathExists_doc__[] = +"OsPathExists(filepath):\n" +" Libc version of os.path.exists.\n" +"\n" +" Arguments:\n" +" filepath: a string\n" +" Returns:\n" +" True or False\n" +; + +static PyObject * +OsPathExists(PyObject *dummy, PyObject *args) { + const char *in; + int len; + int res; + + struct stat buf; + + UNUSED(dummy); + if (!PyArg_ParseTuple(args, "s#", &in, &len)) + return NULL; + if (len < 0) + return NULL; + res = stat(in, &buf); + if (res == -1) Py_RETURN_FALSE; + if (res == 0) Py_RETURN_TRUE; + assert(0); + return NULL; +} + +/*********************************************************************** +OsPathIsFile +************************************************************************/ + +static /* const */ char OsPathIsFile_doc__[] = +"OsPathIsFile(filename):\n" +" Libc version of os.path.isfile.\n" +"\n" +" Arguments:\n" +" filename: a string\n" +" Returns:\n" +" True or False\n" +; + +static PyObject * +OsPathIsFile(PyObject *dummy, PyObject *args) { + const char *in; + int len; + int res; + + struct stat buf; + + UNUSED(dummy); + if (!PyArg_ParseTuple(args, "s#", &in, &len)) + return NULL; + if (len < 0) + return NULL; + res = stat(in, &buf); + if (res == -1) Py_RETURN_FALSE; + if ((res == 0) && S_ISREG(buf.st_mode)) Py_RETURN_TRUE; + if ((res == 0) && !S_ISREG(buf.st_mode)) Py_RETURN_FALSE; + return NULL; +} + + + +/*********************************************************************** +Realpath +***********************************************************************/ + +static /* const */ char Realpath_doc__[] = +"Realpath(filename)\n" +" Libc version of os.path.realpath.\n" +"\n" +" Arguments:\n" +" filename: a string\n" +" Returns:\n" +" the realpath (or filename if it does not exist)\n" +" The semantics of this function is probably not quite the same as that\n" +" of os.path.realpath for paths that do not correspond to existing files.\n" +" This is why we do not call it OsPathRealpath.\n" +""; + +/* TODO(klarlund): make logic so that this file will compile in the + absence of realpath from libc. In that case, use Python realpath. */ + +static PyObject * +Realpath(PyObject *dummy, PyObject *args) { + const char *in; + char *res; + PyObject *result_str; + + UNUSED(dummy); + if (!PyArg_ParseTuple(args, "s", &in)) + return NULL; + res = realpath(in, NULL); + if (res) { + result_str = PyString_FromStringAndSize(res, strlen(res)); + if (result_str == NULL) + return PyErr_NoMemory(); + return result_str; + } + else + return PyString_FromStringAndSize(in, strlen(in)); +} + + + +/*********************************************************************** +Bindings +************************************************************************/ + +static PyMethodDef methods[] = { + {"OsPathExists", (PyCFunction)OsPathExists, METH_VARARGS, + OsPathExists_doc__}, + {"OsPathIsFile", (PyCFunction)OsPathIsFile, METH_VARARGS, + OsPathIsFile_doc__}, + {"Realpath", (PyCFunction)Realpath, METH_VARARGS, Realpath_doc__}, + {"RTokenString",(PyCFunction)RTokenString, METH_VARARGS, + RTokenString_doc__}, + {"RCwd", (PyCFunction)RCwd, METH_VARARGS, RCwd_doc__}, + {"RArgv", (PyCFunction)RArgv, METH_VARARGS, RArgv_doc__}, + {"XArgv", (PyCFunction)XArgv, METH_VARARGS, XArgv_doc__}, + {"CompressLzo1xAlloc", (PyCFunction)CompressLzo1xAlloc, METH_VARARGS, + CompressLzo1xAlloc_doc__}, + {NULL, NULL, 0, NULL} +}; + + +static /* const */ char module_documentation[]= +"Various utilities for distcc-pump.\n" +; + +void initdistcc_pump_c_extensions(void) { + PyObject *module; + PyObject *py_str; + distcc_pump_c_extensionsError = PyErr_NewException( + "distcc_pump_c_extensions.Error", NULL, NULL); + + module = Py_InitModule4("distcc_pump_c_extensions", + methods, + module_documentation, + NULL, + PYTHON_API_VERSION); + + py_str = PyString_FromString("Nils Klarlund"); + PyModule_AddObject(module, "__author__", py_str); + py_str = PyString_FromString(version); + PyModule_AddObject(module, "__version__", py_str); + /* Make the exception class accessible */ + PyModule_AddObject(module, "Error", + distcc_pump_c_extensionsError); + +} diff --git a/include_server/c_extensions_test.py b/include_server/c_extensions_test.py new file mode 100755 index 0000000..abb9414 --- /dev/null +++ b/include_server/c_extensions_test.py @@ -0,0 +1,132 @@ +#!/usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +"""Tests for distcc_pump_c_extensions. Writes out doc strings and calls some +distcc rpc functions. Also, the program times the speed-up of using the libc +versions of os.path.realpath and os.path.exists provided by +distcc_pump_c_extensions.""" + +__author__ = "opensource@google.com" + +import sys +import os.path +import time +import traceback +import struct +import random + +import distcc_pump_c_extensions + + +def main(): + + # Module tempfile doesn't work with distcc. Work-around follows. + random_filename = "distcc-pump" + str(random.random() * time.time()) + if os.path.exists(random_filename): + print sys.stderr >> ( + """"For unfathomably unlikely reasons, this test failed: '%s' exists.""" + % random_filename) + sys.exit(1) + def _MakeTempFile(mode): + return open(random_filename, mode) + + # Exercise metainformation and documentation strings + assert(distcc_pump_c_extensions.__file__) + assert(distcc_pump_c_extensions.__doc__) + assert(distcc_pump_c_extensions.__author__) + assert(distcc_pump_c_extensions.RTokenString.__doc__) + assert(distcc_pump_c_extensions.RArgv.__doc__) + assert(distcc_pump_c_extensions.XArgv.__doc__) + assert(distcc_pump_c_extensions.OsPathExists.__doc__) + assert(distcc_pump_c_extensions.OsPathIsFile.__doc__) + assert(distcc_pump_c_extensions.Realpath.__doc__) + + + # RTokenString and RArgv + + # Pack something and try sending it + pack = struct.pack + fd = _MakeTempFile('wb') + fd.write("ARGC 2") + fd.write("ARGV 6") + fd.write("tomato") + fd.write("ARGV 7") + fd.write("potatos") + fd.close() + + # Now try to read it back with wrong expectations. + fd = _MakeTempFile('rb') + try: + two_string = distcc_pump_c_extensions.RTokenString(fd.fileno(), "XXXX"); + sys.exit("internal error 1 - we should not get to here") + except distcc_pump_c_extensions.Error: + pass + + # Read it back with appropriate expectations. + fd.seek(0); + + two_string = distcc_pump_c_extensions.RTokenString(fd.fileno(), "ARGC"); + if two_string != "AR": + raise distcc_pump_c_extensions.error, "internal error 2" + + fd.seek(0); + args = distcc_pump_c_extensions.RArgv(fd.fileno()) + if args != ["tomato", "potatos"]: + raise distcc_pump_c_extensions.error, "internal error 3" + fd.close() + + # XArgv and RArgv + + fd = _MakeTempFile('wb') + darth_vader_barney = ["Darth Vader", "Barney"] + args = distcc_pump_c_extensions.XArgv(fd.fileno(), darth_vader_barney) + fd.close() + + fd = _MakeTempFile('r') + args = distcc_pump_c_extensions.RArgv(fd.fileno()) + if args != darth_vader_barney: + raise distcc_pump_c_extensions.error, "internal error 4" + fd.close() + + # Libc functions --- also print out how fast they are compared to + # Python built-ins. + t = time.time() + f = "/" + for i in range(10000): + distcc_pump_c_extensions.OsPathExists(f); + print 'Stat', time.time() - t + t = time.time() + for i in range(10000): + os.path.exists(f); + print 'os.path.exists', time.time() - t + for i in range(10000): + distcc_pump_c_extensions.Realpath(f); + print 'c_realpath', time.time() - t + t = time.time() + for i in range(10000): + os.path.realpath(f); + print 'os.path.realpath', time.time() - t + + print "Test passed" + +try: + main() +except: + traceback.print_exc() + sys.exit("c_extensions_test.py failed.") diff --git a/include_server/cache_basics.py b/include_server/cache_basics.py new file mode 100755 index 0000000..7be7507 --- /dev/null +++ b/include_server/cache_basics.py @@ -0,0 +1,858 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +"""Classes enabling definition and composition of caches. + +This file defines caches used to speed up the does-this-file-exist +test that forms the basis of the C preprocessor's include-file +handling, and takes most of its time. + +When the preprocessor sees a line like "#include <foo/bar.h>" it looks +for a file named "bar.h" in many directories: /usr/include/foo/bar.h, +./foo/bar.h, and so forth. More precisely, the preprocessor is given +a "search path", which is a list of directory-names. (By default, the +search-path looks like ['/usr/include', '/usr/local/include', ...], +but it's often extended via gcc flags like -I, -isystem, -iprefix, +etc.) To resolve a single #include like "#include <foo/bar.h>", the +preprocessor goes through every directory in the search path, running + + os.stat(os.path.join(current_working_dir, search_dir, 'foo/bar.h')) + +until the stat call succeeds. With dozens of search-dirs to look +through, dozens of #include lines per source file, and hundreds of +source files per compilation, this can add up to millions of stat +calls. Many of these calls are exactly the same, so caching is a big +win. + +The cache of stat calls takes a filename as input and produces a bool +as output, saying if the filename exists. For reasons that will +become clear in a moment, we actually represent the input filename as +a triple that breaks the filename into its three components: + + 1) currdir: the current working directory (usually os.path.absdir('.')) + 2) searchdir: an element of the search path (eg '/usr/include', 'base') + 3) includepath: the thing that comes after "#include" in source files + ("foo/bar.h" in our examples above). + +Why do we break the input into three parts? Consider what cache-lookups +we have to do for a single source file: + cache[os.path.join(currdir, searchdir1, includepath1)] # #include <ipath1> + cache[os.path.join(currdir, searchdir2, includepath1)] # #include <ipath1> + cache[os.path.join(currdir, searchdir3, includepath1)] # #include <ipath1> + [etc...until the cache-lookup returns True] + cache[os.path.join(currdir, searchdir1, includepath2)] # #include <ipath2> + cache[os.path.join(currdir, searchdir2, includepath2)] # #include <ipath2> + cache[os.path.join(currdir, searchdir3, includepath2)] # #include <ipath2> + [etc] + +By having the key be a triple, we avoid all those unnecessary +os.path.join calls. But even if we do this, we notice bigger fish +to fry: the Python interpreter still has to do a string-hash of +currdir for every lookup, and also has to string-hash searchdirX and +includepathX many times. It would be much more efficient if we did +those hashes ourselves, reducing the number of string-hashes from +O(|search-path| * |#include lines|) to +O(|search-path| + |#include lines|). + +This motivates (finally!) the data structures in this file. We have +three string-to-number maps, for mapping each currdir, searchdir, and +includepath to a small integer. We put that all together in a cache, +that takes a triple of integers as its key and produces True if the +file exists, False if it does not, or None if its status is unknown. + +The String-to-number Map(s) +--------------------------- +The basic map that converts a filepath-path -- a currdir, searchdir, +or includepath -- to a small integer is called MapToIndex. MapToIndex +provides mapping in both directions: + index: a dictionary mapping paths (strings) to indices in 1..N, and + string: an array of size N + 1 that implements the reverse mapping + +So: + obj.string[obj.index[path_as_string]] == path_as_string + obj.index[obj.string[path_as_number]] == path_as_number + +Note we map from 1..N, and not 0..N-1, which leave us 0 free to use as +a synonym for None or False. + +There are also classes that specialize MapToIndex for specific purposes. + +DirectoryMapToIndex assumes the input is a directory, and in +particular a directory that does not have a slash at the end of it (eg +"/etc"). It adds the trailing slash before inserting into the map. +This is useful because it allows us to use + to join this directory +with a relative filename, rather than the slower os.path.join(). + +RelpathMapToIndex assumes the input is a relative filepath, that is, +one that does not start with /. When combined with DirectoryMapToIndex +entries, + can be used as a fast alternative to os.path.join(). + +CanonicalMapToIndex is a MapToIndex that canonializes its input before +inserting it into the map: resolving symlinks, getting rid of ..'s, +etc. It takes an absolute path as input. + +Other Caches +------------ +Besides the maps from strings to integers, there are three other caches. +One is the realpath-cache, that takes a filename and returns +os.path.realpath(filename). We cache this because os.path.realpath() +is very slow. This is called CanonicalPath. + +The second cache, the DirnameCache, maps an arbitrary pathname to +dirname(pathname), that is, the directory the pathname is in. The +input pathname is represented by a (currdir_idx, searchdir_idx, +includepath_idx) triple. The output is likewise represented as a +number: an index into the DirectoryMapToIndex structure. + +The third cache is called SystemdirPrefixCache. It tells you, for a +given absolute filepath, whether it is prefixed by a systemdir (that +is, one of the searchdirs that's built into cpp, such as /usr/include). +This is useful to cache because there are several systemdirs, and it's +expensive to check them all each time. + +Naming Conventions +------------------ + currdir: the current working dir. + searchdir: an element of the search-path (places cpp looks for .h files). + includepath: the string a source file #includes. + realpath: a full filepath with all its symlinks resolved: + os.path.realpath(os.path.join(currdir, searchdir, includepath)) + FOO_idx: the small integer associated with the string FOO. + + includepath_map: the map that takes includepaths to their idx and back + (a RelpathMapToIndex). + directory_map: the map that takes currdirs and searchdirs to their + idx and back. It also is used to store dirname(filepath) for arbitrary + filepaths -- basically, anything we know is a directory (a + DirectoryMapToIndex). + realpath_map: the map that takes full filepaths to their idx and back, + canonicalizing them first (by resolving symlinks) (a + CanonicalMapToIndex). + + searchlist: a list of searchdirs. In gcc/cpp documentation, this is + called the "search path", but for consistency, in this code we reserve + the name "path" to mean "filesystem component," never "list of dirs". + (A list of strings). + systemdir: a searchdir that's built into cpp, rather than set via -I. + (A string.) + + resolved_filepath: given an includepath, and a (possibly implicit) + currdir and searchlist, the resolved_filepath is + os.path.join(currdir, searchdir, includepath) + for the first searchdir in searchlist for which the joined string + exists. This path can be represented in many ways: 1) a string like + "foo/bar/baz.h" (if so, this string has been canonicalized to resolve + symlinks and the like); 2) an index into realpath_map associated with + that string; 3) a triple of indices; or 4) a pair of indices plus an + assumption that os.getcwd() == currdir. + +Pair Represenation of Filepaths +------------------------------- +A file is uniquely determined by the triple + (currdir_idx, searchdir_idx, includepath_idx) +For a single compilation unit, the code will often start with a +chdir(currdir). After that, we often refer to a file by the pair + (searchdir_idx, includepath_idx) +which might be either an absolute filename or relative to $PWD. + +We refer to this pair as a filepath_pair. +TODO(csilvers): find a better name? + +The function IsFilepathPair(x) tests whether x is a pair that could +plausibly have a searchdir_idx as its first element and an +includepath_idx as its second. + +Tests +----- +This code is currently only tested by regression tests of modules +using this one. +""" + +__author__ = "opensource@google.com (Nils Klarlund, Craig Silverstein)" + +import os +import os.path +import sys + +import basics +import statistics +import compiler_defaults + +DIR_ARRAY_SIZE = 500 + +# We currently use the stat and realpath of GNU libc stat and +# realpath. They are about an order of magnitude faster than their +# Python counterparts, even when called through the Python/C +# interface. + +try: + import distcc_pump_c_extensions + _OsPathExists = distcc_pump_c_extensions.OsPathExists + _OsPathIsFile = distcc_pump_c_extensions.OsPathIsFile + _PathRealpath = distcc_pump_c_extensions.Realpath + _path_realpath_works = True +except ImportError: + _OsPathExists = os.path.exists + _OsPathIsFile = os.path.isfile + _PathRealpath = os.path.realpath + # os.path.realpath might have some bugs. TODO(csilvers): check that here + _path_realpath_works = False + +Debug = basics.Debug +DEBUG_TRACE = basics.DEBUG_TRACE +DEBUG_TRACE1 = basics.DEBUG_TRACE1 +DEBUG_TRACE2 = basics.DEBUG_TRACE2 +NotCoveredError = basics.NotCoveredError + + +#### +#### SIMPLE CACHES +#### + +class CanonicalPath(object): + """Memoizing calculation of realpaths. realpath(x) is the 'canonical' + version of x, with all symbolic links eliminated. + """ + + def __init__(self): + self.cache = {} + + def Canonicalize(self, filepath): + """Find a really canonical path, possibly memoized. + + Arguments: + filepath: a filepath (string) + Returns: + the realpath of filepath (string) + + The following is irrelevant if we always use the distcc_pump_c_extensions + realpath function. + --- + Apparently, in some versions of Python 2.4 at least, realpath does + *not* resolve the last component of a filepath if it is a link: + https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1213894&group_id=5470 + Make up for that: follow that final link until a real realpath has + been found. + + Also, realpath is not idempotent. + + Solution (?): turn filepath into abspath before applying realpath; + then we can cache results as well (without worring about value of + current directory). + + The final problem -- that os.path.realpath is very slow, at least + an order of magnitude slower than the gnu libc one --- is solved + through caching all uses through an object of the present class. + """ + assert isinstance(filepath, str) + try: + return self.cache[filepath] + except KeyError: + if _path_realpath_works: + r = _PathRealpath(filepath) + self.cache[filepath] = r + return r + # Fix for os.path.realpath idempotencey bug (Python 2.4). + filepath_ = os.path.abspath(filepath) + filepath_ = _PathRealpath(filepath_) + # Fix for os.path.realpath bug (Python 2.4): symlinks at end not + # resolved. + for unused_i in range(10): + if not os.path.islink(filepath_): + break + filepath_ = os.path.join(os.path.dirname(filepath_), + os.readlink(filepath_)) + else: + raise NotCoveredError("Too many symlinks in '%s'." % filepath) + self.cache[filepath] = filepath_ + return filepath_ + +class DirnameCache(object): + """Cache the mapping from filepath pairs to index of their directory names. + + The key is a triple (currdir_idx, searchdir_idx, includepath_idx). The + value is + + (dir_idx, dir_realpath_idx) + + where dir_idx is the index of dirname of the corresponding filepath, which + possibly is relative, and dir_realpath_idx is the realpath index of the + absolute location of the dirname. The value currdir_idx is of possible + importance for deteterming dir_realpath_idx, but plays no role in determining + dir_idx.""" + + def __init__(self, includepath_map, directory_map, realpath_map): + """Constructor. + Arguments: + includepath_map: the map used to construct the includepath_idx + that will be passed in as arguments to Lookup(). + directory_map: the map used to construct both the currdir_idx + and searchdir_idx that will be passed in as arguments to + Lookup(). It's also the data structure that produces dir_idx. + realpath_map: a string-to-int map of canonicalized filepaths + """ + self.includepath_map = includepath_map + self.directory_map = directory_map + self.realpath_map = realpath_map + self.cache = {} + + def Lookup(self, currdir_idx, searchdir_idx, includepath_idx): + """Return the directory and realpath indices of the dirname of the input. + + Arguments: + currdir_idx: the directory index of the current directory + searchdir_idx: a directory_map index + includepath_idx: an includepath index + Returns: + a pair (directory map index, realpath index) + + See class documentation. + + Example: if the strings of the arguments indices put together make + '/usr/include/foo/bar.h', then this routine will insert '/usr/include/foo/' + into self.directory_map, and then return the corresponding pair (directory + index of /usr/include/foo/, real path index of /usr/include/foo/). If the + arguments put together form "foo.h", then the directory index returned is + that of "", the current directory, and the realpath index is that of + currdir. + """ + try: + return self.cache[(currdir_idx, searchdir_idx, includepath_idx)] + except KeyError: + directory = os.path.dirname(os.path.join( + self.directory_map.string[searchdir_idx], + self.includepath_map.string[includepath_idx])) + dir_idx = self.directory_map.Index(directory) + rp_idx = self.realpath_map.Index( + os.path.join(self.directory_map.string[currdir_idx], + directory)) + self.cache[(currdir_idx, searchdir_idx, includepath_idx)] = (dir_idx, + rp_idx) + return (dir_idx, rp_idx) + + +class SystemdirPrefixCache(object): + """A cache of information about whether a file exists in a systemdir. + + A systemdir is a searchdir that is built in to the C/C++ + preprocessor. That is, when the preprocessor is figuring out what + directory an #include is in, these are the directories it's + hard-coded in to check (you can add other directories via -I). This + cache records, for a given filepath, whether it starts with a + systemdir. This is useful to identify whether the path is likely to + correspond to a system include-file (such as stdio.h). Such files are + unlikely to change, and are likely to already exist on the distcc + servers, both of which are useful things to know for optimization. + + For speed, users can access self.cache directly, rather than going + through the StartsWithSystemdir API. Be sure to call FillCache() to + make sure the cache is populated, before accessing it! + """ + + def __init__(self, systemdirs): + """Constructor. + + Argument: + systemdirs: the list of system-directories the preprocessor + uses. It's a list of strings, probably extracted from the + preprocessor itself. Each systemdir should end in a slash. + + In practice, systemdirs will start empty, and later some routine + (in parse_command.py) will magically fill it. So be sure to wait + for that before calling FillCache! + TODO(csilvers): normalize this; ideally pass systemdirs in to FillCache. + """ + self.systemdirs = systemdirs + # self.cache[i] will be True, False, or None for not-yet-checked. + self.cache = [None] + + def FillCache(self, realpath_map): + """Ensures that there's a cache entry for every index in realpath_map. + + Argument: + realpath_map: a string-to-int map of canonicalized filepaths we know. + + After this function is called, the cache entry is True iff + realpath.startswith(systemdir) is True for any of the systemdirs + passed in to our constructor. + """ + if len(self.cache) >= realpath_map.Length(): + return # we're already all full + for realpath_idx in xrange(len(self.cache), realpath_map.Length()): + realpath = realpath_map.string[realpath_idx] + for systemdir in self.systemdirs: + if realpath.startswith(systemdir): + self.cache.append(True) + break + else: # we get here if the for never 'break'ed + self.cache.append(False) + + assert len(self.cache) == realpath_map.Length() + + def StartsWithSystemdir(self, realpath_idx, realpath_map): + """Return True iff realpath starts with a systemdir. + + Arguments: + realpath_idx: the index of the realpath we want to check. + realpath_map: the map from realpath_idx to a string. + + Return True iff realpath.startswith(systemdir) for any of the + systemdirs passed in to our constructor. (For speed, you can + access self.cache directly instead of calling this, but make + sure FillCache() has been called first!) + """ + self.FillCache(realpath_map) + return self.cache[realpath_idx] + + +#### +#### MAP_TO_INDEX AND ITS SPECIALIZATIONS +#### + +class MapToIndex(object): + """Maps every object it sees to a unique small integer. In + practice, this class is used to map path-components (which are strings). + """ + + def __init__(self): + """Constructor. + + Instance variables: + map: a dictionary such that map[path] is the index of path + string: a list satisfying: string[i] is the path such that map[path] = i + """ + + # Do not make the mistake of letting a real index be 0. (Hint: + # because "if path:" then does not distinguish between 0 and None.) + self.index = {None:None} + self.string = [None] + + def _Invariant_(self): + return len(self.index) == len(self.string) + + def Index(self, path): + """Returns the index i > 0 of path.""" + assert self._Invariant_() + try: + return self.index[path] + except KeyError: + self.index[path] = len(self.string) + self.string.append(path) + return len(self.string) - 1 + + def String(self, i): + """Returns the path such that Index(path) == i.""" + assert self._Invariant_() + assert 0 < i < self.Length() + return self.string[i] + + def Length(self): + """One more than the number of elements indexed.""" + assert self._Invariant_() + return len(self.string) + + +class DirectoryMapToIndex(MapToIndex): + """Like a normal MapToIndex, but assumes the keys are directories, + and in particular, directories without a trailing slash (eg "/etc"). + It stores the directories in the map, but appends the trailing slash + first. This is another type of normalization, and useful for cheap + path-joining (eg using + instead of os.path.join). + """ + + def Index(self, directory): + """Return index d > 0 of normalized directory. + Argument: + directory: a string, either empty or not ending in '/'. + + The empty string is not changed, but other strings are stored with + a '/' appended. + """ + if directory != "" and directory != "/": + assert directory[-1] != '/', directory + directory = directory + '/' + return MapToIndex.Index(self, directory) + + +class RelpathMapToIndex(MapToIndex): + """Like a normal MapToIndex, but assumes the keys are relative + filesystem paths, that is, filesystem paths not starting with /. + This is useful for "cheap" normalization: this invariant ensures that + os.path.join(some-directorymap-string, some-relpathmap-string) can + be implemented using +. + """ + + def Index(self, relpath): + """Return index d > 0 of relative path. + Argument: + directory: a string not starting with /. + """ + if os.path.isabs(relpath): + raise NotCoveredError("Filepath must be relative but isn't: '%s'." % + relpath, + send_email=False) + # Now, remove leading "./" so as not to start an infinite regression when + # say foo.c contains: + # + # #include "./foo.c" + # + # which mighy seduce a recursive include analyzer down the forbidden path: + # + # "foo.c", # "./foo.c", "././foo.c." etc. + while relpath.startswith("./"): + relpath = relpath[2:] + return MapToIndex.Index(self, relpath) + + +class CanonicalMapToIndex(MapToIndex): + """Like a normal MapToIndex, but assumes the keys are absolute + filepaths, and canonicalizes them before inserting into the map. + 'Canonicalize' means to do the equivalent of os.path.realpath(), + which mostly involves resolving symlinks in the filepath. + """ + + def __init__(self, canonicalize): + """Constructor. + Argument: + canonicalize: an instance of the CanonicalPath cache.""" + MapToIndex.__init__(self) + self.canonicalize = canonicalize + + def Index(self, filepath): + """Return the realpath index r of filepath. filepath should be + an absolute filename. + """ + return MapToIndex.Index(self, self.canonicalize(filepath)) + + +def RetrieveDirectoriesExceptSys(directory_map, realpath_map, + systemdir_prefix_cache, directory_idxs): + """Calculate the set of non-system directories of an index list. + + Arguments: + directory_map: a DirectoryMapToIndex cache + realpath_map: a CanonicalMapToIndex cache + directory_idxs: a list or tuple of directory_map indices + Returns: + the corresponding tuple of directories except for those whose + realpath has a prefix that is a sysdir + + The directories in the returned list have their trailing '/' + stripped. + """ + result = [] + for dir_idx in directory_idxs: + # Index the absolute path; this will let us know whether dir_idx is under a + # default systemdir of the compiler. + rp_idx = realpath_map.Index(os.path.join( + os.getcwd(), directory_map.string[dir_idx])) + systemdir_prefix_cache.FillCache(realpath_map) + if not systemdir_prefix_cache.cache[rp_idx]: + result.append(directory_map.string[dir_idx].rstrip('/')) + return tuple(result) + + +#### +#### THE STAT CACHES +#### + +class SimpleBuildStat(object): + """Stat cache that works with strings, not indices.""" + + def __init__(self): + self.cache = {} + + def Lookup(self, filepath): + """Returns true if filepath exists.""" + try: + return self.cache[filepath] + except KeyError: + result = self.cache[filepath] = _OsPathExists(filepath) + return result + + +class BuildStatCache(object): + """A highly optimized mechanism for stat queries of filepaths, + as represented by a triple of indexes: currdir_idx, searchdir_idx, + filepath_idx. Given this input, we can say whether a regular file + represented by this triple exists on the filesystem, and if so, + what its canonical pathname is: that is, the pathname after all + symlinks have been resolved. + + The hash table is three-level structure: + - build_stat[currdir_idx] contains an array for each includepath_idx + - build_stat[currdir_idx][includepath_idx] is this array, and + - build_stat[currdir_idx][includepath_idx][searchdir_idx] is either + * False if os.path.join(currdir, searchdir, includepath) does not exist + * True if it does + * None when it is not known whether it exists or not + In addition, we keep a parallel structure for the realpath, that lets us + quickly map from a filepath to os.path.realpath(filepath). + - real_stat[currdir_idx] contains an array for each fp + - real_stat[currdir_idx][includepath_idx] is this array, and + - real_stat[currdir_idx][includepath_idx][searchdir_idx] is either + * realpath_idx, such that realpath_map.string[realpath_idx] = + os.path.realpath(os.path.join(currdir, searchdir, includepath)) + when build_stat[currdir_idx][includepath_idx][searchdir_idx] = True + * None, otherwise + """ + + def __init__(self, includepath_map, directory_map, realpath_map): + self.build_stat = {} + self.real_stat = {} + self.includepath_map = includepath_map + self.directory_map = directory_map + self.realpath_map = realpath_map + self.bad_realpath_tuples = [] + + def _Verify(self, currdir_idx, searchdir_idx, includepath_idx): + """Verify that the cached result is the same as obtained by stat call. + Prerequisite: we've done a chdir(currdir) before this call. + """ + assert 1 <= includepath_idx < self.includepath_map.Length() + assert 1 <= searchdir_idx < self.directory_map.Length() + if __debug__: statistics.sys_stat_counter += 1 + + # Since we know directory_map entries end in /, and includepaths don't + # start with / (who does "#include </usr/include/string.h>"??), we can + # use + instead of the more expensive os.path.join(). + # Make sure $PWD is currdir, so we don't need to include it in our stat(). + assert os.getcwd() + '/' == self.directory_map.string[currdir_idx] + really_exists = _OsPathIsFile( + self.directory_map.string[searchdir_idx] + + self.includepath_map.string[includepath_idx]) + cache_exists = self.build_stat[currdir_idx][includepath_idx][searchdir_idx] + assert isinstance(cache_exists, bool) + if cache_exists != really_exists: + filepath = os.path.join(self.directory_map.string[currdir_idx], + self.directory_map.string[searchdir_idx], + self.includepath_map.string[includepath_idx]) + sys.exit("FATAL ERROR: " + "Cache inconsistency: '%s' %s, but earlier this path %s." % ( + filepath, + really_exists and "exists" or "does not exist", + cache_exists and "existed" or "did not exist")) + + def GetAndClearBadResolutions(self): + """Return descriptions of resolutions matching realpath warning regexp. + Returns: + a list of tuples of the form + (include_path, resolved_path, real_path) + where include_path is the argument of an #include (or an initial file), + resolved_path is the concatenation of the searchdir where the + include_path is found with this include_path, and real_path is the + realpath of this location (relative to the current directory). + The list is reset to [] with this operation. Thus the items returned are + those that occcurred since the last time this method was invoked. + """ + bad_realpath_tuples = self.bad_realpath_tuples + self.bad_realpath_tuples = [] + return bad_realpath_tuples + + def Resolve(self, includepath_idx, currdir_idx, searchdir_idx, + searchlist_idxs): + """Says whether (currdir_idx, searchdir_idx, includepath_idx) exists, + and if so what its canonicalized form is (with symlinks resolved). + TODO(csilvers): rearrange the order of the arguments. + + Args: + includepath_idx: The index of an includepath, from e.g. "#include <foo>" + currdir_idx: The index of the current working dir. Note that we + require os.getcwd() == currdir before calling Resolve! + searchdir_idx: A single searchdir, which is prepended to searchlist, + or None to not prepend to the searchlist. + searchlist_idxs: A list of directory indices. + + Returns: + 1) (None, None) if, for all sl_idx in [searchdir_idx] + searchlist_idxs, + os.path.join(currdir, sp, includepath) does not exist. + 2) ((sl_idx, includepath_idx), realpath_idx) + if, for some sl_idx in [searchdir_idx] + searchlist_idxs, + os.path.join(currdir, sp, includepath) does exist. In this case, + sl_idx is the index of the first searchlist entry for which the + exists-test succeeds, and realpath_idx is the index into the + realpath_map of os.path.join(currdir, sp, includepath). + + Again, we require as a prequesite that os.getcwd() must equal currdir: + os.getcwd() + '/' == self.directory_map.string[currdir_idx] + """ + includepath = self.includepath_map.string[includepath_idx] + dir_map_string = self.directory_map.string # memoize the fn pointer + build_stat = self.build_stat + real_stat = self.real_stat + if __debug__: + dir_map = self.directory_map + assert 0 < includepath_idx < self.includepath_map.Length() + assert 0 < currdir_idx < dir_map.Length() + assert searchdir_idx is None or 1 <= searchdir_idx < dir_map.Length() + for sl_idx in searchlist_idxs: + assert sl_idx < dir_map.Length() + assert os.getcwd() + '/' == dir_map_string[currdir_idx], ( + "'%s/' != '%s'" % (os.getcwd(), dir_map_string[currdir_idx])) + Debug(DEBUG_TRACE2, "Resolve: includepath: '%s', currdir: '%s', " + "searchdir: '%s', searchlist: %s" % + (includepath, + dir_map_string[currdir_idx], + searchdir_idx and dir_map_string[searchdir_idx], + " \n".join([dir_map_string[idx] for idx in searchlist_idxs]))) + try: + # Locate the array (list) relative to currdir_idx and includepath_idx + searchdir_stats = build_stat[currdir_idx][includepath_idx] + # Locate the corresponding array of realpath names + searchdir_realpaths = real_stat[currdir_idx][includepath_idx] + except KeyError: # We'll need to grow the relevant arrays + currdir_stats = build_stat.setdefault(currdir_idx, {}) + currdir_realpaths = real_stat.setdefault(currdir_idx, {}) + searchdir_stats = currdir_stats[includepath_idx] = \ + [None] * DIR_ARRAY_SIZE + searchdir_realpaths = currdir_realpaths[includepath_idx] = \ + [None] * DIR_ARRAY_SIZE + + # Try searchdir_idx if not None, then try every index in searchlist_idxs. + # This inner loop may be executed tens of millions of times. + # Do not try to form [searchdir_idx] + searchlist_idxs -- too expensive! + for searchlist in (searchdir_idx and [searchdir_idx] or [], + searchlist_idxs): + for sl_idx in searchlist: + if __debug__: + statistics.search_counter += 1 + statistics.build_stat_counter += 1 + try: + # We expect that searchdir_stats[sl_idx] == False, because + # we've usually seen sl_idx before for our includepath and + # our currdir --- and includepath does not usually exist + # relative to the sp directory. We're optimizing for this + # case of course. That should give us a rate of a couple of + # million iterations per second (for this case). + if searchdir_stats[sl_idx] == False: + if __debug__: self._Verify(currdir_idx, sl_idx, includepath_idx) + continue + if searchdir_stats[sl_idx]: + if __debug__: self._Verify(currdir_idx, sl_idx, includepath_idx) + return ((sl_idx, includepath_idx), searchdir_realpaths[sl_idx]) + except IndexError: # DIR_ARRAY_SIZE wasn't big enough; let's double + searchdir_stats.extend([None] * max(sl_idx, len(searchdir_stats))) + searchdir_realpaths.extend([None] * max(sl_idx, len(searchdir_stats))) + + # If we get here, result is not cached yet. + if __debug__: statistics.sys_stat_counter += 1 + # We do not explictly take into account currdir_idx, because + # of the check above that os.getcwd is set to current_dir. + relpath = dir_map_string[sl_idx] + includepath + if _OsPathIsFile(relpath): + searchdir_stats[sl_idx] = True + rpath = os.path.join(dir_map_string[currdir_idx], relpath) + realpath_idx = searchdir_realpaths[sl_idx] = ( + self.realpath_map.Index(rpath)) + # This is the place to catch errant files according to user defined + # abspath_warning option. See documentation for method + # GetAndClearBadResolutions. + if basics.opt_realpath_warning_re: + realpath = self.realpath_map.string[realpath_idx] + if basics.opt_realpath_warning_re.search(realpath): + self.bad_realpath_tuples.append((includepath, relpath, realpath)) + return ((sl_idx, includepath_idx), realpath_idx) + else: + searchdir_stats[sl_idx] = False + + if __debug__: Debug(DEBUG_TRACE2, "Resolve: failed") + return (None, None) + + +class SetUpCaches(object): + """Erect the edifice of caches. + + Instance variables: + includepath_map: RelpathMapToIndex + directory_map: DirectoryMapToIndex + realpath_map: CanonicalMapToIndex + + canonical_path: CanonicalPath + build_stat_cache: BuildStatCache + dirname_cache: DirnameCache + simple_build_stat: SimpleBuildStat + + IsFilepathIndex: test for filepath index + IsDirectoryIndex: test for director index + IsRealpathIndex: test for realpath index + IsFilepathPair: test for filepath pair + """ + + def __init__(self): + # A memoizing (caching) class to canonicalize a path: mostly by + # resolving any symlinks in the path-component. + self.canonical_path = CanonicalPath() + + # The index-map for includepath names: things seen after '#include'. + self.includepath_map = RelpathMapToIndex() + + # The index-map for searchdir names and currdir as well. Also used any + # other time we have something we know is a directory (eg dirname(foo)). + self.directory_map = DirectoryMapToIndex() + + # The index-map for realpaths: the full pathname of an include, with + # symlinks resolved and such (hence the name realpath). + self.realpath_map = CanonicalMapToIndex(self.canonical_path.Canonicalize) + + # A cache of the directory part of filepaths. Note it uses the + # directory_map to actually store the mapping. + self.dirname_cache = DirnameCache(self.includepath_map, self.directory_map, + self.realpath_map) + + # A cache of whether a realpath starts with a system searchdir or + # not. Note: at this time, system_dirs_default_all will be empty. + # It will get filled via processing in parse_command.py. This is + # why we need to store the compiler_defaults instance, to make + # sure "our" system_dirs_default_all is updated. + # TODO(csilvers): get rid of this once prefix_cache TODO is cleaned up + self.compiler_defaults = compiler_defaults.CompilerDefaults( + self.canonical_path.Canonicalize) + self.systemdir_prefix_cache = SystemdirPrefixCache( + self.compiler_defaults.system_dirs_default_all) + + # The main caches, that say whether a file exists or not. We have + # two: a simple one that takes a filepath (string) as an argument, + # and the complicated one that works with index-triples. + self.simple_build_stat = SimpleBuildStat() + self.build_stat_cache = BuildStatCache(self.includepath_map, + self.directory_map, + self.realpath_map) + + # Convenient function closures to test for various semantic datatypes. + self.IsIncludepathIndex = (lambda x: + isinstance(x, int) + and 0 < x < self.includepath_map.Length()) + + self.IsSearchdirIndex = (lambda x: + isinstance(x, int) + and 0 < x < self.directory_map.Length()) + + self.IsCurrdirIndex = (lambda x: + isinstance(x, int) + and 0 < x < self.directory_map.Length()) + + self.IsFilepathPair = (lambda x: + isinstance(x, tuple) + and len(x) == 2 + and self.IsSearchdirIndex(x[0]) + and self.IsIncludepathIndex(x[1])) + + self.IsRealpathIndex = (lambda x: + isinstance(x, int) + and 0 < x < self.realpath_map.Length()) diff --git a/include_server/compiler_defaults.py b/include_server/compiler_defaults.py new file mode 100755 index 0000000..2e039ae --- /dev/null +++ b/include_server/compiler_defaults.py @@ -0,0 +1,180 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +"""Divination of built-in system directories used by compiler installation. + +It is undesirable for the distcc-pump to send header files that reside +under the built-in search path. In a correct compiler installation, +these files must already be present on the server. This module lets +the distcc-pump run the compiler in a special mode that allows the +built-in system directories to be revealed. + +The current code is tested only for gcc 4.1.1. + +TODO(klarlund) Find out what other versions this code works for. +TODO(klarlund) The include server halts if the built-in system +directories cannot be determined. Should this be improved upon? +""" + +__author__ = "Nils Klarlund" + + +import re +import sys +import basics +import subprocess + +Debug = basics.Debug +DEBUG_TRACE = basics.DEBUG_TRACE +DEBUG_DATA = basics.DEBUG_DATA +NotCoveredError = basics.NotCoveredError + + +def _SystemSearchdirsGCC(compiler, language, canonical_lookup): + """Run gcc on empty file; parse output to figure out default paths. + + Arguments: + compiler: a filepath (the first argument on the distcc command line) + language: 'c' or 'c++' or other item in basics.LANGUAGES + canonical_lookup: a function that maps strings to their realpaths + Returns: + list of system search dirs for this compiler and language + + """ + + # We are trying to wring the following kind of text out of the + # compiler: + #-------------------- + # blah. blah. + # ... + # blah. blah. + # #include "..." search starts here: + # #include <...> search starts here: + # /usr/local/include + # /usr/lib/gcc/i486-linux-gnu/4.0.3/include + # /usr/include + # End of search list. + # blah. blah. + #------------ + + command = [compiler, "-x", language, "-v", "-c", "/dev/null", "-o", + "/dev/null"] + + try: + # We annul the environment, because otherwise, directories declared by + # CPATH, for example, will be incorporated into the result. (See the CPP + # manual for the meaning of CPATH.) + p = subprocess.Popen(command, + shell=False, + stdin=None, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + env={}) + out = p.communicate()[0] + except (IOError, OSError), why: + raise NotCoveredError ( + ( "Couldn't determine default system include directories\n" + + "for compiler '%s', language '%s':\n" + + "error executing '%s': %s.") + % (compiler, language, command, why)) + + if p.returncode != 0: + raise NotCoveredError( + ( "Couldn't determine default system include directories\n" + + "for compiler '%s', language '%s':\n" + + "command '%s' exited with status '%d'.\n Command output:\n%s") % + (compiler, language, command, p.returncode, out)) + + match_obj = re.search( + r"%s\n(.*?)\n%s" # don't ask + % ("#include <...> search starts here:", "End of search list"), + out, + re.MULTILINE + re.DOTALL) + if match_obj == None: + raise NotCoveredError( + ( "Couldn't determine default system include directories\n" + + "for compiler '%s', language '%s':\n" + + "couldn't parse output of '%s'.\nReceived:\n%s") % + (compiler, language, command, out)) + return [ canonical_lookup(directory) + for directory in match_obj.group(1).split() ] + + +class CompilerDefaults(object): + """Records and caches the default searchdirs, aka include directories + or search-path. The 'default' searchdirs are those built in to the + preprocessor, as opposed to being set on the commandline via -I et al. + + This scheme works only for gcc, and only some versions at that. + """ + + def __init__(self, canonical_lookup): + """Constructor. + + Instance variables: + system_dirs_real_paths: a dictionary such that + system_dirs_real_paths[c][lang] is a list of directory paths + (strings) for compiler c and language lang + system_dirs_default: a list of all such strings, subjected to + realpath-ification, for all c and lang + """ + self.canonical_lookup = canonical_lookup + self.system_dirs_default_all = set([]) + self.system_dirs_default = {} + + + def SetSystemDirsDefaults(self, compiler, timer=None): + """Set instance variables according to compiler. + + Arguments: + compiler: a string "c", "c++",... + timer: a basis.IncludeAnalyzerTimer or None + + The timer will be disabled during this routine because the select involved + in Popen calls does not handle SIGALRM. + + See also the constructor documentation for this class. + """ + assert isinstance(compiler, str) + Debug(DEBUG_TRACE, "SetSystemDirsDefauls with CC: %s" % compiler) + if compiler in self.system_dirs_default: return + try: + if timer: + # We have to disable the timer because the select system call that is + # executed when calling the compiler through Popen gives up if presented + # with a SIGALRM. + timer.Stop() + self.system_dirs_default[compiler] = {} + # Try 'c', 'c++', ... + for language in basics.LANGUAGES: + self.system_dirs_default[compiler][language] = ( + _SystemSearchdirsGCC(compiler, language, self.canonical_lookup)) + Debug(DEBUG_DATA, + "system_dirs_default[%s][%s]: %s" % + (compiler, language, + self.system_dirs_default[compiler][language])) + # Now summarize what we know and add to system_dirs_default_all. + self.system_dirs_default_all |= set( + [ _default + for _compiler in self.system_dirs_default + for _language in self.system_dirs_default[_compiler] + for _default in self.system_dirs_default[_compiler][_language] ]) + finally: + if timer: + timer.Start() diff --git a/include_server/compress_files.py b/include_server/compress_files.py new file mode 100755 index 0000000..133eb5f --- /dev/null +++ b/include_server/compress_files.py @@ -0,0 +1,112 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +"""Compress files in an include closure.""" + +import os +import sys +import os.path + +import distcc_pump_c_extensions + +class CompressFiles(object): + + def __init__(self, includepath_map, directory_map, realpath_map): + """Constructor. + + Arguments: + includepath_map: MapToIndex, holds idx-to-string info for includepaths + directory_map: DirectoryMapToIndex + realpath_map: CanonicalMapToIndex + """ + self.includepath_map = includepath_map + self.directory_map = directory_map + self.realpath_map = realpath_map + # The realpath_map indices of files that have been compressed already. + self.files_compressed = set([]) + + def Compress(self, include_closure, client_root): + """Copy files in include_closure to the client_root directory, compressing + them as we go, and also inserting #line directives. + + Arguments: + include_closure: a dictionary, see IncludeAnalyzer.RunAlgorithm + client_root: a directory name, see basics.py, the directory to which + compressed files are mirrored + Returns: a list of filepaths under client_root + + Walk through the files in the include closure. Make sure their compressed + images (with either .lzo or lzo.abs extension) exist under client_root. Also + collect all the .lzo or .lzo.abs filepaths in a list, which is the return + value. + """ + realpath_string = self.realpath_map.string + files = [] # where we accumulate files + + for realpath_idx in include_closure: + # Thanks to symbolic links, many absolute filepaths may designate + # the very same canonical path (as calculated by realpath). The + # first such one to be discovered is the one used. + realpath = realpath_string[realpath_idx] + if len(include_closure[realpath_idx]) > 0: + # Designate by suffix '.abs' that this file is to become known by an + # absolute filepath through a #line directive. + new_filepath = "%s%s.lzo.abs" % (client_root, realpath) + else: + new_filepath = "%s%s.lzo" % (client_root, realpath) + files.append(new_filepath) + if not new_filepath in self.files_compressed: + self.files_compressed.add(new_filepath) + dirname = os.path.dirname(new_filepath) + try: + if not os.path.isdir(dirname): + os.makedirs(dirname) + except (IOError, OSError), why: + # Kill include server + sys.exit("Could not make directory '%s': %s" % (dirname, why)) + if new_filepath.endswith('.abs'): + (searchdir_idx, includepath_idx) = include_closure[realpath_idx][0] + # TODO(csilvers): can't we use + here instead of os.path.join? + filepath = os.path.join(self.directory_map.string[searchdir_idx], + self.includepath_map.string[includepath_idx]) + # This file is included through say -I/foo, but /foo does not exist + # on the compiler server. Instead, this file will put under some + # /serverrootpath/foo there. The #line directive informs the compiler + # about the real location. This is useful for error messages. + prefix = ("""#line 1 "%s"\n""" % filepath) + else: + # This file will be relatively resolved on the served. No need to + # change its name. + prefix = "" + try: + real_file_fd = open(realpath, "r") + except (IOError, OSError), why: + sys.exit("Could not open '%s' for reading: %s" % (realpath, why)) + try: + new_filepath_fd = open(new_filepath, "wb") + except (IOError, OSError), why: + sys.exit("Could not open '%s' for writing: %s" % (new_filepath, why)) + try: + new_filepath_fd.write( + distcc_pump_c_extensions.CompressLzo1xAlloc( + prefix + real_file_fd.read())) + except (IOError, OSError), why: + sys.exit("Could not write to '%s': %s" % (new_filepath, why)) + new_filepath_fd.close() + real_file_fd.close() + return files diff --git a/include_server/configure.ac b/include_server/configure.ac new file mode 100644 index 0000000..e9cdbe7 --- /dev/null +++ b/include_server/configure.ac @@ -0,0 +1,10 @@ +AC_INIT(distcc_pump_include_server, + esyscmd(source ../version.sh && echo -n $DISTCC_PUMP_VERSION), + distcc-pump@google.com) +AC_CHECK_PROGS(PYTHON, [python2.4 python2.3 python-2.3 python2.2 python-2.2 python]) +AC_ARG_VAR(PYTHON, [Python interpreter]) +AC_CONFIG_AUX_DIR(../distcc) +AC_CONFIG_FILES([Makefile]) +AC_PROG_INSTALL +AC_OUTPUT + diff --git a/include_server/include_analyzer.py b/include_server/include_analyzer.py new file mode 100755 index 0000000..4706d14 --- /dev/null +++ b/include_server/include_analyzer.py @@ -0,0 +1,362 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +"""The skeleton for an include analyzer. + +This module defines the basic caches and helper functions for an +include analyzer. +""" + +__author__ = "Nils Klarlund" + +import os +import glob + +import basics +import macro_eval +import parse_file +import parse_command +import statistics +import cache_basics +import mirror_path +import compress_files + +Debug = basics.Debug +DEBUG_TRACE = basics.DEBUG_TRACE +NotCoveredError = basics.NotCoveredError + +class IncludeAnalyzer(object): + """The skeleton, including caches, of an include analyzer.""" + + def _InitializeAllCaches(self): + # Make cache for parsed files. + self.file_cache = {} + # Make table for symbols in #define's. + self.symbol_table = {} + # Erect the edifice of caches. + caches = self.caches = cache_basics.SetUpCaches() + + # Migrate the cache stuff to self namespace. + self.includepath_map = caches.includepath_map + self.directory_map = caches.directory_map + self.realpath_map = caches.realpath_map + + self.canonical_path = caches.canonical_path + self.dirname_cache = caches.dirname_cache + self.compiler_defaults = caches.compiler_defaults + self.systemdir_prefix_cache = caches.systemdir_prefix_cache + + self.simple_build_stat = caches.simple_build_stat + self.build_stat_cache = caches.build_stat_cache + + self.IsIncludepathIndex = caches.IsIncludepathIndex + self.IsSearchdirIndex = caches.IsSearchdirIndex + self.IsCurrdirIndex = caches.IsCurrdirIndex + self.IsRealpathIndex = caches.IsRealpathIndex + self.IsFilepathPair = caches.IsFilepathPair + + # Make a cache for the symbolic links encountered; also for their + # replication into root directory. + self.mirror_path = mirror_path.MirrorPath(self.simple_build_stat, + self.canonical_path) + # Make a parser for C/C++. + self.parse_file = parse_file.ParseFile(self.includepath_map) + # Make a compressor for source files. + self.compress_files = compress_files.CompressFiles(self.includepath_map, + self.directory_map, + self.realpath_map) + # A fast cache for avoiding calls into the mirror_path object. + self.mirrored = set([]) + + # For statistics only. We measure the different search lists + # (search paths) by accumulating them all in sets. + self.quote_dirs_set = set([]) # quote search lists + self.angle_dirs_set = set([]) # angle searchlists + self.include_dir_pairs = set([]) # the pairs (quote search list, + # angle search lists) + + def __init__(self, stat_reset_triggers={}): + self.generation = 1 + basics.InitializeClientRoot(self.generation) + self.client_root = basics.client_root + self.stat_reset_triggers = stat_reset_triggers + self.translation_unit = "unknown translation unit" + self.timer = None + self.include_server_cwd = os.getcwd() + self._InitializeAllCaches() + + def _ProcessFileFromCommandLine(self, fpath, kind, search_list): + """Return closure of fpath whose kind is "translation unit" or "include". + Such files come from the command line, either as the file to compile, + or from a "-include" command line option. + Arguments: + fpath: a filepath (as a string) + kind: a string used for an error message if fpath is not found + search_list: a tuple of directory indices (for "include" kind files) + Returns: + an include closure calculated by RunAlgorithm + """ + # We allow the filepath to be absolute. We do not tolerate absolute + # includepaths, in general, and so must be careful here, because we use + # build_stat_cache.Resolve. We prepare to use the searchdir parameter of + # Resolve. + if os.path.isabs(fpath): + file_dirpath, file_filename = os.path.split(fpath) + else: + # Use empty string as directory name (offset from currdir) + file_dirpath, file_filename = "", fpath + fpath_resolved_pair, fpath_real = self.build_stat_cache.Resolve( + self.includepath_map.Index(file_filename), + self.currdir_idx, + self.directory_map.Index(file_dirpath), + search_list) + if fpath_resolved_pair == None: + raise NotCoveredError("Could not find %s '%s'." % (kind, fpath), + send_email=False) + closure = self.RunAlgorithm(fpath_resolved_pair, fpath_real) + return closure + + def ProcessCompilationCommand(self, currdir, parsed_command): + """Do the include analysis for parsed_command. + + Precondition: + currdir == os.getcwd() + + Arguments: + currdir: a string denoting an absolute filepath when command is run + parsed_command: the value returned by ParseCommandArgs + + Returns: + an include closure as described in RunAlgorithm + """ + + Debug(DEBUG_TRACE, "ProcessCompilationCommand: %s, %s" + % (currdir, parsed_command)) + + assert isinstance(currdir, str) + statistics.parse_file_counter_last = statistics.parse_file_counter + (self.quote_dirs, self.angle_dirs, + self.include_files, translation_unit, + self.result_file_prefix, self.d_opts) = parsed_command + + statistics.translation_unit = translation_unit + self.translation_unit = translation_unit + + self.currdir_idx = self.directory_map.Index(currdir) + + # Statistics only. + self.include_dir_pairs |= set([(self.quote_dirs, self.angle_dirs)]) + self.quote_dirs_set.add(self.quote_dirs) + self.angle_dirs_set.add(self.angle_dirs) + statistics.quote_path_total += len(self.quote_dirs) + statistics.angle_path_total += len(self.angle_dirs) + + total_closure = {} + for include_file in self.include_files: + total_closure.update( + self._ProcessFileFromCommandLine( + self.includepath_map.string[include_file], + "include file", + self.quote_dirs)) + total_closure.update(self._ProcessFileFromCommandLine(translation_unit, + "translation unit", + ())) + return total_closure + + def DoStatResetTriggers(self): + """Reset stat caches if a glob evaluates differently from earlier. + + More precisely, if a path of a glob comes in or out of existence or has a + new stamp, then reset stat caches.""" + + trigger_map = self.stat_reset_triggers + old_paths = [ path + for glob_expr in trigger_map + for path in trigger_map[glob_expr] ] + for glob_expr in trigger_map: + for path in glob.glob(glob_expr): + try: + old_paths.remove(path) + except ValueError: + pass + new_stamp = basics.Stamp(path) + if path in trigger_map[glob_expr]: + if new_stamp != trigger_map[glob_expr][path]: + Debug(basics.DEBUG_WARNING, + "Path '%s' changed. Clearing caches.", + path) + trigger_map[glob_expr][path] = new_stamp + self.ClearStatCaches() + return + else: + Debug(basics.DEBUG_WARNING, + "Path '%s' came into existence. Clearing caches.", + path) + trigger_map[glob_expr][path] = basics.Stamp(path) + self.ClearStatCaches() + return + if old_paths: + path = old_paths[0] + Debug(basics.DEBUG_WARNING, + "Path '%s' no longer exists. Clearing caches.", + path) + self.ClearStatCaches() + + def DoCompilationCommand(self, cmd, currdir): + """Parse and and process the command; then gather files and links.""" + + self.translation_unit = "unknown translation unit" # don't know yet + + # Any relative paths in the globs in the --stat_reset_trigger argument + # must be evaluated relative to the include server's original working + # directory. + os.chdir(self.include_server_cwd) + self.DoStatResetTriggers() + + # Now change to the distcc client's working directory. + # That'll let us use os.path.join etc without including currdir explicitly. + os.chdir(currdir) + + parsed_command = ( + parse_command.ParseCommandArgs(cmd, + currdir, + self.includepath_map, + self.directory_map, + self.compiler_defaults, + self.timer)) + (_, _, _, source_file, result_file_prefix, _) = parsed_command + + # Do the real work. + include_closure = ( + self.ProcessCompilationCommand(currdir, parsed_command)) + # Cancel timer before I/O in compress_files. + if self.timer: # timer may not always exist when testing + self.timer.Cancel() + # Get name of the initial source file + translation_unit = self.translation_unit + # Links are accumulated intra-build (across different compilations in a + # build). We send all of 'em every time. This will potentially lead to + # performance degradation for large link farms. We expect at most a + # handful. + links = self.mirror_path.Links() + files = self.compress_files.Compress(include_closure, basics.client_root) + realpath_map = self.realpath_map + + files_and_links = files + links + + if basics.opt_verify: + # Invoke the real preprocessor. + exact_no_system_header_dependency_set = ( + ExactDependencies(" ".join(cmd), + realpath_map, + self.systemdir_prefix_cache, + translation_unit)) + if basics.opt_write_include_closure: + WriteDependencies(exact_no_system_header_dependency_set, + self.result_file_prefix + '.d_exact', + realpath_map) + VerifyExactDependencies(include_closure, + exact_no_system_header_dependency_set, + realpath_map, + translation_unit) + if basics.opt_write_include_closure: + WriteDependencies(include_closure, + self.result_file_prefix + '.d_approx', + realpath_map) + return files_and_links + + def RunAlgorithm(self, filepath_resolved_pair, filepath_real_idx): + """Run FindNode on filepath; then compute include closure. + Arguments: + filepath_resolved_pair: (directory_idx, includepath_idx) + filepath_real: the realpath_map index corresponding to + filepath_resolved_pair + Returns: + include_closure: a dictionary. + + The include_closure consists of entries of the form + + realpath_idx: [(searchdir_idx_1, includepath_idx_1), + (searchdir_idx_2, includepath_idx_2), ...] + + where searchdir_i is an absolute path. realpath_idx is a realpath + index corresponding to a single #include (more exactly, it's the + index of the path that the #include resolves to). + + This include closure calculation omits any system header files, + that is, header files found in a systemdir (recall systemdirs are + those searchdirs that are built into the preprocessor, such as + "/usr/include"). It concentrates only on header files users might + edit. + + The keys are the most important part of the include_closure; the + values are used only to munge the preprocessor output to give more + useful filenames via the #line directive. The issue here is that + source files in the distcc system are not in their "proper" + locations: for instance, /usr/X11R6/include/X11.h might be in + /tmp/distcc/usr/X11R6/include/X11.h rather than in + /usr/X11R6/include. + + As the example above suggests, relative position of .h files is + preserved in distcc-land, so if the #include ends up being a + relative include, we do not need to do any munging, so we don't + bother to store anything in the value-list corresponding to + realpath_idx. If, however, the #include ends up being an absolute + include, we do store the "real" name (as an index-pair) in the + list. For debugging purposes, we may store more than one "real" + name if there are several, which can happen when multiple symlinks + point to the same place. + TODO(csilvers): change the code to only store one. + + Here's a concrete example: suppose we're trying to resolve + #include "bar.h", and the searchdir_list is ["reldir/foo", + "/usr/foo"]. If "<cwd>/reldir/foo/bar.h" exists, then + realpath_idx will resolve to that, and the preprocessor will emit + code like "#line 1 reldir/foo/bar.h". That's correct as-is, no + munging needed, so we don't bother to put a value in the + include_closure entry for this realpath. + + If, however, "<cwd>/reldir/foo/bar.h" does not exist, but + "/usr/foo/bar.h" exists, then realpath_idx will resolve to that, + and the preprocessor will emit code like "#line 1 + /tmp/distcc/usr/foo/bar.h". We'll want to munge that to be + "/usr/foo/bar.h", so we do put a value in the include_closure + entry for this realpath, to tell us what to munge to. + + (Note we *could* use realpath to tell us the "real" filename, + without needing a separate index-pair, but that's not as + user-friendly, since realpath is the filename after symlinks are + resolved. Thus, on some setups the realpath of /usr/foo/bar.h + could be /netapp1/mnt/foo/bar.h or something equally unhelpful.) + + This method to be overridden by derived class. + """ + + raise Exception, "RunAlgorithm not implemented." + + def ClearStatCaches(self): + """Clear caches used for, or dependent on, stats.""" + self.generation += 1 + # Tabula rasa: for this analysis, we must forget everything recorded in the + # client_root directory about source files, directories, and symbolic links. + # But we cannot delete any such information, because slow-poke distcc + # clients that have received earlier include manifests perhaps only now get + # around to reading a previous generation client root directory. + basics.InitializeClientRoot(self.generation) + self.client_root = basics.client_root + self._InitializeAllCaches() diff --git a/include_server/include_analyzer_memoizing_node.py b/include_server/include_analyzer_memoizing_node.py new file mode 100755 index 0000000..7a917b4 --- /dev/null +++ b/include_server/include_analyzer_memoizing_node.py @@ -0,0 +1,641 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +"""A graph-based algorithm for memoizing include closure calculations.""" + +__author__ = "Nils Klarlund" + +# TODO(klarlund) For computed includes, some static analysis checks must be +# introduced to verify soundness of node reutilization in FindNode. + +import os + +import basics +import macro_eval +import parse_file +import statistics +import include_analyzer + +Debug = basics.Debug +DEBUG_TRACE = basics.DEBUG_TRACE +DEBUG_DATA = basics.DEBUG_DATA +NotCoveredError = basics.NotCoveredError + +# RESOLUTION MODES + +RESOLVED = 1 # filepath already resolved and denotes an existing file +QUOTE = 2 # filepath to be resolved against quote directories +ANGLE = 3 # filepath to be resolved against angle directories +NEXT = 4 # filepath to be resolved against each and every quote + # directory; this is how we handle #include_next +RESOLUTION_MODES = [ RESOLVED, QUOTE, ANGLE, NEXT ] +# Textual representation of RESOLUTION_MODES. +RESOLUTION_MODES_STR = [ None, 'RESOLVED', 'QUOTE', 'ANGLE', 'NEXT' ] + + +# MAIN COURSE + +class UnionCache(object): + """Frozen sets and their unions, represented by integers. + + Frozensets are Python's immutable and hashable sets. We hash them into set + ids, which are integers. That allows us to cache union operations efficiently. + """ + + def __init__(self): + """Constructor: + Instance variables: + members: members[set_id] = frozenset([s1,..., sn]), the members of the set + cache: cache[(set1_id, set2_id)] = the id of the union of set1 and set2 + id_map: the set of frozen sets we have seen mapped to {1, 2, ..} + """ + self.members = {} + self.cache = {} + self.id_map = {} + + def SetId(self, members): + """Memoize the frozenset of members and return set id.""" + frozen = frozenset(members) + try: + return self.id_map[frozen] + except KeyError: + self.id_map[frozen] = len(self.id_map) + 1 + self.members[len(self.id_map)] = frozen + return len(self.id_map) + + def Elements(self, set_id): + """The frozenset corresponding to a set id.""" + return self.members[set_id] + + def Union(self, set1_id, set2_id): + """Return the set id of the union of sets represented by set ids.""" + try: + return self.cache[(set1_id, set2_id)] + except KeyError: + frozen = self.members[set1_id] | self.members[set2_id] + frozen_id = self.SetId(frozen) + self.cache[(set1_id, set2_id)] = frozen_id + return frozen_id + + +class SupportRecord(object): + """Record the symbols that expressions depend on. + + A support record is an object that contains a mutable support set of symbols. + Each node in the summary graph is associated with a support record. It is the + set of symbols upon which the included computes depend. A support record is + initially deemed valid. If a symbol is redefined, then it becomes invalid. + For efficiency, the valid field is sometimes explicitly handled by a user of + this object. + """ + + def __init__(self, support_master): + """Constructor. + Argument: + support_master: a record for holding the reverse mapping from symbols to + support records that contain them. + Instance Variables: + support_master: see above + union_cache: a union cache for set manipulation + support_id: the id of a set in union_cache; the set consists of all + symbols referenced by computed includes in any include + dependency of the node to which the support record belongs + valid: a Boolean + """ + self.support_master = support_master + self.valid = True + self.union_cache = support_master.union_cache + self.support_id = self.union_cache.SetId([]) + + def Update(self, set_id): + """Augment the support record with the set represented by set_id. + """ + union_id = self.union_cache.Union(self.support_id, + set_id) + if union_id != self.support_id: + self.support_master.SupportRecordDependencyAdd( + self.union_cache.Elements(set_id), + self) + self.support_id = union_id + + def UpdateSet(self, symbols): + """Add symbols to the support. + + This function is similar to Update, but the argument is a list of elements. + """ + self.Update(self.union_cache.SetId(symbols)) + + +class SupportMaster(object): + """Record the support records that depend on a given symbol. + + A map symbol_to_records is maintained. For each symbol s + self.symbol_to_records[s] is the set of support records r whose support set + contains s.""" + + def __init__(self): + """Constructor. + + Instance variables: + symbol_to_records: a mapping to record sets + union_cache: a UnionCache for memoizing sets and their unions + """ + self.symbol_to_records = {} + self.union_cache = UnionCache() + + def SupportRecordDependencyAdd(self, symbols, support_record): + """Add dependency of support record on symbol.""" + for symbol in symbols: + if symbol not in self.symbol_to_records: + self.symbol_to_records[symbol] = set([]) + self.symbol_to_records[symbol].add(support_record) + + def InvalidateRecords(self, symbol): + """Mark as invalid all support records whose set contains symbol.""" + if symbol in self.symbol_to_records: + for support_record in self.symbol_to_records[symbol]: + support_record.valid = False + + +class IncludeAnalyzerMemoizingNode(include_analyzer.IncludeAnalyzer): + """A memoizing algorithm for include analysis based on a graph construction. + + Instance variables: + + master_cache: a two-level node cache + + The key of the top-level cache is an include configuration of the form + (currdir_idx, quote_dirs, angle_dirs) + + The value of the top-level cache is a node-cache (defined next). + + The key of the second-level (node) cache has the form + (filepath_idx, resolution_mode, file_dir_idx) + + A node is the value of the second-level (node) cache. It has the form + [filepath_real_idx, filepath_resolved_pair, [node_0, ...node_n-1], + support_record] + + where each node_i, for 1 <= i < n, is a node representing a direct include + dependency of node. The direct include dependencies are the edges of a + directed graph called the summary graph. + + TODO(csilvers): document what the values of the node-cache mean. + + In this class, the top-level key is referred to as 'incl_config', the + top-level value is referred to as 'node_cache_for_incl_config', the + second-level key is referred to as 'key', and the second-level value is + referred to as 'node'. + + There are many disjoint summary graphs, one for each include configuration. + Each node of a summary graph is the image of a key, that is, there are values + incl_config and key such that node == master_cache[incl_config][key]. + + As stated the node cache works pre-resolution. But it may well be that, say, + two occurrences of #include "foo.h" in files with different file directories + (that is, the files containing the foo.h includes are in different + directories) actually resolve to the same foo.h file. In that case, we should + reuse the foo.h node -- with a catch: all though the file may be the same + real file, their containing directories may be different. For example, the + file may be in the real location /D/foo.h, but it may also be known as + /E/foo.h, where E is a directory containing a symbolic link foo.h pointing to + /D/foo.h. If file foo.h has a quoted include of bar.h, that is, contains the + directive + + #include "bar.h" + + then bar.h is looked for in /D if the file directory is /D, but it is looked + for in /E if the file directory is /E. That is the real file directory of + /E/foo.h is *not* the directory component of the realpath of /E/foo.h. + Rather, it is the realpath of the directory component of /E/foo.h, that is, + the realpath of /E. + + Thus, if we memoize files according to their real location, then the file + directory as understood above must also be taken into account. + + In particular, we also use as keys pairs of the form: + + (realpath index of resolved file, real path index of filedir). + + This realpath-oriented memoization is not a frivolous attempt at optimization. + It is essential to avoiding infinite loops as in: + + D/mem.h + D/../D/mem.h + D/../D/../D/mem.h + + generated by an include of the form "#include ../D/mem.h" in file mem.h. + + One would think that obviosly these prefixes denote the same location. But + they need not! For D of the first line could be a symbolic link to a real + directory dir1_D. And, the second D could be another symbolic link in + dir1_D/ to dir2_D, etc... + + So, when the include processor is lead astray by includes that resolve this + way it is by no means obvious how to investigate the paths with symbolic links + of the form + + (D/..)* + + This will diverge even if there is just one mem.h file with an include of + ../D/mem.h started in the real directory D. [Remember that the include + processor does not heed include guards.] + + For termination, we rely on the fact that eventually the pair (realpath of + file, real path of file directory) will be seen again (because there are + finitely many files and directories). In practice, with this technique, the + recursion is stopped at the second attempt to include mem.h. + """ + + # The magic '3' selects the fourth component of a node, see the class + # documentation. + SUPPORT_RECORD = 3 + + def _InitializeAllCachesMemoizing(self): + self.master_cache = {} + # Keep track of the support of each included file. The support of the file + # is the union of the support of expressions in computed includes in the + # file or in recursively included file. + self.support_master = SupportMaster() + # Enable the mechanism that invalidates all support records that contain a + # symbol that is being defined or redefined. + self.parse_file.SetDefineCallback(self.support_master.InvalidateRecords) + + def __init__(self, stat_reset_triggers={}): + """Constructor.""" + include_analyzer.IncludeAnalyzer.__init__(self, + stat_reset_triggers) + self._InitializeAllCachesMemoizing() + + def ClearStatCaches(self): + """Reset stat caches and the node cache, which depends on stat caches.""" + # First, clear caches as the IncludeAnalyzer class prescribes it. + include_analyzer.IncludeAnalyzer.ClearStatCaches(self) + # Then, clear own caches. + self._InitializeAllCachesMemoizing() + + def _PrintableFilePath(self, fp): + return (isinstance(fp, int) and self.includepath_map.String(fp) + or isinstance(fp, tuple) and + (self.directory_map.string[fp[0]], + self.includepath_map.string[fp[1]])) + + + def RunAlgorithm(self, filepath_resolved_pair, filepath_real_idx): + """See RunAlgorithm of class IncludeAnalyzer in include_analyzer.""" + incl_config = (self.currdir_idx, self.quote_dirs, self.angle_dirs) + try: + nodes_for_incl_config = self.master_cache[incl_config] + except KeyError: + nodes_for_incl_config = self.master_cache[incl_config] = {} + + # Process symbols defined on command line. + for d_opt in self.d_opts: + if len(d_opt) == 1: + lhs, rhs = d_opt[0], "1" + elif len(d_opt) == 2: + [lhs, rhs] = d_opt + parse_file.InsertMacroDefInTable(lhs, rhs, self.symbol_table, + self.support_master.InvalidateRecords) + else: + # Assume this is a syntax error of some sort. + pass + + # Construct or find the node for filepath_resolved. + node = self.FindNode(nodes_for_incl_config, + filepath_resolved_pair, + RESOLVED, + None, + filepath_real_idx) + # Find the nodes reachable from node and represent as an include closure. + include_closure = {} + self._CalculateIncludeClosureExceptSystem(node, include_closure) + return include_closure + + def FindNode(self, + nodes_for_incl_config, + fp, + resolution_mode, + file_dir_idx=None, + fp_real_idx=None): + """Find a previosly constructed node or create a new node. + + Arguments: + nodes_for_incl_config: a dictionary (see class documentation). + fp: a filepath index or, if resolution_mode == RESOLVED, a filepath pair + resolution_mode: an integer in RESOLUTION_MODES + file_dir_idx: consider the file F that has the line '#include "fp"' + which is causing us to call FindNode on fp. file_dir_idx is the + index of dirname(F). (This argument affects the semantics of + resolution for resolution_mode == QUOTE.) + fp_real_idx: the realpath index of resolved filepath + (Useful for resolution_mode == RESOLVED only.) + Returns: + a node or None + Raises: + NotCoveredError + + This is function is long, too long. But function calls are + expensive in Python. TODO(klarlund): refactor. + """ + # Convenient abbreviations for cache access. + dir_map = self.directory_map + includepath_map = self.includepath_map + resolve = self.build_stat_cache.Resolve + # Now a little dynamic type verification. Remember that "A implies B" is + # exactly the same as "not A or B", at least in some primitive formal + # systems. + assert isinstance(nodes_for_incl_config, dict) + assert (not self.IsFilepathPair(fp) + or resolution_mode == RESOLVED) + assert (not fp + or (self.IsFilepathPair(fp) + or (resolution_mode != RESOLVED + and self.IsIncludepathIndex(fp)))) + assert resolution_mode in RESOLUTION_MODES + assert not resolution_mode == QUOTE or file_dir_idx + assert not file_dir_idx or resolution_mode == QUOTE + assert not fp_real_idx or resolution_mode == RESOLVED + + if __debug__: + Debug(DEBUG_TRACE, + "FindNode: fp: %s, mode: %s\n file_dir: %s,\n fp_real: %s" % + (self._PrintableFilePath(fp), + RESOLUTION_MODES_STR[resolution_mode], + not file_dir_idx and " " or dir_map.string[file_dir_idx], + not fp_real_idx and " " + or self.realpath_map.string[fp_real_idx])) + statistics.find_node_counter += 1 + + if fp == None: return + + # We must remember the resolution_mode when we key our function call. And + # for resolution_mode == QUOTE it is important to also remember the + # file_dir_idx, because the filepath is resolved against file_dir. + key = (fp, resolution_mode, file_dir_idx) + if key in nodes_for_incl_config: + # Is the support record valid? + if nodes_for_incl_config[key][self.SUPPORT_RECORD].valid: + statistics.master_hit_counter += 1 + return nodes_for_incl_config[key] + else: + # Invalid support record. The meaning of some computed includes may have + # changed. + node = nodes_for_incl_config[key] + currdir_idx = self.currdir_idx + quote_dirs = self.quote_dirs + angle_dirs = self.angle_dirs + # Retrieve filepath information. That is still OK. Disregard children, + # because they will be rebuilt. Reuse support_record. Don't switch + # support_record.valid to True before running through all the caching + # code below -- we don't want to reuse an earlier result. + [fp_real_idx, fp_resolved_pair, _, support_record] = node + Debug(DEBUG_TRACE, + "Invalid record for translation unit: %s, file: %s", + self.translation_unit, self._PrintableFilePath(fp)) + + else: + # This is a new file -- for this include configuration at least. + support_record = SupportRecord(self.support_master) + currdir_idx = self.currdir_idx + quote_dirs = self.quote_dirs + angle_dirs = self.angle_dirs + + if resolution_mode == QUOTE: + (fp_resolved_pair, fp_real_idx) = ( + resolve(fp, currdir_idx, file_dir_idx, quote_dirs)) + elif resolution_mode == ANGLE: + (fp_resolved_pair, fp_real_idx) = ( + resolve(fp, currdir_idx, None, angle_dirs)) + elif resolution_mode == NEXT: + # The node we return is just a dummy whose children are all the + # possible resolvants. + fp_resolved_pair = None + fp_real_idx = None + else: + assert resolution_mode == RESOLVED + assert fp_real_idx # this is the realpath corresponding to fp + assert self.IsFilepathPair(fp) + fp_resolved_pair = fp # we are given the resolvant + + if fp_resolved_pair: + # The resolution succeeded. Before recursing, make sure to + # mirror the path. Guard the call of MirrorPath with a cache + # check; many files will have been visited before (for other + # include directories). + (d_, fp_) = fp_resolved_pair + if (fp_resolved_pair, currdir_idx) not in self.mirrored: + self.mirrored.add((fp_resolved_pair, currdir_idx)) + self.mirror_path.DoPath( + os.path.join(dir_map.string[currdir_idx], + dir_map.string[d_], + includepath_map.string[fp_]), + currdir_idx, + self.client_root) + + # We have fp_resolved_pair if and only if we have fp_real_idx + assert not fp_resolved_pair or fp_real_idx + assert not fp_real_idx or fp_resolved_pair + # Now construct the node, even before we know the children; this + # early construction/late filling-in of children allows us to stop + # a recursion early, when key is in nodes_for_incl_config. A cyclic + # structure may arise in this way. + children = [] + node = (fp_real_idx, fp_resolved_pair, children, + support_record) + nodes_for_incl_config[key] = node + + if not fp_resolved_pair: + if resolution_mode == NEXT: + # Create children of this dummy node. Try against all + # directories in quote_dirs; that list includes the + # angle_dirs. Recurse for each success. + for d in quote_dirs: + (fp_resolved_pair_, fp_real_idx_) = ( + resolve(fp, currdir_idx, None, (d,))) + if fp_resolved_pair_ != None: + node_ = self.FindNode(nodes_for_incl_config, + fp_resolved_pair_, + RESOLVED, + None, # file_dir_idx + fp_real_idx_) + children.append(node_) + return node + else: + # For non-NEXT resolution modes + return node + + # Now, we've got the resolution: (search directory, include path). + assert (fp and fp_real_idx and fp_resolved_pair) + (searchdir_idx, includepath_idx) = fp_resolved_pair + + # We need the realpath index of the current file directory. That's because + # we are going to ask whether we have really visited this file, despite the + # failure above to recognize it using a possibly relative name. Here, + # 'really' means 'with respect to realpath'. Please see the class + # documentation for why we need to calculate the realpath index of file + # directory as part of the investigation of whether we have 'really' + # encountered the file before. + try: + (fp_dirname_idx, fp_dirname_real_idx) = ( + self.dirname_cache.cache[(currdir_idx, + searchdir_idx, + includepath_idx)]) + except KeyError: + (fp_dirname_idx, fp_dirname_real_idx) = ( + self.dirname_cache.Lookup(currdir_idx, + searchdir_idx, + includepath_idx)) + + if resolution_mode != RESOLVED: + # See whether we know about filepath post-resolution. + if ((fp_real_idx, fp_dirname_real_idx) in nodes_for_incl_config + and support_record.valid): + statistics.master_hit_counter += 1 + # Redo former decision about node: we use the one that is + # already there. + node = nodes_for_incl_config[(fp_real_idx, fp_dirname_real_idx)] + nodes_for_incl_config[key] = node + return node + # Couldn't find node under real name. We'll remember the node, but have to + # continue processing it. + nodes_for_incl_config[(fp_real_idx, fp_dirname_real_idx)] = node + + # All chances of hitting the node cache are now exhausted! + statistics.master_miss_counter += 1 + # If we're revisiting because the support record was invalid, then it is + # time to set it. + support_record.valid = True + + # Try to get the cached result of parsing file. + try: + (quote_includes, angle_includes, expr_includes, next_includes) = ( + self.file_cache[fp_real_idx]) + except KeyError: + # Parse the file. + self.file_cache[fp_real_idx] = self.parse_file.Parse( + self.realpath_map.string[fp_real_idx], + self.symbol_table) + (quote_includes, angle_includes, expr_includes, next_includes) = ( + self.file_cache[fp_real_idx]) + + + # Do the includes of the form #include "foo.h". + for quote_filepath in quote_includes: + node_ = self.FindNode(nodes_for_incl_config, quote_filepath, QUOTE, + fp_dirname_idx) + if node_: + children.append(node_) + support_record.Update(node_[self.SUPPORT_RECORD].support_id) + # Do the includes of the form #include <foo.h>. + for angle_filepath in angle_includes: + node_ = self.FindNode(nodes_for_incl_config, angle_filepath, ANGLE) + if node_: + children.append(node_) + support_record.Update(node_[self.SUPPORT_RECORD].support_id) + if __debug__: + if expr_includes: # Computed includes are interesting + Debug(DEBUG_DATA, "FindNode, expr_includes: file: %s: '%s'", + (isinstance(fp, int) and includepath_map.String(fp) + or (isinstance(fp, tuple) and + (dir_map.string[fp[0]], + includepath_map.string[fp[1]]))), + expr_includes) + + # Do the includes of the form #include expr, the computed includes. + for expr in expr_includes: + # Use multi-valued semantics to gather set of possible filepaths that the + # C/C++ string expr may evaluate to under preprocessing semantics, given + # the current symbol table. The symbols are all those of possible + # expansions. + (files, symbols) = ( + macro_eval.ResolveExpr(includepath_map.Index, + resolve, + expr, + self.currdir_idx, fp_dirname_idx, + self.quote_dirs, self.angle_dirs, + self.symbol_table)) + for (fp_resolved_pair_, fp_real_idx_) in files: + node_ = self.FindNode(nodes_for_incl_config, + fp_resolved_pair_, + RESOLVED, None, fp_real_idx_) + if node_: + children.append(node_) + support_record.Update(node_[self.SUPPORT_RECORD].support_id) + # Now the resolution of includes of the file of the present node depends + # on symbols. + support_record.UpdateSet(symbols) + + # Do includes of the form #include_next "foo.h" or # #include_next <foo.h>. + for include_next_filepath in next_includes: + node_ = self.FindNode(nodes_for_incl_config, include_next_filepath, NEXT) + if node_: + children.append(node_) + support_record.Update(node_[self.SUPPORT_RECORD].support_id) + return node + + def _CalculateIncludeClosureExceptSystem(self, node, include_closure): + """Explore the subgraph reachable from node and gather real paths. + + Arguments: + node: the node of the translation unit, the initial source file + (see class documentation for a description of this tuple). + include_closure: a map (see IncludeAnalyzer.RunAlgorithm + documentation for a description of this map). + Modifies: + include_closure. We modify in place to avoid copying this big struct. + """ + assert not include_closure # should start out empty + # We access prefix_cache's vars directly, so we need to ensure it's filled. + self.systemdir_prefix_cache.FillCache(self.realpath_map) + visited = set([]) + starts_with_systemdir = self.systemdir_prefix_cache.cache + dir_map_string = self.directory_map.string + if not node: return + stack = ([node]) # TODO(csilvers): consider using a deque + if __debug__: statistics.len_calculated_closure_nonsys = 0 + while stack: + node = stack.pop(-1) + id_ = id(node) + if id_ in visited: + continue + visited.add(id_) + # We optimized away: + # + # (fp_real_idx, fp_resolved_pair, children) = node + # + # so that the common case (that fp_real_idx is known to compiler) + # is dispatched away with quickly: + if node[0]: # fp_real_idx + if __debug__: statistics.len_calculated_closure_nonsys += 1 + # We ignore "system" includes like /usr/include/stdio.h. + # These files are not likely to change, so it's safe to skip them. + if not starts_with_systemdir[node[0]]: + # Add the resolved filepath to those found for realpath. + if node[0] not in include_closure: + include_closure[node[0]] = [] + searchdir_idx = node[1][0] # the searchdir part of fp_pair + if (searchdir_idx and dir_map_string[searchdir_idx] and + dir_map_string[searchdir_idx][0] == '/'): + include_closure[node[0]].append(node[1]) + # Even when a node does not describe a filepath, it may still + # have children that do if it is a dummy node. + # TODO(csilvers): see if it speeds things up to append node[2], + # so stack is a list of lists. + stack.extend(node[2]) + statistics.len_calculated_closure = len(include_closure) diff --git a/include_server/include_analyzer_memoizing_node_test.py b/include_server/include_analyzer_memoizing_node_test.py new file mode 100755 index 0000000..898c921 --- /dev/null +++ b/include_server/include_analyzer_memoizing_node_test.py @@ -0,0 +1,233 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +__author__ = "Nils Klarlund" + +import os +import time + +import basics +import parse_command +import cache_basics +import include_analyzer_memoizing_node +import unittest + +NotCoveredError = basics.NotCoveredError + +class IncludeAnalyzerMemoizingNodeUnitTest(unittest.TestCase): + + def _ToString(self, include_closure): + """Translate the indices in an include closure to their denoted strings.""" + return ( + dict((self.realpath_map.string[rp_idx], + [ (self.directory_map.string[dir_idx], self.includepath_map.string[ip_idx]) + for (dir_idx, ip_idx) in include_closure[rp_idx] ]) + for rp_idx in include_closure)) + + def setUp(self): + basics.opt_debug_pattern = 1 + basics.InitializeClientTmp() + self.include_analyzer = ( + include_analyzer_memoizing_node.IncludeAnalyzerMemoizingNode()) + + self.includepath_map = self.include_analyzer.includepath_map + self.canonical_path = self.include_analyzer.canonical_path + self.directory_map = self.include_analyzer.directory_map + self.realpath_map = self.include_analyzer.realpath_map + + + def test__CalculateIncludeClosureExceptSystem(self): + """Construct a summary graph, then calculate closure and check.""" + includepath_map = self.includepath_map + canonical_path = self.canonical_path + directory_map = self.directory_map + realpath_map = self.realpath_map + + # Create summary graph with structure A -> B -> C -> B and B -> D -> C' -> + # E. Note that B has two immediate successors. Assume the current dir is + # /curr (for all nodes). The include graph is made for a searchlist [src, /, + # /dirlink]. Note that the first directory in the searchlist is relative. + # For simplicity, we consider angled resolution only. Here is a description + # of the nodes. + # + # - Nodes A, B correspond to includepaths a.h and b.h, which are relatively + # resolved because they are found in src, which means absolute + # directory /curr/src. These filepaths are thus resolved to src/a.h and + # src/b.h and their corresponding realpaths are /curr/src/a.h and + # /curr/src/b.h. The realpaths are all what is recorded in the include + # closure, because the files are relatively resolved. + # + # - Nodes C, C', and E are absolutely resolved includepaths. More + # specifically: + # + # - Nodes C and C' correspond to includepath dir/c.h and c.h, which + # during resolution were found in / and /dirlink, respectively. + # However, /dirlink is a symbolic link to /dir, which is a real + # directory, so C and C' in fact correspond to the same realpath + # namely /dir/c.h. + # + # - Node E corresponds to includepath dir/e.h and was found during + # resolution to be in /. So, the realpath of this node is /dir/e.h. + # + # - Node D is a dummy and it is not recorded in the include closure. Still, + # its non-dummy descendants are recorded. + + src_idx = directory_map.Index("src") + curr_idx = directory_map.Index("/curr") + root_idx = directory_map.Index("/") + dirlink_idx = directory_map.Index("/dirlink") + curr_src_idx = directory_map.Index("/curr/src") + dir_idx = directory_map.Index("/dir") + + A_children = [] + A = (realpath_map.Index("/curr/src/a.h"), + (src_idx, includepath_map.Index("a.h")), + A_children) + + B_children = [] + B = (realpath_map.Index("/curr/src/b.h"), + (src_idx, includepath_map.Index("b.h")), + B_children) + + C_children = [] + C = (realpath_map.Index("/dir/c.h"), + (root_idx, includepath_map.Index("dir/c.h")), + C_children) + + C__children = [] + C_ = (realpath_map.Index("/dir/c.h"), + (dirlink_idx, includepath_map.Index("c.h")), + C__children) + + D_children = [] + D = (None, None, D_children) + + E_children = [] + E = (realpath_map.Index("/dir/e.h"), + (root_idx, includepath_map.Index("dir/e.h")), + E_children) + + A_children.extend([B]) + B_children.extend([C, D]) + C_children.extend([B]) + C__children.extend([E]) + D_children.extend([C_]) + E_children.extend([]) + + include_closure = {} + self.include_analyzer._CalculateIncludeClosureExceptSystem(A, include_closure) + stringified_include_closure = self._ToString(include_closure) + + # /curr/src/a.h is not known under absolute pathnames. + self.assertEqual(stringified_include_closure['/curr/src/a.h'], []) + # Neither is /curr/src/b.h. + self.assertEqual(stringified_include_closure['/curr/src/b.h'], []) + # But, /dir/c.h is known under two different absolute names. + self.assertEqual(stringified_include_closure['/dir/c.h'], + [('/dirlink/', 'c.h'), ('/', 'dir/c.h')]) + # And, dir/e.h is known under exactly one absolute name. + self.assertEqual(stringified_include_closure['/dir/e.h'], [('/', 'dir/e.h')]) + # That is all and nothing more. + self.assertEqual(len(stringified_include_closure), 4) + + + def _ConstructDistccCommandLine(self, src_stem): + # A command line, which is more or less the one found in the + # generated Makefile for distcc. We don't need the exact form of + # the command." + return ("gcc -DHAVE_CONFIG_H -D_GNU_SOURCE" + + " -I./src" + + ' -DSYSCONFDIR="/usr/local/etc"' + + ' -DPKGDATADIR="/usr/local/share/distcc"' + + " -Isrc" + + " -I./lzo" + + " -include include_me.h " + + " -o src/%s.o" + + " -c src/%s.c") % (src_stem, src_stem) + + def test__CalculateIncludeClosureExceptSystem_on_distcc(self): + + includepath_map = self.includepath_map + canonical_path = self.canonical_path + directory_map = self.directory_map + realpath_map = self.realpath_map + include_analyzer = self.include_analyzer + + current_dir = os.path.realpath("test_data/distcc") + os.chdir(current_dir) + + src_stem = "distcc" + cmd = self._ConstructDistccCommandLine(src_stem) + + parsed_command = ( + parse_command.ParseCommandArgs( + parse_command.ParseCommandLine(cmd), + current_dir, + include_analyzer.includepath_map, + include_analyzer.directory_map, + include_analyzer.compiler_defaults)) + + (include_analyzer.quote_dirs, + include_analyzer.angle_dirs, + include_analyzer.include_files, + translation_unit, + include_analyzer.result_file_prefix, + _) = parsed_command + + self.assertEqual(translation_unit, "src/%s.c" % src_stem) + + expected_suffixes = [ + "src/include_me.h", + "src/implicit.h", + "src/distcc.c", + "src/config.h", + "src/distcc.h", + "src/state.h", + "src/compile.h", + "src/trace.h", + "src/exitcode.h", + "src/util.h", + "src/hosts.h", + "src/bulk.h", + "src/emaillog.h"] + + include_closure = ( + include_analyzer.ProcessCompilationCommand(current_dir, + parsed_command)) + + expected_prefix = os.getcwd() + '/' + + expected = set([ expected_prefix + expected_suffix + for expected_suffix in expected_suffixes ]) + self.assertEqual(set([realpath_map.string[key] + for key in include_closure.keys()]), + expected) + + for rp_idx in include_closure: + self.assertEqual(len(include_closure[rp_idx]), 0) + + # TODO(klarlund): massage command so as to test that with a + # different search path files are reported as absolute. That is, + # provoke pairs (directory_idx, includepath_idx) to exist in + # include_closure[rp_idx]. + + def tearDown(self): + pass + + +unittest.main() diff --git a/include_server/include_analyzer_test.py b/include_server/include_analyzer_test.py new file mode 100755 index 0000000..d784eac --- /dev/null +++ b/include_server/include_analyzer_test.py @@ -0,0 +1,508 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +"""Test include analysis, including computed includes, as carried out +by ProcessCompilationCommandLine. Also, test stat_reset_triggers.""" + +__author__ = "Nils Klarlund" + +import os +import re +import glob +import unittest + +import basics +import cache_basics +import parse_command +import statistics +import include_analyzer_memoizing_node + +class IncludeAnalyzerTest(unittest.TestCase): + + def setUp(self): + + statistics.StartTiming() + self.global_dirs = [] + basics.opt_print_statistics = False + basics.opt_debug_pattern = 1 + basics.InitializeClientTmp() + if algorithm == basics.MEMOIZING: + self.include_analyzer = ( + include_analyzer_memoizing_node.IncludeAnalyzerMemoizingNode()) + else: + self.fail("Algorithm not known.") + + statistics.StartTiming() + + self.directory_map = self.include_analyzer.directory_map + self.compiler_defaults = self.include_analyzer.compiler_defaults + self.canonical_path = self.include_analyzer.canonical_path + + def tearDown(self): + if basics.opt_print_statistics: + statistics.EndTiming() + statistics.PrintStatistics(self.include_analyzer) + + def ProcessCompilationCommandLine(self, cmd, cwd): + return ( + self.include_analyzer.ProcessCompilationCommand( + cwd, + parse_command.ParseCommandArgs( + parse_command.ParseCommandLine(cmd), + cwd, + self.include_analyzer.includepath_map, + self.include_analyzer.directory_map, + self.include_analyzer.compiler_defaults))) + + def CanonicalPathsForTestData(self, dirs, test_data_dir='test_data'): + """Absolutize names relative to test_data_dir of current directory.""" + return set([ self.canonical_path.Canonicalize(test_data_dir + '/' + f) + for f in dirs ]) + + + def RetrieveCanonicalPaths(self, files): + return set([ self.include_analyzer.realpath_map.string[f] for f in files ]) + + + def test_AdvancedComputedIncludes(self): + + includes = self.RetrieveCanonicalPaths( + self.ProcessCompilationCommandLine( + "gcc test_data/test_computed_includes/src.c", + os.getcwd())) + + self.assertEqual( + includes, + self.CanonicalPathsForTestData(['test_computed_includes/src.c', + 'test_computed_includes/helper.c', + 'test_computed_includes/incl.h'])) + + includes = self.RetrieveCanonicalPaths( + self.ProcessCompilationCommandLine( + "gcc test_data/test_computed_includes/srcA.c", + os.getcwd())) + + self.assertEqual( + includes, + self.CanonicalPathsForTestData(['test_computed_includes/srcA.c', + 'test_computed_includes/helper.c', + 'test_computed_includes/incl.h', + 'test_computed_includes/inclA.h'])) + + # Test: FindNode is called once only if previous query is repeated. That is, + # include graph is not calculated for this query. + old_FindNode = self.include_analyzer.FindNode + class mock_FindNode(object): + def __init__(self): + self.count = 0 + def FindNode(self, *_): + self.count += 1 + if self.count == 2: + raise Exception, "Did not expect 2 calls of FindNode." + return old_FindNode(*_) + + self.include_analyzer.FindNode = mock_FindNode().FindNode + try: + includes = self.RetrieveCanonicalPaths( + self.ProcessCompilationCommandLine( + "gcc test_data/test_computed_includes/srcA.c", + os.getcwd())) + finally: + self.include_analyzer.FindNode = old_FindNode + + # Test: if a -D option affecting the value of the computed include is + # presented then include graph is recalculated --- and correctly so. + includes = self.RetrieveCanonicalPaths( + self.ProcessCompilationCommandLine( + r"""gcc -DINCL=\"../dfoo/foo2.h\" """ + + " test_data/test_computed_includes/src.c", + os.getcwd())) + + self.assertEqual( + includes, + self.CanonicalPathsForTestData(['test_computed_includes/src.c', + 'test_computed_includes/helper.c', + 'test_computed_includes/incl.h', + 'test_computed_includes/inclA.h', + 'dfoo/foo2.h'])) + + + # Test: functional macros can be passed on the command line. + includes = self.RetrieveCanonicalPaths( + self.ProcessCompilationCommandLine( + """gcc -D"STR(X)=# X" """ + + """-D"FINCLUDE(P)=STR(../TEST_DATA/dfoo/P)" """ + + """-DTEST_DATA=test_data """ + + "test_data/func_macro.c", + os.getcwd())) + + self.assertEqual( + includes, + self.CanonicalPathsForTestData( + ['func_macro.c', + 'dfoo/foo.h', + 'dfoo/foo2.h', + 'dbar/dbar1/bar.h' + ])) + + + + def test_StatResetTriggers(self): + + """Check that the include analysis of a file is done from scratch after a + trigger path went from non-existing to existing. + """ + + def CheckGeneration(lst, expected): + for f_name in lst: + self.failUnless(re.match(r"/dev/shm/.+[.]include_server[-][0-9]+[-]%s" + % expected, + f_name), + f_name) + + def GetFileNamesFromAbsLzoName(lst): + """Transform lists with elements like: + '/dev/shm/tmpsn6NQT.include_server-12272-X/.../test_data/foo.c.lzo' + to lists with elements like: + 'test_data/foo.c'""" + return [ f_name.split('/')[-2] + + '/' + + f_name.split('/')[-1][:-4] + for f_name in lst if f_name.endswith('.lzo') ] + + self.include_analyzer.stat_reset_triggers = {"seven*": {}, + "ate": {"ate": (1,111,2)}, + "nine": {} } + + try: + + real_glob_glob = glob.glob + def Mock_GlobGlob(f): + if f in ["seven*", "nine"]: return [] + if f == 'ate': return ["ate"] + return real_glob_glob(f) + glob.glob = Mock_GlobGlob + + real_os_stat = os.stat + def Mock_OsStat(f): + # Return the same as initial value in two cases below. + if f in ["seven", "nine"]: raise OSError + if f == 'ate': + obj = lambda: None + obj.st_mtime = 1 + obj.st_ino = 111 + obj.st_dev = 2 + return obj + return real_os_stat(f) + os.stat = Mock_OsStat + + real_cache_basic_OsPathIsFile = cache_basics._OsPathIsFile + def Mock_OsPathIsFile(f): + # We postulate that the test_data/stat_reset_triggers.h file does not + # yet exists. Moreover, we pretend that a version ind test_data/dfoo is + # in existence. + return f in [ "test_data/stat_triggers.c", + "test_data/dfoo/stat_triggers.h"] + cache_basics._OsPathIsFile = Mock_OsPathIsFile + + files_and_links = self.include_analyzer.DoCompilationCommand( + "gcc -Itest_data/dfoo test_data/stat_triggers.c".split(), + os.getcwd()) + + # Check that we picked up the dfoo version of the .h file! + self.assertEqual(GetFileNamesFromAbsLzoName(files_and_links), + ['test_data/stat_triggers.c', + 'dfoo/stat_triggers.h']) + + # The generation should still be the original, namely 1. + self.assertEqual(self.include_analyzer.generation, 1) + CheckGeneration(files_and_links, 1) + + def New_Mock_OsStat(f): + if f in ["seven", "nine"]: raise OSError + if f == 'ate': + obj = lambda: None + obj.st_mtime = 1 + obj.st_ino = 111 + obj.st_dev = 3 # so, this component changed from previous value + return obj + return real_os_stat(f) + + os.stat = New_Mock_OsStat + + def New_Mock_OsPathIsFile(f): + return f in [ "test_data/stat_triggers.c", + "test_data/stat_triggers.h", + "test_data/dfoo/stat_triggers.h"] + cache_basics._OsPathIsFile = New_Mock_OsPathIsFile + + files_and_links = self.include_analyzer.DoCompilationCommand( + "gcc -Itest_data/dfoo test_data/stat_triggers.c".split(), + os.getcwd()) + + self.assertEqual(self.include_analyzer.generation, 2) + CheckGeneration(files_and_links, 2) + + # Now, check that we picked up the test_data version of the .h file, not + # the dfoo one! + self.assertEqual(GetFileNamesFromAbsLzoName(files_and_links), + ['test_data/stat_triggers.c', + 'test_data/stat_triggers.h']) + + # Third time. + def New_Mock_GlobGlob(f): + if f in ["seven*"]: return ["seventy"] + if f in ["nine"]: return [] + if f == 'ate': return ["ate"] + return real_glob_glob(f) + glob.glob = New_Mock_GlobGlob + + def New_New_Mock_OsStat(f): + if f in ["seven", "nine"]: raise OSError + if f == 'ate': + obj = lambda: None + obj.st_mtime = 1 + obj.st_ino = 111 + obj.st_dev = 3 + return obj + if f == 'seventy': + obj = lambda: None + obj.st_mtime = 2 + obj.st_ino = 222 + obj.st_dev = 3 + return obj + return real_os_stat(f) + os.stat = New_New_Mock_OsStat + + # Revert _OsPathIsFile + cache_basics._OsPathIsFile = Mock_OsPathIsFile + + files_and_links = self.include_analyzer.DoCompilationCommand( + "gcc -Itest_data/dfoo test_data/stat_triggers.c".split(), + os.getcwd()) + + # Now, check that we again picked up the dfoo version of the .h file. + self.assertEqual(GetFileNamesFromAbsLzoName(files_and_links), + ['test_data/stat_triggers.c', + 'dfoo/stat_triggers.h']) + + self.assertEqual(self.include_analyzer.generation, 3) + CheckGeneration(files_and_links, 3) + + finally: + glob.glob = real_glob_glob + os.stat = real_os_stat + cache_basics._OsPathIsFile = real_cache_basic_OsPathIsFile + + + def test_DotdotInInclude(self): + """Set up tricky situation involving an "#include "../foo" occurring in a + file accessed through a symbolic link. This include is to be resolved + relative to the file directory, namely where the link is, not where the file + is. Also, the include processor tries to identify files by their + relatives names. This may lead to an infinite recursion according to an + increasing sequence of filepath names involving "../" So if the included + file includes the original file, an infinite loop may occur.""" + + # In test_data, we find + # + # symlink_farm/sub_farm/link_to_dotdot_dotdot_dfoo_include_dotdot_foo + # + # which is a link to ../../dfoo/include_dotdot_foo, that is, to + # + # dfoo/include_dotdot_foo + # + # which is a file that contains: + # + # #include "../foo" + # + # Here ../foo must refer to the file in location symlink_farm/sub_farm/foo, + # which we have made a real file (not a symlink). + # + # We check that this "foo" is included. Moreover, we have put: + # + # #include "sub_farm/link_to_dotdot_dotdot_dfoo_include_dotdot_foo" + # + # into symlink_farm/sub_farm/foo, so that a nice infinite inclusion chain + # is modeled. That should not faze the include server. In particular, we + # do not want to see an infinitude of paths of the form: + # + # symlink_farm/sub_farm/../sub_farm/../ + # ... + # /sub_farm/../sub_farm/foo + + includes = self.RetrieveCanonicalPaths( + self.ProcessCompilationCommandLine( + "gcc -xc test_data/symlink_farm/sub_farm/" + + "link_to_dotdot_dotdot_dfoo_include_dotdot_foo", + os.getcwd())) + self.assertEqual( + includes, + self.CanonicalPathsForTestData( + ['dfoo/include_dotdot_foo', 'symlink_farm/foo'], + "test_data")) + + + def helper_test_IncludeAnalyzer(self, test_data_dir): + """Test basic functionality assuming test data is in test_data_dir.""" + + # Simple stuff: quoted and angled directories, recursion + includes = self.RetrieveCanonicalPaths( + self.ProcessCompilationCommandLine( + "gcc -Itest_data/dfoo test_data/parse.c", + os.getcwd())) + self.assertEqual( + includes, + self.CanonicalPathsForTestData( + ['parse.c', + 'dfoo/foo2.h', + 'dfoo/foo.h', + 'dfoo/../dbar/dbar1/bar.h'], + test_data_dir)) + + # Computed includesgg + + includes = self.RetrieveCanonicalPaths( + self.ProcessCompilationCommandLine( + "gcc -Itest_data/dfoo test_data/computed_includes.c", + os.getcwd())) + + # The path to the computed angle includes was not provided, so + # they were not found. + self.assertEqual( + includes, + self.CanonicalPathsForTestData( + ['computed_includes.c', 'p1.h'], + test_data_dir)) + + # Check that symbol_table has been updated. + self.assertEqual(self.include_analyzer.symbol_table, + {'dfoo_foo2_h': [None], + 'A': ['"p1.h"'], + 'dbar_dbar1_bar_h': [None], + 'm': [(['a'], '<a##_pre.c>'), (['a'], '<a##_post.c>')]}) + + + # The include path to the angle includes, -Itest_data, is + # provided at our next try. This should include abc_pre.c and + # abc_post.c. This is especially challenging for incremental + # analysis because the previous cached result of include analyzing + # computed_includes.c cannot in fact be reused here. That is an + # unusual case. + includes = self.RetrieveCanonicalPaths( + self.ProcessCompilationCommandLine( + "gcc -Itest_data/dfoo -Itest_data" + + " test_data/computed_includes.c", + os.getcwd())) + + self.assertEqual( + includes, + self.CanonicalPathsForTestData( + ['computed_includes.c', 'p1.h', 'abc_post.c', 'abc_pre.c'], + test_data_dir)) + + # The inclusion chain is baz/start_x -> baz/x.h -> foo/x.h -> + # bar/x.h -> baz.h. Only the final #include_next "x.h" in baz/x.h + # does not Resolve because we just used -Ibaz for resolution, the + # last in the list. This should not raise an exception, because the + # failure may in reality not happen: the bad include_next could be + # guarded by a conditional for example. + self.assertEqual( + self.RetrieveCanonicalPaths(self.ProcessCompilationCommandLine( + "gcc -E -Itest_data/test_include_next/foo" + + " -Itest_data/test_include_next/bar" + + " -Itest_data/test_include_next/baz" + + " test_data/test_include_next/baz/start_x.c", + os.getcwd())), + self.CanonicalPathsForTestData( + ['test_include_next/baz/start_x.c', + 'test_include_next/baz/x.h', + 'test_include_next/foo/x.h', + 'test_include_next/bar/x.h', + 'test_include_next/baz/x.h'], + test_data_dir)) + + # In contrast to previous example, the #final include_next in baz + # resolves this time, namely to biz/x.h. + self.assertEqual( + self.RetrieveCanonicalPaths(self.ProcessCompilationCommandLine( + "gcc -E -Itest_data/test_include_next/foo" + + " -Itest_data/test_include_next/bar" + + " -Itest_data/test_include_next/baz" + + " -Itest_data/test_include_next/biz" + + " test_data/test_include_next/baz/start_x.c", + os.getcwd())), + self.CanonicalPathsForTestData( + ['test_include_next/baz/start_x.c', + 'test_include_next/baz/x.h', + 'test_include_next/foo/x.h', + 'test_include_next/bar/x.h', + 'test_include_next/biz/x.h'], + test_data_dir)) + + + includes = self.RetrieveCanonicalPaths(self.ProcessCompilationCommandLine( + "gcc -E -Itest_data/test_include_next/foo" + + " -Itest_data/test_include_next/bar" + + " -Itest_data/test_include_next/baz" + + " test_data/test_include_next/baz/start_y.c", + os.getcwd())) + + self.assertEqual( + includes, + self.CanonicalPathsForTestData( + ['test_include_next/baz/start_y.c', + 'test_include_next/baz/../foo/y.h', + 'test_include_next/bar/y.h', + 'test_include_next/foo/y.h', + 'test_include_next/baz/y.h'], + test_data_dir)) + + # Test that a directory that has a name matching an include is not picked. + # Here the directory is test_data/i_am_perhaps_a_directory.h, which is in + # the file directory of the translation unit. Instead, + # test_data/dfoo/i_am_perhaps_a_directory.h should be picked: it is a + # regular file. + includes = self.RetrieveCanonicalPaths(self.ProcessCompilationCommandLine( + "gcc -E -Itest_data/dfoo test_data/test_directory_probing.c", + os.getcwd())) + + self.assertEqual( + includes, + self.CanonicalPathsForTestData( + ['test_directory_probing.c', 'dfoo/i_am_perhaps_a_directory.h'], + test_data_dir)) + + def test_IncludeAnalyzer(self): + """Run helper_test_IncludeAnalyzer 'directly' without complications + of symbolic links.""" + self.helper_test_IncludeAnalyzer('test_data') + + + def test_IncludeAnalyzer_from_symlink_farm(self): + """Run helper_test_IncludeAnalyzer through a link farm to exercise include + processors ability to handle links.""" + self.helper_test_IncludeAnalyzer('test_data/symlink_farm') + + +for algorithm in [ basics.MEMOIZING ]: + try: + print "TESTING ALGORITHM %s" % algorithm + unittest.main() + except: + raise diff --git a/include_server/include_server.py b/include_server/include_server.py new file mode 100755 index 0000000..a0a9c21 --- /dev/null +++ b/include_server/include_server.py @@ -0,0 +1,723 @@ +#!/usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +"""Conservative approximation of include dependencies for C/C++.""" + +__author__ = "Nils Klarlund" + +# TODO (klarlund) Implement abort mechanism: regularly check whether +# ppid is 0; if so, then abort. + +# Python imports +import os +import re +import sys +import glob +import signal +import getopt +import tempfile +import traceback +import SocketServer + +# Include server imports +import basics +import statistics +import include_analyzer_memoizing_node +import distcc_pump_c_extensions + +# The default size passed to listen by a streaming socket server of +# SocketServer is only 5. Make it 128 (which appears to be the hard +# built-in limit for Linux). This enables requests to the include +# server to be buffered better. +REQUEST_QUEUE_SIZE = 128 + +Debug = basics.Debug +DEBUG_TRACE = basics.DEBUG_TRACE +DEBUG_WARNING = basics.DEBUG_WARNING +# Exceptions. +SignalSIGTERM = basics.SignalSIGTERM +NotCoveredError = basics.NotCoveredError +NotCoveredTimeOutError = basics.NotCoveredTimeOutError + + +# USAGE + +def Usage(): + print """include_server --port INCLUDE_SERVER_PORT [options] + +where INCLUDE_SERVER_PORT is a socket name. Fork the include server +for incremental include analysis. The include server answers queries +from the distcc client about which files to include in a C/C++ +compilation. This command itself terminates as soon as the include +server has been spawned. + +Options: + --pid_file FILEPATH The pid of the include server is written to file + FILEPATH. + -dPAT, --debug_pattern=PAT Bit vector for turning on warnings and debugging + 1 = warnings + 2 = trace some functions + other powers of two: see basics.py. + -e, --email Send email to discc-pump developers when include + server gets in trouble. + --no-email Do not send email. + --email_bound NUMBER Maximal number of emails to send (in addition to + a final email). Default: 3. + --realpath_warning_re=RE Write a warning to stderr whenever a filename is + resolved to a realpath that is matched by RE, + which is a regular expression in Python syntax. + (Warnings must be enabled with at least -d1.) + --stat_reset_triggers=LIST Flush stat caches when the timestamp of any + filepath in LIST changes or the filepath comes in + or out of existence. LIST is a colon separated + string of filepaths, possibly containing simple + globs (as allowed by Python's glob module). Print + a warning whenever such a change happens (if + warnings are enabled). This option allows limited + exceptions to distcc_pump's normal assumption that + source files are not modified during the build. + -x, --exact_analysis Use CPP instead, do not omit system headers files. + -v, --verify Verify that files in CPP closure are contained in + closure calculated by include processor. + -s, --statistics Print information to stdout about include analysis. + -t, --time Print elapsed, user, and system time to stderr. + -w, --write_include_closure Write a .d_approx file which lists all the + included files calculated by the include server; + with -x, additionally write the included files + as calculated by CPP to a .d_exact file. +""" + +# TODO(klarlund) +# --simple_algorithm not currently implemented + + +# UTILITIES + +def _PrintStackTrace(fd): + """Print stacktrace to file object.""" + print >> fd, '------- Include server stack trace -----------' + # Limit is 1000 entries. + traceback.print_exc(1000, fd) + print >> fd, '----------------------------------------------' + + +class _EmailSender(object): + """For sending emails. We limit their number to avoid email storms.""" + + def __init__(self): + self.number_sent = 0 + + def TryToSend(self, fd, force=False, never=False): + """Send the contents of file to predefined blame address. + Arguments: + fd: open file descriptor, will remain open + force: send even if bound has been reached + """ + if not basics.opt_send_email: return + if self.number_sent >= basics.opt_email_bound and not force: return + if never: return + self.number_sent += 1 + # For efficiency, we postpone reading needed libraries for emailing until + # now. + import smtplib + import getpass + import socket + try: + user_addr = "%s@%s" % (getpass.getuser(), socket.gethostname()) + fd.seek(0) + msg = "Subject: %s\nTo: %s\nFrom: %s\n\n%s\n%s" % ( + basics.EMAIL_SUBJECT, + basics.DCC_EMAILLOG_WHOM_TO_BLAME, + user_addr, + "Automated email number %d in include server session.\n" % + self.number_sent, + fd.read()) + s = smtplib.SMTP() + s.connect() + s.sendmail(user_addr, [basics.DCC_EMAILLOG_WHOM_TO_BLAME], msg) + Debug(DEBUG_WARNING, "Include server sent email to %s", + basics.DCC_EMAILLOG_WHOM_TO_BLAME) + s.close() + except: + Debug(DEBUG_WARNING, basics.CANT_SEND_MESSAGE) + traceback.print_exc() + + def MaybeSendEmail(self, fd, force=False, never=False): + """Print warning and maybe send email; the contents is from file object. + + Arguments: + fd: a file object that will be closed. + force: send the mail even if number of emails sent exceed + basics.opt_email_bound + """ + fd.seek(0, 0) + Debug(DEBUG_WARNING, "%s", fd.read()) + self.TryToSend(fd, force, never) + fd.close() + + +def _RemoveDirectoryTree(tree_top): + """Recursively remove everything. + + Ignore filesystem errors, because this function may be called as a last resort + and it does its job on a best-effort basis. + """ + # Copied, more or less, from Python 2.4 Library Reference. + if not os.access(tree_top, os.W_OK): + return + for root, dirs, files in os.walk(tree_top, topdown=False): + for name in files: + try: + os.remove(os.path.join(root, name)) + except (IOError, OSError): # should not happen + pass + for name in dirs: + try: + if os.path.islink(os.path.join(root, name)): + os.remove(os.path.join(root, name)) + else: + os.rmdir(os.path.join(root, name)) + except (IOError, OSError): # should not happen + pass + try: + os.rmdir(root) + except (IOError, OSError): # should not happen + pass + + +def _CleanOutClientRoots(client_root): + """Delete client root directory and everything below, for all generations. + Argument: + client_root: a directory path ending in "*distcc-*-*" + """ + # Determine all generations of this directory. + hyphen_ultimate_position = client_root.rfind('-') + client_roots = glob.glob("%s-*" % client_root[:hyphen_ultimate_position]) + assert client_root in client_roots + for client_root_ in client_roots: + _RemoveDirectoryTree(client_root_) + + +def _CleanOutOthers(): + """Search for left-overs from include servers that have passed away.""" + # Find all distcc-pump directories whether abandoned or not. + distcc_directories = glob.glob("%s/*.%s-*-*" % (basics.client_tmp, + basics.INCLUDE_SERVER_NAME)) + for directory in distcc_directories: + # Fish out pid from end of directory name. + hyphen_ultimate_position = directory.rfind('-') + assert hyphen_ultimate_position != -1 + hyphen_penultimate_position = directory[:hyphen_ultimate_position].rfind( + '-') + assert hyphen_penultimate_position != -1 + pid_str = directory[hyphen_penultimate_position + 1: + hyphen_ultimate_position] + try: + pid = int(pid_str) + except ValueError: + continue # Happens only if a spoofer is around. + try: + # Got a pid; does it still exist? + os.getpgid(pid) + continue + except OSError: + # Process pid does not exist. Nuke its associated files. This will + # of course only succeed if the files belong the current uid of + # this process. + if not os.access(directory, os.W_OK): + continue # no access, not ours + Debug(DEBUG_TRACE, + "Cleaning out '%s' after defunct include server." % directory) + _CleanOutClientRoots(directory) + + +NEWLINE_RE = re.compile(r"\n", re.MULTILINE) +BACKSLASH_NEWLINE_RE = re.compile(r"\\\n", re.MULTILINE) + + +def ExactDependencies(cmd, realpath_map, systemdir_prefix_cache, + translation_unit): + """The dependencies as calculated by CPP, the C Preprocessor. + Arguments: + cmd: the compilation command, a string + realpath_map: map from filesystem paths (no symlink) to idx + systemdir_prefix_cache: says whether realpath starts with a systemdir + translation_unit: string + Returns: + the set of realpath indices of the include dependencies. + Raises: + NotCoveredError + """ + + # Safely get a couple of temporary files. + (fd_o, name_o) = tempfile.mkstemp("distcc-pump") + (fd_d, name_d) = tempfile.mkstemp("distcc-pump") + + def _delete_temp_files(): + os.close(fd_d) + os.close(fd_o) + os.unlink(name_o) + os.unlink(name_d) + + # Remove -o option and call with -E, -M, and -MF flags. + preprocessing_command = ( + (re.sub(r"\s-o[ ]?(\w|[./+-])+", " ", cmd) # delete -o option + + " -o %(name_o)s" # add it back, but to temp file, + + " -E" # macro processing only + + " -M -MF %(name_d)s") % # output .d file + {'name_o':name_o, 'name_d':name_d}) + + ret = os.system(preprocessing_command) + if ret: + _delete_temp_files() + raise NotCoveredError("Could not execute '%s'" % + preprocessing_command, + translation_unit) + # Using the primitive fd_d file descriptor for reading is cumbersome, so open + # normally as well. + fd_d_ = open(name_d, "rb") + # Massage the contents of fd_d_ + dotd = re.sub("^.*:", # remove Makefile target + "", + NEWLINE_RE.sub( + "", # remove newlines + BACKSLASH_NEWLINE_RE.sub("", # remove backslashes + fd_d_.read()))) + fd_d_.close() + _delete_temp_files() + # The sets of dependencies is a set the of realpath indices of the + # absolute filenames corresponding to files in the dotd file. + deps = set([ rp_idx + for filepath in dotd.split() + for rp_idx in [ realpath_map.Index(os.path.join(os.getcwd(), + filepath)) ] + if not systemdir_prefix_cache.StartsWithSystemdir(rp_idx, + realpath_map) + ]) + statistics.len_exact_closure = len(deps) + return deps + + +def WriteDependencies(deps, result_file, realpath_map): + """Write the list of deps to result_file. + Arguments: + deps: a list of realpath indices + result_file: a filepath + realpath_map: map from filesystem paths (no symlink) to idx + """ + try: + fd = open(result_file, "w") + fd.write("\n".join([realpath_map.string[d] for d in deps])) + fd.write("\n") + fd.close() + except (IOError, OSError), why: + raise NotCoveredError("Could not write to '%s': %s" % (result_file, why)) + + +def VerifyExactDependencies(include_closure, + exact_no_system_header_dependency_set, + realpath_map, + translation_unit): + """Compare computed and real include closures, ignoring system + header files (such as those in /usr/include). + Arguments: + include_closure: a dictionary whose keys are realpath indices + exact_no_system_header_dependency_set: set of realpath indices + realpath_map: map from filesystem paths (no symlink) to idx + translation_unit: string + Raises: + NotCoveredError +""" + diff = exact_no_system_header_dependency_set - set(include_closure) + statistics.len_surplus_nonsys = ( + len(set(include_closure) - exact_no_system_header_dependency_set)) + + if diff != set([]): + # Pick one bad dependency. + bad_dep = diff.pop() + raise NotCoveredError( + ("Calculated include closure does not contain: '%s'.\n" + + "There %s %d such missing %s.") + % (realpath_map.string[bad_dep], + len(diff) == 0 and "is" or "are", + len(diff) + 1, + len(diff) == 0 and "dependency" or "dependencies"), + translation_unit) + + +# A SOCKET SERVER + +class QueuingSocketServer(SocketServer.UnixStreamServer): + """A socket server whose request queue have size REQUEST_QUEUE_SIZE.""" + request_queue_size = REQUEST_QUEUE_SIZE + + def handle_error(self, _, client_address): + """Re-raise current exception; overrides SocketServer.handle_error. + """ + raise + + +# HANDLER FOR SOCKETSERVER + +def DistccIncludeHandlerGenerator(include_analyzer): + """Wrap a socketserver based on the include_analyzer object inside a new + type that is a class named IncludeHandler.""" + + # TODO(klarlund): Can we do this without dynamic type generation? + + class IncludeHandler(SocketServer.StreamRequestHandler): + """Define a handle() method that invokes the include closure algorithm .""" + + def handle(self): + """Using distcc protocol, read command and return include closure. + + Do the following: + - Read from the socket, using the RPC protocol of distcc: + - the current directory, and + - the compilation command, already broken down into an argv vector. + - Parse the command to find options like -I, -iquote,... + - Invoke the include server's closure algorithm to yield a set of files + and set of symbolic links --- both sets of files under client_root, + which duplicates the part of the file system that CPP will need. + - Transmit the file and link names on the socket using the RPC protocol. + """ + statistics.StartTiming() + currdir = distcc_pump_c_extensions.RCwd(self.rfile.fileno()) + cmd = distcc_pump_c_extensions.RArgv(self.rfile.fileno()) + + try: + try: + # We do timeout the include_analyzer using the crude mechanism of + # SIGALRM. This signal is problematic if raised while Python is doing + # I/O in the C extensions and during use of the subprocess + # module. + # + # TODO(klarlund) The Python library manual states: "When a signal + # arrives during an I/O operation, it is possible that the I/O + # operation raises an exception after the signal handler returns. This + # is dependent on the underlying Unix system's semantics regarding + # interrupted system calls." We must clarify this. Currently, there + # is I/O during DoCompilationCommand: + # + # - when a link is created in mirror_path.py + # - module compress_files is used + # + # TODO(klarlund): Modify mirror_path so that is accumulates symbolic + # link operations instead of actually executing them on the spot. The + # accumulated operations can be executed after DoCompilationCommand + # when the timer has been cancelled. + include_analyzer.timer = basics.IncludeAnalyzerTimer() + files_and_links = include_analyzer.DoCompilationCommand(cmd, currdir) + finally: + # The timer should normally be cancelled during normal execution + # flow. Still, we want to make sure that this is indeed the case in + # all circumstances. + include_analyzer.timer.Cancel() + + except NotCoveredError, inst: + # Warn user. The 'Preprocessing locally' message is meant to + # assure the user that the build process is otherwise intact. + fd = os.tmpfile() + print >> fd, ( + "Preprocessing locally. Include server not covering: %s for " + + "translation unit '%s'") % ( + (inst.args and inst.args[0] or "unknown reason", + include_analyzer.translation_unit)), + # We don't include a stack trace here. + include_analyzer.email_sender.MaybeSendEmail(fd, + never=not inst.send_email) + # The empty argv list denotes failure. Communicate this + # information back to the distcc client, so that it can fall + # back to preprocessing on the client. + distcc_pump_c_extensions.XArgv(self.wfile.fileno(), []) + if isinstance(inst, NotCoveredTimeOutError): + Debug(DEBUG_TRACE, + "Clearing caches because of include server timeout.") + include_analyzer.ClearStatCaches() + + except SignalSIGTERM: + # Normally, we will get this exception when the include server is no + # longer needed. But we also handle it here, during the servicing of a + # request. See basics.RaiseSignalSIGTERM. + Debug(DEBUG_TRACE, "SIGTERM received while handling request.") + raise + except KeyboardInterrupt: + # Propagate to the last-chance exception handler in Main. + raise + except SystemExit, inst: + # When handler tries to exit (by invoking sys.exit, which in turn raises + # SystemExit), something is really wrong. Terminate the include + # server. But, print out an informative message first. + fd = os.tmpfile() + print >> fd, ( + ("Preprocessing locally. Include server fatal error: '%s' for " + + "translation unit '%s'") % ( + (inst.args, include_analyzer.translation_unit))), + _PrintStackTrace(fd) + include_analyzer.email_sender.MaybeSendEmail(fd, force=True) + distcc_pump_c_extensions.XArgv(self.wfile.fileno(), []) + sys.exit("Now terminating include server.") + # All other exceptions are trapped here. + except Exception, inst: + # Internal error. Better be safe than sorry: terminate include + # server. But show error to user on stderr. We hope this message will be + # reported. + fd = os.tmpfile() + print >> fd, ( + ("Preprocessing locally. Include server internal error: '%s: %s' " + + "for translation unit '%s'") % ( + (inst.__class__, inst.args, include_analyzer.translation_unit))), + _PrintStackTrace(fd) + # Force this email through (if basics.opt_send_email is True), because + # this is the last one and this is an important case to report. + include_analyzer.email_sender.MaybeSendEmail(fd, force=True) + distcc_pump_c_extensions.XArgv(self.wfile.fileno(), []) + raise SignalSIGTERM # to be caught in Main with no further stack trace + else: + # No exception raised, include closure can be trusted. + distcc_pump_c_extensions.XArgv(self.wfile.fileno(), files_and_links) + # Finally, stop the clock and report statistics if needed. + statistics.EndTiming() + if basics.opt_statistics: + statistics.PrintStatistics(include_analyzer) + + + return IncludeHandler + + +def _ParseCommandLineOptions(): + """Parse arguments and options for the include server command. + + Returns: + (include_server_port, pid_file), where include_server_port + is a string and pid_file is a string or None + Modifies: + option variables in module basics + """ + try: + opts, args = getopt.getopt(sys.argv[1:], + "d:estvw", + ["port=", + "pid_file=", + "debug_pattern=", + "email", + "no-email", + "email_bound=", + "exact_analysis", + "stat_reset_triggers=", + "simple_algorithm", + "realpath_warning_re=", + "statistics", + "time", + "verify", + "write_include_closure"]) + except getopt.GetoptError: + # Print help information and exit. + Usage() + sys.exit(1) + pid_file = None + include_server_port = None + for opt, arg in opts: + try: + if opt in ("-d", "--debug_pattern"): + basics.opt_debug_pattern = int(arg) + if opt in ("--port",): + include_server_port = arg + if opt in ("--pid_file",): + pid_file = arg + if opt in ("-e", "--email"): + basics.opt_send_email = True + if opt in ("--no-email",): + basics.opt_send_email = False + if opt in ("--email_bound",): + basics.opt_email_bound = int(arg) + if opt in ("--realpath_warning_re",): + basics.opt_realpath_warning_re = re.compile(arg) + if opt in ("--stat_reset_triggers",): + basics.opt_stat_reset_triggers = ( + dict([ (glob_expr, + dict ([ (path, basics.Stamp(path)) + for path in glob.glob(glob_expr) ])) + for glob_expr in arg.split(':') ])) + if opt in ("--simple_algorithm",): + basics.opt_simple_algorithm = True + sys.exit("Not implemented") + if opt in ("-s", "--statistics"): + basics.opt_statistics = True + if opt in ("-t", "--time"): + basics.opt_print_times = True + if opt in ("-v", "--verify"): + basics.opt_verify = True + if opt in ("-w", "--write_include_closure"): + basics.opt_write_include_closure = True + if opt in ("-x", "--exact_analysis"): + basics.opt_exact_include_analysis = True + except ValueError: + Usage() + sys.exit(1) + # We must have a port! + if not include_server_port: + print >> sys.stderr, "INCLUDE_SERVER_PORT not provided. Aborting." + print >> sys.stderr, "-------------------------------------------" + print >> sys.stderr + Usage() + sys.exit(1) + return (include_server_port, pid_file) + + +def _PrintTimes(times_at_start, times_at_fork, times_child): + """Print elapsed, user, system, and user + system times.""" + # The os.times format stores user time in positions 0 and 2 (for parent and + # children, resp.) Similarly, system time is stored in positions 1 and + # 3. Elapsed time is in position 4. Elapsed time is measured relative to some + # epoch whereas user and system time are 0 at the time of process creation. + total_u = (times_at_fork[0] + times_at_fork[2] + + times_child[0] + times_child[2]) + total_s = (times_at_fork[1] + times_at_fork[3] + + times_child[1] + times_child[1]) + total_cpu = total_u + total_s + total_e = times_child[4] - times_at_start[4] + print >> sys.stderr, "Include server timing. ", + print >> sys.stderr, ( + "Elapsed: %3.1fs User: %3.1fs System: %3.1fs User + System: %3.1fs" % + (total_e, total_u, total_s, total_cpu)) + + +class _IncludeServerPortReady(object): + """A simple semaphore for forked processes. + + The implementation uses an unnamed pipe.""" + + def __init__(self): + """Constructor. + + Should be called before fork. + """ + (self.read_fd, self.write_fd) = os.pipe() + + def Acquire(self): + """Acquire the semaphore after fork; blocks until a call of Release.""" + if os.read(self.read_fd, 1) != '\n': + sys.exit("Include server: _IncludeServerPortReady.Acquire failed.") + + def Release(self): + """Release the semaphore after fork.""" + if os.write(self.write_fd, '\n') != 1: + sys.exit("Include server: _IncludeServerPortReady.Release failed.") + + +def _SetUp(include_server_port): + """Setup include_analyzer and socket server. + + Returns: (include_analyzer, server)""" + + try: + os.unlink(include_server_port) + except (IOError, OSError): + pass # this would be expected, the port provided should not exist + + if os.sep != '/': + sys.exit("Expected '/' as separator in filepaths.") + + # Determine basics.client_tmp now. + basics.InitializeClientTmp() + # So that we can call this function --- to sweep out possible junk. Also, this + # will allow the include analyzer to call InitializeClientRoot. + _CleanOutOthers() + + Debug(DEBUG_TRACE, "Starting socketserver %s" % include_server_port) + + # Create the analyser. + include_analyzer = ( + include_analyzer_memoizing_node.IncludeAnalyzerMemoizingNode( + basics.opt_stat_reset_triggers)) + include_analyzer.email_sender = _EmailSender() + # Wrap it inside a handler that is a part of a UnixStreamServer. + server = QueuingSocketServer( + include_server_port, + # Now, produce a StreamRequestHandler subclass whose new objects has + # a handler which calls the include_analyzer just made. + DistccIncludeHandlerGenerator(include_analyzer)) + + return (include_analyzer, server) + + +def _CleanOut(include_analyzer, include_server_port): + """Prepare shutdown by cleaning out files and unlinking port.""" + if include_analyzer and include_analyzer.client_root: + _CleanOutClientRoots(include_analyzer.client_root) + try: + os.unlink(include_server_port) + except OSError: + pass + + +def Main(): + """Parse command line, fork, and start stream request handler.""" + # Remember the time spent in the parent. + times_at_start = os.times() + include_server_port, pid_file = _ParseCommandLineOptions() + # Get locking mechanism. + include_server_port_ready = _IncludeServerPortReady() + # Now spawn child so that parent can exit immediately after writing + # the process id of child to the pid file. + times_at_fork = os.times() + pid = os.fork() + if pid != 0: + # In parent. + # + if pid_file: + pid_file_fd = open(pid_file, "w") + print >> pid_file_fd, pid + pid_file_fd.close() + # Just run to completion now -- after making sure that child is ready. + include_server_port_ready.Acquire() + # concerned. + else: + # In child. + # + # We call _Setup only now, because the process id, used in naming the client + # root, must be that of this process, not that of the parent process. See + # _CleanOutOthers for the importance of the process id. + (include_analyzer, server) = _SetUp(include_server_port) + include_server_port_ready.Release() + try: + try: + server.serve_forever() + except KeyboardInterrupt: + print >> sys.stderr, ( + "Include server: keyboard interrupt, quitting after cleaning up.") + _CleanOut(include_analyzer, include_server_port) + except SignalSIGTERM: + Debug(DEBUG_TRACE, "Include server shutting down.") + _CleanOut(include_analyzer, include_server_port) + except: + print >> sys.stderr, ( + "Include server: exception occurred, quitting after cleaning up.") + _PrintStackTrace(sys.stderr) + _CleanOut(include_analyzer, include_server_port) + raise # reraise exception + finally: + if basics.opt_print_times: + _PrintTimes(times_at_start, times_at_fork, os.times()) + + +if __name__ == "__main__": + # Treat SIGTERM (the default of kill) as Ctrl-C. + signal.signal(signal.SIGTERM, basics.RaiseSignalSIGTERM) + Main() diff --git a/include_server/include_server_test.py b/include_server/include_server_test.py new file mode 100755 index 0000000..c115106 --- /dev/null +++ b/include_server/include_server_test.py @@ -0,0 +1,187 @@ +#!/usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +"""Exercise include server handler with respect to exceptions and email. + +To do this, we mock out socket servers, c_extensions, email handling, and even +ultimately the notion of an AssertionError. +""" + +__author__ = "Nils Klarlund" + +import os +import unittest + +import basics +import cache_basics +import parse_command +import statistics +import include_analyzer_memoizing_node +import include_server +import distcc_pump_c_extensions + +NotCoveredError = basics.NotCoveredError + +class IncludeServerTest(unittest.TestCase): + + def setUp(self): + + statistics.StartTiming() + basics.opt_print_statistics = False + basics.opt_debug_pattern = 1 + + def tearDown(self): + if basics.opt_print_statistics: + statistics.EndTiming() + statistics.PrintStatistics(self.include_analyzer) + + def CanonicalPaths(self, dirs): + return set([ self.canonical_path.Canonicalize(f) for f in dirs ]) + + def RetrieveCanonicalPaths(self, files): + return set([ self.include_analyzer.realpath_map.string[f] for f in files ]) + + def test_IncludeHandler_handle(self): + try: + self_test = self + basics.InitializeClientTmp() + old_RWcd = distcc_pump_c_extensions.RCwd + distcc_pump_c_extensions.RCwd = None # to be set below + old_RArgv = distcc_pump_c_extensions.RArgv + distcc_pump_c_extensions.RArgv = None # to be set below + old_XArgv = distcc_pump_c_extensions.XArgv + distcc_pump_c_extensions.XArgv = lambda _, __: None + old_StreamRequestHandler = ( + include_server.SocketServer.StreamRequestHandler) + + class Mock_StreamRequestHandler(object): + def __init__(self): + self.rfile = lambda: None + self.rfile.fileno = lambda: 27 + self.wfile = lambda: None + self.wfile.fileno = lambda: 27 + + include_server.SocketServer.StreamRequestHandler = ( + Mock_StreamRequestHandler) + + include_analyzer = ( + include_analyzer_memoizing_node.IncludeAnalyzerMemoizingNode()) + + class Mock_EmailSender(object): + + def __init(self): + self.expect = lambda: None + + def MaybeSendEmail(self, fd, force=False, never=False): + fd.seek(0) + text = fd.read() + self.expect(text, force, never) + fd.close() + raise + + mock_email_sender = include_analyzer.email_sender = Mock_EmailSender() + + include_handler = ( + include_server.DistccIncludeHandlerGenerator(include_analyzer)()) + + # Wow, that was a lot of set-up. Now exercise the include server and + # analyzer with an emphasis on triggering exceptions. + + # Exercise 1: non-existent translation unit. + + distcc_pump_c_extensions.RArgv = lambda self: [ "gcc", "parse.c" ] + distcc_pump_c_extensions.RCwd = lambda self: os.getcwd() + + def Expect1(txt, force, never): + self_test.assert_( + "Include server not covering: " + + "Could not find translation unit 'parse.c'" in txt) + self_test.assertEqual(never, True) + + mock_email_sender.expect = Expect1 + try: + include_handler.handle() + except NotCoveredError: + pass + else: + raise AssertionError + + # Exercise 2: provoke assertion error in cache_basics by providing an + # entirely false value of current directory as provided in RCwd. + + distcc_pump_c_extensions.RArgv = lambda self: [ "gcc", "parse.c" ] + distcc_pump_c_extensions.RCwd = lambda self: "/" + # The cwd will be changed because of false value. + oldcwd = os.getcwd() + + # We must distinguish between provoked and erroneous exceptions. So, we + # mock out, in a sense, the provoked assertion exception that we + # expect. The variable got_here allows us to filter the provoked exception + # away from unexpected ones. + got_here = [] + + def Expect2(txt, force, never): + + self_test.assert_( + "Include server internal error: 'exceptions.AssertionError" in txt) + + self_test.assert_("""for translation unit 'parse.c'""" in txt) + + # This email should be sent. + self_test.assertEqual(never, False) + + got_here.append(True) + + mock_email_sender.expect = Expect2 + try: + include_handler.handle() + except AssertionError: + os.chdir(oldcwd) + # Make sure that we're catching the induced AssertionError, not one + # produced in Except2. + self.assert_(got_here) + else: + raise AssertionError + + # Exercise 3: provoke a NotCoveredError due to an absolute #include. + + distcc_pump_c_extensions.RArgv = lambda self: [ "gcc", + "test_data/contains_abs_include.c" ] + distcc_pump_c_extensions.RCwd = lambda self: os.getcwd() + + def Expect3(txt, force, never): + self_test.assert_( + "Filepath must be relative but isn't: '/love/of/my/life'." + in txt) + # Now check that this email is scheduled to not be sent. + self_test.assertEqual(never, True) + + mock_email_sender.expect = Expect3 + try: + include_handler.handle() + except NotCoveredError: + pass + + finally: + distcc_pump_c_extensions.RWcd = old_RWcd + distcc_pump_c_extensions.RArgv = old_RArgv + distcc_pump_c_extensions.XArgv = old_XArgv + include_server.SocketServer.StreamRequestHandler = ( + old_StreamRequestHandler) + +unittest.main() diff --git a/include_server/macro_eval.py b/include_server/macro_eval.py new file mode 100755 index 0000000..a4f4293 --- /dev/null +++ b/include_server/macro_eval.py @@ -0,0 +1,437 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +"""Evaluation of macros acccording to an overapproximation semantics. + +This module generally follows CPP semantics for the evalution of macros. But we +treat every define as a possible one, because we don't know whether it is +actually executed when a file is really preprocessed. Our semantics is thus +multi-valued: an expression (that is, a string) is evaluated to the set of +poosible values it can have according to arbitrary choices of #defines in effect +among those encountered in the program text. + +An example explains the general idea. If we have: + +#define A x +#define A y +#define B 1 +#define B 2 + +Then the expression + + A.B + +evaluates to one of the following: + + x.1 + y.1 + x.2 + y.2 + +The set {"x.1", "y.1", "x.2", "y.2"} is the value of EvalExpr("A.B", +symbol_table), where symbol_table is the dictionary in which we have +stored the four #define's. + +Currently, we will be satisfied with + + A A + +evaluating to + + x x + x y + y x + y y + +although a sharper semantic modelling would yield only: + + x x + y y + + + +How to Read This Code +--------------------- +An understanding of the C preprocessor is necessary. See "The GNU C Preprocessor +Internals" (http://gcc.gnu.org/onlinedocs/cppinternals). Especially the section +"Macro Expansion Algorithm" is informative. + +Whitespace Insertion and Other Deficiencies +------------------------------------------- +CPP inserts whitespaces and sometimes doesn't according to very complicated +rules. We do not insert whitespaces. + +Also, we retokenize each intermediate expansion. + +For actual arguments of macros, we also we do not do the right thing for +parentheses inside single quotes, which is to ignore them. + +There are probably several more deviations from CPP semantics. + +These deviations should not matter for most common included computes. + +What If the Include Processor is Wrong +-------------------------------------- +Assume that we have + + #include very_complicated_call(anfhis,fifj) + +If the include processor produces spurious expansions like: + + "whatda.c" + 2 + 2 + "5 * 3" + +then file whada.c if found in search directory becomes part of the include +closure. So does the file "5 * 3". But 2 + 2 does not have the shape of an a +filepath in an include: the filepath must be in quotes or angle brackets. + +These spurious files are not harmful to preprocessing on the server. + +If the include server omits calculating the expansion + + "right_file.h" + +then the compilation on the server will fail. The client, according to the logic +of dcc_build_somewhere, will then perform a local compilation. + +Symbol Table +------------ + +The symbol table is a dictionary, whose entries are of the form + + symbol: definition_list + +Each definition in definition_list is either + - a string, denoting the expansion of an object-like macro, or + - a pair ([param_1,...,param_n], rhs), which denotes a function-like macro, + whose formal parameters are param_1,.., param_n and whose expansion is rhs, + before the substitution of formal parameters for actual parameters. +""" + +__author__ = "Nils Klarlund" + +import re + +import basics +import parse_file +import statistics + +Debug = basics.Debug +DEBUG_TRACE = basics.DEBUG_TRACE +DEBUG_TRACE1 = basics.DEBUG_TRACE1 +DEBUG_TRACE2 = basics.DEBUG_TRACE2 +NotCoveredError = basics.NotCoveredError + +# REGULAR EXPRESSIONS + +SINGLE_POUND_RE = re.compile(r"\B#\s*(\S*)") # \B = here: not at end of word +DOUBLE_POUND_RE = re.compile(r"##") +SYMBOL_RE = re.compile(r"\b\w+\b") # \b = word boundary \w = word constituent + + +# HELPER FUNCTIONS + +def _BigUnion(list_of_sets): + """Return the set that is the union of the sets or lists in list_of_sets.""" + result = [] + for s in list_of_sets: + result.extend(list(s)) + return set(result) + + +def _PrependToSet(expr, expr_set): + """Return the set consiting of expr + element with element in expr_set.""" + return set([ expr + expr_ for expr_ in expr_set ]) + + +def _SubstituteSymbolInString(x, y, str): + """Return the string that results from substituting x for y in str.""" + Debug(DEBUG_TRACE2, + """_SubstituteSymbolInString: x: "%s", y: "%s", str:"%s" """, + x, y, str) + sub_re = re.compile(r"\b%s\b" % re.escape(x)) + Debug(DEBUG_TRACE2, + """_SubstituteSymbolInString (result): "%s" """, sub_re.sub(y, str)) + return sub_re.sub(y, str) + +def _ParseArgs(string, pos): + """Split stuff according to commas at outer level in parenthesized string. + + If string[pos:] does not start with '(', return (None, pos). If string[pos:] + starts with '(' and there is a balanced parenthesis structure ending + at pos_end, then return (args, pos_end), where args is + string[pos:pos_end] hacked into segments between commas at outer + level. So "(a,m(c, n(d)), c)...." results in (["a", "m(c, n(d))", " + c"], 17) being returned. + """ + # TODO(klarlund): we ignore ignoring parentheses inside single quotes. Such + # occurrences are deemed unlikely at this moment. Fix that so that parentheses + # inside single quotes are ignored. + open_parens = 0 + if not pos < len(string) or string[pos] != '(': + return (None, pos) + # Prepare a list of comma and extremal positions. The '(' at the left is the + # first extremal position. + commas = [pos] + pos_end = None + inside_quotes = False + for i in range(pos, len(string)): + if inside_quotes: + if string[i] == '"' and string[i-1] != r'\\': + inside_quotes = False + continue + if string[i]==',' and open_parens==1: + commas.append(i) + elif string[i]=='(': + open_parens += 1 + elif string[i]==')': + open_parens -= 1 + if open_parens == 0: + pos_end = i + break + elif string[i] == '"' and string[i-1] != r'\\': + inside_quotes = True + if not pos_end: + return (None, pos) + commas.append(pos_end) # the other extremal position + args_list = [] + for i in range(len(commas) - 1): + args_list.append(string[commas[i] + 1 : commas[i + 1]]) + return (args_list, pos_end + 1) + + +def _MassageAccordingToPoundSigns(string): + """Perform 'stringification (#) and concatenation (##).""" + return SINGLE_POUND_RE.sub(r'"\1"', DOUBLE_POUND_RE.sub("", string)) + + +# EVALUATION + +def _EvalExprHelper(expr, symbol_table, disabled): + if __debug__: + Debug(DEBUG_TRACE2, "EvalExprHelper: expr: %s", expr) + + """Evaluate according to an overapproximation macro substitution semantics. + + Arguments: + expr: a string + symbol_table: { symbol: [rhs, + ..., + ([param_1,...,param_n], rhs), + ...], + ... }, where rhs and param_i are strings + disabled: set of disabled symbols (see "The GNU C Preprocessor + Internals") + + Returns: [ expr_1, expr_2, ...], which is a non-empy list of + strings, namely the expansions of expr. + """ + + def _ReEvalRecursivelyForExpansion(expansion, after): + """Reevalute the expansion that is the result of finding a match for a + macro. + + Arguments: + symbol (outer scope): the name of the matched macro that resulted in + expansion; it is the same as match.group() + match (outer scope): the match data for the symbol + expansion: the expansion we are substituting for the match + after: the string after the expansion + Modifies: + value_set: the set of all possible expansions of expr + + The value set is updated according to recursive evaluations of the string + that results from inserting expansion between expr[:match.start()] and + expr[match.end():] (for symbol-like macro) or expr[args_end:] (for + function-like macro). + + The idea is to form a set of strings from a cross product of two string sets + descriping all possibly expansions before and after the match. + + There are two recursions involved. First, we evaluate after to find all + possible values of what follows the match. This recursion does not involve a + larger disabled set. Each resulting string is named after_eval_expr. Second, + we evaluate expansion concatenated with each after_eval_expr value. In + these evaluations, symbol is added to the disabled set. + """ + if __debug__: + Debug(DEBUG_TRACE2, + ("_ReEvalRecursivelyForExpansion: expr: %s\n" + + " before: %s\n expansion: %s\n after: %s") + % (expr, expr[:match.start()], expansion, after)) + value_set.update( + _PrependToSet(expr[:match.start()], + _BigUnion([ _EvalExprHelper(expansion + after_expansion, + symbol_table, + disabled | set([symbol])) + for after_expansion in + _EvalExprHelper(after, + symbol_table, + disabled) ]))) + + def _EvalMacro(definition, disabled): + """Evaluate symbol according to definition. + + Here definition is either object-like or function-like. + """ + # Consider that this symbol goes unevaluated. + value_set.update( + _PrependToSet(expr[:match.end()], + _EvalExprHelper(expr[match.end():], + symbol_table, + disabled))) + if isinstance(definition, str): + # The expansion is the definition. + _ReEvalRecursivelyForExpansion(definition, expr[match.end():]) + elif isinstance(definition, tuple): + # We have an invocation a function-like macro. Find the possible + # values of the function symbol, according to object-like + # expansions, before substituting. + (lhs, rhs) = definition # lhs = formal parameters, rhs = + # expansion before substitution + # Verify that the number of formal parameters match the + # number of actual parameters; otherwise skip. + if not args_list or len(lhs) != len(args_list): + return + # Expand arguments recursively. + args_expand = [ _EvalExprHelper(arg, symbol_table, disabled) + for arg in args_list ] + # Do the substitutions. Again, we'll need to piece together + # strings from a cross product. In this the fragments come from + # the expansions of the arguments. + expansions = [rhs] + for i in range(len(args_expand)): + expansions = [ _SubstituteSymbolInString(lhs[i], arg, expansion) + for expansion in expansions + for arg in args_expand[i] ] + for expansion in expansions: + real_expansion = _MassageAccordingToPoundSigns(expansion) + _ReEvalRecursivelyForExpansion(real_expansion, expr[args_end:]) + else: + assert False, "Definition '%s' is unexpected." % definition + + # Look for a symbol. + match = SYMBOL_RE.search(expr) + if not match: + # No symbol found. + return set([expr]) + else: + # Let's break down the string into segments according to the + # symbol found. This is non-standard: the real CPP only tokenizes + # once. + symbol = match.group() + (args_list, args_end) = _ParseArgs(expr, match.end()) + Debug(DEBUG_TRACE2, + "EvalExprHelper (inside): expr: %s\n" + + " symbol: %s\n args_list: %s\n" + + " before: %s\n", + expr, symbol, args_list, expr[:match.start()]) + if symbol not in symbol_table: + # Process rest of string recursively. + return _PrependToSet(expr[:match.end()], + _EvalExprHelper(expr[match.end():], + symbol_table, + disabled)) + else: + # Now consider the set of meanings of this symbol. But first + # note that the string remaining unexpanded is always a + # possibility, because we are doing a "forall" analysis. + value_set = set([expr]) + # Now carry out substitution on expr[match.start():match.end()], + # the whole stretch of expr that consists of symbol and possibly + # args with parentheses. + if symbol not in disabled: + defs = symbol_table[symbol] + for definition in defs: + _EvalMacro(definition, disabled) + return value_set + + +def EvalExpression(expr, symbol_table): + """Calculate sets of possibly values of expr given symbol_table. + + Arguments: + expr: any string to be macro expanded + symbol_table: { symbol: {rhs, ..}, ,..., + symbol:{((param_1,...,param_n), rhs), ... } + Returns: + [ expr_1, expr_2, ...], a list of strings: the possible expansions of expr. + """ + if __debug__: + Debug(DEBUG_TRACE, "EvalExpression: expr: %s", expr) + r = set(_EvalExprHelper(expr, symbol_table, set([]))) + if __debug__: + Debug(DEBUG_TRACE, "EvalExpression: return: %s", r) + return r + + +def ResolveExpr(includepath_map_index, + resolve, + expr, + currdir_idx, + searchdir_idx, + quote_dirs, + angle_dirs, + symbol_table): + """Evaluate and resolve possible values for expr using symbol table. + + Determine all possible values of expr. Those that are of the form "filepath" + or <filepath> are resolved against (file_dir_idx, quote_dirs) or angle_dirs, + respectively. The set of resolvants is returned along with a list of all + symbols that occurs in possible evaluations of expr. + + Arguments: + includepath_map_index: the Index function of an includepath map + resolve: a Resolve method of a BuildStatCache object + expr: any string to be macro expanded + currdir_idx: a directory index + searchdir_idx: a directory index (used for resolving quote-includes) + quote_dirs: a directory index list + angle_dirs: a directory index list + symbol_table: as described in module macro_expr + Returns: + a pair(files, symbols), where files is a list of (filepath pair, + realpath index), namely those files that are successful resolutions of + possible double-quoted and angle-quoted values of expr, and symbols is + the set of all identifiers occurring in expression or its possible + expansions + Raises: + NotCoveredError + """ + if __debug__: + Debug(DEBUG_TRACE, "ResolveExpr: %s, %s, %s", + expr, searchdir_idx, angle_dirs) + resolved_files = [] + symbols = [] + statistics.resolve_expr_counter += 1 + for val in EvalExpression(expr, symbol_table): + match_result = parse_file.INCLUDE_STRING_RE.match(val) + if match_result: + if match_result.group('quote'): + resolved = resolve(includepath_map_index(match_result.group('quote')), + currdir_idx, searchdir_idx, quote_dirs) + elif match_result.group('angle'): + resolved = resolve(includepath_map_index(match_result.group('angle')), + currdir_idx, None, angle_dirs) + resolved_files.append(resolved) + else: + symbols.extend(SYMBOL_RE.findall(val)) + if __debug__: + Debug(DEBUG_TRACE, "ResolveExpr: return: %s", resolved_files) + return (resolved_files, set(symbols)) diff --git a/include_server/macro_eval_test.py b/include_server/macro_eval_test.py new file mode 100755 index 0000000..be9508a --- /dev/null +++ b/include_server/macro_eval_test.py @@ -0,0 +1,233 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +__author__ = "Nils Klarlund" + +# See also tests in include_server_test.py. + +import os +import basics +import parse_file +import cache_basics +import macro_eval +import unittest + +NotCoveredError = basics.NotCoveredError + +class MacroEvalTest(unittest.TestCase): + + def setUp(self): + + basics.opt_debug_pattern = 1 + + caches = cache_basics.SetUpCaches() + + self.includepath_map = caches.includepath_map + self.canonical_path = caches.canonical_path + self.directory_map = caches.directory_map + self.realpath_map = caches.realpath_map + + + def tearDown(self): + pass + + + def test__SubstituteSymbolInString(self): + self.assertEqual( + macro_eval._SubstituteSymbolInString("X", "f(y)", "X+(X, X##Y)"), + "f(y)+(f(y), f(y)##Y)") + self.assertEqual( + macro_eval._SubstituteSymbolInString("a", "b", "c(a, aa)"), + "c(b, aa)") + + def test_MassageAccordingToPoundSigns(self): + self.assertEqual(macro_eval._MassageAccordingToPoundSigns('#aa##bb'), + '"aabb"') + self.assertEqual(macro_eval._MassageAccordingToPoundSigns('# a(.)'), + '"a(.)"') + + def test__ParseArgs(self): + + self.assertEqual(macro_eval._ParseArgs("(a,m(c, n(d)), c)", 0), + (["a", "m(c, n(d))", " c"], 17)) + + self.assertEqual(macro_eval._ParseArgs("""(a","m(c, n(d)), c)""", 0), + (["""a","m(c, n(d))""", " c"], 19)) + + + def test__PrependToSet(self): + self.assertEqual( + macro_eval._PrependToSet("x", set(["y", "z"])), + set(["xy", "xz"])) + + + def test__BigUnion(self): + self.assertEqual(macro_eval._BigUnion([set([]), set([1,2]), set([3])]), + set([1,2,3])) + + + def test_EvalExprDirs(self): + + self.assertEqual( + macro_eval.EvalExpression("A", { 'A': ['b'] }), + set(['A', 'b'])) + + self.assertEqual( + macro_eval.EvalExpression("A", { 'A': ['B'], 'B': ['A'] }), + set(['A', 'B'])) + + self.assertEqual( + macro_eval.EvalExpression("A", { 'A': ['B'], 'B': ['c'] }), + set(['A', 'B', 'c'])) + + self.assertEqual( + macro_eval.EvalExpression("max(2, 4)", + { 'max': [ ( ['x', 'y'], "x < y? y: x") ] }), + set(['max(2, 4)', '2 < 4? 4: 2'])) + + self.assertEqual( + macro_eval.EvalExpression("F(2, 4)", + { 'F': ['max'], + 'max': [ ( ['x', 'y'], "x < y? y: x") ] }), + set(['max(2, 4)', 'F(2, 4)', '2 < 4? 4: 2'])) + + self.assertEqual( + macro_eval.EvalExpression("max(max(1,2), 3)", + { 'max': [ ( ['x', 'y'], "(x < y? y: x)") ] }), + set(['((1 < 2? 2: 1) < 3? 3: (1 < 2? 2: 1))', + 'max(max(1,2), 3)', + '(max(1,2) < 3? 3: max(1,2))', + 'max((1 < 2? 2: 1), 3)'])) + + self.assertEqual( + macro_eval.EvalExpression("A", { 'A': ['"a.c"'] }), + set(['A', '"a.c"'])) + + # The ## operator only works in rhs of function-like macros. Check + # that it doesn't work stand-alone. + self.assertEqual( + macro_eval.EvalExpression("A##A", { 'A': ['a.c'] }), + set(['A##A', 'a.c##A', 'A##a.c', 'a.c##a.c'])) + + self.assertEqual( + macro_eval.EvalExpression("A(y)A(z)", { 'A': [(['x'], 'x##a.c')] }), + set(['A(y)A(z)', 'A(y)za.c', 'ya.cza.c', 'ya.cA(z)'])) + + self.assertEqual( + macro_eval.EvalExpression("m(abc)", { 'm': [( ['a'], "<a##_post.c>" )] }), + set(['m(abc)', '<abc_post.c>'])) + + self.assertEqual( + macro_eval.EvalExpression("myfile(hello)", + { 'myfile': [(['x'], "myquote(myplace/x)")], + 'myquote': [(['y'], """#y""")] }), + set(['myfile(hello)', + '"myplace/hello"', + 'myquote(myplace/hello)'])) + + + def test_FromCPPInternals(self): + # This little example works. + # + # #define foo(x) bar x + # + # foo(foo) (2) == bar foo (2) + # + # Let us check that. + self.assertEqual( + macro_eval.EvalExpression("foo(foo) (2)", + {'foo':[(['x'], "bar x")]}), + set(['bar foo (2)', 'foo(foo) (2)'])) + + # The next one does not work, because we are not inserting spaces. + # + # From : + # http://gcc.gnu.org/onlinedocs/cppinternals/Token-Spacing.html#Token-Spacing + # + # #define PLUS + + # #define EMPTY + # #define f(x) =x= + # + # +PLUS -EMPTY- PLUS+ f(=) + # ==> + + - - + + = = = + # + # We do not insert spaces as CPP does. But we generate a lot of + # combinations! + self.assertEqual( + macro_eval.EvalExpression("+PLUS -EMPTY- PLUS+ f(=)", + { 'PLUS':['+'], + 'EMPTY':[""], + 'f':[(['x'], '=x=')] }), + set(['++ -EMPTY- ++ ===', + '++ -EMPTY- PLUS+ ===', + '+PLUS -- ++ f(=)', + '+PLUS -EMPTY- ++ ===', + '++ -EMPTY- PLUS+ f(=)', + '+PLUS -EMPTY- PLUS+ f(=)', + '+PLUS -- ++ ===', + '++ -EMPTY- ++ f(=)', + '+PLUS -- PLUS+ ===', + '+PLUS -- PLUS+ f(=)', + '++ -- PLUS+ ===', + '++ -- ++ ===', + '+PLUS -EMPTY- PLUS+ ===', + '++ -- PLUS+ f(=)', + '+PLUS -EMPTY- ++ f(=)', + '++ -- ++ f(=)'])) + + + def test_ResolveExpr(self): + # Erect the edifice of caches. + caches = cache_basics.SetUpCaches() + parse_file_obj = parse_file.ParseFile(caches.includepath_map) + + symbol_table = {} + # Set up symbol_table by parsing test_data/more_macros.c. + self.assertEqual(parse_file_obj.Parse( + "test_data/more_macros.c", symbol_table), + ([], [], ['TEMPLATE_VARNAME(foo)'], [])) + + # Check what we got in symbol_table. + self.assertEqual( + macro_eval.EvalExpression("TEMPLATE_VARNAME(foo)", symbol_table), + set(['TEMPLATE_VARNAME(foo)', + '"maps/foo.tpl.varnames.h"', + 'AS_STRING(maps/foo.tpl.varnames.h)', + 'AS_STRING_INTERNAL(maps/foo.tpl.varnames.h)'])) + + # Verify that resolving this expression yields one actual file (which we + # have placed in test_data/map). + [((d, ip), rp)], symbols = macro_eval.ResolveExpr( + caches.includepath_map.Index, + caches.build_stat_cache.Resolve, + 'TEMPLATE_VARNAME(foo)', + caches.directory_map.Index(os.getcwd()), # current dir + caches.directory_map.Index(""), # file directory + [caches.directory_map.Index("test_data")], # search directory + [], + symbol_table) + self.assertEqual(caches.directory_map.string[d], "test_data/") + self.assertEqual(caches.includepath_map.string[ip], + "maps/foo.tpl.varnames.h") + self.assertEqual(symbols, + set(['TEMPLATE_VARNAME', 'maps', + 'AS_STRING', 'AS_STRING_INTERNAL', + 'tpl', 'varnames', 'h', 'foo'])) + + +unittest.main() diff --git a/include_server/mirror_path.py b/include_server/mirror_path.py new file mode 100755 index 0000000..3be5062 --- /dev/null +++ b/include_server/mirror_path.py @@ -0,0 +1,113 @@ +#!/usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# """Memoizing, piecemeal mirroring of directory and link structure.""" + +__author__ = "Nils Klarlund" + + +import os +import os.path + +import cache_basics + +class MirrorPath(object): + """Make a caching structure for copying all parts of the paths that + method DoPath is called with. This includes replication of symbolic + links. But the targets of symbolic links are absolutized: they are + replaced by the realpath of the original target, whether this target + was relative or absolute.""" + + def __init__(self, + simple_build_stat, + canonical_path): + """Constructor. + + Arguments: + simple_build_stat: object of type SimpleBuildStat + canonical_path: function of type CanonicalPath + """ + assert isinstance(simple_build_stat, cache_basics.SimpleBuildStat) + assert isinstance(canonical_path, cache_basics.CanonicalPath) + # All links encountered so far. + self.links = [] + # We cache tuples (filepath, current_dir_idx) for which we've already fixed + # up the symbolic links. + self.link_stat = set([]) + # Usual abbreviations. + self.simple_build_stat = simple_build_stat + self.canonical_path = canonical_path + + def Links(self): + """Return the list of symbolic links created.""" + return self.links + + def DoPath(self, filepath, current_dir_idx, root): + """Mirror the parts of filepath not yet created under root. + + Arguments: + filepath: a string, which is relative or absolute filename + current_dir_idx: a directory index + root: a string denoting an absolute path for an existing directory + """ + assert isinstance(filepath, str) + assert isinstance(current_dir_idx, int) + assert isinstance(root, str) + assert root[0] == '/' and root[-1] != '/' + assert os.path.isdir(root), root + + link_stat = self.link_stat + lookup = self.simple_build_stat.Lookup + # Working from the end (in the hope that a cache lookup will reveal + # the futility of further work), make sure that intermediate + # destinations exist, and replicate symbolic links where necessary. + while filepath and filepath != '/': + if (filepath, current_dir_idx) in link_stat: + # Filepath is already mirrored + return + link_stat.add((filepath, current_dir_idx)) + # Process suffix of filepath by + # - making sure that the mirrored real path of the prefix exists, + # - and that the suffix if a symbolic link + # is replicated as a symbolic link. + assert filepath[-1] != '/', filepath + + # Now identify the potential symbolic link at the end of filepath + (prefix_filepath, suffix) = os.path.split(filepath) + # Calculate the real position of the destination of the prefix + prefix_real = self.canonical_path.Canonicalize(prefix_filepath) + + if prefix_real == '/': prefix_real = '' + + # And, its counterpart under root + root_prefix_real = root + prefix_real + + # Make sure that root_prefix_real is there + if not lookup(root_prefix_real): + if not os.path.isdir(root_prefix_real): + os.makedirs(root_prefix_real) + self.simple_build_stat.cache[root_prefix_real] = True + + assert os.path.isdir(root_prefix_real) + # Create the mirrored symbolic link if applicable + if os.path.islink(filepath): + link_name = root_prefix_real + '/' + suffix + if not os.path.exists(link_name): + os.symlink(self.canonical_path.Canonicalize(filepath), link_name) + self.links.append(link_name) + filepath = prefix_filepath diff --git a/include_server/mirror_path_test.py b/include_server/mirror_path_test.py new file mode 100755 index 0000000..81c64c1 --- /dev/null +++ b/include_server/mirror_path_test.py @@ -0,0 +1,145 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +__author__ = "Nils Klarlund" + +import os +import os.path + +import basics +import cache_basics +import mirror_path +import unittest + +NotCoveredError = basics.NotCoveredError + + +class MirrorPathTest(unittest.TestCase): + + """We construct a mock-up world of a file system in order to + unittest the DoPath function of mirror_path.""" + + + def setUp(self): + + basics.debug_pattern = 3 + + caches = cache_basics.SetUpCaches() + + self.canonical_path = caches.canonical_path + self.simple_build_stat = caches.simple_build_stat + self.mirror_path = mirror_path.MirrorPath(self.simple_build_stat, + self.canonical_path) + + self.directories = ['/', '/a', '/link', '/a/link', '/a/b', + '/link/link', '/root'] + self.links = ['/a/link', '/link', '/link/link'] + self.exists = self.directories + self.links + self.realpaths = {'/' :'/', + '/a' :'/a', + '/a/link' :'/a/b', + '/link' :'/a', + '/link/link':'/a/b'} + + + def tearDown(self): + pass + + def test_MirrorPath(self): + + try: + + def isdir(path): + return path in self.directories + def exists(path): + return path in self.exists + def islink(path): + return path in self.links + def realpath(path): + if path.startswith('/root'): + self.fail("Not expected that '%s' startd with '/root'." % path) + return self.realpaths[path] + def makedirs(path): + if path == '/root/a': + self.directories.extend(['/root/a']) + self.exists.extend(['/root/a']) + else: + self.fail("makedirs %s" % path) + def symlink(src, dest): + if not (src, dest) in [ ('/a', '/root/link'), + ('/a/b', '/root/a/link') ]: + self.fail("symlink %s %s" % (src, dest)) + self.links.append(dest) + self.exists.append(dest) + # Overwrite the canonicalization function that MirrorPath uses. + self.mirror_path.canonical_path.Canonicalize = realpath + # Overwrite various system functions that MirrorPath uses. + isdir_ = os.path.isdir + os.path.isdir = isdir + exists_ = os.path.exists + os.path.exists = exists + islink_ = os.path.islink + os.path.islink = islink + makedirs_ = os.makedirs + os.makedirs = makedirs + symlink_ = os.symlink + os.symlink = symlink + + # Mirror the link /a/link. + self.mirror_path.DoPath('/a/link', 117, '/root') + self.assertEqual(self.mirror_path.Links(), ['/root/a/link']) + self.assert_(self.simple_build_stat.Lookup('/root/a')) + + # Check that symlink function is not called again, by verifying + # that mirror_path.Links() doesn't grow. + self.mirror_path.DoPath('/a/link', 117, '/root') + self.assertEqual(self.mirror_path.Links(), ['/root/a/link']) + + # Now mirror /link/link. + self.mirror_path.DoPath('/link/link', 117, '/root') + self.assertEqual(self.mirror_path.Links(), ['/root/a/link', '/root/link']) + self.assertEqual( + [ d for d in self.directories if d.startswith('/root') ], + [ '/root', '/root/a' ]) + self.assertEqual( + [ d for d in self.links if d.startswith('/root') ], + [ '/root/a/link', '/root/link' ]) + + # Now mirror /a/b. Since b is a file and /a already is mirrored, + # there is no effect. + self.mirror_path.DoPath('/a/b', 117, '/root') + self.assertEqual(self.mirror_path.Links(), ['/root/a/link', '/root/link']) + self.assertEqual( + [ d for d in self.directories if d.startswith('/root') ], + [ '/root', '/root/a' ]) + self.assertEqual( + [ d for d in self.links if d.startswith('/root') ], + [ '/root/a/link', '/root/link' ]) + + finally: + try: + # Don't propagate another exception. + os.path.isdir = isdir_ + os.path.exists = exists_ + os.path.islink = islink_ + os.makedirs = makedirs_ + os.symlink = symlink_ + except NameError: + pass + +unittest.main() diff --git a/include_server/parse_command.py b/include_server/parse_command.py new file mode 100755 index 0000000..87bec61 --- /dev/null +++ b/include_server/parse_command.py @@ -0,0 +1,464 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +"""Parsing of C and C++ commands and extraction of search paths.""" + +__author__ = "opensource@google.com (Craig Silverstein, Nils Klarlund)" + +import re +import os +import sys + +import basics +import cache_basics + +Debug = basics.Debug +DEBUG_TRACE = basics.DEBUG_TRACE +NotCoveredError = basics.NotCoveredError + +# TODO(klarlund): Make mechanism for handling -D, -U, -undef options, along +# with default symbols. + +class ParseState: + """Everything we figure out during parsing. This is accessed a lot and + needs to be fast, so you should access and set the data members directly. + Mutator functions are provided for the non-list elements, but solely + because this way you can set these elements from within a lambda. + """ + def __init__(self): + self.nostdinc = False + self.file_names = [] + self.quote_dirs = [] + self.include_files = [] + self.i_dirs = [] + self.before_system_dirs = [] + self.after_system_dirs = [] + + self.language = 'none' # equivalent to commandline of '-x none' + self.isysroot = None + self.sysroot = None + self.output_file = None + self.iprefix = "" + self.Dopts = [] + + def set_nostdinc(self): self.nostdinc = True + def set_language(self, x): self.language = x + def set_isysroot(self, x): self.isysroot = x + def set_sysroot(self, x): self.sysroot = x + def set_outputfile(self, x): self.output_file = x + def set_iprefix(self, x): self.iprefix = x + +def _SplitMacroArg(arg): + """Split an arg as found in -Darg + + Argument: + arg: argument + + Returns: [arg] if there is no '=' in arg, otherwise [symb, val], where symb is + what is to the left of '=' and val is what is to the right. + """ + pos = arg.find("=") + if pos > 0: + return [arg[:pos], arg[pos + 1:]] + else: + return [arg] + +def _RaiseNotImplemented(name, comment=''): + raise NotCoveredError('%s is not implemented. %s' % (name, comment)) + +# These are the cpp options that a) are more than one letter long, +# b) always take an argument, and c) may either have that argument +# as a separate word in argv, or may have the argument concatenated +# after the option-name (eg, either "-include foo" or "-includefoo"). +# These are taken from +# http://gcc.gnu.org/onlinedocs/cpp/Invocation.html#Invocation +# and, more completely, from the gnu gcc info pages. +# Each option takes as a value, the function to run on the opt's argument. +# Below, ps is a ParseState object. +# TODO(csilvers): check for arg[0] == '=' for iquote, isystem +CPP_OPTIONS_MAYBE_TWO_WORDS = { + '-MF': lambda ps, arg: _RaiseNotImplemented('-MF'), + '-MT': lambda ps, arg: None, + '-MQ': lambda ps, arg: None, + '-include': lambda ps, arg: ps.include_files.append(arg), + '-imacros': lambda ps, arg: ps.include_files.append(arg), + '-idirafter': lambda ps, arg: ps.after_system_dirs.append(arg), + '-iprefix': lambda ps, arg: ps.set_iprefix(arg), + '-iwithprefix': lambda ps, arg: ps.after_system_dirs.append( + os.path.join(ps.iprefix, arg)), + '-iwithprefixbefore': lambda ps, arg: ps.i_dirs.append( + os.path.join(ps.iprefix, arg)), +# '-isysroot': lambda ps, arg: ps.set_isysroot(arg), + '-isysroot': lambda ps, arg: _RaiseNotImplemented('-isysroot'), + '-imultilib': lambda ps, arg: _RaiseNotImplemented('-imultilib'), + '-isystem': lambda ps, arg: ps.before_system_dirs.append(arg), + '-iquote': lambda ps, arg: ps.quote_dirs.append(arg), +# '--sysroot=': lambda ps, arg: ps.set_sysroot(arg), + '--sysroot=': lambda ps, arg: None, +} +CPP_OPTIONS_MAYBE_TWO_WORDS_FIRST_LETTERS = ('M', 'i', '-') +# A "compile-time" check to make sure the first-letter list is up-to-date +for key in CPP_OPTIONS_MAYBE_TWO_WORDS.keys(): + assert key[1] in CPP_OPTIONS_MAYBE_TWO_WORDS_FIRST_LETTERS + +# These are the cpp options that a) are more than one letter long, +# b) always take an argument, and c) must have that argument as a +# separate word in argv. +CPP_OPTIONS_ALWAYS_TWO_WORDS = { + '-Xpreprocessor': lambda ps, arg: _RaiseNotImplemented('-Xpreprocessor'), + + # In order to parse correctly, this data structure needs to include + # *all* two-word arguments that gcc accepts (we don't want to see + # "gcc -aux-info foo" and think that foo is an output filename...) + # This list is taken from the complete list from the gcc info page: + # "Option Summary". These aren't preprocessor-related, so are noops. + '-aux-info': lambda ps, arg: None, + '--param': lambda ps, arg: None, + '-Xassembler': lambda ps, arg: None, + '-Xlinker': lambda ps, arg: None, +} + +# For efficiency, it's helpful to be able to combine the two above +CPP_OPTIONS_TWO_WORDS = {} +CPP_OPTIONS_TWO_WORDS.update(CPP_OPTIONS_MAYBE_TWO_WORDS) +CPP_OPTIONS_TWO_WORDS.update(CPP_OPTIONS_ALWAYS_TWO_WORDS) + +# These are the cpp options that do not take an argument. +# (Note, most cpp options do not take an argument, but do not pertain to +# preprocessing, so we can ignore them. Those are dealt in the default +# case in our processing loop. This is only for no-argument options +# that we actually care about for preprocessing.) +CPP_OPTIONS_ONE_WORD = { +# '-undef': lambda ps, arg: _RaiseNotImplemented('-undef') + '-undef': lambda ps, arg: None, + '-nostdinc': lambda ps: ps.set_nostdinc(), + # TODO(csilvers): deal with -nostdinc++ as well? +} + +# These are the cpp options that are one letter long, and take an +# argument. In all such cases, the argument may either be the next +# word, or may be appended right after the letter. +CPP_OPTIONS_ONE_LETTER = { + 'D': lambda ps, arg: ps.Dopts.append(arg.split('=')), + 'I': lambda ps, arg: ps.i_dirs.append(arg), +# 'U': lambda ps, arg: _RaiseNotImplemented('-U') # affects computed includes + 'U': lambda ps, arg: None, + 'o': lambda ps, arg: ps.set_outputfile(arg), + 'x': lambda ps, arg: ps.set_language(arg), + + # In order to parse correctly, this data structure needs to include + # *all* two-word arguments that gcc accepts (we don't want to see + # "gcc -L foo" and think that foo is an output filename...) Since + # most one-letter args can go as either '-Lfoo' or '-L foo', we need + # to include (almost) all one-letter args in our list, even when we + # don't care about them. This list is taken from the complete list + # from the gcc info page: "Option Summary". Since these aren't + # preprocessor-related, they are all noops. + 'A': lambda ps, arg: None, + 'l': lambda ps, arg: None, + 'u': lambda ps, arg: None, + 'L': lambda ps, arg: None, + 'B': lambda ps, arg: None, + 'V': lambda ps, arg: None, + 'b': lambda ps, arg: None, +} + + +### DREADFUL PARSER + OPTIMIZED PARSER + +# This parser was written after a *much* simpler parser using regular +# expression turned out to be too slow, two orders of magnitude slower +# than str.split. The parser below is faster than the one based on +# regular expression and more complete, so that's the one we keep. + +NONSPACE_RE = re.compile(r'\S') # don't use \S|$, which introduces backtracking +SPACE_RE = re.compile(r'\s') +NONESC_QUOTE_RE = re.compile(r'[^\\]"|^"') # inefficient +QUOTE_RE = re.compile(r'(?<!\\)"') # backtracking, could also be improved +ESC_QUOTE_RE = re.compile(r'\\"') + +def ParseCommandLineSlowly(line): + """Parse line as if it were issued in a shell. + + Split the line into a list of string arguments indicated by spaces, + except that doubly quoted substrings are treated atomically. Also, + do allow backslash escaped quotes; they are turned into regular + quotes. This function is written for efficiency; only very simple + regular expressions are used in main loop. + + The parser is not needed when the include server is driven by + distcc, because the distcc client passes the argv vector. It is used + as part of a faster parser. + """ + + if "'" in line: + raise NotCoveredError("Single-quotes not accepted in command line.") + args = [] + # Set position of first quote if it exists. + m_unesc_q = NONESC_QUOTE_RE.search(line, 0) + if m_unesc_q: + unesc_q = m_unesc_q.end() - 1 + else: + unesc_q = sys.maxint + m_nonspc = NONSPACE_RE.search(line, 0) + if not m_nonspc: + return args + start = m_nonspc.start() + end = start + 1 + while True: + # Invariant: (1) start is at the beginning of the next argument + # (perhaps at a quote, which will later be removed). (2) end is + # such that line[start:end] is a prefix of the argument. + assert start <= unesc_q + assert start < end <= len(line), (start, end, len(line)) + assert not SPACE_RE.match(line, start) + assert unesc_q == sys.maxint or line[unesc_q] == '"' + try: + end = SPACE_RE.search(line, end).start() + except AttributeError: + end = len(line) + if end < unesc_q: + # We're good: no quotes found, we have an argument. + args.append(ESC_QUOTE_RE.sub( + '"', + QUOTE_RE.sub( + '', + line[start:end]))) + # Search for beginning of next argument. + try: + start = NONSPACE_RE.search(line, end).start() + except AttributeError: + return args + # We have one character so far. + end = start + 1 + continue + # We found a quote. Look for its counterpart. + assert start <= unesc_q < end + if unesc_q == len(line) - 1: + raise NotCoveredError("""Unexpected '"' at end of line.""") + m_unesc_q = NONESC_QUOTE_RE.search(line, unesc_q + 1) + if not m_unesc_q: + raise NotCoveredError("""Missing '"', could not parse command line.""") + assert m_unesc_q.end() - 1 > unesc_q + end = m_unesc_q.end() + if end == len(line): + args.append(ESC_QUOTE_RE.sub( + '"', + QUOTE_RE.sub( + '', + line[start:end]))) + return args + # We found the counterpart before the end of the line. The argument may + # still not be finished. But before continuing, look for the next quote. + m_unesc_q = NONESC_QUOTE_RE.search(line, end) + if m_unesc_q: + unesc_q = m_unesc_q.end() - 1 + else: + unesc_q = sys.maxint + + +def ParseCommandLine(line): + """Parse line as it were issued in a shell (optimized). + """ + # It turns out that str.split() for large string (size 500) is almost two + # orders of magnitude faster than ParseCommandLineSlowly. Usually, when + # there is a '"' this quote is near the beginning of the line (as in dX="some + # thing"). We use this observation to apply split() to the suffix following + # the last quote. In that way, only the prefix up to somewhere around the last + # quote needs to be parsed by more sophisticated means. + quote_pos = line.rfind('"') + if quote_pos == -1: + return line.split() + else: + # Walk forward to a space; the quote could be an escaped one in + # the middle of non-space characters. + good_pos = line.find(' ', quote_pos) + if good_pos != -1: + return (ParseCommandLineSlowly(line[0:good_pos]) + + line[good_pos:].split()) + else: # give up + return ParseCommandLineSlowly(line) + +# Make a regular expression that matches suffixes of strings ending in +# a period followed by a string in the domain of TRANSLATION_UNIT_MAP. +TRANSLATION_UNIT_FILEPATH_RE = ( + re.compile(r".*[.](?P<suffix>%s)$" % + '|'.join([re.escape(ext) + for ext in basics.TRANSLATION_UNIT_MAP.keys()]))) + + +def ParseCommandArgs(args, current_dir, fp_map, dir_map, compiler_defaults, + timer=None): + """Parse arguments like -I to make include directory lists. + + Arguments: + args: list of arguments (strings) + current_dir: string + fp_map: a MapToIndex object + dir_map: a DirectoryMapToIndex object + compiler_defaults: a CompilerDefaults object + timer: a basics.IncludeAnalyzerTimer object + Returns: + (quote_dirs, angle_dirs, files, source_file, source_file_prefix, dopts) + where: + quote_dirs: a list of dir_map-indexed directories + angle_dirs: a list of dir_map-indexed directories + files: a list of fp_map-indexed files + source_file_prefix: the source file name with extension stripped + dopts: a list of items as returned by _SplitMacroArg + Modifies: + compiler_defaults + """ + if __debug__: Debug(DEBUG_TRACE, "ParseCommand %s" % args) + + assert isinstance(dir_map, cache_basics.DirectoryMapToIndex) + assert isinstance(fp_map, cache_basics.MapToIndex) + + parse_state = ParseState() + + if len(args) < 2: + raise NotCoveredError("Command line: too few arguments.") + compiler = args[0] + i = 1 + while i < len(args): + # First, deal with everything that's not a flag-option + if args[i][0] != '-' or args[i] == '-': # - is the stdin file + if args[i].startswith('"-'): + pass # TODO(csilvers): parse arg inside quotes? + else: + parse_state.file_names.append(args[i]) # if not a flag, it's a file + i += 1 + continue + + # Deal with the one-letter options -- the kind most commonly seen. + # We need to figure out whether the option-argument is glommed on to + # the end of the option ("-Dfoo"), or is a separate word ("-D foo"). + action = CPP_OPTIONS_ONE_LETTER.get(args[i][1]) # letter after the - + if action: + arg = args[i][2:] + if arg: # the glommed-onto-end case + action(parse_state, arg) + i += 1 + else: # the separate-word case + try: + action(parse_state, args[i+1]) + i += 2 + except IndexError: + raise NotCoveredError("No argument found for option '%s'" % args[i]) + continue + + # Deal with the have-arg options with the arg as the 2nd word ("-MF foo"). + action = CPP_OPTIONS_TWO_WORDS.get(args[i]) + if action: + try: + action(parse_state, args[i+1]) + i += 2 + except IndexError: + raise NotCoveredError("No argument found for option '%s'" % args[i]) + continue + + # Deal with the options that take no arguments ("-nostdinc"). + action = CPP_OPTIONS_ONE_WORD.get(args[i]) + if action: + action(parse_state) + i += 1 + continue + + # Deal with the have-arg options with the arg concatenated to the word. + # ("-MFfoo"). We do this last because it's slowest. + if args[i][1] in CPP_OPTIONS_MAYBE_TWO_WORDS_FIRST_LETTERS: # filter + found_action = False + for (option, action) in CPP_OPTIONS_MAYBE_TWO_WORDS.items(): + if action and args[i].startswith(option): + action(parse_state, args[i][len(option):]) + i += 1 + found_action = True + break + if found_action: # what we really need here is a goto! + continue + + # Whatever is left must be a one-word option (that is, an option + # without an arg) that it's safe to ignore. + i += 1 + continue + # Done parsing arguments! + + # Sanity-checking on arguments + # -I- is a special form of the -I command. + if "-" in parse_state.i_dirs: + _RaiseNotImplemented('-I-', '(Use -iquote instead.)') + + if len(parse_state.file_names) != 1: + raise NotCoveredError( + "Could not locate name of translation unit: %s." % parse_state.file_names, + send_email=False) + + source_file = parse_state.file_names[0] + + if parse_state.output_file: + # Use output_file to create prefix + source_file_prefix = re.sub("[.]o$", "", parse_state.output_file) + else: + # Remove suffix from source file + source_file_prefix = re.sub("[.](%s)$" % + "|".join(basics.TRANSLATION_UNIT_MAP.keys()), + "", + source_file) + source_file_prefix = os.path.join(current_dir, source_file_prefix) + if parse_state.language == 'none': # no explicit -x flag, or -x none + language_match = TRANSLATION_UNIT_FILEPATH_RE.match(source_file) + if not language_match: + raise NotCoveredError( + "For source file '%s': unrecognized filename extension" % source_file) + parse_state.language = language_match.group('suffix') + assert parse_state.language in basics.TRANSLATION_UNIT_MAP + + compiler_defaults.SetSystemDirsDefaults(compiler, timer) + + def IndexDirs(dir_list): + """Normalize directory names and index. + + Remove leading "./" and trailing "/"'s from directory paths in + dir_list before indexing them according to dir_map. + """ + S = basics.SafeNormPath + I = dir_map.Index + return [I(S(d)) for d in dir_list] + + # Now string the directory lists together according to CPP semantics. + angle_dirs = IndexDirs(parse_state.i_dirs) + angle_dirs.extend(IndexDirs(parse_state.before_system_dirs)) + if not parse_state.nostdinc: + angle_dirs.extend( + IndexDirs(compiler_defaults.system_dirs_default + [compiler][basics.TRANSLATION_UNIT_MAP[parse_state.language]])) + angle_dirs.extend(IndexDirs(parse_state.after_system_dirs)) + + quote_dirs = IndexDirs(parse_state.quote_dirs) + quote_dirs.extend(angle_dirs) + angle_dirs = tuple(angle_dirs) + quote_dirs = tuple(quote_dirs) + include_files = tuple([fp_map.Index(basics.SafeNormPath(f)) + for f in parse_state.include_files]) + + if __debug__: Debug(DEBUG_TRACE, ("ParseCommand result: %s %s %s %s %s %s" % + (quote_dirs, angle_dirs, include_files, + source_file, source_file_prefix, + parse_state.Dopts))) + return (quote_dirs, angle_dirs, include_files, source_file, + source_file_prefix, parse_state.Dopts) diff --git a/include_server/parse_command_test.py b/include_server/parse_command_test.py new file mode 100755 index 0000000..fd5db01 --- /dev/null +++ b/include_server/parse_command_test.py @@ -0,0 +1,196 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +"""Parsing of C and C++ commands and extraction of search paths.""" + +__author__ = "Nils Klarlund" + +import os +import time + +import basics +import cache_basics +import parse_command +import unittest + +NotCoveredError = basics.NotCoveredError + +class ParseCommandUnitTest(unittest.TestCase): + + def setUp(self): + + basics.opt_debug_pattern = 1 + + caches = cache_basics.SetUpCaches() + + self.includepath_map = caches.includepath_map + self.canonical_path = caches.canonical_path + self.directory_map = caches.directory_map + self.realpath_map = caches.realpath_map + self.systemdir_prefix_cache = caches.systemdir_prefix_cache + + mock_compiler = '/usr/crosstool/v8/gcc-4.1.0-glibc-2.2.2/blah/gcc' + self.mock_compiler = mock_compiler + + def Mock_SetSystemDirsDefaults(compiler, timer=None): + if compiler != mock_compiler: + raise Exception, "compiler: %s, mock_compiler: %s" % ( + compiler, mock_compiler) + + self.compiler_defaults = lambda x: x + self.compiler_defaults.SetSystemDirsDefaults = Mock_SetSystemDirsDefaults + self.compiler_defaults.system_dirs_default_all = [] + self.compiler_defaults.system_dirs_default = {} + self.compiler_defaults.system_dirs_default[mock_compiler] = {} + self.compiler_defaults.system_dirs_default[mock_compiler]['c'] = [] + self.compiler_defaults.system_dirs_default[mock_compiler]['c++'] = [] + + def tearDown(self): + pass + + + def test__SplitMacroArg(self): + self.assertEqual(parse_command._SplitMacroArg("="), ["="]) + self.assertEqual(parse_command._SplitMacroArg("A="), ["A", ""]) + self.assertEqual(parse_command._SplitMacroArg("A=B=C"), ["A", "B=C"]) + + + def _RetrieveDirectoriesExceptSys(self, directory_idxs): + return cache_basics.RetrieveDirectoriesExceptSys( + self.directory_map, + self.realpath_map, + self.systemdir_prefix_cache, + directory_idxs) + + def test_ParseCommandLine(self): + + self.assertEqual(parse_command.ParseCommandLine( + """ "a"b"\\"c" "a"\n"b" a b\\"c"""), + ['ab"c', 'a', 'b', 'a', 'b"c']) + + + self.assertEqual(parse_command.ParseCommandLine( + """this is a test"""), + ['this', 'is', 'a', 'test']) + self.assertEqual(parse_command.ParseCommandLine( + """ this is a test"""), + ['this', 'is', 'a', 'test']) + self.assertEqual(parse_command.ParseCommandLine( + """this is a test """), + ['this', 'is', 'a', 'test']) + + self.assertEqual(parse_command.ParseCommandLine( + 'this " is" a"test" '), + ['this', ' is', 'atest']) + + self.assertEqual(parse_command.ParseCommandLine( + r'this " \"is" a"test" '), + ['this', ' "is', 'atest']) + + self.assertEqual(parse_command.ParseCommandLine( + 'this " is" a"test"'), + ['this', ' is', 'atest']) + + self.assertRaises(NotCoveredError, + parse_command.ParseCommandLine, + """this is" a"test" """) + self.assertRaises(NotCoveredError, + parse_command.ParseCommandLine, + 'this is" a"test"') + + def test_ParseCommandArgs(self): + + quote_dirs, angle_dirs, include_files, filepath, _incl_clos_f, _d_opts = ( + parse_command.ParseCommandArgs( + parse_command.ParseCommandLine( + self.mock_compiler + " -isystem system -Imice -iquote/and -I/men a.c " + " -include included_A.h " + " -includeincluded_B.h " + "-Xlinker W,l -L /ignored_by_us -o a.o"), + os.getcwd(), + self.includepath_map, + self.directory_map, + self.compiler_defaults)) + + self.assertEqual( + (self._RetrieveDirectoriesExceptSys(quote_dirs), + self._RetrieveDirectoriesExceptSys(angle_dirs), + [self.includepath_map.String(i) for i in include_files], + filepath), + (('/and', 'mice', '/men', 'system'), + ('mice', '/men', 'system'), + ["included_A.h", "included_B.h"], + 'a.c')) + + + self.assertRaises(NotCoveredError, + parse_command.ParseCommandArgs, + parse_command.ParseCommandLine( + self.mock_compiler +" -I- -iquote a.c"), + os.getcwd(), + self.includepath_map, + self.directory_map, + self.compiler_defaults) + + quote_dirs, angle_dirs, include_files, filepath, _incl_cls_file, _d_opts = ( + parse_command.ParseCommandArgs(parse_command.ParseCommandLine( + "/usr/crosstool/v8/gcc-4.1.0-glibc-2.2.2/blah/gcc" + + " -fno-exceptions -funsigned-char -D__STDC_FORMAT_MACROS -g0" + + " -D_REENTRANT -DCOMPILER_GCC3 -DCOMPILER_GCC4 -DARCH_PIII -DOS_LINUX" + + " -fmessage-length=0 -fno-strict-aliasing -fno-tree-vrp -D_REENTRANT" + + " -DHAS_vsnprintf" + + " -Iobj/gcc-4.1.0-glibc-2.2.2-piii-linux-g0-dbg/genfiles/third_party/libxml/third_party/libxml" + + " -Ithird_party/zlib -iquote . -fno-strict-aliasing -c -o" + + " obj/gcc-4.1.0-glibc-2.2.2-piii-linux-g0-dbg/bin/third_party/libxml/threads.c.o" + + " third_party/libxml/threads.c"), + os.getcwd(), + self.includepath_map, + self.directory_map, + self.compiler_defaults)) + self.assertEqual( + (self._RetrieveDirectoriesExceptSys(quote_dirs), + self._RetrieveDirectoriesExceptSys(angle_dirs), + filepath), + (('', + 'obj/gcc-4.1.0-glibc-2.2.2-piii-linux-g0-dbg/genfiles/third_party/libxml/third_party/libxml', + 'third_party/zlib'), + ('obj/gcc-4.1.0-glibc-2.2.2-piii-linux-g0-dbg/genfiles/third_party/libxml/third_party/libxml', + 'third_party/zlib'), + 'third_party/libxml/threads.c')) + + def test_time_ParseCommandArgs(self): + """Time ParseCommandArgs.""" + fd = open("test_data/gws-main.o.cmd", "r") + whopper = fd.read() + fd.close() + # TODO(klarlund): make this into a fail/pass test as well. + t = time.time() + for unused_i in range(100): + (quote_dirs, angle_dirs, include_files, filepath, + _include_closure_file, _d_opts) = ( + parse_command.ParseCommandArgs( + parse_command.ParseCommandLine(whopper), + os.getcwd(), + self.includepath_map, + self.directory_map, + self.compiler_defaults)) + print "100 iterations of ParseCommandArgs takes %3.1fs" % (time.time() - t) + return True + + +unittest.main() diff --git a/include_server/parse_file.py b/include_server/parse_file.py new file mode 100755 index 0000000..c13d27e --- /dev/null +++ b/include_server/parse_file.py @@ -0,0 +1,342 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +"""A very fast directives-only parser for C and C++ source code. + +We parse only the following directives: + #include (the standard C/C++ inclusion mechanism) + #include_next (a GNU C/C++ extension) + #import (an Objective-C feature, similar to #include) + #define (because #defines can affect the results of '#include MACRO') +""" + +__author__ = 'Nils Klarlund' + +import re +import time + +import basics +import cache_basics +import statistics + +Debug = basics.Debug +DEBUG_TRACE = basics.DEBUG_TRACE +DEBUG_TRACE2 = basics.DEBUG_TRACE2 +NotCoveredError = basics.NotCoveredError + +# For coarse and fast scanning +RE_INCLUDE_DEFINE = re.compile("include|define|import") + +# For fine-grained, but slow backtracking, parsing +POUND_SIGN_RE = re.compile(r""" + ^ # start of line + [ \t]* # space(s) + ([*][/])? # a possible ..*/ ending block comment + [ \t]* # space(s) + ([/][*] [^\n]* [*][/])* # initial block comment(s) /*...*/ + [ \t]* # space(s) + (?P<directive> # group('directive') -- what we're after + [#] # the pound sign + [ \t]* # space(s) + (define|include_next|include|import)\b # the directive + ((?!\\\n).)* # the rest on this line: zero or more + # characters, each not a backslash that + # is followed by \n + (\\\n((?!\\\n).)*)* # (backslash + \n + rest of line)* + ) + """, re.VERBOSE + re.MULTILINE) + + +NOT_COMMA_OR_PARENS = "([^(),])" + +# For parsing macro expressions of the form: +# symbol +# symbol (something, ..., something), where something is not ',', '(', or ')' +MACRO_EXPR = r""" + (?P<symbol>\w+) # the symbol, named 'symbol' + ( \s* + [(] \s* # beginning parenthesis + (?P<args> # a parenthesized expression (with no + # containing expressions -- a limitation) + # named 'args' + %(NOT_COMMA_OR_PARENS)s* # the first argument (if it exists) + ([,]%(NOT_COMMA_OR_PARENS)s*)* # subsequent arguments + ) + [)] # ending parenthesis + )?""" % {'NOT_COMMA_OR_PARENS': NOT_COMMA_OR_PARENS} + +MACRO_EXPR_RE = re.compile(MACRO_EXPR, re.VERBOSE) + +# Nice little parser of certain directive lines (after backslash-ended +# line continuations and comments are removed) +DIRECTIVE_RE = re.compile(r""" + ^[ \t]* + [#] + [ \t]* + ( + ((?P<include> include_next | include | import) + \s* + ( "(?P<quote> (\w|[_/.+-])*)" | # "bar/foo.h" + <(?P<angle> (\w|[_/.+-])*)> | # <stdio.h> + (?P<expr> .*?)) # expr, match . minimally + ) + | + (?P<define> define \s+ (?P<lhs> %s) # insert MACRO_EXPR here + \s* (?P<rhs> .*?)) # match . minimally before + # trailing white space + ) + \s* # trailing whitespace + ((/[*]|//).*)? # optional trailing comment start + $ + """ % MACRO_EXPR, + re.VERBOSE) + +# +INCLUDE_STRING_RE = re.compile(r""" + ^ + \s* + ( "\s*(?P<quote> (\w|[_/.+-])*)\s*" | + <\s*(?P<angle> (\w|[_/.+-])*)\s*> + ) + \s* + $ +""", re.VERBOSE) + +# For ridding lines of backslash +BACKSLASH_RE = re.compile(r"\\\n", re.MULTILINE) + +# For matching non-comment prefix of line. +COMMENT_RE = re.compile(r"((?!/[*]|//).)*") + +# FOR SEARCHING AFTER /* .. */. +PAIRED_COMMENT_RE = re.compile(r"(/[*].*?[*]/)") + + +def InsertMacroDefInTable(lhs, rhs, symbol_table, callback_function): + """Insert the definition of a pair (lhs, rhs) into symbol table. + + Arguments: + lhs: a string, of the form "symbol" or "symbol(param1, ..., paramN)" + rhs: a string + symbol_table: where the definition will be inserted + callback_function: a function called with value "symbol" + """ + m_expr = MACRO_EXPR_RE.match(lhs) + if m_expr.end(0) != len(lhs): + raise NotCoveredError( + "Unexpected macro definition with LHS: '%s'." % lhs) + # Calculate the definition df, either + # - a pair ([arg_1, .., arg_n], rhs) where arg_i is the + # i'th formal parameter (function-like macro definition), or + # - just a symbol (object-like macro definition) + if m_expr.group('args') != None: # perhaps '' + # A function-like macro definition. + # Construct pair (list of formal parameters, rhs). + args = m_expr.group('args').split(',') + df = args, rhs + # lhs is adjusted to be just the 'function' name + lhs = m_expr.group('symbol') + else: # m_expr.group('args') + # An object-like macro definition + assert m_expr.group('symbol') == lhs + df = rhs + if lhs not in symbol_table: + symbol_table[lhs] = [df] + else: + symbol_table[lhs].append(df) + callback_function(lhs) + + +class ParseFile(object): + """Parser class for syntax understood by CPP, the C and C++ + preprocessor. An instance of this class defines the Parse method.""" + + def __init__(self, includepath_map): + """Constructor. Make a parser. + + Arguments: + includepath_map: string-to-index map for includepaths + """ + assert isinstance(includepath_map, cache_basics.MapToIndex) + self.includepath_map = includepath_map + self.define_callback = lambda x: None + + def SetDefineCallback(self, callback_function): + """Set a callback function, which is invoked for '#define's. + + The function is called as callback_function(symbol), whenever a '#define' + of symbol is parsed. The callback allows an include processor to adjust + its notion of which expressions are still current. If we (the include + processor) already met + + #define A B + + and later meet + + #define B + + whether this is the first definition of B or not, then the possible + meanings of A have changed. We set up a callback to identify such + situations.""" + + self.define_callback = callback_function + + def _ParseFine(self, poundsign_match, includepath_map_index, file_contents, + symbol_table, quote_includes, angle_includes, expr_includes, + next_includes): + """Helper function for ParseFile.""" + Debug(DEBUG_TRACE2, "_ParseFine %s", + file_contents[poundsign_match.start('directive'): + poundsign_match.end('directive')]) + m = DIRECTIVE_RE.match( # parse the directive + PAIRED_COMMENT_RE.sub( # remove possible paired comments + "", + BACKSLASH_RE.sub( # get rid of lines ending in backslash + "", + file_contents[poundsign_match.start('directive'): + poundsign_match.end('directive')]))) + if m: + try: + groupdict = m.groupdict() + if groupdict['include'] == 'include' or \ + groupdict['include'] == 'import': + if groupdict['quote']: + quote_includes.append(includepath_map_index(m.group('quote'))) + elif groupdict['angle']: + angle_includes.append(includepath_map_index(m.group('angle'))) + elif groupdict['expr']: + expr_includes.append(m.group('expr').rstrip()) + else: + assert False + elif groupdict['include'] == 'include_next': + # We do not, in fact, distinguish between the two kinds of + # include_next's, because we conservatively assume that they are of + # the quote variety. + if groupdict['quote']: + next_includes.append(includepath_map_index(m.group('quote'))) + elif groupdict['angle']: + next_includes.append(includepath_map_index(m.group('angle'))) + # The following restriction would not be too hard to remove. + elif groupdict['expr']: + NotCoveredError( + "For include_next: cannot deal with computed include here.") + else: + assert False + raise NotCoveredError("include_next not parsed") + elif groupdict['define']: + if not groupdict['lhs']: + raise NotCoveredError("Unexpected macro definition with no LHS.") + else: + lhs = m.group('lhs') + rhs = groupdict['rhs'] and groupdict['rhs'] or None + InsertMacroDefInTable(lhs, rhs, symbol_table, self.define_callback) + except NotCoveredError, inst: + # Decorate this exception with the filename, by recreating it + # appropriately. + if not inst.source_file: + raise NotCoveredError(inst.args[0], + self.filepath, + send_email = inst.send_email) + else: + raise + + def Parse(self, filepath, symbol_table): + """Parse filepath for preprocessor directives and update symbol table. + + Arguments: + filepath: a string + symbol_table: a dictionary, see module macro_expr + + Returns: + (quote_includes, angle_includes, expr_includes, next_includes), where + all are lists of filepath indices, except for expr_includes, which is a + list of expressions. + """ + Debug(DEBUG_TRACE, "ParseFile %s", filepath) + + assert isinstance(filepath, str) + self.filepath = filepath + parse_file_start_time = time.clock() + statistics.parse_file_counter += 1 + + includepath_map_index = self.includepath_map.Index + + try: + fd = open(filepath, "r") + except IOError, msg: + # This normally does not happen because the file should be known to + # exists. Still there might be, say, a permissions issue that prevents it + # from being read. + raise NotCoveredError("Parse file: '%s': %s" % (filepath, msg), + send_email=False) + + file_contents = fd.read() + fd.close() + + quote_includes, angle_includes, expr_includes, next_includes = ( + [], [], [], []) + + i = 0 + line_start_last = None + + while True: + + # Scan coarsely to find something of interest + mfast = RE_INCLUDE_DEFINE.search(file_contents, i + 1) + if not mfast: break + i = mfast.end() + # Identify the line of interest by scanning backwards to \n + line_start = file_contents.rfind("\n", 0, i) + 1 # to beginning of line + # Now, line_start is -1 if \n was not found. + + ### TODO(klarlund) continue going back if line continuation preceeding + + # Is this really a new line? + if line_start == line_start_last: continue + line_start_last = line_start + + # Here we should really skip back over lines to see whether a totally + # pathological situation involving '\'-terminated lines like: + # + # #include <stdio.h> + # # Start of pathological situation involving line continuations: + # # \ + # \ + # \ + # \ + # include "nidgaard.h" + # + # occurs, where the first # on each line is just Python syntax and should + # not be considered as part of the C/C++ example. This code defines a + # valid directive to include "nidgaard.h". We will not handle such + # situations correctly -- the include will be missed. + + # Parse the line of interest according to fine-grained parser + poundsign_match = POUND_SIGN_RE.match(file_contents, line_start) + + if not poundsign_match: + continue + + self._ParseFine(poundsign_match, includepath_map_index, file_contents, + symbol_table, quote_includes, angle_includes, + expr_includes, next_includes) + + + statistics.parse_file_total_time += time.clock() - parse_file_start_time + + return (quote_includes, angle_includes, expr_includes, next_includes) diff --git a/include_server/parse_file_test.py b/include_server/parse_file_test.py new file mode 100755 index 0000000..b42e7f8 --- /dev/null +++ b/include_server/parse_file_test.py @@ -0,0 +1,154 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +"""Tests for parse_file.""" + +__author__ = "opensource@google.com" + +import unittest + +import basics +import cache_basics +import parse_file +import include_server +import include_analyzer + +class parse_file_Test(unittest.TestCase): + + def setUp(self): + include_server.print_statistics = False + basics.InitializeClientTmp() + include_server.write_include_closure_file = True + self.include_analyzer = include_analyzer.IncludeAnalyzer() + + def tearDown(self): + pass + + def test_RegularExpressions(self): + + self.assertEqual(parse_file.POUND_SIGN_RE.match( + """ #\tinclude blah. blah.""" + ).group(0), " #\tinclude blah. blah.") + + self.assertEqual(parse_file.POUND_SIGN_RE.match( + """ # gggg include blah. blah.""" + ), None) + + self.assertEqual(parse_file.POUND_SIGN_RE.match( + """ */ /**/ /* a */ # include blah. blah.""" + ).group(0), ' */ /**/ /* a */ # \tinclude blah. blah.') + + self.assertEqual( + parse_file.MACRO_EXPR_RE.search("m(a, b) + c + n(d)").groupdict(), + {'args': 'a, b', 'symbol': 'm'}) + + # The expression we recognize do not include nested parenthesis + self.assertEqual( + parse_file.MACRO_EXPR_RE.search("m(a, (b)) + c + n(d)").groupdict(), + {'args': None, 'symbol': 'm'}) + + self.assertEqual(parse_file.MACRO_EXPR_RE.match("random()").group('symbol'), + "random") + + self.assert_(parse_file.DIRECTIVE_RE.match( + """ # include <a.c>""").group('angle') == 'a.c') + self.assert_(parse_file.DIRECTIVE_RE.match( + """ # include mac(a.c, mic)""").group('expr') == 'mac(a.c, mic)') + self.assert_(parse_file.DIRECTIVE_RE.match( + """ # include "a.c" """).group('quote') == 'a.c') + self.assert_(parse_file.DIRECTIVE_RE.match( + """ #include "a.c" """).group('quote') == 'a.c') + self.assert_(parse_file.DIRECTIVE_RE.match( + """ #include"a.c" """).group('quote') == 'a.c') + + self.assertEqual(parse_file.DIRECTIVE_RE.match( + """ #define m(a) <a##_post.c> """).group('rhs'), + '<a##_post.c>') + + self.assertEqual( + parse_file.DIRECTIVE_RE.match("#define xmlRealloc(ptr, size)" + + " xmlReallocLoc((ptr), (size)," + + " __FILE__, __LINE__)").group('lhs'), + "xmlRealloc(ptr, size)") + + self.assertEqual( + parse_file.DIRECTIVE_RE.match("#define random() rand()").group('lhs'), + "random()") + + self.assertEqual( + parse_file.DIRECTIVE_RE.match("#define ABBA ").group('lhs'), + "ABBA") + + self.assertEqual( + parse_file.DIRECTIVE_RE.match("#define ABBA").group('lhs'), + "ABBA") + + self.assertEqual(parse_file.BACKSLASH_RE.sub("", +"""a\ +b\ +c\ +d"""), "abcd") + self.assertEqual(parse_file.BACKSLASH_RE.sub("", """a +b +"""), + """a +b +""") + + self.assertEqual(parse_file.PAIRED_COMMENT_RE.sub("", "ab/*./*..*/cd"), "abcd") + self.assertEqual(parse_file.PAIRED_COMMENT_RE.sub("", "ab/*/cd"), "ab/*/cd") + + self.assertEqual(parse_file.COMMENT_RE.match("ab/*cd").group(), "ab") + self.assertEqual(parse_file.COMMENT_RE.match("ab//cd").group(), "ab") + self.assertEqual(parse_file.COMMENT_RE.match("ab/cd").group(), "ab/cd") + + self.assertEqual(parse_file. + INCLUDE_STRING_RE.match(""" < ab.c>""").group('angle'), + "ab.c") + + def test_ParseFile(self): + + includepath_map = cache_basics.MapToIndex() + canonical_path = cache_basics.CanonicalPath() + parse_file_obj = parse_file.ParseFile(includepath_map) + + symbol_table = {} + self.assertEqual(parse_file_obj.Parse( + "test_data/more_macros.c", symbol_table), + ([], [], ['TEMPLATE_VARNAME(foo)'], [])) + self.assertEqual(symbol_table.keys(), + ['ILLFORMED', 'AS_STRING_INTERNAL', + 'TEMPLATE_VARNAME', 'AS_STRING']) + [([arg], val)] = symbol_table['TEMPLATE_VARNAME'] + self.assertEqual(arg, '_filename_') + self.assertEqual(val, 'AS_STRING(maps/_filename_.tpl.varnames.h)') + + self.assertEqual(parse_file_obj.Parse( + "test_data/computed_includes.c", symbol_table), + ([], + [], + [ 'A' , 'm(abc)' ], + [])) + self.assertEqual(symbol_table['A'], ['"p1.h"']) + [val] = symbol_table['ILLFORMED'] + self.assertEqual(val, "(_filename_,(x)) " + + "AS_STRING(maps/_filename_.tpl.varnames.h, " + + "NOTHANDLED(_filename_))") + +unittest.main() diff --git a/include_server/run.py b/include_server/run.py new file mode 100755 index 0000000..db9ad59 --- /dev/null +++ b/include_server/run.py @@ -0,0 +1,106 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +"""Run with PYTHONPATH including appropriate place for extension module.""" + +__author__ = "opensource@google.com" + +import os +import sys +import glob + + +USAGE="""Usage: run.py [--install] CMD [ARG...] + +Option: + + --run_in_install: find extension module under lib of installation directory + +Locate a Python extension module in some directory D under the +c_extensions/build subdirectory of the directory that contains the present +command. With --run_in_install, assume that this script resides in an installed +version; this means that the directory structure is different and D is located +as ../../lib. + +Then run CMD [ARG...] with environment variable PYTHONPATH augmented with D. + +Normally, print out a message where the extension module is found. But, with +--run_in_install this message is suppressed. + +Examples: + +From anywhere: + # Start include server. + /home/distcc/include_server/run.py include_server.py + +In the include_server directory: + # Run include_server tests. + ./run.py include_server_test.py + # Pycheck include_server. + ./run.py `which pychecker` include_server.py + +In installed distcc-pump: + # See 'pump' script. + $include_server_location/run.py --run_in_install include_server.py .. +""" + +def usage(): + print USAGE + sys.exit(1) + +DEFAULT_PATH = "c_extensions/build/lib.*/*" + +cmd = sys.argv[0] +if len(sys.argv) < 2: usage() + +dirname = os.path.dirname(cmd) +directory = os.path.abspath(os.path.join(os.getcwd(), dirname)) + +# Define lib_directory, the directory of the .so, one way or another. +if sys.argv[1]== '--run_in_install': + del sys.argv[1] + if len(sys.argv) < 2: usage() + # We are in share/python. + lib_directory = os.path.join(dirname, "../../lib") +else: + # We're in the source directory, not in installation. + place_to_look = directory + '/' + DEFAULT_PATH + potential_libs = glob.glob(place_to_look) + # Now potential_libs is supposed to contain the filepaths of dynamically + # loaded libraries. We expect exactly one such filepath. + if len(potential_libs) == 0: + sys.exit("No extension modules of the form '%s' found." % + place_to_look) + if len(potential_libs) > 1: + sys.exit("More than one extension module found. " + + " Cannot determine which one to use.") + lib_directory = os.path.dirname(potential_libs[0]) + print "__________Using Python extension in %s" % lib_directory + +# Now, the all important change to PYTHONPATH. Note that we obliterate any +# environmental setting setting as well. This improves performance in +# installations with unneeded Python resources on network disks. +os.environ['PYTHONPATH'] = lib_directory + +try: + os.execv(os.path.join(directory, sys.argv[1]), sys.argv[1:]) +except OSError: + print >> sys.stderr, ( + "Could not run: '%s' with arguments: %s" % + (os.path.join(directory, sys.argv[1]), + sys.argv[1:])) diff --git a/include_server/setup.py b/include_server/setup.py new file mode 100755 index 0000000..cad0b5c --- /dev/null +++ b/include_server/setup.py @@ -0,0 +1,83 @@ +#! /usr/bin/python2.4 + +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +"""Build the include server module""" + +__author__ = "Manos Renieris" + +import distutils +import os +from distutils.core import setup +from distutils.extension import Extension + +ext = Extension( + name="include_server.distcc_pump_c_extensions", + sources=[ + '../distcc/src/clirpc.c', + '../distcc/src/clinet.c', + '../distcc/src/state.c', + '../distcc/src/srvrpc.c', + '../distcc/src/pump.c', + '../distcc/src/rpc.c', + '../distcc/src/io.c', + '../distcc/src/include_server_if.c', + '../distcc/src/trace.c', + '../distcc/src/util.c', + '../distcc/src/tempfile.c', + '../distcc/src/filename.c', + '../distcc/src/bulk.c', + '../distcc/src/sendfile.c', + '../distcc/src/compress.c', + '../distcc/src/argutil.c', + '../distcc/src/cleanup.c', + '../distcc/src/emaillog.c', + '../distcc/src/timeval.c', + '../distcc/src/netutil.c', + '../distcc/lzo/minilzo.c', + 'c_extensions/distcc_pump_c_extensions_module.c', + ], + include_dirs = ["../distcc/src", + "../distcc/lzo", + os.path.join(os.getenv("BUILDDIR") or "", + "../distcc/src"), + os.path.join(os.getenv("BUILDDIR") or "", + "../../distcc/src"), + ], + define_macros = [('_GNU_SOURCE', 1)], + library_dirs = [], + libraries = [], + runtime_library_dirs = [], + extra_objects = [], + extra_compile_args = ['-Wall', '-Wextra', '-Werror'], + extra_link_args = ['-Wall', '-Wextra', '-Werror'], +) + +args = { + 'name': "include_server", + 'package_dir': {'include_server':'.'}, + 'version': '1.00', + 'description': "Include server for distcc-pump", + 'author': "Nils Klarlund", + 'author_email': "opensource@google.com", + 'url': 'http://code.google.com/p/distcc-pump', + 'long_description': """The include server is part of distcc-pump.""", + 'packages': ["include_server"], + 'ext_modules': [ext], +} + +setup(**args) diff --git a/include_server/statistics.py b/include_server/statistics.py new file mode 100755 index 0000000..2dc002a --- /dev/null +++ b/include_server/statistics.py @@ -0,0 +1,121 @@ +#! /usr/bin/python2.4 +# +# Copyright 2007 Google Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +"""Statistics gathering for the distcc-pump include server.""" + +__author__ = "Nils Klarlund" + +import time + +resolve_expr_counter = 0 # number of computed includes +master_hit_counter = 0 # summary node hits +master_miss_counter = 0 # summary node misses +resolve_counter = 0 # calls of Resolve method +search_counter = 0 # number of probes in directory lists +build_stat_counter = 0 # number of stats in build_stat_cache +sys_stat_counter = 0 # number of calls to OS stat +translation_unit_counter = 0 # number of translation units + +start_time = None +translation_unit_time = None +min_time = float('Inf') +max_time = 0.0 +total_time = 0.0 + +parse_file_total_time = 0.0 +parse_file_counter = 0 # number of files parsed + +parse_file_counter_last = 0 # the number of files parsed after previous + # translation unit + +quote_path_total = 0 # total length of quote directory lists +angle_path_total = 0 # total length of angle directory lists + +len_calculated_closure = 0 # number of all included files +len_calculated_closure_nonsys = 0 # same, but excluding system files + # known to compiler +len_exact_closure = 0 # number of all files in CPP-calculated closure +len_surplus_nonsys = 0 # the difference between + # len_calculated_closure and number of files + # in exact closure that are not known to compiler + +find_node_counter = 0 # number of times FindNode is called + + +def StartTiming(): + global start_time, translation_unit_counter + """Mark the start of a request to find an include closure.""" + translation_unit_counter += 1 + start_time = time.clock() + + +def EndTiming(): + """Mark the end of an include closure calculation.""" + global translation_unit_time, min_time, max_time, total_time + translation_unit_time = time.clock() - start_time + min_time = min(translation_unit_time, min_time) + max_time = max(translation_unit_time, max_time) + total_time += translation_unit_time + + +def PrintStatistics(include_analyzer): + # Avoid division by zero in non-interesting case. + if translation_unit_counter == 0: return + + print "TRANSLATION_UNIT: %s" % include_analyzer.translation_unit + print (("TIME: last %-2.3fs, min %-2.3fs, " + "max %-2.3fs, average %-2.3fs, #: %5d, total: %5.1fs") % + (translation_unit_time, min_time, max_time, + total_time/translation_unit_counter, + translation_unit_counter, total_time)) + print ("PARSING: total %-5.3fs, total count: %4d, new files: %-5d" % + (parse_file_total_time, parse_file_counter, + parse_file_counter - parse_file_counter_last)) + print "COUNTER: resolve_expr_counter: %8d" % resolve_expr_counter + print "COUNTER: master_hit_counter: %8d" % master_hit_counter + print "COUNTER: master_miss_counter: %8d" % master_miss_counter + print "SIZE: master_cache %8d" % ( + len(include_analyzer.master_cache)) + print "COUNTER: sys_stat_counter: %10d" % sys_stat_counter + print "COUNTER: build_stat_counter: %10d" % build_stat_counter + if resolve_counter != 0: + print "COUNTER: search_counter (average): %4.1f" % ( + float(search_counter)/resolve_counter) + print "SIZE: include_dir_pairs: %8d" % ( + len(include_analyzer.include_dir_pairs)) + if 'quote_dirs' in include_analyzer.__dict__: + print "SIZE: quote_path %8d" % ( + len(include_analyzer.quote_dirs)) + if 'angle_dirs' in include_analyzer.__dict__: + print "SIZE: angle_path %8d" % ( + len(include_analyzer.angle_dirs)) + print "SIZE: quote_path (average) %4.1f" % ( + float(quote_path_total)/translation_unit_counter) + print "SIZE: angle_path (average) %4.1f" % ( + float(angle_path_total)/translation_unit_counter) + print "SIZE: quote_dirs_set %8d" % ( + len(include_analyzer.quote_dirs_set)) + print "SIZE: angle_dirs_set: %8d" % ( + len(include_analyzer.angle_dirs_set)) + print + print "SIZE: calculated_closure: %8d" % len_calculated_closure + print "SIZE: calculated_closure_nonsys: %8d" % ( + len_calculated_closure_nonsys) + print "SIZE: exact_closure %8d" % len_exact_closure + print "SIZE: surplus_nonsys %8d" % len_surplus_nonsys + print diff --git a/include_server/test_data/abc_post.c b/include_server/test_data/abc_post.c new file mode 100755 index 0000000..5934e6c --- /dev/null +++ b/include_server/test_data/abc_post.c @@ -0,0 +1 @@ +/* Used by computed_includes.c */ diff --git a/include_server/test_data/abc_pre.c b/include_server/test_data/abc_pre.c new file mode 100755 index 0000000..c9e98a6 --- /dev/null +++ b/include_server/test_data/abc_pre.c @@ -0,0 +1 @@ +/* Used by computed_includes.c */ diff --git a/include_server/test_data/computed_includes.c b/include_server/test_data/computed_includes.c new file mode 100755 index 0000000..11b18f5 --- /dev/null +++ b/include_server/test_data/computed_includes.c @@ -0,0 +1,10 @@ +#define A "p1.h" +#include A + +#ifdef C + #define m(a) <a##_pre.c> +#else + #define m(a) <a##_post.c> +#endif +#include m(abc) // <abc_post.c> + diff --git a/include_server/test_data/contains_abs_include.c b/include_server/test_data/contains_abs_include.c new file mode 100644 index 0000000..a442e31 --- /dev/null +++ b/include_server/test_data/contains_abs_include.c @@ -0,0 +1 @@ +#include "/love/of/my/life" diff --git a/include_server/test_data/dbar/dbar1/bar.h b/include_server/test_data/dbar/dbar1/bar.h new file mode 100644 index 0000000..91bb28c --- /dev/null +++ b/include_server/test_data/dbar/dbar1/bar.h @@ -0,0 +1 @@ +#define dbar_dbar1_bar_h diff --git a/include_server/test_data/dbar/foo.h b/include_server/test_data/dbar/foo.h new file mode 100755 index 0000000..692ba26 --- /dev/null +++ b/include_server/test_data/dbar/foo.h @@ -0,0 +1 @@ +#include "foo2.h" diff --git a/include_server/test_data/dfoo/foo.h b/include_server/test_data/dfoo/foo.h new file mode 100755 index 0000000..018d262 --- /dev/null +++ b/include_server/test_data/dfoo/foo.h @@ -0,0 +1,2 @@ +#include "foo2.h" +#include "../dbar/dbar1/bar.h" diff --git a/include_server/test_data/dfoo/foo2.h b/include_server/test_data/dfoo/foo2.h new file mode 100644 index 0000000..9db0ee1 --- /dev/null +++ b/include_server/test_data/dfoo/foo2.h @@ -0,0 +1,3 @@ +#define dfoo_foo2_h +// The include below is not valid syntax and should be ignored. +#include ../dbar/foo.h diff --git a/include_server/test_data/dfoo/i_am_perhaps_a_directory.h b/include_server/test_data/dfoo/i_am_perhaps_a_directory.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/include_server/test_data/dfoo/i_am_perhaps_a_directory.h diff --git a/include_server/test_data/dfoo/include_dotdot_foo b/include_server/test_data/dfoo/include_dotdot_foo new file mode 100644 index 0000000..ec77c1d --- /dev/null +++ b/include_server/test_data/dfoo/include_dotdot_foo @@ -0,0 +1 @@ +#include "../foo" diff --git a/include_server/test_data/dfoo/include_next_foo.h b/include_server/test_data/dfoo/include_next_foo.h new file mode 100755 index 0000000..caf8d79 --- /dev/null +++ b/include_server/test_data/dfoo/include_next_foo.h @@ -0,0 +1 @@ +#include_next <foo.h> diff --git a/include_server/test_data/dfoo/stat_triggers.h b/include_server/test_data/dfoo/stat_triggers.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/include_server/test_data/dfoo/stat_triggers.h diff --git a/include_server/test_data/distcc/README b/include_server/test_data/distcc/README new file mode 100644 index 0000000..5474801 --- /dev/null +++ b/include_server/test_data/distcc/README @@ -0,0 +1 @@ +This is just part of the distcc code, used for testing. diff --git a/include_server/test_data/distcc/src/bulk.h b/include_server/test_data/distcc/src/bulk.h new file mode 100644 index 0000000..7f37109 --- /dev/null +++ b/include_server/test_data/distcc/src/bulk.h @@ -0,0 +1,51 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78; -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +int dcc_r_file(int ifd, const char *filename, unsigned, + enum dcc_compress); +int dcc_r_fifo(int ifd, const char *fifo_name, size_t len); + +int dcc_x_file(int ofd, const char *fname, const char *token, + enum dcc_compress compression, + off_t *); + +int dcc_r_file_timed(int ifd, const char *fname, unsigned size, + enum dcc_compress); + +int dcc_r_token_file(int ifd, + const char *token, + const char *fname, + enum dcc_compress compr); + +int dcc_open_read(const char *fname, int *ifd, off_t *fsize); +int dcc_copy_file_to_fd(const char *in_fname, int out_fd); + +/* clirpc.c */ +int dcc_x_many_files(int ofd, + unsigned int n_files, + char **fnames); + +/* srvrpc.c */ +int dcc_r_many_files(int in_fd, + const char *dirname, + enum dcc_compress compr); + diff --git a/include_server/test_data/distcc/src/compile.h b/include_server/test_data/distcc/src/compile.h new file mode 100644 index 0000000..6876bab --- /dev/null +++ b/include_server/test_data/distcc/src/compile.h @@ -0,0 +1,38 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* remote.c */ +int dcc_compile_remote(char **argv, + char *input_fname, + char *cpp_fname, + char **file_names, + char *output_fname, + char *deps_fname, + char *server_stderr_fname, + pid_t cpp_pid, + int local_cpu_lock_fd, + struct dcc_hostdef *host, + int *status); + +int dcc_build_somewhere_timed(char *argv[], + int sg_level, + int *status); diff --git a/include_server/test_data/distcc/src/config.h b/include_server/test_data/distcc/src/config.h new file mode 100644 index 0000000..975565e --- /dev/null +++ b/include_server/test_data/distcc/src/config.h @@ -0,0 +1,256 @@ +/* src/config.h. Generated by configure. */ +/* src/config.h.in. Generated from configure.ac by autoheader. */ + +/* Use getaddrinfo(), getnameinfo(), etc */ +/* #undef ENABLE_RFC2553 */ + +/* Your gnu-style host triple */ +#define GNU_HOST "x86_64-unknown-linux-gnu" + +/* Define to 1 if you have the <alloca.h> header file. */ +#define HAVE_ALLOCA_H 1 + +/* Define to 1 if you have the <arpa/nameser.h> header file. */ +#define HAVE_ARPA_NAMESER_H 1 + +/* Define to 1 if you have the `asprintf' function. */ +#define HAVE_ASPRINTF 1 + +/* define if vsnprintf is C99 compliant */ +#define HAVE_C99_VSNPRINTF 1 + +/* Define to 1 if you have the <ctype.h> header file. */ +#define HAVE_CTYPE_H 1 + +/* Define to 1 if you have the declaration of `asprintf', and to 0 if you + don't. */ +#define HAVE_DECL_ASPRINTF 1 + +/* Define to 1 if you have the declaration of `snprintf', and to 0 if you + don't. */ +#define HAVE_DECL_SNPRINTF 1 + +/* Define to 1 if you have the declaration of `strndup', and to 0 if you + don't. */ +#define HAVE_DECL_STRNDUP 1 + +/* Define to 1 if you have the declaration of `vasprintf', and to 0 if you + don't. */ +#define HAVE_DECL_VASPRINTF 1 + +/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you + don't. */ +#define HAVE_DECL_VSNPRINTF 1 + +/* Define to 1 if you have the <float.h> header file. */ +#define HAVE_FLOAT_H 1 + +/* Define to 1 if you have the `flock' function. */ +#define HAVE_FLOCK 1 + +/* Define to 1 if you have the `getaddrinfo' function. */ +#define HAVE_GETADDRINFO 1 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `geteuid' function. */ +#define HAVE_GETEUID 1 + +/* Define to 1 if you have the `getloadavg' function. */ +#define HAVE_GETLOADAVG 1 + +/* Define to 1 if you have the `getnameinfo' function. */ +#define HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the `getrusage' function. */ +#define HAVE_GETRUSAGE 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `getuid' function. */ +#define HAVE_GETUID 1 + +/* Define to 1 if you have the `getpagesize' function. */ +#define HAVE_GETPAGESIZE 1 + +/* Define to 1 if you have the `getwd' function. */ +#define HAVE_GETWD 1 + +/* Define to 1 if you have the `hstrerror' function. */ +#define HAVE_HSTRERROR 1 + +/* Define to 1 if you have the `inet_ntoa' function. */ +#define HAVE_INET_NTOA 1 + +/* Define to 1 if you have the `inet_ntop' function. */ +#define HAVE_INET_NTOP 1 + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if the system has the type `in_addr_t'. */ +#define HAVE_IN_ADDR_T 1 + +/* Define to 1 if the system has the type `in_port_t'. */ +#define HAVE_IN_PORT_T 1 + +/* Define to 1 if you have the `lockf' function. */ +#define HAVE_LOCKF 1 + +/* Define to 1 if you have the `mcheck' function. */ +#define HAVE_MCHECK 1 + +/* Define to 1 if you have the <mcheck.h> header file. */ +#define HAVE_MCHECK_H 1 + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mmap' function. */ +#define HAVE_MMAP 1 + +/* Define to 1 if you have the <netinet/in.h> header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the <resolv.h> header file. */ +#define HAVE_RESOLV_H 1 + +/* Define to 1 if you have the `sendfile' function. */ +#define HAVE_SENDFILE 1 + +/* Define to 1 if you have the `setgroups' function. */ +#define HAVE_SETGROUPS 1 + +/* Define to 1 if you have the `setreuid' function. */ +#define HAVE_SETREUID 1 + +/* Define to 1 if you have the `setsid' function. */ +#define HAVE_SETSID 1 + +/* Define to 1 if you have the `setuid' function. */ +#define HAVE_SETUID 1 + +/* Define to 1 if you have the `snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* define if you have struct sockaddr_storage */ +#define HAVE_SOCKADDR_STORAGE 1 + +/* define if you have a working socketpair */ +#define HAVE_SOCKETPAIR 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlcpy' function. */ +/* #undef HAVE_STRLCPY */ + +/* Define to 1 if you have the `strndup' function. */ +#define HAVE_STRNDUP 1 + +/* Define to 1 if you have the `strsignal' function. */ +#define HAVE_STRSIGNAL 1 + +/* Define to 1 if you have the <sys/loadavg.h> header file. */ +/* #undef HAVE_SYS_LOADAVG_H */ + +/* Define to 1 if you have the <sys/mman.h> header file. */ +#define HAVE_SYS_MMAN_H 1 + +/* Define to 1 if you have the <sys/resource.h> header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the <sys/select.h> header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the <sys/sendfile.h> header file. */ +#define HAVE_SYS_SENDFILE_H 1 + +/* Define to 1 if you have the <sys/signal.h> header file. */ +#define HAVE_SYS_SIGNAL_H 1 + +/* Define to 1 if you have the <sys/socket.h> header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if your cpp has vararg macros */ +#define HAVE_VARARG_MACROS + +/* Define to 1 if you have the `vasprintf' function. */ +#define HAVE_VASPRINTF 1 + +/* Whether __va_copy() is available */ +#define HAVE_VA_COPY 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#define HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the `wait3' function. */ +#define HAVE_WAIT3 1 + +/* Define to 1 if you have the `wait4' function. */ +#define HAVE_WAIT4 1 + +/* Define to 1 if you have the `waitpid' function. */ +#define HAVE_WAITPID 1 + +/* Define if MAP_FAILED constant not available */ +#define MAP_FAILED (void *)-1L + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "distcc-pump@google.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "distcc" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "distcc 2.18.3-17gg-pump6" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "distcc" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "2.18.3-17gg-pump6" + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Use GNOME */ +/* #undef WITH_GNOME */ + +/* Use GTK+ */ +/* #undef WITH_GTK */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* type to use in place of socklen_t if not defined */ +/* #undef socklen_t */ diff --git a/include_server/test_data/distcc/src/distcc.c b/include_server/test_data/distcc/src/distcc.c new file mode 100644 index 0000000..2bf4b52 --- /dev/null +++ b/include_server/test_data/distcc/src/distcc.c @@ -0,0 +1,221 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + + + /* 4: The noise of a multitude in the + * mountains, like as of a great people; a + * tumultuous noise of the kingdoms of nations + * gathered together: the LORD of hosts + * mustereth the host of the battle. + * -- Isaiah 13 */ + + + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> + +#include "distcc.h" +#include "trace.h" +#include "exitcode.h" +#include "util.h" +#include "hosts.h" +#include "bulk.h" +#include "implicit.h" +#include "compile.h" +#include "emaillog.h" + + +/* Name of this program, for trace.c */ +const char *rs_program_name = "distcc"; + + +/** + * @file + * + * Entry point for the distcc client. + * + * There are three methods of use for distcc: explicit (distcc gcc -c + * foo.c), implicit (distcc -c foo.c) and masqueraded (gcc -c foo.c, + * where gcc is really a link to distcc). + * + * Detecting these is relatively easy by examining the first one or + * two words of the command. We also need to make sure that when we + * go to run the compiler, we run the one intended by the user. + * + * In particular, for masqueraded mode, we want to make sure that we + * don't invoke distcc recursively. + **/ + +static void dcc_show_usage(void) +{ + dcc_show_version("distcc"); + printf( +"Usage:\n" +" distcc [COMPILER] [compile options] -o OBJECT -c SOURCE\n" +" distcc --help\n" +"\n" +"Options:\n" +" COMPILER defaults to \"cc\"\n" +" --help explain usage and exit\n" +" --version show version and exit\n" +"\n" +"Environment variables:\n" +" See the manual page for a complete list.\n" +" DISTCC_VERBOSE=1 give debug messages\n" +" DISTCC_LOG send messages to file, not stderr\n" +" DISTCC_SSH command to run to open SSH connections\n" +" DISTCC_DIR directory for host list and locks\n" +"\n" +"Server specification:\n" +"A list of servers is taken from the environment variable $DISTCC_HOSTS, or\n" +"$DISTCC_DIR/hosts, or ~/.distcc/hosts, or %s/distcc/hosts.\n" +"Each host can be given in any of these forms, see the manual for details:\n" +"\n" +" localhost run in place\n" +" HOST TCP connection, port %d\n" +" HOST:PORT TCP connection, specified port\n" +" @HOST SSH connection\n" +" USER@HOST SSH connection to specified host\n" +" --randomize Randomize the server list before execution\n" +"\n" +"distcc distributes compilation jobs across volunteer machines running\n" +"distccd. Jobs that cannot be distributed, such as linking or \n" +"preprocessing are run locally. distcc should be used with make's -jN\n" +"option to execute in parallel on several machines.\n", + SYSCONFDIR, + DISTCC_DEFAULT_PORT); +} + + +static RETSIGTYPE dcc_client_signalled (int whichsig) +{ + signal(whichsig, SIG_DFL); + +#ifdef HAVE_STRSIGNAL + rs_log_info("%s", strsignal(whichsig)); +#else + rs_log_info("terminated by signal %d", whichsig); +#endif + + dcc_cleanup_tempfiles_from_signal_handler(); + + raise(whichsig); + +} + + +static void dcc_client_catch_signals(void) +{ + signal(SIGTERM, &dcc_client_signalled); + signal(SIGINT, &dcc_client_signalled); + signal(SIGHUP, &dcc_client_signalled); +} + + + +/** + * distcc client entry point. + * + * This is typically called by make in place of the real compiler. + * + * Performs basic setup and checks for distcc arguments, and then kicks off + * dcc_build_somewhere(). + **/ +int main(int argc, char **argv) +{ + int status, sg_level, tweaked_path = 0; + char **compiler_args; + char *compiler_name; + int ret; + + dcc_client_catch_signals(); + atexit(dcc_cleanup_tempfiles); + atexit(dcc_remove_state_file); + + dcc_set_trace_from_env(); + dcc_setup_log_email(); + + dcc_trace_version(); + + compiler_name = (char *) dcc_find_basename(argv[0]); + + /* Ignore SIGPIPE; we consistently check error codes and will + * see the EPIPE. */ + dcc_ignore_sigpipe(1); + + sg_level = dcc_recursion_safeguard(); + + rs_trace("compiler name is \"%s\"", compiler_name); + + if (strstr(compiler_name, "distcc") != NULL) { + /* Either "distcc -c hello.c" or "distcc gcc -c hello.c" */ + if (argc <= 1 || !strcmp(argv[1], "--help")) { + dcc_show_usage(); + ret = 0; + goto out; + } + if (!strcmp(argv[1], "--version")) { + dcc_show_version("distcc"); + ret = 0; + goto out; + } + + dcc_find_compiler(argv, &compiler_args); + /* compiler_args is now respectively either "cc -c hello.c" or + * "gcc -c hello.c" */ + +#if 0 + /* I don't think we need to call this: if we reached this + * line, our invocation name is something like 'distcc', and + * that's never a problem for masquerading loops. */ + if ((ret = dcc_trim_path(compiler_name)) != 0) + goto out; +#endif + } else { + /* Invoked as "cc -c hello.c", with masqueraded path */ + if ((ret = dcc_support_masquerade(argv, compiler_name, + &tweaked_path)) != 0) + goto out; + + dcc_copy_argv(argv, &compiler_args, 0); + compiler_args[0] = compiler_name; + } + + if (sg_level - tweaked_path > 0) { + rs_log_crit("distcc seems to have invoked itself recursively!"); + ret = EXIT_RECURSION; + goto out; + } + + ret = dcc_build_somewhere_timed(compiler_args, sg_level, &status); + + out: + dcc_maybe_send_email(); + dcc_exit(ret); +} diff --git a/include_server/test_data/distcc/src/distcc.h b/include_server/test_data/distcc/src/distcc.h new file mode 100644 index 0000000..c0686a7 --- /dev/null +++ b/include_server/test_data/distcc/src/distcc.h @@ -0,0 +1,336 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/* distcc.h -- common internal-use header file */ + +#include <sys/types.h> + + +#ifdef NORETURN +/* nothing */ +#elif defined(__GNUC__) +# define NORETURN __attribute__((noreturn)) +#elif defined(__LCLINT__) +# define NORETURN /*@noreturn@*/ x +#else /* !__GNUC__ && !__LCLINT__ */ +# define NORETURN +#endif /* !__GNUC__ && !__LCLINT__ */ + +#ifdef UNUSED +/* nothing */ +#elif defined(__GNUC__) +# define UNUSED(x) UNUSED_ ## x __attribute__((unused)) +#elif defined(__LCLINT__) +# define UNUSED(x) /*@unused@*/ x +#else /* !__GNUC__ && !__LCLINT__ */ +# define UNUSED(x) x +#endif /* !__GNUC__ && !__LCLINT__ */ + + +#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)) +/* This works on Gentoo's (patched?) gcc 3.3.3 but not 3.2.3, and not Debian's + * 3.3.4. It should be standard on 3.4. */ +# define WARN_UNUSED __attribute__((warn_unused_result)) +#else +# define WARN_UNUSED +#endif + + +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +#endif + + +struct dcc_hostdef; + + + +#include "state.h" + + + + +enum dcc_compress { + /* wierd values to catch errors */ + DCC_COMPRESS_NONE = 69, + DCC_COMPRESS_LZO1X +}; + +enum dcc_cpp_where { + /* wierd values to catch errors */ + DCC_CPP_ON_CLIENT = 42, + DCC_CPP_ON_SERVER +}; + +enum dcc_protover { + DCC_VER_1 = 1, /**< vanilla */ + DCC_VER_2 = 2, /**< LZO sprinkles */ + DCC_VER_3 = 3 /**< server-side cpp */ +}; + + + + + +int str_endswith(const char *tail, const char *tiger); + + + + +/* A macro so that we get the right __FUNCTION__ in the trace message. + * + * We condition on rs_trace_enabled so that we don't do the to-string + * conversion unless the user will actually see the result, because it's a + * little expensive. */ +#define dcc_trace_argv(_message, _argv) \ + if (rs_trace_enabled()) { \ + char *_astr; \ + _astr = dcc_argv_tostr(_argv); \ + rs_trace("%s: %s", _message, _astr); \ + free(_astr); \ + } else {} + + +/* help.c */ +int dcc_trace_version(void); +int dcc_show_version(const char *prog); + + +/* hosts.c */ +int dcc_parse_hosts_env(struct dcc_hostdef **ret_list, + int *ret_nhosts); +int dcc_parse_hosts(const char *where, const char *source_name, + struct dcc_hostdef **ret_list, + int *ret_nhosts); + +/* ncpu.c */ +int dcc_ncpus(int *); + +/* ssh.c */ +int dcc_ssh_connect(char *ssh_cmd, char *user, + char *machine, char *path, + int *f_in, int *f_out, + pid_t *ssh_pid); + +/* safeguard.c */ +int dcc_increment_safeguard(void); +int dcc_recursion_safeguard(void); + +/* clirpc.c */ +int dcc_x_req_header(int fd, + enum dcc_protover protover); +int dcc_x_argv(int fd, char **argv); +int dcc_x_cwd(int fd); + +/* srvrpc.c */ +int dcc_r_cwd(int ifd, char **cwd); + +/* remote.c */ +int dcc_send_job_corked(int net_fd, + char **argv, + pid_t cpp_pid, + int *status, + const char *, + const char *cpp_fname, + struct dcc_hostdef *); + +int dcc_retrieve_results(int net_fd, + int *status, + const char *output_fname, + const char *deps_fname, + const char *server_stderr_fname, + struct dcc_hostdef *); + +/* climasq.c */ +int dcc_support_masquerade(char *argv[], char *progname, int *); + + +/* backoff.c */ +int dcc_enjoyed_host(const struct dcc_hostdef *host); +int dcc_disliked_host(const struct dcc_hostdef *host); +int dcc_remove_disliked(struct dcc_hostdef **hostlist); + + + +#define DISTCC_DEFAULT_PORT 3632 +#define DISTCC_DEFAULT_STATS_ENABLED 0 +#define DISTCC_DEFAULT_STATS_PORT 3633 + + + +#ifndef WAIT_ANY +# define WAIT_ANY (-1) +#endif + + +/* If --enable-rfc2553 was given, then we will try to enable compile-time IPv6 + * support. This means we must have a sockaddr_storage large enough to hold + * IPv6 addresses. If not, we'll just use a plain sockaddr, which is more + * likely to compile correctly. */ +#ifdef ENABLE_RFC2553 +# ifndef HAVE_SOCKADDR_STORAGE +# error You can't use RFC2553 because you don't have a sockaddr_storage type +# endif /* HAVE_SOCKADDR_STORAGE */ +# define dcc_sockaddr_storage sockaddr_storage +#else /* !ENABLE_RFC2553 */ +# define dcc_sockaddr_storage sockaddr +#endif /* !ENABLE_RFC2553 */ + +#ifndef O_BINARY +# define O_BINARY 0 +#endif + + +void dcc_set_trace_from_env(void); + + +/* compress.c */ +int dcc_r_bulk_lzo1x(int outf_fd, + int in_fd, + unsigned in_len); + + + +int dcc_compress_file_lzo1x(int in_fd, + size_t in_len, + char **out_buf, + size_t *out_len); + +int dcc_compress_lzo1x_alloc(const char *in_buf, + size_t in_len, + char **out_buf_ret, + size_t *out_len_ret); + + + +/* bulk.h */ +void dcc_calc_rate(off_t size_out, + struct timeval *before, + struct timeval *after, + double *secs, + double *rate); + +/* arg.c */ +int dcc_set_action_opt(char **, const char *); +int dcc_set_output(char **, char *); +int dcc_set_input(char **, char *); +int dcc_scan_args(char *argv[], /*@out@*/ /*@relnull@*/ char **orig_o, + char **orig_i, char ***ret_newargv); + +/* argutil.c */ +unsigned int dcc_argv_len(char **a); +int dcc_argv_search(char **a, const char *); +int dcc_copy_argv(char **argv, char ***out_argv, int extra_args); +int dcc_argv_append(char **argv, char *toadd); +char *dcc_argv_tostr(char **a); +void dcc_free_argv(char **argv); + +/* tempfile.c */ +int dcc_get_tempdir(const char **); +int dcc_make_tmpnam(const char *, const char *suffix, char **); +int dcc_get_new_tmpdir(char **tmpdir); +int dcc_mk_tmpdir(const char *path); +int dcc_mkdir(const char *path); + +int dcc_get_lock_dir(char **path_ret) WARN_UNUSED; +int dcc_get_state_dir(char **path_ret) WARN_UNUSED; +int dcc_get_top_dir(char **path_ret) WARN_UNUSED; +int dcc_get_tmp_top(const char **p_ret) WARN_UNUSED; + +int dcc_mk_tmp_ancestor_dirs(const char* file); + +/* cleanup.c */ +void dcc_cleanup_tempfiles(void); +void dcc_cleanup_tempfiles_from_signal_handler(void); +int dcc_add_cleanup(const char *filename) WARN_UNUSED; + +/* strip.c */ +int dcc_strip_local_args(char **from, char ***out_argv); +int dcc_strip_dasho(char **from, char ***out_argv); + +/* cpp.c */ +int dcc_cpp_maybe(char **argv, char *input_fname, char **cpp_fname, + pid_t *cpp_pid); + +/* filename.c */ +int dcc_is_source(const char *sfile); +int dcc_is_preprocessed(const char *sfile); +int dcc_is_object(const char *filename); +int dcc_source_needs_local(const char *); + +char * dcc_find_extension(char *sfile); +int dcc_output_from_source(const char *sfile, const char *out_extn, + char **ofile); + +const char * dcc_preproc_exten(const char *e); +const char * dcc_find_basename(const char *sfile); +void dcc_truncate_to_dirname(char *file); + + +/* io.c */ + +int dcc_writex(int fd, const void *buf, size_t len); + +int dcc_r_token(int ifd, char *token); + +int dcc_readx(int fd, void *buf, size_t len); +int dcc_pump_sendfile(int ofd, int ifd, size_t n); +int dcc_r_str_alloc(int fd, unsigned len, char **buf); + +int tcp_cork_sock(int fd, int corked); +int dcc_close(int fd); +int dcc_want_mmap(void); + + +int dcc_select_for_write(int fd, int timeout); +int dcc_select_for_read(int fd, int timeout); + +/* loadfile.c */ +int dcc_load_file_string(const char *filename, + char **retbuf); + + +extern const int dcc_connect_timeout, dcc_io_timeout; + + +/* pump.c */ +int dcc_r_bulk(int ofd, + int ifd, + unsigned f_size, + enum dcc_compress compression); + +int dcc_pump_readwrite(int ofd, int ifd, size_t n); + +/* mapfile.c */ +int dcc_map_input_file(int in_fd, off_t in_size, char **buf_ret); + +/* XXX: Kind of kludgy, we should do dynamic allocation. But this will do for + * now. */ +#ifndef MAXPATHLEN +#define MAXPATHLEN 4096 +#endif + + +#ifndef WCOREDUMP +# define WCOREDUMP(status) 0 +#endif diff --git a/include_server/test_data/distcc/src/emaillog.h b/include_server/test_data/distcc/src/emaillog.h new file mode 100644 index 0000000..3b1c33a --- /dev/null +++ b/include_server/test_data/distcc/src/emaillog.h @@ -0,0 +1,10 @@ +#ifndef DCC_EMAILLOG_H +#define DCC_EMAILLOG_H + +#define DCC_EMAILLOG_WHOM_TO_BLAME "distcc-pump-errors@google.com" +void dcc_please_send_email(void); +void dcc_setup_log_email(void); +void dcc_maybe_send_email(void); +int dcc_add_file_to_log_email(const char *description, const char *fname); + +#endif /* EMAILLOG_H */ diff --git a/include_server/test_data/distcc/src/exitcode.h b/include_server/test_data/distcc/src/exitcode.h new file mode 100644 index 0000000..29a595a --- /dev/null +++ b/include_server/test_data/distcc/src/exitcode.h @@ -0,0 +1,61 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef _DISTCC_EXITCODE_H +#define _DISTCC_EXITCODE_H + +/** + * @file + * + * Common exit codes. + **/ + +/** + * Common exit codes for both client and server. + * + * These need to be in [1,255] so that they can be used as exit() + * codes. + **/ +enum dcc_exitcode { + EXIT_DISTCC_FAILED = 100, /**< General failure */ + EXIT_BAD_ARGUMENTS = 101, + EXIT_BIND_FAILED = 102, + EXIT_CONNECT_FAILED = 103, + EXIT_COMPILER_CRASHED = 104, + EXIT_OUT_OF_MEMORY = 105, + EXIT_BAD_HOSTSPEC = 106, + EXIT_IO_ERROR = 107, + EXIT_TRUNCATED = 108, + EXIT_PROTOCOL_ERROR = 109, + EXIT_COMPILER_MISSING = 110, /**< Compiler executable not found */ + EXIT_RECURSION = 111, /**< distcc called itself */ + EXIT_SETUID_FAILED = 112, /**< Failed to discard privileges */ + EXIT_ACCESS_DENIED = 113, /**< Network access denied */ + EXIT_BUSY = 114, /**< In use by another process. */ + EXIT_NO_SUCH_FILE = 115, + EXIT_NO_HOSTS = 116, + EXIT_GONE = 117, /**< No longer relevant */ + EXIT_TIMEOUT = 118 +}; + + +#endif /* _DISTCC_EXITCODE_H */ diff --git a/include_server/test_data/distcc/src/hosts.h b/include_server/test_data/distcc/src/hosts.h new file mode 100644 index 0000000..674ac85 --- /dev/null +++ b/include_server/test_data/distcc/src/hosts.h @@ -0,0 +1,87 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +/** + * @file + * + * Declarations for distcc host selection stuff. + **/ + +/** + * A simple linked list of host definitions. All strings are mallocd. + **/ +struct dcc_hostdef { + enum { + DCC_MODE_TCP = 1, + DCC_MODE_SSH, + DCC_MODE_LOCAL + } mode; + char * user; + char * hostname; + int port; + char * ssh_command; + + /** Mark the host as up == 1, by default, or down == 0, if !hostname */ + int is_up; + + /** Number of tasks that can be dispatched concurrently to this machine. */ + int n_slots; + + /** The full name of this host, taken verbatim from the host + * definition. **/ + char * hostdef_string; + + enum dcc_protover protover; + + /** The kind of compression to use for this host */ + enum dcc_compress compr; + + /** Where are we doing preprocessing? */ + enum dcc_cpp_where cpp_where; + + struct dcc_hostdef *next; +}; + +/** Static definition of localhost **/ +extern struct dcc_hostdef *dcc_hostdef_local; +extern struct dcc_hostdef *dcc_hostdef_local_cpp; + +/* hosts.c */ +int dcc_get_hostlist(struct dcc_hostdef **ret_list, + int *ret_nhosts); + +int dcc_free_hostdef(struct dcc_hostdef *host); + +int dcc_get_features_from_protover(enum dcc_protover protover, + enum dcc_compress *compr, + enum dcc_cpp_where *cpp_where); + +int dcc_get_protover_from_features(enum dcc_compress compr, + enum dcc_cpp_where cpp_where, + enum dcc_protover *protover); + +/* hostfile.c */ +int dcc_parse_hosts_file(const char *fname, + struct dcc_hostdef **ret_list, + int *ret_nhosts); + + diff --git a/include_server/test_data/distcc/src/implicit.h b/include_server/test_data/distcc/src/implicit.h new file mode 100644 index 0000000..371657d --- /dev/null +++ b/include_server/test_data/distcc/src/implicit.h @@ -0,0 +1,25 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * $Header: /data/cvs/distcc/src/implicit.h,v 1.3 2002/09/18 06:57:45 mbp Exp $ + * + * Copyright (C) 2002 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +int dcc_find_compiler(char **argv, char ***); + diff --git a/include_server/test_data/distcc/src/include_me.h b/include_server/test_data/distcc/src/include_me.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/include_server/test_data/distcc/src/include_me.h diff --git a/include_server/test_data/distcc/src/state.h b/include_server/test_data/distcc/src/state.h new file mode 100644 index 0000000..63486fe --- /dev/null +++ b/include_server/test_data/distcc/src/state.h @@ -0,0 +1,91 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#ifndef _DISTCC_STATE_H +#define _DISTCC_STATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +int dcc_get_state_dir (char **p); +int dcc_open_state_file (int *p_fd); + + +/* Note that these must be in the order in which they are encountered + * for the state file to work properly. It's OK if some are skipped + * though. */ +enum dcc_phase { + DCC_PHASE_STARTUP, + DCC_PHASE_BLOCKED, + DCC_PHASE_CONNECT, + DCC_PHASE_CPP, + DCC_PHASE_SEND, + DCC_PHASE_COMPILE, /**< or unknown */ + DCC_PHASE_RECEIVE, + DCC_PHASE_DONE /**< MUST be last */ +}; + + +int dcc_note_state (enum dcc_phase state, + const char *file, + const char *host); +void dcc_remove_state_file (void); + + +extern const char *dcc_state_prefix; + + +#define DCC_STATE_MAGIC 0x44494800 /* DIH\0 */ + +/** + * State and history of a distcc process. Used in memory and also in native + * format for binary state files. + * + * This should be <4kB, so that it will normally be written out + * atomically. + **/ +struct dcc_task_state { + size_t struct_size; + unsigned long magic; + unsigned long cpid; /**< Client pid */ + char file[128]; /**< Input filename */ + char host[128]; /**< Destination host description */ + int slot; /**< Which CPU slot for this host */ + + enum dcc_phase curr_phase; + + /** In memory, point to the next in a list of all tasks. In the + * file, undefined. */ + struct dcc_task_state *next; +}; + + +const char *dcc_get_phase_name(enum dcc_phase); + +void dcc_note_state_slot(int slot); + +#ifdef __cplusplus +} +#endif + +#endif /* _DISTCC_STATE_H */ diff --git a/include_server/test_data/distcc/src/trace.h b/include_server/test_data/distcc/src/trace.h new file mode 100644 index 0000000..0d99e0f --- /dev/null +++ b/include_server/test_data/distcc/src/trace.h @@ -0,0 +1,230 @@ +/*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- + * + * librsync -- generate and apply network deltas + * + * Copyright (C) 2000, 2001, 2002, 2003, 2004 by Martin Pool + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +/** + * @file + * + * Reusable trace library. + * + * @todo A function like perror that includes strerror output. Apache + * does this by adding flags as well as the severity level which say + * whether such information should be included. + * + * @todo Also check in configure for the C9X predefined identifier `_function', or + * whatever it's called. + **/ + +/* Provide simple macro statement wrappers (adapted from glib, and originally from Perl): + * RS_STMT_START { statements; } RS_STMT_END; + * can be used as a single statement, as in + * if (x) RS_STMT_START { ... } RS_STMT_END; else ... + * + * For gcc we will wrap the statements within `({' and `})' braces. + * For SunOS they will be wrapped within `if (1)' and `else (void) 0', + * and otherwise within `do' and `while (0)'. + */ +#if !(defined (RS_STMT_START) && defined (RS_STMT_END)) +# if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus) +# define RS_STMT_START (void)( +# define RS_STMT_END ) +# else +# if (defined (sun) || defined (__sun__)) +# define RS_STMT_START if (1) +# define RS_STMT_END else (void)0 +# else +# define RS_STMT_START do +# define RS_STMT_END while (0) +# endif +# endif +#endif + + +#include <stdarg.h> + +/* unconditionally on */ +#define DO_RS_TRACE + +/** + * Log severity levels. + * + * These have the same numeric values as the levels for syslog, at + * least in glibc. + * + * Trace may be turned off. + * + * Error is always on, but you can return and continue in some way. + */ +typedef enum { + RS_LOG_EMERG = 0, /**< System is unusable */ + RS_LOG_ALERT = 1, /**< Action must be taken immediately */ + RS_LOG_CRIT = 2, /**< Critical conditions */ + RS_LOG_ERR = 3, /**< Error conditions */ + RS_LOG_WARNING = 4, /**< Warning conditions */ + RS_LOG_NOTICE = 5, /**< Normal but significant condition */ + RS_LOG_INFO = 6, /**< Informational */ + RS_LOG_DEBUG = 7 /**< Debug-level messages */ +} rs_loglevel; + +int rs_loglevel_from_name(const char *name); + +enum { + RS_LOG_PRIMASK = 7, /**< Mask to extract priority + part. \internal */ + + RS_LOG_NONAME = 8, /**< \b Don't show function name in + message. */ + + RS_LOG_NO_PROGRAM = 16, + RS_LOG_NO_PID = 32 +}; + + +/** + * \typedef rs_logger_fn + * \brief Callback to write out log messages. + * \param level a syslog level. + * \param msg message to be logged. + * + * \param private Opaque data passed in when logger was added. For + * example, pointer to file descriptor. + */ +typedef void rs_logger_fn(int flags, const char *fn, + char const *msg, va_list, + void *private_ptr, int private_int); + +void rs_format_msg(char *buf, size_t, int, const char *, + const char *fmt, va_list); + +void rs_trace_set_level(rs_loglevel level); + +void rs_add_logger(rs_logger_fn *, int level, void *, int); +void rs_remove_logger(rs_logger_fn *, int level, void *, int); +void rs_remove_all_loggers(void); + + +void rs_logger_file(int level, const char *fn, char const *fmt, va_list va, + void *, int); + +void rs_logger_syslog(int level, const char *fn, char const *fmt, va_list va, + void *, int); + +/** Check whether the library was compiled with debugging trace suport. */ +int rs_supports_trace(void); + +void rs_log0(int level, char const *fn, char const *fmt, ...) +#if defined(__GNUC__) + __attribute__ ((format(printf, 3, 4))) +#endif /* __GNUC__ */ + ; + + + /* TODO: Check for the __FUNCTION__ thing, rather than gnuc */ +#if defined(HAVE_VARARG_MACROS) && defined(__GNUC__) + +#if 1 || defined(DO_RS_TRACE) +# define rs_trace(fmt, arg...) \ + do { rs_log0(RS_LOG_DEBUG, __FUNCTION__, fmt , ##arg); \ + } while (0) +#else +# define rs_trace(s, str...) +#endif /* !DO_RS_TRACE */ + +#define rs_log(l, s, str...) do { \ + rs_log0((l), __FUNCTION__, (s) , ##str); \ + } while (0) + + +#define rs_log_crit(s, str...) do { \ + rs_log0(RS_LOG_CRIT, __FUNCTION__, (s) , ##str); \ + } while (0) + +#define rs_log_error(s, str...) do { \ + rs_log0(RS_LOG_ERR, __FUNCTION__, (s) , ##str); \ + } while (0) + +#define rs_log_notice(s, str...) do { \ + rs_log0(RS_LOG_NOTICE, __FUNCTION__, (s) , ##str); \ + } while (0) + +#define rs_log_warning(s, str...) do { \ + rs_log0(RS_LOG_WARNING, __FUNCTION__, (s) , ##str); \ + } while (0) + +#define rs_log_info(s, str...) do { \ + rs_log0(RS_LOG_INFO, __FUNCTION__, (s) , ##str); \ + } while (0) + +#else /* not defined HAVE_VARARG_MACROS */ + +/* If we don't have gcc vararg macros, then we fall back to making the + * log routines just plain functions. On platforms without gcc (boo + * hiss!) this means at least you get some messages, but not the nice + * function names etc. */ +#define rs_log rs_log0_nofn + +#define rs_trace rs_log_trace_nofn +#define rs_log_info rs_log_info_nofn +#define rs_log_notice rs_log_notice_nofn +#define rs_log_warning rs_log_warning_nofn +#define rs_log_error rs_log_error_nofn +#define rs_log_crit rs_log_critical_nofn +#endif /* HAVE_VARARG_MACROS */ + + + +void rs_log_trace_nofn(char const *s, ...); +void rs_log_info_nofn(char const *, ...); +void rs_log_notice_nofn(char const *, ...); +void rs_log_warning_nofn(char const *s, ...); +void rs_log_error_nofn(char const *s, ...); +void rs_log_critical_nofn(char const *, ...); + +void rs_log0_nofn(int level, char const *fmt, ...); + + + +/** + * \macro rs_trace_enabled() + * + * Call this before putting too much effort into generating trace + * messages. + */ + +extern int rs_trace_level; + +#ifdef DO_RS_TRACE +# define rs_trace_enabled() ((rs_trace_level & RS_LOG_PRIMASK) >= RS_LOG_DEBUG) +#else +# define rs_trace_enabled() 0 +#endif + +/** + * Name of the program, to be included in log messages. + * + * @note This must be defined exactly once in each program that links to + * trace.c + **/ +extern const char *rs_program_name; + +void dcc_job_summary_clear(void); +void dcc_job_summary(void); +void dcc_job_summary_append(const char *s); diff --git a/include_server/test_data/distcc/src/util.h b/include_server/test_data/distcc/src/util.h new file mode 100644 index 0000000..e2aefed --- /dev/null +++ b/include_server/test_data/distcc/src/util.h @@ -0,0 +1,55 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include <setjmp.h> + +/* util.c */ +int dcc_getcurrentload(void); +void dcc_getloadavg(double loadavg[3]); +int argv_contains(char **argv, const char *s); +int dcc_redirect_fd(int, const char *fname, int); +int str_startswith(const char *head, const char *worm); +char *dcc_gethostname(void); +void dcc_exit(int exitcode) NORETURN; +int dcc_getenv_bool(const char *name, int def_value); +int set_cloexec_flag (int desc, int value); +int dcc_ignore_sigpipe(int val); +int dcc_remove_if_exists(const char *fname); +int dcc_trim_path(const char *compiler_name); +int dcc_set_path(const char *newpath); +char *dcc_abspath(const char *path, int path_len); +int dcc_get_dns_domain(const char **domain_name); + +#define str_equal(a, b) (!strcmp((a), (b))) + + +void dcc_get_proc_stats(int *num_D, int *max_RSS, char **max_RSS_name); +void dcc_get_disk_io_stats(int *n_reads, int *n_writes); + + +int dcc_dup_part(const char **psrc, char **pdst, const char *sep); + +#ifndef HAVE_STRLCPY +size_t strlcpy(char *d, const char *s, size_t bufsize); +#endif + +int dcc_tokenize_string(const char *in, char ***argv_ptr); diff --git a/include_server/test_data/func_macro.c b/include_server/test_data/func_macro.c new file mode 100644 index 0000000..9eef80d --- /dev/null +++ b/include_server/test_data/func_macro.c @@ -0,0 +1 @@ +#include FINCLUDE(foo.h) diff --git a/include_server/test_data/gws-main.o.cmd b/include_server/test_data/gws-main.o.cmd new file mode 100644 index 0000000..0b0cc28 --- /dev/null +++ b/include_server/test_data/gws-main.o.cmd @@ -0,0 +1 @@ +/usr/crosstool/v8/gcc-4.1.0-glibc-2.2.2/blah/gcc -Wall -Werror -Wwrite-strings -fno-exceptions -funsigned-char -D__STDC_FORMAT_MACROS -g0 -D_REENTRANT -DCOMPILER_GCC3 -DCOMPILER_GCC4 -DARCH_PIII -DOS_LINUX -fmessage-length=0 -fno-strict-aliasing -Wno-sign-compare -Wno-char-subscripts -DXP_UNIX -D_REENTRANT -DHAS_vsnprintf -DPOSIX_MALLOC_THRESHOLD=10 -DMAX_DUPLENGTH=100000 -DSUPPORT_UTF8 -DSUPPORT_UCP -DHAVE_OPENSSL -D_REENTRANT -DHASH_NAMESPACE=__gnu_cxx -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/musicsearch/frontend -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/musicsearch/frontend -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/musicsearch/onebox -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/musicsearch/onebox -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/web/manybox -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/web/manybox -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/web/onebox -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/web/onebox -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/freshness/queryclassifier/public/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/freshness/queryclassifier/public/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/blogsearch/parsers/feedparser/protos -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/blogsearch/parsers/feedparser/protos -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/extern_js -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/extern_js -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/images -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/images -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/one_google -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/one_google -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/web -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/web -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/webserver -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/webserver -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/wireless -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates/wireless -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/image/daily/mustang/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/image/daily/mustang/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/location/extractor/client/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/location/extractor/client/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/location/extractor/server/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/location/extractor/server/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/repos_www/ftb/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/repos_www/ftb/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/onebox/quicklinks/public/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/onebox/quicklinks/public/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/search/learning/booster -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/search/learning/booster -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ratings/reviews/mustang/servlets -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ratings/reviews/mustang/servlets -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/superroot/corpusroot/web/extras -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/superroot/corpusroot/web/extras -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/tv/showings/frontend/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/tv/showings/frontend/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/index/personalizedsearch/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/index/personalizedsearch/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/stats/relatedvideos/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/stats/relatedvideos/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/weboftrust/prose/data_analysis/video -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/weboftrust/prose/data_analysis/video -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/wireless/sms/frontend/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/wireless/sms/frontend/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/adsearch/servlets -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/adsearch/servlets -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/experiments/base -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/experiments/base -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/messenger/adsnapshots -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/messenger/adsnapshots -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/messenger/base -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/messenger/base -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/proto/creatives -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/proto/creatives -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/chubby/lib/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/chubby/lib/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/chubby/svelte/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/chubby/svelte/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/classifier/phil/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/classifier/phil/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/commerce/shoppinglist/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/commerce/shoppinglist/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/community/introductions/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/community/introductions/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/contentads/cat2/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/contentads/cat2/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/crawler/analysis/javascript -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/crawler/analysis/javascript -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/crawler/sitemaps/common -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/crawler/sitemaps/common -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/crawler/sitemaps/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/crawler/sitemaps/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/enterprise/onebox/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/enterprise/onebox/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/enterprise/superroot/ent_search_params -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/enterprise/superroot/ent_search_params -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/file/gfs/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/file/gfs/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googlebase/mustang/protos -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googlebase/mustang/protos -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googledata/html/templates -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/i18n/segmenter/common -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/i18n/segmenter/common -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/image/mustang/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/image/mustang/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/image/search/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/image/search/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/learning/rephil/api -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/learning/rephil/api -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/localsearch/frontend/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/localsearch/frontend/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/localsearch/geomap_server/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/localsearch/geomap_server/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/localsearch/mustang/servlet -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/localsearch/mustang/servlet -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/localsearch/oblocalsearch/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/localsearch/oblocalsearch/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/location/waldo/base -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/location/waldo/base -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/location/waldo/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/location/waldo/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/wireless/mobilegw -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/wireless/mobilegw -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/maps/soprano/client -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/maps/soprano/client -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/aggregation/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/aggregation/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/repos_www/navboost -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/repos_www/navboost -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/servlets/commerce -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/servlets/commerce -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/servlets/mobile -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/servlets/mobile -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/servlets/querycount -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/servlets/querycount -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/servlets/video -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/servlets/video -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/proto/xml2proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/proto/xml2proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/news/frontend/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/news/frontend/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/news/personalization/nps -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/news/personalization/nps -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ocean/data/docinfo -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ocean/data/docinfo -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ocean/metadata/ids -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ocean/metadata/ids -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/onebox/scholar/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/onebox/scholar/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/onebox/showtimes/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/onebox/showtimes/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/onebox/weather/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/onebox/weather/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/persist/framework/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/persist/framework/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/gws_ui/profiles -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/gws_ui/profiles -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/recommend/base -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/recommend/base -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/recommend/util -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/recommend/util -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/zipit/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/zipit/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/zipit/st -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/zipit/st -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/chameleon/interface -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/chameleon/interface -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/labels/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/labels/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/local/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/local/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/manybox/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/manybox/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/manybox/video -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/manybox/video -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/prose/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/prose/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/sitemap/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/sitemap/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ratings/mustang/servlets -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ratings/mustang/servlets -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ratings/reviews/base -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ratings/reviews/base -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ratings/reviews/movies -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ratings/reviews/movies -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/repository/docchart/extraction -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/repository/docchart/extraction -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/universal/naming/constants -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/universal/naming/constants -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/universal/naming/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/universal/naming/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/util/encryption/docid -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/util/encryption/docid -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/cdb/common -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/cdb/common -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/index/builder -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/index/builder -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/onebox/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/onebox/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/weboftrust/prose/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/weboftrust/prose/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webserver/frontend/modules -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webserver/frontend/modules -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webserver/util/feature_tabs -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webserver/util/feature_tabs -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webserver/util/match_criteria -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webserver/util/match_criteria -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webserver/util/one_google -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webserver/util/one_google -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webserver/util/url_factory -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webserver/util/url_factory -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/wireless/mmp/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/wireless/mmp/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/wireless/mobile_restrict/indexer -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/wireless/mobile_restrict/indexer -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/wireless/msisdndictionary/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/wireless/msisdndictionary/proto -iquote third_party/Inso/common/unix -Ithird_party/Inso/common/unix -iquote third_party/openssl/gcc-3.4-glibc-2.2.2-piii-linux-dbg/include -Ithird_party/openssl/gcc-3.4-glibc-2.2.2-piii-linux-dbg/include -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/adsearch -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/adsearch -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/base -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/base -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/clickencoding -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/clickencoding -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/demographics -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/demographics -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/events -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/events -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/experiments -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/experiments -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/phil -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/phil -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/promos -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/promos -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/snapshot -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/snapshot -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/strategy -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/strategy -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/supermessenger -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ads/supermessenger -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/attributesearch/gwsbackend -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/attributesearch/gwsbackend -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/blog/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/blog/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/blogsearch/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/blogsearch/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/borg/borgletlib -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/borg/borgletlib -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/cacheserving/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/cacheserving/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/caribou/ads -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/caribou/ads -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/commerce/offer -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/commerce/offer -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/commerce/onebox -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/commerce/onebox -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/contentads/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/contentads/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/contentads/vertical -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/contentads/vertical -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/coupons/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/coupons/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/daffie/annotations -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/daffie/annotations -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/daffie/annotations2 -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/daffie/annotations2 -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/daffie/metadata -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/daffie/metadata -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/daffie/search -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/daffie/search -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/directory/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/directory/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/docserving/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/docserving/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/file/base -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/file/base -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/file/fileset -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/file/fileset -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/file/logging -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/file/logging -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/file/sstablefile -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/file/sstablefile -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/finance/onebox -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/finance/onebox -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/finance/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/finance/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/finance/quoteserver -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/finance/quoteserver -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/froogle/base -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/froogle/base -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/froogle/currency -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/froogle/currency -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/gaia/data -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/gaia/data -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/gaia/insclient -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/gaia/insclient -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/gaia/insfriend -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/gaia/insfriend -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/geostore/base -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/geostore/base -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/groups2/browsefe -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/groups2/browsefe -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/gws/config -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/gws/config -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/gws/gws -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/gws/gws -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/gws/onebox -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/gws/onebox -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/i18n/langenc_detect -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/i18n/langenc_detect -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/i18n/localization -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/i18n/localization -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/igoogle/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/igoogle/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/indexer/perdocdata -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/indexer/perdocdata -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/indexserving/elephant_info -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/indexserving/elephant_info -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/indexserving/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/indexserving/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/kansas/datatype -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/kansas/datatype -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/kansas/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/kansas/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/kansas/showmyhistory -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/kansas/showmyhistory -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/linkserver/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/linkserver/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/localsearch/base -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/localsearch/base -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/localsearch/i18n -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/localsearch/i18n -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/localsearch/kml -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/localsearch/kml -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/location/base -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/location/base -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/location/country -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/location/country -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/bigindex -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/bigindex -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/eventid -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/eventid -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/gws -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/gws -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/java -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/java -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/maps -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/maps -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/superroot -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/superroot -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/transit -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/transit -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/zwieback -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs/zwieback -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/maps/wiki_lite -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/maps/wiki_lite -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/music/clients -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/music/clients -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/music/images -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/music/images -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/repos_querycount -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/repos_querycount -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/repos_www -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/repos_www -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/servlets -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang/servlets -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/base -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/base -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/ecatcher -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/ecatcher -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/httpsconnection -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/httpsconnection -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/sslagent -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/sslagent -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/util -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/net/util -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/nlp/ngrams -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/nlp/ngrams -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ocean/acqbase -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ocean/acqbase -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ocean/mustangproto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/ocean/mustangproto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/onebox/glossary -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/onebox/glossary -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/partnerservices/distributiontracking -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/partnerservices/distributiontracking -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/profiles -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/profiles -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/util -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/personalization/util -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/premiumcontent/common -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/premiumcontent/common -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/premiumcontent/onebox -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/premiumcontent/onebox -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/production/cert_auth -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/production/cert_auth -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/navboost -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/navboost -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/rescoring -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/rescoring -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/twiddler -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/quality/twiddler -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/queryrefinement/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/queryrefinement/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/queryrewrite/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/queryrewrite/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/repository/base -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/repository/base -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/repository/docchart -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/repository/docchart -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/reviews/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/reviews/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/science_search/citation -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/science_search/citation -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/security/keymaster -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/security/keymaster -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/security/loas -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/security/loas -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/smartass/logexpansion -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/smartass/logexpansion -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/smartass/predictionmodel -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/smartass/predictionmodel -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/smartass/server -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/smartass/server -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/sortedmap/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/sortedmap/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/spelling/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/spelling/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/sstable/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/sstable/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/stats/io -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/stats/io -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/structuredsearch/client -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/structuredsearch/client -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/superroot/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/superroot/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/third_party/libidn -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/third_party/libidn -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/transportation/dateparser -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/transportation/dateparser -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/transportation/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/transportation/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/universalsearch/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/universalsearch/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/urlscheduler/rpc -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/urlscheduler/rpc -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/util/callback -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/util/callback -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/captioncrunch -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/captioncrunch -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/personalization -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/personalization -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/vcsdb -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/video/vcsdb -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webserver/frontend -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webserver/frontend -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webutil/http -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webutil/http -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webutil/url -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/webutil/url -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/wireless/handset -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/wireless/handset -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/zwieback/proto -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/zwieback/proto -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/includes/third_party/openssl -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/includes/third_party/openssl -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/includes/third_party/stl -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/includes/third_party/stl -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/includes/third_party/zlib -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/includes/third_party/zlib -iquote third_party/SpiderMonkey/src -Ithird_party/SpiderMonkey/src -iquote third_party/htm/include -Ithird_party/htm/include -iquote third_party/icu/current -Ithird_party/icu/current -iquote third_party/pcre/pcre-6.7 -Ithird_party/pcre/pcre-6.7 -iquote third_party/zlib/v1_2_3 -Ithird_party/zlib/v1_2_3 -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/base -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/base -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/borg -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/borg -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/calculator -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/calculator -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/daffie -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/daffie -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googlebot -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/googlebot -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/gws -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/gws -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/indexer -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/indexer -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/logs -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/mustang -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/onebox -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/onebox -iquote obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/sortedmap -Iobj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/genfiles/sortedmap -iquote . -Wno-non-virtual-dtor -isystem obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/includes/third_party/stl/third_party/stl -isystem obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/includes/third_party/stl -Wno-deprecated -Woverloaded-virtual -ftemplate-depth-40 -c gws/gws-main.cc -o obj/gcc-4.1.1-glibc-2.2.2-piii-linux-g0-dbg/bin/gws/gws-main.o diff --git a/include_server/test_data/i_am_perhaps_a_directory.h/empty_file b/include_server/test_data/i_am_perhaps_a_directory.h/empty_file new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/include_server/test_data/i_am_perhaps_a_directory.h/empty_file diff --git a/include_server/test_data/include_include_next_foo.h b/include_server/test_data/include_include_next_foo.h new file mode 100755 index 0000000..f7469fe --- /dev/null +++ b/include_server/test_data/include_include_next_foo.h @@ -0,0 +1 @@ +#include "include_next_foo.h" diff --git a/include_server/test_data/maps/foo.tpl.varnames.h b/include_server/test_data/maps/foo.tpl.varnames.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/include_server/test_data/maps/foo.tpl.varnames.h @@ -0,0 +1 @@ + diff --git a/include_server/test_data/more_macros.c b/include_server/test_data/more_macros.c new file mode 100644 index 0000000..28dd506 --- /dev/null +++ b/include_server/test_data/more_macros.c @@ -0,0 +1,14 @@ + +#define TEMPLATE_VARNAME(_filename_) \ + AS_STRING\ +(maps/_filename_.tpl.varnames.h) + +#define ILLFORMED(_filename_,(x)) \ + AS_STRING(maps/_filename_.tpl.varnames.h, NOTHANDLED(_filename_)) + +// #define BEHINDCOMMENT(x) x + x + +#define AS_STRING(x) AS_STRING_INTERNAL(x) +#define AS_STRING_INTERNAL(x) #x + +#include TEMPLATE_VARNAME(foo) diff --git a/include_server/test_data/p1.h b/include_server/test_data/p1.h new file mode 100755 index 0000000..8b13789 --- /dev/null +++ b/include_server/test_data/p1.h @@ -0,0 +1 @@ + diff --git a/include_server/test_data/parse.c b/include_server/test_data/parse.c new file mode 100644 index 0000000..956d282 --- /dev/null +++ b/include_server/test_data/parse.c @@ -0,0 +1,8 @@ +#includenext "incnext.h" +#include <angle.c> +#include "quote.c" + # include \ + /* comment */ "quote1\ +.c" +#include "foo.h" // in dfoo + diff --git a/include_server/test_data/stat_triggers.c b/include_server/test_data/stat_triggers.c new file mode 100644 index 0000000..5c32f98 --- /dev/null +++ b/include_server/test_data/stat_triggers.c @@ -0,0 +1 @@ +#include "stat_triggers.h" diff --git a/include_server/test_data/stat_triggers.h b/include_server/test_data/stat_triggers.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/include_server/test_data/stat_triggers.h diff --git a/include_server/test_data/symlink_farm/abc_post.c b/include_server/test_data/symlink_farm/abc_post.c new file mode 120000 index 0000000..4fcd3a9 --- /dev/null +++ b/include_server/test_data/symlink_farm/abc_post.c @@ -0,0 +1 @@ +../abc_post.c
\ No newline at end of file diff --git a/include_server/test_data/symlink_farm/abc_pre.c b/include_server/test_data/symlink_farm/abc_pre.c new file mode 120000 index 0000000..4e864a5 --- /dev/null +++ b/include_server/test_data/symlink_farm/abc_pre.c @@ -0,0 +1 @@ +../abc_pre.c
\ No newline at end of file diff --git a/include_server/test_data/symlink_farm/computed_includes.c b/include_server/test_data/symlink_farm/computed_includes.c new file mode 120000 index 0000000..2a694d0 --- /dev/null +++ b/include_server/test_data/symlink_farm/computed_includes.c @@ -0,0 +1 @@ +../computed_includes.c
\ No newline at end of file diff --git a/include_server/test_data/symlink_farm/dbar b/include_server/test_data/symlink_farm/dbar new file mode 120000 index 0000000..a261f21 --- /dev/null +++ b/include_server/test_data/symlink_farm/dbar @@ -0,0 +1 @@ +../dbar
\ No newline at end of file diff --git a/include_server/test_data/symlink_farm/dfoo b/include_server/test_data/symlink_farm/dfoo new file mode 120000 index 0000000..97fa2d0 --- /dev/null +++ b/include_server/test_data/symlink_farm/dfoo @@ -0,0 +1 @@ +../dfoo
\ No newline at end of file diff --git a/include_server/test_data/symlink_farm/foo b/include_server/test_data/symlink_farm/foo new file mode 100644 index 0000000..cd9390c --- /dev/null +++ b/include_server/test_data/symlink_farm/foo @@ -0,0 +1 @@ +#include "sub_farm/link_to_dotdot_dotdot_dfoo_include_dotdot_foo" diff --git a/include_server/test_data/symlink_farm/p1.h b/include_server/test_data/symlink_farm/p1.h new file mode 120000 index 0000000..58fa3b8 --- /dev/null +++ b/include_server/test_data/symlink_farm/p1.h @@ -0,0 +1 @@ +../p1.h
\ No newline at end of file diff --git a/include_server/test_data/symlink_farm/parse.c b/include_server/test_data/symlink_farm/parse.c new file mode 120000 index 0000000..cf5775d --- /dev/null +++ b/include_server/test_data/symlink_farm/parse.c @@ -0,0 +1 @@ +../parse.c
\ No newline at end of file diff --git a/include_server/test_data/symlink_farm/sub_farm/link_to_dotdot_dotdot_dfoo_include_dotdot_foo b/include_server/test_data/symlink_farm/sub_farm/link_to_dotdot_dotdot_dfoo_include_dotdot_foo new file mode 120000 index 0000000..3f08d7c --- /dev/null +++ b/include_server/test_data/symlink_farm/sub_farm/link_to_dotdot_dotdot_dfoo_include_dotdot_foo @@ -0,0 +1 @@ +../../dfoo/include_dotdot_foo
\ No newline at end of file diff --git a/include_server/test_data/symlink_farm/test_directory_probing.c b/include_server/test_data/symlink_farm/test_directory_probing.c new file mode 120000 index 0000000..0af39d3 --- /dev/null +++ b/include_server/test_data/symlink_farm/test_directory_probing.c @@ -0,0 +1 @@ +../test_directory_probing.c
\ No newline at end of file diff --git a/include_server/test_data/symlink_farm/test_include_next b/include_server/test_data/symlink_farm/test_include_next new file mode 120000 index 0000000..9aa56db --- /dev/null +++ b/include_server/test_data/symlink_farm/test_include_next @@ -0,0 +1 @@ +../test_include_next
\ No newline at end of file diff --git a/include_server/test_data/test_computed_includes/helper.c b/include_server/test_data/test_computed_includes/helper.c new file mode 100644 index 0000000..02221a6 --- /dev/null +++ b/include_server/test_data/test_computed_includes/helper.c @@ -0,0 +1 @@ +#include INCL diff --git a/include_server/test_data/test_computed_includes/incl.h b/include_server/test_data/test_computed_includes/incl.h new file mode 100644 index 0000000..1e29313 --- /dev/null +++ b/include_server/test_data/test_computed_includes/incl.h @@ -0,0 +1 @@ +#define MSG "hello" diff --git a/include_server/test_data/test_computed_includes/inclA.h b/include_server/test_data/test_computed_includes/inclA.h new file mode 100644 index 0000000..43ad022 --- /dev/null +++ b/include_server/test_data/test_computed_includes/inclA.h @@ -0,0 +1 @@ +#define MSG "hello A" diff --git a/include_server/test_data/test_computed_includes/src.c b/include_server/test_data/test_computed_includes/src.c new file mode 100644 index 0000000..a361343 --- /dev/null +++ b/include_server/test_data/test_computed_includes/src.c @@ -0,0 +1,9 @@ +#define INCL "incl.h" +#include "helper.c" + +#include<stdio.h> +int main() { + printf(MSG); + printf("\n"); + return 0; +} diff --git a/include_server/test_data/test_computed_includes/srcA.c b/include_server/test_data/test_computed_includes/srcA.c new file mode 100644 index 0000000..075a898 --- /dev/null +++ b/include_server/test_data/test_computed_includes/srcA.c @@ -0,0 +1,9 @@ +#define INCL "inclA.h" +#include "helper.c" +#include <stdio.h> + +int main() { + printf(MSG); + printf("\n"); + return 0; +} diff --git a/include_server/test_data/test_directory_probing.c b/include_server/test_data/test_directory_probing.c new file mode 100644 index 0000000..edadb76 --- /dev/null +++ b/include_server/test_data/test_directory_probing.c @@ -0,0 +1,4 @@ +// For the include: should not be distracted by the directory +// i_am_perhaps_a_directory.h in the present directory (test_data). + +#include "i_am_perhaps_a_directory.h" diff --git a/include_server/test_data/test_include_next/bar/x.h b/include_server/test_data/test_include_next/bar/x.h new file mode 100755 index 0000000..8f6876d --- /dev/null +++ b/include_server/test_data/test_include_next/bar/x.h @@ -0,0 +1,3 @@ +Now bar/x.h +#include_next "x.h" + diff --git a/include_server/test_data/test_include_next/bar/y.h b/include_server/test_data/test_include_next/bar/y.h new file mode 100755 index 0000000..f44afac --- /dev/null +++ b/include_server/test_data/test_include_next/bar/y.h @@ -0,0 +1,3 @@ +Now bar/y.h +#include_next "y.h" + diff --git a/include_server/test_data/test_include_next/baz/start_x.c b/include_server/test_data/test_include_next/baz/start_x.c new file mode 100755 index 0000000..44a0921 --- /dev/null +++ b/include_server/test_data/test_include_next/baz/start_x.c @@ -0,0 +1,2 @@ +Now baz/start_x.h +#include "x.h" diff --git a/include_server/test_data/test_include_next/baz/start_y.c b/include_server/test_data/test_include_next/baz/start_y.c new file mode 100755 index 0000000..1e6a9c8 --- /dev/null +++ b/include_server/test_data/test_include_next/baz/start_y.c @@ -0,0 +1,2 @@ +Now baz/start_y.h +#include "../foo/y.h" diff --git a/include_server/test_data/test_include_next/baz/x.h b/include_server/test_data/test_include_next/baz/x.h new file mode 100755 index 0000000..69218e4 --- /dev/null +++ b/include_server/test_data/test_include_next/baz/x.h @@ -0,0 +1,3 @@ +Now in baz/x.h +#include_next "x.h" + diff --git a/include_server/test_data/test_include_next/baz/y.h b/include_server/test_data/test_include_next/baz/y.h new file mode 100755 index 0000000..50ca3e8 --- /dev/null +++ b/include_server/test_data/test_include_next/baz/y.h @@ -0,0 +1,6 @@ +Now baz/y.h +#ifndef baz_y_h + #define baz_y_h + #include y.h +#endif + diff --git a/include_server/test_data/test_include_next/biz/x.h b/include_server/test_data/test_include_next/biz/x.h new file mode 100755 index 0000000..fcb7a34 --- /dev/null +++ b/include_server/test_data/test_include_next/biz/x.h @@ -0,0 +1 @@ +Now biz/x.h diff --git a/include_server/test_data/test_include_next/foo/x.h b/include_server/test_data/test_include_next/foo/x.h new file mode 100755 index 0000000..c9be0ed --- /dev/null +++ b/include_server/test_data/test_include_next/foo/x.h @@ -0,0 +1,2 @@ +Now: foo/x.h +#include_next "x.h" diff --git a/include_server/test_data/test_include_next/foo/y.h b/include_server/test_data/test_include_next/foo/y.h new file mode 100755 index 0000000..965bf4e --- /dev/null +++ b/include_server/test_data/test_include_next/foo/y.h @@ -0,0 +1,2 @@ +Now: foo/y.h +#include_next "y.h" @@ -0,0 +1,444 @@ +#! /bin/bash +# +# Copyright 2007 Google Inc. All Rights Reserved. +# +# Authors: klarlund@google.com, fergus@google.com +# +# 'pump': a script for using distcc-pump with build commands. + +# This file is processed by configure, +# which substitutes in the right value for @PYTHON@. +PYTHON=@PYTHON@ + +usage_string=\ +'Usage: + pump COMMAND [ARG...] +or + pump --startup + pump --shutdown + +Description: + Pump, also known as distcc-pump, accelerates remote compilation with + distcc by also distributing preprocessing to the servers. + + The simplest usage is the form "pump COMMAND [ARG...]". + This will start an include server for distcc-pump; set some environment + variables; change PATH to use the distcc-pump "distcc" client; execute + COMMAND with the specified ARG(s); and then shutdown the include server. + The COMMAND is typically a parallel build command, such as + "make -j80", that will do many concurrent invocations of distcc. + + An alternative way of invoking pump is to explicitly invoke "pump --startup" + to start the include server and "pump --shutdown" to stop the include server. + The "pump --startup" command will start up the include server, and will print + out some environment variable settings. These environment variables are used + to communicate between the distcc-pump "distcc" client and the include + server, and to communicate between "pump --startup" and "pump --shutdown". + The caller of "pump --startup" is responsible for setting those environment + variables before invoking "distcc" or "pump --shutdown". For example: + + eval `pump --startup` + make -j80 + pump --shutdown + + Note that distcc-pump assumes that sources files will not be modified during + the lifetime of the include server, so modifying source files during a build + may cause inconsistent results. + +Environment variables (all optional): + DISTCC_PUMP_LOCATION The location of distcc-pump 'bin' directory, which is + normally inferred from the link-resolved dirname of + argv[0]. If this location is in fact the bin directory + inside an installation (as will be the case when the + 'pump' script in the installation executes), then + Python executables and distcc itself will be retrieved + from the parent directory of the location. + DISTCC_POTENTIAL_HOSTS The distcc servers that will be queried by lsdistcc + in order to produce a value for DISTCC_HOSTS. + This value may be unset or null. In such + cases, use DISTCC_HOSTS. + DISTCC_HOSTS This variable is passed through to distcc but only if + DISTCC_POTENTIAL_HOSTS is not set. + LSDISTCC_ARGS Extra arguments to lsdistcc. + INCLUDE_SERVER_ARGS Extra arguments to the include server. + PYTHONOPTIMIZE If set to "", then Python optimization is disabled. + +Example: + pump make +' + +# Get the directory of a command. The argument is $0 as received from +# argv[0]. If $0 is of the form /path/symlink and symlink points to +# another directory than /path, then $(basename $0) does not return +# the directory where the executable lives. We fix this here. +GetScriptDir() { + if [ -h "$0" ]; then + link=$(readlink "$0") + linkdir=$(dirname "$link") + case $linkdir in + /*) echo "$linkdir" ;; + *) echo "$(dirname "$0")/$linkdir" + esac + else + dirname "$0" + fi +} + +# Variables inherited from the environment of the caller. +DISTCC_PUMP_LOCATION=${DISTCC_PUMP_LOCATION-$(GetScriptDir "$0")} + +# Variables used by this process. +program_name=$0 +socket_dir='' # Temporary directory created by this process. +tmp_pid_file='' # Temporary file created by this process. +available_hosts_file='' # Temporary file for newline separated list of hosts. +socket='' # Temporary socket file, inside $socket_dir. +include_server_stdout='' # Temporary file, inside $socket_dir. +include_server_stderr='' # Temporary file, inside $socket_dir. +include_server_pid='' +include_server_started_successfully=0 +include_server_relative='' # Set by Initialize(). This path is relative to + # the 'bin' directory of a distcc-pump installation. +distcc_location='' # Set by Initialize(). The directory of the distcc binary. +verbose=1 # Print progress messages to stdout? (1 means yes.) +redirect_io=0 # Redirect include server's I/O streams? (1 means yes.) + +# Make temp file using distinguishing prefix $1. Use optional argument +# $2="-d" to make a directory. The name of the created temp file or +# directory is written to stdout. +MakeTmpFile() { + mktemp $2 /tmp/$1.XXXXXX || \ + { echo "$program_name: Could not make temp \"$1\"" 1>&2; exit 1; } +} + +CheckUsage() { + if [ "$1" = "" -o "$1" = '-h' -o "$1" = '--help' ]; then + echo "$usage_string" + exit 0 + fi +} + + +Initialize() { + # We know the value of $PYTHON when this function is executed. The value is + # set when the 'pump' script is made from 'pump.in'. Use this value in the + # formation of the relative path that takes us from the 'bin' directory of an + # installation to the 'include_server' directory. + include_server_relative="../lib/$PYTHON/site-packages/include_server" + + # We use a little heuristic to determine whether this pump script is part of + # an installation. Specifically, we check whether we're a bin directory, and + # more importantly, we look for the include_server.py script. If we're running + # out of the distcc_pump source directory, both conditions below will fail. + if [ $(basename $DISTCC_PUMP_LOCATION) = 'bin' ] \ + && [ -f "$DISTCC_PUMP_LOCATION/$include_server_relative/\ +include_server.py" ]; \ + then + # Running from installed directory. + is_in_installation=true + else + # Running from configured directory, usually the source directory. + is_in_installation="" + fi + + if [ $is_in_installation ]; then + distcc_location="$DISTCC_PUMP_LOCATION" + else + distcc_location="$DISTCC_PUMP_LOCATION/distcc" + fi + + # Check that we're getting exactly the distcc client we want: the + # one that is part of this build. + if ! [ -x "$distcc_location/distcc" ]; then + echo "$0: error: can't find distcc (looked in $distcc_location)" 1>&2 + exit 1 + fi +} + +Announce() { + echo "__________Using distcc-pump from $(readlink -f $DISTCC_PUMP_LOCATION)" +} + +# Starts up the include server. +# Sets $socket, $socket_dir, $include_server_pid, and +# $include_server_started_successfully. +# If successful, sets exported variable $INCLUDE_SERVER_PORT +# to the socket file ($socket), to tell the distcc clients +# where to find the include server. +shopt -s extglob # allow +(...) construct below +StartIncludeServer() { + # Locate include server depending on whether in installation. + if [ $is_in_installation ]; then + local include_server_location="$DISTCC_PUMP_LOCATION/\ +$include_server_relative" + local pythonpath=$include_server_location + else + # When run from the source code directory (assuming that we configured in + # the distcc_pump top-level directory) we pick up .py files from the + # include_server directory and pick up the .so file from the + # include_server/build/libXXX/include_server directory. When configured in a + # separate directory, we pick up .py files also from include_server/build. + local include_server_location=${DISTCC_PUMP_LOCATION}/include_server + # Now locate the single directory containing the .so file from the build + # directory. Possibly there may be more than one such file; first identify + # them all. + so_files=$(ls ${DISTCC_PUMP_LOCATION}/include_server/\ +build/lib.*/include_server/distcc_pump_c_extensions.so) + if echo $so_files | grep -q ' '; then + include_server_started_successfully=0 + echo \ + '__________Shared libraries for multiple architectures discovered.' + echo \ + "__________Cannot determine which one to use among: $so_files" + echo \ + '__________Could not start distcc-pump include server' + return 0 + else + # There was only one such file. + local so_dir=$(dirname $so_files) + fi + local pythonpath="${DISTCC_PUMP_LOCATION}/include_server:$so_dir" + fi + + # Create a temporary directory $socket_dir. + socket_dir=$(MakeTmpFile "distcc-pump" -d) + + # The socket file on which the include server accepts connections. + socket=$socket_dir/socket + + # Files for the include server's stdout/stderr. + # When a build tool invokes 'pump --startup', stdout/stderr may be + # pipes, in which case the invocation may hang unless the include + # server process closes them. So to avoid this, we need to redirect + # the include server's output to temporary files. + # We print these files during shutdown; better late than never! + include_server_stdout=$socket_dir/stdout + include_server_stderr=$socket_dir/stderr + + # File for the include server process id. + tmp_pid_file=$(MakeTmpFile "distcc-pump-pid") + + # Start include server in optimized mode (no assertions) and with + # debug level 1 for tracing warnings. + # The include server will fork off + # a background process to handle the requests; + # the main process will exit only when the background + # process is ready to accept connections. + + ( + # Optionally redirect the I/O streams for the include server. + case $redirect_io in + 1) exec < /dev/null \ + > $include_server_stdout \ + 2> $include_server_stderr + ;; + *) + rm -f $include_server_stdout $include_server_stderr + ;; + esac + + PYTHONOPTIMIZE=${PYTHONOPTIMIZE-1} \ + PYTHONPATH=$pythonpath \ + $PYTHON \ + $include_server_location/include_server.py \ + --port $socket \ + --pid_file "$tmp_pid_file" \ + --email \ + --email_bound=5 \ + -d1 \ + $INCLUDE_SERVER_ARGS + ) + + include_server_pid=$(cat $tmp_pid_file) + rm $tmp_pid_file + + if [ ! -S "$socket" ]; then + include_server_started_successfully=0 + else + case $include_server_pid in + +([0-9])) + # That's what we expect: a number. + include_server_started_successfully=1 + # Tell the distcc clients where to find it. + INCLUDE_SERVER_PORT=$socket + export INCLUDE_SERVER_PORT + ;; + *) + # This indicates that the socket is not working. + include_server_pid='' + include_server_started_successfully=0 + ;; + esac + fi + if [ "$verbose" = 1 ]; then + if [ "$include_server_started_successfully" = 1 ]; then + echo '__________Started distcc-pump include server' + else + echo '__________Could not start distcc-pump include server' 1>&2 + fi + fi +} + +ShutDown() { + # Always -- at exit -- shut down include_server and remove $socket_dir + if [ "$include_server_pid" ] && \ + ps --pid "$include_server_pid" > /dev/null; then + echo '__________Shutting down distcc-pump include server' + kill $include_server_pid + fi + + if [ -f "$include_server_stdout" ]; then + cat $include_server_stdout + fi + if [ -f "$include_server_stderr" ]; then + cat $include_server_stderr >&2 + fi + + if [ "$socket_dir" ]; then + rm -rf "$socket_dir" + fi + if [ "$tmp_pid_file" ]; then + rm -f "$tmp_pid_file" + fi + if [ "$available_hosts_file" ]; then + rm -f "$available_hosts_file" + fi +} + +# Invokes lsdistcc to find the available servers. This list is +# \n-separated and written to the filepath provided as $1. +AvailableHosts() { + local available_hosts=$1 + local lsdistcc=$DISTCC_PUMP_LOCATION/distcc/lsdistcc + if [ ! -x $lsdistcc ]; then + lsdistcc=$DISTCC_PUMP_LOCATION/lsdistcc + if [ ! -x $lsdistcc ]; then + echo "$0: error: can't find lsdistcc (looked in $DISTCC_PUMP_LOCATION" \ + " and $DISTCC_PUMP_LOCATION/distcc)" 1>&2 + exit 1 + fi + fi + # Call lsdistcc and let it wait no more than 150ms unless overridden in + # LSDISTCC_ARGS. + $lsdistcc -c150 $LSDISTCC_ARGS $DISTCC_POTENTIAL_HOSTS > $available_hosts +} + +# Exports DISTCC_HOSTS as a function of global variables +# - $include_server_started_successfully and +# - $available_hosts_file. +ExportDISTCC_HOSTS() { + local opts='' + if [ "$include_server_started_successfully" = 1 ]; then + # The include server is up. + # Make 'cpp' mode (with lzo) the default. + opts=",cpp,lzo" + else + # The include server is not ready. + # Make 'lzo' mode the default. + if [ "$?" = 1 ]; then + echo "__________Warning: distcc-pump include server failed;" \ + "running unpumped" 1>&2 + fi + opts=",lzo" + fi + # When calculating final value of DISTCC_HOSTS, we get rid of + # newlines (thanks to "$(...)"). + export DISTCC_HOSTS="--randomize $(sed s/'$'/$opts/ $available_hosts_file)" + if [ "$verbose" = 1 ]; then + echo "__________Found" \ + "$(wc -l < $available_hosts_file) available distcc servers" + fi +} + +StartIncludeServerAndDetermineHosts() { + if [ "$DISTCC_POTENTIAL_HOSTS" ]; then + # Probe the distcc servers. It may take up to a second. But + # starting the include server takes about 150ms. Make these + # activities happen in parallel. First, the lsdistcc command goes + # in the background. + available_hosts_file=$(MakeTmpFile "distcc-pump-hosts") + AvailableHosts $available_hosts_file & + + # The include server goes in the foreground so variables can be set. + StartIncludeServer + + # Await for AvailableHosts to finish. + wait + ExportDISTCC_HOSTS $available_hosts_file + rm -f $available_hosts_file + else + if [ -z "$DISTCC_HOSTS" ] && + [ -z "$DISTCC_DIR" -o ! -f "$DISTCC_DIR/hosts" ] && + [ -z "$HOME" -o ! -f "$HOME/.distcc/hosts" ] && + [ ! -f "/etc/distcc/hosts" ] + then + echo "$program_name:" \ + "expected environment variables \"DISTCC_HOSTS\" or" \ + "\"DISTCC_POTENTIAL_HOSTS\" to be set, or to find a" \ + "distcc hosts file in \"\$DISTCC_DIR/hosts\"," \ + "\"\$HOME/.distcc/hosts\", or \"/etc/distcc/hosts\"." \ + 1>&2 + exit 1 + fi + StartIncludeServer + fi +} + +# Prints out environment variable settings, for the --startup option. +DumpEnvironmentVariables() { + # Variables used by "pump --shutdown" + echo export INCLUDE_SERVER_PID=\'$include_server_pid\' + echo export INCLUDE_SERVER_DIR=\'$socket_dir\' + # Variables used by the distcc client + echo export INCLUDE_SERVER_PORT=\'$INCLUDE_SERVER_PORT\' + if [ "$DISTCC_HOSTS" ]; then + echo export DISTCC_HOSTS=\'$DISTCC_HOSTS\' + fi + echo export PATH=\'$distcc_location:$PATH\' +} + +Main() { + + CheckUsage "$@" + + Initialize + + case "$*" in + --startup) + # Don't put ordinary progress messages on stdout, + # because they interfere with the environment variable + # settings that we print out. + verbose=0 + # Redirect the include server's stdin/stdout/stderr + redirect_io=1 + trap 'ShutDown' EXIT # In case we get interrupted. + StartIncludeServerAndDetermineHosts + trap '' EXIT + if [ $include_server_started_successfully = 1 ]; then + DumpEnvironmentVariables + exit 0 + else + exit 1 + fi + ;; + --shutdown) + include_server_pid=$INCLUDE_SERVER_PID + socket_dir=$INCLUDE_SERVER_DIR + include_server_stdout=$socket_dir/stdout + include_server_stderr=$socket_dir/stderr + ShutDown + exit 0 + ;; + *) + trap 'ShutDown' EXIT + Announce + StartIncludeServerAndDetermineHosts + # Now execute the command that is the argument of 'pump'. + PATH="$distcc_location:$PATH" \ + "$@" + # When we exit, the ShutDown function will be called. + ;; + esac +} + +Main "$@" diff --git a/run_all_autoconf.sh b/run_all_autoconf.sh new file mode 100755 index 0000000..bfa352d --- /dev/null +++ b/run_all_autoconf.sh @@ -0,0 +1,20 @@ +#! /bin/bash + +# Run autoconfig and autoheader in a safe way. Running these commands directly +# will likely not work because of caching mechanisms: the information in +# version.sh will not be propagated correctly. + +# We need a stamp file to compare version.sh against, see the Makefile. +AUTOCONF_STAMP=autoconf_stamp + +if ! [ $(basename $(pwd)) = "distcc_pump" ]; then + echo "Must be in distcc_pump directory" 1>&2; + exit 1 +fi + +# Now run autoconf and autoheader through autoreconf -f. This way autoconf is +# apparently not getting confused by old configure files and m4 caches. +echo "Now running autoreconf in order to run autoconf and autoheader." +autoreconf -f -v && touch $AUTOCONF_STAMP + +echo "System must be configured. Run: ./configure." diff --git a/version.sh b/version.sh new file mode 100644 index 0000000..a9a3498 --- /dev/null +++ b/version.sh @@ -0,0 +1,10 @@ +# To be source'ed from run_all_autoconf.sh and build-distcc.sh. + +DISTCC_VERSION=2.18.3 +PUMP_SUBVERSION=17gg1.pump20 + +DISTCC_PUMP_VERSION=$DISTCC_VERSION-$PUMP_SUBVERSION +PACKAGE_NAME='distcc' + + + |