Commit message: resovle BUGFIX handle cyclic typedefs with unions

Fixes #724
CVE: CVE-2019-20395
CWE: CWE-674
Vulnerability description: A stack consumption issue is present in libyang before v1.0-r1 due to the self-referential union type containing leafrefs. Applications that use libyang to parse untrusted input yang files may crash.

Project: libyang
File: resolve.c

resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
                          struct unres_schema *unres)
{
    /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
    int rc = -1, has_str = 0, parent_type = 0, i, k;
    unsigned int j;
    struct ly_ctx * ctx = mod->ctx;
    struct lys_node *root, *next, *node, *par_grp;
    const char *expr;
    uint8_t *u;

    struct ly_set *refs, *procs;
    struct lys_feature *ref, *feat;
    struct lys_ident *ident;
    struct lys_type *stype;
    struct lys_node_choice *choic;
    struct lyxml_elem *yin;
    struct yang_type *yang;
    struct unres_list_uniq *unique_info;
    struct unres_iffeat_data *iff_data;
    struct unres_ext *ext_data;
    struct lys_ext_instance *ext, **extlist;
    struct lyext_plugin *eplugin;

    switch (type) {
    case UNRES_IDENT:
        expr = str_snode;
        has_str = 1;
        ident = item;

        rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
        break;
    case UNRES_TYPE_IDENTREF:
        expr = str_snode;
        has_str = 1;
        stype = item;

        rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
        break;
    case UNRES_TYPE_LEAFREF:
        node = str_snode;
        stype = item;

        rc = resolve_schema_leafref(stype, node, unres);
        break;
    case UNRES_TYPE_DER_EXT:
        parent_type++;
        /* falls through */
    case UNRES_TYPE_DER_TPDF:
        parent_type++;
        /* falls through */
    case UNRES_TYPE_DER:
        /* parent */
        node = str_snode;
        stype = item;

        /* HACK type->der is temporarily unparsed type statement */
        yin = (struct lyxml_elem *)stype->der;
        stype->der = NULL;

        if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
            yang = (struct yang_type *)yin;
            rc = yang_check_type(mod, node, yang, stype, parent_type, unres);

            if (rc) {
                /* may try again later */
                stype->der = (struct lys_tpdf *)yang;
            } else {
                /* we need to always be able to free this, it's safe only in this case */
                lydict_remove(ctx, yang->name);
                free(yang);
            }

        } else {
            rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
            if (!rc || rc == -1) {
                /* we need to always be able to free this, it's safe only in this case */
                lyxml_free(ctx, yin);
            } else {
                /* may try again later, put all back how it was */
                stype->der = (struct lys_tpdf *)yin;
            }
        }
        if (rc == EXIT_SUCCESS) {
            /* it does not make sense to have leaf-list of empty type */
            if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
                LOGWRN(ctx, "The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
            }

            if ((type == UNRES_TYPE_DER_TPDF) && (stype->base == LY_TYPE_UNION)) {
                /* fill typedef union leafref flag */
                ((struct lys_tpdf *)stype->parent)->has_union_leafref = check_type_union_leafref(stype);
            } else if ((type == UNRES_TYPE_DER) && stype->der->has_union_leafref) {
                /* copy the type in case it has union leafref flag */
                if (lys_copy_union_leafrefs(mod, node, stype, NULL, unres)) {
                    LOGERR(ctx, LY_EINT, "Failed to duplicate type.");
                    return -1;
                }
            }
        } else if (rc == EXIT_FAILURE && !(stype->value_flags & LY_VALUE_UNRESGRP)) {
            /* forward reference - in case the type is in grouping, we have to make the grouping unusable
             * by uses statement until the type is resolved. We do that the same way as uses statements inside
             * grouping. The grouping cannot be used unless the unres counter is 0.
             * To remember that the grouping already increased the counter, the LYTYPE_GRP is used as value
             * of the type's base member. */
            for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
            if (par_grp) {
                if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
                    LOGERR(ctx, LY_EINT, "Too many unresolved items (type) inside a grouping.");
                    return -1;
                }
                stype->value_flags |= LY_VALUE_UNRESGRP;
            }
        }
        break;
    case UNRES_IFFEAT:
        iff_data = str_snode;
        rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
        if (!rc) {
            /* success */
            if (iff_data->infeature) {
                /* store backlink into the target feature to allow reverse changes in case of changing feature status */
                feat = *((struct lys_feature **)item);
                if (!feat->depfeatures) {
                    feat->depfeatures = ly_set_new();
                }
                ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
            }
            /* cleanup temporary data */
            lydict_remove(ctx, iff_data->fname);
            free(iff_data);
        }
        break;
    case UNRES_FEATURE:
        feat = (struct lys_feature *)item;

        if (feat->iffeature_size) {
            refs = ly_set_new();
            procs = ly_set_new();
            ly_set_add(procs, feat, 0);

            while (procs->number) {
                ref = procs->set.g[procs->number - 1];
                ly_set_rm_index(procs, procs->number - 1);

                for (i = 0; i < ref->iffeature_size; i++) {
                    resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
                    for (; j > 0 ; j--) {
                        if (ref->iffeature[i].features[j - 1]) {
                            if (ref->iffeature[i].features[j - 1] == feat) {
                                LOGVAL(ctx, LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
                                goto featurecheckdone;
                            }

                            if (ref->iffeature[i].features[j - 1]->iffeature_size) {
                                k = refs->number;
                                if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
                                    /* not yet seen feature, add it for processing */
                                    ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
                                }
                            }
                        } else {
                            /* forward reference */
                            rc = EXIT_FAILURE;
                            goto featurecheckdone;
                        }
                    }

                }
            }
            rc = EXIT_SUCCESS;

featurecheckdone:
            ly_set_free(refs);
            ly_set_free(procs);
        }

        break;
    case UNRES_USES:
        rc = resolve_unres_schema_uses(item, unres);
        break;
    case UNRES_TYPEDEF_DFLT:
        parent_type++;
        /* falls through */
    case UNRES_TYPE_DFLT:
        stype = item;
        rc = check_default(stype, (const char **)str_snode, mod, parent_type);
        if ((rc == EXIT_FAILURE) && !parent_type && (stype->base == LY_TYPE_LEAFREF)) {
            for (par_grp = (struct lys_node *)stype->parent;
                 par_grp && (par_grp->nodetype != LYS_GROUPING);
                 par_grp = lys_parent(par_grp));
            if (par_grp) {
                /* checking default value in a grouping finished with forward reference means we cannot check the value */
                rc = EXIT_SUCCESS;
            }
        }
        break;
    case UNRES_CHOICE_DFLT:
        expr = str_snode;
        has_str = 1;
        choic = item;

        if (!choic->dflt) {
            choic->dflt = resolve_choice_dflt(choic, expr);
        }
        if (choic->dflt) {
            rc = lyp_check_mandatory_choice((struct lys_node *)choic);
        } else {
            rc = EXIT_FAILURE;
        }
        break;
    case UNRES_LIST_KEYS:
        rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
        break;
    case UNRES_LIST_UNIQ:
        unique_info = (struct unres_list_uniq *)item;
        rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
        break;
    case UNRES_AUGMENT:
        rc = resolve_augment(item, NULL, unres);
        break;
    case UNRES_XPATH:
        node = (struct lys_node *)item;
        rc = check_xpath(node, 1);
        break;
    case UNRES_MOD_IMPLEMENT:
        rc = lys_make_implemented_r(mod, unres);
        break;
    case UNRES_EXT:
        ext_data = (struct unres_ext *)str_snode;
        extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
        rc = resolve_extension(ext_data, extlist, unres);
        if (!rc) {
            /* success */
            /* is there a callback to be done to finalize the extension? */
            eplugin = extlist[0]->def->plugin;
            if (eplugin) {
                if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
                    u = malloc(sizeof *u);
                    LY_CHECK_ERR_RETURN(!u, LOGMEM(ctx), -1);
                    (*u) = ext_data->ext_index;
                    if (unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u) == -1) {
                        /* something really bad happend since the extension finalization is not actually
                         * being resolved while adding into unres, so something more serious with the unres
                         * list itself must happened */
                        return -1;
                    }
                }
            }
        }
        if (!rc || rc == -1) {
            /* cleanup on success or fatal error */
            if (ext_data->datatype == LYS_IN_YIN) {
                /* YIN */
                lyxml_free(ctx, ext_data->data.yin);
            } else {
                /* YANG */
                yang_free_ext_data(ext_data->data.yang);
            }
            free(ext_data);
        }
        break;
    case UNRES_EXT_FINALIZE:
        u = (uint8_t *)str_snode;
        ext = (*(struct lys_ext_instance ***)item)[*u];
        free(u);

        eplugin = ext->def->plugin;

        /* inherit */
        if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
            root = (struct lys_node *)ext->parent;
            if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
                LY_TREE_DFS_BEGIN(root->child, next, node) {
                    /* first, check if the node already contain instance of the same extension,
                     * in such a case we won't inherit. In case the node was actually defined as
                     * augment data, we are supposed to check the same way also the augment node itself */
                    if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
                        goto inherit_dfs_sibling;
                    } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
                            lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
                        goto inherit_dfs_sibling;
                    }

                    if (eplugin->check_inherit) {
                        /* we have a callback to check the inheritance, use it */
                        switch ((rc = (*eplugin->check_inherit)(ext, node))) {
                        case 0:
                            /* yes - continue with the inheriting code */
                            break;
                        case 1:
                            /* no - continue with the node's sibling */
                            goto inherit_dfs_sibling;
                        case 2:
                            /* no, but continue with the children, just skip the inheriting code for this node */
                            goto inherit_dfs_child;
                        default:
                            LOGERR(ctx, LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
                                   ext->def->module->name, ext->def->name, rc);
                        }
                    }

                    /* inherit the extension */
                    extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
                    LY_CHECK_ERR_RETURN(!extlist, LOGMEM(ctx), -1);
                    extlist[node->ext_size] = malloc(sizeof **extlist);
                    LY_CHECK_ERR_RETURN(!extlist[node->ext_size], LOGMEM(ctx); node->ext = extlist, -1);
                    memcpy(extlist[node->ext_size], ext, sizeof *ext);
                    extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;

                    node->ext = extlist;
                    node->ext_size++;

inherit_dfs_child:
                    /* modification of - select element for the next run - children first */
                    if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
                        next = NULL;
                    } else {
                        next = node->child;
                    }
                    if (!next) {
inherit_dfs_sibling:
                        /* no children, try siblings */
                        next = node->next;
                    }
                    while (!next) {
                        /* go to the parent */
                        node = lys_parent(node);

                        /* we are done if we are back in the root (the starter's parent */
                        if (node == root) {
                            break;
                        }

                        /* parent is already processed, go to its sibling */
                        next = node->next;
                    }
                }
            }
        }

        /* final check */
        if (eplugin->check_result) {
            if ((*eplugin->check_result)(ext)) {
                LOGERR(ctx, LY_EPLUGIN, "Resolving extension failed.");
                return -1;
            }
        }

        rc = 0;
        break;
    default:
        LOGINT(ctx);
        break;
    }

    if (has_str && !rc) {
        /* the string is no more needed in case of success.
         * In case of forward reference, we will try to resolve the string later */
        lydict_remove(ctx, str_snode);
    }

    return rc;
}

Project: libyang
File: resolve.c

resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
{
    const char *mod_name, *name;
    int mod_name_len, nam_len, has_predicate, i;
    struct lys_node *key;

    if (((i = parse_schema_json_predicate(predicate, &mod_name, &mod_name_len, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
            || !strncmp(name, ".", nam_len)) {
        LOGVAL(list->module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
        return -1;
    }

    predicate += i;
    *parsed += i;

    if (!isdigit(name[0])) {
        for (i = 0; i < list->keys_size; ++i) {
            key = (struct lys_node *)list->keys[i];
            if (!strncmp(key->name, name, nam_len) && !key->name[nam_len]) {
                break;
            }
        }

        if (i == list->keys_size) {
            LOGVAL(list->module->ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
            return -1;
        }
    }

    /* more predicates? */
    if (has_predicate) {
        return resolve_json_schema_list_predicate(predicate, list, parsed);
    }

    return 0;
}

Project: libyang
File: resolve.c

resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
{
    int i;

    assert(der && base);

    if (!base->der) {
        /* create a set for backlinks if it does not exist */
        base->der = ly_set_new();
    }
    /* store backlink */
    ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);

    /* do it recursively */
    for (i = 0; i < base->base_size; i++) {
        resolve_identity_backlink_update(der, base->base[i]);
    }
}

Project: libyang
File: resolve.c

unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
{
    struct lyxml_elem *yin;
    struct yang_type *yang;
    struct unres_iffeat_data *iff_data;

    switch (unres->type[i]) {
    case UNRES_TYPE_DER_TPDF:
    case UNRES_TYPE_DER:
        yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
        if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
            yang =(struct yang_type *)yin;
            ((struct lys_type *)unres->item[i])->base = yang->base;
            lydict_remove(ctx, yang->name);
            free(yang);
            if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
                yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
            }
        } else {
            lyxml_free(ctx, yin);
        }
        break;
    case UNRES_IFFEAT:
        iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
        lydict_remove(ctx, iff_data->fname);
        free(unres->str_snode[i]);
        break;
    case UNRES_IDENT:
    case UNRES_TYPE_IDENTREF:
    case UNRES_CHOICE_DFLT:
    case UNRES_LIST_KEYS:
        lydict_remove(ctx, (const char *)unres->str_snode[i]);
        break;
    case UNRES_LIST_UNIQ:
        free(unres->item[i]);
        break;
    case UNRES_EXT:
        free(unres->str_snode[i]);
        break;
    case UNRES_EXT_FINALIZE:
        free(unres->str_snode[i]);
    default:
        break;
    }
    unres->type[i] = UNRES_RESOLVED;
}

Project: libyang
File: resolve.c

resolve_schema_leafref(struct lys_type *type, struct lys_node *parent, struct unres_schema *unres)
{
    const struct lys_node *node, *op_node = NULL, *tmp_parent;
    struct lys_node_augment *last_aug;
    const struct lys_module *tmp_mod, *cur_module;
    const char *id, *prefix, *name;
    int pref_len, nam_len, parent_times, has_predicate;
    int i, first_iter;
    struct ly_ctx *ctx = parent->module->ctx;

    if (!type->info.lref.target) {
        first_iter = 1;
        parent_times = 0;
        id = type->info.lref.path;

        /* find operation schema we are in */
        for (op_node = lys_parent(parent);
            op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
            op_node = lys_parent(op_node));

        cur_module = lys_node_module(parent);
        do {
            if ((i = parse_path_arg(cur_module, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
                LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
                return -1;
            }
            id += i;

            /* get the current module */
            tmp_mod = prefix ? lyp_get_module(cur_module, NULL, 0, prefix, pref_len, 0) : cur_module;
            if (!tmp_mod) {
                LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
                return EXIT_FAILURE;
            }
            last_aug = NULL;

            if (first_iter) {
                if (parent_times == -1) {
                    /* use module data */
                    node = NULL;

                } else if (parent_times > 0) {
                    /* we are looking for the right parent */
                    for (i = 0, node = parent; i < parent_times; i++) {
                        if (node->parent && (node->parent->nodetype == LYS_AUGMENT)
                                && !((struct lys_node_augment *)node->parent)->target) {
                            /* we are in an unresolved augment, cannot evaluate */
                            LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, node->parent,
                                "Cannot resolve leafref \"%s\" because it is in an unresolved augment.", type->info.lref.path);
                            return EXIT_FAILURE;
                        }

                        /* path is supposed to be evaluated in data tree, so we have to skip
                        * all schema nodes that cannot be instantiated in data tree */
                        for (node = lys_parent(node);
                            node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
                            node = lys_parent(node));

                        if (!node) {
                            if (i == parent_times - 1) {
                                /* top-level */
                                break;
                            }

                            /* higher than top-level */
                            LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
                            return EXIT_FAILURE;
                        }
                    }
                } else {
                    LOGINT(ctx);
                    return -1;
                }
            }

            /* find the next node (either in unconnected augment or as a schema sibling, node is NULL for top-level node -
            * - useless to search for that in augments) */
            if (!tmp_mod->implemented && node) {
    get_next_augment:
                last_aug = lys_getnext_target_aug(last_aug, tmp_mod, node);
            }

            tmp_parent = (last_aug ? (struct lys_node *)last_aug : node);
            node = NULL;
            while ((node = lys_getnext(node, tmp_parent, tmp_mod, LYS_GETNEXT_NOSTATECHECK))) {
                if (lys_node_module(node) != lys_main_module(tmp_mod)) {
                    continue;
                }
                if (strncmp(node->name, name, nam_len) || node->name[nam_len]) {
                    continue;
                }
                /* match */
                break;
            }
            if (!node) {
                if (last_aug) {
                    /* restore the correct augment target */
                    node = last_aug->target;
                    goto get_next_augment;
                }
                LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
                return EXIT_FAILURE;
            }

            if (first_iter) {
                /* set external dependency flag, we can decide based on the first found node */
                if (resolve_schema_leafref_valid_dep_flag(op_node, cur_module, node, (parent_times == -1 ? 1 : 0))) {
                    parent->flags |= LYS_LEAFREF_DEP;
                }
                first_iter = 0;
            }

            if (has_predicate) {
                /* we have predicate, so the current result must be list */
                if (node->nodetype != LYS_LIST) {
                    LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
                    return -1;
                }

                i = resolve_schema_leafref_predicate(id, node, parent);
                if (!i) {
                    return EXIT_FAILURE;
                } else if (i < 0) {
                    return -1;
                }
                id += i;
                has_predicate = 0;
            }
        } while (id[0]);

        /* the target must be leaf or leaf-list (in YANG 1.1 only) */
        if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
            LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
            LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Leafref target \"%s\" is not a leaf nor a leaf-list.", type->info.lref.path);
            return -1;
        }

        /* check status */
        if (lyp_check_status(parent->flags, parent->module, parent->name,
                        node->flags, node->module, node->name, node)) {
            return -1;
        }

        /* assign */
        type->info.lref.target = (struct lys_node_leaf *)node;
    }

    /* as the last thing traverse this leafref and make targets on the path implemented */
    if (lys_node_module(parent)->implemented) {
        /* make all the modules in the path implemented */
        for (node = (struct lys_node *)type->info.lref.target; node; node = lys_parent(node)) {
            if (!lys_node_module(node)->implemented) {
                lys_node_module(node)->implemented = 1;
                if (unres_schema_add_node(lys_node_module(node), unres, NULL, UNRES_MOD_IMPLEMENT, NULL) == -1) {
                    return -1;
                }
            }
        }

        /* store the backlink from leafref target */
        if (lys_leaf_add_leafref_target(type->info.lref.target, (struct lys_node *)type->parent)) {
            return -1;
        }
    }

    /* check if leafref and its target are under common if-features */
    return check_leafref_features(type);
}

Project: libyang
File: resolve.c

resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
{
    int i = 0, j, parsed, cur_idx;
    const struct lys_module *mod, *prev_mod = NULL;
    struct ly_ctx *ctx = data->schema->module->ctx;
    struct lyd_node *root, *node;
    const char *model = NULL, *name;
    char *str;
    int mod_len, name_len, has_predicate;
    struct unres_data node_match;

    memset(&node_match, 0, sizeof node_match);
    *ret = NULL;

    /* we need root to resolve absolute path */
    for (root = data; root->parent; root = root->parent);
    /* we're still parsing it and the pointer is not correct yet */
    if (root->prev) {
        for (; root->prev->next; root = root->prev);
    }

    /* search for the instance node */
    while (path[i]) {
        j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
        if (j <= 0) {
            LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
            goto error;
        }
        i += j;

        if (model) {
            str = strndup(model, mod_len);
            if (!str) {
                LOGMEM(ctx);
                goto error;
            }
            mod = ly_ctx_get_module(ctx, str, NULL, 1);
            if (ctx->data_clb) {
                if (!mod) {
                    mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
                } else if (!mod->implemented) {
                    mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
                }
            }
            free(str);

            if (!mod || !mod->implemented || mod->disabled) {
                break;
            }
        } else if (!prev_mod) {
            /* first iteration and we are missing module name */
            LOGVAL(ctx, LYE_INELEM_LEN, LY_VLOG_LYD, data, name_len, name);
            LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Instance-identifier is missing prefix in the first node.");
            goto error;
        } else {
            mod = prev_mod;
        }

        if (resolve_data(mod, name, name_len, root, &node_match)) {
            /* no instance exists */
            break;
        }

        if (has_predicate) {
            /* we have predicate, so the current results must be list or leaf-list */
            parsed = j = 0;
            /* index of the current node (for lists with position predicates) */
            cur_idx = 1;
            while (j < (signed)node_match.count) {
                node = node_match.node[j];
                parsed = resolve_instid_predicate(mod, &path[i], &node, cur_idx);
                if (parsed < 1) {
                    LOGVAL(ctx, LYE_INPRED, LY_VLOG_LYD, data, &path[i - parsed]);
                    goto error;
                }

                if (!node) {
                    /* current node does not satisfy the predicate */
                    unres_data_del(&node_match, j);
                } else {
                    ++j;
                }
                ++cur_idx;
            }

            i += parsed;
        } else if (node_match.count) {
            /* check that we are not addressing lists */
            for (j = 0; (unsigned)j < node_match.count; ++j) {
                if (node_match.node[j]->schema->nodetype == LYS_LIST) {
                    unres_data_del(&node_match, j--);
                }
            }
            if (!node_match.count) {
                LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYD, data, "Instance identifier is missing list keys.");
            }
        }

        prev_mod = mod;
    }

    if (!node_match.count) {
        /* no instance exists */
        if (req_inst > -1) {
            LOGVAL(ctx, LYE_NOREQINS, LY_VLOG_LYD, data, path);
            return EXIT_FAILURE;
        }
        LOGVRB("There is no instance of \"%s\", but it is not required.", path);
        return EXIT_SUCCESS;
    } else if (node_match.count > 1) {
        /* instance identifier must resolve to a single node */
        LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
        goto error;
    } else {
        /* we have required result, remember it and cleanup */
        *ret = node_match.node[0];
        free(node_match.node);
        return EXIT_SUCCESS;
    }

error:
    /* cleanup */
    free(node_match.node);
    return -1;
}

Project: libyang
File: resolve.c

iff_stack_pop(struct iff_stack *stack)
{
    stack->index--;
    return stack->stack[stack->index];
}

Project: libyang
File: resolve.c

unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
{
    int i;
    struct unres_list_uniq *aux_uniq1, *aux_uniq2;

    if (!unres->count) {
        return -1;
    }

    if (start_on_backwards >= 0) {
        i = start_on_backwards;
    } else {
        i = unres->count - 1;
    }
    for (; i > -1; i--) {
        if (unres->type[i] != type) {
            continue;
        }
        if (type != UNRES_LIST_UNIQ) {
            if (unres->item[i] == item) {
                break;
            }
        } else {
            aux_uniq1 = (struct unres_list_uniq *)unres->item[i];
            aux_uniq2 = (struct unres_list_uniq *)item;
            if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
                break;
            }
        }
    }

    return i;
}

Project: libyang
File: resolve.c

resolve_applies_must(const struct lyd_node *node)
{
    int ret = 0;
    uint8_t must_size;
    struct lys_node *schema, *iter;

    assert(node);

    schema = node->schema;

    /* their own must */
    switch (schema->nodetype) {
    case LYS_CONTAINER:
        must_size = ((struct lys_node_container *)schema)->must_size;
        break;
    case LYS_LEAF:
        must_size = ((struct lys_node_leaf *)schema)->must_size;
        break;
    case LYS_LEAFLIST:
        must_size = ((struct lys_node_leaflist *)schema)->must_size;
        break;
    case LYS_LIST:
        must_size = ((struct lys_node_list *)schema)->must_size;
        break;
    case LYS_ANYXML:
    case LYS_ANYDATA:
        must_size = ((struct lys_node_anydata *)schema)->must_size;
        break;
    case LYS_NOTIF:
        must_size = ((struct lys_node_notif *)schema)->must_size;
        break;
    default:
        must_size = 0;
        break;
    }

    if (must_size) {
        ++ret;
    }

    /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
    if (!node->prev->next) {
        for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
        if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
            ret += 0x2;
        }
    }

    return ret;
}

Project: libyang
File: resolve.c

valequal(struct lys_node *node, const char *noncan_val, int noncan_val_len, const char *can_val)
{
    int ret;
    struct lyd_node_leaf_list leaf;
    struct lys_node_leaf *sleaf = (struct lys_node_leaf*)node;

    /* dummy leaf */
    memset(&leaf, 0, sizeof leaf);
    leaf.value_str = lydict_insert(node->module->ctx, noncan_val, noncan_val_len);

repeat:
    leaf.value_type = sleaf->type.base;
    leaf.schema = node;

    if (leaf.value_type == LY_TYPE_LEAFREF) {
        if (!sleaf->type.info.lref.target) {
            /* it should either be unresolved leafref (leaf.value_type are ORed flags) or it will be resolved */
            LOGINT(node->module->ctx);
            ret = -1;
            goto finish;
        }
        sleaf = sleaf->type.info.lref.target;
        goto repeat;
    } else {
        if (!lyp_parse_value(&sleaf->type, &leaf.value_str, NULL, &leaf, NULL, NULL, 0, 0, 0)) {
            ret = -1;
            goto finish;
        }
    }

    if (!strcmp(leaf.value_str, can_val)) {
        ret = 1;
    } else {
        ret = 0;
    }

finish:
    lydict_remove(node->module->ctx, leaf.value_str);
    return ret;
}

Project: libyang
File: resolve.c

resolve_instid_predicate(const struct lys_module *prev_mod, const char *pred, struct lyd_node **node, int cur_idx)
{
    /* ... /node[key=value] ... */
    struct lyd_node_leaf_list *key;
    struct lys_node_leaf **list_keys = NULL;
    struct lys_node_list *slist = NULL;
    const char *model, *name, *value;
    int mod_len, nam_len, val_len, i, has_predicate, parsed;
    struct ly_ctx *ctx = prev_mod->ctx;

    assert(pred && node && *node);

    parsed = 0;
    do {
        if ((i = parse_predicate(pred + parsed, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
            return -parsed + i;
        }
        parsed += i;

        if (!(*node)) {
            /* just parse it all */
            continue;
        }

        /* target */
        if (name[0] == '.') {
            /* leaf-list value */
            if ((*node)->schema->nodetype != LYS_LEAFLIST) {
                LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects leaf-list, but have %s \"%s\".",
                       strnodetype((*node)->schema->nodetype), (*node)->schema->name);
                parsed = -1;
                goto cleanup;
            }

            /* check the value */
            if (!valequal((*node)->schema, value, val_len, ((struct lyd_node_leaf_list *)*node)->value_str)) {
                *node = NULL;
                goto cleanup;
            }

        } else if (isdigit(name[0])) {
            assert(!value);

            /* keyless list position */
            if ((*node)->schema->nodetype != LYS_LIST) {
                LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
                       strnodetype((*node)->schema->nodetype), (*node)->schema->name);
                parsed = -1;
                goto cleanup;
            }

            if (((struct lys_node_list *)(*node)->schema)->keys) {
                LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list without keys, but have list \"%s\".",
                       (*node)->schema->name);
                parsed = -1;
                goto cleanup;
            }

            /* check the index */
            if (atoi(name) != cur_idx) {
                *node = NULL;
                goto cleanup;
            }

        } else {
            /* list key value */
            if ((*node)->schema->nodetype != LYS_LIST) {
                LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
                       strnodetype((*node)->schema->nodetype), (*node)->schema->name);
                parsed = -1;
                goto cleanup;
            }
            slist = (struct lys_node_list *)(*node)->schema;

            /* prepare key array */
            if (!list_keys) {
                list_keys = malloc(slist->keys_size * sizeof *list_keys);
                LY_CHECK_ERR_RETURN(!list_keys, LOGMEM(ctx), -1);
                for (i = 0; i < slist->keys_size; ++i) {
                    list_keys[i] = slist->keys[i];
                }
            }

            /* find the schema key leaf */
            for (i = 0; i < slist->keys_size; ++i) {
                if (list_keys[i] && !strncmp(list_keys[i]->name, name, nam_len) && !list_keys[i]->name[nam_len]) {
                    break;
                }
            }
            if (i == slist->keys_size) {
                /* this list has no such key */
                LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list with the key \"%.*s\","
                       " but list \"%s\" does not define it.", nam_len, name, slist->name);
                parsed = -1;
                goto cleanup;
            }

            /* check module */
            if (model) {
                if (strncmp(list_keys[i]->module->name, model, mod_len) || list_keys[i]->module->name[mod_len]) {
                    LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects key \"%s\" from module \"%.*s\", not \"%s\".",
                           list_keys[i]->name, model, mod_len, list_keys[i]->module->name);
                    parsed = -1;
                    goto cleanup;
                }
            } else {
                if (list_keys[i]->module != prev_mod) {
                    LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects key \"%s\" from module \"%s\", not \"%s\".",
                           list_keys[i]->name, prev_mod->name, list_keys[i]->module->name);
                    parsed = -1;
                    goto cleanup;
                }
            }

            /* find the actual data key */
            for (key = (struct lyd_node_leaf_list *)(*node)->child; key; key = (struct lyd_node_leaf_list *)key->next) {
                if (key->schema == (struct lys_node *)list_keys[i]) {
                    break;
                }
            }
            if (!key) {
                /* list instance is missing a key? definitely should not happen */
                LOGINT(ctx);
                parsed = -1;
                goto cleanup;
            }

            /* check the value */
            if (!valequal(key->schema, value, val_len, key->value_str)) {
                *node = NULL;
                /* we still want to parse the whole predicate */
                continue;
            }

            /* everything is fine, mark this key as resolved */
            list_keys[i] = NULL;
        }
    } while (has_predicate);

    /* check that all list keys were specified */
    if (*node && list_keys) {
        for (i = 0; i < slist->keys_size; ++i) {
            if (list_keys[i]) {
                LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing list key \"%s\".", list_keys[i]->name);
                parsed = -1;
                goto cleanup;
            }
        }
    }

cleanup:
    free(list_keys);
    return parsed;
}

Project: libyang
File: resolve.c

resolve_list_keys(struct lys_node_list *list, const char *keys_str)
{
    int i, len, rc;
    const char *value;
    char *s = NULL;
    struct ly_ctx *ctx = list->module->ctx;

    for (i = 0; i < list->keys_size; ++i) {
        assert(keys_str);

        if (!list->child) {
            /* no child, possible forward reference */
            LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
            return EXIT_FAILURE;
        }
        /* get the key name */
        if ((value = strpbrk(keys_str, " \t\n"))) {
            len = value - keys_str;
            while (isspace(value[0])) {
                value++;
            }
        } else {
            len = strlen(keys_str);
        }

        rc = lys_getnext_data(lys_node_module((struct lys_node *)list), (struct lys_node *)list, keys_str, len, LYS_LEAF,
                              LYS_GETNEXT_NOSTATECHECK, (const struct lys_node **)&list->keys[i]);
        if (rc) {
            LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list key", keys_str);
            return EXIT_FAILURE;
        }

        if (check_key(list, i, keys_str, len)) {
            /* check_key logs */
            return -1;
        }

        /* check status */
        if (lyp_check_status(list->flags, list->module, list->name,
                             list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
                             (struct lys_node *)list->keys[i])) {
            return -1;
        }

        /* default value - is ignored, keep it but print a warning */
        if (list->keys[i]->dflt) {
            /* log is not hidden only in case this resolving fails and in such a case
             * we cannot get here
             */
            assert(log_opt == ILO_STORE);
            log_opt = ILO_LOG;
            LOGWRN(ctx, "Default value \"%s\" in the list key \"%s\" is ignored. (%s)", list->keys[i]->dflt,
                   list->keys[i]->name, s = lys_path((struct lys_node*)list, LYS_PATH_FIRST_PREFIX));
            log_opt = ILO_STORE;
            free(s);
        }

        /* prepare for next iteration */
        while (value && isspace(value[0])) {
            value++;
        }
        keys_str = value;
    }

    return EXIT_SUCCESS;
}

Project: libyang
File: resolve.c

parse_identifier(const char *id)
{
    unsigned int parsed = 0;

    assert(id);

    if (!isalpha(id[0]) && (id[0] != '_')) {
        return -parsed;
    }

    ++parsed;
    ++id;

    while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
        ++parsed;
        ++id;
    }

    return parsed;
}

Project: libyang
File: resolve.c

resolve_unres_data(struct ly_ctx *ctx, struct unres_data *unres, struct lyd_node **root, int options)
{
    uint32_t i, j, first, resolved, del_items, stmt_count;
    uint8_t prev_when_status;
    int rc, progress, ignore_fail;
    enum int_log_opts prev_ilo;
    struct ly_err_item *prev_eitem;
    LY_ERR prev_ly_errno = ly_errno;
    struct lyd_node *parent;
    struct lys_when *when;

    assert(root);
    assert(unres);

    if (!unres->count) {
        return EXIT_SUCCESS;
    }

    if (options & (LYD_OPT_NOTIF_FILTER | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT)) {
        ignore_fail = 1;
    } else if (options & LYD_OPT_NOEXTDEPS) {
        ignore_fail = 2;
    } else {
        ignore_fail = 0;
    }

    LOGVRB("Resolving unresolved data nodes and their constraints...");
    if (!ignore_fail) {
        /* remember logging state only if errors are generated and valid */
        ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
    }

    /*
     * when-stmt first
     */
    first = 1;
    stmt_count = 0;
    resolved = 0;
    del_items = 0;
    do {
        if (!ignore_fail) {
            ly_err_free_next(ctx, prev_eitem);
        }
        progress = 0;
        for (i = 0; i < unres->count; i++) {
            if (unres->type[i] != UNRES_WHEN) {
                continue;
            }
            if (first) {
                /* count when-stmt nodes in unres list */
                stmt_count++;
            }

            /* resolve when condition only when all parent when conditions are already resolved */
            for (parent = unres->node[i]->parent;
                 parent && LYD_WHEN_DONE(parent->when_status);
                 parent = parent->parent) {
                if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
                    /* the parent node was already unlinked, do not resolve this node,
                     * it will be removed anyway, so just mark it as resolved
                     */
                    unres->node[i]->when_status |= LYD_WHEN_FALSE;
                    unres->type[i] = UNRES_RESOLVED;
                    resolved++;
                    break;
                }
            }
            if (parent) {
                continue;
            }

            prev_when_status = unres->node[i]->when_status;
            rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, &when);
            if (!rc) {
                /* finish with error/delete the node only if when was changed from true to false, an external
                 * dependency was not required, or it was not provided (the flag would not be passed down otherwise,
                 * checked in upper functions) */
                if ((unres->node[i]->when_status & LYD_WHEN_FALSE)
                        && (!(when->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP)) || !(options & LYD_OPT_NOEXTDEPS))) {
                    if ((!(prev_when_status & LYD_WHEN_TRUE) || !(options & LYD_OPT_WHENAUTODEL)) && !unres->node[i]->dflt) {
                        /* false when condition */
                        goto error;
                    } /* follows else */

                    /* auto-delete */
                    LOGVRB("Auto-deleting node \"%s\" due to when condition (%s)", ly_errpath(ctx), when->cond);

                    /* only unlink now, the subtree can contain another nodes stored in the unres list */
                    /* if it has parent non-presence containers that would be empty, we should actually
                     * remove the container
                     */
                    for (parent = unres->node[i];
                            parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
                            parent = parent->parent) {
                        if (((struct lys_node_container *)parent->parent->schema)->presence) {
                            /* presence container */
                            break;
                        }
                        if (parent->next || parent->prev != parent) {
                            /* non empty (the child we are in and we are going to remove is not the only child) */
                            break;
                        }
                    }
                    unres->node[i] = parent;

                    if (*root && *root == unres->node[i]) {
                        *root = (*root)->next;
                    }

                    lyd_unlink(unres->node[i]);
                    unres->type[i] = UNRES_DELETE;
                    del_items++;

                    /* update the rest of unres items */
                    for (j = 0; j < unres->count; j++) {
                        if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
                            continue;
                        }

                        /* test if the node is in subtree to be deleted */
                        for (parent = unres->node[j]; parent; parent = parent->parent) {
                            if (parent == unres->node[i]) {
                                /* yes, it is */
                                unres->type[j] = UNRES_RESOLVED;
                                resolved++;
                                break;
                            }
                        }
                    }
                } else {
                    unres->type[i] = UNRES_RESOLVED;
                }
                if (!ignore_fail) {
                    ly_err_free_next(ctx, prev_eitem);
                }
                resolved++;
                progress = 1;
            } else if (rc == -1) {
                goto error;
            } /* else forward reference */
        }
        first = 0;
    } while (progress && resolved < stmt_count);

    /* do we have some unresolved when-stmt? */
    if (stmt_count > resolved) {
        goto error;
    }

    for (i = 0; del_items && i < unres->count; i++) {
        /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
        if (unres->type[i] != UNRES_DELETE) {
            continue;
        }
        if (!unres->node[i]) {
            unres->type[i] = UNRES_RESOLVED;
            del_items--;
            continue;
        }

        if (unres->store_diff) {
            resolve_unres_data_autodel_diff(unres, i);
        }

        /* really remove the complete subtree */
        lyd_free(unres->node[i]);
        unres->type[i] = UNRES_RESOLVED;
        del_items--;
    }

    /*
     * now leafrefs
     */
    if (options & LYD_OPT_TRUSTED) {
        /* we want to attempt to resolve leafrefs */
        assert(!ignore_fail);
        ignore_fail = 1;

        ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
        ly_errno = prev_ly_errno;
    }
    first = 1;
    stmt_count = 0;
    resolved = 0;
    do {
        progress = 0;
        for (i = 0; i < unres->count; i++) {
            if (unres->type[i] != UNRES_LEAFREF) {
                continue;
            }
            if (first) {
                /* count leafref nodes in unres list */
                stmt_count++;
            }

            rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
            if (!rc) {
                unres->type[i] = UNRES_RESOLVED;
                if (!ignore_fail) {
                    ly_err_free_next(ctx, prev_eitem);
                }
                resolved++;
                progress = 1;
            } else if (rc == -1) {
                goto error;
            } /* else forward reference */
        }
        first = 0;
    } while (progress && resolved < stmt_count);

    /* do we have some unresolved leafrefs? */
    if (stmt_count > resolved) {
        goto error;
    }

    if (!ignore_fail) {
        /* log normally now, throw away irrelevant errors */
        ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
        ly_errno = prev_ly_errno;
    }

    /*
     * rest
     */
    for (i = 0; i < unres->count; ++i) {
        if (unres->type[i] == UNRES_RESOLVED) {
            continue;
        }
        assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));

        rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
        if (rc) {
            /* since when was already resolved, a forward reference is an error */
            return -1;
        }

        unres->type[i] = UNRES_RESOLVED;
    }

    LOGVRB("All data nodes and constraints resolved.");
    unres->count = 0;
    return EXIT_SUCCESS;

error:
    if (!ignore_fail) {
        /* print all the new errors */
        ly_ilo_restore(ctx, prev_ilo, prev_eitem, 1);
        /* do not restore ly_errno, it was udpated properly */
    }
    return -1;
}

Project: libyang
File: resolve.c

parse_path_arg(const struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
               const char **name, int *nam_len, int *parent_times, int *has_predicate)
{
    int parsed = 0, ret, par_times = 0;

    assert(id);
    assert(parent_times);
    if (prefix) {
        *prefix = NULL;
    }
    if (pref_len) {
        *pref_len = 0;
    }
    if (name) {
        *name = NULL;
    }
    if (nam_len) {
        *nam_len = 0;
    }
    if (has_predicate) {
        *has_predicate = 0;
    }

    if (!*parent_times && !strncmp(id, "..", 2)) {
        ++par_times;

        parsed += 2;
        id += 2;

        while (!strncmp(id, "/..", 3)) {
            ++par_times;

            parsed += 3;
            id += 3;
        }
    }

    if (!*parent_times) {
        if (par_times) {
            *parent_times = par_times;
        } else {
            *parent_times = -1;
        }
    }

    if (id[0] != '/') {
        return -parsed;
    }

    /* skip '/' */
    ++parsed;
    ++id;

    /* node-identifier ([prefix:]identifier) */
    if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
        return -parsed - ret;
    }
    if (prefix && !(*prefix)) {
        /* actually we always need prefix even it is not specified */
        *prefix = lys_main_module(mod)->name;
        *pref_len = strlen(*prefix);
    }

    parsed += ret;
    id += ret;

    /* there is no predicate */
    if ((id[0] == '/') || !id[0]) {
        return parsed;
    } else if (id[0] != '[') {
        return -parsed;
    }

    if (has_predicate) {
        *has_predicate = 1;
    }

    return parsed;
}

Project: libyang
File: resolve.c

resolve_partial_json_data_list_predicate(struct parsed_pred pp, struct lyd_node *node, int position)
{
    uint16_t i;
    struct lyd_node_leaf_list *key;
    struct lys_node_list *slist;
    struct ly_ctx *ctx;

    assert(node);
    assert(node->schema->nodetype == LYS_LIST);
    assert(pp.len);

    ctx = node->schema->module->ctx;
    slist = (struct lys_node_list *)node->schema;

    /* is the predicate a number? */
    if (isdigit(pp.pred[0].name[0])) {
        if (position == atoi(pp.pred[0].name)) {
            /* match */
            return 0;
        } else {
            /* not a match */
            return 1;
        }
    }

    key = (struct lyd_node_leaf_list *)node->child;
    if (!key) {
        /* it is not a position, so we need a key for it to be a match */
        return 1;
    }

    /* go through all the keys */
    for (i = 0; i < slist->keys_size; ++i) {
        if (strncmp(key->schema->name, pp.pred[i].name, pp.pred[i].nam_len) || key->schema->name[pp.pred[i].nam_len]) {
            LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
            return -1;
        }

        if (pp.pred[i].mod_name) {
            /* specific module, check that the found key is from that module */
            if (strncmp(lyd_node_module((struct lyd_node *)key)->name, pp.pred[i].mod_name, pp.pred[i].mod_name_len)
                    || lyd_node_module((struct lyd_node *)key)->name[pp.pred[i].mod_name_len]) {
                LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
                return -1;
            }

            /* but if the module is the same as the parent, it should have been omitted */
            if (lyd_node_module((struct lyd_node *)key) == lyd_node_module(node)) {
                LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
                return -1;
            }
        } else {
            /* no module, so it must be the same as the list (parent) */
            if (lyd_node_module((struct lyd_node *)key) != lyd_node_module(node)) {
                LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
                return -1;
            }
        }

        /* value does not match */
        if (strncmp(key->value_str, pp.pred[i].value, pp.pred[i].val_len) || key->value_str[pp.pred[i].val_len]) {
            return 1;
        }

        key = (struct lyd_node_leaf_list *)key->next;
    }

    return 0;
}

Project: libyang
File: resolve.c

resolve_hash_table_find_equal(void *val1_p, void *val2_p, int mod, void *UNUSED(cb_data))
{
    struct lyd_node *val2, *elem2;
    struct parsed_pred pp;
    const char *str;
    int i;

    assert(!mod);
    (void)mod;

    pp = *((struct parsed_pred *)val1_p);
    val2 = *((struct lyd_node **)val2_p);

    if (val2->schema != pp.schema) {
        return 0;
    }

    switch (val2->schema->nodetype) {
    case LYS_CONTAINER:
    case LYS_LEAF:
    case LYS_ANYXML:
    case LYS_ANYDATA:
        return 1;
    case LYS_LEAFLIST:
        str = ((struct lyd_node_leaf_list *)val2)->value_str;
        if (!strncmp(str, pp.pred[0].value, pp.pred[0].val_len) && !str[pp.pred[0].val_len]) {
            return 1;
        }
        return 0;
    case LYS_LIST:
        assert(((struct lys_node_list *)val2->schema)->keys_size);
        assert(((struct lys_node_list *)val2->schema)->keys_size == pp.len);

        /* lists with keys, their equivalence is based on their keys */
        elem2 = val2->child;
        /* the exact data order is guaranteed */
        for (i = 0; elem2 && (i < pp.len); ++i) {
            /* module check */
            if (pp.pred[i].mod_name) {
                if (strncmp(lyd_node_module(elem2)->name, pp.pred[i].mod_name, pp.pred[i].mod_name_len)
                        || lyd_node_module(elem2)->name[pp.pred[i].mod_name_len]) {
                    break;
                }
            } else {
                if (lyd_node_module(elem2) != lys_node_module(pp.schema)) {
                    break;
                }
            }

            /* name check */
            if (strncmp(elem2->schema->name, pp.pred[i].name, pp.pred[i].nam_len) || elem2->schema->name[pp.pred[i].nam_len]) {
                break;
            }

            /* value check */
            str = ((struct lyd_node_leaf_list *)elem2)->value_str;
            if (strncmp(str, pp.pred[i].value, pp.pred[i].val_len) || str[pp.pred[i].val_len]) {
                break;
            }

            /* next key */
            elem2 = elem2->next;
        }
        if (i == pp.len) {
            return 1;
        }
        return 0;
    default:
        break;
    }

    LOGINT(val2->schema->module->ctx);
    return 0;
}

Project: libyang
File: resolve.c

resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
                       struct unres_schema *unres, struct lys_ident **ret)
{
    uint32_t i, j;
    struct lys_ident *base = NULL;
    struct ly_ctx *ctx = module->ctx;

    assert(ret);

    /* search module */
    for (i = 0; i < module->ident_size; i++) {
        if (!strcmp(basename, module->ident[i].name)) {

            if (!ident) {
                /* just search for type, so do not modify anything, just return
                 * the base identity pointer */
                *ret = &module->ident[i];
                return EXIT_SUCCESS;
            }

            base = &module->ident[i];
            goto matchfound;
        }
    }

    /* search submodules */
    for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
        for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
            if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {

                if (!ident) {
                    *ret = &module->inc[j].submodule->ident[i];
                    return EXIT_SUCCESS;
                }

                base = &module->inc[j].submodule->ident[i];
                goto matchfound;
            }
        }
    }

matchfound:
    /* we found it somewhere */
    if (base) {
        /* is it already completely resolved? */
        for (i = 0; i < unres->count; i++) {
            if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
                /* identity found, but not yet resolved, so do not return it in *res and try it again later */

                /* simple check for circular reference,
                 * the complete check is done as a side effect of using only completely
                 * resolved identities (previous check of unres content) */
                if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
                    LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
                    LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
                    return -1;
                }

                return EXIT_FAILURE;
            }
        }

        /* checks done, store the result */
        *ret = base;
        return EXIT_SUCCESS;
    }

    /* base not found (maybe a forward reference) */
    return EXIT_FAILURE;
}

Project: libyang
File: resolve.c

resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start, int output)
{
    char *str;
    const char *name, *mod_name, *id, *backup_mod_name = NULL, *yang_data_name = NULL;
    const struct lys_node *sibling, *start_parent, *parent;
    int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
    int yang_data_name_len, backup_mod_name_len;
    /* resolved import module from the start module, it must match the next node-name-match sibling */
    const struct lys_module *prefix_mod, *module, *prev_mod;

    assert(nodeid && (ctx || start));
    if (!ctx) {
        ctx = start->module->ctx;
    }

    id = nodeid;

    if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1)) < 1) {
        LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
        return NULL;
    }

    if (name[0] == '#') {
        if (is_relative) {
            LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
            return NULL;
        }
        yang_data_name = name + 1;
        yang_data_name_len = nam_len - 1;
        backup_mod_name = mod_name;
        backup_mod_name_len = mod_name_len;
        id += r;
    } else {
        is_relative = -1;
    }

    if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
        LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
        return NULL;
    }
    id += r;

    if (backup_mod_name) {
        mod_name = backup_mod_name;
        mod_name_len = backup_mod_name_len;
    }

    if (is_relative) {
        assert(start);
        start_parent = start;
        while (start_parent && (start_parent->nodetype == LYS_USES)) {
            start_parent = lys_parent(start_parent);
        }
        module = start->module;
    } else {
        if (!mod_name) {
            str = strndup(nodeid, (name + nam_len) - nodeid);
            LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
            free(str);
            return NULL;
        }

        str = strndup(mod_name, mod_name_len);
        module = ly_ctx_get_module(ctx, str, NULL, 1);
        free(str);

        if (!module) {
            str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
            LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
            free(str);
            return NULL;
        }
        start_parent = NULL;
        if (yang_data_name) {
            start_parent = lyp_get_yang_data_template(module, yang_data_name, yang_data_name_len);
            if (!start_parent) {
                str = strndup(nodeid, (yang_data_name + yang_data_name_len) - nodeid);
                LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
                free(str);
                return NULL;
            }
        }

        /* now it's as if there was no module name */
        mod_name = NULL;
        mod_name_len = 0;
    }

    prev_mod = module;

    while (1) {
        sibling = NULL;
        while ((sibling = lys_getnext(sibling, start_parent, module, 0))) {
            /* name match */
            if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
                /* output check */
                for (parent = lys_parent(sibling); parent && !(parent->nodetype & (LYS_INPUT | LYS_OUTPUT)); parent = lys_parent(parent));
                if (parent) {
                    if (output && (parent->nodetype == LYS_INPUT)) {
                        continue;
                    } else if (!output && (parent->nodetype == LYS_OUTPUT)) {
                        continue;
                    }
                }

                /* module check */
                if (mod_name) {
                    /* will also find an augment module */
                    prefix_mod = ly_ctx_nget_module(ctx, mod_name, mod_name_len, NULL, 1);

                    if (!prefix_mod) {
                        str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
                        LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
                        free(str);
                        return NULL;
                    }
                } else {
                    prefix_mod = prev_mod;
                }
                if (prefix_mod != lys_node_module(sibling)) {
                    continue;
                }

                /* do we have some predicates on it? */
                if (has_predicate) {
                    r = 0;
                    if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
                        if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
                            LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
                            return NULL;
                        }
                    } else if (sibling->nodetype == LYS_LIST) {
                        if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
                            return NULL;
                        }
                    } else {
                        LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
                        return NULL;
                    }
                    id += r;
                }

                /* the result node? */
                if (!id[0]) {
                    return sibling;
                }

                /* move down the tree, if possible */
                if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
                    LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
                    return NULL;
                }
                start_parent = sibling;

                /* update prev mod */
                prev_mod = (start_parent->child ? lys_node_module(start_parent->child) : module);
                break;
            }
        }

        /* no match */
        if (!sibling) {
            str = strndup(nodeid, (name + nam_len) - nodeid);
            LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
            free(str);
            return NULL;
        }

        if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
            LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
            return NULL;
        }
        id += r;
    }

    /* cannot get here */
    LOGINT(ctx);
    return NULL;
}

Project: libyang
File: resolve.c

resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
                      enum lyxp_node_type *ctx_node_type)
{
    struct lyd_node *parent;
    struct lys_node *sparent;
    enum lyxp_node_type node_type;
    uint16_t i, data_depth, schema_depth;

    resolve_when_ctx_snode(schema, &schema, &node_type);

    if (node_type == LYXP_NODE_ELEM) {
        /* standard element context node */
        for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
        for (sparent = schema, schema_depth = 0;
                sparent;
                sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
            if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
                ++schema_depth;
            }
        }
        if (data_depth < schema_depth) {
            return -1;
        }

        /* find the corresponding data node */
        for (i = 0; i < data_depth - schema_depth; ++i) {
            node = node->parent;
        }
        if (node->schema != schema) {
            return -1;
        }
    } else {
        /* root context node */
        while (node->parent) {
            node = node->parent;
        }
        while (node->prev->next) {
            node = node->prev;
        }
    }

    *ctx_node = node;
    *ctx_node_type = node_type;
    return EXIT_SUCCESS;
}

Project: libyang
File: resolve.c

iff_stack_clean(struct iff_stack *stack)
{
    stack->size = 0;
    free(stack->stack);
}

Project: libyang
File: resolve.c

parse_schema_json_predicate(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
                            const char **value, int *val_len, int *has_predicate)
{
    const char *ptr;
    int parsed = 0, ret;
    char quote;

    assert(id);
    if (mod_name) {
        *mod_name = NULL;
    }
    if (mod_name_len) {
        *mod_name_len = 0;
    }
    if (name) {
        *name = NULL;
    }
    if (nam_len) {
        *nam_len = 0;
    }
    if (value) {
        *value = NULL;
    }
    if (val_len) {
        *val_len = 0;
    }
    if (has_predicate) {
        *has_predicate = 0;
    }

    if (id[0] != '[') {
        return -parsed;
    }

    ++parsed;
    ++id;

    while (isspace(id[0])) {
        ++parsed;
        ++id;
    }

    /* identifier */
    if (id[0] == '.') {
        ret = 1;

        if (name) {
            *name = id;
        }
        if (nam_len) {
            *nam_len = ret;
        }
    } else if (isdigit(id[0])) {
        if (id[0] == '0') {
            return -parsed;
        }
        ret = 1;
        while (isdigit(id[ret])) {
            ++ret;
        }

        if (name) {
            *name = id;
        }
        if (nam_len) {
            *nam_len = ret;
        }
    } else if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, NULL, 0)) < 1) {
        return -parsed + ret;
    }

    parsed += ret;
    id += ret;

    while (isspace(id[0])) {
        ++parsed;
        ++id;
    }

    /* there is value as well */
    if (id[0] == '=') {
        if (name && isdigit(**name)) {
            return -parsed;
        }

        ++parsed;
        ++id;

        while (isspace(id[0])) {
            ++parsed;
            ++id;
        }

        /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
        if ((id[0] == '\"') || (id[0] == '\'')) {
            quote = id[0];

            ++parsed;
            ++id;

            if ((ptr = strchr(id, quote)) == NULL) {
                return -parsed;
            }
            ret = ptr - id;

            if (value) {
                *value = id;
            }
            if (val_len) {
                *val_len = ret;
            }

            parsed += ret + 1;
            id += ret + 1;
        } else {
            return -parsed;
        }

        while (isspace(id[0])) {
            ++parsed;
            ++id;
        }
    }

    if (id[0] != ']') {
        return -parsed;
    }

    ++parsed;
    ++id;

    if ((id[0] == '[') && has_predicate) {
        *has_predicate = 1;
    }

    return parsed;
}

Project: libyang
File: resolve.c

check_xpath(struct lys_node *node, int check_place)
{
    struct lys_node *parent;
    struct lyxp_set set;
    enum int_log_opts prev_ilo;

    if (check_place) {
        parent = node;
        while (parent) {
            if (parent->nodetype == LYS_GROUPING) {
                /* unresolved grouping, skip for now (will be checked later) */
                return EXIT_SUCCESS;
            }
            if (parent->nodetype == LYS_AUGMENT) {
                if (!((struct lys_node_augment *)parent)->target) {
                    /* unresolved augment, skip for now (will be checked later) */
                    return EXIT_FAILURE;
                } else {
                    parent = ((struct lys_node_augment *)parent)->target;
                    continue;
                }
            }
            parent = parent->parent;
        }
    }

    memset(&set, 0, sizeof set);

    /* produce just warnings */
    ly_ilo_change(NULL, ILO_ERR2WRN, &prev_ilo, NULL);
    lyxp_node_atomize(node, &set, 1);
    ly_ilo_restore(NULL, prev_ilo, NULL, 0);

    if (set.val.snodes) {
        free(set.val.snodes);
    }
    return EXIT_SUCCESS;
}

Project: libyang
File: resolve.c

resolve_unres_data_autodel_diff(struct unres_data *unres, uint32_t unres_i)
{
    struct lyd_node *next, *child, *parent;
    uint32_t i;

    for (i = 0; i < unres->diff_idx; ++i) {
        if (unres->diff->type[i] == LYD_DIFF_DELETED) {
            /* only leaf(-list) default could be removed and there is nothing to be checked in that case */
            continue;
        }

        if (unres->diff->second[i] == unres->node[unres_i]) {
            /* 1) default value was supposed to be created, but is disabled by when
             * -> remove it from diff altogether
             */
            unres_data_diff_rem(unres, i);
            /* if diff type is CREATED, the value was just a pointer, it can be freed normally (unlike in 4) */
            return;
        } else {
            parent = unres->diff->second[i]->parent;
            while (parent && (parent != unres->node[unres_i])) {
                parent = parent->parent;
            }
            if (parent) {
                /* 2) default value was supposed to be created but is disabled by when in some parent
                 * -> remove this default subtree and add the rest into diff as deleted instead in 4)
                 */
                unres_data_diff_rem(unres, i);
                break;
            }

            LY_TREE_DFS_BEGIN(unres->diff->second[i]->parent, next, child) {
                if (child == unres->node[unres_i]) {
                    /* 3) some default child of a default value was supposed to be created but has false when
                     * -> the subtree will be freed later and automatically disconnected from the diff parent node
                     */
                    return;
                }

                LY_TREE_DFS_END(unres->diff->second[i]->parent, next, child);
            }
        }
    }

    /* 4) it does not overlap with created default values in any way
     * -> just add it into diff as deleted
     */
    unres_data_diff_new(unres, unres->node[unres_i], unres->node[unres_i]->parent, 0);
    lyd_unlink(unres->node[unres_i]);

    /* should not be freed anymore */
    unres->node[unres_i] = NULL;
}

Project: libyang
File: resolve.c

unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
                      struct lys_node *snode)
{
    int rc;
    uint32_t u;
    enum int_log_opts prev_ilo;
    struct ly_err_item *prev_eitem;
    LY_ERR prev_ly_errno;
    struct lyxml_elem *yin;
    struct ly_ctx *ctx = mod->ctx;

    assert(unres && (item || (type == UNRES_MOD_IMPLEMENT)) && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID)
           && (type != UNRES_WHEN) && (type != UNRES_MUST)));

    /* check for duplicities in unres */
    for (u = 0; u < unres->count; u++) {
        if (unres->type[u] == type && unres->item[u] == item &&
                unres->str_snode[u] == snode && unres->module[u] == mod) {
            /* duplication can happen when the node contains multiple statements of the same type to check,
             * this can happen for example when refinement is being applied, so we just postpone the processing
             * and do not duplicate the information */
            return EXIT_FAILURE;
        }
    }

    if ((type == UNRES_EXT_FINALIZE) || (type == UNRES_XPATH) || (type == UNRES_MOD_IMPLEMENT)) {
        /* extension finalization is not even tried when adding the item into the inres list,
         * xpath is not tried because it would hide some potential warnings,
         * implementing module must be deferred because some other nodes can be added that will need to be traversed
         * and their targets made implemented */
        rc = EXIT_FAILURE;
    } else {
        prev_ly_errno = ly_errno;
        ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);

        rc = resolve_unres_schema_item(mod, item, type, snode, unres);
        if (rc != EXIT_FAILURE) {
            ly_ilo_restore(ctx, prev_ilo, prev_eitem, rc == -1 ? 1 : 0);
            if (rc != -1) {
                ly_errno = prev_ly_errno;
            }

            if (type == UNRES_LIST_UNIQ) {
                /* free the allocated structure */
                free(item);
            } else if (rc == -1 && type == UNRES_IFFEAT) {
                /* free the allocated resources */
                free(*((char **)item));
            }
            return rc;
        } else {
            /* erase info about validation errors */
            ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
            ly_errno = prev_ly_errno;
        }

        print_unres_schema_item_fail(item, type, snode);

        /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
        if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
            yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
            if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
                lyxml_unlink_elem(mod->ctx, yin, 1);
                ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
            }
        }
    }

    unres->count++;
    unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
    LY_CHECK_ERR_RETURN(!unres->item, LOGMEM(ctx), -1);
    unres->item[unres->count-1] = item;
    unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
    LY_CHECK_ERR_RETURN(!unres->type, LOGMEM(ctx), -1);
    unres->type[unres->count-1] = type;
    unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
    LY_CHECK_ERR_RETURN(!unres->str_snode, LOGMEM(ctx), -1);
    unres->str_snode[unres->count-1] = snode;
    unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
    LY_CHECK_ERR_RETURN(!unres->module, LOGMEM(ctx), -1);
    unres->module[unres->count-1] = mod;

    return rc;
}

Project: libyang
File: resolve.c

resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
{
    int rc;
    struct lys_node *par_grp;
    struct ly_ctx *ctx = uses->module->ctx;

    /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself is used
     *       in some uses. When we see such a uses, the grouping's unres counter is used to store number of so far
     *       unresolved uses. The grouping cannot be used unless this counter is decreased back to 0. To remember
     *       that the uses already increased grouping's counter, the LYS_USESGRP flag is used. */
    for (par_grp = lys_parent((struct lys_node *)uses); par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
    if (par_grp && ly_strequal(par_grp->name, uses->name, 1)) {
        LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
        return -1;
    }

    if (!uses->grp) {
        rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
        if (rc == -1) {
            LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
            return -1;
        } else if (rc > 0) {
            LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
            return -1;
        } else if (!uses->grp) {
            if (par_grp && !(uses->flags & LYS_USESGRP)) {
                if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
                    LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
                    return -1;
                }
                uses->flags |= LYS_USESGRP;
            }
            LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
            return EXIT_FAILURE;
        }
    }

    if (uses->grp->unres_count) {
        if (par_grp && !(uses->flags & LYS_USESGRP)) {
            if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
                LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
                return -1;
            }
            uses->flags |= LYS_USESGRP;
        } else {
            /* instantiate grouping only when it is completely resolved */
            uses->grp = NULL;
        }
        LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
        return EXIT_FAILURE;
    }

    rc = resolve_uses(uses, unres);
    if (!rc) {
        /* decrease unres count only if not first try */
        if (par_grp && (uses->flags & LYS_USESGRP)) {
            assert(((struct lys_node_grp *)par_grp)->unres_count);
            ((struct lys_node_grp *)par_grp)->unres_count--;
            uses->flags &= ~LYS_USESGRP;
        }

        /* check status */
        if (lyp_check_status(uses->flags, uses->module, "of uses",
                         uses->grp->flags, uses->grp->module, uses->grp->name,
                         (struct lys_node *)uses)) {
            return -1;
        }

        return EXIT_SUCCESS;
    }

    return rc;
}

Project: libyang
File: resolve.c

resolve_data(const struct lys_module *mod, const char *name, int nam_len, struct lyd_node *start, struct unres_data *parents)
{
    struct lyd_node *node;
    int flag;
    uint32_t i;

    if (!parents->count) {
        parents->count = 1;
        parents->node = malloc(sizeof *parents->node);
        LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), -1);
        parents->node[0] = NULL;
    }
    for (i = 0; i < parents->count;) {
        if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
            /* skip */
            ++i;
            continue;
        }
        flag = 0;
        LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
            if (lyd_node_module(node) == mod && !strncmp(node->schema->name, name, nam_len)
                    && node->schema->name[nam_len] == '\0') {
                /* matching target */
                if (!flag) {
                    /* put node instead of the current parent */
                    parents->node[i] = node;
                    flag = 1;
                } else {
                    /* multiple matching, so create a new node */
                    ++parents->count;
                    parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
                    LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), EXIT_FAILURE);
                    parents->node[parents->count-1] = node;
                    ++i;
                }
            }
        }

        if (!flag) {
            /* remove item from the parents list */
            unres_data_del(parents, i);
        } else {
            ++i;
        }
    }

    return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
}

Project: libyang
File: resolve.c

unres_schema_dup(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type, void *new_item)
{
    int i;
    struct unres_list_uniq aux_uniq;
    struct unres_iffeat_data *iff_data;

    assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));

    /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
    if (type == UNRES_LIST_UNIQ) {
        aux_uniq.list = item;
        aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
        item = &aux_uniq;
    }
    i = unres_schema_find(unres, -1, item, type);

    if (i == -1) {
        if (type == UNRES_LIST_UNIQ) {
            free(new_item);
        }
        return EXIT_FAILURE;
    }

    if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
            (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
        if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
            LOGINT(mod->ctx);
            return -1;
        }
    } else if (type == UNRES_IFFEAT) {
        /* duplicate unres_iffeature_data */
        iff_data = malloc(sizeof *iff_data);
        LY_CHECK_ERR_RETURN(!iff_data, LOGMEM(mod->ctx), -1);
        iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
        iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
        if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
            LOGINT(mod->ctx);
            return -1;
        }
    } else {
        if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
            LOGINT(mod->ctx);
            return -1;
        }
    }

    return EXIT_SUCCESS;
}

Project: libyang
File: resolve.c

resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
{
    int rc;
    const struct lys_node *leaf = NULL;
    struct ly_ctx *ctx = parent->module->ctx;

    rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, &leaf);
    if (rc || !leaf) {
        if (rc) {
            LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
            if (rc > 0) {
                LOGVAL(ctx, LYE_INCHAR, LY_VLOG_PREV, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
            } else if (rc == -2) {
                LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
            }
            rc = -1;
        } else {
            LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
            LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
            rc = EXIT_FAILURE;
        }
        goto error;
    }
    if (leaf->nodetype != LYS_LEAF) {
        LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
        LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
        return -1;
    }

    /* check status */
    if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
                                                        leaf->flags, leaf->module, leaf->name, leaf)) {
        return -1;
    }

    /* check that all unique's targets are of the same config type */
    if (*trg_type) {
        if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
            LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
            LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
                   "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
                   uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
            return -1;
        }
    } else {
        /* first unique */
        if (leaf->flags & LYS_CONFIG_W) {
            *trg_type = 1;
        } else {
            *trg_type = 2;
        }
    }

    /* set leaf's unique flag */
    ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;

    return EXIT_SUCCESS;

error:

    return rc;
}

Project: libyang
File: resolve.c

resolve_schema_leafref_valid_dep_flag(const struct lys_node *op_node, const struct lys_module *local_mod,
                                      const struct lys_node *first_node, int abs_path)
{
    int dep1, dep2;
    const struct lys_node *node;

    if (!op_node) {
        /* leafref pointing to a different module */
        if (local_mod != lys_node_module(first_node)) {
            return 1;
        }
    } else if (lys_parent(op_node)) {
        /* inner operation (notif/action) */
        if (abs_path) {
            return 1;
        } else {
            /* compare depth of both nodes */
            for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
            for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
            if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
                return 1;
            }
        }
    } else {
        /* top-level operation (notif/rpc) */
        if (op_node != first_node) {
            return 1;
        }
    }

    return 0;
}