static void generate_fingerprints(struct disasm_data ddata, GHashTable *plt_names, GHashTable *call_graph, GList *entries)
{
    GList *it;
    GList *insns;
    struct backtrace_entry *entry;
    fp_function_type *fp;

    for (it = entries; it != NULL; it = g_list_next(it))
    {
        entry = it->data;
        uintptr_t function_begin = entry->function_initial_loc;
        uintptr_t function_end = function_begin + entry->function_length;

        insns = disasm_function(ddata, function_begin, function_end);
        if (insns == NULL)
        {
            VERB1 log("Cannot disassemble function at 0x%jx, not computing fingerprint", (uintmax_t)function_begin);
            continue;
        }

        struct btp_strbuf *strbuf = btp_strbuf_new();
        btp_strbuf_append_strf(strbuf, "v1"); /* Fingerprint version */

        for (fp = fp_components; *fp != NULL; fp++)
        {
            btp_strbuf_append_strf(strbuf, ";");
            (*fp)(strbuf, insns, function_begin, function_end, call_graph, plt_names);
        }

        list_free_with_free(insns);
        entry->fingerprint = btp_strbuf_free_nobuf(strbuf);
    }
}
示例#2
0
文件: curl.c 项目: hors/libreport
CURLcode curl_easy_perform_with_proxy(CURL *handle, const char *url)
{
    GList *proxy_list, *li;
    CURLcode curl_err;

    proxy_list = get_proxy_list(url);

    if (proxy_list)
    {
        /* Try with each proxy before giving up. */
        /* TODO: Should we repeat the perform call only on certain errors? */
        for (li = proxy_list, curl_err = 1; curl_err && li; li = g_list_next(li))
        {
            xcurl_easy_setopt_ptr(handle, CURLOPT_PROXY, li->data);
            VERB1 log("Connecting to %s (using proxy server %s)", url, (const char *)li->data);
            curl_err = curl_easy_perform(handle);
        }
    }
    else
    {
        VERB1 log("Connecting to %s", url);
        curl_err = curl_easy_perform(handle);
    }

    list_free_with_free(proxy_list);

    return curl_err;
}
示例#3
0
文件: rpm.c 项目: wlindauer/abrt
void rpm_init()
{
#ifdef HAVE_LIBRPM
    if (rpmReadConfigFiles(NULL, NULL) != 0)
        error_msg("Can't read RPM rc files");
#endif

    list_free_with_free(list_fingerprints); /* paranoia */
    /* Huh? Why do we start the list with an element with NULL string? */
    list_fingerprints = g_list_alloc();
}
示例#4
0
static void free_rule_list(GList *rule_list)
{
    while (rule_list)
    {
        struct rule *cur_rule = rule_list->data;
        list_free_with_free(cur_rule->conditions);
        free(cur_rule->command);
        free(cur_rule);

        GList *next = rule_list->next;
        g_list_free_1(rule_list);
        rule_list = next;
    }
}
static void fp_calltree_leaves(struct btp_strbuf *buffer, GList *insns,
        uintptr_t begin, uintptr_t end, GHashTable *call_graph, GHashTable *plt)
{
    unsigned iterations_allowed = call_graph_iteration_limit;
    GHashTable *visited = g_hash_table_new_full(g_int64_hash, g_int64_equal, free, NULL);
    GList *queue = g_list_append(NULL, addr_alloc(begin));
    GList *it, *sym = NULL;

    while (queue != NULL && iterations_allowed)
    {
        /* Pop one element */
        it = g_list_first(queue);
        queue = g_list_remove_link(queue, it);
        uintptr_t *key = (uintptr_t*)(it->data);
        /* uintptr_t addr = *key; */
        g_list_free(it);
        iterations_allowed--;

        /* Check if it is not already visited */
        if (g_hash_table_lookup_extended(visited, key, NULL, NULL))
        {
            free(key);
            continue;
        }
        g_hash_table_insert(visited, key, key);

        /* Lookup callees */
        GList *callees = g_hash_table_lookup(call_graph, key);

        /* If callee is PLT, add the corresponding symbols, otherwise
         * extend the worklist */
        for (it = callees; it != NULL; it = g_list_next(it))
        {
            char *s = g_hash_table_lookup(plt, it->data);
            if (s && !g_list_find_custom(sym, s, (GCompareFunc)strcmp))
            {
                sym = g_list_insert_sorted(sym, s, (GCompareFunc)strcmp);
            }
            else if (s == NULL)
            {
                queue = g_list_append(queue, addr_alloc(*(uintptr_t*)(it->data)));
            }
        }
    }
    g_hash_table_destroy(visited);
    list_free_with_free(queue);

    fingerprint_add_list(buffer, "calltree_leaves", sym);
}
示例#6
0
文件: bodhi.c 项目: vrutkovs/abrt
static void free_bodhi_item(struct bodhi *b)
{
    if (!b)
        return;

    free(b->nvr);

#if 0
    list_free_with_free(b->bz_ids);
    free(b->date_pushed);
    free(b->status);
    free(b->dist_tag);
#endif

    free(b);
}
示例#7
0
文件: rhbz.c 项目: mgorny/libreport
void free_bug_info(struct bug_info *bi)
{
    func_entry();

    if (!bi)
        return;

    free(bi->bi_status);
    free(bi->bi_resolution);
    free(bi->bi_reporter);
    free(bi->bi_product);

    list_free_with_free(bi->bi_cc_list);

    free(bi);
}
示例#8
0
文件: rpm.c 项目: wlindauer/abrt
void rpm_destroy()
{
#ifdef HAVE_LIBRPM
    /* Mirroring the order of deinit calls in rpm-4.11.1/lib/poptALL.c::rpmcliFini() */
    rpmFreeCrypto();
    rpmFreeMacros(NULL);
    rpmFreeRpmrc();

/* rpm >= 4.14 handles this automatically on exit */
#if 0
    /* RPM doc says "clean up any open iterators and databases".
     * Observed to eliminate these Berkeley DB warnings:
     * "BDB2053 Freeing read locks for locker 0x1e0: 28718/139661746636736"
     */
    rpmdbCheckTerminate(1);
#endif
#endif

    list_free_with_free(list_fingerprints);
    list_fingerprints = NULL;
}
示例#9
0
GList *load_words_from_file(const char* filename)
{
    GList *words_list = NULL;
    GList *file_list = NULL;
    file_list = g_list_prepend(file_list, concat_path_file(CONF_DIR, filename));
    file_list = g_list_prepend(file_list, get_user_config_file_path(filename, /*don't append suffix*/NULL));
    GList *file_list_cur = file_list;

    while(file_list_cur)
    {
        char *cur_file = (char *)file_list_cur->data;
        FILE *fp = fopen(cur_file, "r");
        if (fp)
        {
            /* every line is one word
             */
            char *line;
            while ((line = xmalloc_fgetline(fp)) != NULL)
            {
                //FIXME: works only if the '#' is first char won't work for " #abcd#
                if (line[0] != '#') // if it's not comment
                    words_list = g_list_append(words_list, line);
                else
                    free(line);
            }
            fclose(fp);
        }
        else
        {
            log_warning("Can't open %s", cur_file);
        }

        file_list_cur = g_list_next(file_list_cur);
    }

    list_free_with_free(file_list);

    return words_list;
}
示例#10
0
static void delete_files(gpointer data, gpointer void_preserve_list)
{
    double cap_size;
    const char *dir = parse_size_pfx(&cap_size, data);
    GList *preserve_files_list = void_preserve_list;

    unsigned count = 100;
    while (--count != 0)
    {
        GList *worst_file_list = NULL;
        double cur_size = get_dir_size(dir, &worst_file_list, preserve_files_list);

        if (cur_size <= cap_size || !worst_file_list)
        {
            list_free_with_free(worst_file_list);
            log_info("cur_size:%.0f cap_size:%.0f, no (more) trimming", cur_size, cap_size);
            break;
        }

        /* Invert the list, so that largest/oldest file is first */
        worst_file_list = g_list_reverse(worst_file_list);
        /* And delete (some of) them */
        while (worst_file_list && cur_size > cap_size)
        {
            struct name_and_size *ns = worst_file_list->data;
            log_notice("%s is %.0f bytes (more than %.0f MB), deleting '%s' (%llu bytes)",
                    dir, cur_size, cap_size / (1024*1024), ns->name, (long long)ns->size);
            if (unlink(ns->name) != 0)
                perror_msg("Can't unlink '%s'", ns->name);
            else
                cur_size -= ns->size;
            free(ns);
            worst_file_list = g_list_delete_link(worst_file_list, worst_file_list);
        }
    }
}
示例#11
0
/* Load ELF 'filename', parse the .eh_frame contents, and for each entry in the
 * second argument check whether its address is contained in the range of some
 * Frame Description Entry. If it does, fill in the function range of the
 * entry. In other words, try to assign start address and length of function
 * corresponding to each backtrace entry. We'll need that for the disassembly.
 *
 * Fails quietly - we should still be able to use the build ids.
 *
 * I wonder if this is really better than parsing eu-readelf text output.
 */
static GHashTable *elf_iterate_fdes(const char *filename, GList *entries, Elf *e)
{
    const unsigned char *e_ident;
    Elf_Data *scn_data;
    GElf_Shdr shdr;
    GElf_Phdr phdr;
    size_t phnum;
    GHashTable *retval = NULL; /* NULL = error */

    e_ident = (unsigned char *)elf_getident(e, NULL);
    if (e_ident == NULL)
    {
        VERB1 log_elf_error("elf_getident", filename);
        return NULL;
    }

    /* Look up the .eh_frame section */
    if (!xelf_section_by_name(e, ".eh_frame", filename, &scn_data, &shdr))
    {
        VERB1 log("Section .eh_frame not found in %s", filename);
        return NULL;
    }

    /* Get the address at which the executable segment is loaded. If the
     * .eh_frame addresses are absolute, this is used to convert them to
     * relative to the beginning of executable segment. We are looking for the
     * first LOAD segment that is executable, I hope this is sufficient.
     */
    if (elf_getphdrnum(e, &phnum) != 0)
    {
        VERB1 log_elf_error("elf_getphdrnum", filename);
        return NULL;
    }

    uintptr_t exec_base;
    int i;
    for (i = 0; i < phnum; i++)
    {
        if (gelf_getphdr(e, i, &phdr) != &phdr)
        {
            VERB1 log_elf_error("gelf_getphdr", filename);
            return NULL;
        }

        if (phdr.p_type == PT_LOAD && phdr.p_flags & PF_X)
        {
            exec_base = (uintptr_t)phdr.p_vaddr;
            goto base_found;
        }
    }

    VERB1 log("Can't determine executable base for '%s'", filename);
    return NULL;

base_found:
    VERB2 log("Executable base: %jx", (uintmax_t)exec_base);

    /* We now have a handle to .eh_frame data. We'll use dwarf_next_cfi to
     * iterate through all FDEs looking for those matching the addresses we
     * have.
     * Some info on .eh_frame can be found at http://www.airs.com/blog/archives/460
     * and in DWARF documentation for .debug_frame. The initial_location and
     * address_range decoding is 'inspired' by elfutils source.
     * XXX: If this linear scan is too slow, we can do binary search on
     * .eh_frame_hdr -- see http://www.airs.com/blog/archives/462
     */
    int ret;
    Dwarf_Off cfi_offset;
    Dwarf_Off cfi_offset_next = 0;
    Dwarf_CFI_Entry cfi;

    struct cie_encoding {
        Dwarf_Off cie_offset;
        int ptr_len;
        bool pcrel;
    } *cie;
    GList *cie_list = NULL;

    /* Init hash table
     * keys are pointers to integers which we allocate with malloc
     * values stored directly */
    GHashTable *hash = g_hash_table_new_full(g_int64_hash, g_int64_equal, free, NULL);

    while(1)
    {
        cfi_offset = cfi_offset_next;
        ret = dwarf_next_cfi(e_ident, scn_data, 1, cfi_offset, &cfi_offset_next, &cfi);

        if (ret > 0)
        {
            /* We're at the end. */
            break;
        }

        if (ret < 0)
        {
            /* Error. If cfi_offset_next was updated, we may skip the
             * erroneous cfi. */
            if (cfi_offset_next > cfi_offset)
            {
                continue;
            }
            VERB1 log("dwarf_next_cfi failed for %s: %s", filename, dwarf_errmsg(-1));
            goto ret_free;
        }

        if (dwarf_cfi_cie_p(&cfi))
        {
            /* Current CFI is a CIE. We store its offset and FDE encoding
             * attributes to be used when reading FDEs.
             */

            /* Default FDE encoding (i.e. no R in augmentation string) is
             * DW_EH_PE_absptr.
             */
            cie = btp_mallocz(sizeof(*cie));
            cie->cie_offset = cfi_offset;
            cie->ptr_len = encoded_size(DW_EH_PE_absptr, e_ident);

            /* Search the augmentation data for FDE pointer encoding.
             * Unfortunately, 'P' can come before 'R' (which we are looking
             * for), so we may have to parse the whole thing. See the
             * abovementioned blog post for details.
             */
            const char *aug = cfi.cie.augmentation;
            const uint8_t *augdata = cfi.cie.augmentation_data;
            bool skip_cie = 0;
            if (*aug == 'z')
            {
                aug++;
            }
            while (*aug != '\0')
            {
                if(*aug == 'R')
                {
                    cie->ptr_len = encoded_size(*augdata, e_ident);

                    if (cie->ptr_len != 4 && cie->ptr_len != 8)
                    {
                        VERB1 log("Unknown FDE encoding (CIE %jx) in %s",
                                (uintmax_t)cfi_offset, filename);
                        skip_cie = 1;
                    }
                    if ((*augdata & 0x70) == DW_EH_PE_pcrel)
                    {
                        cie->pcrel = 1;
                    }
                    break;
                }
                else if (*aug == 'L')
                {
                    augdata++;
                }
                else if (*aug == 'P')
                {
                    unsigned size = encoded_size(*augdata, e_ident);
                    if (size == 0)
                    {
                        VERB1 log("Unknown size for personality encoding in %s",
                                filename);
                        skip_cie = 1;
                        break;
                    }
                    augdata += (size + 1);
                }
                else
                {
                    VERB1 log("Unknown augmentation char in %s", filename);
                    skip_cie = 1;
                    break;
                }
                aug++;
            }
            if (skip_cie)
            {
                free(cie);
                continue;
            }

            cie_list = g_list_append(cie_list, cie);
        }
        else
        {
            /* Current CFI is an FDE.
             */
            GList *it = cie_list;
            cie = NULL;

            /* Find the CIE data that we should have saved earlier. XXX: We can
             * use hash table/tree to speed up the search, the number of CIEs
             * should usally be very low though. */
            while (it != NULL)
            {
                cie = it->data;

                /* In .eh_frame, CIE_pointer is relative, but libdw converts it
                 * to absolute offset. */
                if(cfi.fde.CIE_pointer == cie->cie_offset)
                {
                    break; /* Found. */
                }

                it = g_list_next(it);
            }

            if (it == NULL)
            {
                VERB1 log("CIE not found for FDE %jx in %s",
                        (uintmax_t)cfi_offset, filename);
                continue;
            }

            /* Read the two numbers we need and if they are PC-relative,
             * compute the offset from VMA base
             */

            uintptr_t initial_location = fde_read_address(cfi.fde.start, cie->ptr_len);
            uintptr_t address_range = fde_read_address(cfi.fde.start+cie->ptr_len, cie->ptr_len);

            if (cie->pcrel)
            {
                /* We need to determine how long is the 'length' (and
                 * consequently CIE id) field of this FDE -- it can be either 4
                 * or 12 bytes long. */
                uintptr_t length = fde_read_address(scn_data->d_buf + cfi_offset, 4);
                uintptr_t skip = (length == 0xffffffffUL ? 12 : 4);

                uintptr_t mask = (cie->ptr_len == 4 ? 0xffffffffUL : 0xffffffffffffffffUL);
                initial_location += (uintptr_t)shdr.sh_offset + (uintptr_t)cfi_offset + 2*skip;
                initial_location &= mask;
            }
            else
            {
                /* Assuming that not pcrel means absolute address (what if the file is a library?).
                 * Convert to text-section-start-relative.
                 */
                initial_location -= exec_base;
            }

            /* Insert the pair into hash */
            uintptr_t *key = addr_alloc(initial_location + exec_base);
            g_hash_table_insert(hash, key, (gpointer)address_range);
            VERB3 log("FDE start: 0x%jx length: %u", (uintmax_t)*key, (unsigned)address_range);

            /* Iterate through the backtrace entries and check each address
             * member whether it belongs into the range given by current FDE.
             */
            for (it = entries; it != NULL; it = g_list_next(it))
            {
                struct backtrace_entry *entry = it->data;
                if (initial_location <= entry->build_id_offset
                        && entry->build_id_offset < initial_location + address_range)
                {
                    /* Convert to before-relocation absolute addresses, disassembler uses those. */
                    entry->function_initial_loc = exec_base + initial_location;
                    entry->function_length = address_range;
                    /*TODO: remove the entry from the list to save a bit of time in next iteration?*/
                }
            }
        }
    }

    retval = hash; /* success */

ret_free:
    list_free_with_free(cie_list);
    if (retval == NULL)
        g_hash_table_destroy(hash);
    return retval;
}
示例#12
0
/* Compute intra-module call graph (that is, only calls within the binary).
 */
static GHashTable* compute_call_graph(struct disasm_data data, GHashTable *fdes, GList *entries)
{
    unsigned iterations_allowed = call_graph_iteration_limit;
    GList *it, *insns;
    struct backtrace_entry *entry;
    GList *queue = NULL;
    /* Keys are pointers to addresses, values are GLists of pointers to addresses. */
    GHashTable *succ = g_hash_table_new_full(g_int64_hash, g_int64_equal, free, (GDestroyNotify)list_free_with_free);

    /* Seed the queue with functions from entries */
    for (it = entries; it != NULL; it = g_list_next(it))
    {
        entry = it->data;
        uintptr_t *k = addr_alloc(entry->function_initial_loc);
        queue = g_list_append(queue, k);
    }

    /* Note: allocated addresses that belong to the queue must either be
     * 'reassigned' to succ or freed. */
    while (queue != NULL && iterations_allowed)
    {
        /* Pop one item from the queue */
        it = g_list_first(queue);
        queue = g_list_remove_link(queue, it);
        uintptr_t *key = (uintptr_t*)(it->data);
        uintptr_t function_begin = *key;
        g_list_free(it);
        iterations_allowed--;

        /* Check if it is not already processed */
        if (g_hash_table_lookup_extended(succ, key, NULL, NULL))
        {
            free(key);
            continue;
        }

        /* Look up function length in fdes
         * note: length is stored casted to pointer */
        uintptr_t p = (uintptr_t)g_hash_table_lookup(fdes, key);
        if (p == 0)
        {
            VERB3 log("Range not present for 0x%jx, skipping disassembly", (uintmax_t)function_begin);
            /* Insert empty list of callees so that we avoid looping infinitely */
            g_hash_table_insert(succ, key, NULL);
            continue;
        }
        uintptr_t function_end = function_begin + p;

        /* Disassemble function */
        insns = disasm_function(data, function_begin, function_end);
        if (insns == NULL)
        {
            VERB2 log("Disassembly of 0x%jx-0x%jx failed", (uintmax_t)function_begin, (uintmax_t)function_end);
            /* Insert empty list of callees so that we avoid looping infinitely */
            g_hash_table_insert(succ, key, NULL);
            continue;
        }

        /* Scan for callees */
        GList *fn_callees = callees(insns);
        list_free_with_free(insns);

        VERB3 log("Callees of 0x%jx:", (uintmax_t)function_begin);

        /* Insert callees to the workqueue */
        for (it = fn_callees; it != NULL; it = g_list_next(it))
        {
            uintptr_t c = *(uintptr_t*)it->data;
            queue = g_list_append(queue, addr_alloc(c));

            VERB3 log("\t0x%jx", (uintmax_t)c);
        }

        /* Insert it to the hash so we don't have to recompute it */
        g_hash_table_insert(succ, key, fn_callees);
    }

    return succ;
}
示例#13
0
文件: kernel.c 项目: alisheikh/abrt
void koops_extract_oopses(GList **oops_list, char *buffer, size_t buflen)
{
    char *c;
    int linecount = 0;
    int lines_info_size = 0;
    struct abrt_koops_line_info *lines_info = NULL;

    /* Split buffer into lines */

    if (buflen != 0)
            buffer[buflen - 1] = '\n';  /* the buffer usually ends with \n, but let's make sure */
    c = buffer;
    while (c < buffer + buflen)
    {
        char linelevel;
        char *c9;
        char *colon;

        linecount++;
        c9 = (char*)memchr(c, '\n', buffer + buflen - c); /* a \n will always be found */
        assert(c9);
        *c9 = '\0'; /* turn the \n into a string termination */
        if (c9 == c)
            goto next_line;

        /* Is it a syslog file (/var/log/messages or similar)?
         * Even though _usually_ it looks like "Nov 19 12:34:38 localhost kernel: xxx",
         * some users run syslog in non-C locale:
         * "2010-02-22T09:24:08.156534-08:00 gnu-4 gnome-session[2048]: blah blah"
         *  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ !!!
         * We detect it by checking for N:NN:NN pattern in first 15 chars
         * (and this still is not good enough... false positive: "pci 0000:15:00.0: PME# disabled")
         */
        colon = strchr(c, ':');
        if (colon && colon > c && colon < c + 15
         && isdigit(colon[-1]) /* N:... */
         && isdigit(colon[1]) /* ...N:NN:... */
         && isdigit(colon[2])
         && colon[3] == ':'
         && isdigit(colon[4]) /* ...N:NN:NN... */
         && isdigit(colon[5])
        ) {
            /* It's syslog file, not a bare dmesg */

            /* Skip non-kernel lines */
            char *kernel_str = strstr(c, "kernel: ");
            if (!kernel_str)
            {
                /* if we see our own marker:
                 * "hostname abrt: Kerneloops: Reported 1 kernel oopses to Abrt"
                 * we know we submitted everything upto here already */
                if (strstr(c, "kernel oopses to Abrt"))
                {
                    log_debug("Found our marker at line %d", linecount);
                    free(lines_info);
                    lines_info = NULL;
                    lines_info_size = 0;
                    list_free_with_free(*oops_list);
                    *oops_list = NULL;
                }
                goto next_line;
            }
            c = kernel_str + sizeof("kernel: ")-1;
        }

        /* store and remove kernel log level */
        linelevel = koops_line_skip_level((const char **)&c);
        koops_line_skip_jiffies((const char **)&c);

        if ((lines_info_size & 0xfff) == 0)
        {
            lines_info = xrealloc(lines_info, (lines_info_size + 0x1000) * sizeof(lines_info[0]));
        }
        lines_info[lines_info_size].ptr = c;
        lines_info[lines_info_size].level = linelevel;
        lines_info_size++;
next_line:
        c = c9 + 1;
    }

    koops_extract_oopses_from_lines(oops_list, lines_info, lines_info_size);
    free(lines_info);
}
示例#14
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 = _(
        "& [-vusoxm] [-d DIR]/[-D] [FILE]\n"
        "\n"
        "Extract oops from FILE (or standard input)"
    );
    enum {
        OPT_v = 1 << 0,
        OPT_s = 1 << 1,
        OPT_o = 1 << 2,
        OPT_d = 1 << 3,
        OPT_D = 1 << 4,
        OPT_u = 1 << 5,
        OPT_x = 1 << 6,
        OPT_t = 1 << 7,
        OPT_m = 1 << 8,
    };
    char *problem_dir = NULL;
    char *dump_location = NULL;
    /* Keep enum above and order of options below in sync! */
    struct options program_options[] = {
        OPT__VERBOSE(&g_verbose),
        OPT_BOOL(  's', NULL, NULL, _("Log to syslog")),
        OPT_BOOL(  'o', NULL, NULL, _("Print found oopses on standard output")),
        /* oopses don't contain any sensitive info, and even
         * the old koops app was showing the oopses to all users
         */
        OPT_STRING('d', NULL, &dump_location, "DIR", _("Create new problem directory in DIR for every oops found")),
        OPT_BOOL(  'D', NULL, NULL, _("Same as -d DumpLocation, DumpLocation is specified in abrt.conf")),
        OPT_STRING('u', NULL, &problem_dir, "PROBLEM", _("Save the extracted information in PROBLEM")),
        OPT_BOOL(  'x', NULL, NULL, _("Make the problem directory world readable")),
        OPT_BOOL(  't', NULL, NULL, _("Throttle problem directory creation to 1 per second")),
        OPT_BOOL(  'm', NULL, NULL, _("Print search string(s) to stdout and exit")),
        OPT_END()
    };
    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);

    export_abrt_envvars(0);

    msg_prefix = g_progname;
    if ((opts & OPT_s) || getenv("ABRT_SYSLOG"))
    {
        logmode = LOGMODE_JOURNAL;
    }

    if (opts & OPT_m)
    {
        char *oops_string_filter_regex = abrt_oops_string_filter_regex();
        if (oops_string_filter_regex)
        {
            regex_t filter_re;
            if (regcomp(&filter_re, oops_string_filter_regex, REG_NOSUB) != 0)
                perror_msg_and_die(_("Failed to compile regex"));

            const regex_t *filter[] = { &filter_re, NULL };

            koops_print_suspicious_strings_filtered(filter);

            regfree(&filter_re);
            free(oops_string_filter_regex);
        }
        else
            koops_print_suspicious_strings();

        return 1;
    }

    if (opts & OPT_D)
    {
        if (opts & OPT_d)
            show_usage_and_die(program_usage_string, program_options);
        load_abrt_conf();
        dump_location = g_settings_dump_location;
        g_settings_dump_location = NULL;
        free_abrt_conf_data();
    }

    int oops_utils_flags = 0;
    if ((opts & OPT_x))
        oops_utils_flags |= ABRT_OOPS_WORLD_READABLE;

    if ((opts & OPT_t))
        oops_utils_flags |= ABRT_OOPS_THROTTLE_CREATION;

    if ((opts & OPT_o))
        oops_utils_flags |= ABRT_OOPS_PRINT_STDOUT;

    argv += optind;
    if (argv[0])
        xmove_fd(xopen(argv[0], O_RDONLY), STDIN_FILENO);

    GList *oops_list = NULL;
    scan_syslog_file(&oops_list, STDIN_FILENO);

    unsigned errors = 0;
    if (opts & OPT_u)
    {
        log_warning("Updating problem directory");
        switch (g_list_length(oops_list))
        {
            case 0:
                {
                    error_msg(_("Can't update the problem: no oops found"));
                    errors = 1;
                    break;
                }
            default:
                {
                    log_notice(_("More oopses found: process only the first one"));
                }
                /* falls trought */
            case 1:
                {
                    struct dump_dir *dd = dd_opendir(problem_dir, /*open for writing*/0);
                    if (dd)
                    {
                        abrt_oops_save_data_in_dump_dir(dd, (char *)oops_list->data, /*no proc modules*/NULL);
                        dd_close(dd);
                    }
                }
        }
    }
    else
        errors = abrt_oops_process_list(oops_list, dump_location,
                                        ABRT_DUMP_OOPS_ANALYZER, oops_utils_flags);

    list_free_with_free(oops_list);
    //oops_list = NULL;

    return errors;
}
示例#15
0
/* Checks rules in *pp_rule_list, starting from first (remaining) rule,
 * until it finds a rule with all conditions satisfied.
 * In this case, it deletes this rule and returns this rule's cmd.
 * Else (if it didn't find such rule), it returns NULL.
 * In case of error (dump_dir can't be opened), returns NULL.
 *
 * Intended usage:
 * list = load_rule_list(...);
 * while ((cmd = pop_next_command(&list, ...)) != NULL)
 *     run(cmd);
 */
static char* pop_next_command(GList **pp_rule_list,
        char **pp_event_name,    /* reports EVENT value thru this, if not NULL on entry */
        struct dump_dir **pp_dd, /* use *pp_dd for access to dump dir, if non-NULL */
        const char *dump_dir_name,
        const char *pfx,
        unsigned pfx_len
)
{
    char *command = NULL;
    struct dump_dir *dd = pp_dd ? *pp_dd : NULL;

    GList *rule_list = *pp_rule_list;
    while (rule_list)
    {
        struct rule *cur_rule = rule_list->data;

        GList *condition = cur_rule->conditions;
        while (condition)
        {
            const char *cond_str = condition->data;
            const char *eq_sign = strchr(cond_str, '=');

            /* Is it "EVENT=foo"? */
            if (strncmp(cond_str, "EVENT=", 6) == 0)
            {
                if (strncmp(eq_sign + 1, pfx, pfx_len) != 0)
                    goto next_rule; /* prefix doesn't match */
                if (pp_event_name)
                {
                    free(*pp_event_name);
                    *pp_event_name = xstrdup(eq_sign + 1);
                }
            }
            else
            {
                /* Read from dump dir and compare */
                if (!dd)
                {
                    /* Without dir to match, we assume match for all conditions */
                    if (!dump_dir_name)
                        goto next_cond;
                    dd = dd_opendir(dump_dir_name, /*flags:*/ DD_OPEN_READONLY);
                    if (!dd)
                    {
                        free_rule_list(rule_list);
                        *pp_rule_list = NULL;
                        goto ret; /* error (note: dd_opendir logged error msg) */
                    }
                }
                /* Is it "VAR~=REGEX"? */
                int regex = (eq_sign > cond_str && eq_sign[-1] == '~');
                /* Is it "VAR!=VAL"? */
                int inverted = (eq_sign > cond_str && eq_sign[-1] == '!');
                char *var_name = xstrndup(cond_str, eq_sign - cond_str - (regex|inverted));
                char *real_val = dd_load_text_ext(dd, var_name, DD_FAIL_QUIETLY_ENOENT);
                free(var_name);
                int vals_differ = regex ? regcmp_lines(real_val, eq_sign + 1) : strcmp(real_val, eq_sign + 1);
                free(real_val);
                if (inverted)
                    vals_differ = !vals_differ;

                /* Do values match? */
                if (vals_differ) /* no */
                {
                    //log_debug("var '%s': '%.*s'!='%s', skipping line",
                    //        p,
                    //        (int)(strchrnul(real_val, '\n') - real_val), real_val,
                    //        eq_sign);
                    goto next_rule;
                }
            }
 next_cond:
            /* We are here if current condition is satisfied */

            condition = condition->next;
        } /* while (condition) */
        /* We are here if all conditions are satisfied */
        /* IOW, we found rule to run, delete it and return its command */
        *pp_rule_list = g_list_remove(*pp_rule_list, cur_rule);
        list_free_with_free(cur_rule->conditions);
        command = cur_rule->command;
        /*free(cur_rule->command); - WRONG! we are returning it! */
        free(cur_rule);
        break;

 next_rule:
        rule_list = rule_list->next;
    } /* while (rule_list) */

 ret:
    if (pp_dd)
        *pp_dd = dd;
    else
        dd_close(dd);
    return command;
}