コード例 #1
0
ファイル: listmgr_ns.c プロジェクト: cea-hpc/robinhood
/**
 * Get the list of children of a given parent (or list of parents).
 * \param parent_list       [in]  list of parents to get the child of
 * \param parent_count      [in]  number of ids in parent list
 * \param attr_mask         [in]  required attributes for children
 * \param child_id_list     [out] ptr to array of child ids
 * \param child_attr_list   [out] ptr to array of child attrs
 * \param child_count       [out] number of returned children
 */
int ListMgr_GetChild(lmgr_t *p_mgr, const lmgr_filter_t *p_filter,
                     const wagon_t *parent_list, unsigned int parent_count,
                     attr_mask_t attr_mask,
                     wagon_t **child_id_list, attr_set_t **child_attr_list,
                     unsigned int *child_count)
{
    result_handle_t result;
    char *path = NULL;
    int path_len;
    int                rc, i;
    GString           *req = NULL;
    GString           *fields = NULL;
    GString           *from = NULL;
    GString           *where = NULL;
    struct field_count field_cnt = {0};
    struct field_count filter_cnt = {0};
    table_enum         query_tab = T_DNAMES;
    bool               distinct = false;
    int                retry_status;

    /* XXX: querying children from several parent cannot work, since
     * we need to get the paths of the children. Or we could do a
     * lookup into parent_list to find the right one. In the meantime,
     * try not to mess up the code. */
    if (unlikely(parent_count != 1))
        RBH_BUG("cannot get children for several parent simultaneously");

    /* always request for name to build fullpath in wagon */
    attr_mask_set_index(&attr_mask, ATTR_INDEX_name);

    fields = g_string_new(NULL);

    /* append fields for all tables */
    if (!attr_mask_is_null(attr_mask))
    {
        /* retrieve source info for generated fields */
        add_source_fields_for_gen(&attr_mask.std);

        field_cnt.nb_names = attrmask2fieldlist(fields, attr_mask, T_DNAMES,
                                                DNAMES_TABLE".", "",
                                                AOF_LEADING_SEP);

        field_cnt.nb_main = attrmask2fieldlist(fields, attr_mask, T_MAIN,
                                               MAIN_TABLE".", "",
                                               AOF_LEADING_SEP);

        field_cnt.nb_annex = attrmask2fieldlist(fields, attr_mask, T_ANNEX,
                                                ANNEX_TABLE".", "",
                                                AOF_LEADING_SEP);
    }
    else
    {
        /* no returned attrs */
        if (child_attr_list != NULL)
            *child_attr_list = NULL;
    }

    where = g_string_new(NULL);

    /* starts with condition on parent */
    rc = append_parent_cond(p_mgr, where, parent_list, parent_count, DNAMES_TABLE".");
    if (rc != DB_SUCCESS)
        goto free_str;

    /* check filters on other tables */
    if (!no_filter(p_filter))
    {
        if (unlikely(dir_filter(p_mgr, NULL, p_filter, NULL, NULL) != FILTERDIR_NONE))
        {
            DisplayLog(LVL_MAJOR, LISTMGR_TAG, "Directory filter not supported in %s()", __func__);
            rc = DB_NOT_SUPPORTED;
            goto free_str;
        }
        else if (unlikely(func_filter(p_mgr, NULL, p_filter, T_MAIN, 0)))
        {
            DisplayLog(LVL_MAJOR, LISTMGR_TAG, "Function filter not supported in %s()", __func__);
            rc = DB_NOT_SUPPORTED;
            goto free_str;
        }

        /* There is always a filter on T_DNAMES, which is the parent condition.
         * Look for optional filters.
         */
        filter_where(p_mgr, p_filter, &filter_cnt, where,
                     AOF_LEADING_SEP | AOF_SKIP_NAME);
        /** @FIXME process other filters on NAMES */
    }

    from = g_string_new(DNAMES_TABLE);

    /* add filter_count + field_count to build the FROM clause.
     * Preserve field count which is needed to interpret the result.
     */
    filter_cnt.nb_main += field_cnt.nb_main;
    filter_cnt.nb_annex += field_cnt.nb_annex;
    filter_cnt.nb_names += field_cnt.nb_names;
    /* query tab is DNAMES, skip_name=true, is_first_tab=T_DNAMES */
    filter_from(p_mgr, &filter_cnt, from, &query_tab, &distinct,
                AOF_LEADING_SEP | AOF_SKIP_NAME);

    /* request is always on the DNAMES table (which contains [parent_id, id] relationship */
    if (distinct)
        req = g_string_new("SELECT DISTINCT("DNAMES_TABLE".id) as id");
    else
        req = g_string_new("SELECT "DNAMES_TABLE".id as id");

    /* build the whole request */
    g_string_append_printf(req, "%s FROM %s WHERE %s", fields->str, from->str, where->str);

retry:
    rc = db_exec_sql(&p_mgr->conn, req->str, &result);
    retry_status = lmgr_delayed_retry(p_mgr, rc);
    if (retry_status == 1)
        goto retry;
    else if (retry_status == 2) {
        rc = DB_RBH_SIG_SHUTDOWN;
        goto free_str;
    } else if (rc)
        goto free_str;

    /* copy result to output structures */
    *child_count = db_result_nb_records(&p_mgr->conn, &result);

    /* allocate entry_id array */
    *child_id_list = MemCalloc(*child_count, sizeof(wagon_t));
    if (*child_id_list == NULL)
    {
        rc = DB_NO_MEMORY;
        goto free_str;
    }

    if (child_attr_list)
    {
        *child_attr_list = MemCalloc(*child_count, sizeof(attr_set_t));
        if (*child_attr_list == NULL)
        {
            rc = DB_NO_MEMORY;
            goto array_free;
        }
    }

    /* Allocate a string long enough to contain the parent path and a
     * child name. */
    path_len = strlen(parent_list[0].fullname) + RBH_NAME_MAX + 2;
    path = malloc(path_len);
    if (!path) {
        DisplayLog(LVL_MAJOR, LISTMGR_TAG, "Can't alloc enough memory (%d bytes)",
                    path_len);
        rc = DB_NO_MEMORY;
        goto array_free;
    }

    for (i = 0; i < *child_count; i++)
    {
        char *res[128]; /* 128 fields per record is large enough */

        rc = db_next_record(&p_mgr->conn, &result, res, sizeof(res)/sizeof(*res));
        if (rc)
            goto array_free;

        /* copy id to array */
        pk2entry_id(p_mgr, res[0], &((*child_id_list)[i].id));

        /* copy attributes to array */
        if (child_attr_list)
        {
            unsigned int shift = 1; /* first was NAMES.id */

            (*child_attr_list)[i].attr_mask = attr_mask;

            /* first id, then dnames attrs, then main attrs, then annex attrs */
            if (field_cnt.nb_names > 0)
            {
                /* shift of 1 for id */
                rc = result2attrset(T_DNAMES, res + shift, field_cnt.nb_names, &((*child_attr_list)[i]));
                if (rc)
                    goto array_free;
                shift += field_cnt.nb_names;
            }

            if (field_cnt.nb_main > 0)
            {
                /* first id, then main attrs, then annex attrs */
                /* shift of 1 for id */
                rc = result2attrset(T_MAIN, res + shift, field_cnt.nb_main, &((*child_attr_list)[i]));
                if (rc)
                    goto array_free;
                shift += field_cnt.nb_main;
            }

            if (field_cnt.nb_annex > 0)
            {
                /* shift of main_attrs count */
                rc = result2attrset(T_ANNEX, res + shift, field_cnt.nb_annex,
                                     &((*child_attr_list)[i]));
                if (rc)
                    goto array_free;
                shift += field_cnt.nb_annex;
            }

#ifdef _LUSTRE
            if (stripe_fields(attr_mask))
            {
                if (get_stripe_info(p_mgr, res[0], &ATTR(&(*child_attr_list)[i], stripe_info),
                                     &ATTR(&(*child_attr_list)[i], stripe_items)))
                {
                    ATTR_MASK_UNSET(&(*child_attr_list)[i], stripe_info);
                    ATTR_MASK_UNSET(&(*child_attr_list)[i], stripe_items);
                }
            }
#endif

            generate_fields(&((*child_attr_list)[i]));

            /* Note: path is properly sized already to not overflow. */
            snprintf(path, path_len, "%s/%s", parent_list[0].fullname,
                     (*child_attr_list)[i].attr_values.name);
            (*child_id_list)[i].fullname = strdup(path);
        }
    }

    if (path)
        free(path);

    db_result_free(&p_mgr->conn, &result);
    g_string_free(req, TRUE);
    g_string_free(fields, TRUE);
    g_string_free(from, TRUE);
    g_string_free(where, TRUE);
    return 0;

array_free:
    if (path)
        free(path);
    if (child_attr_list && *child_attr_list)
    {
        MemFree(*child_attr_list);
        *child_attr_list = NULL;
    }
    MemFree(*child_id_list);
    *child_id_list = NULL;
free_str:
    g_string_free(req, TRUE);
    g_string_free(fields, TRUE);
    g_string_free(from, TRUE);
    g_string_free(where, TRUE);
    return rc;
}
コード例 #2
0
/**
 * check if the entry exists in the database and what info
 * must be retrieved.
 */
int EntryProc_get_info_db( struct entry_proc_op_t *p_op, lmgr_t * lmgr )
{
    int      rc = 0;
    int      next_stage = -1; /* -1 = skip */
    attr_mask_t attr_allow_cached = null_mask;
    attr_mask_t attr_need_fresh = null_mask;
    uint32_t status_scope = 0; /* status mask only */
    attr_mask_t tmp;

    const pipeline_stage_t *stage_info =
        &entry_proc_pipeline[p_op->pipeline_stage];

    /* check if entry is in policies scope */
    add_matching_scopes_mask(&p_op->entry_id, &p_op->fs_attrs, true,
                             &status_scope);

    /* XXX also retrieve needed attributes to check the scope? */

    /* get diff attributes from DB and FS (to allow comparison) */
    p_op->db_attr_need = attr_mask_or(&p_op->db_attr_need, &diff_mask);

    tmp = attr_mask_and_not(&diff_mask, &p_op->fs_attrs.attr_mask);
    p_op->fs_attr_need = attr_mask_or(&p_op->fs_attr_need, &tmp);

    if (entry_proc_conf.detect_fake_mtime)
        attr_mask_set_index(&p_op->db_attr_need, ATTR_INDEX_creation_time);

    attr_allow_cached = attrs_for_status_mask(status_scope, false);
    attr_need_fresh = attrs_for_status_mask(status_scope, true);
    /* XXX check if entry is in policy scope? */

    /* what must be retrieved from DB: */
    tmp = attr_mask_and_not(&attr_allow_cached, &p_op->fs_attrs.attr_mask);
    p_op->db_attr_need = attr_mask_or(&p_op->db_attr_need, &tmp);

    /* no dircount for non-dirs */
    if (ATTR_MASK_TEST(&p_op->fs_attrs, type) &&
        !strcmp(ATTR(&p_op->fs_attrs, type), STR_TYPE_DIR))
    {
        attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_dircount);
    }

    /* no readlink for non symlinks */
    if (ATTR_MASK_TEST(&p_op->fs_attrs, type)) /* likely */
    {
        if (!strcmp(ATTR(&p_op->fs_attrs, type), STR_TYPE_LINK))
        {
            attr_mask_set_index(&p_op->db_attr_need, ATTR_INDEX_link); /* check if it is known */
            /* no stripe for symlinks */
            attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_stripe_info);
            attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_stripe_items);
        }
        else
            attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_link);
    }

    if (!attr_mask_is_null(p_op->db_attr_need))
    {
        p_op->db_attrs.attr_mask = p_op->db_attr_need;
        rc = ListMgr_Get(lmgr, &p_op->entry_id, &p_op->db_attrs);

        if (rc == DB_SUCCESS)
        {
            p_op->db_exists = 1;
        }
        else if (rc == DB_NOT_EXISTS )
        {
            p_op->db_exists = 0;
            ATTR_MASK_INIT( &p_op->db_attrs );
        }
        else
        {
            /* ERROR */
            DisplayLog(LVL_CRIT, ENTRYPROC_TAG,
                       "Error %d retrieving entry "DFID" from DB: %s.", rc,
                       PFID(&p_op->entry_id), lmgr_err2str(rc));
            p_op->db_exists = 0;
            ATTR_MASK_INIT( &p_op->db_attrs );
        }
    }
    else
    {
        p_op->db_exists = ListMgr_Exists( lmgr, &p_op->entry_id );
    }

    /* get status for all policies with a matching scope */
    add_matching_scopes_mask(&p_op->entry_id, &p_op->fs_attrs, true,
                             &p_op->fs_attr_need.status);
    tmp = attr_mask_and_not(&attr_need_fresh, &p_op->fs_attrs.attr_mask);
    p_op->fs_attr_need = attr_mask_or(&p_op->fs_attr_need, &tmp);

    if ( !p_op->db_exists )
    {
        /* new entry */
        p_op->db_op_type = OP_TYPE_INSERT;

        /* set creation time if it was not set by scan module */
        if (!ATTR_MASK_TEST(&p_op->fs_attrs, creation_time))
        {
            ATTR_MASK_SET( &p_op->fs_attrs, creation_time );
            ATTR( &p_op->fs_attrs, creation_time ) = time(NULL); /* XXX min(atime,mtime,ctime)? */
        }

#ifdef _LUSTRE
        if (ATTR_MASK_TEST(&p_op->fs_attrs, type)
            && !strcmp(ATTR( &p_op->fs_attrs, type ), STR_TYPE_FILE )
                /* only if it was not retrieved during the scan */
                && !(ATTR_MASK_TEST(&p_op->fs_attrs, stripe_info)
                    && ATTR_MASK_TEST(&p_op->fs_attrs, stripe_items)))
        {
            attr_mask_set_index(&p_op->fs_attr_need, ATTR_INDEX_stripe_info);
            attr_mask_set_index(&p_op->fs_attr_need, ATTR_INDEX_stripe_items);
        }
#endif

        /* readlink for symlinks (if not already known) */
        if (ATTR_MASK_TEST(&p_op->fs_attrs, type)
            && !strcmp(ATTR( &p_op->fs_attrs, type ), STR_TYPE_LINK)
            && !ATTR_MASK_TEST(&p_op->fs_attrs, link))
        {
            attr_mask_set_index(&p_op->fs_attr_need, ATTR_INDEX_link);
        }
        else
        {
            attr_mask_unset_index(&p_op->fs_attr_need, ATTR_INDEX_link);
        }

#ifdef ATTR_INDEX_status /** @FIXME RBHv3 drop old-style status reference */
        if (ATTR_MASK_TEST(&p_op->fs_attrs, type)
#ifdef _LUSTRE_HSM
            && !strcmp( ATTR(&p_op->fs_attrs, type), STR_TYPE_FILE ))
#elif defined (_HSM_LITE)
            && (strcmp( ATTR(&p_op->fs_attrs, type), STR_TYPE_DIR ) != 0)
            && !p_op->extra_info.not_supp)
#endif
        {
            p_op->fs_attr_need |= ATTR_MASK_status;
#ifdef _HSM_LITE
            p_op->fs_attr_need |= (attr_need_fresh & ~p_op->fs_attrs.attr_mask);
#endif
        }
        else
        {
コード例 #3
0
ファイル: rbh_find_printf.c プロジェクト: cea-hpc/robinhood
/* Analyze a format string, and find the next chunk. Each argument is
 * transformed into its real printf type. For instance "%s" means the
 * size, and is stored as an large integer in the database, needs to
 * be displayed as an "%zu". */
static const char *extract_chunk(const char *str, struct fchunk *chunk)
{
    int rc;
    chunk->directive = 0;

    while (*str) {
        if (*str != '%') {
            if (*str == '\\') {
                str++;

                switch (*str) {
                case '\\':
                    g_string_append_c(chunk->format, '\\');
                    break;

                case 'n':
                    g_string_append_c(chunk->format, '\n');
                    break;

                case 't':
                    g_string_append_c(chunk->format, '\t');
                    break;

                case 'x':
                    rc = parse_escaped_int(str+1, chunk, 16);
                    if (rc == 0) {
                        DisplayLog(LVL_CRIT, FIND_TAG,
                                   "Error: invalid \\x not followed by hex in format string");
                        return NULL;
                    }
                    /* need a new chunk for \0, return back to \\ */
                    if (rc == -1)
                        return str - 1;
                    str += rc;
                    break;

                case 0:
                    DisplayLog(LVL_CRIT, FIND_TAG,
                               "Error: lone \\ at end of format string");
                    return NULL;

                default:
                    /* check for octal value */
                    if (*str >= '0' && *str <= '7') {
                        rc = parse_escaped_int(str, chunk, 8);
                        /* need a new chunk for \0, return back to \\ */
                        if (rc == -1)
                            return str - 1;
                        str += rc - 1; /* -1 because no leading character */
                        break;
                    }

                    DisplayLog(LVL_CRIT, FIND_TAG,
                               "Error: unrecognized escape code \\%c", *str);
                    return NULL;
                }
            } else {
                g_string_append_c(chunk->format, *str);
            }

            str++;
            continue;
        }

        if (chunk->directive) {
            /* Already have a directive. Stop here. */
            return str;
        }

        str++;

        if (*str == 0) {
            DisplayLog(LVL_CRIT, FIND_TAG,
                       "Error: lone %% at end of format string");
            return NULL;
        }

        /* Ignore %% as it is a valid printf directive, which saves a
         * chunk. */
        if (*str == '%') {
            g_string_append(chunk->format, "%%");
            str++;
            continue;
        }

        /* Found a new directive */
        g_string_append_c(chunk->format, '%');
        str = extract_field_width(str, chunk->format);
        if (str == NULL) {
            DisplayLog(LVL_CRIT, FIND_TAG,
                       "Error: invalid length field in format string at %s",
                       str);
            return NULL;
        }

        chunk->directive = *str;

        switch (*str) {
        case 'A':
            disp_mask.std |= ATTR_MASK_last_access;
            str = append_time_format(str, chunk);
            if (str == NULL)
                return NULL;
            break;

        case 'b':
            disp_mask.std |= ATTR_MASK_blocks;
            g_string_append(chunk->format, "zu");
            break;

        case 'C':
            disp_mask.std |= ATTR_MASK_last_mdchange;
            str = append_time_format(str, chunk);
            if (str == NULL)
                return NULL;
            break;

        case 'd':
            disp_mask.std |= ATTR_MASK_depth;
            g_string_append_c(chunk->format, 'u');
            break;

        case 'f':
            disp_mask.std |= ATTR_MASK_name;
            g_string_append_c(chunk->format, 's');
            break;

        case 'g':
            disp_mask.std |= ATTR_MASK_gid;
            if (global_config.uid_gid_as_numbers)
                g_string_append_c(chunk->format, 'd');
            else
                g_string_append_c(chunk->format, 's');
            break;

        case 'M':
            disp_mask.std |= ATTR_MASK_mode;
            g_string_append_c(chunk->format, 's');
            break;

        case 'm':
            disp_mask.std |= ATTR_MASK_mode;
            g_string_append_c(chunk->format, 'o');
            break;

        case 'n':
            disp_mask.std |= ATTR_MASK_nlink;
            g_string_append_c(chunk->format, 'u');
            break;

        case 'p':
            g_string_append_c(chunk->format, 's');
            break;

        case 's':
            disp_mask.std |= ATTR_MASK_size;
            g_string_append(chunk->format, "zu");
            break;

        case 'T':
            disp_mask.std |= ATTR_MASK_last_mod;
            str = append_time_format(str, chunk);
            if (str == NULL)
                return NULL;
            break;

        case 'u':
            disp_mask.std |= ATTR_MASK_uid;
            if (global_config.uid_gid_as_numbers)
                g_string_append_c(chunk->format, 'd');
            else
                g_string_append_c(chunk->format, 's');
            break;

        case 'Y':
            disp_mask.std |= ATTR_MASK_type;
            g_string_append_c(chunk->format, 's');
            break;

        case 'y':
            disp_mask.std |= ATTR_MASK_type;
            g_string_append_c(chunk->format, 'c');
            break;

        case 'R':
            str++;
            chunk->sub_directive = *str;

            switch (*str) {
            case 'C':
                disp_mask.std |= ATTR_MASK_creation_time;
                str = append_time_format(str, chunk);
                if (str == NULL)
                    return NULL;
                break;

            case 'c':
                disp_mask.std |= ATTR_MASK_fileclass;
                g_string_append_c(chunk->format, 's');
                break;

            case 'f':
                g_string_append_c(chunk->format, 's');
                break;

            case 'm':
                /* Module name and attribute followed by
                 * format. e.g. "%Rm{lhsm.archive_id}". */
                str++;

                str = extract_mod_attr(str, chunk);
                if (str == NULL) {
                    DisplayLog(LVL_CRIT, FIND_TAG,
                               "Error: cannot extract module attribute name, or invalid name");
                    return NULL;
                }

                attr_mask_set_index(&disp_mask, chunk->attr_index);

                if (strcmp(chunk->def->user_name, "status") == 0) {
                    /* status is a special case. Change the directive
                     * for print_entry(). */
                    chunk->sub_directive = SUB_DIRECTIVE_STATUS;
                    g_string_append_c(chunk->format, 's');

                    break;
                }

                chunk->rel_sm_info_index = attr2sminfo_index(chunk->attr_index)
                                           - chunk->smi->sm_info_offset;

                /* The format for that attribute */
                switch (chunk->def->db_type) {
                case DB_UINT:
                case DB_BOOL:
                    g_string_append_c(chunk->format, 'u');
                    break;

                case DB_INT:
                    g_string_append_c(chunk->format, 'i');
                    break;

                case DB_TEXT:
                    g_string_append_c(chunk->format, 's');
                    break;

                default:
                    DisplayLog(LVL_CRIT, FIND_TAG,
                               "Error: unsupported database format %d",
                               chunk->def->db_type);
                    break;
                }
                break;

            case 'o':
                disp_mask.std |= ATTR_MASK_stripe_items;
                g_string_append_c(chunk->format, 's');
                break;

            case 'p':
                disp_mask.std |= ATTR_MASK_parent_id;
                g_string_append_c(chunk->format, 's');
                break;

            case 0:
                DisplayLog(LVL_CRIT, FIND_TAG,
                           "Error: lone %%R at end of format string");
                return NULL;

            default:
                DisplayLog(LVL_CRIT, FIND_TAG,
                           "Error: unrecognized format %%R%c", *str);
                return NULL;
            }
            break;

        case 0:
            DisplayLog(LVL_CRIT, FIND_TAG,
                       "Error: lone %% at end of format string");
            return NULL;

        default:
            DisplayLog(LVL_CRIT, FIND_TAG, "Error: unrecognized format %%%c",
                       *str);
            return NULL;
        }

        str++;
    }

    return str;
}