libyang  4.0.2
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 
16 #define _GNU_SOURCE /* asprintf */
17 
18 #include "plugins_types.h"
19 
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 
24 #include "libyang.h"
25 
26 /* additional internal headers for some useful simple macros */
27 #include "compat.h"
28 #include "ly_common.h"
29 #include "plugins_internal.h" /* LY_TYPE_*_STR */
30 
50 static LY_ERR
51 identityref_ident2str(const struct lysc_ident *ident, LY_VALUE_FORMAT format, void *prefix_data, char **str, uint32_t *str_len)
52 {
53  int len;
54  const char *prefix;
55 
56  /* get the prefix, may be NULL for no prefix and the default namespace */
57  prefix = lyplg_type_get_prefix(ident->module, format, prefix_data);
58 
59  if (prefix) {
60  len = asprintf(str, "%s:%s", prefix, ident->name);
61  } else {
62  len = asprintf(str, "%s", ident->name);
63  }
64  if (len == -1) {
65  return LY_EMEM;
66  }
67 
68  if (str_len) {
69  *str_len = (uint32_t)len;
70  }
71  return LY_SUCCESS;
72 }
73 
87 static LY_ERR
88 identityref_str2ident(const char *value, uint32_t value_size, LY_VALUE_FORMAT format, void *prefix_data,
89  const struct ly_ctx *ctx, const struct lysc_node *ctx_node, struct lysc_ident **ident, struct ly_err_item **err)
90 {
91  const char *id_name, *prefix = value;
92  uint32_t id_len, prefix_len;
93  const struct lys_module *mod;
95  struct lysc_ident *id, *identities;
96 
97  /* locate prefix if any */
98  for (prefix_len = 0; (prefix_len < value_size) && (value[prefix_len] != ':'); ++prefix_len) {}
99  if (prefix_len < value_size) {
100  id_name = &value[prefix_len + 1];
101  id_len = value_size - (prefix_len + 1);
102  } else {
103  prefix_len = 0;
104  id_name = value;
105  id_len = value_size;
106  }
107 
108  if (!id_len) {
109  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid empty identityref value.");
110  }
111 
112  mod = lyplg_type_identity_module(ctx, ctx_node, prefix, prefix_len, format, prefix_data);
113  if (!mod) {
114  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
115  "Invalid identityref \"%.*s\" value - unable to map prefix to YANG schema.", (int)value_size, value);
116  }
117 
118  id = NULL;
119  identities = mod->identities;
120  LY_ARRAY_FOR(identities, u) {
121  if (!ly_strncmp(identities[u].name, id_name, id_len)) {
122  /* we have match */
123  id = &identities[u];
124  break;
125  }
126  }
127  if (!id) {
128  /* no match */
129  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
130  "Invalid identityref \"%.*s\" value - identity not found in module \"%s\".",
131  (int)value_size, value, mod->name);
132  }
133 
134  *ident = id;
135  return LY_SUCCESS;
136 }
137 
147 static LY_ERR
148 identityref_check_base(const struct lysc_ident *ident, struct lysc_type_identityref *type, const char *value,
149  uint32_t value_size, struct ly_err_item **err)
150 {
151  LY_ERR ret;
152  uint32_t str_len;
153  char *str;
155  struct lysc_ident *base;
156 
157  /* check that the identity matches some of the type's base identities */
158  LY_ARRAY_FOR(type->bases, u) {
159  if (!lyplg_type_identity_isderived(type->bases[u], ident)) {
160  /* we have match */
161  break;
162  }
163  }
164 
165  /* it does not, generate a nice error */
166  if (u == LY_ARRAY_COUNT(type->bases)) {
167  str = NULL;
168  str_len = 1;
169  LY_ARRAY_FOR(type->bases, u) {
170  base = type->bases[u];
171  str_len += (u ? 2 : 0) + 1 + strlen(base->module->name) + 1 + strlen(base->name) + 1;
172  str = ly_realloc(str, str_len);
173  sprintf(str + (u ? strlen(str) : 0), "%s\"%s:%s\"", u ? ", " : "", base->module->name, base->name);
174  }
175 
176  /* no match */
177  if (u == 1) {
178  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
179  "Invalid identityref \"%.*s\" value - identity not derived from the base %s.",
180  (int)value_size, value, str);
181  } else {
182  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
183  "Invalid identityref \"%.*s\" value - identity not derived from all the bases %s.",
184  (int)value_size, value, str);
185  }
186  free(str);
187  return ret;
188  }
189 
190  return LY_SUCCESS;
191 }
192 
208 static LY_ERR
209 identityref_check_ident(const struct lysc_ident *ident, const char *value,
210  uint32_t value_size, uint32_t options, struct lys_glob_unres *unres, struct ly_err_item **err)
211 {
212  LY_ERR ret = LY_SUCCESS;
213 
214  if (!ident->module->implemented) {
215  if (options & LYPLG_TYPE_STORE_IMPLEMENT) {
216  ret = lyplg_type_make_implemented(ident->module, NULL, unres);
217  } else {
218  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
219  "Invalid identityref \"%.*s\" value - identity found in non-implemented module \"%s\".",
220  (int)value_size, (char *)value, ident->module->name);
221  }
222  } else if (ident->module->parsed && (lys_identity_iffeature_value(ident) == LY_ENOT)) {
223  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
224  "Invalid identityref \"%.*s\" value - identity is disabled by if-feature.",
225  (int)value_size, value);
226  }
227 
228  return ret;
229 }
230 
231 static LY_ERR
232 lyplg_type_store_identityref(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint32_t value_size_bits,
233  uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
234  const struct lysc_ext_instance *UNUSED(top_ext), struct lyd_value *storage, struct lys_glob_unres *unres,
235  struct ly_err_item **err)
236 {
237  LY_ERR ret = LY_SUCCESS;
238  struct lysc_type_identityref *type_ident = (struct lysc_type_identityref *)type;
239  uint32_t value_size;
240  char *canon;
241  struct lysc_ident *ident = NULL;
242 
243  /* init storage */
244  memset(storage, 0, sizeof *storage);
245  storage->realtype = type;
246 
247  /* check value length */
248  ret = lyplg_type_check_value_size("identityref", format, value_size_bits, LYPLG_LYB_SIZE_VARIABLE_BYTES, 0,
249  &value_size, err);
250  LY_CHECK_GOTO(ret, cleanup);
251 
252  /* check hints */
253  ret = lyplg_type_check_hints(hints, value, value_size, type->basetype, NULL, err);
254  LY_CHECK_GOTO(ret, cleanup);
255 
256  /* find a matching identity */
257  ret = identityref_str2ident(value, value_size, format, prefix_data, ctx, ctx_node, &ident, err);
258  LY_CHECK_GOTO(ret, cleanup);
259 
260  /* check if the identity is enabled */
261  ret = identityref_check_ident(ident, value, value_size, options, unres, err);
262  LY_CHECK_GOTO(ret, cleanup);
263 
264  /* check that the identity is derived form all the bases */
265  ret = identityref_check_base(ident, type_ident, value, value_size, err);
266  LY_CHECK_GOTO(ret, cleanup);
267 
268  if (ctx_node) {
269  /* check status */
270  ret = lyplg_type_check_status(ctx_node, ident->flags, format, prefix_data, ident->name, err);
271  LY_CHECK_GOTO(ret, cleanup);
272  }
273 
274  /* store value */
275  storage->ident = ident;
276 
277  /* store canonical value */
278  if (format == LY_VALUE_CANON) {
279  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
280  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
281  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
282  LY_CHECK_GOTO(ret, cleanup);
283  } else {
284  ret = lydict_insert(ctx, value, value_size, &storage->_canonical);
285  LY_CHECK_GOTO(ret, cleanup);
286  }
287  } else {
288  /* JSON format with prefix is the canonical one */
289  if (asprintf(&canon, "%s:%s", ident->module->name, ident->name) == -1) {
290  LOGMEM(ctx);
291  ret = LY_EMEM;
292  goto cleanup;
293  }
294 
295  ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
296  LY_CHECK_GOTO(ret, cleanup);
297  }
298 
299 cleanup:
300  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
301  free((void *)value);
302  }
303 
304  if (ret) {
305  lyplg_type_free_simple(ctx, storage);
306  }
307  return ret;
308 }
309 
310 static LY_ERR
311 lyplg_type_compare_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
312  const struct lyd_value *val2)
313 {
314  if (val1->ident == val2->ident) {
315  return LY_SUCCESS;
316  }
317  return LY_ENOT;
318 }
319 
320 static int
321 lyplg_type_sort_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
322  const struct lyd_value *val2)
323 {
324  return strcmp(val1->ident->name, val2->ident->name);
325 }
326 
327 static const void *
328 lyplg_type_print_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
329  void *prefix_data, ly_bool *dynamic, uint32_t *value_size_bits)
330 {
331  char *ret;
332  uint32_t value_size;
333 
334  if (format == LY_VALUE_CANON) {
335  if (dynamic) {
336  *dynamic = 0;
337  }
338  if (value_size_bits) {
339  *value_size_bits = strlen(value->_canonical) * 8;
340  }
341  return value->_canonical;
342  }
343 
344  /* print the value in the specific format */
345  if (identityref_ident2str(value->ident, format, prefix_data, &ret, &value_size)) {
346  return NULL;
347  }
348  *dynamic = 1;
349  if (value_size_bits) {
350  *value_size_bits = value_size * 8;
351  }
352 
353  return ret;
354 }
355 
364  {
365  .module = "",
366  .revision = NULL,
367  .name = LY_TYPE_IDENT_STR,
368 
369  .plugin.id = "ly2 identityref",
370  .plugin.lyb_size = lyplg_type_lyb_size_variable_bytes,
371  .plugin.store = lyplg_type_store_identityref,
372  .plugin.validate_value = NULL,
373  .plugin.validate_tree = NULL,
374  .plugin.compare = lyplg_type_compare_identityref,
375  .plugin.sort = lyplg_type_sort_identityref,
376  .plugin.print = lyplg_type_print_identityref,
377  .plugin.duplicate = lyplg_type_dup_simple,
378  .plugin.free = lyplg_type_free_simple,
379  },
380  {0}
381 };
struct lysc_type * realtype
Definition: tree_data.h:567
Compiled YANG data node.
Definition: tree_schema.h:1434
memset(value->fixed_mem, 0, LYD_VALUE_FIXED_MEM_SIZE)
struct lysp_module * parsed
Definition: tree_schema.h:2196
uint16_t flags
Definition: tree_schema.h:1234
LIBYANG_API_DECL LY_ERR lyplg_type_check_value_size(const char *type_name, LY_VALUE_FORMAT format, uint32_t value_size_bits, enum lyplg_lyb_size_type lyb_size_type, uint32_t lyb_fixed_size_bits, uint32_t *value_size, struct ly_err_item **err)
Check a value type in bits is correct and as expected.
YANG extension compiled instance.
Definition: plugins_exts.h:436
LY_ERR
libyang&#39;s error codes returned by the libyang functions.
Definition: log.h:240
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:1230
struct lysc_ident * identities
Definition: tree_schema.h:2202
ly_bool implemented
Definition: tree_schema.h:2214
Definition: log.h:254
#define LYPLG_TYPE_STORE_DYNAMIC
YANG identity-stmt.
Definition: tree_schema.h:1226
#define LOGMEM(CTX)
Definition: tree_edit.h:22
struct lyplg_type_record plugins_identityref[]
Plugin information for identityref type implementation.
Definition: identityref.c:363
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.
Definition: log.h:242
The main libyang public header.
LIBYANG_API_DECL void lyplg_type_lyb_size_variable_bytes(const struct lysc_type *type, enum lyplg_lyb_size_type *size_type, uint32_t *fixed_size_bits)
Implementation of lyplg_type_lyb_size_clb for a type with variable length rounded to bytes...
YANG data representation.
Definition: tree_data.h:563
const char * _canonical
Definition: tree_data.h:564
Libyang full error structure.
Definition: log.h:285
Definition: log.h:277
LIBYANG_API_DECL struct lys_module * lyplg_type_identity_module(const struct ly_ctx *ctx, const struct lysc_node *ctx_node, const char *prefix, uint32_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 *data_path, char *apptag, const char *err_format,...) _FORMAT_PRINTF(6
Create and fill error structure.
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:2184
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.
Definition: log.h:248
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
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.
#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:1392
LY_DATA_TYPE basetype
Definition: tree_schema.h:1300
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.
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.
LIBYANG_API_DECL LY_ERR lyplg_type_check_hints(uint32_t hints, const char *value, uint32_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.
API for (user) types plugins.
const char * name
Definition: tree_schema.h:1227
libyang context handler.
const char * name
Definition: tree_schema.h:2186