#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"
char const *rs_program_name = "distccd";
static int dcc_inetd_server(void);
static void dcc_setup_real_log(void);
#include <arpa/inet.h>
#include <inttypes.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dns_sd.h>
#include <sys/socket.h>
#include <ifaddrs.h>
static DNSServiceRef zcRegRef = NULL;
static pthread_t zcRegThread;
static int zcPort;
static void dcc_reg_reply(const DNSServiceRef ref,
const DNSServiceFlags flags,
const DNSServiceErrorType errorCode,
const char *aName,
const char *aRegType,
const char *aDomain,
void *aContext)
{
if ( errorCode ) {
rs_log_error("Aborting zeroconfiguration registration due to error: %d", errorCode);
pthread_exit(NULL);
} else {
rs_log_info("Registered and active as \"%s.%s%s\"", aName, aRegType, aDomain);
}
}
static void dcc_actually_register(void *listen_addr_ptr)
{
char *listen_addr = (char *)listen_addr_ptr;
char *service = getenv("DISTCCD_SERVICE_NAME");
int interface = 0;
if (listen_addr != NULL) {
struct ifaddrs *first, *curr;
struct in_addr addr;
struct sockaddr *ifa_addr;
inet_aton(listen_addr, &addr);
if (getifaddrs(&first) == 0) {
curr = first;
while (curr && interface == 0) {
if (curr->ifa_addr->sa_family == AF_INET) {
struct sockaddr_in *in_addr = (struct sockaddr_in *)curr->ifa_addr;
if (memcmp(&addr, &in_addr->sin_addr, sizeof(struct in_addr)) == 0)
interface = if_nametoindex(curr->ifa_name);
}
curr = curr->ifa_next;
}
freeifaddrs(first);
}
}
if (service == NULL)
service = "_xcodedistcc._tcp.";
DNSServiceErrorType exitValue = DNSServiceRegister(&zcRegRef,
0,
0,
NULL,
service,
"",
NULL,
htons(zcPort),
0,
NULL,
(DNSServiceRegisterReply)dcc_reg_reply,
NULL);
if ( exitValue == kDNSServiceErr_NoError ) {
while ( 1 ) {
exitValue = DNSServiceProcessResult(zcRegRef);
if ( exitValue != kDNSServiceErr_NoError ) {
rs_log_error("Unable to handle zeroconfiguration replies: %d", exitValue);
break;
}
}
} else {
rs_log_error("Unable to register for zeroconfiguration: %d", exitValue);
}
pthread_exit(NULL);
}
void dcc_register_bonjour(int servicePort)
{
zcPort = servicePort;
if ( pthread_create(&zcRegThread, NULL,
(void *(*)(void *))dcc_actually_register,
opt_listen_addr) ) {
rs_log_error("Unable to create thread for zeroconfiguration");
}
}
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)
{
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;
}
}
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);
dcc_register_bonjour(arg_port);
if (!dcc_should_be_inetd())
if ((ret = dcc_set_lifetime()) != 0)
dcc_exit(ret);
if (nice(opt_niceness) == -1) {
rs_log_warning("nice %d failed: %s", opt_niceness,
strerror(errno));
}
if ((ret = dcc_discard_root()) != 0)
dcc_exit(ret);
dcc_setup_real_log();
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);
}
int dcc_set_lifetime(void)
{
if (opt_lifetime) {
alarm(opt_lifetime);
}
return 0;
}
static void dcc_setup_real_log(void)
{
int fd;
if (opt_log_stderr) {
rs_remove_all_loggers();
rs_add_logger(rs_logger_file, RS_LOG_DEBUG, 0, STDERR_FILENO);
return;
}
if (arg_log_file) {
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));
} else {
rs_remove_all_loggers();
rs_add_logger(rs_logger_file, RS_LOG_DEBUG, NULL, fd);
return;
}
}
rs_remove_all_loggers();
openlog("distccd", LOG_PID, LOG_DAEMON);
rs_add_logger(rs_logger_syslog, RS_LOG_DEBUG, 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;
}
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)) {
rs_log_notice("failed to get peer name: %s", strerror(errno));
psa = NULL;
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;
}