ksession_parse.c 24 KB

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