示例#1
0
文件: exec.c 项目: katakk/distcc
/**
 * Called inside the newly-spawned child process to execute a command.
 * Either executes it, or returns an appropriate error.
 *
 * This routine also takes a lock on localhost so that it's counted
 * against the process load.  That lock will go away when the process
 * exits.
 *
 * In this current version locks are taken without regard to load limitation
 * on the current machine.  The main impact of this is that cpp running on
 * localhost will cause jobs to be preferentially distributed away from
 * localhost, but it should never cause the machine to deadlock waiting for
 * localhost slots.
 *
 * @param what Type of process to be run here (cpp, cc, ...)
 **/
static void dcc_inside_child(char **argv,
                             const char *stdin_file,
                             const char *stdout_file,
                             const char *stderr_file)
{
    int ret;

    if ((ret = dcc_ignore_sigpipe(0)))
        goto fail;              /* set handler back to default */

    /* Ignore failure */
    dcc_increment_safeguard();

#ifdef __CYGWIN__
    /* This will execute compiler and CORRECTLY redirect output if compiler is
     * a native Windows application.  If this never returns, it means the
     * compiler-execute succeeded.  We use a hack to decide if it's a windows
     * application: if argv[0] starts with "<letter>:" or with "\\", then it's
     * a windows path and we try dcc_execvp_cyg.  If not, we assume it's a
     * cygwin app and fall through to the unix-style forking, below.  If we
     * guess wrong, dcc_execvp_cyg will probably fail with error 3
     * (windows-exe for "path not found"), so again we'll fall through to the
     * unix-fork case.  Otherwise we just fail in a generic way.
     * TODO(csilvers): Figure out the right way to deal with this.  Running
     *                 cygwin apps via dcc_execvp_cyg segfaults (and takes a
     *                 long time to do it too), so I want to avoid that if
     *                 possible.  I don't know enough about cygwin or
     *                 cygwin/windows interactions to know the right thing to
     *                 do here.  Until distcc has cl.exe support, this may
     *                 all be a moot point anyway.
     */
    if (argv[0] && ((argv[0][0] != '\0' && argv[0][1] == ':') ||
                    (argv[0][0] == '\\' && argv[0][1] == '\\'))) {
        DWORD status;
        status = dcc_execvp_cyg(argv, stdin_file, stdout_file, stderr_file);
        if (status != 3) {
            ret = EXIT_DISTCC_FAILED;
            goto fail;
        }
    }
#endif

    /* do this last, so that any errors from previous operations are
     * visible */
    if ((ret = dcc_redirect_fds(stdin_file, stdout_file, stderr_file)))
        goto fail;

    dcc_execvp(argv);

    ret = EXIT_DISTCC_FAILED;

    fail:
    dcc_exit(ret);
}
示例#2
0
文件: serve.c 项目: aosm/distcc
/**
 * 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;
}