#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 <netdb.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 "util.h"
#include "exitcode.h"
#include "snprintf.h"
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);
}
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));
}
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)
{
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;
}
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);
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;
if (!S_ISLNK(sb.st_mode))
break;
if ((len = readlink(buf, linkbuf, sizeof linkbuf)) <= 0)
continue;
linkbuf[len] = '\0';
if (strstr(linkbuf, "distcc")) {
newpath = n;
}
}
if (newpath) {
int ret = dcc_set_path(newpath);
if (ret)
return ret;
} else
rs_trace("not modifying PATH");
free(buf);
return 0;
}
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;
}
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_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;
}
int dcc_dup_part(const char **psrc, char **pdst, const char *sep)
{
int 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;
}
#ifndef HAVE_STRLCPY
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