libyang  2.0.194
libyang is YANG data modelling language parser and toolkit written (and providing API) in C.
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 
54  len = asprintf(str, "%s:%s", lyplg_type_get_prefix(ident->module, format, prefix_data), ident->name);
55  if (len == -1) {
56  return LY_EMEM;
57  }
58 
59  if (str_len) {
60  *str_len = (size_t)len;
61  }
62  return LY_SUCCESS;
63 }
64 
78 static LY_ERR
79 identityref_str2ident(const char *value, size_t value_len, LY_VALUE_FORMAT format, void *prefix_data,
80  const struct ly_ctx *ctx, const struct lysc_node *ctx_node, struct lysc_ident **ident, struct ly_err_item **err)
81 {
82  const char *id_name, *prefix = value;
83  size_t id_len, prefix_len;
84  const struct lys_module *mod;
86  struct lysc_ident *id, *identities;
87 
88  /* locate prefix if any */
89  for (prefix_len = 0; (prefix_len < value_len) && (value[prefix_len] != ':'); ++prefix_len) {}
90  if (prefix_len < value_len) {
91  id_name = &value[prefix_len + 1];
92  id_len = value_len - (prefix_len + 1);
93  } else {
94  prefix_len = 0;
95  id_name = value;
96  id_len = value_len;
97  }
98 
99  if (!id_len) {
100  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid empty identityref value.");
101  }
102 
103  mod = lyplg_type_identity_module(ctx, ctx_node, prefix, prefix_len, format, prefix_data);
104  if (!mod) {
105  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
106  "Invalid identityref \"%.*s\" value - unable to map prefix to YANG schema.", (int)value_len, value);
107  }
108 
109  id = NULL;
110  identities = mod->identities;
111  LY_ARRAY_FOR(identities, u) {
112  if (!ly_strncmp(identities[u].name, id_name, id_len)) {
113  /* we have match */
114  id = &identities[u];
115  break;
116  }
117  }
118  if (!id) {
119  /* no match */
120  return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
121  "Invalid identityref \"%.*s\" value - identity not found in module \"%s\".",
122  (int)value_len, value, mod->name);
123  }
124 
125  *ident = id;
126  return LY_SUCCESS;
127 }
128 
138 static LY_ERR
139 identityref_check_base(const struct lysc_ident *ident, struct lysc_type_identityref *type, const char *value,
140  size_t value_len, struct ly_err_item **err)
141 {
142  LY_ERR ret;
143  size_t str_len;
144  char *str;
146  struct lysc_ident *base;
147 
148  /* check that the identity matches some of the type's base identities */
149  LY_ARRAY_FOR(type->bases, u) {
150  if (!lyplg_type_identity_isderived(type->bases[u], ident)) {
151  /* we have match */
152  break;
153  }
154  }
155 
156  /* it does not, generate a nice error */
157  if (u == LY_ARRAY_COUNT(type->bases)) {
158  str = NULL;
159  str_len = 1;
160  LY_ARRAY_FOR(type->bases, u) {
161  base = type->bases[u];
162  str_len += (u ? 2 : 0) + 1 + strlen(base->module->name) + 1 + strlen(base->name) + 1;
163  str = ly_realloc(str, str_len);
164  sprintf(str + (u ? strlen(str) : 0), "%s\"%s:%s\"", u ? ", " : "", base->module->name, base->name);
165  }
166 
167  /* no match */
168  if (u == 1) {
169  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
170  "Invalid identityref \"%.*s\" value - identity not derived from the base %s.",
171  (int)value_len, value, str);
172  } else {
173  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
174  "Invalid identityref \"%.*s\" value - identity not derived from all the bases %s.",
175  (int)value_len, value, str);
176  }
177  free(str);
178  return ret;
179  }
180 
181  return LY_SUCCESS;
182 }
183 
199 static LY_ERR
200 identityref_check_ident(const struct lysc_ident *ident, const char *value,
201  size_t value_len, uint32_t options, struct lys_glob_unres *unres, struct ly_err_item **err)
202 {
203  LY_ERR ret = LY_SUCCESS;
204 
205  if (!ident->module->implemented) {
206  if (options & LYPLG_TYPE_STORE_IMPLEMENT) {
207  ret = lyplg_type_make_implemented(ident->module, NULL, unres);
208  } else {
209  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
210  "Invalid identityref \"%.*s\" value - identity found in non-implemented module \"%s\".",
211  (int)value_len, (char *)value, ident->module->name);
212  }
213  } else if (lys_identity_iffeature_value(ident) == LY_ENOT) {
214  ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL,
215  "Invalid identityref \"%.*s\" value - identity is disabled by if-feature.",
216  (int)value_len, value);
217  }
218 
219  return ret;
220 }
221 
222 LIBYANG_API_DEF LY_ERR
223 lyplg_type_store_identityref(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
224  uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
225  struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err)
226 {
227  LY_ERR ret = LY_SUCCESS;
228  struct lysc_type_identityref *type_ident = (struct lysc_type_identityref *)type;
229  char *canon;
230  struct lysc_ident *ident = NULL;
231 
232  /* init storage */
233  memset(storage, 0, sizeof *storage);
234  storage->realtype = type;
235 
236  /* check hints */
237  ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
238  LY_CHECK_GOTO(ret, cleanup);
239 
240  /* find a matching identity */
241  ret = identityref_str2ident(value, value_len, format, prefix_data, ctx, ctx_node, &ident, err);
242  LY_CHECK_GOTO(ret, cleanup);
243 
244  /* check if the identity is enabled */
245  ret = identityref_check_ident(ident, value, value_len, options, unres, err);
246  LY_CHECK_GOTO(ret, cleanup);
247 
248  /* check that the identity is derived form all the bases */
249  ret = identityref_check_base(ident, type_ident, value, value_len, err);
250  LY_CHECK_GOTO(ret, cleanup);
251 
252  if (ctx_node) {
253  /* check status */
254  ret = lyplg_type_check_status(ctx_node, ident->flags, format, prefix_data, ident->name, err);
255  LY_CHECK_GOTO(ret, cleanup);
256  }
257 
258  /* store value */
259  storage->ident = ident;
260 
261  /* store canonical value */
262  if (format == LY_VALUE_CANON) {
263  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
264  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
265  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
266  LY_CHECK_GOTO(ret, cleanup);
267  } else {
268  ret = lydict_insert(ctx, value, value_len, &storage->_canonical);
269  LY_CHECK_GOTO(ret, cleanup);
270  }
271  } else {
272  /* JSON format with prefix is the canonical one */
273  ret = identityref_ident2str(ident, LY_VALUE_JSON, NULL, &canon, NULL);
274  LY_CHECK_GOTO(ret, cleanup);
275 
276  ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
277  LY_CHECK_GOTO(ret, cleanup);
278  }
279 
280 cleanup:
281  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
282  free((void *)value);
283  }
284 
285  if (ret) {
286  lyplg_type_free_simple(ctx, storage);
287  }
288  return ret;
289 }
290 
291 LIBYANG_API_DEF LY_ERR
292 lyplg_type_compare_identityref(const struct lyd_value *val1, const struct lyd_value *val2)
293 {
294  if (val1->realtype != val2->realtype) {
295  return LY_ENOT;
296  }
297 
298  if (val1->ident == val2->ident) {
299  return LY_SUCCESS;
300  }
301  return LY_ENOT;
302 }
303 
304 LIBYANG_API_DEF const void *
305 lyplg_type_print_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
306  void *prefix_data, ly_bool *dynamic, size_t *value_len)
307 {
308  char *ret;
309 
310  if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
311  if (dynamic) {
312  *dynamic = 0;
313  }
314  if (value_len) {
315  *value_len = strlen(value->_canonical);
316  }
317  return value->_canonical;
318  }
319 
320  /* print the value in the specific format */
321  if (identityref_ident2str(value->ident, format, prefix_data, &ret, value_len)) {
322  return NULL;
323  }
324  *dynamic = 1;
325  return ret;
326 }
327 
335 const struct lyplg_type_record plugins_identityref[] = {
336  {
337  .module = "",
338  .revision = NULL,
339  .name = LY_TYPE_IDENT_STR,
340 
341  .plugin.id = "libyang 2 - identityref, version 1",
342  .plugin.store = lyplg_type_store_identityref,
343  .plugin.validate = NULL,
344  .plugin.compare = lyplg_type_compare_identityref,
345  .plugin.sort = NULL,
346  .plugin.print = lyplg_type_print_identityref,
347  .plugin.duplicate = lyplg_type_dup_simple,
348  .plugin.free = lyplg_type_free_simple,
349  .plugin.lyb_data_len = -1,
350  },
351  {0}
352 };
libyang context handler.
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...
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,...
LY_ERR
libyang's error codes returned by the libyang functions.
Definition: log.h:244
@ LYVE_DATA
Definition: log.h:281
@ LY_EMEM
Definition: log.h:246
@ LY_ENOT
Definition: log.h:258
@ LY_EVALID
Definition: log.h:252
@ LY_SUCCESS
Definition: log.h:245
Libyang full error structure.
Definition: log.h:289
const char * module
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.
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.
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 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 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 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.
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's hints (if any) in the specified format.
LIBYANG_API_DEF 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:292
LIBYANG_API_DEF 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:223
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.
#define LYPLG_TYPE_STORE_DYNAMIC
#define LYPLG_TYPE_STORE_IMPLEMENT
const char * name
Definition: tree_schema.h:2343
LY_DATA_TYPE basetype
Definition: tree_schema.h:1536
const char * name
Definition: tree_schema.h:1463
struct lysc_ident * identities
Definition: tree_schema.h:2357
struct lys_module * module
Definition: tree_schema.h:1466
ly_bool implemented
Definition: tree_schema.h:2368
uint16_t flags
Definition: tree_schema.h:1470
struct lysc_ident ** bases
Definition: tree_schema.h:1614
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.
Available YANG schema tree structures representing YANG module.
Definition: tree_schema.h:2341
YANG identity-stmt.
Definition: tree_schema.h:1462
Compiled YANG data node.
Definition: tree_schema.h:1650
#define LY_ARRAY_COUNT(ARRAY)
Get the number of records in the ARRAY.
Definition: tree.h:148
#define LY_ARRAY_FOR(ARRAY,...)
Sized-array iterator (for-loop).
Definition: tree.h:167
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition: tree.h:235
#define LY_ARRAY_COUNT_TYPE
Type (i.e. size) of the sized array's size counter.
Definition: tree.h:104
@ LY_VALUE_JSON
Definition: tree.h:240
@ LY_VALUE_CANON
Definition: tree.h:236
@ LY_VALUE_LYB
Definition: tree.h:241
LIBYANG_API_DEF const void * lyplg_type_print_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format, void *prefix_data, ly_bool *dynamic, size_t *value_len)
Definition: identityref.c:305
const struct lyplg_type_record plugins_identityref[]
Plugin information for identityref type implementation.
Definition: identityref.c:335
The main libyang public header.
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:27
API for (user) types plugins.
const struct lysc_type * realtype
Definition: tree_data.h:564
const char * _canonical
Definition: tree_data.h:561
YANG data representation.
Definition: tree_data.h:560
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,...