libyang  2.0.112
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 API 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  /* check status */
253  ret = lyplg_type_check_status(ctx_node, ident->flags, format, prefix_data, ident->name, err);
254  LY_CHECK_GOTO(ret, cleanup);
255 
256  /* store value */
257  storage->ident = ident;
258 
259  /* store canonical value */
260  if (format == LY_VALUE_CANON) {
261  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
262  ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
263  options &= ~LYPLG_TYPE_STORE_DYNAMIC;
264  LY_CHECK_GOTO(ret, cleanup);
265  } else {
266  ret = lydict_insert(ctx, value, value_len, &storage->_canonical);
267  LY_CHECK_GOTO(ret, cleanup);
268  }
269  } else {
270  /* JSON format with prefix is the canonical one */
271  ret = identityref_ident2str(ident, LY_VALUE_JSON, NULL, &canon, NULL);
272  LY_CHECK_GOTO(ret, cleanup);
273 
274  ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
275  LY_CHECK_GOTO(ret, cleanup);
276  }
277 
278 cleanup:
279  if (options & LYPLG_TYPE_STORE_DYNAMIC) {
280  free((void *)value);
281  }
282 
283  if (ret) {
284  lyplg_type_free_simple(ctx, storage);
285  }
286  return ret;
287 }
288 
289 API LY_ERR
290 lyplg_type_compare_identityref(const struct lyd_value *val1, const struct lyd_value *val2)
291 {
292  if (val1->realtype != val2->realtype) {
293  return LY_ENOT;
294  }
295 
296  if (val1->ident == val2->ident) {
297  return LY_SUCCESS;
298  }
299  return LY_ENOT;
300 }
301 
302 API const void *
303 lyplg_type_print_identityref(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
304  void *prefix_data, ly_bool *dynamic, size_t *value_len)
305 {
306  char *ret;
307 
308  if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
309  if (dynamic) {
310  *dynamic = 0;
311  }
312  if (value_len) {
313  *value_len = strlen(value->_canonical);
314  }
315  return value->_canonical;
316  }
317 
318  /* print the value in the specific format */
319  if (identityref_ident2str(value->ident, format, prefix_data, &ret, value_len)) {
320  return NULL;
321  }
322  *dynamic = 1;
323  return ret;
324 }
325 
334  {
335  .module = "",
336  .revision = NULL,
337  .name = LY_TYPE_IDENT_STR,
338 
339  .plugin.id = "libyang 2 - identityref, version 1",
340  .plugin.store = lyplg_type_store_identityref,
341  .plugin.validate = NULL,
342  .plugin.compare = lyplg_type_compare_identityref,
343  .plugin.sort = NULL,
344  .plugin.print = lyplg_type_print_identityref,
345  .plugin.duplicate = lyplg_type_dup_simple,
346  .plugin.free = lyplg_type_free_simple,
347  .plugin.lyb_data_len = -1,
348  },
349  {0}
350 };
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:290
struct lysc_type * realtype
Definition: tree_data.h:539
Compiled YANG data node.
Definition: tree_schema.h:1666
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.
uint16_t flags
Definition: tree_schema.h:1486
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:248
uint8_t ly_bool
Type to indicate boolean value.
Definition: log.h:25
struct lys_module * module
Definition: tree_schema.h:1482
struct lysc_ident * identities
Definition: tree_schema.h:2358
ly_bool implemented
Definition: tree_schema.h:2369
#define LYPLG_TYPE_STORE_DYNAMIC
LY_ERR lys_identity_iffeature_value(const struct lysc_ident *ident)
Get how the if-feature statement is evaluated for certain identity.
YANG identity-stmt.
Definition: tree_schema.h:1478
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...
struct lyplg_type_record plugins_identityref[]
Plugin information for identityref type implementation.
Definition: identityref.c:333
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.
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.
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...
YANG data representation.
Definition: tree_data.h:535
const char * _canonical
Definition: tree_data.h:536
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
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 full error structure.
Definition: log.h:291
Definition: log.h:283
Definition: log.h:254
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.
Available YANG schema tree structures representing YANG module.
Definition: tree_schema.h:2342
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.
const char * module
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.
#define LY_ARRAY_COUNT(ARRAY)
Get the number of records in the ARRAY.
Definition: tree.h:148
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.
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:260
#define LYPLG_TYPE_STORE_IMPLEMENT
LY_VALUE_FORMAT
All kinds of supported value formats and prefix mappings to modules.
Definition: tree.h:235
struct lysc_ident ** bases
Definition: tree_schema.h:1630
LY_DATA_TYPE basetype
Definition: tree_schema.h:1552
LY_ERR
libyang&#39;s error codes returned by the libyang functions.
Definition: log.h:245
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.
API for (user) types plugins.
const char * name
Definition: tree_schema.h:1479
libyang context handler.
const char * name
Definition: tree_schema.h:2344