show.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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. static void show_container(const struct lyd_node *node, size_t level,
  17. enum diff_op op, pline_opts_t *opts, bool_t parent_is_oneliner);
  18. static void show_list(const struct lyd_node *node, size_t level,
  19. enum diff_op op, pline_opts_t *opts, bool_t parent_is_oneliner);
  20. static void show_leaf(const struct lyd_node *node, size_t level,
  21. enum diff_op op, pline_opts_t *opts, bool_t parent_is_oneliner);
  22. static void show_leaflist(const struct lyd_node *node, size_t level,
  23. enum diff_op op, pline_opts_t *opts, bool_t parent_is_oneliner);
  24. static void show_node(const struct lyd_node *node, size_t level,
  25. enum diff_op op, pline_opts_t *opts, bool_t parent_is_oneliner);
  26. static enum diff_op str2diff_op(const char *str);
  27. static const char *diff_prefix(enum diff_op op, pline_opts_t *opts)
  28. {
  29. bool_t c = opts->colorize;
  30. if (DIFF_OP_CREATE == op)
  31. return c ? "\x1b[32m+" : "+";
  32. else if (DIFF_OP_DELETE == op)
  33. return c ? "\x1b[31m-" : "-";
  34. else if (DIFF_OP_REPLACE == op)
  35. return c ? "\x1b[33m=" : "=";
  36. return "";
  37. }
  38. static const char *diff_suffix(enum diff_op op, pline_opts_t *opts)
  39. {
  40. if (opts->colorize && (DIFF_OP_NONE != op))
  41. return "\x1b[0m";
  42. return "";
  43. }
  44. static void show_container(const struct lyd_node *node, size_t level,
  45. enum diff_op op, pline_opts_t *opts, bool_t parent_is_oneliner)
  46. {
  47. char begin_bracket[3] = {' ', opts->begin_bracket, '\0'};
  48. size_t child_num = 0;
  49. bool_t show_brackets = BOOL_FALSE;
  50. bool_t node_is_oneliner = BOOL_FALSE;
  51. if (!node)
  52. return;
  53. child_num = klyd_visible_child_num(node);
  54. node_is_oneliner = opts->oneliners && (child_num == 1);
  55. show_brackets = opts->show_brackets && !node_is_oneliner && (child_num != 0);
  56. printf("%s%*s%s%s%s%s",
  57. diff_prefix(op, opts),
  58. parent_is_oneliner ? 1 : (int)(level * opts->indent), "",
  59. node->schema->name,
  60. show_brackets ? begin_bracket : "",
  61. diff_suffix(op, opts),
  62. node_is_oneliner ? "" : "\n");
  63. if (child_num != 0)
  64. show_subtree(lyd_child(node),
  65. node_is_oneliner ? level : (level + 1),
  66. op, opts, node_is_oneliner);
  67. if (show_brackets) {
  68. printf("%s%*s%c%s\n",
  69. diff_prefix(op, opts),
  70. (int)(level * opts->indent), "",
  71. opts->end_bracket,
  72. diff_suffix(op, opts));
  73. }
  74. }
  75. static void show_list(const struct lyd_node *node, size_t level,
  76. enum diff_op op, pline_opts_t *opts, bool_t parent_is_oneliner)
  77. {
  78. char begin_bracket[3] = {' ', opts->begin_bracket, '\0'};
  79. const struct lyd_node *iter = NULL;
  80. bool_t first_key = BOOL_TRUE;
  81. const char *default_value = NULL;
  82. size_t child_num = 0;
  83. bool_t show_brackets = BOOL_FALSE;
  84. bool_t node_is_oneliner = BOOL_FALSE;
  85. if (!node)
  86. return;
  87. child_num = klyd_visible_child_num(node);
  88. node_is_oneliner = opts->oneliners && (child_num == 1);
  89. show_brackets = opts->show_brackets && !node_is_oneliner && (child_num != 0);
  90. printf("%s%*s%s",
  91. diff_prefix(op, opts),
  92. parent_is_oneliner ? 1 : (int)(level * opts->indent), "",
  93. node->schema->name);
  94. LY_LIST_FOR(lyd_child(node), iter) {
  95. char *value = NULL;
  96. if (!(iter->schema->nodetype & LYS_LEAF))
  97. continue;
  98. if (!(iter->schema->flags & LYS_KEY))
  99. continue;
  100. default_value = klysc_node_ext_default(iter->schema);
  101. value = klyd_node_value(iter);
  102. // Don't show "default" keys with default values
  103. if (opts->default_keys &&
  104. !opts->show_default_keys && default_value &&
  105. (faux_str_cmp(default_value, value) == 0)) {
  106. faux_str_free(value);
  107. continue;
  108. }
  109. if (opts->keys_w_stmt && (!first_key || (first_key &&
  110. (opts->first_key_w_stmt ||
  111. (opts->default_keys && default_value)))))
  112. printf(" %s", iter->schema->name);
  113. printf(" %s", value);
  114. faux_str_free(value);
  115. first_key = BOOL_FALSE;
  116. }
  117. printf("%s%s%s",
  118. show_brackets ? begin_bracket : "",
  119. diff_suffix(op, opts),
  120. node_is_oneliner ? "" : "\n");
  121. if (child_num != 0)
  122. show_subtree(lyd_child(node),
  123. node_is_oneliner ? level : (level + 1),
  124. op, opts, node_is_oneliner);
  125. if (show_brackets) {
  126. printf("%s%*s%c%s\n",
  127. diff_prefix(op, opts),
  128. (int)(level * opts->indent), "",
  129. opts->end_bracket,
  130. diff_suffix(op, opts));
  131. }
  132. }
  133. static void show_leaf(const struct lyd_node *node, size_t level,
  134. enum diff_op op, pline_opts_t *opts, bool_t parent_is_oneliner)
  135. {
  136. struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)node;
  137. if (!node)
  138. return;
  139. if (node->schema->flags & LYS_KEY)
  140. return;
  141. printf("%s%*s%s",
  142. diff_prefix(op, opts),
  143. parent_is_oneliner ? 1 : (int)(level * opts->indent), "",
  144. node->schema->name);
  145. leaf = (struct lysc_node_leaf *)node->schema;
  146. if (leaf->type->basetype != LY_TYPE_EMPTY) {
  147. if (opts->hide_passwords &&
  148. klysc_node_ext_is_password(node->schema)) {
  149. printf(" <hidden>");
  150. } else {
  151. char *value = klyd_node_value(node);
  152. printf(" %s", value);
  153. faux_str_free(value);
  154. }
  155. }
  156. printf("%s%s\n",
  157. opts->show_semicolons ? ";" : "",
  158. diff_suffix(op, opts));
  159. }
  160. static void show_leaflist(const struct lyd_node *node, size_t level,
  161. enum diff_op op, pline_opts_t *opts, bool_t parent_is_oneliner)
  162. {
  163. char *value = NULL;
  164. if (!node)
  165. return;
  166. value = klyd_node_value(node);
  167. printf("%s%*s%s %s%s%s\n",
  168. diff_prefix(op, opts),
  169. parent_is_oneliner ? 1 : (int)(level * opts->indent), "",
  170. node->schema->name,
  171. value,
  172. opts->show_semicolons ? ";" : "",
  173. diff_suffix(op, opts));
  174. faux_str_free(value);
  175. }
  176. static void show_node(const struct lyd_node *node, size_t level,
  177. enum diff_op op, pline_opts_t *opts, bool_t parent_is_oneliner)
  178. {
  179. const struct lysc_node *schema = NULL;
  180. struct lyd_meta *meta = NULL;
  181. enum diff_op cur_op = op;
  182. if (!node)
  183. return;
  184. if (node->flags & LYD_DEFAULT)
  185. return;
  186. schema = node->schema;
  187. if (!schema)
  188. return;
  189. if (!(schema->nodetype & SRP_NODETYPE_CONF))
  190. return;
  191. if (!(schema->flags & LYS_CONFIG_W))
  192. return;
  193. meta = lyd_find_meta(node->meta, NULL, "yang:operation");
  194. if (meta)
  195. cur_op = str2diff_op(lyd_get_meta_value(meta));
  196. // Container
  197. if (schema->nodetype & LYS_CONTAINER) {
  198. show_container(node, level, cur_op, opts, parent_is_oneliner);
  199. // List
  200. } else if (schema->nodetype & LYS_LIST) {
  201. show_list(node, level, cur_op, opts, parent_is_oneliner);
  202. // Leaf
  203. } else if (schema->nodetype & LYS_LEAF) {
  204. show_leaf(node, level, cur_op, opts, parent_is_oneliner);
  205. // Leaf-list
  206. } else if (schema->nodetype & LYS_LEAFLIST) {
  207. show_leaflist(node, level, cur_op, opts, parent_is_oneliner);
  208. } else {
  209. return;
  210. }
  211. }
  212. static void show_sorted_list(faux_list_t *list, size_t level,
  213. enum diff_op op, pline_opts_t *opts, bool_t parent_is_oneliner)
  214. {
  215. faux_list_node_t *iter = NULL;
  216. const struct lyd_node *lyd = NULL;
  217. if (!list)
  218. return;
  219. iter = faux_list_head(list);
  220. while ((lyd = (const struct lyd_node *)faux_list_each(&iter)))
  221. show_node(lyd, level, op, opts, parent_is_oneliner);
  222. }
  223. static char *list_keys_str(const struct lyd_node *node)
  224. {
  225. char *keys = NULL;
  226. const struct lyd_node *iter = NULL;
  227. if (!node)
  228. return NULL;
  229. if (node->schema->nodetype != LYS_LIST)
  230. return NULL;
  231. LY_LIST_FOR(lyd_child(node), iter) {
  232. if (!(iter->schema->nodetype & LYS_LEAF))
  233. continue;
  234. if (!(iter->schema->flags & LYS_KEY))
  235. continue;
  236. if (keys)
  237. faux_str_cat(&keys, " ");
  238. faux_str_cat(&keys, lyd_get_value(iter));
  239. }
  240. return keys;
  241. }
  242. static int list_compare(const void *first, const void *second)
  243. {
  244. int rc = 0;
  245. const struct lyd_node *f = (const struct lyd_node *)first;
  246. const struct lyd_node *s = (const struct lyd_node *)second;
  247. char *f_keys = list_keys_str(f);
  248. char *s_keys = list_keys_str(s);
  249. rc = faux_str_numcmp(f_keys, s_keys);
  250. faux_str_free(f_keys);
  251. faux_str_free(s_keys);
  252. return rc;
  253. }
  254. static int leaflist_compare(const void *first, const void *second)
  255. {
  256. const struct lyd_node *f = (const struct lyd_node *)first;
  257. const struct lyd_node *s = (const struct lyd_node *)second;
  258. return faux_str_numcmp(lyd_get_value(f), lyd_get_value(s));
  259. }
  260. void show_subtree(const struct lyd_node *nodes_list, size_t level,
  261. enum diff_op op, pline_opts_t *opts, bool_t parent_is_oneliner)
  262. {
  263. const struct lyd_node *iter = NULL;
  264. faux_list_t *list = NULL;
  265. const struct lysc_node *saved_lysc = NULL;
  266. if(!nodes_list)
  267. return;
  268. LY_LIST_FOR(nodes_list, iter) {
  269. if (saved_lysc) {
  270. if (saved_lysc == iter->schema) {
  271. faux_list_add(list, (void *)iter);
  272. continue;
  273. }
  274. show_sorted_list(list, level, op, opts, parent_is_oneliner);
  275. faux_list_free(list);
  276. list = NULL;
  277. saved_lysc = NULL;
  278. }
  279. if (((LYS_LIST == iter->schema->nodetype) ||
  280. (LYS_LEAFLIST == iter->schema->nodetype)) &&
  281. (iter->schema->flags & LYS_ORDBY_SYSTEM)) {
  282. saved_lysc = iter->schema;
  283. if (LYS_LIST == iter->schema->nodetype) {
  284. list = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  285. list_compare, NULL, NULL);
  286. } else { // LEAFLIST
  287. list = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  288. leaflist_compare, NULL, NULL);
  289. }
  290. faux_list_add(list, (void *)iter);
  291. continue;
  292. }
  293. show_node(iter, level, op, opts, parent_is_oneliner);
  294. }
  295. if (list) {
  296. show_sorted_list(list, level, op, opts, parent_is_oneliner);
  297. faux_list_free(list);
  298. }
  299. }
  300. bool_t show_xpath(sr_session_ctx_t *sess, const char *xpath,
  301. size_t xpath_depth, pline_opts_t *opts)
  302. {
  303. sr_data_t *data = NULL;
  304. struct lyd_node *nodes_list = NULL;
  305. const char *expath = xpath; // Effective XPath
  306. size_t edepth = xpath_depth;
  307. assert(sess);
  308. if (!expath) {
  309. expath = "/*";
  310. edepth = 0;
  311. }
  312. if (sr_get_data(sess, expath, 0, 0, 0, &data) != SR_ERR_OK)
  313. return BOOL_FALSE;
  314. if (!data) // Not found
  315. return BOOL_TRUE;
  316. nodes_list = data->tree;
  317. while (nodes_list && (edepth > 0)) {
  318. nodes_list = lyd_child_no_keys(nodes_list);
  319. edepth--;
  320. }
  321. if (nodes_list)
  322. show_subtree(nodes_list, 0, DIFF_OP_NONE, opts, BOOL_FALSE);
  323. sr_release_data(data);
  324. return BOOL_TRUE;
  325. }
  326. static enum diff_op str2diff_op(const char *str)
  327. {
  328. if (!strcmp(str, "create"))
  329. return DIFF_OP_CREATE;
  330. else if (!strcmp(str, "delete"))
  331. return DIFF_OP_DELETE;
  332. else if (!strcmp(str, "replace"))
  333. return DIFF_OP_REPLACE;
  334. return DIFF_OP_NONE;
  335. }