libyang  3.1.0
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, size_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 = (size_t)len;
70  }
71  return LY_SUCCESS;
72 }
73 
87 static LY_ERR
88 identityref_str2ident(const char *value, size_t value_len, 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  size_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_len) && (value[prefix_len] != ':'); ++prefix_len) {}
99  if (prefix_len < value_len) {
100  id_name = &value[prefix_len + 1];
101  id_len = value_len - (prefix_len + 1);
102  } else {
103  prefix_len = 0;
104  id_name = value;
105  id_len = value_len;
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_len, 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_len, 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  size_t value_len, struct ly_err_item **err)
150 {
151  LY_ERR ret;
152  size_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_len, 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_len, 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  size_t value_len, 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_len, (char *)value, ident->module->name);
221  }
222  } else if (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_len, value);
226  }
227 
228  return ret;
229 }
230 
231 LIBYANG_API_DEF LY_ERR
232 lyplg_type_store_identityref(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
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  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 hints */
246  ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
247  LY_CHECK_GOTO(ret, cleanup);
248 
249  /* find a matching identity */
250  ret = identityref_str2ident(value, value_len, format, prefix_data, ctx, ctx_node, &ident, err);
251  LY_CHECK_GOTO(ret, cleanup);
252 
253  /* check if the identity is enabled */
254  ret = identityref_check_ident(ident, value, value_len, options, unres, err);
255  LY_CHECK_GOTO(ret, cleanup);
256 
257  /* check that the identity is derived form all the bases */
258  ret = identityref_check_base(ident, type_ident, value, value_len, err);
259  LY_CHECK_GOTO(ret, cleanup);
260 
261  if (ctx_node) {
262  /* check status */
263  ret = lyplg_type_check_status(ctx_node, ident->flags, format, prefix_data, ident->name, err);
264  LY_CHECK_GOTO(ret, cleanup);
265  }
266 
267  /* store value */
268  storage->ident = ident;
269 
270  /* store canonical value */
271  if (format == LY_VALUE_CANON) {
272  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
273  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
274  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
275  LY_CHECK_GOTO(ret, cleanup);
276  } else {
277  ret = lydict_insert(ctx, value, value_len, &storage->_canonical);
278  LY_CHECK_GOTO(ret, cleanup);
279  }
280  } else {
281  /* JSON format with prefix is the canonical one */
282  if (asprintf(&canon, "%s:%s", ident->module->name, ident->name) == -1) {
283  LOGMEM(ctx);
284  ret = LY_EMEM;
285  goto cleanup;
286  }
287 
288  ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
289  LY_CHECK_GOTO(ret, cleanup);
290  }
291 
292 cleanup:
293  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
294  free((void *)value);
295  }
296 
297  if (ret) {
298  lyplg_type_free_simple(ctx, storage);
299  }
300  return ret;
301 }
302 
303 LIBYANG_API_DEF LY_ERR
304 lyplg_type_compare_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
305  const struct lyd_value *val2)
306 {
307  if (val1->ident == val2->ident) {
308  return LY_SUCCESS;
309  }
310  return LY_ENOT;
311 }
312 
313 LIBYANG_API_DEF int
314 lyplg_type_sort_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *val1,
315  const struct lyd_value *val2)
316 {
317  return strcmp(val1->ident->name, val2->ident->name);
318 }
319 
320 LIBYANG_API_DEF const void *
321 lyplg_type_print_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
322  void *prefix_data, ly_bool *dynamic, size_t *value_len)
323 {
324  char *ret;
325 
326  if (format == LY_VALUE_CANON) {
327  if (dynamic) {
328  *dynamic = 0;
329  }
330  if (value_len) {
331  *value_len = strlen(value->_canonical);
332  }
333  return value->_canonical;
334  }
335 
336  /* print the value in the specific format */
337  if (identityref_ident2str(value->ident, format, prefix_data, &ret, value_len)) {
338  return NULL;
339  }
340  *dynamic = 1;
341  return ret;
342 }
343 
352  {
353  .module = "",
354  .revision = NULL,
355  .name = LY_TYPE_IDENT_STR,
356 
357  .plugin.id = "libyang 2 - identityref, version 1",
358  .plugin.store = lyplg_type_store_identityref,
359  .plugin.validate = NULL,
360  .plugin.compare = lyplg_type_compare_identityref,
361  .plugin.sort = lyplg_type_sort_identityref,
362  .plugin.print = lyplg_type_print_identityref,
363  .plugin.duplicate = lyplg_type_dup_simple,
364  .plugin.free = lyplg_type_free_simple,
365  .plugin.lyb_data_len = -1,
366  },
367  {0}
368 };
struct lysc_type * realtype
Definition: tree_data.h:575
Compiled YANG data node.
Definition: tree_schema.h:1439
memset(value->fixed_mem, 0, LYD_VALUE_FIXED_MEM_SIZE)
uint16_t flags
Definition: tree_schema.h:1238
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.
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:1234
Definition: log.h:242
struct lysc_ident * identities
Definition: tree_schema.h:2147
LIBYANG_API_DEF int lyplg_type_sort_identityref(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of lyplg_type_sort_clb for the built-in identityref type.
ly_bool implemented
Definition: tree_schema.h:2158
#define LYPLG_TYPE_STORE_DYNAMIC
YANG identity-stmt.
Definition: tree_schema.h:1230
#define LOGMEM(CTX)
Definition: tree_edit.h:22
struct lyplg_type_record plugins_identityref[]
Plugin information for identityref type implementation.
Definition: identityref.c:351
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:571
const char * _canonical
Definition: tree_data.h:572
Libyang full error structure.
Definition: log.h:285
Definition: log.h:277
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 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:2131
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
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:232
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
Definition: log.h:248
struct lysc_ident ** bases
Definition: tree_schema.h:1397
LY_DATA_TYPE basetype
Definition: tree_schema.h:1305
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.
API for (user) types plugins.
const char * name
Definition: tree_schema.h:1231
LY_ERR
libyang&#39;s error codes returned by the libyang functions.
Definition: log.h:240
libyang context handler.
const char * name
Definition: tree_schema.h:2133
LIBYANG_API_DECL LY_ERR lyplg_type_compare_identityref(const struct ly_ctx *ctx, const struct lyd_value *val1, const struct lyd_value *val2)
Implementation of lyplg_type_compare_clb for the built-in identityref type.
Definition: log.h:254