/** * Write a token, and then the string @p buf. * * The length of buf is determined by its nul delimiter, but the \0 is not sent. **/ int dcc_x_token_string(int fd, const char *token, const char *buf) { int ret; size_t len; len = strlen(buf); if ((ret = dcc_x_token_int(fd, token, (unsigned) len))) return ret; if ((ret = dcc_writex(fd, buf, len))) return ret; return 0; }
/** * 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; }
/** * Read a request, run the compiler, and send a response. **/ static int dcc_run_job(int in_fd, int out_fd) { char **argv; int status; char *temp_i, *temp_o, *err_fname, *out_fname; int ret, compile_ret; char *orig_input, *orig_output; pid_t cc_pid; enum dcc_protover protover; enum dcc_compress compr; dcc_indirection indirect; if ((ret = dcc_make_tmpnam("distcc", ".stderr", &err_fname))) goto out_cleanup; if ((ret = dcc_make_tmpnam("distcc", ".stdout", &out_fname))) goto out_cleanup; dcc_remove_if_exists(err_fname); dcc_remove_if_exists(out_fname); /* Capture any messages relating to this compilation to the same file as * compiler errors so that they can all be sent back to the client. */ dcc_add_log_to_file(err_fname); /* Ignore SIGPIPE; we consistently check error codes and will see the * EPIPE. Note that it is set back to the default behaviour when spawning * a child, to handle cases like the assembler dying while its being fed * from the compiler */ dcc_ignore_sigpipe(1); /* Allow output to accumulate into big packets. */ tcp_cork_sock(out_fd, 1); if ((ret = dcc_r_request_header(in_fd, &protover)) || (ret = dcc_r_argv(in_fd, &argv)) || (ret = dcc_scan_args(argv, &orig_input, &orig_output, &argv))) goto out_cleanup; if (strcmp(argv[0],"--host-info") == 0) { if ((ret = dcc_x_result_header(out_fd, protover)) || (ret = dcc_send_host_info(out_fd))) dcc_x_token_int(out_fd, "DOTO", 0); } else { rs_trace("output file %s", orig_output); if ((ret = dcc_input_tmpnam(orig_input, &temp_i))) goto out_cleanup; if ((ret = dcc_make_tmpnam("distccd", ".o", &temp_o))) goto out_cleanup; compr = (protover == 2) ? DCC_COMPRESS_LZO1X : DCC_COMPRESS_NONE; if ((ret = dcc_r_token_file(in_fd, "DOTI", temp_i, compr)) || (ret = dcc_set_input(argv, temp_i)) || (ret = dcc_set_output(argv, temp_o))) goto out_cleanup; if ((ret = dcc_check_compiler_masq(argv[0]))) goto out_cleanup; indirect.in_fd = in_fd; indirect.out_fd = out_fd; if ((compile_ret = dcc_spawn_child(argv, &cc_pid, "/dev/null", out_fname, err_fname, &indirect)) || (compile_ret = dcc_collect_child("cc", cc_pid, &status))) { /* We didn't get around to finding a wait status from the actual compiler */ status = W_EXITCODE(compile_ret, 0); } if ((ret = dcc_x_result_header(out_fd, protover)) || (ret = dcc_send_system_info(out_fd)) || (ret = dcc_send_compiler_version(out_fd, argv[0])) || (ret = dcc_x_cc_status(out_fd, status)) || (ret = dcc_x_file(out_fd, err_fname, "SERR", compr, NULL)) || (ret = dcc_x_file(out_fd, out_fname, "SOUT", compr, NULL)) || WIFSIGNALED(status) || WEXITSTATUS(status)) { /* Something went wrong, so send DOTO 0 */ dcc_x_token_int(out_fd, "DOTO", 0); } else { ret = dcc_x_file(out_fd, temp_o, "DOTO", compr, NULL); } dcc_critique_status(status, argv[0], orig_input, dcc_hostdef_local, 0); } tcp_cork_sock(out_fd, 0); rs_log(RS_LOG_INFO|RS_LOG_NONAME, "job complete"); out_cleanup: dcc_remove_log_to_file(); dcc_cleanup_tempfiles(); return ret; }
/* * Transmit header for whole request. */ int dcc_x_req_header(int fd, enum dcc_protover protover) { return dcc_x_token_int(fd, "DIST", protover); }
/* 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 = 0; char link_points_to[MAXPATHLEN + 1]; int is_link; const char *fname; char *original_fname = NULL; #ifdef XCODE_INTEGRATION /* NOTE: If this function is ever used for something besides pump * mode support for sending things to be compiled, then it should * take another argument to include/exclude this fixup. */ char *xci_original_fname, *xci_link_points_to; #endif 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; } #ifdef XCODE_INTEGRATION xci_original_fname = dcc_xci_mask_developer_dir(original_fname); if (xci_original_fname) { free(original_fname); original_fname = xci_original_fname; xci_original_fname = NULL; } else { ret = EXIT_OUT_OF_MEMORY; return ret; } #endif if (is_link) { if ((ret = dcc_read_link(fname, link_points_to))) { return ret; } #ifdef XCODE_INTEGRATION xci_link_points_to = dcc_xci_mask_developer_dir(link_points_to); if (xci_link_points_to) { strlcpy(link_points_to, xci_link_points_to, sizeof(link_points_to)); free(xci_link_points_to); xci_link_points_to = NULL; } else { ret = EXIT_OUT_OF_MEMORY; return ret; } #endif if ((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; }
/** * Send start of a result: DONE <version> **/ int dcc_x_result_header(int ofd, enum dcc_protover protover) { return dcc_x_token_int(ofd, "DONE", protover); }
int dcc_x_cc_status(int ofd, int status) { return dcc_x_token_int(ofd, "STAT", (unsigned) status); }