libyang  6.3.1
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 "compat.h"
25 #include "dict.h"
26 #include "ly_array.h"
27 #include "ly_common.h"
28 #include "plugins_internal.h"
29 
49 static LY_ERR
50 identityref_ident2str(const struct lysc_ident *ident, LY_VALUE_FORMAT format, void *prefix_data, char **str, uint32_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 = (uint32_t)len;
69  }
70  return LY_SUCCESS;
71 }
72 
86 static LY_ERR
87 identityref_str2ident(const char *value, uint32_t value_size, 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  uint32_t id_len, prefix_len;
92  const struct lys_module *mod;
93  LYA_COUNT_T u;
94  struct lysc_ident *id, *identities;
95 
96  /* locate prefix if any */
97  for (prefix_len = 0; (prefix_len < value_size) && (value[prefix_len] != ':'); ++prefix_len) {}
98  if (prefix_len < value_size) {
99  id_name = &value[prefix_len + 1];
100  id_len = value_size - (prefix_len + 1);
101  } else {
102  prefix_len = 0;
103  id_name = value;
104  id_len = value_size;
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 = lys_find_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_size, value);
115  }
116 
117  id = NULL;
118  identities = mod->identities;
119  LYA_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_size, 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  uint32_t value_size, struct ly_err_item **err)
149 {
150  LY_ERR ret;
151  uint32_t str_len;
152  char *str;
153  LYA_COUNT_T u;
154  struct lysc_ident *base;
155 
156  /* check that the identity matches some of the type's base identities */
157  LYA_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 == LYA_COUNT(type->bases)) {
166  str = NULL;
167  str_len = 1;
168  LYA_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_size, 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_size, 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, uint32_t value_size, uint32_t options,
209  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_size, (char *)value, ident->module->name);
220  }
221  } else if (ident->module->parsed && (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_size, value);
225  }
226 
227  return ret;
228 }
229 
230 static LY_ERR
231 lyplg_type_store_identityref(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, uint64_t value_size_bits,
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  uint32_t value_size;
238  char *canon;
239  struct lysc_ident *ident = NULL;
240 
241  /* init storage */
242  memset(storage, 0, sizeof *storage);
243  storage->realtype = type;
244 
245  /* check value length */
246  ret = lyplg_type_check_value_size("identityref", format, value_size_bits, LYPLG_LYB_SIZE_VARIABLE_BYTES, 0,
247  &value_size, err);
248  LY_CHECK_GOTO(ret, cleanup);
249 
250  /* check hints */
251  ret = lyplg_type_check_hints(hints, value, value_size, type->basetype, NULL, err);
252  LY_CHECK_GOTO(ret, cleanup);
253 
254  /* find a matching identity */
255  ret = identityref_str2ident(value, value_size, format, prefix_data, ctx, ctx_node, &ident, err);
256  LY_CHECK_GOTO(ret, cleanup);
257 
258  /* check if the identity is enabled */
259  ret = identityref_check_ident(ident, value, value_size, options, unres, err);
260  LY_CHECK_GOTO(ret, cleanup);
261 
262  /* check that the identity is derived form all the bases */
263  ret = identityref_check_base(ident, type_ident, value, value_size, err);
264  LY_CHECK_GOTO(ret, cleanup);
265 
266  if (ctx_node) {
267  /* check status */
268  ret = lyplg_type_check_status(ctx_node, ident->flags, format, prefix_data, ident->name, err);
269  LY_CHECK_GOTO(ret, cleanup);
270  }
271 
272  /* store value */
273  storage->ident = ident;
274 
275  /* store canonical value */
276  if (format == LY_VALUE_CANON) {
277  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
278  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
279  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
280  LY_CHECK_GOTO(ret, cleanup);
281  } else {
282  ret = lydict_insert(ctx, value, value_size, &storage->_canonical);
283  LY_CHECK_GOTO(ret, cleanup);
284  }
285  } else {
286  /* JSON format with prefix is the canonical one */
287  if (asprintf(&canon, "%s:%s", ident->module->name, ident->name) == -1) {
288  LOGMEM(ctx);
289  ret = LY_EMEM;
290  goto cleanup;
291  }
292 
293  ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
294  LY_CHECK_GOTO(ret, cleanup);
295  }
296 
297 cleanup:
298  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
299  free((void *)value);
300  }
301 
302  if (ret) {
303  lyplg_type_free_simple(ctx, storage);
304  }
305  return ret;
306 }
307 
308 static LY_ERR
309 lyplg_type_compare_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
310  const struct lyd_value *val2)
311 {
312  if (val1->ident == val2->ident) {
313  return LY_SUCCESS;
314  }
315  return LY_ENOT;
316 }
317 
318 static int
319 lyplg_type_sort_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
320  const struct lyd_value *val2)
321 {
322  return strcmp(val1->ident->name, val2->ident->name);
323 }
324 
325 static const void *
326 lyplg_type_print_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
327  void *prefix_data, ly_bool *dynamic, uint64_t *value_size_bits)
328 {
329  char *ret;
330  uint32_t value_size;
331 
332  if (format == LY_VALUE_CANON) {
333  if (dynamic) {
334  *dynamic = 0;
335  }
336  if (value_size_bits) {
337  *value_size_bits = strlen(value->_canonical) * 8;
338  }
339  return value->_canonical;
340  }
341 
342  /* print the value in the specific format */
343  if (identityref_ident2str(value->ident, format, prefix_data, &ret, &value_size)) {
344  return NULL;
345  }
346  *dynamic = 1;
347  if (value_size_bits) {
348  *value_size_bits = value_size * 8;
349  }
350 
351  return ret;
352 }
353 
362  {
363  .module = "",
364  .revision = NULL,
365  .name = LY_TYPE_IDENT_STR,
366 
367  .plugin.id = "ly2 identityref",
368  .plugin.lyb_size = lyplg_type_lyb_size_variable_bytes,
369  .plugin.store = lyplg_type_store_identityref,
370  .plugin.validate_value = NULL,
371  .plugin.validate_tree = NULL,
372  .plugin.compare = lyplg_type_compare_identityref,
373  .plugin.sort = lyplg_type_sort_identityref,
374  .plugin.print = lyplg_type_print_identityref,
375  .plugin.duplicate = lyplg_type_dup_simple,
376  .plugin.free = lyplg_type_free_simple,
377  },
378  {0}
379 };
#define LYA_COUNT_T
Type (i.e. size) of the sized array&#39;s size counter.
Definition: ly_array.h:38
struct lysc_type * realtype
Definition: tree_data.h:615
Compiled YANG data node.
Definition: tree_schema.h:1430
#define LYA_FOR(ARRAY, INDEX)
Helper macro to go through sized-arrays with a numeric iterator.
Definition: ly_array.h:55
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
libyang dictionary
Definition: log.h:269
#define LYPLG_TYPE_STORE_DYNAMIC
YANG identity-stmt.
Definition: tree_schema.h:1221
struct lyplg_type_record plugins_identityref[]
Plugin information for identityref type implementation.
Definition: identityref.c:361
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
YANG data representation.
Definition: tree_data.h:611
const char * _canonical
Definition: tree_data.h:612
Libyang full error structure.
Definition: log.h:301
#define LYA_COUNT(ARRAY)
Get the number of records in the ARRAY.
Definition: ly_array.h:78
Definition: log.h:293
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 sized array API.
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
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: utils.h:93
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