libyang  5.8.5
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 = lys_find_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, uint32_t value_size, uint32_t options,
210  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, uint64_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  struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
235 {
236  LY_ERR ret = LY_SUCCESS;
237  struct lysc_type_identityref *type_ident = (struct lysc_type_identityref *)type;
238  uint32_t value_size;
239  char *canon;
240  struct lysc_ident *ident = NULL;
241 
242  /* init storage */
243  memset(storage, 0, sizeof *storage);
244  storage->realtype = type;
245 
246  /* check value length */
247  ret = lyplg_type_check_value_size("identityref", format, value_size_bits, LYPLG_LYB_SIZE_VARIABLE_BYTES, 0,
248  &value_size, err);
249  LY_CHECK_GOTO(ret, cleanup);
250 
251  /* check hints */
252  ret = lyplg_type_check_hints(hints, value, value_size, type->basetype, NULL, err);
253  LY_CHECK_GOTO(ret, cleanup);
254 
255  /* find a matching identity */
256  ret = identityref_str2ident(value, value_size, format, prefix_data, ctx, ctx_node, &ident, err);
257  LY_CHECK_GOTO(ret, cleanup);
258 
259  /* check if the identity is enabled */
260  ret = identityref_check_ident(ident, value, value_size, options, unres, err);
261  LY_CHECK_GOTO(ret, cleanup);
262 
263  /* check that the identity is derived form all the bases */
264  ret = identityref_check_base(ident, type_ident, value, value_size, err);
265  LY_CHECK_GOTO(ret, cleanup);
266 
267  if (ctx_node) {
268  /* check status */
269  ret = lyplg_type_check_status(ctx_node, ident->flags, format, prefix_data, ident->name, err);
270  LY_CHECK_GOTO(ret, cleanup);
271  }
272 
273  /* store value */
274  storage->ident = ident;
275 
276  /* store canonical value */
277  if (format == LY_VALUE_CANON) {
278  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
279  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
280  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
281  LY_CHECK_GOTO(ret, cleanup);
282  } else {
283  ret = lydict_insert(ctx, value, value_size, &storage->_canonical);
284  LY_CHECK_GOTO(ret, cleanup);
285  }
286  } else {
287  /* JSON format with prefix is the canonical one */
288  if (asprintf(&canon, "%s:%s", ident->module->name, ident->name) == -1) {
289  LOGMEM(ctx);
290  ret = LY_EMEM;
291  goto cleanup;
292  }
293 
294  ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
295  LY_CHECK_GOTO(ret, cleanup);
296  }
297 
298 cleanup:
299  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
300  free((void *)value);
301  }
302 
303  if (ret) {
304  lyplg_type_free_simple(ctx, storage);
305  }
306  return ret;
307 }
308 
309 static LY_ERR
310 lyplg_type_compare_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
311  const struct lyd_value *val2)
312 {
313  if (val1->ident == val2->ident) {
314  return LY_SUCCESS;
315  }
316  return LY_ENOT;
317 }
318 
319 static int
320 lyplg_type_sort_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
321  const struct lyd_value *val2)
322 {
323  return strcmp(val1->ident->name, val2->ident->name);
324 }
325 
326 static const void *
327 lyplg_type_print_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
328  void *prefix_data, ly_bool *dynamic, uint64_t *value_size_bits)
329 {
330  char *ret;
331  uint32_t value_size;
332 
333  if (format == LY_VALUE_CANON) {
334  if (dynamic) {
335  *dynamic = 0;
336  }
337  if (value_size_bits) {
338  *value_size_bits = strlen(value->_canonical) * 8;
339  }
340  return value->_canonical;
341  }
342 
343  /* print the value in the specific format */
344  if (identityref_ident2str(value->ident, format, prefix_data, &ret, &value_size)) {
345  return NULL;
346  }
347  *dynamic = 1;
348  if (value_size_bits) {
349  *value_size_bits = value_size * 8;
350  }
351 
352  return ret;
353 }
354 
363  {
364  .module = "",
365  .revision = NULL,
366  .name = LY_TYPE_IDENT_STR,
367 
368  .plugin.id = "ly2 identityref",
369  .plugin.lyb_size = lyplg_type_lyb_size_variable_bytes,
370  .plugin.store = lyplg_type_store_identityref,
371  .plugin.validate_value = NULL,
372  .plugin.validate_tree = NULL,
373  .plugin.compare = lyplg_type_compare_identityref,
374  .plugin.sort = lyplg_type_sort_identityref,
375  .plugin.print = lyplg_type_print_identityref,
376  .plugin.duplicate = lyplg_type_dup_simple,
377  .plugin.free = lyplg_type_free_simple,
378  },
379  {0}
380 };
struct lysc_type * realtype
Definition: tree_data.h:551
Compiled YANG data node.
Definition: tree_schema.h:1430
memset(value->fixed_mem, 0, LYD_VALUE_FIXED_MEM_SIZE)
struct lysp_module * parsed
Definition: tree_schema.h:2276
uint16_t flags
Definition: tree_schema.h:1229
LIBYANG_API_DECL void lyplg_type_lyb_size_variable_bytes(const struct lysc_type *type, enum lyplg_lyb_size_type *size_type, uint64_t *fixed_size_bits)
Implementation of lyplg_type_lyb_size_clb for a type with variable length rounded to bytes...
LIBYANG_API_DECL struct lys_module * lys_find_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)
Find a module matching a prefix (or a default one).
LY_ERR
libyang&#39;s error codes returned by the libyang functions.
Definition: log.h:255
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:29
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:1225
struct lysc_ident * identities
Definition: tree_schema.h:2282
LIBYANG_API_DECL LY_ERR lyplg_type_check_value_size(const char *type_name, LY_VALUE_FORMAT format, uint64_t value_size_bits, enum lyplg_lyb_size_type lyb_size_type, uint64_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.
ly_bool implemented
Definition: tree_schema.h:2294
Definition: log.h:269
#define LYPLG_TYPE_STORE_DYNAMIC
YANG identity-stmt.
Definition: tree_schema.h:1221
#define LOGMEM(CTX)
Definition: tree_edit.h:22
struct lyplg_type_record plugins_identityref[]
Plugin information for identityref type implementation.
Definition: identityref.c:362
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:257
The main libyang public header.
YANG data representation.
Definition: tree_data.h:547
const char * _canonical
Definition: tree_data.h:548
Libyang full error structure.
Definition: log.h:300
Definition: log.h:292
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:2264
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:263
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:1388
LY_DATA_TYPE basetype
Definition: tree_schema.h:1296
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:1222
libyang context handler.
const char * name
Definition: tree_schema.h:2266