libyang  2.1.111
libyang is YANG data modelling language parser and toolkit written (and providing API) in C.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
identityref.c
Go to the documentation of this file.
1 
15 #define _GNU_SOURCE /* asprintf */
16 
17 #include "plugins_types.h"
18 
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 
23 #include "libyang.h"
24 
25 /* additional internal headers for some useful simple macros */
26 #include "common.h"
27 #include "compat.h"
28 #include "plugins_internal.h" /* LY_TYPE_*_STR */
29 
49 static LY_ERR
50 identityref_ident2str(const struct lysc_ident *ident, LY_VALUE_FORMAT format, void *prefix_data, char **str, size_t *str_len)
51 {
52  int len;
53  const char *prefix;
54 
55  /* get the prefix, may be NULL for no prefix and the default namespace */
56  prefix = lyplg_type_get_prefix(ident->module, format, prefix_data);
57 
58  if (prefix) {
59  len = asprintf(str, "%s:%s", prefix, ident->name);
60  } else {
61  len = asprintf(str, "%s", ident->name);
62  }
63  if (len == -1) {
64  return LY_EMEM;
65  }
66 
67  if (str_len) {
68  *str_len = (size_t)len;
69  }
70  return LY_SUCCESS;
71 }
72 
86 static LY_ERR
87 identityref_str2ident(const char *value, size_t value_len, LY_VALUE_FORMAT format, void *prefix_data,
88  const struct ly_ctx *ctx, const struct lysc_node *ctx_node, struct lysc_ident **ident, struct ly_err_item **err)
89 {
90  const char *id_name, *prefix = value;
91  size_t id_len, prefix_len;
92  const struct lys_module *mod;
94  struct lysc_ident *id, *identities;
95 
96  /* locate prefix if any */
97  for (prefix_len = 0; (prefix_len < value_len) && (value[prefix_len] != ':'); ++prefix_len) {}
98  if (prefix_len < value_len) {
99  id_name = &value[prefix_len + 1];
100  id_len = value_len - (prefix_len + 1);
101  } else {
102  prefix_len = 0;
103  id_name = value;
104  id_len = value_len;
105  }
106 
107  if (!id_len) {
108  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid empty identityref value.");
109  }
110 
111  mod = lyplg_type_identity_module(ctx, ctx_node, prefix, prefix_len, format, prefix_data);
112  if (!mod) {
113  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
114  "Invalid identityref \"%.*s\" value - unable to map prefix to YANG schema.", (int)value_len, value);
115  }
116 
117  id = NULL;
118  identities = mod->identities;
119  LY_ARRAY_FOR(identities, u) {
120  if (!ly_strncmp(identities[u].name, id_name, id_len)) {
121  /* we have match */
122  id = &identities[u];
123  break;
124  }
125  }
126  if (!id) {
127  /* no match */
128  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
129  "Invalid identityref \"%.*s\" value - identity not found in module \"%s\".",
130  (int)value_len, value, mod->name);
131  }
132 
133  *ident = id;
134  return LY_SUCCESS;
135 }
136 
146 static LY_ERR
147 identityref_check_base(const struct lysc_ident *ident, struct lysc_type_identityref *type, const char *value,
148  size_t value_len, struct ly_err_item **err)
149 {
150  LY_ERR ret;
151  size_t str_len;
152  char *str;
154  struct lysc_ident *base;
155 
156  /* check that the identity matches some of the type's base identities */
157  LY_ARRAY_FOR(type->bases, u) {
158  if (!lyplg_type_identity_isderived(type->bases[u], ident)) {
159  /* we have match */
160  break;
161  }
162  }
163 
164  /* it does not, generate a nice error */
165  if (u == LY_ARRAY_COUNT(type->bases)) {
166  str = NULL;
167  str_len = 1;
168  LY_ARRAY_FOR(type->bases, u) {
169  base = type->bases[u];
170  str_len += (u ? 2 : 0) + 1 + strlen(base->module->name) + 1 + strlen(base->name) + 1;
171  str = ly_realloc(str, str_len);
172  sprintf(str + (u ? strlen(str) : 0), "%s\"%s:%s\"", u ? ", " : "", base->module->name, base->name);
173  }
174 
175  /* no match */
176  if (u == 1) {
177  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
178  "Invalid identityref \"%.*s\" value - identity not derived from the base %s.",
179  (int)value_len, value, str);
180  } else {
181  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
182  "Invalid identityref \"%.*s\" value - identity not derived from all the bases %s.",
183  (int)value_len, value, str);
184  }
185  free(str);
186  return ret;
187  }
188 
189  return LY_SUCCESS;
190 }
191 
207 static LY_ERR
208 identityref_check_ident(const struct lysc_ident *ident, const char *value,
209  size_t value_len, uint32_t options, struct lys_glob_unres *unres, struct ly_err_item **err)
210 {
211  LY_ERR ret = LY_SUCCESS;
212 
213  if (!ident->module->implemented) {
214  if (options & LYPLG_TYPE_STORE_IMPLEMENT) {
215  ret = lyplg_type_make_implemented(ident->module, NULL, unres);
216  } else {
217  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
218  "Invalid identityref \"%.*s\" value - identity found in non-implemented module \"%s\".",
219  (int)value_len, (char *)value, ident->module->name);
220  }
221  } else if (lys_identity_iffeature_value(ident) == LY_ENOT) {
222  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
223  "Invalid identityref \"%.*s\" value - identity is disabled by if-feature.",
224  (int)value_len, value);
225  }
226 
227  return ret;
228 }
229 
230 LIBYANG_API_DEF LY_ERR
231 lyplg_type_store_identityref(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
232  uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
233  struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
234 {
235  LY_ERR ret = LY_SUCCESS;
236  struct lysc_type_identityref *type_ident = (struct lysc_type_identityref *)type;
237  char *canon;
238  struct lysc_ident *ident = NULL;
239 
240  /* init storage */
241  memset(storage, 0, sizeof *storage);
242  storage->realtype = type;
243 
244  /* check hints */
245  ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
246  LY_CHECK_GOTO(ret, cleanup);
247 
248  /* find a matching identity */
249  ret = identityref_str2ident(value, value_len, format, prefix_data, ctx, ctx_node, &ident, err);
250  LY_CHECK_GOTO(ret, cleanup);
251 
252  /* check if the identity is enabled */
253  ret = identityref_check_ident(ident, value, value_len, options, unres, err);
254  LY_CHECK_GOTO(ret, cleanup);
255 
256  /* check that the identity is derived form all the bases */
257  ret = identityref_check_base(ident, type_ident, value, value_len, err);
258  LY_CHECK_GOTO(ret, cleanup);
259 
260  if (ctx_node) {
261  /* check status */
262  ret = lyplg_type_check_status(ctx_node, ident->flags, format, prefix_data, ident->name, err);
263  LY_CHECK_GOTO(ret, cleanup);
264  }
265 
266  /* store value */
267  storage->ident = ident;
268 
269  /* store canonical value */
270  if (format == LY_VALUE_CANON) {
271  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
272  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
273  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
274  LY_CHECK_GOTO(ret, cleanup);
275  } else {
276  ret = lydict_insert(ctx, value, value_len, &storage->_canonical);
277  LY_CHECK_GOTO(ret, cleanup);
278  }
279  } else {
280  /* JSON format is the canonical one */
281  ret = identityref_ident2str(ident, LY_VALUE_JSON, ctx_node ? ctx_node->module : NULL, &canon, NULL);
282  LY_CHECK_GOTO(ret, cleanup);
283 
284  ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
285  LY_CHECK_GOTO(ret, cleanup);
286  }
287 
288 cleanup:
289  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
290  free((void *)value);
291  }
292 
293  if (ret) {
294  lyplg_type_free_simple(ctx, storage);
295  }
296  return ret;
297 }
298 
299 LIBYANG_API_DEF LY_ERR
300 lyplg_type_compare_identityref(const struct lyd_value *val1, const struct lyd_value *val2)
301 {
302  if (val1->realtype != val2->realtype) {
303  return LY_ENOT;
304  }
305 
306  if (val1->ident == val2->ident) {
307  return LY_SUCCESS;
308  }
309  return LY_ENOT;
310 }
311 
312 LIBYANG_API_DEF const void *
313 lyplg_type_print_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
314  void *prefix_data, ly_bool *dynamic, size_t *value_len)
315 {
316  char *ret;
317 
318  if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
319  if (dynamic) {
320  *dynamic = 0;
321  }
322  if (value_len) {
323  *value_len = strlen(value->_canonical);
324  }
325  return value->_canonical;
326  }
327 
328  /* print the value in the specific format */
329  if (identityref_ident2str(value->ident, format, prefix_data, &ret, value_len)) {
330  return NULL;
331  }
332  *dynamic = 1;
333  return ret;
334 }
335 
344  {
345  .module = "",
346  .revision = NULL,
347  .name = LY_TYPE_IDENT_STR,
348 
349  .plugin.id = "libyang 2 - identityref, version 1",
350  .plugin.store = lyplg_type_store_identityref,
351  .plugin.validate = NULL,
352  .plugin.compare = lyplg_type_compare_identityref,
353  .plugin.sort = NULL,
354  .plugin.print = lyplg_type_print_identityref,
355  .plugin.duplicate = lyplg_type_dup_simple,
356  .plugin.free = lyplg_type_free_simple,
357  .plugin.lyb_data_len = -1,
358  },
359  {0}
360 };
struct lysc_type * realtype
Definition: tree_data.h:564
Compiled YANG data node.
Definition: tree_schema.h:1414
uint16_t flags
Definition: tree_schema.h:1233
LIBYANG_API_DECL struct lys_module * lyplg_type_identity_module(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *prefix, size_t prefix_len, LY_VALUE_FORMAT format, const void *prefix_data)
Get the corresponding module for the identity value.
LIBYANG_API_DECL LY_ERR ly_err_new(struct ly_err_item **err, LY_ERR ecode, LY_VECODE vecode, char *path, char *apptag, const char *err_format,...) _FORMAT_PRINTF(6
Create and fill error structure.
Definition: log.h:256
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:28
LIBYANG_API_DECL LY_ERR lyplg_type_make_implemented(struct lys_module *mod, const char **features, struct lys_glob_unres *unres)
Implement a module (just like lys_set_implemented()), but keep maintaining unresolved items...
struct lys_module * module
Definition: tree_schema.h:1229
struct lysc_ident * identities
Definition: tree_schema.h:2116
ly_bool implemented
Definition: tree_schema.h:2127
#define LYPLG_TYPE_STORE_DYNAMIC
YANG identity-stmt.
Definition: tree_schema.h:1225
struct lyplg_type_record plugins_identityref[]
Plugin information for identityref type implementation.
Definition: identityref.c:343
LIBYANG_API_DECL LY_ERR lyplg_type_compare_identityref(const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of lyplg_type_compare_clb for the built-in identityref type.
Definition: identityref.c:300
LIBYANG_API_DECL LY_ERR lyplg_type_check_status(const struct lysc_node *ctx_node, uint16_t val_flags, LY_VALUE_FORMAT format, void *prefix_data, const char *val_name, struct ly_err_item **err)
Check that the value of a type is allowed based on its status.
LIBYANG_API_DECL const char * lyplg_type_get_prefix(const struct lys_module *mod, LY_VALUE_FORMAT format, void *prefix_data)
Get format-specific prefix for a module.
The main libyang public header.
YANG data representation.
Definition: tree_data.h:560
const char * _canonical
Definition: tree_data.h:561
Libyang full error structure.
Definition: log.h:299
Definition: log.h:291
Definition: log.h:262
LIBYANG_API_DECL const void * lyplg_type_print_identityref(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len)
Implementation of lyplg_type_print_clb for the built-in identityref type.
LIBYANG_API_DECL LY_ERR lys_identity_iffeature_value(const struct lysc_ident *ident)
Get how the if-feature statement is evaluated for certain identity.
LIBYANG_API_DECL LY_ERR lydict_insert(const struct ly_ctx *ctx, const char *value, size_t len, const char **str_p)
Insert string into dictionary. If the string is already present, only a reference counter is incremen...
Available YANG schema tree structures representing YANG module.
Definition: tree_schema.h:2100
LIBYANG_API_DECL LY_ERR lyplg_type_identity_isderived(const struct lysc_ident *base, const struct lysc_ident *derived)
Decide if the derived identity is derived from (based on) the base identity.
LIBYANG_API_DECL LY_ERR lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_DATA_TYPE type, int *base, struct ly_err_item **err)
Check that the type is suitable for the parser&#39;s hints (if any) in the specified format.
const char * module
#define LY_ARRAY_COUNT(ARRAY)
Get the number of records in the ARRAY.
Definition: tree.h:148
void * ly_realloc(void *ptr, size_t size)
Wrapper for realloc() call. The only difference is that if it fails to allocate the requested memory...
#define LY_ARRAY_FOR(ARRAY,...)
Sized-array iterator (for-loop).
Definition: tree.h:167
#define LY_ARRAY_COUNT_TYPE
Type (i.e. size) of the sized array&#39;s size counter.
Definition: tree.h:104
Definition: log.h:268
LIBYANG_API_DECL LY_ERR lyplg_type_store_identityref(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len, uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node, struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
Implementation of lyplg_type_store_clb for the built-in identityref type.
Definition: identityref.c:231
LIBYANG_API_DECL LY_ERR lydict_insert_zc(const struct ly_ctx *ctx, char *value, const char **str_p)
Insert string into dictionary - zerocopy version. If the string is already present, only a reference counter is incremented and no memory allocation is performed. This insert function variant avoids duplication of specified value - it is inserted into the dictionary directly.
struct lys_module * module
Definition: tree_schema.h:1418
#define LYPLG_TYPE_STORE_IMPLEMENT
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition: tree.h:234
struct lysc_ident ** bases
Definition: tree_schema.h:1378
LY_DATA_TYPE basetype
Definition: tree_schema.h:1299
LIBYANG_API_DECL LY_ERR lyplg_type_dup_simple(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
Implementation of lyplg_type_dup_clb for a generic simple type.
LY_ERR
libyang&#39;s error codes returned by the libyang functions.
Definition: log.h:254
LIBYANG_API_DECL void lyplg_type_free_simple(const struct ly_ctx *ctx, struct lyd_value *value)
Implementation of lyplg_type_free_clb for a generic simple type.
API for (user) types plugins.
const char * name
Definition: tree_schema.h:1226
libyang context handler.
const char * name
Definition: tree_schema.h:2102