show.c 10 KB

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