kly.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. #include <stdlib.h>
  2. #include <stdint.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <assert.h>
  6. #include <syslog.h>
  7. #include <faux/faux.h>
  8. #include <faux/str.h>
  9. #include <faux/list.h>
  10. #include <faux/argv.h>
  11. #include <sysrepo.h>
  12. #include <sysrepo/xpath.h>
  13. #include <sysrepo/values.h>
  14. #include <libyang/tree_edit.h>
  15. #include "klish_plugin_sysrepo.h"
  16. int klysc_key_compare(const void *first, const void *second)
  17. {
  18. const klysc_key_t *f = (const klysc_key_t *)first;
  19. const klysc_key_t *s = (const klysc_key_t *)second;
  20. return strcmp(f->node->name, s->node->name);
  21. }
  22. int klysc_key_kcompare(const void *key, const void *list_item)
  23. {
  24. const char *f = (const char *)key;
  25. const klysc_key_t *s = (const klysc_key_t *)list_item;
  26. return strcmp(f, s->node->name);
  27. }
  28. // Get extension by name from schema node
  29. static bool_t klysc_ext(const struct lysc_ext_instance *exts,
  30. const char *module, const char *name, const char **argument)
  31. {
  32. LY_ARRAY_COUNT_TYPE u = 0;
  33. if (!exts)
  34. return BOOL_FALSE;
  35. LY_ARRAY_FOR(exts, u) {
  36. const struct lysc_ext_instance *ext = &exts[u];
  37. //syslog(LOG_ERR, "mod: %s, ext: %s", ext->def->module->name, ext->def->name);
  38. if (faux_str_cmp(ext->def->module->name, module) != 0)
  39. continue;
  40. if (faux_str_cmp(ext->def->name, name) != 0)
  41. continue;
  42. if (argument)
  43. *argument = ext->argument;
  44. return BOOL_TRUE;
  45. }
  46. return BOOL_FALSE;
  47. }
  48. // Get extension by name from node
  49. bool_t klysc_node_ext(const struct lysc_node *node,
  50. const char *module, const char *name, const char **argument)
  51. {
  52. if (!node)
  53. return BOOL_FALSE;
  54. if (klysc_ext(node->exts, module, name, argument))
  55. return BOOL_TRUE;
  56. return BOOL_FALSE;
  57. }
  58. // Get extension by name from type
  59. bool_t klysc_type_ext(const struct lysc_type *type,
  60. const char *module, const char *name, const char **argument)
  61. {
  62. if (!type)
  63. return BOOL_FALSE;
  64. if (klysc_ext(type->exts, module, name, argument))
  65. return BOOL_TRUE;
  66. return BOOL_FALSE;
  67. }
  68. // Get extension by name from node or type
  69. bool_t klysc_node_or_type_ext(const struct lysc_node *node,
  70. const char *module, const char *name, const char **argument)
  71. {
  72. struct lysc_type *type = NULL;
  73. if (!node)
  74. return BOOL_FALSE;
  75. if (klysc_node_ext(node, module, name, argument))
  76. return BOOL_TRUE;
  77. switch (node->nodetype) {
  78. case LYS_LEAF:
  79. type = ((struct lysc_node_leaf *)node)->type;
  80. break;
  81. case LYS_LEAFLIST:
  82. type = ((struct lysc_node_leaflist *)node)->type;
  83. break;
  84. default:
  85. return BOOL_FALSE;
  86. }
  87. if (klysc_type_ext(type, module, name, argument))
  88. return BOOL_TRUE;
  89. return BOOL_FALSE;
  90. }
  91. bool_t klysc_node_ext_is_password(const struct lysc_node *node)
  92. {
  93. return klysc_node_ext(node, "klish", "password", NULL);
  94. }
  95. const char *klysc_node_ext_completion(const struct lysc_node *node)
  96. {
  97. const char *xpath = NULL;
  98. klysc_node_or_type_ext(node, "klish", "completion", &xpath);
  99. return xpath;
  100. }
  101. const char *klysc_node_ext_default(const struct lysc_node *node)
  102. {
  103. const char *dflt = NULL;
  104. klysc_node_ext(node, "klish", "default", &dflt);
  105. return dflt;
  106. }
  107. char *klyd_esc_value(const char *value)
  108. {
  109. char *space = NULL;
  110. char *escaped = NULL;
  111. char *result = NULL;
  112. if (!value)
  113. return NULL;
  114. escaped = faux_str_c_esc(value);
  115. // String with space must have quotes
  116. space = strchr(escaped, ' ');
  117. if (space) {
  118. result = faux_str_sprintf("\"%s\"", escaped);
  119. faux_str_free(escaped);
  120. } else {
  121. result = escaped;
  122. }
  123. return result;
  124. }
  125. // Get value from data lyd node
  126. char *klyd_node_value(const struct lyd_node *node)
  127. {
  128. const struct lysc_node *schema = NULL;
  129. const struct lysc_type *type = NULL;
  130. const char *origin_value = NULL;
  131. if (!node)
  132. return NULL;
  133. schema = node->schema;
  134. if (!(schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)))
  135. return NULL;
  136. if (schema->nodetype & LYS_LEAF)
  137. type = ((const struct lysc_node_leaf *)schema)->type;
  138. else
  139. type = ((const struct lysc_node_leaflist *)schema)->type;
  140. if (type->basetype != LY_TYPE_IDENT) {
  141. origin_value = lyd_get_value(node);
  142. } else {
  143. // Identity
  144. const struct lyd_value *value = NULL;
  145. value = &((const struct lyd_node_term *)node)->value;
  146. origin_value = value->ident->name;
  147. }
  148. return klyd_esc_value(origin_value);
  149. }
  150. // Don't use standard lys_find_child() because it checks given module to be
  151. // equal to found node's module. So augmented nodes will not be found.
  152. const struct lysc_node *klysc_find_child(const struct lysc_node *node,
  153. const char *name)
  154. {
  155. const struct lysc_node *iter = NULL;
  156. if (!node)
  157. return NULL;
  158. LY_LIST_FOR(node, iter) {
  159. if (!(iter->nodetype & SRP_NODETYPE_CONF))
  160. continue;
  161. if (!(iter->flags & LYS_CONFIG_W))
  162. continue;
  163. // Special case. LYS_CHOICE and LYS_CASE must search for
  164. // specified name inside themselfs.
  165. if (iter->nodetype & (LYS_CHOICE | LYS_CASE)) {
  166. const struct lysc_node *node_in = NULL;
  167. node_in = klysc_find_child(lysc_node_child(iter), name);
  168. if (node_in)
  169. return node_in;
  170. continue;
  171. }
  172. if (!faux_str_cmp(iter->name, name))
  173. return iter;
  174. }
  175. return NULL;
  176. }
  177. static struct lysc_ident *klysc_find_ident(struct lysc_ident *ident, const char *name)
  178. {
  179. LY_ARRAY_COUNT_TYPE u = 0;
  180. if (!ident)
  181. return NULL;
  182. if (!ident->derived) {
  183. if (!faux_str_cmp(name, ident->name))
  184. return ident;
  185. return NULL;
  186. }
  187. LY_ARRAY_FOR(ident->derived, u) {
  188. struct lysc_ident *identity = klysc_find_ident(ident->derived[u], name);
  189. if (identity)
  190. return identity;
  191. }
  192. return NULL;
  193. }
  194. const char *klysc_identityref_prefix(struct lysc_type_identityref *type,
  195. const char *name)
  196. {
  197. LY_ARRAY_COUNT_TYPE u = 0;
  198. assert(type);
  199. LY_ARRAY_FOR(type->bases, u) {
  200. struct lysc_ident *identity = klysc_find_ident(type->bases[u], name);
  201. if (identity)
  202. return identity->module->name;
  203. }
  204. return NULL;
  205. }
  206. // Get module name by internal prefix. Sysrepo requests use module names but not
  207. // prefixes.
  208. static const char *module_by_prefix(const struct lysp_module *parsed, const char *prefix)
  209. {
  210. LY_ARRAY_COUNT_TYPE u = 0;
  211. if (!parsed)
  212. return NULL;
  213. if (!prefix)
  214. return NULL;
  215. // Try prefix of module itself
  216. if (faux_str_cmp(prefix, parsed->mod->prefix) == 0)
  217. return parsed->mod->name;
  218. // Try imported modules
  219. LY_ARRAY_FOR(parsed->imports, u) {
  220. const struct lysp_import *import = &parsed->imports[u];
  221. if (faux_str_cmp(prefix, import->prefix) == 0)
  222. return import->name;
  223. }
  224. return NULL;
  225. }
  226. static char *remap_xpath_prefixes(const char *orig_xpath, const struct lysp_module *parsed)
  227. {
  228. char *remaped = NULL;
  229. const char *pos = orig_xpath;
  230. const char *start = orig_xpath;
  231. char *cached_prefix = NULL;
  232. char *cached_module = NULL;
  233. if (!orig_xpath)
  234. return NULL;
  235. while (*pos != '\0') {
  236. if (*pos == '/') {
  237. faux_str_catn(&remaped, start, pos - start + 1);
  238. start = pos + 1;
  239. } else if (*pos == ':') {
  240. if (pos != start) {
  241. char *prefix = faux_str_dupn(start, pos - start);
  242. if (cached_prefix && (faux_str_cmp(prefix, cached_prefix) == 0)) {
  243. faux_str_cat(&remaped, cached_module);
  244. faux_str_free(prefix);
  245. } else {
  246. const char *module = module_by_prefix(parsed, prefix);
  247. if (module) {
  248. faux_str_cat(&remaped, module);
  249. faux_str_free(cached_prefix);
  250. faux_str_free(cached_module);
  251. cached_prefix = prefix;
  252. cached_module = faux_str_dup(module);
  253. } else {
  254. faux_str_cat(&remaped, prefix);
  255. faux_str_free(prefix);
  256. }
  257. }
  258. }
  259. faux_str_cat(&remaped, ":");
  260. start = pos + 1;
  261. }
  262. pos++;
  263. }
  264. if (start != pos)
  265. faux_str_catn(&remaped, start, pos - start);
  266. faux_str_free(cached_prefix);
  267. faux_str_free(cached_module);
  268. return remaped;
  269. }
  270. static const char *cut_front_ups(const char *orig_xpath, size_t *up_num)
  271. {
  272. const char *xpath = orig_xpath;
  273. const char *needle = "../";
  274. size_t needle_len = strlen(needle);
  275. size_t num = 0;
  276. if (!xpath)
  277. return NULL;
  278. while (faux_str_cmpn(xpath, needle, needle_len) == 0) {
  279. num++;
  280. xpath += needle_len;
  281. }
  282. if (up_num)
  283. *up_num = num;
  284. return xpath;
  285. }
  286. static char *cut_trailing_components(const char *orig_xpath, size_t up_num)
  287. {
  288. const char *xpath = NULL;
  289. char *res = NULL;
  290. size_t num = 0;
  291. if (!orig_xpath)
  292. return NULL;
  293. xpath = orig_xpath + strlen(orig_xpath);
  294. while (xpath >= orig_xpath) {
  295. if (*xpath == '/')
  296. num++;
  297. if (num == up_num) {
  298. res = faux_str_dupn(orig_xpath, xpath - orig_xpath + 1);
  299. break;
  300. }
  301. xpath--;
  302. }
  303. return res;
  304. }
  305. char *klysc_leafref_xpath(const struct lysc_node *node,
  306. const struct lysc_type *type, const char *node_path)
  307. {
  308. char *compl_xpath = NULL;
  309. const struct lysc_type_leafref *leafref = NULL;
  310. const char *orig_xpath = NULL;
  311. char *remaped_xpath = NULL;
  312. const char *tmp = NULL;
  313. size_t up_num = 0;
  314. if (!type)
  315. return NULL;
  316. if (!node)
  317. return NULL;
  318. if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST)))
  319. return NULL;
  320. if (type->basetype != LY_TYPE_LEAFREF)
  321. return NULL;
  322. leafref = (const struct lysc_type_leafref *)type;
  323. orig_xpath = lyxp_get_expr(leafref->path);
  324. if (!orig_xpath)
  325. return NULL;
  326. remaped_xpath = remap_xpath_prefixes(orig_xpath, node->module->parsed);
  327. if (remaped_xpath[0] == '/') // Absolute path
  328. return remaped_xpath;
  329. // Relative path
  330. if (!node_path) {
  331. faux_str_free(remaped_xpath);
  332. return NULL;
  333. }
  334. tmp = cut_front_ups(remaped_xpath, &up_num);
  335. compl_xpath = cut_trailing_components(node_path, up_num);
  336. if (!compl_xpath) {
  337. faux_str_free(remaped_xpath);
  338. return NULL;
  339. }
  340. faux_str_cat(&compl_xpath, tmp);
  341. faux_str_free(remaped_xpath);
  342. return compl_xpath;
  343. }
  344. size_t klyd_visible_child_num(const struct lyd_node *node)
  345. {
  346. const struct lyd_node *nodes_list = NULL;
  347. const struct lyd_node *iter = NULL;
  348. size_t num = 0;
  349. if (!node)
  350. return 0;
  351. nodes_list = lyd_child(node);
  352. if(!nodes_list)
  353. return 0;
  354. LY_LIST_FOR(nodes_list, iter) {
  355. if (iter->flags & LYD_DEFAULT)
  356. continue;
  357. if (!(iter->schema->nodetype & SRP_NODETYPE_CONF))
  358. continue;
  359. if (!(iter->schema->flags & LYS_CONFIG_W)) // config is true
  360. continue;
  361. if (iter->schema->flags & LYS_KEY)
  362. continue;
  363. num++;
  364. }
  365. return num;
  366. }
  367. bool_t kly_str2ds(const char *str, size_t len, sr_datastore_t *ds)
  368. {
  369. if (!str)
  370. return BOOL_FALSE;
  371. if (len == 0)
  372. return BOOL_FALSE;
  373. if (!ds)
  374. return BOOL_FALSE;
  375. if (faux_str_cmpn(str, "candidate", len) == 0)
  376. *ds = SR_DS_CANDIDATE;
  377. else if (faux_str_cmpn(str, "running", len) == 0)
  378. *ds = SR_DS_RUNNING;
  379. else if (faux_str_cmpn(str, "operational", len) == 0)
  380. *ds = SR_DS_OPERATIONAL;
  381. else if (faux_str_cmpn(str, "startup", len) == 0)
  382. *ds = SR_DS_STARTUP;
  383. #ifdef SR_DS_FACTORY_DEFAULT
  384. else if (faux_str_cmpn(str, "factory-default", len) == 0)
  385. *ds = SR_DS_FACTORY_DEFAULT;
  386. #endif
  387. else // No DS prefix found
  388. return BOOL_FALSE;
  389. return BOOL_TRUE;
  390. }
  391. bool_t kly_parse_ext_xpath(const char *xpath, const char **raw_xpath,
  392. sr_datastore_t *ds)
  393. {
  394. char *space = NULL;
  395. if (!xpath)
  396. return BOOL_FALSE;
  397. if (!raw_xpath)
  398. return BOOL_FALSE;
  399. if (!ds)
  400. return BOOL_FALSE;
  401. *ds = SRP_REPO_EDIT; // Default
  402. *raw_xpath = xpath;
  403. space = strchr(xpath, ' ');
  404. if (space) {
  405. size_t len = space - xpath;
  406. if (kly_str2ds(xpath, len, ds))
  407. *raw_xpath = space + 1;
  408. }
  409. return BOOL_TRUE;
  410. }