show.c 9.8 KB

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