#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 <signal.h>
#include <sys/stat.h>
#include <sys/time.h>
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
#include <sys/param.h>
#include "distcc.h"
#include "trace.h"
#include "io.h"
#include "util.h"
#include "exitcode.h"
int 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);
}
rs_log(RS_LOG_INFO,
"exit: code %d; self: %d.%04d user %d.%04d sys; children: %d.%04d user %d.%04d 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));
}
int argv_contains(char **argv, const char *s)
{
while (*argv) {
if (!strcmp(*argv, s))
return 1;
argv++;
}
return 0;
}
int dcc_redirect_fd(int fd, const char *fname, int mode)
{
int newfd;
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;
}
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;
}
int set_cloexec_flag (int desc, int value)
{
int oldflags = fcntl (desc, F_GETFD, 0);
if (oldflags < 0)
return oldflags;
if (value != 0)
oldflags |= FD_CLOEXEC;
else
oldflags &= ~FD_CLOEXEC;
return fcntl (desc, F_SETFD, oldflags);
}
int dcc_ignore_sigpipe(int val)
{
struct sigaction action;
action.sa_handler = val ? SIG_IGN : SIG_DFL;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
if (sigaction(SIGPIPE, &action, NULL)) {
rs_log_warning("sigaction(SIGPIPE, %s) failed: %s",
val ? "ignore" : "default",
strerror(errno));
return -1;
}
return 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_error("getwd overflowed in dcc_abspath()");
exit(EXIT_FAILURE);
}
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_FAILURE);
}
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;
}