syms.c 32 KB

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