diff options
author | Craig Silverstein <csilvers@khanacademy.org> | 2008-04-11 22:36:40 +0000 |
---|---|---|
committer | Craig Silverstein <csilvers@khanacademy.org> | 2008-04-11 22:36:40 +0000 |
commit | 596cf4e2f019a766965ad0566495c56b7d295fe4 (patch) | |
tree | 1726969de95d86fc5647af1eeb99ea0489ba91c4 /src/clirpc.c | |
parent | 0a38eace37b20a663b235fb20107829e22fbeb43 (diff) | |
download | distcc-git-596cf4e2f019a766965ad0566495c56b7d295fe4.tar.gz |
The first step of moving everything in the distcc directory to the top
level. I'm doing this in two stages, because I don't understand svn
enough to be confident to do it in one. This first stage just copies
all the files from distcc/FOO to FOO. Now there are two copies of
each file under distcc; the Makefile/etc uses the one in distcc and
ignores the one at the top level.
The next commit will delete everything under distcc, and rewrite the
Makefile/etc to use the top-level versions instead.
Diffstat (limited to 'src/clirpc.c')
-rw-r--r-- | src/clirpc.c | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/src/clirpc.c b/src/clirpc.c new file mode 100644 index 0000000..43e2fda --- /dev/null +++ b/src/clirpc.c @@ -0,0 +1,281 @@ +/* -*- c-file-style: "java"; indent-tabs-mode: nil -*- + * + * distcc -- A simple distributed compiler system + * + * Copyright (C) 2002, 2003, 2004 by Martin Pool <mbp@samba.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "distcc.h" +#include "trace.h" +#include "exec.h" +#include "rpc.h" +#include "exitcode.h" +#include "util.h" +#include "clinet.h" +#include "bulk.h" +#include "hosts.h" +#include "state.h" +#include "include_server_if.h" +#include "emaillog.h" + +/** + * @file + * + * @brief Client-side RPC functions. + **/ + +/* + * Transmit header for whole request. + */ +int dcc_x_req_header(int fd, + enum dcc_protover protover) +{ + return dcc_x_token_int(fd, "DIST", protover); +} + + + +/** + * Transmit an argv array. + **/ +int dcc_x_argv(int fd, char **argv) +{ + int i; + int ret; + int argc; + + argc = dcc_argv_len(argv); + + if (dcc_x_token_int(fd, "ARGC", (unsigned) argc)) + return EXIT_PROTOCOL_ERROR; + + for (i = 0; i < argc; i++) { + if ((ret = dcc_x_token_string(fd, "ARGV", argv[i]))) + return ret; + } + + return 0; +} + +/** + * Transmit the current working directory + */ +int dcc_x_cwd(int fd) +{ + int ret; + char cwd[MAXPATHLEN + 1]; + char * cwd_ret; + cwd_ret = getcwd(cwd, MAXPATHLEN); + if (cwd_ret == NULL) { + return 0; + } + ret = dcc_x_token_string(fd, "CDIR", cwd); + return ret; +} + +/** + * Read the "DONE" token from the network that introduces a response. + **/ +int dcc_r_result_header(int ifd, + enum dcc_protover expect_ver) +{ + unsigned vers; + int ret; + + if ((ret = dcc_r_token_int(ifd, "DONE", &vers))) + return ret; + + if (vers != expect_ver) { + rs_log_error("got version %d not %d in response from server", + vers, expect_ver); + return EXIT_PROTOCOL_ERROR; + } + + rs_trace("got response header"); + + return 0; +} + + +int dcc_r_cc_status(int ifd, int *status) +{ + unsigned u_status; + int ret; + + ret = dcc_r_token_int(ifd, "STAT", &u_status); + *status = u_status; + return ret; +} + + +/** + * The second half of the client protocol: retrieve all results from the server. + **/ +int dcc_retrieve_results(int net_fd, + int *status, + const char *output_fname, + const char *deps_fname, + const char *server_stderr_fname, + struct dcc_hostdef *host) +{ + unsigned len; + int ret; + unsigned o_len; + + if ((ret = dcc_r_result_header(net_fd, host->protover))) + return ret; + + /* We've started to see the response, so the server is done + * compiling. */ + dcc_note_state(DCC_PHASE_RECEIVE, NULL, NULL); + + if ((ret = dcc_r_cc_status(net_fd, status))) + return ret; + + if ((ret = dcc_r_token_int(net_fd, "SERR", &len))) + return ret; + + /* Save the server-side errors into a file. This way, we can + decide later whether we want to report them to the user + or not. We don't want to report them to the user if + we are going to redo the compilation locally, because then + the local errors are going to appear. + Always put the server-side errors in the email we will + send to the maintainers, though. + */ + + if ((ret = dcc_r_file(net_fd, server_stderr_fname, len, host->compr))) + return ret; + + if (dcc_add_file_to_log_email("server-side stderr", server_stderr_fname)) + return ret; + + if ((ret = dcc_r_token_int(net_fd, "SOUT", &len)) + || (ret = dcc_r_bulk(STDOUT_FILENO, net_fd, len, host->compr)) + || (ret = dcc_r_token_int(net_fd, "DOTO", &o_len))) + return ret; + + + /* If the compiler succeeded, then we always retrieve the result, + * even if it's 0 bytes. */ + if (*status == 0) { + if ((ret = dcc_r_file_timed(net_fd, output_fname, o_len, host->compr))) + return ret; + if (host->cpp_where == DCC_CPP_ON_SERVER) { + if ((ret = dcc_r_token_int(net_fd, "DOTD", &len) == 0) + && deps_fname != NULL) { + ret = dcc_r_file_timed(net_fd, deps_fname, len, host->compr); + return ret; + } + } + } else if (o_len != 0) { + rs_log_error("remote compiler failed but also returned output: " + "I don't know what to do"); + } + + return 0; +} + +/* points_to must be at least MAXPATHLEN + 1 long */ +static int dcc_read_link(const char* fname, char *points_to) +{ + int len; + if ((len = readlink(fname, points_to, MAXPATHLEN)) == -1) { + rs_log_error("readlink '%s' failed: %s", fname, strerror(errno)); + return EXIT_IO_ERROR; + } + points_to[len] = '\0'; + return 0; +} + +static int dcc_is_link(const char *fname, int *is_link) +{ + struct stat buf; + + if (lstat(fname, &buf) == -1) { + rs_log_error("stat '%s' failed: %s", fname, strerror(errno)); + return EXIT_IO_ERROR; + } + + *is_link = ((buf.st_mode & S_IFLNK) == S_IFLNK); + return 0; +} + +/* Send to @p ofd @p n_files whose names are in @p fnames. + * @fnames must be null-terminated. + * The names can be coming from the include server, so + * we consult dcc_get_original_fname to get the real names. + * Always uses lzo compression. + */ +/* TODO: This code is highly specific to DCC_VER_3; it assumes + lzo compression is on, and that the include server has + actually compressed the files. */ +int dcc_x_many_files(int ofd, + unsigned int n_files, + char **fnames) +{ + int ret; + char link_points_to[MAXPATHLEN + 1]; + int is_link; + const char *fname; + char *original_fname; + + dcc_x_token_int(ofd, "NFIL", n_files); + + for (; *fnames != NULL; ++fnames) { + fname = *fnames; + ret = dcc_get_original_fname(fname, &original_fname); + if (ret) return ret; + + if ((ret = dcc_is_link(fname, &is_link))) { + return ret; + } + + if (is_link) { + if ((ret = dcc_read_link(fname, link_points_to)) || + (ret = dcc_x_token_string(ofd, "NAME", original_fname)) || + (ret = dcc_x_token_string(ofd, "LINK", link_points_to))) { + return ret; + } + } else { + ret = dcc_x_token_string(ofd, "NAME", original_fname); + if (ret) return ret; + /* File should be compressed already. + If we ever support non-compressed server-side-cpp, + we should have some checks here and then uncompress + the file if it is compressed. */ + ret = dcc_x_file(ofd, fname, "FILE", DCC_COMPRESS_NONE, + NULL); + if (ret) return ret; + } + } + return 0; +} |