show.c 10 KB

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