syms.c 26 KB

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