syms.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <assert.h>
  5. #include <syslog.h>
  6. #include <faux/faux.h>
  7. #include <faux/str.h>
  8. #include <faux/argv.h>
  9. #include <faux/list.h>
  10. #include <faux/error.h>
  11. #include <klish/khelper.h>
  12. #include <klish/kplugin.h>
  13. #include <klish/kentry.h>
  14. #include <klish/kscheme.h>
  15. #include <klish/kcontext.h>
  16. #include <klish/kpargv.h>
  17. #include <sysrepo.h>
  18. #include <sysrepo/xpath.h>
  19. #include <sysrepo/values.h>
  20. #include "klish_plugin_sysrepo.h"
  21. #define ERRORMSG "Error: "
  22. #define ARG_PATH "path"
  23. #define ARG_FROM_PATH "from_path"
  24. #define ARG_TO_PATH "to_path"
  25. // Print sysrepo session errors
  26. static void srp_print_errors(sr_session_ctx_t *session)
  27. {
  28. const sr_error_info_t *err_info = NULL;
  29. int rc = 0;
  30. unsigned int i = 0;
  31. if (!session)
  32. return;
  33. rc = sr_session_get_error(session, &err_info);
  34. if ((rc != SR_ERR_OK) || !err_info)
  35. return;
  36. // Show the first error only. Because probably next errors are
  37. // originated from internal sysrepo code but is not from subscribers.
  38. // for (i = 0; i < err_info->err_count; i++)
  39. for (i = 0; i < (err_info->err_count < 1 ? err_info->err_count : 1); i++)
  40. fprintf(stderr, ERRORMSG "%s\n", err_info->err[i].message);
  41. }
  42. // Print sysrepo session errors and then specified error
  43. static void srp_error(sr_session_ctx_t *session, const char *fmt, ...)
  44. {
  45. srp_print_errors(session);
  46. if (fmt) {
  47. va_list argptr;
  48. va_start(argptr, fmt);
  49. vfprintf(stderr, fmt, argptr);
  50. va_end(argptr);
  51. }
  52. }
  53. static faux_argv_t *param2argv(const faux_argv_t *cur_path,
  54. const kpargv_t *pargv, const char *entry_name)
  55. {
  56. faux_list_node_t *iter = NULL;
  57. faux_list_t *pargs = NULL;
  58. faux_argv_t *args = NULL;
  59. kparg_t *parg = NULL;
  60. assert(pargv);
  61. if (!pargv)
  62. return NULL;
  63. pargs = kpargv_find_multi(pargv, entry_name);
  64. if (cur_path)
  65. args = faux_argv_dup(cur_path);
  66. else
  67. args = faux_argv_new();
  68. iter = faux_list_head(pargs);
  69. while ((parg = (kparg_t *)faux_list_each(&iter))) {
  70. faux_argv_add(args, kparg_value(parg));
  71. }
  72. faux_list_free(pargs);
  73. return args;
  74. }
  75. // Candidate from pargv contains possible begin of current word (that must be
  76. // completed). kpargv's list don't contain candidate but only already parsed
  77. // words.
  78. static int srp_compl_or_help(kcontext_t *context, bool_t help,
  79. pt_e enabled_ptypes, bool_t use_cur_path)
  80. {
  81. faux_argv_t *args = NULL;
  82. pline_t *pline = NULL;
  83. sr_session_ctx_t *sess = NULL;
  84. const char *entry_name = NULL;
  85. faux_argv_t *cur_path = NULL;
  86. assert(context);
  87. sess = srp_udata_sr_sess(context);
  88. if (use_cur_path)
  89. cur_path = (faux_argv_t *)srp_udata_path(context);
  90. entry_name = kentry_name(kcontext_candidate_entry(context));
  91. args = param2argv(cur_path, kcontext_parent_pargv(context), entry_name);
  92. pline = pline_parse(sess, args, srp_udata_opts(context));
  93. faux_argv_free(args);
  94. pline_print_completions(pline, help, enabled_ptypes);
  95. pline_free(pline);
  96. return 0;
  97. }
  98. int srp_compl(kcontext_t *context)
  99. {
  100. return srp_compl_or_help(context, BOOL_FALSE, PT_COMPL_ALL, BOOL_TRUE);
  101. }
  102. int srp_help(kcontext_t *context)
  103. {
  104. return srp_compl_or_help(context, BOOL_TRUE, PT_COMPL_ALL, BOOL_TRUE);
  105. }
  106. int srp_compl_set(kcontext_t *context)
  107. {
  108. return srp_compl_or_help(context, BOOL_FALSE, PT_COMPL_SET, BOOL_TRUE);
  109. }
  110. int srp_help_set(kcontext_t *context)
  111. {
  112. return srp_compl_or_help(context, BOOL_TRUE, PT_COMPL_SET, BOOL_TRUE);
  113. }
  114. int srp_compl_del(kcontext_t *context)
  115. {
  116. return srp_compl_or_help(context, BOOL_FALSE, PT_COMPL_DEL, BOOL_TRUE);
  117. }
  118. int srp_help_del(kcontext_t *context)
  119. {
  120. return srp_compl_or_help(context, BOOL_TRUE, PT_COMPL_DEL, BOOL_TRUE);
  121. }
  122. int srp_compl_edit(kcontext_t *context)
  123. {
  124. return srp_compl_or_help(context, BOOL_FALSE, PT_COMPL_EDIT, BOOL_TRUE);
  125. }
  126. int srp_compl_edit_abs(kcontext_t *context)
  127. {
  128. return srp_compl_or_help(context, BOOL_FALSE, PT_COMPL_EDIT, BOOL_FALSE);
  129. }
  130. int srp_help_edit(kcontext_t *context)
  131. {
  132. return srp_compl_or_help(context, BOOL_TRUE, PT_COMPL_EDIT, BOOL_TRUE);
  133. }
  134. int srp_help_edit_abs(kcontext_t *context)
  135. {
  136. return srp_compl_or_help(context, BOOL_TRUE, PT_COMPL_EDIT, BOOL_FALSE);
  137. }
  138. int srp_compl_insert(kcontext_t *context)
  139. {
  140. return srp_compl_or_help(context, BOOL_FALSE, PT_COMPL_INSERT, BOOL_TRUE);
  141. }
  142. int srp_help_insert(kcontext_t *context)
  143. {
  144. return srp_compl_or_help(context, BOOL_TRUE, PT_COMPL_INSERT, BOOL_TRUE);
  145. }
  146. int srp_prompt_edit_path(kcontext_t *context)
  147. {
  148. faux_argv_t *cur_path = NULL;
  149. char *path = NULL;
  150. assert(context);
  151. cur_path = (faux_argv_t *)srp_udata_path(context);
  152. if (cur_path)
  153. path = faux_argv_line(cur_path);
  154. kcontext_printf(context, "[edit%s%s]\n",
  155. path ? " " : "", path ? path : "");
  156. faux_str_free(path);
  157. return 0;
  158. }
  159. static int srp_check_type(kcontext_t *context,
  160. pt_e not_accepted_nodes, size_t max_expr_num, bool_t use_cur_path)
  161. {
  162. int ret = -1;
  163. faux_argv_t *args = NULL;
  164. pline_t *pline = NULL;
  165. sr_session_ctx_t *sess = NULL;
  166. const char *entry_name = NULL;
  167. const char *value = NULL;
  168. pexpr_t *expr = NULL;
  169. size_t expr_num = 0;
  170. faux_argv_t *cur_path = NULL;
  171. assert(context);
  172. sess = srp_udata_sr_sess(context);
  173. if (use_cur_path)
  174. cur_path = (faux_argv_t *)srp_udata_path(context);
  175. entry_name = kentry_name(kcontext_candidate_entry(context));
  176. value = kcontext_candidate_value(context);
  177. args = param2argv(cur_path, kcontext_parent_pargv(context), entry_name);
  178. if (value)
  179. faux_argv_add(args, value);
  180. pline = pline_parse(sess, args, srp_udata_opts(context));
  181. faux_argv_free(args);
  182. if (pline->invalid)
  183. goto err;
  184. expr_num = faux_list_len(pline->exprs);
  185. if (expr_num < 1)
  186. goto err;
  187. if ((max_expr_num > 0) && // '0' means unlimited
  188. (expr_num > max_expr_num))
  189. goto err;
  190. expr = pline_current_expr(pline);
  191. if (expr->pat & not_accepted_nodes)
  192. goto err;
  193. ret = 0;
  194. err:
  195. pline_free(pline);
  196. return ret;
  197. }
  198. int srp_PLINE_SET(kcontext_t *context)
  199. {
  200. return srp_check_type(context, PT_NOT_SET, 0, BOOL_TRUE);
  201. }
  202. int srp_PLINE_DEL(kcontext_t *context)
  203. {
  204. return srp_check_type(context, PT_NOT_DEL, 1, BOOL_TRUE);
  205. }
  206. int srp_PLINE_EDIT(kcontext_t *context)
  207. {
  208. return srp_check_type(context, PT_NOT_EDIT, 1, BOOL_TRUE);
  209. }
  210. int srp_PLINE_EDIT_ABS(kcontext_t *context)
  211. {
  212. return srp_check_type(context, PT_NOT_EDIT, 1, BOOL_FALSE);
  213. }
  214. int srp_PLINE_INSERT_FROM(kcontext_t *context)
  215. {
  216. return srp_check_type(context, PT_NOT_INSERT, 1, BOOL_TRUE);
  217. }
  218. static faux_argv_t *assemble_insert_to(sr_session_ctx_t *sess, const kpargv_t *pargv,
  219. faux_argv_t *cur_path, const char *candidate_value, pline_opts_t *opts)
  220. {
  221. faux_argv_t *args = NULL;
  222. faux_argv_t *insert_to = NULL;
  223. pline_t *pline = NULL;
  224. pexpr_t *expr = NULL;
  225. size_t i = 0;
  226. assert(sess);
  227. args = param2argv(cur_path, pargv, ARG_FROM_PATH);
  228. pline = pline_parse(sess, args, opts);
  229. expr = pline_current_expr(pline);
  230. for (i = 0; i < (expr->args_num - expr->list_pos); i++) {
  231. faux_argv_node_t *iter = faux_argv_iterr(args);
  232. faux_argv_del(args, iter);
  233. }
  234. insert_to = param2argv(args, pargv, ARG_TO_PATH);
  235. faux_argv_free(args);
  236. if (candidate_value)
  237. faux_argv_add(insert_to, candidate_value);
  238. pline_free(pline);
  239. return insert_to;
  240. }
  241. int srp_PLINE_INSERT_TO(kcontext_t *context)
  242. {
  243. int ret = -1;
  244. faux_argv_t *args = NULL;
  245. pline_t *pline = NULL;
  246. sr_session_ctx_t *sess = NULL;
  247. const char *value = NULL;
  248. pexpr_t *expr = NULL;
  249. size_t expr_num = 0;
  250. faux_argv_t *cur_path = NULL;
  251. assert(context);
  252. sess = srp_udata_sr_sess(context);
  253. cur_path = (faux_argv_t *)srp_udata_path(context);
  254. value = kcontext_candidate_value(context);
  255. args = assemble_insert_to(sess, kcontext_parent_pargv(context),
  256. cur_path, value, srp_udata_opts(context));
  257. pline = pline_parse(sess, args, srp_udata_opts(context));
  258. faux_argv_free(args);
  259. if (pline->invalid)
  260. goto err;
  261. expr_num = faux_list_len(pline->exprs);
  262. if (expr_num != 1)
  263. goto err;
  264. expr = pline_current_expr(pline);
  265. if (expr->pat & PT_NOT_INSERT)
  266. goto err;
  267. ret = 0;
  268. err:
  269. pline_free(pline);
  270. return ret;
  271. }
  272. static int srp_compl_or_help_insert_to(kcontext_t *context, bool_t help)
  273. {
  274. faux_argv_t *args = NULL;
  275. pline_t *pline = NULL;
  276. sr_session_ctx_t *sess = NULL;
  277. faux_argv_t *cur_path = NULL;
  278. assert(context);
  279. sess = srp_udata_sr_sess(context);
  280. cur_path = (faux_argv_t *)srp_udata_path(context);
  281. args = assemble_insert_to(sess, kcontext_parent_pargv(context),
  282. cur_path, NULL, srp_udata_opts(context));
  283. pline = pline_parse(sess, args, srp_udata_opts(context));
  284. faux_argv_free(args);
  285. pline_print_completions(pline, help, PT_COMPL_INSERT);
  286. pline_free(pline);
  287. return 0;
  288. }
  289. int srp_compl_insert_to(kcontext_t *context)
  290. {
  291. return srp_compl_or_help_insert_to(context, BOOL_FALSE);
  292. }
  293. int srp_help_insert_to(kcontext_t *context)
  294. {
  295. return srp_compl_or_help_insert_to(context, BOOL_TRUE);
  296. }
  297. int srp_set(kcontext_t *context)
  298. {
  299. int ret = 0;
  300. faux_argv_t *args = NULL;
  301. pline_t *pline = NULL;
  302. sr_session_ctx_t *sess = NULL;
  303. faux_list_node_t *iter = NULL;
  304. pexpr_t *expr = NULL;
  305. size_t err_num = 0;
  306. faux_argv_t *cur_path = NULL;
  307. assert(context);
  308. sess = srp_udata_sr_sess(context);
  309. cur_path = (faux_argv_t *)srp_udata_path(context);
  310. args = param2argv(cur_path, kcontext_pargv(context), ARG_PATH);
  311. pline = pline_parse(sess, args, srp_udata_opts(context));
  312. faux_argv_free(args);
  313. if (pline->invalid) {
  314. fprintf(stderr, ERRORMSG "Invalid set request\n");
  315. ret = -1;
  316. goto cleanup;
  317. }
  318. iter = faux_list_head(pline->exprs);
  319. while ((expr = (pexpr_t *)faux_list_each(&iter))) {
  320. if (!(expr->pat & PT_SET)) {
  321. err_num++;
  322. fprintf(stderr, ERRORMSG "Illegal expression for set operation\n");
  323. break;
  324. }
  325. if (sr_set_item_str(sess, expr->xpath, expr->value, NULL, 0) !=
  326. SR_ERR_OK) {
  327. err_num++;
  328. srp_error(sess, ERRORMSG "Can't set data\n");
  329. break;
  330. }
  331. }
  332. if (err_num > 0)
  333. ret = -1;
  334. if (!sr_has_changes(sess))
  335. goto cleanup;
  336. if (err_num > 0) {
  337. sr_discard_changes(sess);
  338. goto cleanup;
  339. }
  340. if (sr_apply_changes(sess, 0) != SR_ERR_OK) {
  341. sr_discard_changes(sess);
  342. srp_error(sess, ERRORMSG "Can't apply changes\n");
  343. goto cleanup;
  344. }
  345. cleanup:
  346. pline_free(pline);
  347. return ret;
  348. }
  349. int srp_del(kcontext_t *context)
  350. {
  351. int ret = -1;
  352. faux_argv_t *args = NULL;
  353. pline_t *pline = NULL;
  354. sr_session_ctx_t *sess = NULL;
  355. pexpr_t *expr = NULL;
  356. faux_argv_t *cur_path = NULL;
  357. assert(context);
  358. sess = srp_udata_sr_sess(context);
  359. cur_path = (faux_argv_t *)srp_udata_path(context);
  360. args = param2argv(cur_path, kcontext_pargv(context), ARG_PATH);
  361. pline = pline_parse(sess, args, srp_udata_opts(context));
  362. faux_argv_free(args);
  363. if (pline->invalid) {
  364. fprintf(stderr, ERRORMSG "Invalid 'del' request\n");
  365. goto err;
  366. }
  367. if (faux_list_len(pline->exprs) > 1) {
  368. fprintf(stderr, ERRORMSG "Can't delete more than one object\n");
  369. goto err;
  370. }
  371. expr = (pexpr_t *)faux_list_data(faux_list_head(pline->exprs));
  372. if (!(expr->pat & PT_DEL)) {
  373. fprintf(stderr, ERRORMSG "Illegal expression for 'del' operation\n");
  374. goto err;
  375. }
  376. if (sr_delete_item(sess, expr->xpath, 0) != SR_ERR_OK) {
  377. srp_error(sess, ERRORMSG "Can't delete data\n");
  378. goto err;
  379. }
  380. if (sr_apply_changes(sess, 0) != SR_ERR_OK) {
  381. sr_discard_changes(sess);
  382. srp_error(sess, ERRORMSG "Can't apply changes\n");
  383. goto err;
  384. }
  385. ret = 0;
  386. err:
  387. pline_free(pline);
  388. return ret;
  389. }
  390. int srp_edit(kcontext_t *context)
  391. {
  392. int ret = -1;
  393. faux_argv_t *args = NULL;
  394. pline_t *pline = NULL;
  395. sr_session_ctx_t *sess = NULL;
  396. pexpr_t *expr = NULL;
  397. faux_argv_t *cur_path = NULL;
  398. assert(context);
  399. sess = srp_udata_sr_sess(context);
  400. cur_path = (faux_argv_t *)srp_udata_path(context);
  401. args = param2argv(cur_path, kcontext_pargv(context), ARG_PATH);
  402. pline = pline_parse(sess, args, srp_udata_opts(context));
  403. if (pline->invalid) {
  404. fprintf(stderr, ERRORMSG "Invalid 'edit' request\n");
  405. goto err;
  406. }
  407. if (faux_list_len(pline->exprs) > 1) {
  408. fprintf(stderr, ERRORMSG "Can't process more than one object\n");
  409. goto err;
  410. }
  411. expr = (pexpr_t *)faux_list_data(faux_list_head(pline->exprs));
  412. if (!(expr->pat & PT_EDIT)) {
  413. fprintf(stderr, ERRORMSG "Illegal expression for 'edit' operation\n");
  414. goto err;
  415. }
  416. if (sr_set_item_str(sess, expr->xpath, NULL, NULL, 0) != SR_ERR_OK) {
  417. srp_error(sess, ERRORMSG "Can't set editing data\n");
  418. goto err;
  419. }
  420. if (sr_apply_changes(sess, 0) != SR_ERR_OK) {
  421. sr_discard_changes(sess);
  422. srp_error(sess, ERRORMSG "Can't apply changes\n");
  423. goto err;
  424. }
  425. // Set new current path
  426. srp_udata_set_path(context, args);
  427. ret = 0;
  428. err:
  429. if (ret < 0)
  430. faux_argv_free(args);
  431. pline_free(pline);
  432. return ret;
  433. }
  434. int srp_top(kcontext_t *context)
  435. {
  436. assert(context);
  437. srp_udata_set_path(context, NULL);
  438. return 0;
  439. }
  440. int srp_up(kcontext_t *context)
  441. {
  442. sr_session_ctx_t *sess = NULL;
  443. faux_argv_t *cur_path = NULL;
  444. faux_argv_node_t *iter = NULL;
  445. assert(context);
  446. sess = srp_udata_sr_sess(context);
  447. cur_path = (faux_argv_t *)srp_udata_path(context);
  448. if (!cur_path)
  449. return -1; // It's top level and can't level up
  450. // Remove last arguments one by one and wait for legal edit-like pline
  451. while (faux_argv_len(cur_path) > 0) {
  452. pline_t *pline = NULL;
  453. pexpr_t *expr = NULL;
  454. size_t len = 0;
  455. iter = faux_argv_iterr(cur_path);
  456. faux_argv_del(cur_path, iter);
  457. pline = pline_parse(sess, cur_path, srp_udata_opts(context));
  458. if (pline->invalid) {
  459. pline_free(pline);
  460. continue;
  461. }
  462. len = faux_list_len(pline->exprs);
  463. if (len != 1) {
  464. pline_free(pline);
  465. continue;
  466. }
  467. expr = (pexpr_t *)faux_list_data(faux_list_head(pline->exprs));
  468. if (!(expr->pat & PT_EDIT)) {
  469. pline_free(pline);
  470. continue;
  471. }
  472. // Here new path is ok
  473. pline_free(pline);
  474. break;
  475. }
  476. // Don't store empty path
  477. if (faux_argv_len(cur_path) == 0)
  478. srp_udata_set_path(context, NULL);
  479. return 0;
  480. }
  481. int srp_insert(kcontext_t *context)
  482. {
  483. int ret = -1;
  484. pline_t *pline = NULL;
  485. pline_t *pline_to = NULL;
  486. sr_session_ctx_t *sess = NULL;
  487. pexpr_t *expr = NULL;
  488. pexpr_t *expr_to = NULL;
  489. faux_argv_t *cur_path = NULL;
  490. faux_argv_t *insert_from = NULL;
  491. faux_argv_t *insert_to = NULL;
  492. sr_move_position_t position = SR_MOVE_LAST;
  493. kpargv_t *pargv = NULL;
  494. const char *list_keys = NULL;
  495. const char *leaflist_value = NULL;
  496. assert(context);
  497. sess = srp_udata_sr_sess(context);
  498. cur_path = (faux_argv_t *)srp_udata_path(context);
  499. pargv = kcontext_pargv(context);
  500. // 'from' argument
  501. insert_from = param2argv(cur_path, pargv, ARG_FROM_PATH);
  502. pline = pline_parse(sess, insert_from, srp_udata_opts(context));
  503. faux_argv_free(insert_from);
  504. if (pline->invalid) {
  505. fprintf(stderr, ERRORMSG "Invalid 'from' expression\n");
  506. goto err;
  507. }
  508. if (faux_list_len(pline->exprs) > 1) {
  509. fprintf(stderr, ERRORMSG "Can't process more than one object\n");
  510. goto err;
  511. }
  512. expr = (pexpr_t *)faux_list_data(faux_list_head(pline->exprs));
  513. if (!(expr->pat & PT_INSERT)) {
  514. fprintf(stderr, ERRORMSG "Illegal 'from' expression for 'insert' operation\n");
  515. goto err;
  516. }
  517. // Position
  518. if (kpargv_find(pargv, "first"))
  519. position = SR_MOVE_FIRST;
  520. else if (kpargv_find(pargv, "last"))
  521. position = SR_MOVE_LAST;
  522. else if (kpargv_find(pargv, "before"))
  523. position = SR_MOVE_BEFORE;
  524. else if (kpargv_find(pargv, "after"))
  525. position = SR_MOVE_AFTER;
  526. else {
  527. fprintf(stderr, ERRORMSG "Illegal 'position' argument\n");
  528. goto err;
  529. }
  530. // 'to' argument
  531. if ((SR_MOVE_BEFORE == position) || (SR_MOVE_AFTER == position)) {
  532. insert_to = assemble_insert_to(sess, pargv, cur_path,
  533. NULL, srp_udata_opts(context));
  534. pline_to = pline_parse(sess, insert_to, srp_udata_opts(context));
  535. faux_argv_free(insert_to);
  536. if (pline_to->invalid) {
  537. fprintf(stderr, ERRORMSG "Invalid 'to' expression\n");
  538. goto err;
  539. }
  540. if (faux_list_len(pline_to->exprs) > 1) {
  541. fprintf(stderr, ERRORMSG "Can't process more than one object\n");
  542. goto err;
  543. }
  544. expr_to = (pexpr_t *)faux_list_data(faux_list_head(pline_to->exprs));
  545. if (!(expr_to->pat & PT_INSERT)) {
  546. fprintf(stderr, ERRORMSG "Illegal 'to' expression for 'insert' operation\n");
  547. goto err;
  548. }
  549. if (PAT_LIST_KEY == expr_to->pat)
  550. list_keys = expr_to->last_keys;
  551. else // PATH_LEAFLIST_VALUE
  552. leaflist_value = expr_to->last_keys;
  553. }
  554. if (sr_move_item(sess, expr->xpath, position,
  555. list_keys, leaflist_value, NULL, 0) != SR_ERR_OK) {
  556. srp_error(sess, ERRORMSG "Can't move element\n");
  557. goto err;
  558. }
  559. if (sr_apply_changes(sess, 0) != SR_ERR_OK) {
  560. sr_discard_changes(sess);
  561. srp_error(sess, ERRORMSG "Can't apply changes\n");
  562. goto err;
  563. }
  564. ret = 0;
  565. err:
  566. pline_free(pline);
  567. pline_free(pline_to);
  568. return ret;
  569. }
  570. int srp_verify(kcontext_t *context)
  571. {
  572. int ret = -1;
  573. sr_session_ctx_t *sess = NULL;
  574. assert(context);
  575. sess = srp_udata_sr_sess(context);
  576. // Validate candidate config
  577. if (sr_validate(sess, NULL, 0) != SR_ERR_OK) {
  578. srp_error(sess, ERRORMSG "Invalid candidate configuration\n");
  579. goto err;
  580. }
  581. ret = 0;
  582. err:
  583. return ret;
  584. }
  585. int srp_commit(kcontext_t *context)
  586. {
  587. int ret = -1;
  588. sr_session_ctx_t *sess = NULL;
  589. assert(context);
  590. sess = srp_udata_sr_sess(context);
  591. // Validate candidate config. The copy operation is not enough to fully
  592. // verify candidate config. It verifies only the part of it. So verify
  593. // before commit
  594. if (sr_validate(sess, NULL, 0) != SR_ERR_OK) {
  595. srp_error(sess, ERRORMSG "Invalid candidate configuration\n");
  596. goto err;
  597. }
  598. // Copy candidate to running-config
  599. if (sr_session_switch_ds(sess, SR_DS_RUNNING)) {
  600. srp_error(sess, ERRORMSG "Can't connect to running-config data store\n");
  601. goto err;
  602. }
  603. if (sr_copy_config(sess, NULL, SRP_REPO_EDIT, 0) != SR_ERR_OK) {
  604. srp_error(sess, ERRORMSG "Can't commit to running-config\n");
  605. goto err;
  606. }
  607. // Copy running-config to startup-config
  608. if (sr_session_switch_ds(sess, SR_DS_STARTUP)) {
  609. srp_error(sess, ERRORMSG "Can't connect to startup-config data store\n");
  610. goto err;
  611. }
  612. if (sr_copy_config(sess, NULL, SR_DS_RUNNING, 0) != SR_ERR_OK) {
  613. srp_error(sess, ERRORMSG "Can't store data to startup-config\n");
  614. goto err;
  615. }
  616. ret = 0;
  617. err:
  618. sr_session_switch_ds(sess, SRP_REPO_EDIT);
  619. return ret;
  620. }
  621. int srp_reset(kcontext_t *context)
  622. {
  623. int ret = -1;
  624. sr_session_ctx_t *sess = NULL;
  625. assert(context);
  626. sess = srp_udata_sr_sess(context);
  627. // Copy running-config to candidate config
  628. if (sr_copy_config(sess, NULL, SR_DS_RUNNING, 0) != SR_ERR_OK) {
  629. srp_error(sess, ERRORMSG "Can't reset to running-config\n");
  630. goto err;
  631. }
  632. ret = 0;
  633. err:
  634. return ret;
  635. }
  636. int srp_show_xml(kcontext_t *context)
  637. {
  638. int ret = -1;
  639. faux_argv_t *args = NULL;
  640. pline_t *pline = NULL;
  641. sr_session_ctx_t *sess = NULL;
  642. pexpr_t *expr = NULL;
  643. faux_argv_t *cur_path = NULL;
  644. sr_data_t *data = NULL;
  645. struct ly_out *out = NULL;
  646. assert(context);
  647. sess = srp_udata_sr_sess(context);
  648. cur_path = (faux_argv_t *)srp_udata_path(context);
  649. args = param2argv(cur_path, kcontext_pargv(context), ARG_PATH);
  650. pline = pline_parse(sess, args, srp_udata_opts(context));
  651. faux_argv_free(args);
  652. if (pline->invalid) {
  653. fprintf(stderr, ERRORMSG "Invalid 'show' request\n");
  654. goto err;
  655. }
  656. if (faux_list_len(pline->exprs) > 1) {
  657. fprintf(stderr, ERRORMSG "Can't process more than one object\n");
  658. goto err;
  659. }
  660. expr = (pexpr_t *)faux_list_data(faux_list_head(pline->exprs));
  661. if (!(expr->pat & PT_EDIT)) {
  662. fprintf(stderr, ERRORMSG "Illegal expression for 'show' operation\n");
  663. goto err;
  664. }
  665. if (sr_get_subtree(sess, expr->xpath, 0, &data) != SR_ERR_OK) {
  666. srp_error(sess, ERRORMSG "Can't get specified subtree\n");
  667. goto err;
  668. }
  669. if (!data) // Not found
  670. goto err;
  671. ly_out_new_file(stdout, &out);
  672. lyd_print_tree(out, data->tree, LYD_XML, 0);
  673. ly_out_free(out, NULL, 0);
  674. // child = lyd_child(data->tree);
  675. // if (child) {
  676. // ly_out_new_file(stdout, &out);
  677. // lyd_print_all(out, child, LYD_XML, 0);
  678. // }
  679. struct lyd_meta *meta = lyd_find_meta(data->tree->meta, NULL, "junos-configuration-metadata:active");
  680. if (meta)
  681. printf("META\n");
  682. sr_release_data(data);
  683. ret = 0;
  684. err:
  685. pline_free(pline);
  686. return ret;
  687. }
  688. static int show(kcontext_t *context, sr_datastore_t ds,
  689. const char *path_var, bool_t use_cur_path)
  690. {
  691. int ret = -1;
  692. faux_argv_t *args = NULL;
  693. pline_t *pline = NULL;
  694. sr_session_ctx_t *sess = NULL;
  695. pexpr_t *expr = NULL;
  696. faux_argv_t *cur_path = NULL;
  697. char *xpath = NULL;
  698. assert(context);
  699. sess = srp_udata_sr_sess(context);
  700. if (ds != SRP_REPO_EDIT)
  701. sr_session_switch_ds(sess, ds);
  702. if (use_cur_path)
  703. cur_path = (faux_argv_t *)srp_udata_path(context);
  704. if (kpargv_find(kcontext_pargv(context), path_var) || cur_path) {
  705. args = param2argv(cur_path, kcontext_pargv(context), path_var);
  706. pline = pline_parse(sess, args, srp_udata_opts(context));
  707. faux_argv_free(args);
  708. if (pline->invalid) {
  709. fprintf(stderr, ERRORMSG "Invalid 'show' request\n");
  710. goto err;
  711. }
  712. if (faux_list_len(pline->exprs) > 1) {
  713. fprintf(stderr, ERRORMSG "Can't process more than one object\n");
  714. goto err;
  715. }
  716. if (!(expr = (pexpr_t *)faux_list_data(faux_list_head(pline->exprs)))) {
  717. fprintf(stderr, ERRORMSG "Can't get expression\n");
  718. goto err;
  719. }
  720. if (!(expr->pat & PT_EDIT)) {
  721. fprintf(stderr, ERRORMSG "Illegal expression for 'show' operation\n");
  722. goto err;
  723. }
  724. if (!expr->xpath) {
  725. fprintf(stderr, ERRORMSG "Empty expression for 'show' operation\n");
  726. goto err;
  727. }
  728. xpath = expr->xpath;
  729. }
  730. show_xpath(sess, xpath, srp_udata_opts(context));
  731. ret = 0;
  732. err:
  733. pline_free(pline);
  734. if (ds != SRP_REPO_EDIT)
  735. sr_session_switch_ds(sess, SRP_REPO_EDIT);
  736. return ret;
  737. }
  738. static int show_path(kcontext_t *context, bool_t use_cur_path)
  739. {
  740. sr_datastore_t ds = SRP_REPO_EDIT;
  741. const char *script = NULL;
  742. assert(context);
  743. script = kcontext_script(context);
  744. if (!faux_str_is_empty(script))
  745. if (!kly_str2ds(script, strlen(script), &ds))
  746. ds = SRP_REPO_EDIT;
  747. return show(context, ds, ARG_PATH, use_cur_path);
  748. }
  749. int srp_show_abs(kcontext_t *context)
  750. {
  751. return show_path(context, BOOL_FALSE);
  752. }
  753. int srp_show(kcontext_t *context)
  754. {
  755. return show_path(context, BOOL_TRUE);
  756. }
  757. int srp_deactivate(kcontext_t *context)
  758. {
  759. int ret = -1;
  760. faux_argv_t *args = NULL;
  761. pline_t *pline = NULL;
  762. sr_session_ctx_t *sess = NULL;
  763. pexpr_t *expr = NULL;
  764. faux_argv_t *cur_path = NULL;
  765. sr_data_t *data = NULL;
  766. assert(context);
  767. sess = srp_udata_sr_sess(context);
  768. cur_path = (faux_argv_t *)srp_udata_path(context);
  769. args = param2argv(cur_path, kcontext_pargv(context), ARG_PATH);
  770. pline = pline_parse(sess, args, srp_udata_opts(context));
  771. faux_argv_free(args);
  772. if (pline->invalid) {
  773. fprintf(stderr, ERRORMSG "Invalid 'show' request\n");
  774. goto err;
  775. }
  776. if (faux_list_len(pline->exprs) > 1) {
  777. fprintf(stderr, ERRORMSG "Can't process more than one object\n");
  778. goto err;
  779. }
  780. expr = (pexpr_t *)faux_list_data(faux_list_head(pline->exprs));
  781. if (!(expr->pat & PT_DEL)) {
  782. fprintf(stderr, ERRORMSG "Illegal expression for 'show' operation\n");
  783. goto err;
  784. }
  785. if (sr_get_subtree(sess, expr->xpath, 0, &data) != SR_ERR_OK) {
  786. srp_error(sess, ERRORMSG "Can't get specified subtree\n");
  787. goto err;
  788. }
  789. if (!data) // Not found
  790. goto err;
  791. if (lyd_new_meta(LYD_CTX(data->tree), data->tree, NULL,
  792. "junos-configuration-metadata:active", "false", 0, NULL)) {
  793. fprintf(stderr, ERRORMSG "Can't deactivate\n");
  794. goto err;
  795. }
  796. struct lyd_meta *meta = lyd_find_meta(data->tree->meta, NULL, "junos-configuration-metadata:active");
  797. if (meta)
  798. printf("META\n");
  799. if (sr_has_changes(sess))
  800. fprintf(stderr, ERRORMSG "Has changes\n");
  801. if (sr_apply_changes(sess, 0) != SR_ERR_OK) {
  802. sr_discard_changes(sess);
  803. srp_error(sess, ERRORMSG "Can't apply changes\n");
  804. }
  805. sr_release_data(data);
  806. if (sr_get_subtree(sess, expr->xpath, 0, &data) != SR_ERR_OK) {
  807. srp_error(sess, ERRORMSG "Can't get specified subtree\n");
  808. goto err;
  809. }
  810. if (!data) // Not found
  811. goto err;
  812. struct ly_out *out = NULL;
  813. ly_out_new_file(stdout, &out);
  814. lyd_print_tree(out, data->tree, LYD_XML, 0);
  815. ly_out_free(out, NULL, 0);
  816. sr_release_data(data);
  817. ret = 0;
  818. err:
  819. pline_free(pline);
  820. return ret;
  821. }
  822. int srp_diff(kcontext_t *context)
  823. {
  824. int ret = -1;
  825. pline_t *pline = NULL;
  826. sr_session_ctx_t *sess = NULL;
  827. sr_data_t *data1 = NULL;
  828. sr_data_t *data2 = NULL;
  829. faux_argv_t *cur_path = NULL;
  830. const char *xpath = NULL;
  831. struct lyd_node *diff = NULL;
  832. pline_opts_t masked_opts = {};
  833. assert(context);
  834. sess = srp_udata_sr_sess(context);
  835. cur_path = (faux_argv_t *)srp_udata_path(context);
  836. if (kpargv_find(kcontext_pargv(context), ARG_PATH) || cur_path) {
  837. faux_argv_t *args = NULL;
  838. pexpr_t *expr = NULL;
  839. args = param2argv(cur_path, kcontext_pargv(context), ARG_PATH);
  840. pline = pline_parse(sess, args, srp_udata_opts(context));
  841. faux_argv_free(args);
  842. if (pline->invalid) {
  843. fprintf(stderr, ERRORMSG "Invalid 'show' request\n");
  844. goto err;
  845. }
  846. if (faux_list_len(pline->exprs) > 1) {
  847. fprintf(stderr, ERRORMSG "Can't process more than one object\n");
  848. goto err;
  849. }
  850. if (!(expr = (pexpr_t *)faux_list_data(faux_list_head(pline->exprs)))) {
  851. fprintf(stderr, ERRORMSG "Can't get expression\n");
  852. goto err;
  853. }
  854. if (!(expr->pat & PT_EDIT)) {
  855. fprintf(stderr, ERRORMSG "Illegal expression for 'show' operation\n");
  856. goto err;
  857. }
  858. if (!expr->xpath) {
  859. fprintf(stderr, ERRORMSG "Empty expression for 'show' operation\n");
  860. goto err;
  861. }
  862. xpath = expr->xpath;
  863. }
  864. if (!xpath)
  865. xpath = "/*";
  866. if (sr_get_data(sess, xpath, 0, 0, 0, &data2) != SR_ERR_OK) {
  867. srp_error(sess, ERRORMSG "Can't get specified subtree\n");
  868. goto err;
  869. }
  870. // Running config
  871. sr_session_switch_ds(sess, SR_DS_RUNNING);
  872. if (sr_get_data(sess, xpath, 0, 0, 0, &data1) != SR_ERR_OK) {
  873. srp_error(sess, ERRORMSG "Can't get specified subtree\n");
  874. goto err;
  875. }
  876. if (lyd_diff_siblings(data1 ? data1->tree : NULL, data2 ? data2->tree : NULL,
  877. 0, &diff) != LY_SUCCESS) {
  878. srp_error(sess, ERRORMSG "Can't generate diff\n");
  879. goto err;
  880. }
  881. // Hack to don't show oneliners within diff. Mask oneliners flag
  882. masked_opts = *srp_udata_opts(context);
  883. masked_opts.oneliners = BOOL_FALSE;
  884. show_subtree(diff, 0, DIFF_OP_NONE, &masked_opts, BOOL_FALSE);
  885. lyd_free_siblings(diff);
  886. ret = 0;
  887. err:
  888. if (data1)
  889. sr_release_data(data1);
  890. if (data2)
  891. sr_release_data(data2);
  892. pline_free(pline);
  893. sr_session_switch_ds(sess, SRP_REPO_EDIT);
  894. return ret;
  895. }
  896. int srp_compl_xpath(kcontext_t *context)
  897. {
  898. sr_session_ctx_t *sess = NULL;
  899. sr_val_t *vals = NULL;
  900. size_t val_num = 0;
  901. size_t i = 0;
  902. const char *script = NULL;
  903. const char *raw_xpath = NULL;
  904. sr_datastore_t ds = SRP_REPO_EDIT;
  905. assert(context);
  906. script = kcontext_script(context);
  907. if (faux_str_is_empty(script))
  908. return -1;
  909. if (!kly_parse_ext_xpath(script, &raw_xpath, &ds))
  910. return -1;
  911. sess = srp_udata_sr_sess(context);
  912. if (ds != SRP_REPO_EDIT)
  913. sr_session_switch_ds(sess, ds);
  914. sr_get_items(sess, raw_xpath, 0, 0, &vals, &val_num);
  915. for (i = 0; i < val_num; i++) {
  916. char *tmp = sr_val_to_str(&vals[i]);
  917. if (!tmp)
  918. continue;
  919. printf("%s\n", tmp);
  920. free(tmp);
  921. }
  922. sr_free_values(vals, val_num);
  923. if (ds != SRP_REPO_EDIT)
  924. sr_session_switch_ds(sess, SRP_REPO_EDIT);
  925. return 0;
  926. }