show.c 10 KB

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