kexec.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. /** @file kexec.c
  2. */
  3. #include <assert.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <sys/types.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <faux/list.h>
  11. #include <faux/buf.h>
  12. #include <faux/eloop.h>
  13. #include <klish/khelper.h>
  14. #include <klish/kcontext.h>
  15. #include <klish/kexec.h>
  16. // Declaration of grabber. Implementation is in the grabber.c
  17. void grabber(int fds[][2]);
  18. struct kexec_s {
  19. faux_list_t *contexts;
  20. bool_t dry_run;
  21. int stdin;
  22. int stdout;
  23. int stderr;
  24. faux_buf_t *bufin;
  25. faux_buf_t *bufout;
  26. faux_buf_t *buferr;
  27. };
  28. // Dry-run
  29. KGET_BOOL(exec, dry_run);
  30. KSET_BOOL(exec, dry_run);
  31. // STDIN
  32. KGET(exec, int, stdin);
  33. KSET(exec, int, stdin);
  34. // STDOUT
  35. KGET(exec, int, stdout);
  36. KSET(exec, int, stdout);
  37. // STDERR
  38. KGET(exec, int, stderr);
  39. KSET(exec, int, stderr);
  40. // BufIN
  41. KGET(exec, faux_buf_t *, bufin);
  42. KSET(exec, faux_buf_t *, bufin);
  43. // BufOUT
  44. KGET(exec, faux_buf_t *, bufout);
  45. KSET(exec, faux_buf_t *, bufout);
  46. // BufERR
  47. KGET(exec, faux_buf_t *, buferr);
  48. KSET(exec, faux_buf_t *, buferr);
  49. // CONTEXT list
  50. KADD_NESTED(exec, kcontext_t *, contexts);
  51. KNESTED_LEN(exec, contexts);
  52. KNESTED_IS_EMPTY(exec, contexts);
  53. KNESTED_ITER(exec, contexts);
  54. KNESTED_EACH(exec, kcontext_t *, contexts);
  55. kexec_t *kexec_new()
  56. {
  57. kexec_t *exec = NULL;
  58. exec = faux_zmalloc(sizeof(*exec));
  59. assert(exec);
  60. if (!exec)
  61. return NULL;
  62. exec->dry_run = BOOL_FALSE;
  63. // List of execute contexts
  64. exec->contexts = faux_list_new(FAUX_LIST_UNSORTED, FAUX_LIST_NONUNIQUE,
  65. NULL, NULL, (void (*)(void *))kcontext_free);
  66. assert(exec->contexts);
  67. // I/O
  68. exec->stdin = -1;
  69. exec->stdout = -1;
  70. exec->stderr = -1;
  71. exec->bufin = faux_buf_new(0);
  72. exec->bufout = faux_buf_new(0);
  73. exec->buferr = faux_buf_new(0);
  74. return exec;
  75. }
  76. void kexec_free(kexec_t *exec)
  77. {
  78. if (!exec)
  79. return;
  80. faux_list_free(exec->contexts);
  81. faux_buf_free(exec->bufin);
  82. faux_buf_free(exec->bufout);
  83. faux_buf_free(exec->buferr);
  84. free(exec);
  85. }
  86. size_t kexec_len(const kexec_t *exec)
  87. {
  88. assert(exec);
  89. if (!exec)
  90. return 0;
  91. return faux_list_len(exec->contexts);
  92. }
  93. size_t kexec_is_empty(const kexec_t *exec)
  94. {
  95. assert(exec);
  96. if (!exec)
  97. return 0;
  98. return faux_list_is_empty(exec->contexts);
  99. }
  100. // kexec is done when all the kexec's contexts are done
  101. bool_t kexec_done(const kexec_t *exec)
  102. {
  103. faux_list_node_t *iter = NULL;
  104. kcontext_t *context = NULL;
  105. assert(exec);
  106. if (!exec)
  107. return BOOL_FALSE;
  108. iter = kexec_contexts_iter(exec);
  109. while ((context = kexec_contexts_each(&iter))) {
  110. if (!kcontext_done(context))
  111. return BOOL_FALSE;
  112. }
  113. return BOOL_TRUE;
  114. }
  115. // Retcode of kexec is a retcode of its first context execution because
  116. // next contexts just a filters. Retcode valid if kexec is done. Else current
  117. // retcode is non-valid and will not be returned at all.
  118. bool_t kexec_retcode(const kexec_t *exec, int *status)
  119. {
  120. assert(exec);
  121. if (!exec)
  122. return BOOL_FALSE;
  123. if (kexec_is_empty(exec))
  124. return BOOL_FALSE;
  125. if (!kexec_done(exec)) // Unfinished execution
  126. return BOOL_FALSE;
  127. if (status)
  128. *status = kcontext_retcode(
  129. (kcontext_t *)faux_list_data(faux_list_head(exec->contexts)));
  130. return BOOL_TRUE;
  131. }
  132. bool_t kexec_add(kexec_t *exec, kcontext_t *context)
  133. {
  134. assert(exec);
  135. assert(context);
  136. if (!exec)
  137. return BOOL_FALSE;
  138. if (!context)
  139. return BOOL_FALSE;
  140. if (!faux_list_add(exec->contexts, context))
  141. return BOOL_FALSE;
  142. return BOOL_TRUE;
  143. }
  144. static bool_t kexec_prepare(kexec_t *exec)
  145. {
  146. int pipefd[2] = {};
  147. faux_list_node_t *iter = NULL;
  148. int global_stderr = -1;
  149. int fflags = 0;
  150. assert(exec);
  151. if (!exec)
  152. return BOOL_FALSE;
  153. // Nothing to prepare for empty list
  154. if (kexec_contexts_is_empty(exec))
  155. return BOOL_FALSE;
  156. // Create "global" stdin, stdout, stderr for the whole job execution.
  157. // Now function creates only the simple pipes but somedays it will be
  158. // able to create pseudo-terminal for interactive sessions.
  159. // STDIN
  160. if (pipe(pipefd) < 0)
  161. return BOOL_FALSE;
  162. kcontext_set_stdin(faux_list_data(faux_list_head(exec->contexts)),
  163. pipefd[0]); // Read end
  164. kexec_set_stdin(exec, pipefd[1]); // Write end
  165. // STDOUT
  166. if (pipe(pipefd) < 0)
  167. return BOOL_FALSE;
  168. // Read end of 'stdout' pipe must be non-blocked
  169. fflags = fcntl(pipefd[0], F_GETFL);
  170. fcntl(pipefd[0], F_SETFL, fflags | O_NONBLOCK);
  171. kexec_set_stdout(exec, pipefd[0]); // Read end
  172. kcontext_set_stdout(faux_list_data(faux_list_tail(exec->contexts)),
  173. pipefd[1]); // Write end
  174. // STDERR
  175. if (pipe(pipefd) < 0)
  176. return BOOL_FALSE;
  177. // Read end of 'stderr' pipe must be non-blocked
  178. fflags = fcntl(pipefd[0], F_GETFL);
  179. fcntl(pipefd[0], F_SETFL, fflags | O_NONBLOCK);
  180. kexec_set_stderr(exec, pipefd[0]); // Read end
  181. // STDERR write end will be set to all list members as stderr
  182. global_stderr = pipefd[1]; // Write end
  183. // Iterate all context_t elements to fill all stdin, stdout, stderr
  184. for (iter = faux_list_head(exec->contexts); iter;
  185. iter = faux_list_next_node(iter)) {
  186. faux_list_node_t *next = faux_list_next_node(iter);
  187. kcontext_t *context = (kcontext_t *)faux_list_data(iter);
  188. // Set the same STDERR to all contexts
  189. kcontext_set_stderr(context, global_stderr);
  190. // Create pipes beetween processes
  191. if (next) {
  192. kcontext_t *next_context = (kcontext_t *)faux_list_data(next);
  193. if (pipe(pipefd) < 0)
  194. return BOOL_FALSE;
  195. kcontext_set_stdout(context, pipefd[1]); // Write end
  196. kcontext_set_stdin(next_context, pipefd[0]); // Read end
  197. }
  198. }
  199. return BOOL_TRUE;
  200. }
  201. // === SYNC symbol execution
  202. // The function will be executed right here. It's necessary for
  203. // navigation implementation for example. To grab function output the
  204. // service process will be forked. It gets output and stores it to the
  205. // internal buffer. After sym function return grabber will write
  206. // buffered data back. So grabber will simulate async sym execution.
  207. static bool_t exec_action_sync(kcontext_t *context, const kaction_t *action,
  208. pid_t *pid, int *retcode)
  209. {
  210. ksym_fn fn = NULL;
  211. int exitcode = 0;
  212. pid_t child_pid = -1;
  213. int pipe_stdout[2] = {};
  214. int pipe_stderr[2] = {};
  215. // Create pipes beetween sym function and grabber
  216. if (pipe(pipe_stdout) < 0)
  217. return BOOL_FALSE;
  218. if (pipe(pipe_stderr) < 0) {
  219. close(pipe_stdout[0]);
  220. close(pipe_stdout[1]);
  221. return BOOL_FALSE;
  222. }
  223. fn = ksym_function(kaction_sym(action));
  224. // Prepare streams before fork
  225. fflush(stdout);
  226. fflush(stderr);
  227. // Fork the grabber
  228. child_pid = fork();
  229. if (child_pid == -1) {
  230. close(pipe_stdout[0]);
  231. close(pipe_stdout[1]);
  232. close(pipe_stderr[0]);
  233. close(pipe_stderr[1]);
  234. return BOOL_FALSE;
  235. }
  236. // Parent
  237. if (child_pid != 0) {
  238. int saved_stdout = -1;
  239. int saved_stderr = -1;
  240. // Save pid of grabber
  241. if (pid)
  242. *pid = child_pid;
  243. // Temporarily replace orig output streams by pipe
  244. // stdout
  245. saved_stdout = dup(STDOUT_FILENO);
  246. dup2(pipe_stdout[1], STDOUT_FILENO);
  247. close(pipe_stdout[0]);
  248. close(pipe_stdout[1]);
  249. // stderr
  250. saved_stderr = dup(STDERR_FILENO);
  251. dup2(pipe_stderr[1], STDERR_FILENO);
  252. close(pipe_stderr[0]);
  253. close(pipe_stderr[1]);
  254. // Execute sym function right here
  255. exitcode = fn(context);
  256. if (retcode)
  257. *retcode = exitcode;
  258. // Restore orig output streams
  259. // stdout
  260. fflush(stdout);
  261. dup2(saved_stdout, STDOUT_FILENO);
  262. close(saved_stdout);
  263. // stderr
  264. fflush(stderr);
  265. dup2(saved_stderr, STDERR_FILENO);
  266. close(saved_stderr);
  267. return BOOL_TRUE;
  268. }
  269. // Child (Output grabber)
  270. close(pipe_stdout[1]);
  271. close(pipe_stderr[1]);
  272. {
  273. int fds[][2] = {
  274. {pipe_stdout[0], kcontext_stdout(context)},
  275. {pipe_stderr[0], kcontext_stderr(context)},
  276. {-1, -1},
  277. };
  278. grabber(fds);
  279. }
  280. close(pipe_stdout[0]);
  281. close(pipe_stderr[0]);
  282. _exit(0);
  283. return BOOL_TRUE;
  284. }
  285. // === ASYNC symbol execution
  286. // The process will be forked and sym will be executed there.
  287. // The parent will save forked process's pid and immediately return
  288. // control to event loop which will get forked process stdout and
  289. // wait for process termination.
  290. static bool_t exec_action_async(kcontext_t *context, const kaction_t *action,
  291. pid_t *pid)
  292. {
  293. ksym_fn fn = NULL;
  294. int exitcode = 0;
  295. pid_t child_pid = -1;
  296. fn = ksym_function(kaction_sym(action));
  297. // Oh, it's amazing world of stdio!
  298. // Flush buffers before fork() because buffer content will be inherited
  299. // by child. Moreover dup2() can replace old stdout file descriptor by
  300. // the new one but buffer linked with stdout stream will remain the same.
  301. // It must be empty.
  302. fflush(stdout);
  303. fflush(stderr);
  304. child_pid = fork();
  305. if (child_pid == -1)
  306. return BOOL_FALSE;
  307. // Parent
  308. // Save the child pid and return control. Later event loop will wait
  309. // for saved pid.
  310. if (child_pid != 0) {
  311. if (pid)
  312. *pid = child_pid;
  313. return BOOL_TRUE;
  314. }
  315. // Child
  316. dup2(kcontext_stdin(context), STDIN_FILENO);
  317. dup2(kcontext_stdout(context), STDOUT_FILENO);
  318. dup2(kcontext_stderr(context), STDERR_FILENO);
  319. exitcode = fn(context);
  320. // We will use _exit() later so stdio streams will remain unflushed.
  321. // Some output data can be lost. Flush necessary streams here.
  322. fflush(stdout);
  323. fflush(stderr);
  324. // Use _exit() but not exit() to don't flush all the stdio streams. It
  325. // can be dangerous because parent can have a lot of streams inhereted
  326. // by child process.
  327. _exit(exitcode);
  328. return BOOL_TRUE;
  329. }
  330. static bool_t exec_action(kcontext_t *context, const kaction_t *action,
  331. pid_t *pid, int *retcode)
  332. {
  333. assert(context);
  334. if (!context)
  335. return BOOL_FALSE;
  336. assert(action);
  337. if (!action)
  338. return BOOL_FALSE;
  339. if (kaction_is_sync(action))
  340. return exec_action_sync(context, action, pid, retcode);
  341. return exec_action_async(context, action, pid);
  342. }
  343. static bool_t exec_action_sequence(const kexec_t *exec, kcontext_t *context,
  344. pid_t pid, int wstatus)
  345. {
  346. faux_list_node_t *iter = NULL;
  347. int exitstatus = WEXITSTATUS(wstatus);
  348. pid_t new_pid = -1; // PID of newly forked ACTION process
  349. assert(context);
  350. if (!context)
  351. return BOOL_FALSE;
  352. // There is two reasons to don't start any real actions.
  353. // - The ACTION sequence is already done;
  354. // - Passed PID (PID of completed process) is not owned by this context.
  355. // Returns false that indicates this PID is not mine.
  356. if (kcontext_done(context) || (kcontext_pid(context) != pid))
  357. return BOOL_FALSE;
  358. // Here we know that given PID is our PID
  359. iter = kcontext_action_iter(context); // Get saved current ACTION
  360. // ASYNC: Compute new value for retcode.
  361. // Here iter is a pointer to previous action but not new.
  362. // It's for async actions only. Sync actions will change global
  363. // retcode after the exec_action() invocation.
  364. if (iter) {
  365. const kaction_t *terminated_action = faux_list_data(iter);
  366. assert(terminated_action);
  367. if (!kaction_is_sync(terminated_action) &&
  368. kaction_update_retcode(terminated_action))
  369. kcontext_set_retcode(context, exitstatus);
  370. }
  371. // Loop is needed because some ACTIONs will be skipped due to specified
  372. // execution conditions. So try next actions.
  373. do {
  374. const kaction_t *action = NULL;
  375. bool_t is_sync = BOOL_FALSE;
  376. // Get next ACTION from sequence
  377. if (!iter) { // Is it the first ACTION within list
  378. faux_list_t *actions =
  379. kentry_actions(kpargv_command(kcontext_pargv(context)));
  380. assert(actions);
  381. iter = faux_list_head(actions);
  382. } else {
  383. iter = faux_list_next_node(iter);
  384. }
  385. kcontext_set_action_iter(context, iter);
  386. // Is it end of ACTION sequence?
  387. if (!iter) {
  388. kcontext_set_done(context, BOOL_TRUE);
  389. return BOOL_TRUE;
  390. }
  391. // Get new ACTION to execute
  392. action = (const kaction_t *)faux_list_data(iter);
  393. assert(action);
  394. // Check for previous retcode to find out if next command must
  395. // be executed or skipped.
  396. if (!kaction_meet_exec_conditions(action, kcontext_retcode(context)))
  397. continue; // Skip action, try next one
  398. // Check for dry-run flag and 'permanent' feature of ACTION.
  399. if (kexec_dry_run(exec) && !kaction_permanent(action)) {
  400. is_sync = BOOL_TRUE; // Simulate sync action
  401. exitstatus = 0; // Exit status while dry-run is always 0
  402. } else { // Normal execution
  403. is_sync = kaction_is_sync(action);
  404. exec_action(context, action, &new_pid, &exitstatus);
  405. }
  406. // SYNC: Compute new value for retcode.
  407. // Sync actions return retcode immediatelly. Their forked
  408. // processes are for output handling only.
  409. if (is_sync && kaction_update_retcode(action))
  410. kcontext_set_retcode(context, exitstatus);
  411. } while (-1 == new_pid); // PID is not -1 when new process was forked
  412. // Save PID of newly created process
  413. kcontext_set_pid(context, new_pid);
  414. return BOOL_TRUE;
  415. }
  416. bool_t kexec_continue_command_execution(kexec_t *exec, pid_t pid, int wstatus)
  417. {
  418. faux_list_node_t *iter = NULL;
  419. kcontext_t *context = NULL;
  420. assert(exec);
  421. if (!exec)
  422. return BOOL_FALSE;
  423. iter = kexec_contexts_iter(exec);
  424. while ((context = kexec_contexts_each(&iter))) {
  425. bool_t found = BOOL_FALSE;
  426. found = exec_action_sequence(exec, context, pid, wstatus);
  427. if (found && (pid != -1))
  428. break;
  429. }
  430. return BOOL_TRUE;
  431. }
  432. bool_t kexec_exec(kexec_t *exec)
  433. {
  434. assert(exec);
  435. if (!exec)
  436. return BOOL_FALSE;
  437. // Firsly prepare kexec object for execution. The file streams must
  438. // be created for stdin, stdout, stderr of processes.
  439. if (!kexec_prepare(exec))
  440. return BOOL_FALSE;
  441. // Here no ACTIONs are executing, so pass -1 as pid of terminated
  442. // ACTION's process.
  443. kexec_continue_command_execution(exec, -1, 0);
  444. return BOOL_TRUE;
  445. }