include_server_if.c [plain text]
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include "distcc.h"
#include "trace.h"
#include "rpc.h"
#include "clinet.h"
#include "exitcode.h"
#include "util.h"
#include "hosts.h"
#include "include_server_if.h"
static int dcc_count_slashes(const char *path);
static int dcc_count_leading_dotdots(const char *path);
static int dcc_categorize_file(const char *include_server_filename);
#define INCLUDE_SERVER_DIR_DEPTH 3
int dcc_talk_to_include_server(char **argv, char ***files)
{
char *include_server_port;
int fd;
struct sockaddr_un sa;
int ret;
char *stub;
stub = getenv("INCLUDE_SERVER_STUB");
if (stub != NULL) {
ret = dcc_tokenize_string(stub, files);
rs_log_warning("INCLUDE_SERVER_STUB is set to '%s'; "
"ignoring include server",
dcc_argv_tostr(*files));
return ret;
}
include_server_port = getenv("INCLUDE_SERVER_PORT");
if (include_server_port == NULL) {
rs_log_warning("INCLUDE_SERVER_PORT not set - "
"did you forget to run under 'pump'?");
return 1;
}
if (strlen(include_server_port) >= ((int)sizeof(sa.sun_path) - 1)) {
rs_log_warning("$INCLUDE_SERVER_PORT is longer than %d characters",
(sizeof(sa.sun_path) - 1));
return 1;
}
strcpy(sa.sun_path, include_server_port);
sa.sun_family = AF_UNIX;
if (dcc_connect_by_addr((struct sockaddr *) &sa, sizeof(sa), &fd))
return 1;
if (dcc_x_cwd(fd) ||
dcc_x_argv(fd, argv) ||
dcc_r_argv(fd, files)) {
rs_log_warning("failed to talk to include server '%s'",
include_server_port);
dcc_close(fd);
return 1;
}
if (dcc_close(fd)) {
return 1;
}
if (dcc_argv_len(*files) == 0) {
rs_log_warning("include server gave up analyzing");
return 1;
}
return 0;
}
int dcc_get_original_fname(const char *fname, char **original_fname)
{
int i;
char *work, *alloced_work, *extension;
alloced_work = work = strdup(fname);
if (work == NULL)
return EXIT_OUT_OF_MEMORY;
for (i = 0; i < INCLUDE_SERVER_DIR_DEPTH; ++i) {
work = strchr(work + 1, '/');
if (work == NULL) {
return 1;
}
}
extension = dcc_find_extension(work);
if (extension && (strcmp(extension, ".abs") == 0)) {
*extension = '\0';
}
extension = dcc_find_extension(work);
if (extension && (strcmp(extension, ".lzo") == 0)) {
*extension = '\0';
}
*original_fname = strdup(work);
if (*original_fname == NULL) {
free(alloced_work);
return EXIT_OUT_OF_MEMORY;
}
free(alloced_work);
return 0;
}
int
dcc_approximate_includes(struct dcc_hostdef *host, char **argv)
{
char **files;
int i;
int ret;
if (host->cpp_where != DCC_CPP_ON_SERVER) {
rs_log_error("'--scan_includes' specified, "
"but distcc wouldn't have used include server "
"(make sure hosts list includes ',cpp' option?)");
return EXIT_DISTCC_FAILED;
}
if ((ret = dcc_talk_to_include_server(argv, &files))) {
rs_log_error("failed to get includes from include server");
return ret;
}
for (i = 0; files[i]; i++) {
if ((ret = dcc_categorize_file(files[i])))
return ret;
}
return 0;
}
static int
dcc_categorize_file(const char *include_server_filename) {
char *filename;
int is_symlink = 0;
int is_forced_directory = 0;
int is_system_include_directory = 0;
char link_target[MAXPATHLEN + 1];
int ret;
if ((ret = dcc_is_link(include_server_filename, &is_symlink)))
return ret;
if (is_symlink)
if ((ret = dcc_read_link(include_server_filename, link_target)))
return ret;
if ((ret = dcc_get_original_fname(include_server_filename, &filename))) {
rs_log_error("dcc_get_original_fname failed");
return ret;
}
if (str_endswith("/forcing_technique_271828", filename)) {
filename[strlen(filename) - strlen("/forcing_technique_271828")]
= '\0';
is_forced_directory = 1;
}
if (is_symlink) {
int leading_dotdots = dcc_count_leading_dotdots(link_target);
is_system_include_directory =
leading_dotdots > 0 &&
leading_dotdots > dcc_count_slashes(filename) &&
strcmp(link_target + 3 * leading_dotdots - 1, filename) == 0;
}
printf("%-9s %s\n", is_system_include_directory ? "SYSTEMDIR" :
is_forced_directory ? "DIRECTORY" :
is_symlink ? "SYMLINK" :
"FILE",
filename);
return 0;
}
static int
dcc_count_slashes(const char *path)
{
int i;
int count = 0;
for (i = 0; path[i]; i++) {
if (path[i] == '/')
count++;
}
return count;
}
static int
dcc_count_leading_dotdots(const char *path)
{
int count = 0;
while (str_startswith("../", path)) {
path += 3;
count++;
}
return count;
}