⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exec.c

📁 distcc编译器的源代码.好像是readhat公司开发的.
💻 C
字号:
/* -*- c-file-style: "java"; indent-tabs-mode: nil; fill-column: 78 -*- *  * 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 */			/* 18 Their bows also shall dash the young men			 * to pieces; and they shall have no pity on			 * the fruit of the womb; their eyes shall not			 * spare children.			 *		-- Isaiah 13 *//** * @file * * Run compilers or preprocessors. * * The whole server is run in a separate process group and normally in a * separate session.  (It is not a separate session in --no-detach debug * mode.)  This allows us to cleanly kill off all children and all compilers * when the parent is terminated. * * @todo On Cygwin, fork() must be emulated and therefore will be * slow.  It would be faster to just use their spawn() call, rather * than fork/exec. **/#include "config.h"#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <fcntl.h>#include <errno.h>#include <signal.h>#include <sys/types.h>#include <sys/wait.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/resource.h>#include "distcc.h"#include "trace.h"#include "util.h"#include "exitcode.h"#include "exec.h"#include "lock.h"#include "hosts.h"static void dcc_inside_child(char **argv,                             const char *stdin_file,                             const char *stdout_file,                             const char *stderr_file) NORETURN;static void dcc_execvp(char **argv) NORETURN;void dcc_note_execution(struct dcc_hostdef *host, char **argv){    char *astr;    astr = dcc_argv_tostr(argv);    rs_log(RS_LOG_INFO|RS_LOG_NONAME, "exec on %s: %s",           host->hostdef_string, astr);    free(astr);}/** * Redirect stdin/out/err.  Filenames may be NULL to leave them untouched. * * This is called when running a job remotely, but *not* when running * it locally, because people might e.g. want cpp to read from stdin. **/int dcc_redirect_fds(const char *stdin_file,                     const char *stdout_file,                     const char *stderr_file){    int ret;        if (stdin_file)        if ((ret = dcc_redirect_fd(STDIN_FILENO, stdin_file, O_RDONLY)))            return ret;        if (stdout_file) {        if ((ret = dcc_redirect_fd(STDOUT_FILENO, stdout_file,                                   O_WRONLY | O_CREAT | O_TRUNC)))            return ret;    }        if (stderr_file) {        /* Open in append mode, because the server will dump its own error         * messages into the compiler's error file.  */        if ((ret = dcc_redirect_fd(STDERR_FILENO, stderr_file,                                   O_WRONLY | O_CREAT | O_APPEND)))            return ret;    }    return 0;}/** * Replace this program with another in the same process. * * Does not return, either execs the compiler in place, or exits with * a message. **/static void dcc_execvp(char **argv){    char *slash;        execvp(argv[0], argv);    /* If we're still running, the program was not found on the path.  One     * thing that might have happened here is that the client sent an absolute     * compiler path, but the compiler's located somewhere else on the server.     * In the absence of anything better to do, we search the path for its     * basename.     *     * Actually this code is called on both the client and server, which might     * cause unintnded behaviour in contrived cases, like giving a full path     * to a file that doesn't exist.  I don't think that's a problem. */    slash = strrchr(argv[0], '/');    if (slash)        execvp(slash + 1, argv);        /* shouldn't be reached */    rs_log_error("failed to exec %s: %s", argv[0], strerror(errno));    dcc_exit(EXIT_COMPILER_MISSING); /* a generalization, i know */}/** * 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();    /* 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);}int dcc_new_pgrp(void){    /* If we're a session group leader, then we are not able to call     * setpgid().  However, setsid will implicitly have put us into a new     * process group, so we don't have to do anything. */    /* Does everyone have getpgrp()?  It's in POSIX.1.  We used to call     * getpgid(0), but that is not available on BSD/OS. */    if (getpgrp() == getpid()) {        rs_trace("already a process group leader");        return 0;    }        if (setpgid(0, 0) == 0) {        rs_trace("entered process group");        return 0;    } else {        rs_trace("setpgid(0, 0) failed: %s", strerror(errno));        return EXIT_DISTCC_FAILED;    }}/** * Run @p argv in a child asynchronously. * * stdin, stdout and stderr are redirected as shown, unless those * filenames are NULL.  In that case they are left alone. * * @warning When called on the daemon, where stdin/stdout may refer to random * network sockets, all of the standard file descriptors must be redirected! **/int dcc_spawn_child(char **argv, pid_t *pidptr,                    const char *stdin_file,                    const char *stdout_file,                    const char *stderr_file){    pid_t pid;    dcc_trace_argv("forking to execute", argv);        pid = fork();    if (pid == -1) {        rs_log_error("failed to fork: %s", strerror(errno));        return EXIT_OUT_OF_MEMORY; /* probably */    } else if (pid == 0) {        dcc_inside_child(argv, stdin_file, stdout_file, stderr_file);        /* !! NEVER RETURN FROM HERE !! */    } else {        *pidptr = pid;        rs_trace("child started as pid%d", (int) pid);        return 0;    }}void dcc_reset_signal(int whichsig){    struct sigaction act_dfl;    memset(&act_dfl, 0, sizeof act_dfl);    act_dfl.sa_handler = SIG_DFL;    sigaction(whichsig, &act_dfl, NULL);    /* might be called from signal handler, therefore no IO to log a     * message */}static int sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage){#ifdef HAVE_WAIT4    return wait4(pid, status, options, rusage);#elif HAVE_WAITPID    /* Just doing getrusage(children) is not sufficient, because other     * children may have exited previously. */    memset(rusage, 0, sizeof *rusage);    return waitpid(pid, status, options);#else#error Please port this#endif}/** * Blocking wait for a child to exit.  This is used when waiting for * cpp, gcc, etc. * * This is not used by the daemon-parent; it has its own * implementation in dcc_reap_kids().  They could be unified, but the * parent only waits when it thinks a child has exited; the child * waits all the time. **/int dcc_collect_child(const char *what, pid_t pid,                      int *wait_status){    struct rusage ru;    pid_t ret_pid;        while (1) {        if ((ret_pid = sys_wait4(pid, wait_status, 0, &ru)) != -1) {            /* This is not the main user-visible message, that comes from             * critique_status(). */            rs_trace("%s child %ld terminated with status %#x",                     what, (long) ret_pid, *wait_status);            rs_log_info("%s times: user %ld.%06lds, system %ld.%06lds, "                        "%ld minflt, %ld majflt",                        what,                        ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,                        ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,                        ru.ru_minflt, ru.ru_majflt);            return 0;        } else if (errno == EINTR) {            rs_trace("wait4 was interrupted; retrying");            continue;        } else {            rs_log_error("sys_wait4(pid=%d) borked: %s", (int) pid, strerror(errno));            return EXIT_DISTCC_FAILED;        }    }}/** * Analyze and report to the user on a command's exit code.   * * @param command short human-readable description of the command (perhaps * argv[0]) * * @returns 0 if the command succeeded; 128+SIGNAL if it stopped on a * signal; otherwise the command's exit code. **/int dcc_critique_status(int status,                        const char *command,                        const char *input_fname,                        struct dcc_hostdef *host,                        int verbose){    int logmode;    /* verbose mode is only used for executions that the user is likely to     * particularly need to know about */    if (verbose)        logmode = RS_LOG_ERR | RS_LOG_NONAME;    else        logmode = RS_LOG_INFO | RS_LOG_NONAME;        if (WIFSIGNALED(status)) {#ifdef HAVE_STRSIGNAL        rs_log(logmode,               "%s %s on %s:%s %s",               command, input_fname, host->hostdef_string,               strsignal(WTERMSIG(status)),               WCOREDUMP(status) ? " (core dumped)" : "");#else        rs_log(logmode,               "%s %s on %s terminated by signal %d%s",               command, input_fname, host->hostdef_string,               WTERMSIG(status),               WCOREDUMP(status) ? " (core dumped)" : "");#endif        /* Unix convention is to return 128+signal when a subprocess crashes. */        return 128 + WTERMSIG(status);    } else if (WEXITSTATUS(status) == 1) {        /* Normal failure gives exit code 1, so handle that specially */        rs_log(logmode, "%s %s on %s failed", command, input_fname, host->hostdef_string);        return WEXITSTATUS(status);    } else if (WEXITSTATUS(status)) {        /* This is a tough call; we don't really want to clutter the client's         * error stream, but if we don't say where the compilation failed then         * people may find it hard to work things out. */        rs_log(logmode,               "%s %s on %s failed with exit code %d",               command, input_fname, host->hostdef_string, WEXITSTATUS(status));        return WEXITSTATUS(status);    } else {        rs_log(RS_LOG_INFO|RS_LOG_NONAME,               "%s %s on %s completed ok", command, input_fname, host->hostdef_string);        return 0;    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -