static int dcc_input_tmpnam(char * orig_input, char **tmpnam_ret) { const char *input_exten; rs_trace("input file %s", orig_input); input_exten = dcc_find_extension(orig_input); if (input_exten) input_exten = dcc_preproc_exten(input_exten); if (!input_exten) /* previous line might return NULL */ input_exten = ".tmp"; return dcc_make_tmpnam("distccd", input_exten, tmpnam_ret); }
/** * 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; }
/* Given the name of a dotd file, and the name of the directory * masquerading as root, write a @p new_dotd file that * contains everything in dotd, but with the "root" directory removed. * It will also substitute client_out_name for server_out_name, * rewriting the dependency target. */ int dcc_cleanup_dotd(const char *dotd_fname, char **new_dotd_fname, const char *root_dir, const char *client_out_name, const char *server_out_name) { /* When we do the substitution of server-side output name to * client-side output name, we may end up with a line that * longer than the longest line we expect from the compiler. */ char buf[2 * MAX_DOTD_LINE_LEN]; FILE *dotd, *tmp_dotd; char *found; int ret; dotd = fopen(dotd_fname, "r"); if (dotd == NULL) { return 1; } ret = dcc_make_tmpnam(dcc_find_basename(dotd_fname), ".d", new_dotd_fname); if (ret) { fclose(dotd); return ret; } tmp_dotd = fopen(*new_dotd_fname, "w"); if (tmp_dotd == NULL) { fclose(dotd); return 1; } while (fgets(buf, MAX_DOTD_LINE_LEN, dotd)) { if ((strchr(buf, '\n') == NULL) && !feof(dotd)) { /* Line length must have exceeded MAX_DOTD_LINE_LEN: bail out. */ fclose(dotd); fclose(tmp_dotd); return 1; } /* First, the dependency target substitution */ if (dcc_strgraft(buf, sizeof(buf), server_out_name, client_out_name)) { fclose(dotd); fclose(tmp_dotd); return 1; } /* Second, the trimming of the "root" directory" */ found = strstr(buf, root_dir); while (found) { char *rest_of_buf = found + strlen(root_dir); memmove(found, rest_of_buf, strlen(rest_of_buf) + 1); found = strstr(found, root_dir); } if (fprintf(tmp_dotd, "%s", buf) < 0) { fclose(dotd); fclose(tmp_dotd); return 1; } } if (ferror(dotd) || ferror(tmp_dotd)) { return 1; } fclose(dotd); if (fclose(tmp_dotd) < 0) { return 1; } return 0; }