void dump_lxc_info(struct dump_dir *dd, const char *lxc_cmd)
{
    if (!dd_exist(dd, FILENAME_CONTAINER))
        dd_save_text(dd, FILENAME_CONTAINER, "lxc");

    char *mntnf_path = concat_path_file(dd->dd_dirname, FILENAME_MOUNTINFO);
    FILE *mntnf_file = fopen(mntnf_path, "r");
    free(mntnf_path);

    struct mountinfo mntnf;
    int r = get_mountinfo_for_mount_point(mntnf_file, &mntnf, "/");
    fclose(mntnf_file);

    if (r != 0)
    {
        error_msg("lxc processes must have re-mounted root");
        goto dump_lxc_info_cleanup;
    }

    const char *mnt_root = MOUNTINFO_ROOT(mntnf);
    const char *last_slash = strrchr(mnt_root, '/');
    if (last_slash == NULL || (strcmp("rootfs", last_slash +1) != 0))
    {
        error_msg("Invalid root path '%s'", mnt_root);
        goto dump_lxc_info_cleanup;
    }

    if (last_slash == mnt_root)
    {
        error_msg("root path misses container id: '%s'", mnt_root);
        goto dump_lxc_info_cleanup;
    }

    const char *tmp = strrchr(last_slash - 1, '/');
    if (tmp == NULL)
    {
        error_msg("root path misses first /: '%s'", mnt_root);
        goto dump_lxc_info_cleanup;
    }

    char *container_id = xstrndup(tmp + 1, (last_slash - tmp) - 1);

    dd_save_text(dd, FILENAME_CONTAINER_ID, container_id);
    dd_save_text(dd, FILENAME_CONTAINER_UUID, container_id);

    free(container_id);

    /* TODO: make a copy of 'config' */
    /* get mount point for MOUNTINFO_MOUNT_SOURCE(mntnf) + MOUNTINFO_ROOT(mntnf) */

dump_lxc_info_cleanup:
    mountinfo_destroy(&mntnf);
}
Esempio n. 2
0
/* The function expects that FILENAME_COUNT dump dir element is created by
 * abrtd after all post-create events are successfully done. Thus if
 * FILENAME_COUNT element doesn't exist abrtd can consider the dump directory
 * as unprocessed.
 *
 * Relying on content of dump directory has one problem. If a hook provides
 * FILENAME_COUNT abrtd will consider the dump directory as processed.
 */
static void mark_unprocessed_dump_dirs_not_reportable(const char *path)
{
    log_notice("Searching for unprocessed dump directories");

    DIR *dp = opendir(path);
    if (!dp)
    {
        perror_msg("Can't open directory '%s'", path);
        return;
    }

    struct dirent *dent;
    while ((dent = readdir(dp)) != NULL)
    {
        if (dot_or_dotdot(dent->d_name))
            continue; /* skip "." and ".." */

        char *full_name = concat_path_file(path, dent->d_name);

        struct stat stat_buf;
        if (stat(full_name, &stat_buf) != 0)
        {
            perror_msg("Can't access path '%s'", full_name);
            goto next_dd;
        }

        if (S_ISDIR(stat_buf.st_mode) == 0)
            /* This is expected. The dump location contains some aux files */
            goto next_dd;

        struct dump_dir *dd = dd_opendir(full_name, /*flags*/0);
        if (dd)
        {
            if (!problem_dump_dir_is_complete(dd) && !dd_exist(dd, FILENAME_NOT_REPORTABLE))
            {
                log_warning("Marking '%s' not reportable (no '"FILENAME_COUNT"' item)", full_name);

                dd_save_text(dd, FILENAME_NOT_REPORTABLE, _("The problem data are "
                            "incomplete. This usually happens when a problem "
                            "is detected while computer is shutting down or "
                            "user is logging out. In order to provide "
                            "valuable problem reports, ABRT will not allow "
                            "you to submit this problem. If you have time and "
                            "want to help the developers in their effort to "
                            "sort out this problem, please contact them directly."));

            }
            dd_close(dd);
        }

  next_dd:
        free(full_name);
    }
    closedir(dp);
}
Esempio n. 3
0
static void save_bt_to_dump_dir(const char *bt, const char *exe, const char *reason)
{
    time_t t = time(NULL);
    const char *iso_date = iso_date_string(&t);

    pid_t my_pid = getpid();

    char base[sizeof("xorg-YYYY-MM-DD-hh:mm:ss-%lu-%lu") + 2 * sizeof(long)*3];
    sprintf(base, "xorg-%s-%lu-%u", iso_date, (long)my_pid, g_bt_count);
    char *path = concat_path_file(debug_dumps_dir, base);

    struct dump_dir *dd = dd_create(path, /*fs owner*/0, DEFAULT_DUMP_DIR_MODE);
    if (dd)
    {
        dd_create_basic_files(dd, /*no uid*/(uid_t)-1L, NULL);
        dd_save_text(dd, FILENAME_ABRT_VERSION, VERSION);
        dd_save_text(dd, FILENAME_ANALYZER, "abrt-xorg");
        dd_save_text(dd, FILENAME_TYPE, "xorg");
        dd_save_text(dd, FILENAME_REASON, reason);
        dd_save_text(dd, FILENAME_BACKTRACE, bt);
        /*
         * Reporters usually need component name to file a bug.
	 * It is usually derived from executable.
         * We _guess_ X server's executable name as a last resort.
         * Better ideas?
         */
        if (!exe)
        {
            exe = "/usr/bin/X";
            if (access("/usr/bin/Xorg", X_OK) == 0)
                exe = "/usr/bin/Xorg";
        }
        dd_save_text(dd, FILENAME_EXECUTABLE, exe);
        if (!(g_opts & OPT_x))
            dd_set_no_owner(dd);
        dd_close(dd);
        notify_new_path(path);
    }

    free(path);
}
Esempio n. 4
0
/* Create a new problem directory from client session.
 * Caller must ensure that all fields in struct client
 * are properly filled.
 */
static int create_problem_dir(GHashTable *problem_info, unsigned pid)
{
    /* Exit if free space is less than 1/4 of MaxCrashReportsSize */
    if (g_settings_nMaxCrashReportsSize > 0)
    {
        if (low_free_space(g_settings_nMaxCrashReportsSize, g_settings_dump_location))
            exit(1);
    }

    /* Create temp directory with the problem data.
     * This directory is renamed to final directory name after
     * all files have been stored into it.
     */

    gchar *dir_basename = g_hash_table_lookup(problem_info, "basename");
    if (!dir_basename)
        dir_basename = g_hash_table_lookup(problem_info, FILENAME_TYPE);

    char *path = xasprintf("%s/%s-%s-%u.new",
                           g_settings_dump_location,
                           dir_basename,
                           iso_date_string(NULL),
                           pid);

    /* This item is useless, don't save it */
    g_hash_table_remove(problem_info, "basename");

    /* No need to check the path length, as all variables used are limited,
     * and dd_create() fails if the path is too long.
     */
    struct dump_dir *dd = dd_create(path, /*fs owner*/0, DEFAULT_DUMP_DIR_MODE);
    if (!dd)
    {
        error_msg_and_die("Error creating problem directory '%s'", path);
    }

    dd_create_basic_files(dd, client_uid, NULL);
    dd_save_text(dd, FILENAME_ABRT_VERSION, VERSION);

    gpointer gpkey = g_hash_table_lookup(problem_info, FILENAME_CMDLINE);
    if (!gpkey)
    {
        /* Obtain and save the command line. */
        char *cmdline = get_cmdline(pid);
        if (cmdline)
        {
            dd_save_text(dd, FILENAME_CMDLINE, cmdline);
            free(cmdline);
        }
    }

    /* Store id of the user whose application crashed. */
    char uid_str[sizeof(long) * 3 + 2];
    sprintf(uid_str, "%lu", (long)client_uid);
    dd_save_text(dd, FILENAME_UID, uid_str);

    GHashTableIter iter;
    gpointer gpvalue;
    g_hash_table_iter_init(&iter, problem_info);
    while (g_hash_table_iter_next(&iter, &gpkey, &gpvalue))
    {
        dd_save_text(dd, (gchar *) gpkey, (gchar *) gpvalue);
    }

    dd_close(dd);

    /* Not needing it anymore */
    g_hash_table_destroy(problem_info);

    /* Move the completely created problem directory
     * to final directory.
     */
    char *newpath = xstrndup(path, strlen(path) - strlen(".new"));
    if (rename(path, newpath) == 0)
        strcpy(path, newpath);
    free(newpath);

    log_notice("Saved problem directory of pid %u to '%s'", pid, path);

    /* We let the peer know that problem dir was created successfully
     * _before_ we run potentially long-running post-create.
     */
    printf("HTTP/1.1 201 Created\r\n\r\n");
    fflush(NULL);
    close(STDOUT_FILENO);
    xdup2(STDERR_FILENO, STDOUT_FILENO); /* paranoia: don't leave stdout fd closed */

    /* Trim old problem directories if necessary */
    if (g_settings_nMaxCrashReportsSize > 0)
    {
        trim_problem_dirs(g_settings_dump_location, g_settings_nMaxCrashReportsSize * (double)(1024*1024), path);
    }

    run_post_create(path);

    /* free(path); */
    exit(0);
}
Esempio n. 5
0
static int run_post_create(const char *dirname)
{
    /* If doesn't start with "g_settings_dump_location/"... */
    if (!dir_is_in_dump_location(dirname))
    {
        /* Then refuse to operate on it (someone is attacking us??) */
        error_msg("Bad problem directory name '%s', should start with: '%s'", dirname, g_settings_dump_location);
        return 400; /* Bad Request */
    }
    if (!dir_has_correct_permissions(dirname, DD_PERM_EVENTS))
    {
        error_msg("Problem directory '%s' has wrong owner or group", dirname);
        return 400; /*  */
    }
    /* Check completness */
    {
        struct dump_dir *dd = dd_opendir(dirname, DD_OPEN_READONLY);

        char *provoker = NULL;
        const bool event_dir = dd && problem_dump_dir_was_provoked_by_abrt_event(dd, &provoker);
        if (event_dir)
        {
            if (g_settings_debug_level == 0)
            {
                error_msg("Removing problem provoked by ABRT(pid:%s): '%s'", provoker, dirname);
                dd_delete(dd);
            }
            else
            {
                char *dumpdir = NULL;
                char *event   = NULL;
                char *reason  = NULL;
                char *cmdline = NULL;

                /* Ignore errors */
                dd_get_env_variable(dd, "DUMP_DIR", &dumpdir);
                dd_get_env_variable(dd, "EVENT",    &event);
                reason  = dd_load_text(dd, FILENAME_REASON);
                cmdline = dd_load_text(dd, FILENAME_CMDLINE);

                error_msg("ABRT_SERVER_PID=%s;DUMP_DIR='%s';EVENT='%s';REASON='%s';CMDLINE='%s'",
                           provoker, dumpdir, event, reason, cmdline);

            }

            free(provoker);
            return 400;
        }

        const bool complete = dd && problem_dump_dir_is_complete(dd);
        dd_close(dd);
        if (complete)
        {
            error_msg("Problem directory '%s' has already been processed", dirname);
            return 403;
        }
    }

    int child_stdout_fd;
    int child_pid = spawn_event_handler_child(dirname, "post-create", &child_stdout_fd);

    char *dup_of_dir = NULL;
    struct strbuf *cmd_output = strbuf_new();

    bool child_is_post_create = 1; /* else it is a notify child */

 read_child_output:
    //log("Reading from event fd %d", child_stdout_fd);

    /* Read streamed data and split lines */
    for (;;)
    {
        char buf[250]; /* usually we get one line, no need to have big buf */
        errno = 0;
        int r = safe_read(child_stdout_fd, buf, sizeof(buf) - 1);
        if (r <= 0)
            break;
        buf[r] = '\0';

        /* split lines in the current buffer */
        char *raw = buf;
        char *newline;
        while ((newline = strchr(raw, '\n')) != NULL)
        {
            *newline = '\0';
            strbuf_append_str(cmd_output, raw);
            char *msg = cmd_output->buf;

            if (child_is_post_create
             && prefixcmp(msg, "DUP_OF_DIR: ") == 0
            ) {
                free(dup_of_dir);
                dup_of_dir = xstrdup(msg + strlen("DUP_OF_DIR: "));
            }
            else
                log("%s", msg);

            strbuf_clear(cmd_output);
            /* jump to next line */
            raw = newline + 1;
        }

        /* beginning of next line. the line continues by next read */
        strbuf_append_str(cmd_output, raw);
    }

    /* EOF/error */

    /* Wait for child to actually exit, collect status */
    int status = 0;
    if (safe_waitpid(child_pid, &status, 0) <= 0)
    /* should not happen */
        perror_msg("waitpid(%d)", child_pid);

    /* If it was a "notify[-dup]" event, then we're done */
    if (!child_is_post_create)
        goto ret;

    /* exit 0 means "this is a good, non-dup dir" */
    /* exit with 1 + "DUP_OF_DIR: dir" string => dup */
    if (status != 0)
    {
        if (WIFSIGNALED(status))
        {
            log("'post-create' on '%s' killed by signal %d",
                            dirname, WTERMSIG(status));
            goto delete_bad_dir;
        }
        /* else: it is WIFEXITED(status) */
        if (!dup_of_dir)
        {
            log("'post-create' on '%s' exited with %d",
                            dirname, WEXITSTATUS(status));
            goto delete_bad_dir;
        }
    }

    const char *work_dir = (dup_of_dir ? dup_of_dir : dirname);

    /* Load problem_data (from the *first dir* if this one is a dup) */
    struct dump_dir *dd = dd_opendir(work_dir, /*flags:*/ 0);
    if (!dd)
        /* dd_opendir already emitted error msg */
        goto delete_bad_dir;

    /* Update count */
    char *count_str = dd_load_text_ext(dd, FILENAME_COUNT, DD_FAIL_QUIETLY_ENOENT);
    unsigned long count = strtoul(count_str, NULL, 10);

    /* Don't increase crash count if we are working with newly uploaded
     * directory (remote crash) which already has its crash count set.
     */
    if ((status != 0 && dup_of_dir) || count == 0)
    {
        count++;
        char new_count_str[sizeof(long)*3 + 2];
        sprintf(new_count_str, "%lu", count);
        dd_save_text(dd, FILENAME_COUNT, new_count_str);

        /* This condition can be simplified to either
         * (status * != 0 && * dup_of_dir) or (count == 1). But the
         * chosen form is much more reliable and safe. We must not call
         * dd_opendir() to locked dd otherwise we go into a deadlock.
         */
        if (strcmp(dd->dd_dirname, dirname) != 0)
        {
            /* Update the last occurrence file by the time file of the new problem */
            struct dump_dir *new_dd = dd_opendir(dirname, DD_OPEN_READONLY);
            char *last_ocr = NULL;
            if (new_dd)
            {
                /* TIME must exists in a valid dump directory but we don't want to die
                 * due to broken duplicated dump directory */
                last_ocr = dd_load_text_ext(new_dd, FILENAME_TIME,
                            DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE | DD_FAIL_QUIETLY_ENOENT);
                dd_close(new_dd);
            }
            else
            {   /* dd_opendir() already produced a message with good information about failure */
                error_msg("Can't read the last occurrence file from the new dump directory.");
            }

            if (!last_ocr)
            {   /* the new dump directory may lie in the dump location for some time */
                log("Using current time for the last occurrence file which may be incorrect.");
                time_t t = time(NULL);
                last_ocr = xasprintf("%lu", (long)t);
            }

            dd_save_text(dd, FILENAME_LAST_OCCURRENCE, last_ocr);

            free(last_ocr);
        }
    }

    /* Reset mode/uig/gid to correct values for all files created by event run */
    dd_sanitize_mode_and_owner(dd);

    dd_close(dd);

    if (!dup_of_dir)
        log_notice("New problem directory %s, processing", work_dir);
    else
    {
        log_warning("Deleting problem directory %s (dup of %s)",
                    strrchr(dirname, '/') + 1,
                    strrchr(dup_of_dir, '/') + 1);
        delete_dump_dir(dirname);
    }

    /* Run "notify[-dup]" event */
    int fd;
    child_pid = spawn_event_handler_child(
                work_dir,
                (dup_of_dir ? "notify-dup" : "notify"),
                &fd
    );
    //log("Started notify, fd %d -> %d", fd, child_stdout_fd);
    xmove_fd(fd, child_stdout_fd);
    child_is_post_create = 0;
    strbuf_clear(cmd_output);
    free(dup_of_dir);
    dup_of_dir = NULL;
    goto read_child_output;

 delete_bad_dir:
    log_warning("Deleting problem directory '%s'", dirname);
    delete_dump_dir(dirname);

 ret:
    strbuf_free(cmd_output);
    free(dup_of_dir);
    close(child_stdout_fd);
    return 0;
}
Esempio n. 6
0
int main(int argc, char **argv)
{
    /* I18n */
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    abrt_init(argv);

    const char *dump_dir_name = ".";

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "& [-v] -d DIR\n"
        "\n"
        "Calculates and saves UUID of coredump in problem directory DIR"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
    };
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING('d', NULL, &dump_dir_name, "DIR", _("Problem directory")),
        OPT_END()
    };
    /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    char *unstrip_n_output = NULL;
    char *coredump_path = xasprintf("%s/"FILENAME_COREDUMP, dump_dir_name);
    if (access(coredump_path, R_OK) == 0)
        unstrip_n_output = run_unstrip_n(dump_dir_name, /*timeout_sec:*/ 30);

    free(coredump_path);

    if (unstrip_n_output)
    {
        /* Run unstrip -n and trim its output, leaving only sizes and build ids */
        /* modifies unstrip_n_output in-place: */
        trim_unstrip_output(unstrip_n_output, unstrip_n_output);
    }
    else
    {
        /* bad dump_dir_name, can't run unstrip, etc...
         * or maybe missing coredump - try generating it from core_backtrace
         */

        unstrip_n_output = build_ids_from_core_backtrace(dump_dir_name);
    }

    /* Hash package + executable + unstrip_n_output and save it as UUID */

    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        return 1;

    char *executable = dd_load_text(dd, FILENAME_EXECUTABLE);
    /* FILENAME_PACKAGE may be missing if ProcessUnpackaged = yes... */
    char *package = dd_load_text_ext(dd, FILENAME_PACKAGE, DD_FAIL_QUIETLY_ENOENT);
    /* Package variable has "firefox-3.5.6-1.fc11[.1]" format */
    /* Remove distro suffix and maybe least significant version number */
    char *p = package;
    while (*p)
    {
        if (*p == '.' && (p[1] < '0' || p[1] > '9'))
        {
            /* We found "XXXX.nondigitXXXX", trim this part */
            *p = '\0';
            break;
        }
        p++;
    }
    char *first_dot = strchr(package, '.');
    if (first_dot)
    {
        char *last_dot = strrchr(first_dot, '.');
        if (last_dot != first_dot)
        {
            /* There are more than one dot: "1.2.3"
             * Strip last part, we don't want to distinquish crashes
             * in packages which differ only by minor release number.
             */
            *last_dot = '\0';
        }
    }

    char *string_to_hash = xasprintf("%s%s%s", package, executable, unstrip_n_output);
    /*free(package);*/
    /*free(executable);*/
    /*free(unstrip_n_output);*/

    log_debug("String to hash: %s", string_to_hash);

    char hash_str[SHA1_RESULT_LEN*2 + 1];
    str_to_sha1str(hash_str, string_to_hash);

    dd_save_text(dd, FILENAME_UUID, hash_str);
    dd_close(dd);

    return 0;
}
Esempio n. 7
0
struct dump_dir *create_dump_dir_from_problem_data(problem_data_t *problem_data, const char *base_dir_name)
{
    INITIALIZE_LIBREPORT();

    char *type = problem_data_get_content_or_NULL(problem_data, FILENAME_ANALYZER);

    if (!type)
    {
        error_msg(_("Missing required item: '%s'"), FILENAME_ANALYZER);
        return NULL;
    }

    uid_t uid = (uid_t)-1L;
    char *uid_str = problem_data_get_content_or_NULL(problem_data, FILENAME_UID);

    if (uid_str)
    {
        char *endptr;
        errno = 0;
        long val = strtol(uid_str, &endptr, 10);

        if (errno != 0 || endptr == uid_str || *endptr != '\0' || INT_MAX < val)
        {
            error_msg(_("uid value is not valid: '%s'"), uid_str);
            return NULL;
        }

        uid = (uid_t)val;
    }

    struct timeval tv;
    if (gettimeofday(&tv, NULL) < 0)
    {
        perror_msg("gettimeofday()");
        return NULL;
    }

    char *problem_id = xasprintf("%s-%s.%ld-%lu"NEW_PD_SUFFIX, type, iso_date_string(&(tv.tv_sec)), (long)tv.tv_usec, (long)getpid());

    log_info("Saving to %s/%s with uid %d", base_dir_name, problem_id, uid);

    struct dump_dir *dd;
    if (base_dir_name)
        dd = try_dd_create(base_dir_name, problem_id, uid);
    else
    {
        /* Try /var/run/abrt */
        dd = try_dd_create(LOCALSTATEDIR"/run/abrt", problem_id, uid);
        /* Try $HOME/tmp */
        if (!dd)
        {
            char *home = getenv("HOME");
            if (home && home[0])
            {
                home = concat_path_file(home, "tmp");
                /*mkdir(home, 0777); - do we want this? */
                dd = try_dd_create(home, problem_id, uid);
                free(home);
            }
        }
//TODO: try user's home dir obtained by getpwuid(getuid())?
        /* Try system temporary directory */
        if (!dd)
            dd = try_dd_create(LARGE_DATA_TMP_DIR, problem_id, uid);
    }

    if (!dd) /* try_dd_create() already emitted the error message */
        goto ret;

    GHashTableIter iter;
    char *name;
    struct problem_item *value;
    g_hash_table_iter_init(&iter, problem_data);
    while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value))
    {
        if (value->flags & CD_FLAG_BIN)
        {
            char *dest = concat_path_file(dd->dd_dirname, name);
            log_info("copying '%s' to '%s'", value->content, dest);
            off_t copied = copy_file(value->content, dest, DEFAULT_DUMP_DIR_MODE | S_IROTH);
            if (copied < 0)
                error_msg("Can't copy %s to %s", value->content, dest);
            else
                log_info("copied %li bytes", (unsigned long)copied);
            free(dest);

            continue;
        }

        /* only files should contain '/' and those are handled earlier */
        if (name[0] == '.' || strchr(name, '/'))
        {
            error_msg("Problem data field name contains disallowed chars: '%s'", name);
            continue;
        }

        dd_save_text(dd, name, value->content);
    }

    /* need to create basic files AFTER we save the pd to dump_dir
     * otherwise we can't skip already created files like in case when
     * reporting from anaconda where we can't read /etc/{system,redhat}-release
     * and os_release is taken from anaconda
     */
    dd_create_basic_files(dd, uid, NULL);

    problem_id[strlen(problem_id) - strlen(NEW_PD_SUFFIX)] = '\0';
    char* new_path = concat_path_file(base_dir_name, problem_id);
    log_info("Renaming from '%s' to '%s'", dd->dd_dirname, new_path);
    dd_rename(dd, new_path);

 ret:
    free(problem_id);
    return dd;
}
Esempio n. 8
0
/* returns number of errors */
unsigned abrt_oops_create_dump_dirs(GList *oops_list, const char *dump_location, const char *analyzer, int flags)
{
    const int oops_cnt = g_list_length(oops_list);
    unsigned countdown = ABRT_OOPS_MAX_DUMPED_COUNT; /* do not report hundreds of oopses */

    log_notice("Saving %u oopses as problem dirs", oops_cnt >= countdown ? countdown : oops_cnt);

    char *cmdline_str = xmalloc_fopen_fgetline_fclose("/proc/cmdline");
    char *fips_enabled = xmalloc_fopen_fgetline_fclose("/proc/sys/crypto/fips_enabled");
    char *proc_modules = xmalloc_open_read_close("/proc/modules", /*maxsize:*/ NULL);
    char *suspend_stats = xmalloc_open_read_close("/sys/kernel/debug/suspend_stats", /*maxsize:*/ NULL);

    time_t t = time(NULL);
    const char *iso_date = iso_date_string(&t);
    /* dump should be readable by all if we're run with -x */
    uid_t my_euid = (uid_t)-1L;
    mode_t mode = DEFAULT_DUMP_DIR_MODE | S_IROTH;
    /* and readable only for the owner otherwise */
    if (!(flags & ABRT_OOPS_WORLD_READABLE))
    {
        mode = DEFAULT_DUMP_DIR_MODE;
        my_euid = geteuid();
    }

    pid_t my_pid = getpid();
    unsigned idx = 0;
    unsigned errors = 0;
    while (idx < oops_cnt)
    {
        char base[sizeof("oops-YYYY-MM-DD-hh:mm:ss-%lu-%lu") + 2 * sizeof(long)*3];
        sprintf(base, "oops-%s-%lu-%lu", iso_date, (long)my_pid, (long)idx);
        char *path = concat_path_file(dump_location, base);

        struct dump_dir *dd = dd_create(path, /*uid:*/ my_euid, mode);
        if (dd)
        {
            dd_create_basic_files(dd, /*uid:*/ my_euid, NULL);
            abrt_oops_save_data_in_dump_dir(dd, (char*)g_list_nth_data(oops_list, idx++), proc_modules);
            dd_save_text(dd, FILENAME_ABRT_VERSION, VERSION);
            dd_save_text(dd, FILENAME_ANALYZER, "abrt-oops");
            dd_save_text(dd, FILENAME_TYPE, "Kerneloops");
            if (cmdline_str)
                dd_save_text(dd, FILENAME_CMDLINE, cmdline_str);
            if (proc_modules)
                dd_save_text(dd, "proc_modules", proc_modules);
            if (fips_enabled && strcmp(fips_enabled, "0") != 0)
                dd_save_text(dd, "fips_enabled", fips_enabled);
            if (suspend_stats)
                dd_save_text(dd, "suspend_stats", suspend_stats);
            dd_close(dd);
            notify_new_path(path);
        }
        else
            errors++;

        free(path);

        if (--countdown == 0)
            break;

        if (dd && (flags & ABRT_OOPS_THROTTLE_CREATION))
            if (abrt_oops_signaled_sleep(1) > 0)
                break;
    }

    free(cmdline_str);
    free(proc_modules);
    free(fips_enabled);
    free(suspend_stats);

    return errors;
}
void dump_docker_info(struct dump_dir *dd, const char *root_dir)
{
    if (!dd_exist(dd, FILENAME_CONTAINER))
        dd_save_text(dd, FILENAME_CONTAINER, "docker");

    json_object *json = NULL;
    char *mntnf_path = concat_path_file(dd->dd_dirname, FILENAME_MOUNTINFO);
    FILE *mntnf_file = fopen(mntnf_path, "r");
    free(mntnf_path);

    struct mount_point {
        const char *name;
        enum mountinfo_fields {
            MOUNTINFO_ROOT,
            MOUNTINFO_SOURCE,
        } field;
    } mount_points[] = {
        { "/sys/fs/cgroup/memory", MOUNTINFO_ROOT },
        { "/",                     MOUNTINFO_SOURCE },
    };

    char *container_id = NULL;
    char *output = NULL;

    /* initialized to 0 because we call mountinfo_destroy below */
    struct mountinfo mntnf = {0};

    for (size_t i = 0; i < ARRAY_SIZE(mount_points); ++i)
    {
        log_debug("Parsing container ID from mount point '%s'", mount_points[i].name);

        rewind(mntnf_file);

        /* get_mountinfo_for_mount_point() re-initializes &mntnf */
        mountinfo_destroy(&mntnf);
        int r = get_mountinfo_for_mount_point(mntnf_file, &mntnf, mount_points[i].name);

        if (r != 0)
        {
            log_debug("Mount poin not found");
            continue;
        }

        const char *mnt_info = NULL;
        switch(mount_points[i].field)
        {
            case MOUNTINFO_ROOT:
                mnt_info = MOUNTINFO_ROOT(mntnf);
                break;
            case MOUNTINFO_SOURCE:
                mnt_info = MOUNTINFO_MOUNT_SOURCE(mntnf);
                break;
            default:
                error_msg("BUG: forgotten MOUNTINFO field type");
                abort();
        }
        const char *last = strrchr(mnt_info, '/');
        if (last == NULL || strncmp("/docker-", last, strlen("/docker-")) != 0)
        {
            log_debug("Mounted source is not a docker mount source: '%s'", mnt_info);
            continue;
        }

        last = strrchr(last, '-');
        if (last == NULL)
        {
            log_debug("The docker mount point has unknown format");
            continue;
        }

        ++last;

        /* Why we copy only 12 bytes here?
         * Because only the first 12 characters are used by docker as ID of the
         * container. */
        container_id = xstrndup(last, 12);
        if (strlen(container_id) != 12)
        {
            log_debug("Failed to get container ID");
            continue;
        }

        char *docker_inspect_cmdline = NULL;
        if (root_dir != NULL)
            docker_inspect_cmdline = xasprintf("chroot %s /bin/sh -c \"docker inspect %s\"", root_dir, container_id);
        else
            docker_inspect_cmdline = xasprintf("docker inspect %s", container_id);

        log_debug("Executing: '%s'", docker_inspect_cmdline);
        output = run_in_shell_and_save_output(0, docker_inspect_cmdline, "/", NULL);

        free(docker_inspect_cmdline);

        if (output == NULL || strcmp(output, "[]\n") == 0)
        {
            log_debug("Unsupported container ID: '%s'", container_id);

            free(container_id);
            container_id = NULL;

            free(output);
            output = NULL;

            continue;
        }

        break;
    }
    fclose(mntnf_file);

    if (container_id == NULL)
    {
        error_msg("Could not inspect the container");
        goto dump_docker_info_cleanup;
    }

    dd_save_text(dd, FILENAME_CONTAINER_ID, container_id);
    dd_save_text(dd, FILENAME_DOCKER_INSPECT, output);

    json = json_tokener_parse(output);
    free(output);

    if (is_error(json))
    {
        error_msg("Unable parse response from docker");
        goto dump_docker_info_cleanup;
    }

    json_object *container = json_object_array_get_idx(json, 0);
    if (container == NULL)
    {
        error_msg("docker does not contain array of containers");
        goto dump_docker_info_cleanup;
    }

    json_object *config = NULL;
    if (!json_object_object_get_ex(container, "Config", &config))
    {
        error_msg("container does not have 'Config' member");
        goto dump_docker_info_cleanup;
    }

    json_object *image = NULL;
    if (!json_object_object_get_ex(config, "Image", &image))
    {
        error_msg("Config does not have 'Image' member");
        goto dump_docker_info_cleanup;
    }

    char *name = strtrimch(xstrdup(json_object_to_json_string(image)), '"');
    dd_save_text(dd, FILENAME_CONTAINER_IMAGE, name);
    free(name);

dump_docker_info_cleanup:
    if (json != NULL)
        json_object_put(json);

    mountinfo_destroy(&mntnf);

    return;
}
Esempio n. 10
0
int main(int argc, char **argv)
{
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    abrt_init(argv);

    struct ureport_server_config config = {
        .ur_url = SERVER_URL,
        .ur_ssl_verify = true,
    };

    bool insecure = !config.ur_ssl_verify;
    bool attach_reported_to = false;
    const char *dump_dir_path = ".";
    const char *ureport_hash = NULL;
    int rhbz_bug = -1;
    struct dump_dir *dd = NULL;
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT__DUMP_DIR(&dump_dir_path),
        OPT_STRING('u', "url", &config.ur_url, "URL", _("Specify server URL")),
        OPT_BOOL('k', "insecure", &insecure,
                          _("Allow insecure connection to ureport server")),
        OPT_STRING('a', "attach", &ureport_hash, "BTHASH",
                          _("bthash of uReport to attach")),
        OPT_INTEGER('b', "bug-id", &rhbz_bug,
                          _("Attach RHBZ bug (requires -a)")),
        OPT_BOOL('r', "attach-reported-to", &attach_reported_to,
                          _("Attach contents of reported_to")),
        OPT_END(),
    };

    const char *program_usage_string = _(
        "& [-v] [-u URL] [-k] [-a bthash -b bug-id] [-r] [-d DIR]\n"
        "\n"
        "Upload micro report or add an attachment to a micro report"
    );

    parse_opts(argc, argv, program_options, program_usage_string);

    config.ur_ssl_verify = !insecure;
    load_ureport_server_config(&config);
    post_state_t *post_state = NULL;

    /* we either need both -b & -a or none of them */
    if (ureport_hash && rhbz_bug > 0)
        return perform_attach(&config, ureport_hash, rhbz_bug);
    if (ureport_hash && rhbz_bug <= 0)
        error_msg_and_die(_("You need to specify bug ID to attach."));
    if (!ureport_hash && rhbz_bug > 0)
        error_msg_and_die(_("You need to specify bthash of the uReport to attach."));

    /* -r */
    if (attach_reported_to)
    {
        dd = dd_opendir(dump_dir_path, DD_OPEN_READONLY);
        if (!dd)
            xfunc_die();

        report_result_t *ureport_result = find_in_reported_to(dd, "uReport");
        report_result_t *bz_result = find_in_reported_to(dd, "Bugzilla");

        dd_close(dd);

        if (!ureport_result || !ureport_result->bthash)
            error_msg_and_die(_("This problem does not have an uReport assigned."));

        if (!bz_result || !bz_result->url)
            error_msg_and_die(_("This problem has not been reported to Bugzilla."));

        char *bthash = xstrdup(ureport_result->bthash);
        free_report_result(ureport_result);

        char *bugid_ptr = strstr(bz_result->url, "show_bug.cgi?id=");
        if (!bugid_ptr)
            error_msg_and_die(_("Unable to find bug ID in bugzilla URL '%s'"), bz_result->url);
        bugid_ptr += strlen("show_bug.cgi?id=");
        int bugid;
        /* we're just reading int, sscanf works fine */
        if (sscanf(bugid_ptr, "%d", &bugid) != 1)
            error_msg_and_die(_("Unable to parse bug ID from bugzilla URL '%s'"), bz_result->url);

        free_report_result(bz_result);

        const int result = perform_attach(&config, bthash, bugid);

        free(bthash);
        return result;
    }

    /* -b, -a nor -r were specified - upload uReport from dump_dir */
    int ret = 1; /* "failure" (for now) */
    char *dest_url = concat_path_file(config.ur_url, REPORT_URL_SFX);
    config.ur_url = dest_url;

    char *json_ureport = ureport_from_dump_dir(dump_dir_path);
    if (!json_ureport)
    {
        error_msg(_("Not uploading an empty uReport"));
        goto format_err;
    }

    post_state = post_ureport(json_ureport, &config);
    free(json_ureport);

    if (!post_state)
    {
        error_msg(_("Failed on submitting the problem"));
        goto format_err;
    }

    struct ureport_server_response *response = get_server_response(post_state, &config);

    if (!response)
        goto format_err;

    if (!response->is_error)
    {
        VERB1 log("is known: %s", response->value);
        ret = 0; /* "success" */

        dd = dd_opendir(dump_dir_path, /* flags */ 0);
        if (!dd)
            xfunc_die();

        if (response->bthash)
        {
            char *msg = xasprintf("uReport: BTHASH=%s", response->bthash);
            add_reported_to(dd, msg);
            free(msg);
        }

        if (response->reported_to_list)
        {
            for (GList *e = response->reported_to_list; e; e = g_list_next(e))
                add_reported_to(dd, e->data);
        }

        if (response->solution)
            dd_save_text(dd, FILENAME_NOT_REPORTABLE, response->solution);

        dd_close(dd);

        /* If a reported problem is not known then emit NEEDMORE */
        if (strcmp("true", response->value) == 0)
        {
            log(_("This problem has already been reported."));
            if (response->message)
                log(response->message);

            ret = EXIT_STOP_EVENT_RUN;
        }
    }
    else
    {
        error_msg(_("Server responded with an error: '%s'"), response->value);
    }

    free_ureport_server_response(response);

format_err:
    free_post_state(post_state);
    free(dest_url);

    return ret;
}
Esempio n. 11
0
int main(int argc, char **argv)
{
    abrt_init(argv);

    const char *dump_dir_name = ".";

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "\b [-v] -d DIR\n"
        "\n"
        "Calculates and saves UUID of coredump in dump directory DIR"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
    };
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING('d', NULL, &dump_dir_name, "DIR", _("Dump directory")),
        OPT_END()
    };
    /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    /* Run unstrip -n and trim its output, leaving only sizes and build ids */

    char *unstrip_n_output = run_unstrip_n(dump_dir_name, /*timeout_sec:*/ 30);
    if (!unstrip_n_output)
        return 1; /* bad dump_dir_name, can't run unstrip, etc... */
    /* modifies unstrip_n_output in-place: */
    trim_unstrip_output(unstrip_n_output, unstrip_n_output);

    /* Hash package + executable + unstrip_n_output and save it as UUID */

    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        return 1;

    char *executable = dd_load_text(dd, FILENAME_EXECUTABLE);
    char *package = dd_load_text(dd, FILENAME_PACKAGE);
    /* Package variable has "firefox-3.5.6-1.fc11[.1]" format */
    /* Remove distro suffix and maybe least significant version number */
    char *p = package;
    while (*p)
    {
        if (*p == '.' && (p[1] < '0' || p[1] > '9'))
        {
            /* We found "XXXX.nondigitXXXX", trim this part */
            *p = '\0';
            break;
        }
        p++;
    }
    char *first_dot = strchr(package, '.');
    if (first_dot)
    {
        char *last_dot = strrchr(first_dot, '.');
        if (last_dot != first_dot)
        {
            /* There are more than one dot: "1.2.3"
             * Strip last part, we don't want to distinquish crashes
             * in packages which differ only by minor release number.
             */
            *last_dot = '\0';
        }
    }

    char *string_to_hash = xasprintf("%s%s%s", package, executable, unstrip_n_output);
    /*free(package);*/
    /*free(executable);*/
    /*free(unstrip_n_output);*/

    char hash_str[SHA1_RESULT_LEN*2 + 1];
    create_hash(hash_str, string_to_hash);

    dd_save_text(dd, FILENAME_UUID, hash_str);
    dd_close(dd);

    return 0;
}
static int SavePackageDescriptionToDebugDump(const char *dump_dir_name, const char *chroot)
{
    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        return 1;

    char *type = dd_load_text(dd, FILENAME_TYPE);
    if (!strcmp(type, "Kerneloops"))
    {
        dd_save_text(dd, FILENAME_PACKAGE, "kernel");
        dd_save_text(dd, FILENAME_COMPONENT, "kernel");
        dd_close(dd);
        free(type);
        return 0;
    }
    free(type);

    char *cmdline = NULL;
    char *executable = NULL;
    char *rootdir = NULL;
    char *package_short_name = NULL;
    struct pkg_envra *pkg_name = NULL;
    char *component = NULL;
    int error = 1;
    /* note: "goto ret" statements below free all the above variables,
     * but they don't dd_close(dd) */

    cmdline = dd_load_text_ext(dd, FILENAME_CMDLINE, DD_FAIL_QUIETLY_ENOENT);
    executable = dd_load_text(dd, FILENAME_EXECUTABLE);
    if (chroot == NULL)
        chroot = rootdir = dd_load_text_ext(dd, FILENAME_ROOTDIR,
                               DD_FAIL_QUIETLY_ENOENT | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE);

    /* Close dd while we query package database. It can take some time,
     * don't want to keep dd locked longer than necessary */
    dd_close(dd);

    if (is_path_blacklisted(executable))
    {
        log("Blacklisted executable '%s'", executable);
        goto ret; /* return 1 (failure) */
    }

    pkg_name = rpm_get_package_nvr(executable, chroot);
    if (!pkg_name)
    {
        if (settings_bProcessUnpackaged)
        {
            log_info("Crash in unpackaged executable '%s', "
                      "proceeding without packaging information", executable);
            goto ret0; /* no error */
        }
        log("Executable '%s' doesn't belong to any package"
		" and ProcessUnpackaged is set to 'no'",
		executable
        );
        goto ret; /* return 1 (failure) */
    }

    /* Check well-known interpreter names */
    const char *basename = strrchr(executable, '/');
    if (basename)
        basename++;
    else
        basename = executable;

    /* if basename is known interpreter, we want to blame the running script
     * not the interpreter
     */
    if (g_list_find_custom(settings_Interpreters, basename, (GCompareFunc)g_strcmp0))
    {
        struct pkg_envra *script_pkg = get_script_name(cmdline, &executable, chroot);
        /* executable may have changed, check it again */
        if (is_path_blacklisted(executable))
        {
            log("Blacklisted executable '%s'", executable);
            goto ret; /* return 1 (failure) */
        }
        if (!script_pkg)
        {
            /* Script name is not absolute, or it doesn't
             * belong to any installed package.
             */
            if (!settings_bProcessUnpackaged)
            {
                log("Interpreter crashed, but no packaged script detected: '%s'", cmdline);
                goto ret; /* return 1 (failure) */
            }

            /* Unpackaged script, but the settings says we want to keep it.
             * BZ plugin wont allow to report this anyway, because component
             * is missing, so there is no reason to mark it as not_reportable.
             * Someone might want to use abrt to report it using ftp.
             */
            goto ret0;
        }

        free_pkg_envra(pkg_name);
        pkg_name = script_pkg;
    }

    package_short_name = xasprintf("%s", pkg_name->p_name);
    log_info("Package:'%s' short:'%s'", pkg_name->p_nvr, package_short_name);


    if (g_list_find_custom(settings_setBlackListedPkgs, package_short_name, (GCompareFunc)g_strcmp0))
    {
        log("Blacklisted package '%s'", package_short_name);
        goto ret; /* return 1 (failure) */
    }

    if (settings_bOpenGPGCheck)
    {
        if (!rpm_chk_fingerprint(package_short_name))
        {
            log("Package '%s' isn't signed with proper key", package_short_name);
            goto ret; /* return 1 (failure) */
        }
        /* We used to also check the integrity of the executable here:
         *  if (!CheckHash(package_short_name.c_str(), executable)) BOOM();
         * Checking the MD5 sum requires to run prelink to "un-prelink" the
         * binaries - this is considered potential security risk so we don't
         * do it now, until we find some non-intrusive way.
         */
    }

    component = rpm_get_component(executable, chroot);

    dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        goto ret; /* return 1 (failure) */

    if (pkg_name)
    {
        dd_save_text(dd, FILENAME_PACKAGE, pkg_name->p_nvr);
        dd_save_text(dd, FILENAME_PKG_EPOCH, pkg_name->p_epoch);
        dd_save_text(dd, FILENAME_PKG_NAME, pkg_name->p_name);
        dd_save_text(dd, FILENAME_PKG_VERSION, pkg_name->p_version);
        dd_save_text(dd, FILENAME_PKG_RELEASE, pkg_name->p_release);
        dd_save_text(dd, FILENAME_PKG_ARCH, pkg_name->p_arch);
    }

    if (component)
        dd_save_text(dd, FILENAME_COMPONENT, component);

    dd_close(dd);

 ret0:
    error = 0;
 ret:
    free(cmdline);
    free(executable);
    free(rootdir);
    free(package_short_name);
    free_pkg_envra(pkg_name);
    free(component);

    return error;
}
Esempio n. 13
0
int main(int argc, char **argv)
{
    /* I18n */
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    abrt_init(argv);

    char *i_opt = NULL;

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "& [options] -d DIR\n"
        "\n"
        "Analyzes coredump in problem directory DIR, generates and saves backtrace"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
        OPT_i = 1 << 2,
        OPT_t = 1 << 3,
    };
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING( 'd', NULL, &dump_dir_name   , "DIR"           , _("Problem directory")),
        OPT_STRING( 'i', NULL, &i_opt           , "DIR1[:DIR2]...", _("Additional debuginfo directories")),
        OPT_INTEGER('t', NULL, &exec_timeout_sec,                   _("Kill gdb if it runs for more than NUM seconds")),
        OPT_END()
    };
    /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    map_string_t *settings = new_map_string();
    if (!load_abrt_plugin_conf_file(CCPP_CONF, settings))
        error_msg("Can't load '%s'", CCPP_CONF);

    const char *value = get_map_string_item_or_NULL(settings, "DebuginfoLocation");
    char *debuginfo_location;
    if (value)
        debuginfo_location = xstrdup(value);
    else
        debuginfo_location = xstrdup(LOCALSTATEDIR"/cache/abrt-di");

    free_map_string(settings);
    char *debuginfo_dirs = NULL;
    if (i_opt)
        debuginfo_dirs = xasprintf("%s:%s", debuginfo_location, i_opt);

    /* Create gdb backtrace */
    char *backtrace = get_backtrace(dump_dir_name, exec_timeout_sec,
            (debuginfo_dirs) ? debuginfo_dirs : debuginfo_location);
    free(debuginfo_location);
    if (!backtrace)
    {
        backtrace = xstrdup("");
        log_warning("get_backtrace() returns NULL, broken core/gdb?");
    }
    free(debuginfo_dirs);
    free_abrt_conf_data();

    /* Store gdb backtrace */

    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        return 1;
    dd_save_text(dd, FILENAME_BACKTRACE, backtrace);
    dd_close(dd);

    /* Don't be completely silent. gdb run takes a few seconds,
     * it is useful to let user know it (maybe) worked.
     */
    log_warning(_("Backtrace is generated and saved, %u bytes"), (int)strlen(backtrace));
    free(backtrace);

    return 0;
}
Esempio n. 14
0
mw_result_t LoadDebugDump(const char *dump_dir_name, problem_data_t **problem_data)
{
    mw_result_t res;

    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        return MW_ERROR;
    struct cdump_state state;
    state.uid = dd_load_text(dd, FILENAME_UID);
    state.uuid = NULL;
    state.crash_dump_dup_name = NULL;
    char *analyzer = dd_load_text(dd, FILENAME_ANALYZER);
    dd_close(dd);

    res = MW_ERROR;

    /* Run post-create event handler(s) */
    struct run_event_state *run_state = new_run_event_state();
    run_state->post_run_callback = is_crash_a_dup;
    run_state->post_run_param = &state;
    run_state->logging_callback = do_log;
    int r = run_event_on_dir_name(run_state, dump_dir_name, "post-create");
    free_run_event_state(run_state);

//TODO: consider this case:
// new dump is created, post-create detects that it is a dup,
// but then FillCrashInfo(dup_name) *FAILS*.
// In this case, we later delete damaged dup_name (right?)
// but new dump never gets its FILENAME_COUNT set!

    /* Is crash a dup? (In this case, is_crash_a_dup() should have
     * aborted "post-create" event processing as soon as it saw uuid
     * and determined that there is another crash with same uuid.
     * In this case it sets state.crash_dump_dup_name)
     */
    if (!state.crash_dump_dup_name)
    {
        /* No. Was there error on one of processing steps in run_event? */
        if (r != 0)
            goto ret; /* yes */

        /* Was uuid created after all? (In this case, is_crash_a_dup()
         * should have fetched it and created state.uuid)
         */
        if (!state.uuid)
        {
            /* no */
            log("Dump directory '%s' has no UUID element", dump_dir_name);
            goto ret;
        }
    }
    else
    {
        dump_dir_name = state.crash_dump_dup_name;
    }

    /* Loads problem_data (from the *first debugdump dir* if this one is a dup)
     * Returns:
     * MW_OCCURRED: "crash count is != 1" (iow: it is > 1 - dup)
     * MW_OK: "crash count is 1" (iow: this is a new crash, not a dup)
     * else: an error code
     */
    {
        dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
        if (!dd)
        {
            res = MW_ERROR;
            goto ret;
        }

        /* Reset mode/uig/gid to correct values for all files created by event run */
        dd_sanitize_mode_and_owner(dd);

        /* Update count */
        char *count_str = dd_load_text_ext(dd, FILENAME_COUNT, DD_FAIL_QUIETLY_ENOENT);
        unsigned long count = strtoul(count_str, NULL, 10);
        count++;
        char new_count_str[sizeof(long)*3 + 2];
        sprintf(new_count_str, "%lu", count);
        dd_save_text(dd, FILENAME_COUNT, new_count_str);
        dd_close(dd);

        *problem_data = FillCrashInfo(dump_dir_name);
        if (*problem_data != NULL)
        {
            res = MW_OK;
            if (count > 1)
            {
                log("Dump directory is a duplicate of %s", dump_dir_name);
                res = MW_OCCURRED;
            }
        }
    }

 ret:
    free(state.uuid);
    free(state.uid);
    free(state.crash_dump_dup_name);
    free(analyzer);

    return res;
}
Esempio n. 15
0
int main(int argc, char **argv)
{
    abrt_init(argv);

    const char *dump_dir_name = ".";

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "\b [-v] -d DIR\n"
        "\n"
        "Calculates and saves UUID and DUPHASH of python crash dumps"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1,
    };
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING('d', NULL, &dump_dir_name, "DIR", _("Dump directory")),
        OPT_END()
    };
    /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        return 1;
    char *bt = dd_load_text(dd, FILENAME_BACKTRACE);

    /* Hash 1st line of backtrace and save it as UUID and DUPHASH */
    /* "example.py:1:<module>:ZeroDivisionError: integer division or modulo by zero" */

    unsigned char hash_bytes[SHA1_RESULT_LEN];
    sha1_ctx_t sha1ctx;
    sha1_begin(&sha1ctx);
    const char *bt_end = strchrnul(bt, '\n');
    sha1_hash(&sha1ctx, bt, bt_end - bt);
    sha1_end(&sha1ctx, hash_bytes);
    free(bt);

    char hash_str[SHA1_RESULT_LEN*2 + 1];
    unsigned len = SHA1_RESULT_LEN;
    unsigned char *s = hash_bytes;
    char *d = hash_str;
    while (len)
    {
        *d++ = "0123456789abcdef"[*s >> 4];
        *d++ = "0123456789abcdef"[*s & 0xf];
        s++;
        len--;
    }
    *d = '\0';

    dd_save_text(dd, FILENAME_UUID, hash_str);
    dd_save_text(dd, FILENAME_DUPHASH, hash_str);
    dd_close(dd);

    return 0;
}
int main(int argc, char **argv)
{
    /* I18n */
    setlocale(LC_ALL, "");
#if ENABLE_NLS
    bindtextdomain(PACKAGE, LOCALEDIR);
    textdomain(PACKAGE);
#endif

    abrt_init(argv);

    /* Can't keep these strings/structs static: _() doesn't support that */
    const char *program_usage_string = _(
        "& [options] -d DIR\n"
        "\n"
        "Analyzes C/C++ backtrace, generates duplication hash, backtrace rating,\n"
        "and identifies crash function in problem directory DIR"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_d = 1 << 1
    };
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_STRING('d', NULL, &dump_dir_name, "DIR", _("Problem directory")),
        OPT_END()
    };
    /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
    if (!dd)
        return 1;

    char *component = dd_load_text(dd, FILENAME_COMPONENT);

    /* Read backtrace */
    char *backtrace_str = dd_load_text_ext(dd, FILENAME_BACKTRACE,
                                           DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE);
    if (!backtrace_str)
    {
        dd_close(dd);
        return 1;
    }

    /* Compute backtrace hash */
    struct sr_location location;
    sr_location_init(&location);
    const char *backtrace_str_ptr = backtrace_str;
    struct sr_gdb_stacktrace *backtrace = sr_gdb_stacktrace_parse(&backtrace_str_ptr, &location);
    free(backtrace_str);

    /* Store backtrace hash */
    if (!backtrace)
    {
        /*
         * The parser failed. Compute the duphash from the executable
         * instead of a backtrace.
         * and component only.  This is not supposed to happen often.
         */
        log(_("Backtrace parsing failed for %s"), dump_dir_name);
        log("%d:%d: %s", location.line, location.column, location.message);
        struct strbuf *emptybt = strbuf_new();

        char *executable = dd_load_text(dd, FILENAME_EXECUTABLE);
        strbuf_prepend_str(emptybt, executable);
        free(executable);

        strbuf_prepend_str(emptybt, component);

        log_debug("Generating duphash: %s", emptybt->buf);
        char hash_str[SHA1_RESULT_LEN*2 + 1];
        str_to_sha1str(hash_str, emptybt->buf);

        dd_save_text(dd, FILENAME_DUPHASH, hash_str);
        /*
         * Other parts of ABRT assume that if no rating is available,
         * it is ok to allow reporting of the bug. To be sure no bad
         * backtrace is reported, rate the backtrace with the lowest
         * rating.
         */
        dd_save_text(dd, FILENAME_RATING, "0");

        strbuf_free(emptybt);
        free(component);
        dd_close(dd);

        /* Report success even if the parser failed, as the backtrace
         * has been created and rated. The failure is caused by a flaw
         * in the parser, not in the backtrace.
         */
        return 0;
    }

    /* Compute duplication hash. */
    struct sr_thread *crash_thread =
        (struct sr_thread *)sr_gdb_stacktrace_find_crash_thread(backtrace);

    if (crash_thread)
    {
        char *hash_str;

        if (g_verbose >= 3)
        {
            hash_str = sr_thread_get_duphash(crash_thread, 3, component,
                                             SR_DUPHASH_NOHASH);
            log("Generating duphash: %s", hash_str);
            free(hash_str);
        }

        hash_str = sr_thread_get_duphash(crash_thread, 3, component,
                                         SR_DUPHASH_NORMAL);
        dd_save_text(dd, FILENAME_DUPHASH, hash_str);
        free(hash_str);
    }
    else
        log(_("Crash thread not found"));


    /* Compute the backtrace rating. */
    float quality = sr_gdb_stacktrace_quality_complex(backtrace);
    const char *rating;
    if (quality < 0.6f)
        rating = "0";
    else if (quality < 0.7f)
        rating = "1";
    else if (quality < 0.8f)
        rating = "2";
    else if (quality < 0.9f)
        rating = "3";
    else
        rating = "4";
    dd_save_text(dd, FILENAME_RATING, rating);

    /* Get the function name from the crash frame. */
    struct sr_gdb_frame *crash_frame = sr_gdb_stacktrace_get_crash_frame(backtrace);
    if (crash_frame)
    {
        if (crash_frame->function_name &&
            0 != strcmp(crash_frame->function_name, "??"))
        {
            dd_save_text(dd, FILENAME_CRASH_FUNCTION, crash_frame->function_name);
        }
        sr_gdb_frame_free(crash_frame);
    }
    sr_gdb_stacktrace_free(backtrace);
    dd_close(dd);
    free(component);
    return 0;
}
Esempio n. 17
0
void abrt_oops_save_data_in_dump_dir(struct dump_dir *dd, char *oops, const char *proc_modules)
{
    char *first_line = oops;
    char *second_line = (char*)strchr(first_line, '\n'); /* never NULL */
    *second_line++ = '\0';

    if (first_line[0])
        dd_save_text(dd, FILENAME_KERNEL, first_line);
    dd_save_text(dd, FILENAME_BACKTRACE, second_line);

    /* check if trace doesn't have line: 'Your BIOS is broken' */
    if (strstr(second_line, "Your BIOS is broken"))
        dd_save_text(dd, FILENAME_NOT_REPORTABLE,
                _("A kernel problem occurred because of broken BIOS. "
                  "Unfortunately, such problems are not fixable by kernel maintainers."));
    /* check if trace doesn't have line: 'Your hardware is unsupported' */
    else if (strstr(second_line, "Your hardware is unsupported"))
        dd_save_text(dd, FILENAME_NOT_REPORTABLE,
                _("A kernel problem occurred, but your hardware is unsupported, "
                  "therefore kernel maintainers are unable to fix this problem."));
    else
    {
        char *tainted_short = kernel_tainted_short(second_line);
        if (tainted_short)
        {
            log_notice("Kernel is tainted '%s'", tainted_short);
            dd_save_text(dd, FILENAME_TAINTED_SHORT, tainted_short);

            char *tnt_long = kernel_tainted_long(tainted_short);
            dd_save_text(dd, FILENAME_TAINTED_LONG, tnt_long);
            free(tnt_long);

            struct strbuf *reason = strbuf_new();
            const char *fmt = _("A kernel problem occurred, but your kernel has been "
                    "tainted (flags:%s). Kernel maintainers are unable to "
                    "diagnose tainted reports.");
            strbuf_append_strf(reason, fmt, tainted_short);

            char *modlist = !proc_modules ? NULL : abrt_oops_list_of_tainted_modules(proc_modules);
            if (modlist)
            {
                strbuf_append_strf(reason, _(" Tainted modules: %s."), modlist);
                free(modlist);
            }

            dd_save_text(dd, FILENAME_NOT_REPORTABLE, reason->buf);
            strbuf_free(reason);
            free(tainted_short);
        }
    }

    // TODO: add "Kernel oops: " prefix, so that all oopses have recognizable FILENAME_REASON?
    // kernel oops 1st line may look quite puzzling otherwise...
    char *reason_pretty = NULL;
    char *error = NULL;
    struct sr_stacktrace *trace = sr_stacktrace_parse(SR_REPORT_KERNELOOPS, second_line, &error);
    if (trace)
    {
        reason_pretty = sr_stacktrace_get_reason(trace);
        sr_stacktrace_free(trace);
    }
    else
        free(error);

    if (reason_pretty)
    {
        dd_save_text(dd, FILENAME_REASON, reason_pretty);
        free(reason_pretty);
    }
    else
        dd_save_text(dd, FILENAME_REASON, second_line);
}