#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.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 "io.h"
#include "dopt.h"
#include "exitcode.h"
#include "setuid.h"
#include "access.h"
int arg_nice_inc;
int arg_nchildren = 2;
int arg_port = DISTCC_DEFAULT_PORT;
int opt_no_fork = 0;
int opt_daemon_mode = 0;
int opt_inetd_mode = 0;
int opt_no_fifo = 0;
struct dcc_allow_list *opt_allowed = NULL;
int opt_no_detach = 0;
int opt_log_stderr = 0;
int opt_lifetime = 0;
const char *arg_pid_file = NULL;
const char *arg_log_file = NULL;
enum {
opt_log_to_file = 300
};
const struct poptOption options[] = {
{ "allow", 'a', POPT_ARG_STRING, 0, 'a', 0, 0 },
{ "concurrent", 'n', POPT_ARG_INT, &arg_nchildren, 'n', 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 },
{ "log-file", 0, POPT_ARG_STRING, &arg_log_file, 0, 0, 0 },
{ "log-stderr", 0, POPT_ARG_NONE, &opt_log_stderr, 0, 0, 0 },
{ "nice", 'N', POPT_ARG_INT, &arg_nice_inc, 'N', 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 },
{ 0, 0, 0, 0, 0, 0, 0 }
};
static void distccd_show_usage(void)
{
dcc_show_version("distccd");
dcc_show_copyright();
printf (
"Usage:\n"
" distccd [OPTIONS]\n"
"\n"
"Options:\n"
" --help explain usage and exit\n"
" --version show version and exit\n"
" -p, --port PORT TCP port to listen on\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"
" -a, --allow IP[/MASK] client address access control\n"
" Debug and trace:\n"
" --verbose include debug messages in log\n"
" --no-fork single process only (for debugging ONLY)\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 (for debugging)\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': {
struct dcc_allow_list *new;
new = malloc(sizeof *new);
if (!new)
rs_fatal("malloc failed");
new->next = opt_allowed;
opt_allowed = new;
if ((exitcode = dcc_parse_mask(poptGetOptArg(po), &new->addr, &new->mask)))
goto out_exit;
}
break;
case 'n':
if (arg_nchildren < 1 || arg_nchildren > 20000) {
rs_log_error("--tasks argument must be >1");
exitcode = EXIT_BAD_ARGUMENTS;
goto out_exit;
}
break;
case 'N':
if (nice(arg_nice_inc) == -1) {
rs_log_warning("nice %d failed: %s", arg_nice_inc,
strerror(errno));
}
break;
case 'u':
if (getuid() != 0 && geteuid() != 0) {
rs_log_warning("--user is ignored when distccd is not run by root");
}
break;
case 'V':
dcc_show_version("distccd");
exitcode = EXIT_SUCCESS;
goto out_exit;
case 'v':
rs_trace_set_level(RS_LOG_DEBUG);
break;
default:
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);
}