#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"
const char *rs_program_name = "distcc";
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"
" --show-hosts show host list and exit\n"
" -j calculate the concurrency level from\n"
" the host list.\n"
"\n"
"Environment variables:\n"
" See the manual page for a complete list.\n"
" 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);
}
static void dcc_free_hostlist(struct dcc_hostdef *list) {
while (list) {
struct dcc_hostdef *l = list;
list = list->next;
dcc_free_hostdef(l);
}
}
static void dcc_show_hosts(void) {
struct dcc_hostdef *list, *l;
int nhosts;
if (dcc_get_hostlist(&list, &nhosts) != 0) {
rs_log_crit("Failed to get host list");
return;
}
for (l = list; l; l = l->next)
printf("%s\n", l->hostdef_string);
dcc_free_hostlist(list);
}
static void dcc_concurrency_level(void) {
struct dcc_hostdef *list, *l;
int nhosts;
int nslots = 0;
if (dcc_get_hostlist(&list, &nhosts) != 0) {
rs_log_crit("Failed to get host list");
return;
}
for (l = list; l; l = l->next)
nslots += l->n_slots;
dcc_free_hostlist(list);
printf("%i\n", nslots);
}
int main(int argc, char **argv)
{
int status, sg_level, tweaked_path = 0;
char **compiler_args = NULL;
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]);
dcc_ignore_sigpipe(1);
sg_level = dcc_recursion_safeguard();
rs_trace("compiler name is \"%s\"", compiler_name);
if (strstr(compiler_name, "distcc") != NULL) {
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;
}
if (!strcmp(argv[1], "--show-hosts")) {
dcc_show_hosts();
ret = 0;
goto out;
}
if (!strcmp(argv[1], "-j")) {
dcc_concurrency_level();
ret = 0;
goto out;
}
if (!strcmp(argv[1], "--scan-includes")) {
dcc_scan_includes = 1;
argv++;
}
#ifdef XCODE_INTEGRATION
if (!strcmp(argv[1], "--host-info") && argc == 3) {
ret = dcc_show_host_info(argv[2]);
goto out;
}
#endif
if ((ret = dcc_find_compiler(argv, &compiler_args)) != 0) {
goto out;
}
#if 0
if ((ret = dcc_trim_path(compiler_name)) != 0)
goto out;
#endif
} else {
if ((ret = dcc_support_masquerade(argv, compiler_name,
&tweaked_path)) != 0)
goto out;
if ((ret = dcc_copy_argv(argv, &compiler_args, 0)) != 0) {
goto out;
}
free(compiler_args[0]);
compiler_args[0] = strdup(compiler_name);
if (!compiler_args[0]) {
rs_log_error("strdup failed - out of memory?");
ret = EXIT_OUT_OF_MEMORY;
goto out;
}
}
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);
compiler_args = NULL;
out:
if (compiler_args) {
dcc_free_argv(compiler_args);
}
dcc_maybe_send_email();
dcc_exit(ret);
}