Exemple #1
0
/* Run parser */
static int parser_run(struct parser_obj *po)
{
    int error = EOK;
    struct collection_item *item = NULL;
    uint32_t action = 0;
    action_fn operations[] = { parser_read,
                               parser_inspect,
                               parser_post,
                               parser_error,
                               NULL };

    TRACE_FLOW_ENTRY();

    while(1) {
        /* Get next action */
        item = NULL;
        error = col_dequeue_item(po->queue, &item);
        if (error) {
            TRACE_ERROR_NUMBER("Failed to get action", error);
            return error;
        }

        /* Get action, run operation */
        action = *((uint32_t *)(col_get_item_data(item)));
        col_delete_item(item);

        if (action == PARSE_DONE) {

            TRACE_INFO_NUMBER("We are done", error);

            /* Report merge error in detect mode
             * if no other error was detected. */
            if ((po->ret == 0) &&
                (po->merge_error != 0) &&
                ((po->collision_flags & INI_MV1S_DETECT) ||
                 (po->collision_flags & INI_MV2S_DETECT) ||
                 (po->collision_flags & INI_MS_DETECT)))
                po->ret = po->merge_error;

            error = po->ret;
            break;
        }

        error = operations[action](po);
        if (error) {
            TRACE_ERROR_NUMBER("Failed to perform an action", error);
            return error;
        }

    }

    TRACE_FLOW_EXIT();
    return error;
}
Exemple #2
0
/* Configuration copy callback */
static int ini_copy_cb(struct collection_item *item,
                       void *ext_data,
                       int *skip)
{
    int error = EOK;
    struct value_obj *vo = NULL;
    struct value_obj *new_vo = NULL;

    TRACE_FLOW_ENTRY();

    ext_data = NULL;
    *skip = 0;

    /* Banary items are the values */
    if(col_get_item_type(item) == COL_TYPE_BINARY) {
        vo = *((struct value_obj **)(col_get_item_data(item)));

        error = value_copy(vo, &new_vo);
        if (error) {
            TRACE_ERROR_NUMBER("Failed to copy value", error);
            return error;
        }

        error = col_modify_binary_item(item,
                                       NULL,
                                       &new_vo,
                                       sizeof(struct value_obj *));
        if (error) {
            TRACE_ERROR_NUMBER("Failed to copy value", error);
            value_destroy(new_vo);
            return error;
        }
    }

    TRACE_FLOW_EXIT();
    return error;
}
Exemple #3
0
/* Find if there is a collistion */
static int check_section_collision(struct parser_obj *po)
{
    int error = EOK;
    struct collection_item *item = NULL;

    TRACE_FLOW_ENTRY();

    TRACE_INFO_STRING("Searching for:", col_get_item_property(po->sec, NULL));

    error = col_get_item(po->top,
                         col_get_item_property(po->sec, NULL),
                         COL_TYPE_ANY,
                         COL_TRAVERSE_DEFAULT,
                         &item);

    if (error) {
        TRACE_ERROR_NUMBER("Failed searching for dup", error);
        return error;
    }

    /* Check if there is a dup */
    if (item) {
        TRACE_INFO_STRING("Collision found:",
                          col_get_item_property(item, NULL));
        /* Get the actual section collection instead of reference */
        po->merge_sec = *((struct collection_item **)
                          (col_get_item_data(item)));
    }
    else {
        TRACE_INFO_STRING("Collision not found.", "");
        po->merge_sec = NULL;
    }

    TRACE_FLOW_EXIT();
    return EOK;
}
Exemple #4
0
/* Complete value processing */
static int complete_value_processing(struct parser_obj *po)
{
    int error = EOK;
    int error2 = EOK;
    struct value_obj *vo = NULL;
    struct value_obj *vo_old = NULL;
    unsigned insertmode;
    uint32_t mergemode;
    int suppress = 0;
    int doinsert = 0;
    struct collection_item *item = NULL;
    struct collection_item *section = NULL;
    int merging = 0;

    TRACE_FLOW_ENTRY();

    if (po->merge_sec) {
        TRACE_INFO_STRING("Processing value in merge mode", "");
        section = po->merge_sec;
        merging = 1;
    }
    else if(!(po->sec)) {
        TRACE_INFO_STRING("Creating default section", "");
        /* If there is not open section create a default one */
        error = col_create_collection(&po->sec,
                                      INI_DEFAULT_SECTION,
                                      COL_CLASS_INI_SECTION);
        if (error) {
            TRACE_ERROR_NUMBER("Failed to create default section", error);
            return error;
        }
        section = po->sec;
    }
    else {
        TRACE_INFO_STRING("Processing value in normal mode", "");
        section = po->sec;
    }

    if (merging) {
        TRACE_INFO_STRING("Using merge key:", po->merge_key);
        vo = po->merge_vo;
        /* We are adding to the merge section so use MV2S flags.
         * But flags are done in such a way that deviding MV2S by MV1S mask
         * will translate MV2S flags into MV1S so we can use
         * MV1S constants. */
        TRACE_INFO_NUMBER("Collisions flags:", po->collision_flags);
        mergemode = (po->collision_flags & INI_MV2S_MASK) / INI_MV1S_MASK;
    }
    else {
        /* Construct value object from what we have */
        error = value_create_from_refarray(po->raw_lines,
                                           po->raw_lengths,
                                           po->keylinenum,
                                           INI_VALUE_READ,
                                           po->key_len,
                                           po->boundary,
                                           po->ic,
                                           &vo);

        if (error) {
            TRACE_ERROR_NUMBER("Failed to create value object", error);
            return error;
        }
        /* Forget about the arrays. They are now owned by the value object */
        po->ic = NULL;
        po->raw_lines = NULL;
        po->raw_lengths = NULL;
        mergemode = po->collision_flags & INI_MV1S_MASK;
    }

    switch (mergemode) {
    case INI_MV1S_ERROR:

        insertmode = COL_INSERT_DUPERROR;
        doinsert = 1;
        break;

    case INI_MV1S_PRESERVE:

        insertmode = COL_INSERT_DUPERROR;
        doinsert = 1;
        suppress = 1;
        break;

    case INI_MV1S_ALLOW:

        insertmode = COL_INSERT_NOCHECK;
        doinsert = 1;
        break;

    case INI_MV1S_OVERWRITE: /* Special handling */
    case INI_MV1S_DETECT:
    default:
        break;
    }

    /* Do not insert but search for dups first */
    if (!doinsert) {
        TRACE_INFO_STRING("Overwrite mode. Looking for:",
                          (char *)(merging ? po->merge_key : po->key));

        error = col_get_item(section,
                             merging ? po->merge_key : po->key,
                             COL_TYPE_BINARY,
                             COL_TRAVERSE_DEFAULT,
                             &item);

        if (error) {
            TRACE_ERROR_NUMBER("Failed searching for dup", error);
            value_destroy(vo);
            return error;
        }

        /* Check if there is a dup */
        if (item) {
            /* Check if we are in the detect mode */
            if (mergemode == INI_MV1S_DETECT) {
                po->merge_error = EEXIST;
                /* There is a dup - inform user about it and continue */
                error = save_error(po->el,
                                   merging ? po->seclinenum : po->keylinenum,
                                   merging ? ERR_DUPKEYSEC : ERR_DUPKEY,
                                   ERROR_TXT);
                if (error) {
                    TRACE_ERROR_NUMBER("Failed to save error", error);
                    value_destroy(vo);
                    return error;
                }
                doinsert = 1;
                insertmode = COL_INSERT_NOCHECK;

            }
            else {

                /* Dup exists - update it */
                vo_old = *((struct value_obj **)(col_get_item_data(item)));
                error = col_modify_binary_item(item,
                                               NULL,
                                               &vo,
                                               sizeof(struct value_obj *));
                if (error) {
                    TRACE_ERROR_NUMBER("Failed updating the value", error);
                    value_destroy(vo);
                    return error;
                }

                /* If we failed to update it is better to leak then crash,
                 * so destroy original value only on the successful update.
                 */
                value_destroy(vo_old);
            }
        }
        else {
            /* No dup found so we can insert with no check */
            doinsert = 1;
            insertmode = COL_INSERT_NOCHECK;
        }
    }

    if (doinsert) {
        /* Add value to collection */
        error = col_insert_binary_property(section,
                                           NULL,
                                           COL_DSP_END,
                                           NULL,
                                           0,
                                           insertmode,
                                           merging ? po->merge_key : po->key,
                                           &vo,
                                           sizeof(struct value_obj *));
        if (error) {
            value_destroy(vo);

            if ((suppress) && (error == EEXIST)) {
                TRACE_INFO_STRING("Preseved exisitng value",
                                  (char *)(merging ? po->merge_key : po->key));
            }
            else {
                /* Check if this is a critical error or not */
                if ((mergemode == INI_MV1S_ERROR) && (error == EEXIST)) {
                    TRACE_ERROR_NUMBER("Failed to add value object "
                                       "to the section", error);
                    error2 = save_error(po->el,
                                       merging ? po->seclinenum : po->keylinenum,
                                       merging ? ERR_DUPKEYSEC : ERR_DUPKEY,
                                       ERROR_TXT);
                    if (error2) {
                        TRACE_ERROR_NUMBER("Failed to save error", error2);
                        return error2;
                    }
                    return error;
                }
                else {
                    TRACE_ERROR_NUMBER("Failed to add value object"
                                       " to the section", error);
                    return error;
                }
            }
        }
    }

    if (!merging) {
        free(po->key);
        po->key = NULL;
        po->key_len = 0;
    }

    TRACE_FLOW_EXIT();
    return EOK;
}
Exemple #5
0
/* Merge contents of the section */
static int merge_section(struct parser_obj *po)
{
    int error = EOK;
    struct collection_item *item = NULL;
    struct value_obj *vo = NULL;
    int work_to_do = 1;
    const char *key;

    TRACE_FLOW_ENTRY();

    do {
        TRACE_INFO_STRING("Top of the merge loop", "");

        item = NULL;
        error = col_extract_item_from_current(po->sec,
                                              COL_DSP_FRONT,
                                              NULL,
                                              0,
                                              COL_TYPE_ANY,
                                              &item);
        if ((error) && (error != ENOENT)) {
            TRACE_ERROR_NUMBER("Failed to extract item.", error);
            return error;
        }

        if (item) {

            TRACE_INFO_STRING("Item found:", col_get_item_property(item, NULL));

            if (strncmp(col_get_item_property(item, NULL),
                        INI_SECTION_KEY, 1) == 0) {
                /* Just ignore the first item */
                vo = *((struct value_obj **)(col_get_item_data(item)));
                value_destroy(vo);
                col_delete_item(item);
                continue;
            }

            po->merge_vo = *((struct value_obj **)(col_get_item_data(item)));
            key = col_get_item_property(item, NULL);
            /* To be able to use po->merge_key in the loop
             * we have to overcome constraints imposed by
             * the "const" declaration.
             */
            memcpy(&(po->merge_key), &key, sizeof(char *));

            /* Use the value processing function to inser the value */
            error = complete_value_processing(po);

            /* In case of error value is already cleaned */
            po->merge_vo = NULL;
            po->merge_key = NULL;
            col_delete_item(item);
            /* Now we can check the error */
            if (error) {
                TRACE_ERROR_NUMBER("Failed to merge item.", error);
                return error;
            }
        }
        else {
            TRACE_INFO_STRING("No more items:", "");
            work_to_do = 0;
        }
    }
    while (work_to_do);

    /* If we reached this place the incoming section is empty.
     * but just to be safe clean with callback. */
    col_destroy_collection_with_cb(po->sec, ini_cleanup_cb, NULL);
    po->sec = NULL;

    TRACE_FLOW_EXIT();
    return EOK;
}
Exemple #6
0
/* Clean all items in the section */
int empty_section(struct collection_item *sec)
{
    int error = EOK;
    struct collection_item *item = NULL;
    struct collection_item *save_item = NULL;
    struct value_obj *vo = NULL;
    int work_to_do = 1;

    TRACE_FLOW_ENTRY();

    do {
        item = NULL;
        error = col_extract_item_from_current(sec,
                                              COL_DSP_FRONT,
                                              NULL,
                                              0,
                                              COL_TYPE_ANY,
                                              &item);
        if ((error) && (error != ENOENT)) {
            TRACE_ERROR_NUMBER("Failed to extract item.", error);
            return error;
        }

        if (item) {
            TRACE_INFO_STRING("Item found:",
                              col_get_item_property(item, NULL));

            if (strncmp(col_get_item_property(item, NULL),
                        INI_SECTION_KEY, 1) == 0) {
                /* Just ignore the first item */
                save_item = item;
                continue;
            }

            vo = *((struct value_obj **)(col_get_item_data(item)));
            value_destroy(vo);
            col_delete_item(item);
        }
        else {
            TRACE_INFO_STRING("No more items:", "");
            /* Restore saved item */
            error = col_insert_item(sec,
                                    NULL,
                                    save_item,
                                    COL_DSP_END,
                                    NULL,
                                    0,
                                    COL_INSERT_NOCHECK);
            if (error) {
                TRACE_ERROR_NUMBER("Failed to restore item.", error);
                return error;
            }

            work_to_do = 0;
        }
    }
    while (work_to_do);

    TRACE_FLOW_EXIT();
    return EOK;
}
Exemple #7
0
/* Internal function that prints errors */
static void print_error_list(FILE *file,
                             struct collection_item *error_list,
                             int cclass,
                             char *wrong_col_error,
                             char *failed_to_process,
                             char *error_header,
                             char *line_format,
                             int family)
{
    struct collection_iterator *iterator;
    int error;
    struct collection_item *item = NULL;
    struct parse_error *pe;
    unsigned int count;

    TRACE_FLOW_STRING("print_error_list", "Entry");

    /* If we have something to print print it */
    if (error_list == NULL) {
        TRACE_ERROR_STRING("No error list","");
        return;
    }

    /* Make sure we go the right collection */
    if (!col_is_of_class(error_list, cclass)) {
        TRACE_ERROR_STRING("Wrong collection class:", wrong_col_error);
        fprintf(file,"%s\n", wrong_col_error);
        return;
    }

    /* Bind iterator */
    error =  col_bind_iterator(&iterator, error_list, COL_TRAVERSE_DEFAULT);
    if (error) {
        TRACE_ERROR_STRING("Error (bind):", failed_to_process);
        fprintf(file, "%s\n", failed_to_process);
        return;
    }

    while(1) {
        /* Loop through a collection */
        error = col_iterate_collection(iterator, &item);
        if (error) {
            TRACE_ERROR_STRING("Error (iterate):", failed_to_process);
            fprintf(file, "%s\n", failed_to_process);
            col_unbind_iterator(iterator);
            return;
        }

        /* Are we done ? */
        if (item == NULL) break;

        /* Process collection header */
        if (col_get_item_type(item) == COL_TYPE_COLLECTION) {
            col_get_collection_count(item, &count);
            if (count <= 2) break;
        } else if (col_get_item_type(item) == COL_TYPE_STRING) {
            fprintf(file, error_header, (char *)col_get_item_data(item));
        }
        else {
            /* Put error into provided format */
            pe = (struct parse_error *)(col_get_item_data(item));
            fprintf(file, line_format,
                    col_get_item_property(item, NULL), /* Error or warning */
                    pe->error,                         /* Error */
                    pe->line,                          /* Line */
                    ini_get_error_str(pe->error,
                                      family));        /* Error str */
        }

    }

    /* Do not forget to unbind iterator - otherwise there will be a leak */
    col_unbind_iterator(iterator);

    TRACE_FLOW_STRING("print_error_list", "Exit");
}