You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2310 lines
80 KiB

  1. /* main.c - boot messages monitor
  2. *
  3. * Copyright (C) 2007 Red Hat, Inc
  4. *
  5. * This file is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published
  7. * by the Free Software Foundation; either version 2 of the License,
  8. * or (at your option) any later version.
  9. *
  10. * This file is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this; see the file COPYING. If not, write to the Free
  17. * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  18. * 02111-1307, USA.
  19. *
  20. * Written by: Ray Strode <rstrode@redhat.com>
  21. */
  22. #include "config.h"
  23. #include <sys/stat.h>
  24. #include <sys/types.h>
  25. #include <math.h>
  26. #include <limits.h>
  27. #include <dirent.h>
  28. #include <fcntl.h>
  29. #include <stdlib.h>
  30. #include <stdio.h>
  31. #include <sysexits.h>
  32. #include <sys/ioctl.h>
  33. #include <unistd.h>
  34. #include <wchar.h>
  35. #include <paths.h>
  36. #include <assert.h>
  37. #include <values.h>
  38. #include <locale.h>
  39. #include <linux/kd.h>
  40. #include <linux/vt.h>
  41. #include "ply-buffer.h"
  42. #include "ply-command-parser.h"
  43. #include "ply-boot-server.h"
  44. #include "ply-boot-splash.h"
  45. #include "ply-device-manager.h"
  46. #include "ply-event-loop.h"
  47. #include "ply-hashtable.h"
  48. #include "ply-list.h"
  49. #include "ply-logger.h"
  50. #include "ply-renderer.h"
  51. #include "ply-terminal-session.h"
  52. #include "ply-trigger.h"
  53. #include "ply-utils.h"
  54. #include "ply-progress.h"
  55. #define BOOT_DURATION_FILE PLYMOUTH_TIME_DIRECTORY "/boot-duration"
  56. #define SHUTDOWN_DURATION_FILE PLYMOUTH_TIME_DIRECTORY "/shutdown-duration"
  57. typedef struct
  58. {
  59. const char *keys;
  60. ply_trigger_t *trigger;
  61. } ply_keystroke_watch_t;
  62. typedef struct
  63. {
  64. enum { PLY_ENTRY_TRIGGER_TYPE_PASSWORD,
  65. PLY_ENTRY_TRIGGER_TYPE_QUESTION }
  66. type;
  67. const char *prompt;
  68. ply_trigger_t *trigger;
  69. } ply_entry_trigger_t;
  70. typedef struct
  71. {
  72. ply_event_loop_t *loop;
  73. ply_boot_server_t *boot_server;
  74. ply_boot_splash_t *boot_splash;
  75. ply_terminal_session_t *session;
  76. ply_buffer_t *boot_buffer;
  77. ply_progress_t *progress;
  78. ply_list_t *keystroke_triggers;
  79. ply_list_t *entry_triggers;
  80. ply_buffer_t *entry_buffer;
  81. ply_list_t *messages;
  82. ply_command_parser_t *command_parser;
  83. ply_boot_splash_mode_t mode;
  84. ply_terminal_t *local_console_terminal;
  85. ply_device_manager_t *device_manager;
  86. ply_trigger_t *deactivate_trigger;
  87. ply_trigger_t *quit_trigger;
  88. double start_time;
  89. double splash_delay;
  90. double device_timeout;
  91. uint32_t no_boot_log : 1;
  92. uint32_t showing_details : 1;
  93. uint32_t system_initialized : 1;
  94. uint32_t is_redirected : 1;
  95. uint32_t is_attached : 1;
  96. uint32_t should_be_attached : 1;
  97. uint32_t should_retain_splash : 1;
  98. uint32_t is_inactive : 1;
  99. uint32_t is_shown : 1;
  100. uint32_t should_force_details : 1;
  101. uint32_t splash_is_becoming_idle : 1;
  102. char *override_splash_path;
  103. char *system_default_splash_path;
  104. char *distribution_default_splash_path;
  105. const char *default_tty;
  106. int number_of_errors;
  107. } state_t;
  108. static void show_splash (state_t *state);
  109. static ply_boot_splash_t *load_built_in_theme (state_t *state);
  110. static ply_boot_splash_t *load_theme (state_t *state,
  111. const char *theme_path);
  112. static ply_boot_splash_t *show_theme (state_t *state,
  113. const char *theme_path);
  114. static void attach_splash_to_devices (state_t *state,
  115. ply_boot_splash_t *splash);
  116. static bool attach_to_running_session (state_t *state);
  117. static void detach_from_running_session (state_t *state);
  118. static void on_escape_pressed (state_t *state);
  119. static void dump_details_and_quit_splash (state_t *state);
  120. static void update_display (state_t *state);
  121. static void on_error_message (ply_buffer_t *debug_buffer,
  122. const void *bytes,
  123. size_t number_of_bytes);
  124. static ply_buffer_t *debug_buffer;
  125. static char *debug_buffer_path = NULL;
  126. static char *pid_file = NULL;
  127. static void toggle_between_splash_and_details (state_t *state);
  128. #ifdef PLY_ENABLE_SYSTEMD_INTEGRATION
  129. static void tell_systemd_to_print_details (state_t *state);
  130. static void tell_systemd_to_stop_printing_details (state_t *state);
  131. #endif
  132. static const char *get_cache_file_for_mode (ply_boot_splash_mode_t mode);
  133. static void on_escape_pressed (state_t *state);
  134. static void on_enter (state_t *state,
  135. const char *line);
  136. static void on_keyboard_input (state_t *state,
  137. const char *keyboard_input,
  138. size_t character_size);
  139. static void on_backspace (state_t *state);
  140. static void on_quit (state_t *state,
  141. bool retain_splash,
  142. ply_trigger_t *quit_trigger);
  143. static bool sh_is_init (state_t *state);
  144. static void cancel_pending_delayed_show (state_t *state);
  145. static void prepare_logging (state_t *state);
  146. static void
  147. on_session_output (state_t *state,
  148. const char *output,
  149. size_t size)
  150. {
  151. ply_buffer_append_bytes (state->boot_buffer, output, size);
  152. if (state->boot_splash != NULL)
  153. ply_boot_splash_update_output (state->boot_splash,
  154. output, size);
  155. }
  156. static void
  157. on_session_hangup (state_t *state)
  158. {
  159. ply_trace ("got hang up on terminal session fd");
  160. }
  161. static void
  162. on_update (state_t *state,
  163. const char *status)
  164. {
  165. ply_trace ("updating status to '%s'", status);
  166. ply_progress_status_update (state->progress,
  167. status);
  168. if (state->boot_splash != NULL)
  169. ply_boot_splash_update_status (state->boot_splash,
  170. status);
  171. }
  172. static void
  173. on_change_mode (state_t *state,
  174. const char *mode)
  175. {
  176. ply_trace ("updating mode to '%s'", mode);
  177. if (strcmp (mode, "boot-up") == 0)
  178. state->mode = PLY_BOOT_SPLASH_MODE_BOOT_UP;
  179. else if (strcmp (mode, "shutdown") == 0)
  180. state->mode = PLY_BOOT_SPLASH_MODE_SHUTDOWN;
  181. else if (strcmp (mode, "reboot") == 0)
  182. state->mode = PLY_BOOT_SPLASH_MODE_REBOOT;
  183. else if (strcmp (mode, "updates") == 0)
  184. state->mode = PLY_BOOT_SPLASH_MODE_UPDATES;
  185. else if (strcmp (mode, "system-upgrade") == 0)
  186. state->mode = PLY_BOOT_SPLASH_MODE_SYSTEM_UPGRADE;
  187. else if (strcmp (mode, "firmware-upgrade") == 0)
  188. state->mode = PLY_BOOT_SPLASH_MODE_FIRMWARE_UPGRADE;
  189. else
  190. return;
  191. if (state->session != NULL) {
  192. prepare_logging (state);
  193. }
  194. if (state->boot_splash == NULL) {
  195. ply_trace ("no splash set");
  196. return;
  197. }
  198. if (!ply_boot_splash_show (state->boot_splash, state->mode)) {
  199. ply_trace ("failed to update splash");
  200. return;
  201. }
  202. }
  203. static void
  204. on_system_update (state_t *state,
  205. int progress)
  206. {
  207. if (state->boot_splash == NULL) {
  208. ply_trace ("no splash set");
  209. return;
  210. }
  211. ply_trace ("setting system update to '%i'", progress);
  212. if (!ply_boot_splash_system_update (state->boot_splash, progress)) {
  213. ply_trace ("failed to update splash");
  214. return;
  215. }
  216. }
  217. static void
  218. show_messages (state_t *state)
  219. {
  220. if (state->boot_splash == NULL) {
  221. ply_trace ("not displaying messages, since no boot splash");
  222. return;
  223. }
  224. ply_list_node_t *node = ply_list_get_first_node (state->messages);
  225. while (node != NULL) {
  226. ply_list_node_t *next_node;
  227. char *message = ply_list_node_get_data (node);
  228. ply_trace ("displaying messages");
  229. ply_boot_splash_display_message (state->boot_splash, message);
  230. next_node = ply_list_get_next_node (state->messages, node);
  231. node = next_node;
  232. }
  233. }
  234. static bool
  235. load_settings (state_t *state,
  236. const char *path,
  237. char **theme_path)
  238. {
  239. ply_key_file_t *key_file = NULL;
  240. bool settings_loaded = false;
  241. char *scale_string = NULL;
  242. char *splash_string = NULL;
  243. ply_trace ("Trying to load %s", path);
  244. key_file = ply_key_file_new (path);
  245. if (!ply_key_file_load (key_file))
  246. goto out;
  247. splash_string = ply_key_file_get_value (key_file, "Daemon", "Theme");
  248. if (splash_string != NULL) {
  249. asprintf (theme_path,
  250. PLYMOUTH_RUNTIME_THEME_PATH "%s/%s.plymouth",
  251. splash_string, splash_string);
  252. ply_trace ("Checking if %s exists", *theme_path);
  253. if (!ply_file_exists (*theme_path)) {
  254. ply_trace ("%s not found, fallbacking to " PLYMOUTH_THEME_PATH,
  255. *theme_path);
  256. asprintf (theme_path,
  257. PLYMOUTH_THEME_PATH "%s/%s.plymouth",
  258. splash_string, splash_string);
  259. }
  260. }
  261. if (isnan (state->splash_delay)) {
  262. char *delay_string;
  263. delay_string = ply_key_file_get_value (key_file, "Daemon", "ShowDelay");
  264. if (delay_string != NULL) {
  265. state->splash_delay = atof (delay_string);
  266. ply_trace ("Splash delay is set to %lf", state->splash_delay);
  267. free (delay_string);
  268. }
  269. }
  270. if (isnan (state->device_timeout)) {
  271. char *timeout_string;
  272. timeout_string = ply_key_file_get_value (key_file, "Daemon", "DeviceTimeout");
  273. if (timeout_string != NULL) {
  274. state->device_timeout = atof (timeout_string);
  275. ply_trace ("Device timeout is set to %lf", state->device_timeout);
  276. free (timeout_string);
  277. }
  278. }
  279. scale_string = ply_key_file_get_value (key_file, "Daemon", "DeviceScale");
  280. if (scale_string != NULL) {
  281. ply_set_device_scale (strtoul (scale_string, NULL, 0));
  282. free (scale_string);
  283. }
  284. settings_loaded = true;
  285. out:
  286. free (splash_string);
  287. ply_key_file_free (key_file);
  288. return settings_loaded;
  289. }
  290. static void
  291. show_detailed_splash (state_t *state)
  292. {
  293. ply_boot_splash_t *splash;
  294. cancel_pending_delayed_show (state);
  295. if (state->boot_splash != NULL)
  296. return;
  297. ply_trace ("Showing detailed splash screen");
  298. splash = show_theme (state, NULL);
  299. if (splash == NULL) {
  300. ply_trace ("Could not start detailed splash screen, this could be a problem.");
  301. return;
  302. }
  303. state->boot_splash = splash;
  304. show_messages (state);
  305. update_display (state);
  306. }
  307. static void
  308. find_override_splash (state_t *state)
  309. {
  310. char *splash_string;
  311. if (state->override_splash_path != NULL)
  312. return;
  313. splash_string = ply_kernel_command_line_get_key_value ("plymouth.splash=");
  314. if (splash_string != NULL) {
  315. ply_trace ("Splash is configured to be '%s'", splash_string);
  316. asprintf (&state->override_splash_path,
  317. PLYMOUTH_RUNTIME_THEME_PATH "%s/%s.plymouth",
  318. splash_string, splash_string);
  319. ply_trace ("Checking if %s exists", state->override_splash_path);
  320. if (!ply_file_exists (state->override_splash_path)) {
  321. ply_trace ("%s not found, fallbacking to " PLYMOUTH_THEME_PATH,
  322. state->override_splash_path);
  323. free (state->override_splash_path);
  324. asprintf (&state->override_splash_path,
  325. PLYMOUTH_THEME_PATH "%s/%s.plymouth",
  326. splash_string, splash_string);
  327. }
  328. free (splash_string);
  329. }
  330. if (isnan (state->splash_delay)) {
  331. const char *delay_string;
  332. delay_string = ply_kernel_command_line_get_string_after_prefix ("plymouth.splash-delay=");
  333. if (delay_string != NULL)
  334. state->splash_delay = atof (delay_string);
  335. }
  336. }
  337. static void
  338. find_force_scale (state_t *state)
  339. {
  340. const char *scale_string;
  341. scale_string = ply_kernel_command_line_get_string_after_prefix ("plymouth.force-scale=");
  342. if (scale_string != NULL)
  343. ply_set_device_scale (strtoul (scale_string, NULL, 0));
  344. }
  345. static void
  346. find_system_default_splash (state_t *state)
  347. {
  348. if (state->system_default_splash_path != NULL)
  349. return;
  350. if (!load_settings (state, PLYMOUTH_CONF_DIR "plymouthd.conf", &state->system_default_splash_path)) {
  351. ply_trace ("failed to load " PLYMOUTH_CONF_DIR "plymouthd.conf");
  352. return;
  353. }
  354. ply_trace ("System configured theme file is '%s'", state->system_default_splash_path);
  355. }
  356. static void
  357. find_distribution_default_splash (state_t *state)
  358. {
  359. if (state->distribution_default_splash_path != NULL)
  360. return;
  361. if (!load_settings (state, PLYMOUTH_RUNTIME_DIR "/plymouthd.defaults", &state->distribution_default_splash_path)) {
  362. ply_trace ("failed to load " PLYMOUTH_RUNTIME_DIR "/plymouthd.defaults, trying " PLYMOUTH_POLICY_DIR);
  363. if (!load_settings (state, PLYMOUTH_POLICY_DIR "plymouthd.defaults", &state->distribution_default_splash_path)) {
  364. ply_trace ("failed to load " PLYMOUTH_POLICY_DIR "plymouthd.defaults");
  365. return;
  366. }
  367. }
  368. ply_trace ("Distribution default theme file is '%s'", state->distribution_default_splash_path);
  369. }
  370. static void
  371. show_default_splash (state_t *state)
  372. {
  373. if (state->boot_splash != NULL)
  374. return;
  375. ply_trace ("Showing splash screen");
  376. if (state->override_splash_path != NULL) {
  377. ply_trace ("Trying override splash at '%s'", state->override_splash_path);
  378. state->boot_splash = show_theme (state, state->override_splash_path);
  379. }
  380. if (state->boot_splash == NULL &&
  381. state->system_default_splash_path != NULL) {
  382. ply_trace ("Trying system default splash");
  383. state->boot_splash = show_theme (state, state->system_default_splash_path);
  384. }
  385. if (state->boot_splash == NULL &&
  386. state->distribution_default_splash_path != NULL) {
  387. ply_trace ("Trying distribution default splash");
  388. state->boot_splash = show_theme (state, state->distribution_default_splash_path);
  389. }
  390. if (state->boot_splash == NULL) {
  391. ply_trace ("Trying old scheme for default splash");
  392. state->boot_splash = show_theme (state, PLYMOUTH_THEME_PATH "default.plymouth");
  393. }
  394. if (state->boot_splash == NULL) {
  395. ply_trace ("Could not start default splash screen,"
  396. "showing text splash screen");
  397. state->boot_splash = show_theme (state, PLYMOUTH_THEME_PATH "text/text.plymouth");
  398. }
  399. if (state->boot_splash == NULL) {
  400. ply_trace ("Could not start text splash screen,"
  401. "showing built-in splash screen");
  402. state->boot_splash = show_theme (state, NULL);
  403. }
  404. if (state->boot_splash == NULL) {
  405. ply_error ("plymouthd: could not start boot splash: %m");
  406. return;
  407. }
  408. show_messages (state);
  409. update_display (state);
  410. }
  411. static void
  412. cancel_pending_delayed_show (state_t *state)
  413. {
  414. if (isnan (state->splash_delay))
  415. return;
  416. ply_event_loop_stop_watching_for_timeout (state->loop,
  417. (ply_event_loop_timeout_handler_t)
  418. show_splash,
  419. state);
  420. state->splash_delay = NAN;
  421. }
  422. static void
  423. on_ask_for_password (state_t *state,
  424. const char *prompt,
  425. ply_trigger_t *answer)
  426. {
  427. ply_entry_trigger_t *entry_trigger;
  428. if (state->boot_splash == NULL) {
  429. /* Waiting to be shown, boot splash will
  430. * arrive shortly so just sit tight
  431. */
  432. if (state->is_shown) {
  433. bool has_displays;
  434. cancel_pending_delayed_show (state);
  435. has_displays = ply_device_manager_has_displays (state->device_manager);
  436. if (has_displays) {
  437. ply_trace ("displays available now, showing splash immediately");
  438. show_splash (state);
  439. } else {
  440. ply_trace ("splash still coming up, waiting a bit");
  441. }
  442. } else {
  443. /* No splash, client will have to get password */
  444. ply_trace ("no splash loaded, replying immediately with no password");
  445. ply_trigger_pull (answer, NULL);
  446. return;
  447. }
  448. }
  449. entry_trigger = calloc (1, sizeof(ply_entry_trigger_t));
  450. entry_trigger->type = PLY_ENTRY_TRIGGER_TYPE_PASSWORD;
  451. entry_trigger->prompt = prompt;
  452. entry_trigger->trigger = answer;
  453. ply_trace ("queuing password request with boot splash");
  454. ply_list_append_data (state->entry_triggers, entry_trigger);
  455. update_display (state);
  456. }
  457. static void
  458. on_ask_question (state_t *state,
  459. const char *prompt,
  460. ply_trigger_t *answer)
  461. {
  462. ply_entry_trigger_t *entry_trigger;
  463. entry_trigger = calloc (1, sizeof(ply_entry_trigger_t));
  464. entry_trigger->type = PLY_ENTRY_TRIGGER_TYPE_QUESTION;
  465. entry_trigger->prompt = prompt;
  466. entry_trigger->trigger = answer;
  467. ply_trace ("queuing question with boot splash");
  468. ply_list_append_data (state->entry_triggers, entry_trigger);
  469. update_display (state);
  470. }
  471. static void
  472. on_display_message (state_t *state,
  473. const char *message)
  474. {
  475. if (state->boot_splash != NULL) {
  476. ply_trace ("displaying message %s", message);
  477. ply_boot_splash_display_message (state->boot_splash, message);
  478. } else {
  479. ply_trace ("not displaying message %s as no splash", message);
  480. }
  481. ply_list_append_data (state->messages, strdup (message));
  482. }
  483. static void
  484. on_hide_message (state_t *state,
  485. const char *message)
  486. {
  487. ply_list_node_t *node;
  488. ply_trace ("hiding message %s", message);
  489. node = ply_list_get_first_node (state->messages);
  490. while (node != NULL) {
  491. ply_list_node_t *next_node;
  492. char *list_message;
  493. list_message = ply_list_node_get_data (node);
  494. next_node = ply_list_get_next_node (state->messages, node);
  495. if (strcmp (list_message, message) == 0) {
  496. free (list_message);
  497. ply_list_remove_node (state->messages, node);
  498. ply_boot_splash_hide_message (state->boot_splash, message);
  499. }
  500. node = next_node;
  501. }
  502. }
  503. static void
  504. on_watch_for_keystroke (state_t *state,
  505. const char *keys,
  506. ply_trigger_t *trigger)
  507. {
  508. ply_keystroke_watch_t *keystroke_trigger =
  509. calloc (1, sizeof(ply_keystroke_watch_t));
  510. ply_trace ("watching for keystroke");
  511. keystroke_trigger->keys = keys;
  512. keystroke_trigger->trigger = trigger;
  513. ply_list_append_data (state->keystroke_triggers, keystroke_trigger);
  514. }
  515. static void
  516. on_ignore_keystroke (state_t *state,
  517. const char *keys)
  518. {
  519. ply_list_node_t *node;
  520. ply_trace ("ignoring for keystroke");
  521. for (node = ply_list_get_first_node (state->keystroke_triggers); node;
  522. node = ply_list_get_next_node (state->keystroke_triggers, node)) {
  523. ply_keystroke_watch_t *keystroke_trigger = ply_list_node_get_data (node);
  524. if ((!keystroke_trigger->keys && !keys) ||
  525. (keystroke_trigger->keys && keys && strcmp (keystroke_trigger->keys, keys) == 0)) {
  526. ply_trigger_pull (keystroke_trigger->trigger, NULL);
  527. ply_list_remove_node (state->keystroke_triggers, node);
  528. return;
  529. }
  530. }
  531. }
  532. static void
  533. on_progress_pause (state_t *state)
  534. {
  535. ply_trace ("pausing progress");
  536. ply_progress_pause (state->progress);
  537. }
  538. static void
  539. on_progress_unpause (state_t *state)
  540. {
  541. ply_trace ("unpausing progress");
  542. ply_progress_unpause (state->progress);
  543. }
  544. static void
  545. on_newroot (state_t *state,
  546. const char *root_dir)
  547. {
  548. if (sh_is_init (state)) {
  549. ply_trace ("new root mounted at \"%s\", exiting since init= a shell", root_dir);
  550. on_quit (state, false, ply_trigger_new (NULL));
  551. return;
  552. }
  553. ply_trace ("new root mounted at \"%s\", switching to it", root_dir);
  554. chdir (root_dir);
  555. chroot (".");
  556. chdir ("/");
  557. /* Update local now that we have /usr/share/locale available */
  558. setlocale(LC_ALL, "");
  559. ply_progress_load_cache (state->progress, get_cache_file_for_mode (state->mode));
  560. if (state->boot_splash != NULL)
  561. ply_boot_splash_root_mounted (state->boot_splash);
  562. }
  563. static const char *
  564. get_cache_file_for_mode (ply_boot_splash_mode_t mode)
  565. {
  566. const char *filename;
  567. switch (mode) {
  568. case PLY_BOOT_SPLASH_MODE_BOOT_UP:
  569. filename = BOOT_DURATION_FILE;
  570. break;
  571. case PLY_BOOT_SPLASH_MODE_SHUTDOWN:
  572. case PLY_BOOT_SPLASH_MODE_REBOOT:
  573. filename = SHUTDOWN_DURATION_FILE;
  574. break;
  575. case PLY_BOOT_SPLASH_MODE_UPDATES:
  576. case PLY_BOOT_SPLASH_MODE_SYSTEM_UPGRADE:
  577. case PLY_BOOT_SPLASH_MODE_FIRMWARE_UPGRADE:
  578. filename = NULL;
  579. break;
  580. case PLY_BOOT_SPLASH_MODE_INVALID:
  581. default:
  582. ply_error ("Unhandled case in %s line %d\n", __FILE__, __LINE__);
  583. abort ();
  584. break;
  585. }
  586. ply_trace ("returning cache file '%s'", filename);
  587. return filename;
  588. }
  589. static const char *
  590. get_log_file_for_state (state_t *state)
  591. {
  592. const char *filename;
  593. switch (state->mode) {
  594. case PLY_BOOT_SPLASH_MODE_BOOT_UP:
  595. if (state->no_boot_log)
  596. filename = NULL;
  597. else
  598. filename = PLYMOUTH_LOG_DIRECTORY "/boot.log";
  599. break;
  600. case PLY_BOOT_SPLASH_MODE_SHUTDOWN:
  601. case PLY_BOOT_SPLASH_MODE_REBOOT:
  602. case PLY_BOOT_SPLASH_MODE_UPDATES:
  603. case PLY_BOOT_SPLASH_MODE_SYSTEM_UPGRADE:
  604. case PLY_BOOT_SPLASH_MODE_FIRMWARE_UPGRADE:
  605. filename = _PATH_DEVNULL;
  606. break;
  607. case PLY_BOOT_SPLASH_MODE_INVALID:
  608. default:
  609. ply_error ("Unhandled case in %s line %d\n", __FILE__, __LINE__);
  610. abort ();
  611. break;
  612. }
  613. ply_trace ("returning log file '%s'", filename);
  614. return filename;
  615. }
  616. static const char *
  617. get_log_spool_file_for_mode (ply_boot_splash_mode_t mode)
  618. {
  619. const char *filename;
  620. switch (mode) {
  621. case PLY_BOOT_SPLASH_MODE_BOOT_UP:
  622. filename = PLYMOUTH_SPOOL_DIRECTORY "/boot.log";
  623. break;
  624. case PLY_BOOT_SPLASH_MODE_SHUTDOWN:
  625. case PLY_BOOT_SPLASH_MODE_REBOOT:
  626. case PLY_BOOT_SPLASH_MODE_UPDATES:
  627. case PLY_BOOT_SPLASH_MODE_SYSTEM_UPGRADE:
  628. case PLY_BOOT_SPLASH_MODE_FIRMWARE_UPGRADE:
  629. filename = NULL;
  630. break;
  631. case PLY_BOOT_SPLASH_MODE_INVALID:
  632. default:
  633. ply_error ("Unhandled case in %s line %d\n", __FILE__, __LINE__);
  634. abort ();
  635. break;
  636. }
  637. ply_trace ("returning spool file '%s'", filename);
  638. return filename;
  639. }
  640. static void
  641. spool_error (state_t *state)
  642. {
  643. const char *logfile;
  644. const char *logspool;
  645. ply_trace ("spooling error for viewer");
  646. logfile = get_log_file_for_state (state);
  647. logspool = get_log_spool_file_for_mode (state->mode);
  648. if (logfile != NULL && logspool != NULL) {
  649. unlink (logspool);
  650. ply_create_file_link (logfile, logspool);
  651. }
  652. }
  653. static void
  654. prepare_logging (state_t *state)
  655. {
  656. const char *logfile;
  657. if (!state->system_initialized) {
  658. ply_trace ("not preparing logging yet, system not initialized");
  659. return;
  660. }
  661. if (state->session == NULL) {
  662. ply_trace ("not preparing logging, no session");
  663. return;
  664. }
  665. ply_terminal_session_close_log (state->session);
  666. logfile = get_log_file_for_state (state);
  667. if (logfile != NULL) {
  668. bool log_opened;
  669. ply_trace ("opening log '%s'", logfile);
  670. log_opened = ply_terminal_session_open_log (state->session, logfile);
  671. if (!log_opened)
  672. ply_trace ("failed to open log: %m");
  673. if (state->number_of_errors > 0)
  674. spool_error (state);
  675. }
  676. }
  677. static void
  678. on_system_initialized (state_t *state)
  679. {
  680. ply_trace ("system now initialized, opening log");
  681. state->system_initialized = true;
  682. #ifdef PLY_ENABLE_SYSTEMD_INTEGRATION
  683. if (state->is_attached)
  684. tell_systemd_to_print_details (state);
  685. #endif
  686. prepare_logging (state);
  687. }
  688. static void
  689. on_error (state_t *state)
  690. {
  691. ply_trace ("encountered error during boot up");
  692. if (state->system_initialized && state->number_of_errors == 0)
  693. spool_error (state);
  694. else
  695. ply_trace ("not spooling because number of errors %d", state->number_of_errors);
  696. state->number_of_errors++;
  697. }
  698. static bool
  699. plymouth_should_ignore_show_splash_calls (state_t *state)
  700. {
  701. ply_trace ("checking if plymouth should be running");
  702. if (state->mode != PLY_BOOT_SPLASH_MODE_BOOT_UP || ply_kernel_command_line_has_argument ("plymouth.force-splash"))
  703. return false;
  704. if (ply_kernel_command_line_has_argument ("plymouth.ignore-show-splash"))
  705. return true;
  706. return false;
  707. }
  708. static bool
  709. sh_is_init (state_t *state)
  710. {
  711. char *init_string = ply_kernel_command_line_get_key_value ("init=");
  712. bool result = false;
  713. size_t length;
  714. if (init_string) {
  715. length = strlen (init_string);
  716. if (length > 2 && init_string[length - 2] == 's' &&
  717. init_string[length - 1] == 'h')
  718. result = true;
  719. free (init_string);
  720. }
  721. return result;
  722. }
  723. static bool
  724. plymouth_should_show_default_splash (state_t *state)
  725. {
  726. ply_trace ("checking if plymouth should show default splash");
  727. const char * const strings[] = {
  728. "single", "1", "s", "S", "-S", NULL
  729. };
  730. int i;
  731. if (state->should_force_details)
  732. return false;
  733. for (i = 0; strings[i] != NULL; i++) {
  734. if (ply_kernel_command_line_has_argument (strings[i])) {
  735. ply_trace ("no default splash because kernel command line has option \"%s\"", strings[i]);
  736. return false;
  737. }
  738. }
  739. if (ply_kernel_command_line_has_argument ("splash=verbose")) {
  740. ply_trace ("no default splash because kernel command line has option \"splash=verbose\"");
  741. return false;
  742. }
  743. if (ply_kernel_command_line_has_argument ("rhgb")) {
  744. ply_trace ("using default splash because kernel command line has option \"rhgb\"");
  745. return true;
  746. }
  747. if (ply_kernel_command_line_has_argument ("splash")) {
  748. ply_trace ("using default splash because kernel command line has option \"splash\"");
  749. return true;
  750. }
  751. if (ply_kernel_command_line_has_argument ("splash=silent")) {
  752. ply_trace ("using default splash because kernel command line has option \"splash=silent\"");
  753. return true;
  754. }
  755. ply_trace ("no default splash because kernel command line lacks \"splash\" or \"rhgb\"");
  756. return false;
  757. }
  758. static void
  759. on_show_splash (state_t *state)
  760. {
  761. bool has_displays;
  762. if (state->is_shown) {
  763. ply_trace ("show splash called while already shown");
  764. return;
  765. }
  766. if (state->is_inactive) {
  767. ply_trace ("show splash called while inactive");
  768. return;
  769. }
  770. if (plymouth_should_ignore_show_splash_calls (state)) {
  771. ply_trace ("show splash called while ignoring show splash calls");
  772. dump_details_and_quit_splash (state);
  773. return;
  774. }
  775. state->is_shown = true;
  776. has_displays = ply_device_manager_has_displays (state->device_manager);
  777. if (!state->is_attached && state->should_be_attached && has_displays)
  778. attach_to_running_session (state);
  779. if (has_displays) {
  780. ply_trace ("at least one display already available, so loading splash");
  781. show_splash (state);
  782. } else {
  783. ply_trace ("no displays available to show splash on, waiting...");
  784. }
  785. }
  786. static void
  787. show_splash (state_t *state)
  788. {
  789. if (state->boot_splash != NULL)
  790. return;
  791. if (!isnan (state->splash_delay)) {
  792. double now, running_time;
  793. now = ply_get_timestamp ();
  794. running_time = now - state->start_time;
  795. if (state->splash_delay > running_time) {
  796. double time_left = state->splash_delay - running_time;
  797. ply_trace ("delaying show splash for %lf seconds",
  798. time_left);
  799. ply_event_loop_stop_watching_for_timeout (state->loop,
  800. (ply_event_loop_timeout_handler_t)
  801. show_splash,
  802. state);
  803. ply_event_loop_watch_for_timeout (state->loop,
  804. time_left,
  805. (ply_event_loop_timeout_handler_t)
  806. show_splash,
  807. state);
  808. /* Listen for ESC to show details */
  809. ply_device_manager_activate_keyboards (state->device_manager);
  810. return;
  811. }
  812. }
  813. if (plymouth_should_show_default_splash (state)) {
  814. show_default_splash (state);
  815. state->showing_details = false;
  816. } else {
  817. show_detailed_splash (state);
  818. state->showing_details = true;
  819. }
  820. }
  821. static void
  822. on_keyboard_added (state_t *state,
  823. ply_keyboard_t *keyboard)
  824. {
  825. ply_trace ("listening for keystrokes");
  826. ply_keyboard_add_input_handler (keyboard,
  827. (ply_keyboard_input_handler_t)
  828. on_keyboard_input, state);
  829. ply_trace ("listening for escape");
  830. ply_keyboard_add_escape_handler (keyboard,
  831. (ply_keyboard_escape_handler_t)
  832. on_escape_pressed, state);
  833. ply_trace ("listening for backspace");
  834. ply_keyboard_add_backspace_handler (keyboard,
  835. (ply_keyboard_backspace_handler_t)
  836. on_backspace, state);
  837. ply_trace ("listening for enter");
  838. ply_keyboard_add_enter_handler (keyboard,
  839. (ply_keyboard_enter_handler_t)
  840. on_enter, state);
  841. if (state->boot_splash != NULL) {
  842. ply_trace ("keyboard set after splash loaded, so attaching to splash");
  843. ply_boot_splash_set_keyboard (state->boot_splash, keyboard);
  844. }
  845. }
  846. static void
  847. on_keyboard_removed (state_t *state,
  848. ply_keyboard_t *keyboard)
  849. {
  850. ply_trace ("no longer listening for keystrokes");
  851. ply_keyboard_remove_input_handler (keyboard,
  852. (ply_keyboard_input_handler_t)
  853. on_keyboard_input);
  854. ply_trace ("no longer listening for escape");
  855. ply_keyboard_remove_escape_handler (keyboard,
  856. (ply_keyboard_escape_handler_t)
  857. on_escape_pressed);
  858. ply_trace ("no longer listening for backspace");
  859. ply_keyboard_remove_backspace_handler (keyboard,
  860. (ply_keyboard_backspace_handler_t)
  861. on_backspace);
  862. ply_trace ("no longer listening for enter");
  863. ply_keyboard_remove_enter_handler (keyboard,
  864. (ply_keyboard_enter_handler_t)
  865. on_enter);
  866. if (state->boot_splash != NULL)
  867. ply_boot_splash_unset_keyboard (state->boot_splash);
  868. }
  869. static void
  870. on_pixel_display_added (state_t *state,
  871. ply_pixel_display_t *display)
  872. {
  873. if (state->is_shown) {
  874. if (state->boot_splash == NULL) {
  875. ply_trace ("pixel display added before splash loaded, so loading splash now");
  876. show_splash (state);
  877. } else {
  878. ply_trace ("pixel display added after splash loaded, so attaching to splash");
  879. ply_boot_splash_add_pixel_display (state->boot_splash, display);
  880. update_display (state);
  881. }
  882. }
  883. }
  884. static void
  885. on_pixel_display_removed (state_t *state,
  886. ply_pixel_display_t *display)
  887. {
  888. if (state->boot_splash == NULL)
  889. return;
  890. ply_boot_splash_remove_pixel_display (state->boot_splash, display);
  891. }
  892. static void
  893. on_text_display_added (state_t *state,
  894. ply_text_display_t *display)
  895. {
  896. if (state->is_shown) {
  897. if (state->boot_splash == NULL) {
  898. ply_trace ("text display added before splash loaded, so loading splash now");
  899. show_splash (state);
  900. } else {
  901. ply_trace ("text display added after splash loaded, so attaching to splash");
  902. ply_boot_splash_add_text_display (state->boot_splash, display);
  903. update_display (state);
  904. }
  905. }
  906. }
  907. static void
  908. on_text_display_removed (state_t *state,
  909. ply_text_display_t *display)
  910. {
  911. if (state->boot_splash == NULL)
  912. return;
  913. ply_boot_splash_remove_text_display (state->boot_splash, display);
  914. }
  915. static void
  916. load_devices (state_t *state,
  917. ply_device_manager_flags_t flags)
  918. {
  919. state->device_manager = ply_device_manager_new (state->default_tty, flags);
  920. state->local_console_terminal = ply_device_manager_get_default_terminal (state->device_manager);
  921. ply_device_manager_watch_devices (state->device_manager,
  922. state->device_timeout,
  923. (ply_keyboard_added_handler_t)
  924. on_keyboard_added,
  925. (ply_keyboard_removed_handler_t)
  926. on_keyboard_removed,
  927. (ply_pixel_display_added_handler_t)
  928. on_pixel_display_added,
  929. (ply_pixel_display_removed_handler_t)
  930. on_pixel_display_removed,
  931. (ply_text_display_added_handler_t)
  932. on_text_display_added,
  933. (ply_text_display_removed_handler_t)
  934. on_text_display_removed,
  935. state);
  936. if (ply_device_manager_has_serial_consoles (state->device_manager)) {
  937. state->should_force_details = true;
  938. }
  939. }
  940. static void
  941. quit_splash (state_t *state)
  942. {
  943. ply_trace ("quitting splash");
  944. if (state->boot_splash != NULL) {
  945. ply_trace ("freeing splash");
  946. ply_boot_splash_free (state->boot_splash);
  947. state->boot_splash = NULL;
  948. }
  949. ply_device_manager_deactivate_keyboards (state->device_manager);
  950. if (state->local_console_terminal != NULL) {
  951. if (!state->should_retain_splash) {
  952. ply_trace ("Not retaining splash, so deallocating VT");
  953. ply_terminal_deactivate_vt (state->local_console_terminal);
  954. ply_terminal_close (state->local_console_terminal);
  955. }
  956. }
  957. detach_from_running_session (state);
  958. }
  959. static void
  960. hide_splash (state_t *state)
  961. {
  962. if (state->boot_splash && ply_boot_splash_uses_pixel_displays (state->boot_splash))
  963. ply_device_manager_deactivate_renderers (state->device_manager);
  964. state->is_shown = false;
  965. cancel_pending_delayed_show (state);
  966. if (state->boot_splash == NULL)
  967. return;
  968. ply_boot_splash_hide (state->boot_splash);
  969. if (state->local_console_terminal != NULL)
  970. ply_terminal_set_mode (state->local_console_terminal, PLY_TERMINAL_MODE_TEXT);
  971. }
  972. static void
  973. dump_details_and_quit_splash (state_t *state)
  974. {
  975. state->showing_details = false;
  976. toggle_between_splash_and_details (state);
  977. hide_splash (state);
  978. quit_splash (state);
  979. }
  980. static void
  981. on_hide_splash (state_t *state)
  982. {
  983. if (state->is_inactive)
  984. return;
  985. if (state->boot_splash == NULL)
  986. return;
  987. ply_trace ("hiding boot splash");
  988. dump_details_and_quit_splash (state);
  989. }
  990. static void
  991. quit_program (state_t *state)
  992. {
  993. ply_trace ("cleaning up devices");
  994. ply_device_manager_free (state->device_manager);
  995. ply_trace ("exiting event loop");
  996. ply_event_loop_exit (state->loop, 0);
  997. if (pid_file != NULL) {
  998. unlink (pid_file);
  999. free (pid_file);
  1000. pid_file = NULL;
  1001. }
  1002. if (state->deactivate_trigger != NULL) {
  1003. ply_trigger_pull (state->deactivate_trigger, NULL);
  1004. state->deactivate_trigger = NULL;
  1005. }
  1006. if (state->quit_trigger != NULL) {
  1007. ply_trigger_pull (state->quit_trigger, NULL);
  1008. state->quit_trigger = NULL;
  1009. }
  1010. }
  1011. static void
  1012. deactivate_console (state_t *state)
  1013. {
  1014. detach_from_running_session (state);
  1015. if (state->local_console_terminal != NULL) {
  1016. ply_trace ("deactivating terminal");
  1017. ply_terminal_stop_watching_for_vt_changes (state->local_console_terminal);
  1018. ply_terminal_set_buffered_input (state->local_console_terminal);
  1019. ply_terminal_close (state->local_console_terminal);
  1020. }
  1021. /* do not let any tty opened where we could write after deactivate */
  1022. if (ply_kernel_command_line_has_argument ("plymouth.debug"))
  1023. ply_logger_close_file (ply_logger_get_error_default ());
  1024. }
  1025. static void
  1026. deactivate_splash (state_t *state)
  1027. {
  1028. assert (!state->is_inactive);
  1029. if (state->boot_splash && ply_boot_splash_uses_pixel_displays (state->boot_splash))
  1030. ply_device_manager_deactivate_renderers (state->device_manager);
  1031. deactivate_console (state);
  1032. state->is_inactive = true;
  1033. ply_trigger_pull (state->deactivate_trigger, NULL);
  1034. state->deactivate_trigger = NULL;
  1035. }
  1036. static void
  1037. on_boot_splash_idle (state_t *state)
  1038. {
  1039. ply_trace ("boot splash idle");
  1040. /* In the case where we've received both a deactivate command and a
  1041. * quit command, the quit command takes precedence.
  1042. */
  1043. if (state->quit_trigger != NULL) {
  1044. if (!state->should_retain_splash) {
  1045. ply_trace ("hiding splash");
  1046. hide_splash (state);
  1047. }
  1048. ply_trace ("quitting splash");
  1049. quit_splash (state);
  1050. ply_trace ("quitting program");
  1051. quit_program (state);
  1052. } else if (state->deactivate_trigger != NULL) {
  1053. ply_trace ("deactivating splash");
  1054. deactivate_splash (state);
  1055. }
  1056. state->splash_is_becoming_idle = false;
  1057. }
  1058. static void
  1059. on_deactivate (state_t *state,
  1060. ply_trigger_t *deactivate_trigger)
  1061. {
  1062. if (state->is_inactive) {
  1063. deactivate_console (state);
  1064. ply_trigger_pull (deactivate_trigger, NULL);
  1065. return;
  1066. }
  1067. if (state->deactivate_trigger != NULL) {
  1068. ply_trigger_add_handler (state->deactivate_trigger,
  1069. (ply_trigger_handler_t)
  1070. ply_trigger_pull,
  1071. deactivate_trigger);
  1072. return;
  1073. }
  1074. state->deactivate_trigger = deactivate_trigger;
  1075. ply_trace ("deactivating");
  1076. cancel_pending_delayed_show (state);
  1077. ply_device_manager_pause (state->device_manager);
  1078. ply_device_manager_deactivate_keyboards (state->device_manager);
  1079. if (state->boot_splash != NULL) {
  1080. if (!state->splash_is_becoming_idle) {
  1081. ply_boot_splash_become_idle (state->boot_splash,
  1082. (ply_boot_splash_on_idle_handler_t)
  1083. on_boot_splash_idle,
  1084. state);
  1085. state->splash_is_becoming_idle = true;
  1086. }
  1087. } else {
  1088. ply_trace ("deactivating splash");
  1089. deactivate_splash (state);
  1090. }
  1091. }
  1092. static void
  1093. on_reactivate (state_t *state)
  1094. {
  1095. if (!state->is_inactive)
  1096. return;
  1097. if (state->local_console_terminal != NULL) {
  1098. ply_terminal_open (state->local_console_terminal);
  1099. ply_terminal_watch_for_vt_changes (state->local_console_terminal);
  1100. ply_terminal_set_unbuffered_input (state->local_console_terminal);
  1101. ply_terminal_ignore_mode_changes (state->local_console_terminal, false);
  1102. }
  1103. if ((state->session != NULL) && state->should_be_attached) {
  1104. ply_trace ("reactivating terminal session");
  1105. attach_to_running_session (state);
  1106. }
  1107. ply_device_manager_activate_keyboards (state->device_manager);
  1108. if (state->boot_splash && ply_boot_splash_uses_pixel_displays (state->boot_splash))
  1109. ply_device_manager_activate_renderers (state->device_manager);
  1110. ply_device_manager_unpause (state->device_manager);
  1111. state->is_inactive = false;
  1112. update_display (state);
  1113. }
  1114. static void
  1115. on_quit (state_t *state,
  1116. bool retain_splash,
  1117. ply_trigger_t *quit_trigger)
  1118. {
  1119. ply_trace ("quitting (retain splash: %s)", retain_splash ? "true" : "false");
  1120. if (state->quit_trigger != NULL) {
  1121. ply_trace ("quit trigger already pending, so chaining to it");
  1122. ply_trigger_add_handler (state->quit_trigger,
  1123. (ply_trigger_handler_t)
  1124. ply_trigger_pull,
  1125. quit_trigger);
  1126. return;
  1127. }
  1128. if (state->system_initialized) {
  1129. ply_trace ("system initialized so saving boot-duration file");
  1130. ply_create_directory (PLYMOUTH_TIME_DIRECTORY);
  1131. ply_progress_save_cache (state->progress,
  1132. get_cache_file_for_mode (state->mode));
  1133. } else {
  1134. ply_trace ("system not initialized so skipping saving boot-duration file");
  1135. }
  1136. state->quit_trigger = quit_trigger;
  1137. state->should_retain_splash = retain_splash;
  1138. #ifdef PLY_ENABLE_SYSTEMD_INTEGRATION
  1139. tell_systemd_to_stop_printing_details (state);
  1140. #endif
  1141. ply_trace ("closing log");
  1142. if (state->session != NULL)
  1143. ply_terminal_session_close_log (state->session);
  1144. ply_device_manager_deactivate_keyboards (state->device_manager);
  1145. ply_trace ("unloading splash");
  1146. if (state->is_inactive && !retain_splash) {
  1147. /* We've been deactivated and X failed to start
  1148. */
  1149. dump_details_and_quit_splash (state);
  1150. quit_program (state);
  1151. } else if (state->boot_splash != NULL) {
  1152. if (!state->splash_is_becoming_idle) {
  1153. ply_boot_splash_become_idle (state->boot_splash,
  1154. (ply_boot_splash_on_idle_handler_t)
  1155. on_boot_splash_idle,
  1156. state);
  1157. state->splash_is_becoming_idle = true;
  1158. }
  1159. } else {
  1160. quit_program (state);
  1161. }
  1162. }
  1163. static bool
  1164. on_has_active_vt (state_t *state)
  1165. {
  1166. if (state->local_console_terminal != NULL)
  1167. return ply_terminal_is_active (state->local_console_terminal);
  1168. else
  1169. return false;
  1170. }
  1171. static ply_boot_server_t *
  1172. start_boot_server (state_t *state)
  1173. {
  1174. ply_boot_server_t *server;
  1175. server = ply_boot_server_new ((ply_boot_server_update_handler_t) on_update,
  1176. (ply_boot_server_change_mode_handler_t) on_change_mode,
  1177. (ply_boot_server_system_update_handler_t) on_system_update,
  1178. (ply_boot_server_ask_for_password_handler_t) on_ask_for_password,
  1179. (ply_boot_server_ask_question_handler_t) on_ask_question,
  1180. (ply_boot_server_display_message_handler_t) on_display_message,
  1181. (ply_boot_server_hide_message_handler_t) on_hide_message,
  1182. (ply_boot_server_watch_for_keystroke_handler_t) on_watch_for_keystroke,
  1183. (ply_boot_server_ignore_keystroke_handler_t) on_ignore_keystroke,
  1184. (ply_boot_server_progress_pause_handler_t) on_progress_pause,
  1185. (ply_boot_server_progress_unpause_handler_t) on_progress_unpause,
  1186. (ply_boot_server_show_splash_handler_t) on_show_splash,
  1187. (ply_boot_server_hide_splash_handler_t) on_hide_splash,
  1188. (ply_boot_server_newroot_handler_t) on_newroot,
  1189. (ply_boot_server_system_initialized_handler_t) on_system_initialized,
  1190. (ply_boot_server_error_handler_t) on_error,
  1191. (ply_boot_server_deactivate_handler_t) on_deactivate,
  1192. (ply_boot_server_reactivate_handler_t) on_reactivate,
  1193. (ply_boot_server_quit_handler_t) on_quit,
  1194. (ply_boot_server_has_active_vt_handler_t) on_has_active_vt,
  1195. state);
  1196. if (!ply_boot_server_listen (server)) {
  1197. ply_save_errno ();
  1198. ply_boot_server_free (server);
  1199. ply_restore_errno ();
  1200. return NULL;
  1201. }
  1202. ply_boot_server_attach_to_event_loop (server, state->loop);
  1203. return server;
  1204. }
  1205. static void
  1206. update_display (state_t *state)
  1207. {
  1208. if (!state->boot_splash) return;
  1209. ply_list_node_t *node;
  1210. node = ply_list_get_first_node (state->entry_triggers);
  1211. if (node) {
  1212. ply_entry_trigger_t *entry_trigger = ply_list_node_get_data (node);
  1213. if (entry_trigger->type == PLY_ENTRY_TRIGGER_TYPE_PASSWORD) {
  1214. int bullets = ply_utf8_string_get_length (ply_buffer_get_bytes (state->entry_buffer),
  1215. ply_buffer_get_size (state->entry_buffer));
  1216. bullets = MAX (0, bullets);
  1217. ply_boot_splash_display_password (state->boot_splash,
  1218. entry_trigger->prompt,
  1219. bullets);
  1220. } else if (entry_trigger->type == PLY_ENTRY_TRIGGER_TYPE_QUESTION) {
  1221. ply_boot_splash_display_question (state->boot_splash,
  1222. entry_trigger->prompt,
  1223. ply_buffer_get_bytes (state->entry_buffer));
  1224. } else {
  1225. ply_trace ("unkown entry type");
  1226. }
  1227. } else {
  1228. ply_boot_splash_display_normal (state->boot_splash);
  1229. }
  1230. }
  1231. static void
  1232. toggle_between_splash_and_details (state_t *state)
  1233. {
  1234. ply_trace ("toggling between splash and details");
  1235. if (state->boot_splash != NULL) {
  1236. ply_trace ("hiding and freeing current splash");
  1237. hide_splash (state);
  1238. ply_boot_splash_free (state->boot_splash);
  1239. state->boot_splash = NULL;
  1240. }
  1241. if (!state->showing_details) {
  1242. show_detailed_splash (state);
  1243. state->showing_details = true;
  1244. } else {
  1245. show_default_splash (state);
  1246. state->showing_details = false;
  1247. }
  1248. }
  1249. static void
  1250. on_escape_pressed (state_t *state)
  1251. {
  1252. ply_trace ("escape key pressed");
  1253. toggle_between_splash_and_details (state);
  1254. }
  1255. static void
  1256. on_keyboard_input (state_t *state,
  1257. const char *keyboard_input,
  1258. size_t character_size)
  1259. {
  1260. ply_list_node_t *node;
  1261. node = ply_list_get_first_node (state->entry_triggers);
  1262. if (node) { /* \x3 (ETX) is Ctrl+C and \x4 (EOT) is Ctrl+D */
  1263. if (character_size == 1 && (keyboard_input[0] == '\x3' || keyboard_input[0] == '\x4')) {
  1264. ply_entry_trigger_t *entry_trigger = ply_list_node_get_data (node);
  1265. ply_trigger_pull (entry_trigger->trigger, "\x3");
  1266. ply_buffer_clear (state->entry_buffer);
  1267. ply_list_remove_node (state->entry_triggers, node);
  1268. free (entry_trigger);
  1269. } else {
  1270. ply_buffer_append_bytes (state->entry_buffer, keyboard_input, character_size);
  1271. }
  1272. update_display (state);
  1273. } else {
  1274. for (node = ply_list_get_first_node (state->keystroke_triggers); node;
  1275. node = ply_list_get_next_node (state->keystroke_triggers, node)) {
  1276. ply_keystroke_watch_t *keystroke_trigger = ply_list_node_get_data (node);
  1277. if (!keystroke_trigger->keys || strstr (keystroke_trigger->keys, keyboard_input)) { /* assume strstr works on utf8 arrays */
  1278. ply_trigger_pull (keystroke_trigger->trigger, keyboard_input);
  1279. ply_list_remove_node (state->keystroke_triggers, node);
  1280. free (keystroke_trigger);
  1281. return;
  1282. }
  1283. }
  1284. return;
  1285. }
  1286. }
  1287. static void
  1288. on_backspace (state_t *state)
  1289. {
  1290. ssize_t bytes_to_remove;
  1291. ssize_t previous_character_size;
  1292. const char *bytes;
  1293. size_t size;
  1294. ply_list_node_t *node = ply_list_get_first_node (state->entry_triggers);
  1295. if (!node) return;
  1296. bytes = ply_buffer_get_bytes (state->entry_buffer);
  1297. size = ply_buffer_get_size (state->entry_buffer);
  1298. if (size == 0)
  1299. return;
  1300. bytes_to_remove = MIN (size, PLY_UTF8_CHARACTER_SIZE_MAX);
  1301. while ((previous_character_size = ply_utf8_character_get_size (bytes + size - bytes_to_remove, bytes_to_remove)) < bytes_to_remove) {
  1302. if (previous_character_size > 0)
  1303. bytes_to_remove -= previous_character_size;
  1304. else
  1305. bytes_to_remove--;
  1306. }
  1307. ply_buffer_remove_bytes_at_end (state->entry_buffer, bytes_to_remove);
  1308. update_display (state);
  1309. }
  1310. static void
  1311. on_enter (state_t *state,
  1312. const char *line)
  1313. {
  1314. ply_list_node_t *node;
  1315. node = ply_list_get_first_node (state->entry_triggers);
  1316. if (node) {
  1317. ply_entry_trigger_t *entry_trigger = ply_list_node_get_data (node);
  1318. const char *reply_text = ply_buffer_get_bytes (state->entry_buffer);
  1319. ply_trigger_pull (entry_trigger->trigger, reply_text);
  1320. ply_buffer_clear (state->entry_buffer);
  1321. ply_list_remove_node (state->entry_triggers, node);
  1322. free (entry_trigger);
  1323. update_display (state);
  1324. } else {
  1325. for (node = ply_list_get_first_node (state->keystroke_triggers); node;
  1326. node = ply_list_get_next_node (state->keystroke_triggers, node)) {
  1327. ply_keystroke_watch_t *keystroke_trigger = ply_list_node_get_data (node);
  1328. if (!keystroke_trigger->keys || strstr (keystroke_trigger->keys, "\n")) { /* assume strstr works on utf8 arrays */
  1329. ply_trigger_pull (keystroke_trigger->trigger, line);
  1330. ply_list_remove_node (state->keystroke_triggers, node);
  1331. free (keystroke_trigger);
  1332. return;
  1333. }
  1334. }
  1335. return;
  1336. }
  1337. }
  1338. static void
  1339. attach_splash_to_devices (state_t *state,
  1340. ply_boot_splash_t *splash)
  1341. {
  1342. ply_list_t *keyboards;
  1343. ply_list_t *pixel_displays;
  1344. ply_list_t *text_displays;
  1345. ply_list_node_t *node;
  1346. keyboards = ply_device_manager_get_keyboards (state->device_manager);
  1347. node = ply_list_get_first_node (keyboards);
  1348. while (node != NULL) {
  1349. ply_keyboard_t *keyboard;
  1350. ply_list_node_t *next_node;
  1351. keyboard = ply_list_node_get_data (node);
  1352. next_node = ply_list_get_next_node (keyboards, node);
  1353. ply_boot_splash_set_keyboard (splash, keyboard);
  1354. node = next_node;
  1355. }
  1356. pixel_displays = ply_device_manager_get_pixel_displays (state->device_manager);
  1357. node = ply_list_get_first_node (pixel_displays);
  1358. while (node != NULL) {
  1359. ply_pixel_display_t *pixel_display;
  1360. ply_list_node_t *next_node;
  1361. pixel_display = ply_list_node_get_data (node);
  1362. next_node = ply_list_get_next_node (pixel_displays, node);
  1363. ply_boot_splash_add_pixel_display (splash, pixel_display);
  1364. node = next_node;
  1365. }
  1366. text_displays = ply_device_manager_get_text_displays (state->device_manager);
  1367. node = ply_list_get_first_node (text_displays);
  1368. while (node != NULL) {
  1369. ply_text_display_t *text_display;
  1370. ply_list_node_t *next_node;
  1371. text_display = ply_list_node_get_data (node);
  1372. next_node = ply_list_get_next_node (text_displays, node);
  1373. ply_boot_splash_add_text_display (splash, text_display);
  1374. node = next_node;
  1375. }
  1376. }
  1377. #ifdef PLY_ENABLE_SYSTEMD_INTEGRATION
  1378. static void
  1379. tell_systemd_to_print_details (state_t *state)
  1380. {
  1381. ply_trace ("telling systemd to start printing details");
  1382. if (kill (1, SIGRTMIN + 20) < 0)
  1383. ply_trace ("could not tell systemd to print details: %m");
  1384. }
  1385. static void
  1386. tell_systemd_to_stop_printing_details (state_t *state)
  1387. {
  1388. ply_trace ("telling systemd to stop printing details");
  1389. if (kill (1, SIGRTMIN + 21) < 0)
  1390. ply_trace ("could not tell systemd to stop printing details: %m");
  1391. }
  1392. #endif
  1393. static ply_boot_splash_t *
  1394. load_built_in_theme (state_t *state)
  1395. {
  1396. ply_boot_splash_t *splash;
  1397. bool is_loaded;
  1398. ply_trace ("Loading built-in theme");
  1399. splash = ply_boot_splash_new ("",
  1400. PLYMOUTH_PLUGIN_PATH,
  1401. state->boot_buffer);
  1402. is_loaded = ply_boot_splash_load_built_in (splash);
  1403. if (!is_loaded) {
  1404. ply_save_errno ();
  1405. ply_boot_splash_free (splash);
  1406. ply_restore_errno ();
  1407. return NULL;
  1408. }
  1409. ply_trace ("attaching plugin to event loop");
  1410. ply_boot_splash_attach_to_event_loop (splash, state->loop);
  1411. ply_trace ("attaching progress to plugin");
  1412. ply_boot_splash_attach_progress (splash, state->progress);
  1413. return splash;
  1414. }
  1415. static ply_boot_splash_t *
  1416. load_theme (state_t *state,
  1417. const char *theme_path)
  1418. {
  1419. ply_boot_splash_t *splash;
  1420. bool is_loaded;
  1421. ply_trace ("Loading boot splash theme '%s'",
  1422. theme_path);
  1423. splash = ply_boot_splash_new (theme_path,
  1424. PLYMOUTH_PLUGIN_PATH,
  1425. state->boot_buffer);
  1426. is_loaded = ply_boot_splash_load (splash);
  1427. if (!is_loaded) {
  1428. ply_save_errno ();
  1429. ply_boot_splash_free (splash);
  1430. ply_restore_errno ();
  1431. return NULL;
  1432. }
  1433. ply_trace ("attaching plugin to event loop");
  1434. ply_boot_splash_attach_to_event_loop (splash, state->loop);
  1435. ply_trace ("attaching progress to plugin");
  1436. ply_boot_splash_attach_progress (splash, state->progress);
  1437. return splash;
  1438. }
  1439. static ply_boot_splash_t *
  1440. show_theme (state_t *state,
  1441. const char *theme_path)
  1442. {
  1443. ply_boot_splash_t *splash;
  1444. if (theme_path != NULL)
  1445. splash = load_theme (state, theme_path);
  1446. else
  1447. splash = load_built_in_theme (state);
  1448. if (splash == NULL)
  1449. return NULL;
  1450. attach_splash_to_devices (state, splash);
  1451. if (ply_boot_splash_uses_pixel_displays (splash))
  1452. ply_device_manager_activate_renderers (state->device_manager);
  1453. if (!ply_boot_splash_show (splash, state->mode)) {
  1454. ply_save_errno ();
  1455. ply_boot_splash_free (splash);
  1456. ply_restore_errno ();
  1457. return NULL;
  1458. }
  1459. ply_device_manager_activate_keyboards (state->device_manager);
  1460. return splash;
  1461. }
  1462. static bool
  1463. attach_to_running_session (state_t *state)
  1464. {
  1465. ply_terminal_session_t *session;
  1466. ply_terminal_session_flags_t flags;
  1467. bool should_be_redirected;
  1468. flags = 0;
  1469. should_be_redirected = !state->no_boot_log;
  1470. if (should_be_redirected)
  1471. flags |= PLY_TERMINAL_SESSION_FLAGS_REDIRECT_CONSOLE;
  1472. if (state->session == NULL) {
  1473. ply_trace ("creating new terminal session");
  1474. session = ply_terminal_session_new (NULL);
  1475. ply_terminal_session_attach_to_event_loop (session, state->loop);
  1476. } else {
  1477. session = state->session;
  1478. ply_trace ("session already created");
  1479. }
  1480. if (!ply_terminal_session_attach (session, flags,
  1481. (ply_terminal_session_output_handler_t)
  1482. on_session_output,
  1483. (ply_terminal_session_hangup_handler_t)
  1484. (should_be_redirected ? on_session_hangup : NULL),
  1485. -1, state)) {
  1486. ply_save_errno ();
  1487. ply_terminal_session_free (session);
  1488. ply_buffer_free (state->boot_buffer);
  1489. state->boot_buffer = NULL;
  1490. ply_restore_errno ();
  1491. state->is_redirected = false;
  1492. state->is_attached = false;
  1493. return false;
  1494. }
  1495. #ifdef PLY_ENABLE_SYSTEMD_INTEGRATION
  1496. tell_systemd_to_print_details (state);
  1497. #endif
  1498. state->is_redirected = should_be_redirected;
  1499. state->is_attached = true;
  1500. state->session = session;
  1501. return true;
  1502. }
  1503. static void
  1504. detach_from_running_session (state_t *state)
  1505. {
  1506. if (state->session == NULL)
  1507. return;
  1508. if (!state->is_attached)
  1509. return;
  1510. #ifdef PLY_ENABLE_SYSTEMD_INTEGRATION
  1511. tell_systemd_to_stop_printing_details (state);
  1512. #endif
  1513. ply_trace ("detaching from terminal session");
  1514. ply_terminal_session_detach (state->session);
  1515. state->is_redirected = false;
  1516. state->is_attached = false;
  1517. }
  1518. static void
  1519. check_verbosity (state_t *state)
  1520. {
  1521. char *stream;
  1522. ply_trace ("checking if tracing should be enabled");
  1523. if (!debug_buffer_path)
  1524. debug_buffer_path = ply_kernel_command_line_get_key_value ("plymouth.debug=file:");
  1525. stream = ply_kernel_command_line_get_key_value ("plymouth.debug=stream:");
  1526. if (stream != NULL || debug_buffer_path != NULL ||
  1527. ply_kernel_command_line_has_argument ("plymouth.debug")) {
  1528. int fd;
  1529. ply_trace ("tracing should be enabled!");
  1530. if (!ply_is_tracing ())
  1531. ply_toggle_tracing ();
  1532. if (debug_buffer == NULL)
  1533. debug_buffer = ply_buffer_new ();
  1534. if (stream != NULL) {
  1535. ply_trace ("streaming debug output to %s instead of screen", stream);
  1536. fd = open (stream, O_RDWR | O_NOCTTY | O_CREAT, 0600);
  1537. if (fd < 0)
  1538. ply_trace ("could not stream output to %s: %m", stream);
  1539. else
  1540. ply_logger_set_output_fd (ply_logger_get_error_default (), fd);
  1541. free (stream);
  1542. } else {
  1543. const char *device;
  1544. char *file;
  1545. device = state->default_tty;
  1546. ply_trace ("redirecting debug output to %s", device);
  1547. if (strncmp (device, "/dev/", strlen ("/dev/")) == 0)
  1548. file = strdup (device);
  1549. else
  1550. asprintf (&file, "/dev/%s", device);
  1551. fd = open (file, O_RDWR | O_APPEND);
  1552. if (fd < 0)
  1553. ply_trace ("could not redirected debug output to %s: %m", device);
  1554. else
  1555. ply_logger_set_output_fd (ply_logger_get_error_default (), fd);
  1556. free (file);
  1557. }
  1558. } else {
  1559. ply_trace ("tracing shouldn't be enabled!");
  1560. }
  1561. if (debug_buffer != NULL) {
  1562. if (debug_buffer_path == NULL)
  1563. debug_buffer_path = strdup (PLYMOUTH_LOG_DIRECTORY "/plymouth-debug.log");
  1564. ply_logger_add_filter (ply_logger_get_error_default (),
  1565. (ply_logger_filter_handler_t)
  1566. on_error_message,
  1567. debug_buffer);
  1568. }
  1569. }
  1570. static void
  1571. check_logging (state_t *state)
  1572. {
  1573. bool kernel_no_log;
  1574. ply_trace ("checking if console messages should be redirected and logged");
  1575. kernel_no_log = ply_kernel_command_line_has_argument ("plymouth.nolog");
  1576. if (kernel_no_log)
  1577. state->no_boot_log = true;
  1578. if (state->no_boot_log)
  1579. ply_trace ("logging won't be enabled!");
  1580. else
  1581. ply_trace ("logging will be enabled!");
  1582. }
  1583. static bool
  1584. redirect_standard_io_to_dev_null (void)
  1585. {
  1586. int fd;
  1587. fd = open ("/dev/null", O_RDWR | O_APPEND);
  1588. if (fd < 0)
  1589. return false;
  1590. dup2 (fd, STDIN_FILENO);
  1591. dup2 (fd, STDOUT_FILENO);
  1592. dup2 (fd, STDERR_FILENO);
  1593. close (fd);
  1594. return true;
  1595. }
  1596. static const char *
  1597. find_fallback_tty (state_t *state)
  1598. {
  1599. static const char *tty_list[] =
  1600. {
  1601. "/dev/ttyS0",
  1602. "/dev/hvc0",
  1603. "/dev/xvc0",
  1604. "/dev/ttySG0",
  1605. NULL
  1606. };
  1607. int i;
  1608. for (i = 0; tty_list[i] != NULL; i++) {
  1609. if (ply_character_device_exists (tty_list[i]))
  1610. return tty_list[i];
  1611. }
  1612. return state->default_tty;
  1613. }
  1614. static bool
  1615. initialize_environment (state_t *state)
  1616. {
  1617. ply_trace ("initializing minimal work environment");
  1618. if (!state->default_tty)
  1619. if (getenv ("DISPLAY") != NULL && access (PLYMOUTH_PLUGIN_PATH "renderers/x11.so", F_OK) == 0)
  1620. state->default_tty = "/dev/tty";
  1621. if (!state->default_tty) {
  1622. if (state->mode == PLY_BOOT_SPLASH_MODE_SHUTDOWN ||
  1623. state->mode == PLY_BOOT_SPLASH_MODE_REBOOT)
  1624. state->default_tty = SHUTDOWN_TTY;
  1625. else
  1626. state->default_tty = BOOT_TTY;
  1627. ply_trace ("checking if '%s' exists", state->default_tty);
  1628. if (!ply_character_device_exists (state->default_tty)) {
  1629. ply_trace ("nope, forcing details mode");
  1630. state->should_force_details = true;
  1631. state->default_tty = find_fallback_tty (state);
  1632. ply_trace ("going to go with '%s'", state->default_tty);
  1633. }
  1634. }
  1635. check_verbosity (state);
  1636. check_logging (state);
  1637. ply_trace ("source built on %s", __DATE__);
  1638. state->keystroke_triggers = ply_list_new ();
  1639. state->entry_triggers = ply_list_new ();
  1640. state->entry_buffer = ply_buffer_new ();
  1641. state->messages = ply_list_new ();
  1642. if (!ply_is_tracing ())
  1643. redirect_standard_io_to_dev_null ();
  1644. ply_trace ("Making sure " PLYMOUTH_RUNTIME_DIR " exists");
  1645. if (!ply_create_directory (PLYMOUTH_RUNTIME_DIR))
  1646. ply_trace ("could not create " PLYMOUTH_RUNTIME_DIR ": %m");
  1647. ply_trace ("initialized minimal work environment");
  1648. return true;
  1649. }
  1650. static void
  1651. on_error_message (ply_buffer_t *debug_buffer,
  1652. const void *bytes,
  1653. size_t number_of_bytes)
  1654. {
  1655. ply_buffer_append_bytes (debug_buffer, bytes, number_of_bytes);
  1656. }
  1657. static void
  1658. dump_debug_buffer_to_file (void)
  1659. {
  1660. int fd;
  1661. const char *bytes;
  1662. size_t size;
  1663. fd = open (debug_buffer_path,
  1664. O_WRONLY | O_CREAT | O_TRUNC, 0600);
  1665. if (fd < 0)
  1666. return;
  1667. size = ply_buffer_get_size (debug_buffer);
  1668. bytes = ply_buffer_get_bytes (debug_buffer);
  1669. ply_write (fd, bytes, size);
  1670. close (fd);
  1671. }
  1672. #include <termios.h>
  1673. #include <unistd.h>
  1674. static void
  1675. on_crash (int signum)
  1676. {
  1677. struct termios term_attributes;
  1678. int fd;
  1679. static const char *show_cursor_sequence = "\033[?25h";
  1680. fd = open ("/dev/tty1", O_RDWR | O_NOCTTY);
  1681. if (fd < 0) fd = open ("/dev/hvc0", O_RDWR | O_NOCTTY);
  1682. ioctl (fd, KDSETMODE, KD_TEXT);
  1683. write (fd, show_cursor_sequence, sizeof (show_cursor_sequence) - 1);
  1684. tcgetattr (fd, &term_attributes);
  1685. term_attributes.c_iflag |= BRKINT | IGNPAR | ICRNL | IXON;
  1686. term_attributes.c_oflag |= OPOST;
  1687. term_attributes.c_lflag |= ECHO | ICANON | ISIG | IEXTEN;
  1688. tcsetattr (fd, TCSAFLUSH, &term_attributes);
  1689. close (fd);
  1690. if (debug_buffer != NULL) {
  1691. dump_debug_buffer_to_file ();
  1692. sleep (30);
  1693. }
  1694. if (pid_file != NULL) {
  1695. unlink (pid_file);
  1696. free (pid_file);
  1697. pid_file = NULL;
  1698. }
  1699. signal (signum, SIG_DFL);
  1700. raise (signum);
  1701. }
  1702. static void
  1703. write_pid_file (const char *filename)
  1704. {
  1705. FILE *fp;
  1706. fp = fopen (filename, "w");
  1707. if (fp == NULL) {
  1708. ply_error ("could not write pid file %s: %m", filename);
  1709. } else {
  1710. fprintf (fp, "%d\n", (int) getpid ());
  1711. fclose (fp);
  1712. }
  1713. }
  1714. int
  1715. main (int argc,
  1716. char **argv)
  1717. {
  1718. state_t state = { 0 };
  1719. int exit_code;
  1720. bool should_help = false;
  1721. bool no_boot_log = false;
  1722. bool no_daemon = false;
  1723. bool debug = false;
  1724. bool attach_to_session;
  1725. ply_daemon_handle_t *daemon_handle = NULL;
  1726. char *mode_string = NULL;
  1727. char *kernel_command_line = NULL;
  1728. char *tty = NULL;
  1729. ply_device_manager_flags_t device_manager_flags = PLY_DEVICE_MANAGER_FLAGS_NONE;
  1730. state.start_time = ply_get_timestamp ();
  1731. state.command_parser = ply_command_parser_new ("plymouthd", "Splash server");
  1732. state.loop = ply_event_loop_get_default ();
  1733. ply_command_parser_add_options (state.command_parser,
  1734. "help", "This help message", PLY_COMMAND_OPTION_TYPE_FLAG,
  1735. "attach-to-session", "Redirect console messages from screen to log", PLY_COMMAND_OPTION_TYPE_FLAG,
  1736. "no-daemon", "Do not daemonize", PLY_COMMAND_OPTION_TYPE_FLAG,
  1737. "debug", "Output debugging information", PLY_COMMAND_OPTION_TYPE_FLAG,
  1738. "debug-file", "File to output debugging information to", PLY_COMMAND_OPTION_TYPE_STRING,
  1739. "mode", "Mode is one of: boot, shutdown", PLY_COMMAND_OPTION_TYPE_STRING,
  1740. "pid-file", "Write the pid of the daemon to a file", PLY_COMMAND_OPTION_TYPE_STRING,
  1741. "kernel-command-line", "Fake kernel command line to use", PLY_COMMAND_OPTION_TYPE_STRING,
  1742. "tty", "TTY to use instead of default", PLY_COMMAND_OPTION_TYPE_STRING,
  1743. "no-boot-log", "Do not write boot log file", PLY_COMMAND_OPTION_TYPE_FLAG,
  1744. NULL);
  1745. if (!ply_command_parser_parse_arguments (state.command_parser, state.loop, argv, argc)) {
  1746. char *help_string;
  1747. help_string = ply_command_parser_get_help_string (state.command_parser);
  1748. ply_error_without_new_line ("%s", help_string);
  1749. free (help_string);
  1750. return EX_USAGE;
  1751. }
  1752. ply_command_parser_get_options (state.command_parser,
  1753. "help", &should_help,
  1754. "attach-to-session", &attach_to_session,
  1755. "mode", &mode_string,
  1756. "no-boot-log", &no_boot_log,
  1757. "no-daemon", &no_daemon,
  1758. "debug", &debug,
  1759. "debug-file", &debug_buffer_path,
  1760. "pid-file", &pid_file,
  1761. "tty", &tty,
  1762. "kernel-command-line", &kernel_command_line,
  1763. NULL);
  1764. if (should_help) {
  1765. char *help_string;
  1766. help_string = ply_command_parser_get_help_string (state.command_parser);
  1767. if (argc < 2)
  1768. fprintf (stderr, "%s", help_string);
  1769. else
  1770. printf ("%s", help_string);
  1771. free (help_string);
  1772. return 0;
  1773. }
  1774. if (debug && !ply_is_tracing ())
  1775. ply_toggle_tracing ();
  1776. if (mode_string != NULL) {
  1777. if (strcmp (mode_string, "shutdown") == 0)
  1778. state.mode = PLY_BOOT_SPLASH_MODE_SHUTDOWN;
  1779. else if (strcmp (mode_string, "reboot") == 0)
  1780. state.mode = PLY_BOOT_SPLASH_MODE_REBOOT;
  1781. else if (strcmp (mode_string, "updates") == 0)
  1782. state.mode = PLY_BOOT_SPLASH_MODE_UPDATES;
  1783. else if (strcmp (mode_string, "system-upgrade") == 0)
  1784. state.mode = PLY_BOOT_SPLASH_MODE_SYSTEM_UPGRADE;
  1785. else if (strcmp (mode_string, "firmware-upgrade") == 0)
  1786. state.mode = PLY_BOOT_SPLASH_MODE_FIRMWARE_UPGRADE;
  1787. else
  1788. state.mode = PLY_BOOT_SPLASH_MODE_BOOT_UP;
  1789. free (mode_string);
  1790. }
  1791. if (tty != NULL)
  1792. state.default_tty = tty;
  1793. if (kernel_command_line != NULL)
  1794. ply_kernel_command_line_override (kernel_command_line);
  1795. if (geteuid () != 0) {
  1796. ply_error ("plymouthd must be run as root user");
  1797. return EX_OSERR;
  1798. }
  1799. state.no_boot_log = no_boot_log;
  1800. chdir ("/");
  1801. signal (SIGPIPE, SIG_IGN);
  1802. if (!no_daemon) {
  1803. daemon_handle = ply_create_daemon ();
  1804. if (daemon_handle == NULL) {
  1805. ply_error ("plymouthd: cannot daemonize: %m");
  1806. return EX_UNAVAILABLE;
  1807. }
  1808. }
  1809. if (debug)
  1810. debug_buffer = ply_buffer_new ();
  1811. signal (SIGABRT, on_crash);
  1812. signal (SIGSEGV, on_crash);
  1813. /* before do anything we need to make sure we have a working
  1814. * environment.
  1815. */
  1816. if (!initialize_environment (&state)) {
  1817. if (errno == 0) {
  1818. if (daemon_handle != NULL)
  1819. ply_detach_daemon (daemon_handle, 0);
  1820. return 0;
  1821. }
  1822. ply_error ("plymouthd: could not setup basic operating environment: %m");
  1823. if (daemon_handle != NULL)
  1824. ply_detach_daemon (daemon_handle, EX_OSERR);
  1825. return EX_OSERR;
  1826. }
  1827. /* Make the first byte in argv be '@' so that we can survive systemd's killing
  1828. * spree when going from initrd to /, and so we stay alive all the way until
  1829. * the power is killed at shutdown.
  1830. * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons
  1831. */
  1832. argv[0][0] = '@';
  1833. state.boot_server = start_boot_server (&state);
  1834. if (state.boot_server == NULL) {
  1835. ply_trace ("plymouthd is already running");
  1836. if (daemon_handle != NULL)
  1837. ply_detach_daemon (daemon_handle, EX_OK);
  1838. return EX_OK;
  1839. }
  1840. state.boot_buffer = ply_buffer_new ();
  1841. if (attach_to_session) {
  1842. state.should_be_attached = attach_to_session;
  1843. if (!attach_to_running_session (&state)) {
  1844. ply_trace ("could not redirect console session: %m");
  1845. if (!no_daemon)
  1846. ply_detach_daemon (daemon_handle, EX_UNAVAILABLE);
  1847. return EX_UNAVAILABLE;
  1848. }
  1849. }
  1850. state.progress = ply_progress_new ();
  1851. state.splash_delay = NAN;
  1852. state.device_timeout = NAN;
  1853. ply_progress_load_cache (state.progress,
  1854. get_cache_file_for_mode (state.mode));
  1855. if (pid_file != NULL)
  1856. write_pid_file (pid_file);
  1857. if (daemon_handle != NULL
  1858. && !ply_detach_daemon (daemon_handle, 0)) {
  1859. ply_error ("plymouthd: could not tell parent to exit: %m");
  1860. return EX_UNAVAILABLE;
  1861. }
  1862. find_override_splash (&state);
  1863. find_system_default_splash (&state);
  1864. find_distribution_default_splash (&state);
  1865. if (ply_kernel_command_line_has_argument ("plymouth.ignore-serial-consoles"))
  1866. device_manager_flags |= PLY_DEVICE_MANAGER_FLAGS_IGNORE_SERIAL_CONSOLES;
  1867. if (ply_kernel_command_line_has_argument ("plymouth.ignore-udev") ||
  1868. (getenv ("DISPLAY") != NULL))
  1869. device_manager_flags |= PLY_DEVICE_MANAGER_FLAGS_IGNORE_UDEV;
  1870. if (!plymouth_should_show_default_splash (&state)) {
  1871. /* don't bother listening for udev events or setting up a graphical renderer
  1872. * if we're forcing details */
  1873. device_manager_flags |= PLY_DEVICE_MANAGER_FLAGS_SKIP_RENDERERS;
  1874. device_manager_flags |= PLY_DEVICE_MANAGER_FLAGS_IGNORE_UDEV;
  1875. /* don't ever delay showing the detailed splash */
  1876. state.splash_delay = NAN;
  1877. }
  1878. find_force_scale (&state);
  1879. load_devices (&state, device_manager_flags);
  1880. ply_trace ("entering event loop");
  1881. exit_code = ply_event_loop_run (state.loop);
  1882. ply_trace ("exited event loop");
  1883. ply_boot_splash_free (state.boot_splash);
  1884. state.boot_splash = NULL;
  1885. ply_command_parser_free (state.command_parser);
  1886. ply_boot_server_free (state.boot_server);
  1887. state.boot_server = NULL;
  1888. ply_trace ("freeing terminal session");
  1889. ply_terminal_session_free (state.session);
  1890. ply_buffer_free (state.boot_buffer);
  1891. ply_progress_free (state.progress);
  1892. ply_trace ("exiting with code %d", exit_code);
  1893. if (debug_buffer != NULL) {
  1894. dump_debug_buffer_to_file ();
  1895. ply_buffer_free (debug_buffer);
  1896. }
  1897. ply_free_error_log ();
  1898. return exit_code;
  1899. }
  1900. /* vim: set ts=4 ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */