libyang  2.1.30
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 
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 
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 };
struct lysc_type * realtype
Definition: tree_data.h:564
Compiled YANG data node.
Definition: tree_schema.h:1414
uint16_t flags
Definition: tree_schema.h:1233
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.
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.
Definition: log.h:256
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:1229
struct lysc_ident * identities
Definition: tree_schema.h:2113
ly_bool implemented
Definition: tree_schema.h:2124
#define LYPLG_TYPE_STORE_DYNAMIC
YANG identity-stmt.
Definition: tree_schema.h:1225
struct lyplg_type_record plugins_identityref[]
Plugin information for identityref type implementation.
Definition: identityref.c:335
LIBYANG_API_DECL 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_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:560
const char * _canonical
Definition: tree_data.h:561
Libyang full error structure.
Definition: log.h:299
Definition: log.h:291
Definition: log.h:262
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:2097
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
Definition: log.h:268
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:223
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:1378
LY_DATA_TYPE basetype
Definition: tree_schema.h:1299
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.
LY_ERR
libyang&#39;s error codes returned by the libyang functions.
Definition: log.h:254
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:1226
libyang context handler.
const char * name
Definition: tree_schema.h:2099