/** * 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; }
/* Go through arguments (in @p argv), and relevant environment variables, and * find out where the dependencies output should go. Return that location in a * newly allocated string in @p dotd_fname. @p needs_dotd is set to true if the * compilation command line and environent imply that a .d file must be * produced. @p sets_dotd_target is set to true if there is a -MQ or -MT * option. This is to be used on the client, so that the client knows where to * put the .d file it gets from the server. @p dotd_target is set only if * @needs_dotd is true and @sets_dotd_target is false and the target is given in * the DEPENDENCIES_OUTPUT environment variable. * * Note: -M is not handled here, because this option implies -E. * * TODO(manos): it does not support SUNPRO_DEPENDENCIES. */ int dcc_get_dotd_info(char **argv, char **dotd_fname, int *needs_dotd, int *sets_dotd_target, char **dotd_target) { char *deps_output = 0; char *input_file; char *output_file; char **new_args; /* will throw this away */ int has_dash_o = 0; char *env_var = 0; int ret; int i; char *a; *needs_dotd = 0; *sets_dotd_target = 0; *dotd_target = NULL; env_var = getenv("DEPENDENCIES_OUTPUT"); if (env_var != NULL) { *needs_dotd = 1; } for (i = 0; (a = argv[i]); i++) { if (strcmp(a, "-MT") == 0) { *sets_dotd_target = 1; ++i; continue; } if (strcmp(a, "-MQ") == 0) { *sets_dotd_target = 1; ++i; continue; } /* Catch-all for all -MD, -MMD, etc, options. * -MQ and -MT do not imply a deps file is expected. */ if (strncmp(a, "-M", 2) == 0) { *needs_dotd = 1; } if (strcmp(a, "-MF") == 0) { ++i; deps_output = argv[i]; } else if (strncmp(a, "-MF", 3) == 0) { deps_output = argv[i] + 3; } else if (strcmp(a, "-o") == 0) { has_dash_o = 1; } } /* TODO(csilvers): we also need to parse -Wp,-x,-y,-z, in the same * way we do gcc flags in the for loop above. Note that the -Wp * flags are passed to cpp, with slightly different semantics than * gcc flags (eg -Wp,-MD takes a filename argument, while -MD does * not). */ if (deps_output) { *dotd_fname = strdup(deps_output); if (*dotd_fname == NULL) { return EXIT_OUT_OF_MEMORY; } else { return 0; } } /* ok, so there is no explicit setting of the deps filename. */ deps_output = env_var; if (deps_output) { char *space; *dotd_fname = strdup(deps_output); if (*dotd_fname == NULL) { return EXIT_OUT_OF_MEMORY; } space = strchr(*dotd_fname, ' '); if (space != NULL) { *space = '\0'; *dotd_target = space + 1; } return 0; } /* and it's not set explicitly in the variable */ { /* Call dcc_scan_args to find the input/output files in order to calculate a name for the .d file.*/ char *extension; char *tmp_dotd_fname; ret = dcc_scan_args(argv, &input_file, &output_file, &new_args, NULL); if (ret) return ret; /* if .o is set, just append .d. * otherwise, take the basename of the input, and set the suffix to .d */ if (has_dash_o) tmp_dotd_fname = strdup(output_file); else tmp_dotd_fname = strdup(input_file); if (tmp_dotd_fname == NULL) return EXIT_OUT_OF_MEMORY; extension = dcc_find_extension(tmp_dotd_fname); /* Whether derived from input or output filename, we peel the extension off (if it exists). */ if (extension) { /* dcc_find_extension guarantees that there is space for 'd'. */ extension[1] = 'd'; extension[2] = '\0'; *dotd_fname = tmp_dotd_fname; } else { /* There is no extension (or name ends with a "."). */ if (tmp_dotd_fname[strlen(tmp_dotd_fname) - 1] == '.') checked_asprintf(dotd_fname, "%s%s", tmp_dotd_fname, "d"); else checked_asprintf(dotd_fname, "%s%s", tmp_dotd_fname, ".d"); if (*dotd_fname == NULL) { return EXIT_OUT_OF_MEMORY; } free(tmp_dotd_fname); } return 0; } }