show.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  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 (opts->keys_w_stmt &&
  162. (!first_key ||
  163. (first_key && opts->first_key_w_stmt)))
  164. printf(" %s", iter->schema->name);
  165. value = get_value(iter);
  166. printf(" %s", value);
  167. faux_str_free(value);
  168. first_key = BOOL_FALSE;
  169. }
  170. printf("%s%s\n",
  171. opts->show_brackets ? begin_bracket : "",
  172. diff_suffix(op, opts));
  173. show_subtree(lyd_child(node), level + 1, op, opts);
  174. if (opts->show_brackets) {
  175. printf("%s%*s%c%s\n",
  176. diff_prefix(op, opts),
  177. (int)(level * opts->indent), "",
  178. opts->end_bracket,
  179. diff_suffix(op, opts));
  180. }
  181. }
  182. static void show_leaf(const struct lyd_node *node, size_t level,
  183. enum diff_op op, pline_opts_t *opts)
  184. {
  185. struct lysc_node_leaf *leaf = (struct lysc_node_leaf *)node;
  186. if (!node)
  187. return;
  188. if (node->schema->flags & LYS_KEY)
  189. return;
  190. printf("%s%*s%s",
  191. diff_prefix(op, opts),
  192. (int)(level * opts->indent), "",
  193. node->schema->name);
  194. leaf = (struct lysc_node_leaf *)node->schema;
  195. if (leaf->type->basetype != LY_TYPE_EMPTY) {
  196. if (opts->hide_passwords &&
  197. klysc_node_ext_is_password(node->schema)) {
  198. printf(" <hidden>");
  199. } else {
  200. char *value = get_value(node);
  201. printf(" %s", value);
  202. faux_str_free(value);
  203. }
  204. }
  205. printf("%s%s\n",
  206. opts->show_semicolons ? ";" : "",
  207. diff_suffix(op, opts));
  208. }
  209. static void show_leaflist(const struct lyd_node *node, size_t level,
  210. enum diff_op op, pline_opts_t *opts)
  211. {
  212. char *value = NULL;
  213. if (!node)
  214. return;
  215. value = get_value(node);
  216. printf("%s%*s%s %s%s%s\n",
  217. diff_prefix(op, opts),
  218. (int)(level * opts->indent), "",
  219. node->schema->name,
  220. value,
  221. opts->show_semicolons ? ";" : "",
  222. diff_suffix(op, opts));
  223. faux_str_free(value);
  224. }
  225. static void show_node(const struct lyd_node *node, size_t level,
  226. enum diff_op op, pline_opts_t *opts)
  227. {
  228. const struct lysc_node *schema = NULL;
  229. struct lyd_meta *meta = NULL;
  230. enum diff_op cur_op = op;
  231. if (!node)
  232. return;
  233. if (node->flags & LYD_DEFAULT)
  234. return;
  235. schema = node->schema;
  236. if (!schema)
  237. return;
  238. if (!(schema->nodetype & SRP_NODETYPE_CONF))
  239. return;
  240. if (!(schema->flags & LYS_CONFIG_W))
  241. return;
  242. meta = lyd_find_meta(node->meta, NULL, "yang:operation");
  243. if (meta)
  244. cur_op = str2diff_op(lyd_get_meta_value(meta));
  245. // Container
  246. if (schema->nodetype & LYS_CONTAINER) {
  247. show_container(node, level, cur_op, opts);
  248. // List
  249. } else if (schema->nodetype & LYS_LIST) {
  250. show_list(node, level, cur_op, opts);
  251. // Leaf
  252. } else if (schema->nodetype & LYS_LEAF) {
  253. show_leaf(node, level, cur_op, opts);
  254. // Leaf-list
  255. } else if (schema->nodetype & LYS_LEAFLIST) {
  256. show_leaflist(node, level, cur_op, opts);
  257. } else {
  258. return;
  259. }
  260. }
  261. static void show_sorted_list(faux_list_t *list, size_t level,
  262. enum diff_op op, pline_opts_t *opts)
  263. {
  264. faux_list_node_t *iter = NULL;
  265. const struct lyd_node *lyd = NULL;
  266. if (!list)
  267. return;
  268. iter = faux_list_head(list);
  269. while ((lyd = (const struct lyd_node *)faux_list_each(&iter)))
  270. show_node(lyd, level, op, opts);
  271. }
  272. static char *list_keys_str(const struct lyd_node *node)
  273. {
  274. char *keys = NULL;
  275. const struct lyd_node *iter = NULL;
  276. if (!node)
  277. return NULL;
  278. if (node->schema->nodetype != LYS_LIST)
  279. return NULL;
  280. LY_LIST_FOR(lyd_child(node), iter) {
  281. if (!(iter->schema->nodetype & LYS_LEAF))
  282. continue;
  283. if (!(iter->schema->flags & LYS_KEY))
  284. continue;
  285. if (keys)
  286. faux_str_cat(&keys, " ");
  287. faux_str_cat(&keys, lyd_get_value(iter));
  288. }
  289. return keys;
  290. }
  291. static int list_compare(const void *first, const void *second)
  292. {
  293. int rc = 0;
  294. const struct lyd_node *f = (const struct lyd_node *)first;
  295. const struct lyd_node *s = (const struct lyd_node *)second;
  296. char *f_keys = list_keys_str(f);
  297. char *s_keys = list_keys_str(s);
  298. rc = faux_str_numcmp(f_keys, s_keys);
  299. faux_str_free(f_keys);
  300. faux_str_free(s_keys);
  301. return rc;
  302. }
  303. static int leaflist_compare(const void *first, const void *second)
  304. {
  305. const struct lyd_node *f = (const struct lyd_node *)first;
  306. const struct lyd_node *s = (const struct lyd_node *)second;
  307. return faux_str_numcmp(lyd_get_value(f), lyd_get_value(s));
  308. }
  309. void show_subtree(const struct lyd_node *nodes_list, size_t level,
  310. enum diff_op op, pline_opts_t *opts)
  311. {
  312. const struct lyd_node *iter = NULL;
  313. faux_list_t *list = NULL;
  314. const struct lysc_node *saved_lysc = NULL;
  315. if(!nodes_list)
  316. return;
  317. LY_LIST_FOR(nodes_list, iter) {
  318. if (saved_lysc) {
  319. if (saved_lysc == iter->schema) {
  320. faux_list_add(list, (void *)iter);
  321. continue;
  322. }
  323. show_sorted_list(list, level, op, opts);
  324. faux_list_free(list);
  325. list = NULL;
  326. saved_lysc = NULL;
  327. }
  328. if (((LYS_LIST == iter->schema->nodetype) ||
  329. (LYS_LEAFLIST == iter->schema->nodetype)) &&
  330. (iter->schema->flags & LYS_ORDBY_SYSTEM)) {
  331. saved_lysc = iter->schema;
  332. if (LYS_LIST == iter->schema->nodetype) {
  333. list = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  334. list_compare, NULL, NULL);
  335. } else { // LEAFLIST
  336. list = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  337. leaflist_compare, NULL, NULL);
  338. }
  339. faux_list_add(list, (void *)iter);
  340. continue;
  341. }
  342. show_node(iter, level, op, opts);
  343. }
  344. if (list) {
  345. show_sorted_list(list, level, op, opts);
  346. faux_list_free(list);
  347. }
  348. }
  349. bool_t show_xpath(sr_session_ctx_t *sess, const char *xpath, pline_opts_t *opts)
  350. {
  351. sr_data_t *data = NULL;
  352. struct lyd_node *nodes_list = NULL;
  353. assert(sess);
  354. if (xpath) {
  355. if (sr_get_subtree(sess, xpath, 0, &data) != SR_ERR_OK)
  356. return BOOL_FALSE;
  357. nodes_list = lyd_child(data->tree);
  358. } else {
  359. if (sr_get_data(sess, "/*", 0, 0, 0, &data) != SR_ERR_OK)
  360. return BOOL_FALSE;
  361. nodes_list = data->tree;
  362. }
  363. show_subtree(nodes_list, 0, DIFF_OP_NONE, opts);
  364. sr_release_data(data);
  365. return BOOL_TRUE;
  366. }
  367. static enum diff_op str2diff_op(const char *str)
  368. {
  369. if (!strcmp(str, "create"))
  370. return DIFF_OP_CREATE;
  371. else if (!strcmp(str, "delete"))
  372. return DIFF_OP_DELETE;
  373. else if (!strcmp(str, "replace"))
  374. return DIFF_OP_REPLACE;
  375. return DIFF_OP_NONE;
  376. }