kexec.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. /** @file kexec.c
  2. */
  3. #define _XOPEN_SOURCE
  4. #define _XOPEN_SOURCE_EXTENDED
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <assert.h>
  8. #include <string.h>
  9. #include <sys/types.h>
  10. #include <unistd.h>
  11. #include <fcntl.h>
  12. #include <syslog.h>
  13. #include <sys/ioctl.h>
  14. #include <termios.h>
  15. #include <faux/list.h>
  16. #include <faux/buf.h>
  17. #include <faux/eloop.h>
  18. #include <klish/khelper.h>
  19. #include <klish/kcontext.h>
  20. #include <klish/kpath.h>
  21. #include <klish/kexec.h>
  22. #define PTMX_PATH "/dev/ptmx"
  23. // Declaration of grabber. Implementation is in the grabber.c
  24. void grabber(int fds[][2]);
  25. struct kexec_s {
  26. faux_list_t *contexts;
  27. bool_t dry_run;
  28. int stdin;
  29. int stdout;
  30. int stderr;
  31. faux_buf_t *bufin;
  32. faux_buf_t *bufout;
  33. faux_buf_t *buferr;
  34. kpath_t *saved_path;
  35. };
  36. // Dry-run
  37. KGET_BOOL(exec, dry_run);
  38. KSET_BOOL(exec, dry_run);
  39. // STDIN
  40. KGET(exec, int, stdin);
  41. KSET(exec, int, stdin);
  42. // STDOUT
  43. KGET(exec, int, stdout);
  44. KSET(exec, int, stdout);
  45. // STDERR
  46. KGET(exec, int, stderr);
  47. KSET(exec, int, stderr);
  48. // BufIN
  49. KGET(exec, faux_buf_t *, bufin);
  50. KSET(exec, faux_buf_t *, bufin);
  51. // BufOUT
  52. KGET(exec, faux_buf_t *, bufout);
  53. KSET(exec, faux_buf_t *, bufout);
  54. // BufERR
  55. KGET(exec, faux_buf_t *, buferr);
  56. KSET(exec, faux_buf_t *, buferr);
  57. // Saved path
  58. KGET(exec, kpath_t *, saved_path);
  59. // CONTEXT list
  60. KADD_NESTED(exec, kcontext_t *, contexts);
  61. KNESTED_LEN(exec, contexts);
  62. KNESTED_IS_EMPTY(exec, contexts);
  63. KNESTED_ITER(exec, contexts);
  64. KNESTED_EACH(exec, kcontext_t *, contexts);
  65. kexec_t *kexec_new()
  66. {
  67. kexec_t *exec = NULL;
  68. exec = faux_zmalloc(sizeof(*exec));
  69. assert(exec);
  70. if (!exec)
  71. return NULL;
  72. exec->dry_run = BOOL_FALSE;
  73. exec->saved_path = NULL;
  74. // List of execute contexts
  75. exec->contexts = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_NONUNIQUE,
  76. NULL, NULL, (void (*)(void *))kcontext_free);
  77. assert(exec->contexts);
  78. // I/O
  79. exec->stdin = -1;
  80. exec->stdout = -1;
  81. exec->stderr = -1;
  82. exec->bufin = faux_buf_new(0);
  83. exec->bufout = faux_buf_new(0);
  84. exec->buferr = faux_buf_new(0);
  85. return exec;
  86. }
  87. void kexec_free(kexec_t *exec)
  88. {
  89. if (!exec)
  90. return;
  91. faux_list_free(exec->contexts);
  92. if (exec->stdin != -1)
  93. close(exec->stdin);
  94. if (exec->stdout != -1)
  95. close(exec->stdout);
  96. if (exec->stderr != -1)
  97. close(exec->stderr);
  98. faux_buf_free(exec->bufin);
  99. faux_buf_free(exec->bufout);
  100. faux_buf_free(exec->buferr);
  101. kpath_free(exec->saved_path);
  102. free(exec);
  103. }
  104. size_t kexec_len(const kexec_t *exec)
  105. {
  106. assert(exec);
  107. if (!exec)
  108. return 0;
  109. return faux_list_len(exec->contexts);
  110. }
  111. size_t kexec_is_empty(const kexec_t *exec)
  112. {
  113. assert(exec);
  114. if (!exec)
  115. return 0;
  116. return faux_list_is_empty(exec->contexts);
  117. }
  118. // kexec is done when all the kexec's contexts are done
  119. bool_t kexec_done(const kexec_t *exec)
  120. {
  121. faux_list_node_t *iter = NULL;
  122. kcontext_t *context = NULL;
  123. assert(exec);
  124. if (!exec)
  125. return BOOL_FALSE;
  126. iter = kexec_contexts_iter(exec);
  127. while ((context = kexec_contexts_each(&iter))) {
  128. if (!kcontext_done(context))
  129. return BOOL_FALSE;
  130. }
  131. return BOOL_TRUE;
  132. }
  133. // Retcode of kexec is a retcode of its first context execution because
  134. // next contexts just a filters. Retcode valid if kexec is done. Else current
  135. // retcode is non-valid and will not be returned at all.
  136. bool_t kexec_retcode(const kexec_t *exec, int *status)
  137. {
  138. assert(exec);
  139. if (!exec)
  140. return BOOL_FALSE;
  141. if (kexec_is_empty(exec))
  142. return BOOL_FALSE;
  143. if (!kexec_done(exec)) // Unfinished execution
  144. return BOOL_FALSE;
  145. if (status)
  146. *status = kcontext_retcode(
  147. (kcontext_t *)faux_list_data(faux_list_head(exec->contexts)));
  148. return BOOL_TRUE;
  149. }
  150. bool_t kexec_path_is_changed(const kexec_t *exec)
  151. {
  152. kpath_t *path = NULL;
  153. kcontext_t *context = NULL;
  154. assert(exec);
  155. if (!exec)
  156. return BOOL_FALSE;
  157. context = (kcontext_t *)faux_list_data(faux_list_head(exec->contexts));
  158. path = ksession_path(kcontext_session(context));
  159. if (kpath_is_equal(exec->saved_path, path))
  160. return BOOL_FALSE;
  161. return BOOL_TRUE;
  162. }
  163. bool_t kexec_add(kexec_t *exec, kcontext_t *context)
  164. {
  165. assert(exec);
  166. assert(context);
  167. if (!exec)
  168. return BOOL_FALSE;
  169. if (!context)
  170. return BOOL_FALSE;
  171. if (!faux_list_add(exec->contexts, context))
  172. return BOOL_FALSE;
  173. return BOOL_TRUE;
  174. }
  175. bool_t kexec_set_winsize(kexec_t *exec)
  176. {
  177. int fd = -1;
  178. size_t width = 0;
  179. size_t height = 0;
  180. struct winsize ws = {};
  181. int res = -1;
  182. kcontext_t *context = NULL;
  183. ksession_t *session = NULL;
  184. if (!exec)
  185. return BOOL_FALSE;
  186. if (!kexec_interactive(exec))
  187. return BOOL_FALSE;
  188. fd = kexec_stdin(exec);
  189. if (fd < 0)
  190. return BOOL_FALSE;
  191. if (!isatty(fd))
  192. return BOOL_FALSE;
  193. context = (kcontext_t *)faux_list_data(faux_list_head(exec->contexts));
  194. if (!context)
  195. return BOOL_FALSE;
  196. session = kcontext_session(context);
  197. if (!session)
  198. return BOOL_FALSE;
  199. // Set pseudo terminal window size
  200. width = ksession_term_width(session);
  201. height = ksession_term_height(session);
  202. if ((width == 0) || (height == 0))
  203. return BOOL_FALSE;
  204. ws.ws_col = (unsigned short)width;
  205. ws.ws_row = (unsigned short)height;
  206. res = ioctl(fd, TIOCSWINSZ, &ws);
  207. if (res < 0)
  208. return BOOL_FALSE;
  209. return BOOL_TRUE;
  210. }
  211. static bool_t kexec_prepare(kexec_t *exec)
  212. {
  213. int pipefd[2] = {};
  214. faux_list_node_t *iter = NULL;
  215. int global_stderr = -1;
  216. int fflags = 0;
  217. assert(exec);
  218. if (!exec)
  219. return BOOL_FALSE;
  220. // Nothing to prepare for empty list
  221. if (kexec_contexts_is_empty(exec))
  222. return BOOL_FALSE;
  223. // If command is interactive then prepare pseudoterminal. Note
  224. // interactive commands can't have filters
  225. if (kexec_interactive(exec)) {
  226. int ptm = -1;
  227. char *pts_name = NULL;
  228. kcontext_t *context = (kcontext_t *)faux_list_data(
  229. faux_list_head(exec->contexts));
  230. ptm = open(PTMX_PATH, O_RDWR, O_NOCTTY);
  231. if (ptm < 0)
  232. return BOOL_FALSE;
  233. // Set O_NONBLOCK flag here. Because this flag is ignored while
  234. // open() ptmx. I don't know why. fcntl() is working fine.
  235. fflags = fcntl(ptm, F_GETFL);
  236. fcntl(ptm, F_SETFL, fflags | O_NONBLOCK);
  237. grantpt(ptm);
  238. unlockpt(ptm);
  239. pts_name = ptsname(ptm);
  240. kexec_set_stdin(exec, ptm);
  241. kexec_set_stdout(exec, ptm);
  242. kexec_set_stderr(exec, ptm);
  243. // Don't set pts fd here. In a case of pseudo-terminal the pts
  244. // must be opened later in the child after setsid(). So just
  245. // save filename of pts.
  246. kcontext_set_pts_fn(context, pts_name);
  247. // Set pseudo terminal window size
  248. kexec_set_winsize(exec);
  249. return BOOL_TRUE;
  250. }
  251. // Create "global" stdin, stdout, stderr for the whole job execution.
  252. // Now function creates only the simple pipes but somedays it will be
  253. // able to create pseudo-terminal for interactive sessions.
  254. // STDIN
  255. if (pipe(pipefd) < 0)
  256. return BOOL_FALSE;
  257. kcontext_set_stdin(faux_list_data(faux_list_head(exec->contexts)),
  258. pipefd[0]); // Read end
  259. kexec_set_stdin(exec, pipefd[1]); // Write end
  260. // STDOUT
  261. if (pipe(pipefd) < 0)
  262. return BOOL_FALSE;
  263. // Read end of 'stdout' pipe must be non-blocked
  264. fflags = fcntl(pipefd[0], F_GETFL);
  265. fcntl(pipefd[0], F_SETFL, fflags | O_NONBLOCK);
  266. kexec_set_stdout(exec, pipefd[0]); // Read end
  267. kcontext_set_stdout(faux_list_data(faux_list_tail(exec->contexts)),
  268. pipefd[1]); // Write end
  269. // STDERR
  270. if (pipe(pipefd) < 0)
  271. return BOOL_FALSE;
  272. // Read end of 'stderr' pipe must be non-blocked
  273. fflags = fcntl(pipefd[0], F_GETFL);
  274. fcntl(pipefd[0], F_SETFL, fflags | O_NONBLOCK);
  275. kexec_set_stderr(exec, pipefd[0]); // Read end
  276. // STDERR write end will be set to all list members as stderr
  277. global_stderr = pipefd[1]; // Write end
  278. // Iterate all context_t elements to fill all stdin, stdout, stderr
  279. for (iter = faux_list_head(exec->contexts); iter;
  280. iter = faux_list_next_node(iter)) {
  281. faux_list_node_t *next = faux_list_next_node(iter);
  282. kcontext_t *context = (kcontext_t *)faux_list_data(iter);
  283. // The first context is a context of main command. The other
  284. // contexts are contexts of filters. So save current path from
  285. // first context.
  286. if (iter == faux_list_head(exec->contexts)) {
  287. ksession_t *session = kcontext_session(context);
  288. if (session && ksession_path(session))
  289. exec->saved_path = kpath_clone(
  290. ksession_path(session));
  291. }
  292. // Set the same STDERR to all contexts
  293. kcontext_set_stderr(context, global_stderr);
  294. // Create pipes beetween processes
  295. if (next) {
  296. kcontext_t *next_context = (kcontext_t *)faux_list_data(next);
  297. if (pipe(pipefd) < 0)
  298. return BOOL_FALSE;
  299. kcontext_set_stdout(context, pipefd[1]); // Write end
  300. kcontext_set_stdin(next_context, pipefd[0]); // Read end
  301. }
  302. }
  303. return BOOL_TRUE;
  304. }
  305. // === SYNC symbol execution
  306. // The function will be executed right here. It's necessary for
  307. // navigation implementation for example. To grab function output the
  308. // service process will be forked. It gets output and stores it to the
  309. // internal buffer. After sym function return grabber will write
  310. // buffered data back. So grabber will simulate async sym execution.
  311. static bool_t exec_action_sync(kcontext_t *context, const kaction_t *action,
  312. pid_t *pid, int *retcode)
  313. {
  314. ksym_fn fn = NULL;
  315. int exitcode = 0;
  316. pid_t child_pid = -1;
  317. int pipe_stdout[2] = {};
  318. int pipe_stderr[2] = {};
  319. // Create pipes beetween sym function and grabber
  320. if (pipe(pipe_stdout) < 0)
  321. return BOOL_FALSE;
  322. if (pipe(pipe_stderr) < 0) {
  323. close(pipe_stdout[0]);
  324. close(pipe_stdout[1]);
  325. return BOOL_FALSE;
  326. }
  327. fn = ksym_function(kaction_sym(action));
  328. // Prepare streams before fork
  329. fflush(stdout);
  330. fflush(stderr);
  331. // Fork the grabber
  332. child_pid = fork();
  333. if (child_pid == -1) {
  334. close(pipe_stdout[0]);
  335. close(pipe_stdout[1]);
  336. close(pipe_stderr[0]);
  337. close(pipe_stderr[1]);
  338. return BOOL_FALSE;
  339. }
  340. // Parent
  341. if (child_pid != 0) {
  342. int saved_stdout = -1;
  343. int saved_stderr = -1;
  344. // Save pid of grabber
  345. if (pid)
  346. *pid = child_pid;
  347. // Temporarily replace orig output streams by pipe
  348. // stdout
  349. saved_stdout = dup(STDOUT_FILENO);
  350. dup2(pipe_stdout[1], STDOUT_FILENO);
  351. close(pipe_stdout[0]);
  352. close(pipe_stdout[1]);
  353. // stderr
  354. saved_stderr = dup(STDERR_FILENO);
  355. dup2(pipe_stderr[1], STDERR_FILENO);
  356. close(pipe_stderr[0]);
  357. close(pipe_stderr[1]);
  358. // Execute sym function right here
  359. exitcode = fn(context);
  360. if (retcode)
  361. *retcode = exitcode;
  362. // Restore orig output streams
  363. // stdout
  364. fflush(stdout);
  365. dup2(saved_stdout, STDOUT_FILENO);
  366. close(saved_stdout);
  367. // stderr
  368. fflush(stderr);
  369. dup2(saved_stderr, STDERR_FILENO);
  370. close(saved_stderr);
  371. return BOOL_TRUE;
  372. }
  373. // Child (Output grabber)
  374. close(pipe_stdout[1]);
  375. close(pipe_stderr[1]);
  376. {
  377. int fds[][2] = {
  378. {pipe_stdout[0], kcontext_stdout(context)},
  379. {pipe_stderr[0], kcontext_stderr(context)},
  380. {-1, -1},
  381. };
  382. grabber(fds);
  383. }
  384. close(pipe_stdout[0]);
  385. close(pipe_stderr[0]);
  386. _exit(0);
  387. return BOOL_TRUE;
  388. }
  389. // === ASYNC symbol execution
  390. // The process will be forked and sym will be executed there.
  391. // The parent will save forked process's pid and immediately return
  392. // control to event loop which will get forked process stdout and
  393. // wait for process termination.
  394. static bool_t exec_action_async(kcontext_t *context, const kaction_t *action,
  395. pid_t *pid)
  396. {
  397. ksym_fn fn = NULL;
  398. int exitcode = 0;
  399. pid_t child_pid = -1;
  400. int i = 0;
  401. int fdmax = 0;
  402. const char *pts_fn = NULL;
  403. fn = ksym_function(kaction_sym(action));
  404. // Oh, it's amazing world of stdio!
  405. // Flush buffers before fork() because buffer content will be inherited
  406. // by child. Moreover dup2() can replace old stdout file descriptor by
  407. // the new one but buffer linked with stdout stream will remain the same.
  408. // It must be empty.
  409. fflush(stdout);
  410. fflush(stderr);
  411. child_pid = fork();
  412. if (child_pid == -1)
  413. return BOOL_FALSE;
  414. // Parent
  415. // Save the child pid and return control. Later event loop will wait
  416. // for saved pid.
  417. if (child_pid != 0) {
  418. if (pid)
  419. *pid = child_pid;
  420. return BOOL_TRUE;
  421. }
  422. // Child
  423. if ((pts_fn = kcontext_pts_fn(context)) != NULL) {
  424. int fd = -1;
  425. setsid();
  426. fd = open(pts_fn, O_RDWR, 0);
  427. if (fd < 0)
  428. _exit(-1);
  429. dup2(fd, STDIN_FILENO);
  430. dup2(fd, STDOUT_FILENO);
  431. dup2(fd, STDERR_FILENO);
  432. } else {
  433. dup2(kcontext_stdin(context), STDIN_FILENO);
  434. dup2(kcontext_stdout(context), STDOUT_FILENO);
  435. dup2(kcontext_stderr(context), STDERR_FILENO);
  436. }
  437. // Close all inherited fds except stdin, stdout, stderr
  438. fdmax = (int)sysconf(_SC_OPEN_MAX);
  439. for (i = (STDERR_FILENO + 1); i < fdmax; i++)
  440. close(i);
  441. exitcode = fn(context);
  442. // We will use _exit() later so stdio streams will remain unflushed.
  443. // Some output data can be lost. Flush necessary streams here.
  444. fflush(stdout);
  445. fflush(stderr);
  446. // Use _exit() but not exit() to don't flush all the stdio streams. It
  447. // can be dangerous because parent can have a lot of streams inhereted
  448. // by child process.
  449. _exit(exitcode);
  450. return BOOL_TRUE;
  451. }
  452. static bool_t exec_action(kcontext_t *context, const kaction_t *action,
  453. pid_t *pid, int *retcode)
  454. {
  455. assert(context);
  456. if (!context)
  457. return BOOL_FALSE;
  458. assert(action);
  459. if (!action)
  460. return BOOL_FALSE;
  461. if (kaction_is_sync(action))
  462. return exec_action_sync(context, action, pid, retcode);
  463. return exec_action_async(context, action, pid);
  464. }
  465. static bool_t exec_action_sequence(const kexec_t *exec, kcontext_t *context,
  466. pid_t pid, int wstatus)
  467. {
  468. faux_list_node_t *iter = NULL;
  469. int exitstatus = WEXITSTATUS(wstatus);
  470. pid_t new_pid = -1; // PID of newly forked ACTION process
  471. assert(context);
  472. if (!context)
  473. return BOOL_FALSE;
  474. // There is two reasons to don't start any real actions.
  475. // - The ACTION sequence is already done;
  476. // - Passed PID (PID of completed process) is not owned by this context.
  477. // Returns false that indicates this PID is not mine.
  478. if (kcontext_done(context) || (kcontext_pid(context) != pid))
  479. return BOOL_FALSE;
  480. // Here we know that given PID is our PID
  481. iter = kcontext_action_iter(context); // Get saved current ACTION
  482. // ASYNC: Compute new value for retcode.
  483. // Here iter is a pointer to previous action but not new.
  484. // It's for async actions only. Sync actions will change global
  485. // retcode after the exec_action() invocation.
  486. if (iter) {
  487. const kaction_t *terminated_action = faux_list_data(iter);
  488. assert(terminated_action);
  489. if (!kaction_is_sync(terminated_action) &&
  490. kaction_update_retcode(terminated_action))
  491. kcontext_set_retcode(context, exitstatus);
  492. }
  493. // Loop is needed because some ACTIONs will be skipped due to specified
  494. // execution conditions. So try next actions.
  495. do {
  496. const kaction_t *action = NULL;
  497. bool_t is_sync = BOOL_FALSE;
  498. // Get next ACTION from sequence
  499. if (!iter) { // Is it the first ACTION within list
  500. faux_list_t *actions =
  501. kentry_actions(kpargv_command(kcontext_pargv(context)));
  502. assert(actions);
  503. iter = faux_list_head(actions);
  504. } else {
  505. iter = faux_list_next_node(iter);
  506. }
  507. kcontext_set_action_iter(context, iter);
  508. // Is it end of ACTION sequence?
  509. if (!iter) {
  510. kcontext_set_done(context, BOOL_TRUE);
  511. return BOOL_TRUE;
  512. }
  513. // Get new ACTION to execute
  514. action = (const kaction_t *)faux_list_data(iter);
  515. assert(action);
  516. // Check for previous retcode to find out if next command must
  517. // be executed or skipped.
  518. if (!kaction_meet_exec_conditions(action, kcontext_retcode(context)))
  519. continue; // Skip action, try next one
  520. // Check for dry-run flag and 'permanent' feature of ACTION.
  521. if (kexec_dry_run(exec) && !kaction_is_permanent(action)) {
  522. is_sync = BOOL_TRUE; // Simulate sync action
  523. exitstatus = 0; // Exit status while dry-run is always 0
  524. } else { // Normal execution
  525. is_sync = kaction_is_sync(action);
  526. exec_action(context, action, &new_pid, &exitstatus);
  527. }
  528. // SYNC: Compute new value for retcode.
  529. // Sync actions return retcode immediatelly. Their forked
  530. // processes are for output handling only.
  531. if (is_sync && kaction_update_retcode(action))
  532. kcontext_set_retcode(context, exitstatus);
  533. } while (-1 == new_pid); // PID is not -1 when new process was forked
  534. // Save PID of newly created process
  535. kcontext_set_pid(context, new_pid);
  536. return BOOL_TRUE;
  537. }
  538. bool_t kexec_continue_command_execution(kexec_t *exec, pid_t pid, int wstatus)
  539. {
  540. faux_list_node_t *iter = NULL;
  541. kcontext_t *context = NULL;
  542. assert(exec);
  543. if (!exec)
  544. return BOOL_FALSE;
  545. iter = kexec_contexts_iter(exec);
  546. while ((context = kexec_contexts_each(&iter))) {
  547. bool_t found = BOOL_FALSE;
  548. found = exec_action_sequence(exec, context, pid, wstatus);
  549. if (found && (pid != -1))
  550. break;
  551. }
  552. return BOOL_TRUE;
  553. }
  554. bool_t kexec_exec(kexec_t *exec)
  555. {
  556. kcontext_t *context = NULL;
  557. const kpargv_t *pargv = NULL;
  558. const kentry_t *entry = NULL;
  559. bool_t restore = BOOL_FALSE;
  560. assert(exec);
  561. if (!exec)
  562. return BOOL_FALSE;
  563. // Firsly prepare kexec object for execution. The file streams must
  564. // be created for stdin, stdout, stderr of processes.
  565. if (!kexec_prepare(exec))
  566. return BOOL_FALSE;
  567. // Pre-change VIEW if command has "restore" flag. Only first command in
  568. // line (if many commands are piped) matters. Filters can't change the
  569. // VIEW.
  570. context = (kcontext_t *)faux_list_data(faux_list_head(exec->contexts));
  571. pargv = kcontext_pargv(context);
  572. entry = kpargv_command(pargv);
  573. if (entry)
  574. restore = kentry_restore(entry);
  575. if (restore) {
  576. size_t level = kpargv_level(pargv);
  577. kpath_t *path = ksession_path(kcontext_session(context));
  578. while(kpath_len(path) > (level + 1))
  579. kpath_pop(path);
  580. }
  581. // Here no ACTIONs are executing, so pass -1 as pid of terminated
  582. // ACTION's process.
  583. kexec_continue_command_execution(exec, -1, 0);
  584. return BOOL_TRUE;
  585. }
  586. bool_t kexec_interactive(const kexec_t *exec)
  587. {
  588. faux_list_node_t *node = NULL;
  589. kcontext_t *context = NULL;
  590. const kentry_t *entry = NULL;
  591. assert(exec);
  592. if (!exec)
  593. return BOOL_FALSE;
  594. // Only the ACTION of first context can be interactive
  595. node = faux_list_head(exec->contexts);
  596. if (!node)
  597. return BOOL_FALSE;
  598. context = (kcontext_t *)faux_list_data(node);
  599. if (!context)
  600. return BOOL_FALSE;
  601. entry = kcontext_command(context);
  602. if (!entry)
  603. return BOOL_FALSE;
  604. return kentry_interactive(entry);
  605. }