ksession_parse.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. /** @file ksession_parse.c
  2. */
  3. #include <assert.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <signal.h>
  8. #include <sys/types.h>
  9. #include <sys/wait.h>
  10. #include <unistd.h>
  11. #include <faux/eloop.h>
  12. #include <faux/buf.h>
  13. #include <faux/list.h>
  14. #include <faux/argv.h>
  15. #include <faux/error.h>
  16. #include <klish/khelper.h>
  17. #include <klish/kscheme.h>
  18. #include <klish/kpath.h>
  19. #include <klish/kpargv.h>
  20. #include <klish/kexec.h>
  21. #include <klish/ksession.h>
  22. #include <klish/ksession_parse.h>
  23. static bool_t ksession_validate_arg(ksession_t *session, kpargv_t *pargv)
  24. {
  25. const char *out = NULL;
  26. int retcode = -1;
  27. const kentry_t *ptype_entry = NULL;
  28. kparg_t *candidate = NULL;
  29. assert(session);
  30. if (!session)
  31. return BOOL_FALSE;
  32. assert(pargv);
  33. if (!pargv)
  34. return BOOL_FALSE;
  35. candidate = kpargv_candidate_parg(pargv);
  36. if (!candidate)
  37. return BOOL_FALSE;
  38. ptype_entry = kentry_nested_by_purpose(kparg_entry(candidate),
  39. KENTRY_PURPOSE_PTYPE);
  40. if (!ptype_entry)
  41. return BOOL_FALSE;
  42. if (!ksession_exec_locally(session, ptype_entry, pargv,
  43. &retcode, &out)) {
  44. return BOOL_FALSE;
  45. }
  46. if (retcode != 0)
  47. return BOOL_FALSE;
  48. if (!faux_str_is_empty(out))
  49. kparg_set_value(candidate, out);
  50. return BOOL_TRUE;
  51. }
  52. static kpargv_status_e ksession_parse_arg(ksession_t *session,
  53. const kentry_t *current_entry, faux_argv_node_t **argv_iter,
  54. kpargv_t *pargv, bool_t entry_is_command)
  55. {
  56. const kentry_t *entry = current_entry;
  57. kentry_mode_e mode = KENTRY_MODE_NONE;
  58. kpargv_status_e retcode = KPARSE_INPROGRESS; // For ENTRY itself
  59. kpargv_status_e rc = KPARSE_NOTFOUND; // For nested ENTRYs
  60. faux_argv_node_t *saved_argv_iter = NULL;
  61. kpargv_purpose_e purpose = KPURPOSE_NONE;
  62. //fprintf(stderr, "PARSE: name=%s, ref=%s, arg=%s\n",
  63. //kentry_name(entry), kentry_ref_str(entry), faux_argv_current(*argv_iter));
  64. assert(current_entry);
  65. if (!current_entry)
  66. return KPARSE_ERROR;
  67. assert(argv_iter);
  68. if (!argv_iter)
  69. return KPARSE_ERROR;
  70. assert(pargv);
  71. if (!pargv)
  72. return KPARSE_ERROR;
  73. purpose = kpargv_purpose(pargv); // Purpose of parsing
  74. // If we know the entry is a command then don't validate it. This
  75. // behaviour is usefull for special purpose entries like PTYPEs, CONDs,
  76. // etc. These entries are the starting point for parsing their args.
  77. // We don't need to parse command itself. Command is predefined.
  78. if (entry_is_command) {
  79. kparg_t *parg = NULL;
  80. // Command is an ENTRY with ACTIONs
  81. if (kentry_actions_len(entry) <= 0)
  82. return KPARSE_ILLEGAL;
  83. parg = kparg_new(entry, NULL);
  84. kpargv_add_pargs(pargv, parg);
  85. kpargv_set_command(pargv, entry);
  86. retcode = KPARSE_INPROGRESS;
  87. // Is entry candidate to resolve current arg?
  88. // Container can't be a candidate.
  89. } else if (!kentry_container(entry)) {
  90. const char *current_arg = NULL;
  91. kparg_t *parg = NULL;
  92. // When purpose is COMPLETION or HELP then fill completion list.
  93. // Additionally if it's last continuable argument then lie to
  94. // engine: make all last arguments NOTFOUND. It's necessary to walk
  95. // through all variants to gether all completions.
  96. if ((KPURPOSE_COMPLETION == purpose) ||
  97. (KPURPOSE_HELP == purpose)) {
  98. if (!*argv_iter) {
  99. // That's time to add entry to completions list.
  100. if (!kpargv_continuable(pargv))
  101. kpargv_add_completions(pargv, entry);
  102. return KPARSE_INCOMPLETED;
  103. } else {
  104. // Add entry to completions if it's last incompleted arg.
  105. if (faux_argv_is_last(*argv_iter) &&
  106. kpargv_continuable(pargv)) {
  107. kpargv_add_completions(pargv, entry);
  108. return KPARSE_NOTFOUND;
  109. }
  110. }
  111. }
  112. // If all arguments are resolved already then return INCOMPLETED
  113. if (!*argv_iter)
  114. return KPARSE_INCOMPLETED;
  115. // Validate argument
  116. current_arg = faux_argv_current(*argv_iter);
  117. parg = kparg_new(entry, current_arg);
  118. kpargv_set_candidate_parg(pargv, parg);
  119. if (ksession_validate_arg(session, pargv)) {
  120. kpargv_accept_candidate_parg(pargv);
  121. // Command is an ENTRY with ACTIONs or NAVigation
  122. if (kentry_actions_len(entry) > 0)
  123. kpargv_set_command(pargv, entry);
  124. faux_argv_each(argv_iter); // Next argument
  125. retcode = KPARSE_INPROGRESS;
  126. } else {
  127. // It's not a container and is not validated so
  128. // no chance to find anything here.
  129. kpargv_decline_candidate_parg(pargv);
  130. kparg_free(parg);
  131. return KPARSE_NOTFOUND;
  132. }
  133. }
  134. // ENTRY has no nested ENTRYs so return
  135. if (kentry_entrys_is_empty(entry))
  136. return retcode;
  137. // Walk through the nested entries:
  138. saved_argv_iter = *argv_iter;
  139. // EMPTY mode
  140. mode = kentry_mode(entry);
  141. if (KENTRY_MODE_EMPTY == mode)
  142. return retcode;
  143. // Following code (SWITCH or SEQUENCE cases) sometimes don's set rc.
  144. // It happens when entry has nested entries but purposes of all entries
  145. // are not COMMON so they will be ignored. So return code of function
  146. // will be the code of ENTRY itself processing.
  147. rc = retcode;
  148. // SWITCH mode
  149. // Entries within SWITCH can't has 'min'/'max' else than 1.
  150. // So these attributes will be ignored. Note SWITCH itself can have
  151. // 'min'/'max'.
  152. if (KENTRY_MODE_SWITCH == mode) {
  153. kentry_entrys_node_t *iter = kentry_entrys_iter(entry);
  154. const kentry_t *nested = NULL;
  155. while ((nested = kentry_entrys_each(&iter))) {
  156. //printf("SWITCH arg: %s, entry %s\n", *argv_iter ? faux_argv_current(*argv_iter) : "<empty>", kentry_name(nested));
  157. // Ignore entries with non-COMMON purpose.
  158. if (kentry_purpose(nested) != KENTRY_PURPOSE_COMMON)
  159. continue;
  160. rc = ksession_parse_arg(session, nested, argv_iter,
  161. pargv, BOOL_FALSE);
  162. //printf("%s\n", kpargv_status_decode(rc));
  163. // If some arguments was consumed then we will not check
  164. // next SWITCH's entries in any case.
  165. if (saved_argv_iter != *argv_iter)
  166. break;
  167. // Try next entries if current status is NOTFOUND.
  168. // The INCOMPLETED status is for completion list. In this
  169. // case all next statuses will be INCOMPLETED too.
  170. if ((rc != KPARSE_NOTFOUND) && (rc != KPARSE_INCOMPLETED))
  171. break;
  172. }
  173. // SEQUENCE mode
  174. } else if (KENTRY_MODE_SEQUENCE == mode) {
  175. kentry_entrys_node_t *iter = kentry_entrys_iter(entry);
  176. kentry_entrys_node_t *saved_iter = iter;
  177. const kentry_t *nested = NULL;
  178. while ((nested = kentry_entrys_each(&iter))) {
  179. kpargv_status_e nrc = KPARSE_NOTFOUND;
  180. size_t num = 0;
  181. size_t min = kentry_min(nested);
  182. //fprintf(stderr, "SEQ arg: %s, entry %s\n", *argv_iter ? faux_argv_current(*argv_iter) : "<empty>", kentry_name(nested));
  183. // Ignore entries with non-COMMON purpose.
  184. if (kentry_purpose(nested) != KENTRY_PURPOSE_COMMON)
  185. continue;
  186. // Filter out double parsing for optional entries.
  187. if (kpargv_entry_exists(pargv, nested))
  188. continue;
  189. // Try to match argument and current entry
  190. // (from 'min' to 'max' times)
  191. for (num = 0; num < kentry_max(nested); num++) {
  192. nrc = ksession_parse_arg(session, nested,
  193. argv_iter, pargv, BOOL_FALSE);
  194. //fprintf(stderr, "%s: %s\n", kentry_name(nested), kpargv_status_decode(nrc));
  195. if (nrc != KPARSE_INPROGRESS)
  196. break;
  197. }
  198. // All errors will break the loop
  199. if ((KPARSE_ERROR == nrc) ||
  200. (KPARSE_ILLEGAL == nrc) ||
  201. (KPARSE_NONE == nrc)) {
  202. rc = nrc;
  203. break;
  204. }
  205. // Not found necessary number of mandatory instances
  206. if (num < min) {
  207. if (KPARSE_INPROGRESS == nrc)
  208. rc = KPARSE_NOTFOUND;
  209. else
  210. rc = nrc; // NOTFOUND or INCOMPLETED
  211. break;
  212. }
  213. // It's not an error if optional parameter is absend
  214. rc = KPARSE_INPROGRESS;
  215. // Mandatory or ordered parameter
  216. if ((min > 0) || kentry_order(nested))
  217. saved_iter = iter;
  218. // If optional entry is found then go back to nearest
  219. // non-optional (or ordered) entry to try to find
  220. // another optional entries.
  221. if ((0 == min) && (num > 0))
  222. iter = saved_iter;
  223. }
  224. }
  225. // If nested result is NOTFOUND but argument was consumed
  226. // within nested entries or by entry itself then whole sequence
  227. // is ILLEGAL.
  228. if ((KPARSE_NOTFOUND == rc) &&
  229. ((saved_argv_iter != *argv_iter) || !kentry_container(entry)))
  230. rc = KPARSE_ILLEGAL;
  231. return rc;
  232. }
  233. kpargv_t *ksession_parse_line(ksession_t *session, const faux_argv_t *argv,
  234. kpargv_purpose_e purpose)
  235. {
  236. faux_argv_node_t *argv_iter = NULL;
  237. kpargv_t *pargv = NULL;
  238. kpargv_status_e pstatus = KPARSE_NONE;
  239. kpath_levels_node_t *levels_iterr = NULL;
  240. klevel_t *level = NULL;
  241. size_t level_found = 0; // Level where command was found
  242. kpath_t *path = NULL;
  243. assert(session);
  244. if (!session)
  245. return NULL;
  246. assert(argv);
  247. if (!argv)
  248. return NULL;
  249. argv_iter = faux_argv_iter(argv);
  250. // Initialize kpargv_t
  251. pargv = kpargv_new();
  252. assert(pargv);
  253. kpargv_set_continuable(pargv, faux_argv_is_continuable(argv));
  254. kpargv_set_purpose(pargv, purpose);
  255. // Iterate levels of path from higher to lower. Note the reversed
  256. // iterator will be used.
  257. path = ksession_path(session);
  258. levels_iterr = kpath_iterr(path);
  259. level_found = kpath_len(path) - 1; // Levels begin with '0'
  260. while ((level = kpath_eachr(&levels_iterr))) {
  261. const kentry_t *current_entry = klevel_entry(level);
  262. // Ignore entries with non-COMMON purpose. These entries are for
  263. // special processing and will be ignored here.
  264. if (kentry_purpose(current_entry) != KENTRY_PURPOSE_COMMON)
  265. continue;
  266. // Parsing
  267. pstatus = ksession_parse_arg(session, current_entry, &argv_iter,
  268. pargv, BOOL_FALSE);
  269. if (pstatus != KPARSE_NOTFOUND)
  270. break;
  271. // NOTFOUND but some args were parsed.
  272. // When it's completion for first argument (that can be continued)
  273. // len == 0 and engine will search for completions on higher
  274. // levels of path.
  275. if (kpargv_pargs_len(pargv) > 0)
  276. break;
  277. level_found--;
  278. }
  279. // Save last argument
  280. if (argv_iter)
  281. kpargv_set_last_arg(pargv, faux_argv_current(argv_iter));
  282. // It's a higher level of parsing, so some statuses can have different
  283. // meanings
  284. if (KPARSE_NONE == pstatus)
  285. pstatus = KPARSE_ERROR; // Strange case
  286. else if (KPARSE_INPROGRESS == pstatus) {
  287. if (NULL == argv_iter) // All args are parsed
  288. pstatus = KPARSE_OK;
  289. else
  290. pstatus = KPARSE_ILLEGAL; // Additional not parsable args
  291. } else if (KPARSE_NOTFOUND == pstatus)
  292. pstatus = KPARSE_ILLEGAL; // Unknown command
  293. // If no ACTIONs were found i.e. command was not found
  294. if ((KPARSE_OK == pstatus) && !kpargv_command(pargv))
  295. pstatus = KPARSE_NOACTION;
  296. kpargv_set_status(pargv, pstatus);
  297. kpargv_set_level(pargv, level_found);
  298. return pargv;
  299. }
  300. // Delimeter of commands is '|' (pipe)
  301. faux_list_t *ksession_split_pipes(const char *raw_line, faux_error_t *error)
  302. {
  303. faux_list_t *list = NULL;
  304. faux_argv_t *argv = NULL;
  305. faux_argv_node_t *argv_iter = NULL;
  306. faux_argv_t *cur_argv = NULL; // Current argv
  307. const char *delimeter = "|";
  308. const char *arg = NULL;
  309. assert(raw_line);
  310. if (!raw_line)
  311. return NULL;
  312. // Split raw line to arguments
  313. argv = faux_argv_new();
  314. assert(argv);
  315. if (!argv)
  316. return NULL;
  317. if (faux_argv_parse(argv, raw_line) < 0) {
  318. faux_argv_free(argv);
  319. return NULL;
  320. }
  321. list = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_NONUNIQUE,
  322. NULL, NULL, (void (*)(void *))faux_argv_free);
  323. assert(list);
  324. if (!list) {
  325. faux_argv_free(argv);
  326. return NULL;
  327. }
  328. argv_iter = faux_argv_iter(argv);
  329. cur_argv = faux_argv_new();
  330. assert(cur_argv);
  331. while ((arg = faux_argv_each(&argv_iter))) {
  332. if (strcmp(arg, delimeter) == 0) {
  333. // End of current line (from "|" to "|")
  334. // '|' in a first position is an error
  335. if (faux_argv_len(cur_argv) == 0) {
  336. faux_argv_free(argv);
  337. faux_list_free(list);
  338. faux_error_sprintf(error, "The pipe '|' can't "
  339. "be at the first position");
  340. return NULL;
  341. }
  342. // Add argv to argv's list
  343. faux_list_add(list, cur_argv);
  344. cur_argv = faux_argv_new();
  345. assert(cur_argv);
  346. } else {
  347. faux_argv_add(cur_argv, arg);
  348. }
  349. }
  350. // Continuable flag is usefull for last argv
  351. faux_argv_set_continuable(cur_argv, faux_argv_is_continuable(argv));
  352. // Empty cur_argv is not an error. It's usefull for completion and help.
  353. // But empty cur_argv and continuable is abnormal.
  354. if ((faux_argv_len(cur_argv) == 0) &&
  355. faux_argv_is_continuable(cur_argv)) {
  356. faux_argv_free(argv);
  357. faux_list_free(list);
  358. faux_error_sprintf(error, "The pipe '|' can't "
  359. "be the last argument");
  360. return NULL;
  361. }
  362. faux_list_add(list, cur_argv);
  363. faux_argv_free(argv);
  364. return list;
  365. }
  366. // All components except last one must be legal for execution but last
  367. // component must be parsed for completion.
  368. // Completion is a "back-end" operation so it doesn't need detailed error
  369. // reporting.
  370. kpargv_t *ksession_parse_for_completion(ksession_t *session,
  371. const char *raw_line)
  372. {
  373. faux_list_t *split = NULL;
  374. faux_list_node_t *iter = NULL;
  375. kpargv_t *pargv = NULL;
  376. assert(session);
  377. if (!session)
  378. return NULL;
  379. assert(raw_line);
  380. if (!raw_line)
  381. return NULL;
  382. // Split raw line (with '|') to components
  383. split = ksession_split_pipes(raw_line, NULL);
  384. if (!split || (faux_list_len(split) < 1)) {
  385. faux_list_free(split);
  386. return NULL;
  387. }
  388. iter = faux_list_head(split);
  389. while (iter) {
  390. faux_argv_t *argv = (faux_argv_t *)faux_list_data(iter);
  391. if (iter == faux_list_tail(split)) { // Last item
  392. pargv = ksession_parse_line(session, argv,
  393. KPURPOSE_COMPLETION);
  394. if (!pargv) {
  395. faux_list_free(split);
  396. return NULL;
  397. }
  398. } else { // Non-last item
  399. pargv = ksession_parse_line(session, argv,
  400. KPURPOSE_EXEC);
  401. // All non-last components must be ready for execution
  402. if (!pargv || kpargv_status(pargv) != KPARSE_OK) {
  403. kpargv_free(pargv);
  404. faux_list_free(split);
  405. return NULL;
  406. }
  407. }
  408. iter = faux_list_next_node(iter);
  409. }
  410. faux_list_free(split);
  411. return pargv;
  412. }
  413. kexec_t *ksession_parse_for_exec(ksession_t *session, const char *raw_line,
  414. faux_error_t *error)
  415. {
  416. faux_list_t *split = NULL;
  417. faux_list_node_t *iter = NULL;
  418. kpargv_t *pargv = NULL;
  419. kexec_t *exec = NULL;
  420. assert(session);
  421. if (!session)
  422. return NULL;
  423. assert(raw_line);
  424. if (!raw_line)
  425. return NULL;
  426. // Split raw line (with '|') to components
  427. split = ksession_split_pipes(raw_line, error);
  428. if (!split || (faux_list_len(split) < 1)) {
  429. faux_list_free(split);
  430. return NULL;
  431. }
  432. // Create exec list
  433. exec = kexec_new();
  434. assert(exec);
  435. if (!exec) {
  436. faux_list_free(split);
  437. return NULL;
  438. }
  439. iter = faux_list_head(split);
  440. while (iter) {
  441. faux_argv_t *argv = (faux_argv_t *)faux_list_data(iter);
  442. kcontext_t *context = NULL;
  443. pargv = ksession_parse_line(session, argv, KPURPOSE_EXEC);
  444. // All components must be ready for execution
  445. if (!pargv) {
  446. faux_list_free(split);
  447. return NULL;
  448. }
  449. if (kpargv_status(pargv) != KPARSE_OK) {
  450. faux_error_sprintf(error, "%s",
  451. kpargv_status_str(pargv));
  452. kpargv_free(pargv);
  453. faux_list_free(split);
  454. return NULL;
  455. }
  456. // Only the first component can have 'restore=true' attribute
  457. if ((iter != faux_list_head(split)) &&
  458. kentry_restore(kpargv_command(pargv))) {
  459. faux_error_sprintf(error, "The command \"%s\" "
  460. "can't be destination of pipe",
  461. kentry_name(kpargv_command(pargv)));
  462. kpargv_free(pargv);
  463. faux_list_free(split);
  464. return NULL;
  465. }
  466. // Fill the kexec_t
  467. context = kcontext_new(KCONTEXT_ACTION);
  468. assert(context);
  469. kcontext_set_pargv(context, pargv);
  470. // Context for ACTION execution contains session
  471. kcontext_set_session(context, session);
  472. kexec_add_contexts(exec, context);
  473. // Next component
  474. iter = faux_list_next_node(iter);
  475. }
  476. faux_list_free(split);
  477. return exec;
  478. }
  479. kexec_t *ksession_parse_for_local_exec(ksession_t *session,
  480. const kentry_t *entry, const kpargv_t *parent_pargv)
  481. {
  482. faux_argv_node_t *argv_iter = NULL;
  483. kpargv_t *pargv = NULL;
  484. kexec_t *exec = NULL;
  485. faux_argv_t *argv = NULL;
  486. kcontext_t *context = NULL;
  487. kpargv_status_e pstatus = KPARSE_NONE;
  488. const char *line = NULL; // TODO: Must be 'line' field of ENTRY
  489. assert(entry);
  490. if (!entry)
  491. return NULL;
  492. exec = kexec_new();
  493. assert(exec);
  494. argv = faux_argv_new();
  495. assert(argv);
  496. faux_argv_parse(argv, line);
  497. argv_iter = faux_argv_iter(argv);
  498. pargv = kpargv_new();
  499. assert(pargv);
  500. kpargv_set_continuable(pargv, faux_argv_is_continuable(argv));
  501. kpargv_set_purpose(pargv, KPURPOSE_EXEC);
  502. pstatus = ksession_parse_arg(session, entry, &argv_iter, pargv,
  503. BOOL_TRUE);
  504. // Parsing problems
  505. if ((pstatus != KPARSE_INPROGRESS) || (argv_iter != NULL)) {
  506. kexec_free(exec);
  507. faux_argv_free(argv);
  508. kpargv_free(pargv);
  509. return NULL;
  510. }
  511. context = kcontext_new(KCONTEXT_SERVICE_ACTION);
  512. assert(context);
  513. kcontext_set_pargv(context, pargv);
  514. kcontext_set_parent_pargv(context, parent_pargv);
  515. // Service ACTIONs like PTYPE, CONDitions etc. doesn't need session
  516. // data within context. Else it will be able to change path.
  517. kexec_add_contexts(exec, context);
  518. faux_argv_free(argv);
  519. return exec;
  520. }
  521. static bool_t stop_loop_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
  522. void *associated_data, void *user_data)
  523. {
  524. ksession_t *session = (ksession_t *)user_data;
  525. if (!session)
  526. return BOOL_FALSE;
  527. ksession_set_done(session, BOOL_TRUE); // Stop the whole session
  528. // Happy compiler
  529. eloop = eloop;
  530. type = type;
  531. associated_data = associated_data;
  532. return BOOL_FALSE; // Stop Event Loop
  533. }
  534. static bool_t action_terminated_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
  535. void *associated_data, void *user_data)
  536. {
  537. int wstatus = 0;
  538. pid_t child_pid = -1;
  539. kexec_t *exec = (kexec_t *)user_data;
  540. if (!exec)
  541. return BOOL_FALSE;
  542. // Wait for any child process. Doesn't block.
  543. while ((child_pid = waitpid(-1, &wstatus, WNOHANG)) > 0)
  544. kexec_continue_command_execution(exec, child_pid, wstatus);
  545. // Check if kexec is done now
  546. if (kexec_done(exec))
  547. return BOOL_FALSE; // To break a loop
  548. // Happy compiler
  549. eloop = eloop;
  550. type = type;
  551. associated_data = associated_data;
  552. return BOOL_TRUE;
  553. }
  554. static bool_t action_stdout_ev(faux_eloop_t *eloop, faux_eloop_type_e type,
  555. void *associated_data, void *user_data)
  556. {
  557. faux_eloop_info_fd_t *info = (faux_eloop_info_fd_t *)associated_data;
  558. kexec_t *exec = (kexec_t *)user_data;
  559. ssize_t r = -1;
  560. faux_buf_t *faux_buf = NULL;
  561. void *linear_buf = NULL;
  562. if (!exec)
  563. return BOOL_FALSE;
  564. faux_buf = kexec_bufout(exec);
  565. assert(faux_buf);
  566. do {
  567. ssize_t really_readed = 0;
  568. ssize_t linear_len =
  569. faux_buf_dwrite_lock_easy(faux_buf, &linear_buf);
  570. // Non-blocked read. The fd became non-blocked while
  571. // kexec_prepare().
  572. r = read(info->fd, linear_buf, linear_len);
  573. if (r > 0)
  574. really_readed = r;
  575. faux_buf_dwrite_unlock_easy(faux_buf, really_readed);
  576. } while (r > 0);
  577. // Happy compiler
  578. eloop = eloop;
  579. type = type;
  580. return BOOL_TRUE;
  581. }
  582. bool_t ksession_exec_locally(ksession_t *session, const kentry_t *entry,
  583. kpargv_t *parent_pargv, int *retcode, const char **out)
  584. {
  585. kexec_t *exec = NULL;
  586. faux_eloop_t *eloop = NULL;
  587. faux_buf_t *buf = NULL;
  588. char *cstr = NULL;
  589. ssize_t len = 0;
  590. assert(entry);
  591. if (!entry)
  592. return BOOL_FALSE;
  593. // Parsing
  594. exec = ksession_parse_for_local_exec(session, entry, parent_pargv);
  595. if (!exec)
  596. return BOOL_FALSE;
  597. // Session status can be changed while parsing because it can execute
  598. // nested ksession_exec_locally() to check for PTYPEs, CONDitions etc.
  599. // So check for 'done' flag to propagate it.
  600. if (ksession_done(session)) {
  601. kexec_free(exec);
  602. return BOOL_FALSE; // Because action is not completed
  603. }
  604. // Execute kexec and then wait for completion using local Eloop
  605. if (!kexec_exec(exec)) {
  606. kexec_free(exec);
  607. return BOOL_FALSE; // Something went wrong
  608. }
  609. // If kexec contains only non-exec (for example dry-run) ACTIONs then
  610. // we don't need event loop and can return here.
  611. if (kexec_retcode(exec, retcode)) {
  612. kexec_free(exec);
  613. return BOOL_TRUE;
  614. }
  615. // Local service loop
  616. eloop = faux_eloop_new(NULL);
  617. faux_eloop_add_signal(eloop, SIGINT, stop_loop_ev, session);
  618. faux_eloop_add_signal(eloop, SIGTERM, stop_loop_ev, session);
  619. faux_eloop_add_signal(eloop, SIGQUIT, stop_loop_ev, session);
  620. faux_eloop_add_signal(eloop, SIGCHLD, action_terminated_ev, exec);
  621. faux_eloop_add_fd(eloop, kexec_stdout(exec), POLLIN,
  622. action_stdout_ev, exec);
  623. faux_eloop_loop(eloop);
  624. faux_eloop_free(eloop);
  625. kexec_retcode(exec, retcode);
  626. if (!out) {
  627. kexec_free(exec);
  628. return BOOL_TRUE;
  629. }
  630. buf = kexec_bufout(exec);
  631. if ((len = faux_buf_len(buf)) <= 0) {
  632. kexec_free(exec);
  633. return BOOL_TRUE;
  634. }
  635. cstr = faux_malloc(len + 1);
  636. faux_buf_read(buf, cstr, len);
  637. cstr[len] = '\0';
  638. *out = cstr;
  639. kexec_free(exec);
  640. return BOOL_TRUE;
  641. }