示例#1
0
static pid_t spawn_event_handler_child(const char *dump_dir_name, const char *event_name, int *fdp)
{
    char *args[9];
    args[0] = (char *) LIBEXEC_DIR"/abrt-handle-event";
    /* Do not forward ASK_* messages to parent*/
    args[1] = (char *) "-i";
    args[2] = (char *) "--nice";
    args[3] = (char *) "10";
    args[4] = (char *) "-e";
    args[5] = (char *) event_name;
    args[6] = (char *) "--";
    args[7] = (char *) dump_dir_name;
    args[8] = NULL;

    int pipeout[2];
    int flags = EXECFLG_INPUT_NUL | EXECFLG_OUTPUT | EXECFLG_QUIET | EXECFLG_ERR2OUT;
    VERB1 flags &= ~EXECFLG_QUIET;

    char *env_vec[3];
    /* Intercept ASK_* messages in Client API -> don't wait for user response */
    env_vec[0] = xstrdup("REPORT_CLIENT_NONINTERACTIVE=1");
    env_vec[1] = xasprintf("%s=%d", ABRT_SERVER_EVENT_ENV, getpid());
    env_vec[2] = NULL;

    pid_t child = fork_execv_on_steroids(flags, args, pipeout,
                                         env_vec, /*dir:*/ NULL,
                                         /*uid(unused):*/ 0);
    if (fdp)
        *fdp = pipeout[0];
    return child;
}
示例#2
0
文件: spawn.c 项目: rplnt/abrt
char *run_in_shell_and_save_output(int flags,
		const char *cmd,
		const char *dir,
		size_t *size_p)
{
	flags |= EXECFLG_OUTPUT;
	flags &= ~EXECFLG_INPUT;

	const char *argv[] = { "/bin/sh", "-c", cmd, NULL };
	int pipeout[2];
	pid_t child = fork_execv_on_steroids(flags, (char **)argv, pipeout,
		/*env_vec:*/ NULL, dir, /*uid (unused):*/ 0);

	size_t pos = 0;
	char *result = NULL;
	while (1) {
		result = (char*) xrealloc(result, pos + 4*1024 + 1);
		size_t sz = safe_read(pipeout[0], result + pos, 4*1024);
		if (sz <= 0) {
			break;
		}
		pos += sz;
	}
	result[pos] = '\0';
	if (size_p)
		*size_p = pos;
	close(pipeout[0]);
	waitpid(child, NULL, 0);

	return result;
}
示例#3
0
int spawn_next_command(struct run_event_state *state,
                const char *dump_dir_name,
                const char *event,
                unsigned execflags
) {
    char *cmd = pop_next_command(&state->rule_list,
                NULL,          /* don't return event_name */
                NULL,          /* NULL dd: we match by... */
                dump_dir_name, /* ...dirname */
                event, strlen(event)+1 /* for this event name exactly (not prefix) */
    );
    if (!cmd)
        return -1;

    /* We count it even if fork fails. The counter isn't meant
     * to count *successful* forks, it is meant to let caller know
     * whether the event we run has *any* handlers configured, or not.
     */
    state->children_count++;

    log_notice("Executing '%s'", cmd);

    /* Export some useful environment variables for children */
    char *env_vec[4];
    /* Just exporting dump_dir_name isn't always ok: it can be "."
     * and some children want to cd to other directory but still
     * be able to find problem directory by using $DUMP_DIR...
     */
    char *full_name = realpath(dump_dir_name, NULL);
    env_vec[0] = xasprintf("DUMP_DIR=%s", (full_name ? full_name : dump_dir_name));
    free(full_name);
    env_vec[1] = xasprintf("EVENT=%s", event);
    env_vec[2] = xasprintf("REPORT_CLIENT_SLAVE=1");
    env_vec[3] = NULL;

    char *argv[4];
    argv[0] = (char*)"/bin/sh"; // TODO: honor $SHELL?
    argv[1] = (char*)"-c";
    argv[2] = cmd;
    argv[3] = NULL;

    int pipefds[2];
    state->command_pid = fork_execv_on_steroids(
                EXECFLG_INPUT | EXECFLG_OUTPUT | EXECFLG_ERR2OUT | execflags,
                argv,
                pipefds,
                /* env_vec: */ env_vec,
                /* dir: */ dump_dir_name,
                /* uid(unused): */ 0
    );
    state->command_out_fd = pipefds[0];
    state->command_in_fd = pipefds[1];

    free(env_vec[0]);
    free(env_vec[1]);
    free(env_vec[2]);
    free(cmd);

    return 0;
}
示例#4
0
static void exec_and_feed_input(const char* text, char **args)
{
    int pipein[2];

    pid_t child = fork_execv_on_steroids(
                EXECFLG_INPUT | EXECFLG_QUIET,
                args,
                pipein,
                /*env_vec:*/ NULL,
                /*dir:*/ NULL,
                /*uid (ignored):*/ 0
    );

    full_write_str(pipein[1], text);
    close(pipein[1]);

    int status;
    waitpid(child, &status, 0); /* wait for command completion */
    if (status != 0)
        error_msg_and_die("Error running '%s'", args[0]);
}
示例#5
0
文件: hooklib.c 项目: RavenB/abrt
/**
 *
 * @param[out] status See `man 2 wait` for status information.
 * @return Malloc'ed string
 */
static char* exec_vp(char **args, int redirect_stderr, int exec_timeout_sec, int *status)
{
    /* Nuke everything which may make setlocale() switch to non-POSIX locale:
     * we need to avoid having gdb output in some obscure language.
     */
    static const char *const env_vec[] = {
        "LANG",
        "LC_ALL",
        "LC_COLLATE",
        "LC_CTYPE",
        "LC_MESSAGES",
        "LC_MONETARY",
        "LC_NUMERIC",
        "LC_TIME",
        /* Workaround for
         * http://sourceware.org/bugzilla/show_bug.cgi?id=9622
         * (gdb emitting ESC sequences even with -batch)
         */
        "TERM",
        NULL
    };

    int flags = EXECFLG_INPUT_NUL | EXECFLG_OUTPUT | EXECFLG_SETSID | EXECFLG_QUIET;
    if (redirect_stderr)
        flags |= EXECFLG_ERR2OUT;
    VERB1 flags &= ~EXECFLG_QUIET;

    int pipeout[2];
    pid_t child = fork_execv_on_steroids(flags, args, pipeout, (char**)env_vec, /*dir:*/ NULL, /*uid(unused):*/ 0);

    /* We use this function to run gdb and unstrip. Bugs in gdb or corrupted
     * coredumps were observed to cause gdb to enter infinite loop.
     * Therefore we have a (largish) timeout, after which we kill the child.
     */
    ndelay_on(pipeout[0]);
    int t = time(NULL); /* int is enough, no need to use time_t */
    int endtime = t + exec_timeout_sec;
    struct strbuf *buf_out = strbuf_new();
    while (1)
    {
        int timeout = endtime - t;
        if (timeout < 0)
        {
            kill(child, SIGKILL);
            strbuf_append_strf(buf_out, "\n"
                        "Timeout exceeded: %u seconds, killing %s.\n"
                        "Looks like gdb hung while generating backtrace.\n"
                        "This may be a bug in gdb. Consider submitting a bug report to gdb developers.\n"
                        "Please attach coredump from this crash to the bug report if you do.\n",
                        exec_timeout_sec, args[0]
            );
            break;
        }

        /* We don't check poll result - checking read result is enough */
        struct pollfd pfd;
        pfd.fd = pipeout[0];
        pfd.events = POLLIN;
        poll(&pfd, 1, timeout * 1000);

        char buff[1024];
        int r = read(pipeout[0], buff, sizeof(buff) - 1);
        if (r <= 0)
        {
            /* I did see EAGAIN happening here */
            if (r < 0 && errno == EAGAIN)
                goto next;
            break;
        }
        buff[r] = '\0';
        strbuf_append_str(buf_out, buff);
 next:
        t = time(NULL);
    }
    close(pipeout[0]);

    /* Prevent having zombie child process, and maybe collect status
     * (note that status == NULL is ok too) */
    safe_waitpid(child, status, 0);

    return strbuf_free_nobuf(buf_out);
}
示例#6
0
文件: hooklib.c 项目: RavenB/abrt
char *run_unstrip_n(const char *dump_dir_name, unsigned timeout_sec)
{
    int flags = EXECFLG_INPUT_NUL | EXECFLG_OUTPUT | EXECFLG_SETSID | EXECFLG_QUIET;
    VERB1 flags &= ~EXECFLG_QUIET;
    int pipeout[2];
    char* args[4];
    args[0] = (char*)"eu-unstrip";
    args[1] = xasprintf("--core=%s/"FILENAME_COREDUMP, dump_dir_name);
    args[2] = (char*)"-n";
    args[3] = NULL;
    pid_t child = fork_execv_on_steroids(flags, args, pipeout, /*env_vec:*/ NULL, /*dir:*/ NULL, /*uid(unused):*/ 0);
    free(args[1]);

    /* Bugs in unstrip or corrupted coredumps can cause it to enter infinite loop.
     * Therefore we have a (largish) timeout, after which we kill the child.
     */
    ndelay_on(pipeout[0]);
    int t = time(NULL); /* int is enough, no need to use time_t */
    int endtime = t + timeout_sec;
    struct strbuf *buf_out = strbuf_new();
    while (1)
    {
        int timeout = endtime - t;
        if (timeout < 0)
        {
            kill(child, SIGKILL);
            strbuf_free(buf_out);
            buf_out = NULL;
            break;
        }

        /* We don't check poll result - checking read result is enough */
        struct pollfd pfd;
        pfd.fd = pipeout[0];
        pfd.events = POLLIN;
        poll(&pfd, 1, timeout * 1000);

        char buff[1024];
        int r = read(pipeout[0], buff, sizeof(buff) - 1);
        if (r <= 0)
        {
            /* I did see EAGAIN happening here */
            if (r < 0 && errno == EAGAIN)
                goto next;
            break;
        }
        buff[r] = '\0';
        strbuf_append_str(buf_out, buff);
 next:
        t = time(NULL);
    }
    close(pipeout[0]);

    /* Prevent having zombie child process */
    int status;
    safe_waitpid(child, &status, 0);

    if (status != 0 || buf_out == NULL)
    {
        /* unstrip didnt exit with exit code 0, or we timed out */
        strbuf_free(buf_out);
        return NULL;
    }

    return strbuf_free_nobuf(buf_out);
}
示例#7
0
static char *run_unstrip_n(const char *dump_dir_name, unsigned timeout_sec)
{
    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        return NULL;

    char *uid_str = dd_load_text_ext(dd, FILENAME_UID, DD_FAIL_QUIETLY_ENOENT | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE);
    dd_close(dd);
    uid_t uid = -1L;
    if (uid_str)
    {
        uid = xatoi_positive(uid_str);
        free(uid_str);
        if (uid == geteuid())
        {
            uid = -1L; /* no need to setuid/gid if we are already under right uid */
        }
    }

    int flags = EXECFLG_INPUT_NUL | EXECFLG_OUTPUT | EXECFLG_SETSID | EXECFLG_QUIET;
    if (uid != (uid_t)-1L)
        flags |= EXECFLG_SETGUID;
    VERB1 flags &= ~EXECFLG_QUIET;
    int pipeout[2];
    char* args[4];
    args[0] = (char*)"eu-unstrip";
    args[1] = xasprintf("--core=%s/"FILENAME_COREDUMP, dump_dir_name);
    args[2] = (char*)"-n";
    args[3] = NULL;
    pid_t child = fork_execv_on_steroids(flags, args, pipeout, /*env_vec:*/ NULL, /*dir:*/ NULL, uid);
    free(args[1]);

    /* Bugs in unstrip or corrupted coredumps can cause it to enter infinite loop.
     * Therefore we have a (largish) timeout, after which we kill the child.
     */
    int t = time(NULL); /* int is enough, no need to use time_t */
    int endtime = t + timeout_sec;
    struct strbuf *buf_out = strbuf_new();
    while (1)
    {
        int timeout = endtime - t;
        if (timeout < 0)
        {
            kill(child, SIGKILL);
            strbuf_append_strf(buf_out, "\nTimeout exceeded: %u seconds, killing %s\n", timeout_sec, args[0]);
            break;
        }

        /* We don't check poll result - checking read result is enough */
        struct pollfd pfd;
        pfd.fd = pipeout[0];
        pfd.events = POLLIN;
        poll(&pfd, 1, timeout * 1000);

        char buff[1024];
        int r = read(pipeout[0], buff, sizeof(buff) - 1);
        if (r <= 0)
            break;
        buff[r] = '\0';
        strbuf_append_str(buf_out, buff);
        t = time(NULL);
    }
    close(pipeout[0]);

    /* Prevent having zombie child process */
    int status;
    waitpid(child, &status, 0);

    if (status != 0)
    {
        /* unstrip didnt exit with exit code 0 */
        strbuf_free(buf_out);
        return NULL;
    }

    return strbuf_free_nobuf(buf_out);
}