Merge lp:~ubuntu-branches/ubuntu/precise/plymouth/precise-201311300306 into lp:ubuntu/precise/plymouth

Proposed by Ubuntu Package Importer
Status: Needs review
Proposed branch: lp:~ubuntu-branches/ubuntu/precise/plymouth/precise-201311300306
Merge into: lp:ubuntu/precise/plymouth
Diff against target: 8207 lines (+8060/-28) (has conflicts)
11 files modified
.pc.moved/tty1-after-boot.patch/src/main.c (+1/-7)
.pc/applied-patches (+23/-0)
.pc/debug-fixes.patch/src/main.c (+1992/-0)
.pc/initramfsless-boot.patch/src/main.c (+2003/-0)
.pc/main-Don-t-watch-for-keyboard-input-if-no-keyboard.patch/src/main.c (+1986/-0)
.pc/upstream-terminal-no-ISTRIP.patch/src/main.c (+1986/-0)
debian/changelog (+13/-0)
debian/patches/initramfsless-boot.patch (+54/-0)
debian/patches/misc-changes.patch (+0/-14)
debian/patches/series (+1/-0)
src/main.c (+1/-7)
Conflict adding files to .pc.  Created directory.
Conflict because .pc is not versioned, but has versioned children.  Versioned directory.
Conflict adding file .pc.  Moved existing file to .pc.moved.
Conflict adding files to .pc/debug-fixes.patch.  Created directory.
Conflict because .pc/debug-fixes.patch is not versioned, but has versioned children.  Versioned directory.
Conflict adding files to .pc/debug-fixes.patch/src.  Created directory.
Conflict because .pc/debug-fixes.patch/src is not versioned, but has versioned children.  Versioned directory.
Conflict adding files to .pc/main-Don-t-watch-for-keyboard-input-if-no-keyboard.patch.  Created directory.
Conflict because .pc/main-Don-t-watch-for-keyboard-input-if-no-keyboard.patch is not versioned, but has versioned children.  Versioned directory.
Conflict adding files to .pc/main-Don-t-watch-for-keyboard-input-if-no-keyboard.patch/src.  Created directory.
Conflict because .pc/main-Don-t-watch-for-keyboard-input-if-no-keyboard.patch/src is not versioned, but has versioned children.  Versioned directory.
Conflict adding files to .pc/upstream-terminal-no-ISTRIP.patch.  Created directory.
Conflict because .pc/upstream-terminal-no-ISTRIP.patch is not versioned, but has versioned children.  Versioned directory.
Conflict adding files to .pc/upstream-terminal-no-ISTRIP.patch/src.  Created directory.
Conflict because .pc/upstream-terminal-no-ISTRIP.patch/src is not versioned, but has versioned children.  Versioned directory.
To merge this branch: bzr merge lp:~ubuntu-branches/ubuntu/precise/plymouth/precise-201311300306
Reviewer Review Type Date Requested Status
Ubuntu branches Pending
Review via email: mp+197278@code.launchpad.net

Description of the change

The package importer has detected a possible inconsistency between the package history in the archive and the history in bzr. As the archive is authoritative the importer has made lp:ubuntu/precise/plymouth reflect what is in the archive and the old bzr branch has been pushed to lp:~ubuntu-branches/ubuntu/precise/plymouth/precise-201311300306. This merge proposal was created so that an Ubuntu developer can review the situations and perform a merge/upload if necessary. There are three typical cases where this can happen.
  1. Where someone pushes a change to bzr and someone else uploads the package without that change. This is the reason that this check is done by the importer. If this appears to be the case then a merge/upload should be done if the changes that were in bzr are still desirable.
  2. The importer incorrectly detected the above situation when someone made a change in bzr and then uploaded it.
  3. The importer incorrectly detected the above situation when someone just uploaded a package and didn't touch bzr.

If this case doesn't appear to be the first situation then set the status of the merge proposal to "Rejected" and help avoid the problem in future by filing a bug at https://bugs.launchpad.net/udd linking to this merge proposal.

(this is an automatically generated message)

To post a comment you must log in.

Unmerged revisions

1425. By Steve Langasek

* debian/patches/initramfsless-boot.patch: clean up our failure path when
  /dev/pts isn't available yet:
  - don't free a buffer that we might use again later
  - once we've created the session object, keep it around, instead of
    freeing it again and leaving a dangling reference to it in the loop
    exit handler list.
  it's not clear if this was working before, but it definitely hits an
  assert now. LP: #981314.

1424. By Steve Langasek

split initramfsless boot support out into a separate patch

1423. By Colin Watson

releasing version 0.8.2-2ubuntu30

1422. By Colin Watson

merge lp:~jamesodhunt/ubuntu/precise/plymouth/bug-553745, with added quilt fixing

1421. By Colin Watson

add lots of .pc files to try to stop the importer thinking it needs to overwrite this branch

1420. By Steve Langasek

merge fix for bug #979824

1419. By Steve Langasek

releasing version 0.8.2-2ubuntu29

1418. By Steve Langasek

debian/plymouth-theme-{k,}ubuntu-text.{triggers,postinst}: regenerate
our theme when /etc/lsb-release changes. LP: #957380.

1417. By Steve Langasek

debian/patches/tty1-after-boot.patch: Switch back to tty1 on exit if
started with vt.handoff. Closes LP: #913731.

1416. By Steve Langasek

the new file is named ubuntu_logo.png, not ubuntu-logo.png.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory '.pc'
2=== renamed directory '.pc' => '.pc.moved'
3=== modified file '.pc.moved/tty1-after-boot.patch/src/main.c'
4--- .pc/tty1-after-boot.patch/src/main.c 2012-04-13 15:11:36 +0000
5+++ .pc.moved/tty1-after-boot.patch/src/main.c 2013-11-30 04:03:08 +0000
6@@ -1478,6 +1478,7 @@
7 session = ply_terminal_session_new (NULL);
8
9 ply_terminal_session_attach_to_event_loop (session, state->loop);
10+ state->session = session;
11 }
12 else
13 {
14@@ -1492,12 +1493,6 @@
15 (should_be_redirected? on_session_finished: NULL),
16 -1, state))
17 {
18- ply_save_errno ();
19- ply_terminal_session_free (session);
20- ply_buffer_free (state->boot_buffer);
21- state->boot_buffer = NULL;
22- ply_restore_errno ();
23-
24 state->is_redirected = false;
25 state->is_attached = false;
26 return false;
27@@ -1505,7 +1500,6 @@
28
29 state->is_redirected = should_be_redirected;
30 state->is_attached = true;
31- state->session = session;
32
33 return true;
34 }
35
36=== added file '.pc/applied-patches'
37--- .pc/applied-patches 1970-01-01 00:00:00 +0000
38+++ .pc/applied-patches 2013-11-30 04:03:08 +0000
39@@ -0,0 +1,23 @@
40+ubuntu_details.patch
41+details_removeSeparator.patch
42+misc-changes.patch
43+initramfsless-boot.patch
44+vga16fb-renderer.patch
45+lbm-nouveau.patch
46+nouveau-framebuffer.patch
47+ubuntu-logo.patch
48+ubuntu-text.patch
49+kubuntu-text.patch
50+gcc45-arith-workaround.patch
51+debug-fixes.patch
52+upstart-bridge.patch
53+avoid-sigpipe.patch
54+upstream-event-loop-reference.patch
55+upstream-event-loop-number.patch
56+upstream-terminal-force-newline.patch
57+upstream-terminal-OPOST.patch
58+upstream-terminal-no-ISTRIP.patch
59+main-Don-t-watch-for-keyboard-input-if-no-keyboard.patch
60+tty1-after-boot.patch
61+invalid-event-source-workaround.patch
62+autoreconf.patch
63
64=== added directory '.pc/debug-fixes.patch'
65=== added directory '.pc/debug-fixes.patch/src'
66=== added file '.pc/debug-fixes.patch/src/main.c'
67--- .pc/debug-fixes.patch/src/main.c 1970-01-01 00:00:00 +0000
68+++ .pc/debug-fixes.patch/src/main.c 2013-11-30 04:03:08 +0000
69@@ -0,0 +1,1992 @@
70+/* main.c - boot messages monitor
71+ *
72+ * Copyright (C) 2007 Red Hat, Inc
73+ *
74+ * This file is free software; you can redistribute it and/or modify
75+ * it under the terms of the GNU General Public License as published
76+ * by the Free Software Foundation; either version 2 of the License,
77+ * or (at your option) any later version.
78+ *
79+ * This file is distributed in the hope that it will be useful, but
80+ * WITHOUT ANY WARRANTY; without even the implied warranty of
81+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
82+ * General Public License for more details.
83+ *
84+ * You should have received a copy of the GNU General Public License
85+ * along with this; see the file COPYING. If not, write to the Free
86+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
87+ * 02111-1307, USA.
88+ *
89+ * Written by: Ray Strode <rstrode@redhat.com>
90+ */
91+#include "config.h"
92+
93+#include <sys/stat.h>
94+#include <sys/types.h>
95+#include <limits.h>
96+#include <dirent.h>
97+#include <fcntl.h>
98+#include <stdlib.h>
99+#include <stdio.h>
100+#include <sysexits.h>
101+#include <sys/ioctl.h>
102+#include <unistd.h>
103+#include <wchar.h>
104+#include <paths.h>
105+#include <assert.h>
106+
107+#include <linux/kd.h>
108+#include <linux/vt.h>
109+
110+#include "ply-buffer.h"
111+#include "ply-command-parser.h"
112+#include "ply-boot-server.h"
113+#include "ply-boot-splash.h"
114+#include "ply-event-loop.h"
115+#include "ply-list.h"
116+#include "ply-logger.h"
117+#include "ply-terminal-session.h"
118+#include "ply-trigger.h"
119+#include "ply-utils.h"
120+#include "ply-progress.h"
121+
122+#ifndef PLY_MAX_COMMAND_LINE_SIZE
123+#define PLY_MAX_COMMAND_LINE_SIZE 512
124+#endif
125+
126+#define BOOT_DURATION_FILE PLYMOUTH_TIME_DIRECTORY "/boot-duration"
127+#define SHUTDOWN_DURATION_FILE PLYMOUTH_TIME_DIRECTORY "/shutdown-duration"
128+
129+typedef enum {
130+ PLY_MODE_BOOT,
131+ PLY_MODE_SHUTDOWN
132+} ply_mode_t;
133+
134+typedef struct
135+{
136+ const char *keys;
137+ ply_trigger_t *trigger;
138+} ply_keystroke_watch_t;
139+
140+typedef struct
141+{
142+ enum {PLY_ENTRY_TRIGGER_TYPE_PASSWORD,
143+ PLY_ENTRY_TRIGGER_TYPE_QUESTION}
144+ type;
145+ const char *prompt;
146+ ply_trigger_t *trigger;
147+} ply_entry_trigger_t;
148+
149+typedef struct
150+{
151+ ply_event_loop_t *loop;
152+ ply_boot_server_t *boot_server;
153+ ply_list_t *pixel_displays;
154+ ply_list_t *text_displays;
155+ ply_keyboard_t *keyboard;
156+ ply_boot_splash_t *boot_splash;
157+ ply_terminal_session_t *session;
158+ ply_buffer_t *boot_buffer;
159+ ply_progress_t *progress;
160+ ply_list_t *keystroke_triggers;
161+ ply_list_t *entry_triggers;
162+ ply_buffer_t *entry_buffer;
163+ ply_command_parser_t *command_parser;
164+ ply_mode_t mode;
165+ ply_renderer_t *renderer;
166+ ply_terminal_t *terminal;
167+
168+ ply_trigger_t *deactivate_trigger;
169+ ply_trigger_t *quit_trigger;
170+
171+ char kernel_command_line[PLY_MAX_COMMAND_LINE_SIZE];
172+ uint32_t no_boot_log : 1;
173+ uint32_t showing_details : 1;
174+ uint32_t system_initialized : 1;
175+ uint32_t is_redirected : 1;
176+ uint32_t is_attached : 1;
177+ uint32_t should_be_attached : 1;
178+ uint32_t should_retain_splash : 1;
179+ uint32_t is_inactive : 1;
180+
181+ char *kernel_console_tty;
182+ char *override_splash_path;
183+ char *system_default_splash_path;
184+ char *distribution_default_splash_path;
185+ const char *default_tty;
186+
187+ int number_of_errors;
188+ ply_list_t *pending_messages;
189+} state_t;
190+
191+static ply_boot_splash_t *start_boot_splash (state_t *state,
192+ const char *theme_path);
193+
194+static void add_display_and_keyboard_for_terminal (state_t *state,
195+ const char *tty_name);
196+
197+static void add_default_displays_and_keyboard (state_t *state);
198+
199+static bool attach_to_running_session (state_t *state);
200+static void on_escape_pressed (state_t *state);
201+static void dump_details_and_quit_splash (state_t *state);
202+static void update_display (state_t *state);
203+
204+static void on_error_message (ply_buffer_t *debug_buffer,
205+ const void *bytes,
206+ size_t number_of_bytes);
207+static ply_buffer_t *debug_buffer;
208+static char *debug_buffer_path = NULL;
209+static char *pid_file = NULL;
210+static void check_for_consoles (state_t *state,
211+ const char *default_tty,
212+ bool should_add_displays);
213+static void toggle_between_splash_and_details (state_t *state);
214+
215+static void
216+on_session_output (state_t *state,
217+ const char *output,
218+ size_t size)
219+{
220+ ply_buffer_append_bytes (state->boot_buffer, output, size);
221+ if (state->boot_splash != NULL)
222+ ply_boot_splash_update_output (state->boot_splash,
223+ output, size);
224+}
225+
226+static void
227+on_session_finished (state_t *state)
228+{
229+ ply_trace ("got hang up on terminal session fd");
230+}
231+
232+static void
233+on_update (state_t *state,
234+ const char *status)
235+{
236+ ply_trace ("updating status to '%s'", status);
237+ if (strncmp (status, "fsck:", 5))
238+ ply_progress_status_update (state->progress,
239+ status);
240+ if (state->boot_splash != NULL)
241+ ply_boot_splash_update_status (state->boot_splash,
242+ status);
243+}
244+
245+static void
246+flush_pending_messages (state_t *state)
247+{
248+ ply_list_node_t *node = ply_list_get_first_node (state->pending_messages);
249+ while (node != NULL)
250+ {
251+ ply_list_node_t *next_node;
252+ char *message = ply_list_node_get_data (node);
253+
254+ ply_trace ("displaying queued message");
255+
256+ ply_boot_splash_display_message (state->boot_splash, message);
257+ next_node = ply_list_get_next_node (state->pending_messages, node);
258+ ply_list_remove_node (state->pending_messages, node);
259+ free(message);
260+ node = next_node;
261+ }
262+}
263+
264+static void
265+show_detailed_splash (state_t *state)
266+{
267+ if (state->boot_splash != NULL)
268+ return;
269+
270+ ply_trace ("Showing detailed splash screen");
271+ state->boot_splash = start_boot_splash (state,
272+ PLYMOUTH_THEME_PATH "details/details.plymouth");
273+
274+ if (state->boot_splash == NULL)
275+ {
276+ ply_trace ("Could not start detailed splash screen, exiting");
277+ exit (1);
278+ }
279+}
280+
281+static void
282+find_override_splash (state_t *state)
283+{
284+ char *splash_string;
285+
286+ if (state->override_splash_path != NULL)
287+ return;
288+
289+ splash_string = strstr (state->kernel_command_line, "plymouth:splash=");
290+
291+ if (splash_string != NULL)
292+ {
293+ char *end;
294+ splash_string = strdup (splash_string + strlen ("plymouth:splash="));
295+
296+ end = strstr (splash_string, " ");
297+
298+ if (end != NULL)
299+ *end = '\0';
300+
301+ ply_trace ("Splash is configured to be '%s'", splash_string);
302+
303+ asprintf (&state->override_splash_path,
304+ PLYMOUTH_THEME_PATH "%s/%s.plymouth",
305+ splash_string, splash_string);
306+ }
307+}
308+
309+static void
310+find_system_default_splash (state_t *state)
311+{
312+ ply_key_file_t *key_file;
313+ char *splash_string;
314+
315+ if (state->system_default_splash_path != NULL)
316+ return;
317+
318+ ply_trace ("Trying to load " PLYMOUTH_CONF_DIR "plymouthd.conf");
319+ key_file = ply_key_file_new (PLYMOUTH_CONF_DIR "plymouthd.conf");
320+
321+ if (!ply_key_file_load (key_file))
322+ {
323+ ply_trace ("failed to load " PLYMOUTH_CONF_DIR "plymouthd.conf");
324+ ply_key_file_free (key_file);
325+ return;
326+ }
327+
328+ splash_string = ply_key_file_get_value (key_file, "Daemon", "Theme");
329+
330+ ply_trace ("System default splash is configured to be '%s'", splash_string);
331+
332+ asprintf (&state->system_default_splash_path,
333+ PLYMOUTH_THEME_PATH "%s/%s.plymouth",
334+ splash_string, splash_string);
335+ free (splash_string);
336+}
337+
338+static void
339+find_distribution_default_splash (state_t *state)
340+{
341+ ply_key_file_t *key_file;
342+ char *splash_string;
343+
344+ if (state->distribution_default_splash_path != NULL)
345+ return;
346+
347+ ply_trace ("Trying to load " PLYMOUTH_POLICY_DIR "plymouthd.defaults");
348+ key_file = ply_key_file_new (PLYMOUTH_POLICY_DIR "plymouthd.defaults");
349+
350+ if (!ply_key_file_load (key_file))
351+ {
352+ ply_trace ("failed to load " PLYMOUTH_POLICY_DIR "plymouthd.defaults");
353+ ply_key_file_free (key_file);
354+ return;
355+ }
356+
357+ splash_string = ply_key_file_get_value (key_file, "Daemon", "Theme");
358+
359+ ply_trace ("Distribution default splash is configured to be '%s'", splash_string);
360+
361+ asprintf (&state->distribution_default_splash_path,
362+ PLYMOUTH_THEME_PATH "%s/%s.plymouth",
363+ splash_string, splash_string);
364+ free (splash_string);
365+}
366+
367+static void
368+show_default_splash (state_t *state)
369+{
370+ if (state->boot_splash != NULL)
371+ return;
372+
373+ ply_trace ("Showing splash screen");
374+ find_override_splash (state);
375+ if (state->override_splash_path != NULL)
376+ {
377+ ply_trace ("Trying override splash at '%s'", state->override_splash_path);
378+ state->boot_splash = start_boot_splash (state,
379+ state->override_splash_path);
380+ }
381+
382+ find_system_default_splash (state);
383+ if (state->boot_splash == NULL &&
384+ state->system_default_splash_path != NULL)
385+ {
386+ ply_trace ("Trying system default splash");
387+ state->boot_splash = start_boot_splash (state,
388+ state->system_default_splash_path);
389+ }
390+
391+ find_distribution_default_splash (state);
392+ if (state->boot_splash == NULL &&
393+ state->distribution_default_splash_path != NULL)
394+ {
395+ ply_trace ("Trying distribution default splash");
396+ state->boot_splash = start_boot_splash (state,
397+ state->distribution_default_splash_path);
398+ }
399+
400+ if (state->boot_splash == NULL)
401+ {
402+ ply_trace ("Trying old scheme for default splash");
403+ state->boot_splash = start_boot_splash (state,
404+ PLYMOUTH_THEME_PATH "default.plymouth");
405+ }
406+
407+ if (state->boot_splash == NULL)
408+ {
409+ ply_trace ("Could not start default splash screen,"
410+ "showing text splash screen");
411+ state->boot_splash = start_boot_splash (state,
412+ PLYMOUTH_THEME_PATH "text.plymouth");
413+ }
414+
415+ if (state->boot_splash == NULL)
416+ {
417+ if (errno != ENOENT)
418+ ply_error ("could not start boot splash: %m");
419+ show_detailed_splash (state);
420+ }
421+}
422+
423+static void
424+on_ask_for_password (state_t *state,
425+ const char *prompt,
426+ ply_trigger_t *answer)
427+{
428+ ply_entry_trigger_t *entry_trigger;
429+
430+ /* No splash, client will have to get password
431+ */
432+ if (state->boot_splash == NULL)
433+ {
434+ ply_trace ("no splash loaded, replying immediately with no password");
435+ ply_trigger_pull (answer, NULL);
436+ return;
437+ }
438+
439+ entry_trigger = calloc (1, sizeof (ply_entry_trigger_t));
440+ entry_trigger->type = PLY_ENTRY_TRIGGER_TYPE_PASSWORD;
441+ entry_trigger->prompt = prompt;
442+ entry_trigger->trigger = answer;
443+ ply_trace ("queuing password request with boot splash");
444+ ply_list_append_data (state->entry_triggers, entry_trigger);
445+ update_display (state);
446+}
447+
448+static void
449+on_ask_question (state_t *state,
450+ const char *prompt,
451+ ply_trigger_t *answer)
452+{
453+ ply_entry_trigger_t *entry_trigger;
454+
455+ entry_trigger = calloc (1, sizeof (ply_entry_trigger_t));
456+ entry_trigger->type = PLY_ENTRY_TRIGGER_TYPE_QUESTION;
457+ entry_trigger->prompt = prompt;
458+ entry_trigger->trigger = answer;
459+ ply_trace ("queuing question with boot splash");
460+ ply_list_append_data (state->entry_triggers, entry_trigger);
461+ update_display (state);
462+}
463+
464+static void
465+on_display_message (state_t *state,
466+ const char *message)
467+{
468+ ply_trace ("displaying message %s", message);
469+ if (state->boot_splash != NULL)
470+ ply_boot_splash_display_message (state->boot_splash, message);
471+ else
472+ ply_list_append_data (state->pending_messages, strdup(message));
473+}
474+
475+static void
476+on_watch_for_keystroke (state_t *state,
477+ const char *keys,
478+ ply_trigger_t *trigger)
479+{
480+ ply_keystroke_watch_t *keystroke_trigger =
481+ calloc (1, sizeof (ply_keystroke_watch_t));
482+ ply_trace ("watching for keystroke");
483+ keystroke_trigger->keys = keys;
484+ keystroke_trigger->trigger = trigger;
485+ ply_list_append_data (state->keystroke_triggers, keystroke_trigger);
486+}
487+
488+static void
489+on_ignore_keystroke (state_t *state,
490+ const char *keys)
491+{
492+ ply_list_node_t *node;
493+
494+ ply_trace ("ignoring for keystroke");
495+
496+ for (node = ply_list_get_first_node (state->keystroke_triggers); node;
497+ node = ply_list_get_next_node (state->keystroke_triggers, node))
498+ {
499+ ply_keystroke_watch_t* keystroke_trigger = ply_list_node_get_data (node);
500+ if ((!keystroke_trigger->keys && !keys) ||
501+ (keystroke_trigger->keys && keys && strcmp(keystroke_trigger->keys, keys)==0))
502+ {
503+ ply_trigger_pull (keystroke_trigger->trigger, NULL);
504+ ply_list_remove_node (state->keystroke_triggers, node);
505+ return;
506+ }
507+ }
508+}
509+
510+static void
511+on_progress_pause (state_t *state)
512+{
513+ ply_trace ("pausing progress");
514+ ply_progress_pause (state->progress);
515+}
516+
517+static void
518+on_progress_unpause (state_t *state)
519+{
520+ ply_trace ("unpausing progress");
521+ ply_progress_unpause (state->progress);
522+}
523+
524+static void
525+on_newroot (state_t *state,
526+ const char *root_dir)
527+{
528+ if (state->mode != PLY_MODE_BOOT)
529+ {
530+ ply_trace ("new root is only supported in boot mode ");
531+ return;
532+ }
533+
534+ ply_trace ("new root mounted at \"%s\", switching to it", root_dir);
535+ chdir(root_dir);
536+ chroot(".");
537+ chdir("/");
538+ ply_progress_load_cache (state->progress, BOOT_DURATION_FILE);
539+ if (state->boot_splash != NULL)
540+ ply_boot_splash_root_mounted (state->boot_splash);
541+}
542+
543+static const char *
544+get_cache_file_for_mode (ply_mode_t mode)
545+{
546+ const char *filename;
547+
548+ switch ((int)mode)
549+ {
550+ case PLY_MODE_BOOT:
551+ filename = BOOT_DURATION_FILE;
552+ break;
553+ case PLY_MODE_SHUTDOWN:
554+ filename = SHUTDOWN_DURATION_FILE;
555+ break;
556+ default:
557+ fprintf (stderr, "Unhandled case in %s line %d\n", __FILE__, __LINE__);
558+ abort ();
559+ break;
560+ }
561+
562+ ply_trace ("returning cache file '%s'", filename);
563+ return filename;
564+}
565+
566+static const char *
567+get_log_file_for_mode (ply_mode_t mode)
568+{
569+ const char *filename;
570+
571+ switch ((int)mode)
572+ {
573+ case PLY_MODE_BOOT:
574+ filename = PLYMOUTH_LOG_DIRECTORY "/boot.log";
575+ break;
576+ case PLY_MODE_SHUTDOWN:
577+ filename = _PATH_DEVNULL;
578+ break;
579+ default:
580+ fprintf (stderr, "Unhandled case in %s line %d\n", __FILE__, __LINE__);
581+ abort ();
582+ break;
583+ }
584+
585+ ply_trace ("returning log file '%s'", filename);
586+ return filename;
587+}
588+
589+static const char *
590+get_log_spool_file_for_mode (ply_mode_t mode)
591+{
592+ const char *filename;
593+
594+ switch ((int)mode)
595+ {
596+ case PLY_MODE_BOOT:
597+ filename = PLYMOUTH_SPOOL_DIRECTORY "/boot.log";
598+ break;
599+ case PLY_MODE_SHUTDOWN:
600+ filename = NULL;
601+ break;
602+ default:
603+ fprintf (stderr, "Unhandled case in %s line %d\n", __FILE__, __LINE__);
604+ abort ();
605+ break;
606+ }
607+
608+ ply_trace ("returning spool file '%s'", filename);
609+ return filename;
610+}
611+
612+static void
613+spool_error (state_t *state)
614+{
615+ const char *logfile;
616+ const char *logspool;
617+
618+ ply_trace ("spooling error for viewer");
619+
620+ logfile = get_log_file_for_mode (state->mode);
621+ logspool = get_log_spool_file_for_mode (state->mode);
622+
623+ if (logfile != NULL && logspool != NULL)
624+ {
625+ unlink (logspool);
626+
627+ ply_create_file_link (logfile, logspool);
628+ }
629+}
630+
631+static void
632+prepare_logging (state_t *state)
633+{
634+ const char *logfile;
635+
636+ if (!state->system_initialized)
637+ {
638+ ply_trace ("not preparing logging yet, system not initialized");
639+ return;
640+ }
641+
642+ if (state->session == NULL)
643+ {
644+ ply_trace ("not preparing logging, no session");
645+ return;
646+ }
647+
648+ logfile = get_log_file_for_mode (state->mode);
649+ if (logfile != NULL)
650+ {
651+ ply_trace ("opening log '%s'", logfile);
652+ ply_terminal_session_open_log (state->session, logfile);
653+
654+ if (state->number_of_errors > 0)
655+ spool_error (state);
656+ }
657+}
658+
659+static void
660+on_system_initialized (state_t *state)
661+{
662+ ply_trace ("system now initialized, opening log");
663+ state->system_initialized = true;
664+
665+ prepare_logging (state);
666+}
667+
668+static void
669+on_error (state_t *state)
670+{
671+ ply_trace ("encountered error during boot up");
672+
673+ if (state->system_initialized && state->number_of_errors == 0)
674+ spool_error (state);
675+ else
676+ ply_trace ("not spooling because number of errors %d", state->number_of_errors);
677+
678+ state->number_of_errors++;
679+}
680+
681+static bool
682+plymouth_should_ignore_show_splash_calls (state_t *state)
683+{
684+ ply_trace ("checking if plymouth should be running");
685+ if (state->mode != PLY_MODE_BOOT || ply_string_has_prefix (state->kernel_command_line, "plymouth:force-splash") || strstr (state->kernel_command_line, " plymouth:force-splash") != NULL)
686+ return false;
687+
688+ return ply_string_has_prefix (state->kernel_command_line, "init=") || strstr (state->kernel_command_line, " init=") != NULL;
689+}
690+
691+static bool
692+plymouth_should_show_default_splash (state_t *state)
693+{
694+ ply_trace ("checking if plymouth should show default splash");
695+
696+ const char const *strings[] = {
697+ " single ", " single\n", "^single ",
698+ " 1 ", " 1\n", "^1 ",
699+ " s ", " s\n", "^s ",
700+ " S ", " S\n", "^S ",
701+ " -s ", " -s\n", "^-s ",
702+ NULL
703+ };
704+ int i;
705+
706+ if (state->kernel_console_tty != NULL)
707+ return false;
708+
709+ for (i = 0; strings[i] != NULL; i++)
710+ {
711+ int cmp;
712+ if (strings[i][0] == '^')
713+ cmp = strncmp(state->kernel_command_line, strings[i]+1,
714+ strlen(strings[i]+1)) == 0;
715+ else
716+ cmp = strstr (state->kernel_command_line, strings[i]) != NULL;
717+
718+ if (cmp)
719+ {
720+ ply_trace ("kernel command line has option \"%s\"", strings[i]);
721+ return false;
722+ }
723+ }
724+
725+ return strstr (state->kernel_command_line, "rhgb") != NULL || (strstr (state->kernel_command_line, "splash") != NULL && strstr(state->kernel_command_line, "splash=verbose") == NULL);
726+}
727+
728+static void
729+remove_displays_and_keyboard (state_t *state)
730+{
731+ ply_list_node_t *node;
732+ ply_trace ("removing displays and keyboard");
733+
734+ node = ply_list_get_first_node (state->pixel_displays);
735+ while (node != NULL)
736+ {
737+ ply_list_node_t *next_node;
738+ ply_pixel_display_t *display;
739+
740+ ply_trace ("removing pixel display");
741+ next_node = ply_list_get_next_node (state->pixel_displays, node);
742+ display = ply_list_node_get_data (node);
743+ ply_pixel_display_free (display);
744+
745+ ply_list_remove_node (state->pixel_displays, node);
746+
747+ node = next_node;
748+ }
749+
750+ node = ply_list_get_first_node (state->text_displays);
751+ while (node != NULL)
752+ {
753+ ply_list_node_t *next_node;
754+ ply_text_display_t *display;
755+
756+ ply_trace ("removing text display");
757+ next_node = ply_list_get_next_node (state->text_displays, node);
758+ display = ply_list_node_get_data (node);
759+ ply_text_display_free (display);
760+
761+ ply_list_remove_node (state->text_displays, node);
762+
763+ node = next_node;
764+ }
765+
766+ if (state->keyboard != NULL)
767+ {
768+ ply_trace ("removing keyboard");
769+ ply_keyboard_stop_watching_for_input (state->keyboard);
770+ ply_keyboard_free (state->keyboard);
771+ state->keyboard = NULL;
772+ }
773+}
774+
775+static void
776+on_show_splash (state_t *state)
777+{
778+ bool has_display;
779+
780+ if (state->is_inactive)
781+ {
782+ ply_trace ("show splash called while inactive");
783+ return;
784+ }
785+
786+ if (plymouth_should_ignore_show_splash_calls (state))
787+ {
788+ ply_trace ("show splash called while ignoring show splash calls");
789+ dump_details_and_quit_splash (state);
790+ return;
791+ }
792+
793+ check_for_consoles (state, state->default_tty, true);
794+
795+ has_display = ply_list_get_length (state->pixel_displays) > 0 ||
796+ ply_list_get_length (state->text_displays) > 0;
797+
798+ if (!state->is_attached && state->should_be_attached && has_display)
799+ attach_to_running_session (state);
800+
801+ if (!has_display && state->is_attached)
802+ {
803+ ply_trace ("no open seats, detaching session");
804+ ply_terminal_session_detach (state->session);
805+ state->is_redirected = false;
806+ state->is_attached = false;
807+ }
808+
809+ if (plymouth_should_show_default_splash (state))
810+ {
811+ show_default_splash (state);
812+ state->showing_details = false;
813+ }
814+ else
815+ {
816+ show_detailed_splash (state);
817+ state->showing_details = true;
818+ }
819+ flush_pending_messages (state);
820+}
821+
822+static void
823+quit_splash (state_t *state)
824+{
825+ ply_trace ("quiting splash");
826+ if (state->boot_splash != NULL)
827+ {
828+ ply_trace ("freeing splash");
829+ ply_boot_splash_free (state->boot_splash);
830+ state->boot_splash = NULL;
831+ }
832+
833+ ply_trace ("removing displays and keyboard");
834+ remove_displays_and_keyboard (state);
835+
836+ if (state->renderer != NULL)
837+ {
838+ ply_renderer_close (state->renderer);
839+ ply_renderer_free (state->renderer);
840+ state->renderer = NULL;
841+ }
842+
843+ if (state->terminal != NULL)
844+ {
845+ if (!state->should_retain_splash)
846+ {
847+ ply_trace ("Not retaining splash, so deallocating VT");
848+ ply_terminal_deactivate_vt (state->terminal);
849+ }
850+ ply_terminal_close (state->terminal);
851+ ply_terminal_free (state->terminal);
852+ state->terminal = NULL;
853+ }
854+
855+ if (state->session != NULL)
856+ {
857+ ply_trace ("detaching session");
858+ ply_terminal_session_detach (state->session);
859+ state->is_redirected = false;
860+ state->is_attached = false;
861+ }
862+}
863+
864+static void
865+dump_details_and_quit_splash (state_t *state)
866+{
867+ state->showing_details = false;
868+ toggle_between_splash_and_details (state);
869+
870+ if (state->renderer != NULL)
871+ ply_renderer_deactivate (state->renderer);
872+ if (state->boot_splash != NULL)
873+ ply_boot_splash_hide (state->boot_splash);
874+
875+ quit_splash (state);
876+}
877+
878+static void
879+on_hide_splash (state_t *state)
880+{
881+ if (state->is_inactive)
882+ return;
883+
884+ if (state->boot_splash == NULL)
885+ return;
886+
887+ ply_trace ("hiding boot splash");
888+ dump_details_and_quit_splash (state);
889+}
890+
891+#ifdef PLY_ENABLE_GDM_TRANSITION
892+static void
893+tell_gdm_to_transition (void)
894+{
895+ int fd;
896+
897+ fd = creat ("/var/spool/gdm/force-display-on-active-vt", 0644);
898+ close (fd);
899+}
900+#endif
901+
902+static void
903+quit_program (state_t *state)
904+{
905+ ply_trace ("exiting event loop");
906+ ply_event_loop_exit (state->loop, 0);
907+
908+ if (pid_file != NULL)
909+ {
910+ unlink (pid_file);
911+ free (pid_file);
912+ pid_file = NULL;
913+ }
914+
915+#ifdef PLY_ENABLE_GDM_TRANSITION
916+ if (state->should_retain_splash)
917+ {
918+ tell_gdm_to_transition ();
919+ }
920+#endif
921+
922+ if (state->deactivate_trigger != NULL)
923+ {
924+ ply_trigger_pull (state->deactivate_trigger, NULL);
925+ state->deactivate_trigger = NULL;
926+ }
927+ if (state->quit_trigger != NULL)
928+ {
929+ ply_trigger_pull (state->quit_trigger, NULL);
930+ state->quit_trigger = NULL;
931+ }
932+}
933+
934+static void
935+deactivate_splash (state_t *state)
936+{
937+ assert (!state->is_inactive);
938+
939+ if (state->renderer != NULL)
940+ {
941+ ply_trace ("deactivating renderer");
942+ ply_renderer_deactivate (state->renderer);
943+ }
944+
945+ if (state->keyboard != NULL)
946+ {
947+ ply_trace ("deactivating keyboard");
948+ ply_keyboard_stop_watching_for_input (state->keyboard);
949+ }
950+
951+ if ((state->session != NULL) && state->is_attached)
952+ {
953+ ply_trace ("deactivating terminal session");
954+ ply_terminal_session_detach (state->session);
955+ state->is_redirected = false;
956+ state->is_attached = false;
957+ }
958+
959+ if (state->terminal != NULL)
960+ {
961+ ply_trace ("deactivating terminal");
962+ ply_terminal_stop_watching_for_vt_changes (state->terminal);
963+ ply_terminal_set_buffered_input (state->terminal);
964+ ply_terminal_ignore_mode_changes (state->terminal, true);
965+ }
966+
967+ state->is_inactive = true;
968+
969+ ply_trigger_pull (state->deactivate_trigger, NULL);
970+ state->deactivate_trigger = NULL;
971+}
972+
973+static void
974+on_boot_splash_idle (state_t *state)
975+{
976+ ply_trace ("boot splash idle");
977+
978+ /* In the case where we've received both a deactivate command and a
979+ * quit command, the quit command takes precedence.
980+ */
981+ if (state->quit_trigger != NULL)
982+ {
983+ if (!state->should_retain_splash)
984+ {
985+ ply_trace ("hiding splash");
986+ if (state->renderer != NULL)
987+ ply_renderer_deactivate (state->renderer);
988+ if (state->boot_splash != NULL)
989+ ply_boot_splash_hide (state->boot_splash);
990+ }
991+
992+ ply_trace ("quitting splash");
993+ quit_splash (state);
994+ ply_trace ("quitting program");
995+ quit_program (state);
996+ }
997+ else if (state->deactivate_trigger != NULL)
998+ {
999+ ply_trace ("deactivating splash");
1000+ deactivate_splash (state);
1001+ }
1002+}
1003+
1004+
1005+static void
1006+on_deactivate (state_t *state,
1007+ ply_trigger_t *deactivate_trigger)
1008+{
1009+ if ((state->deactivate_trigger != NULL) || state->is_inactive)
1010+ {
1011+ ply_trigger_add_handler (state->deactivate_trigger,
1012+ (ply_trigger_handler_t)
1013+ ply_trigger_pull,
1014+ deactivate_trigger);
1015+ return;
1016+ }
1017+
1018+ state->deactivate_trigger = deactivate_trigger;
1019+
1020+ ply_trace ("deactivating");
1021+ if (state->boot_splash != NULL)
1022+ {
1023+ ply_boot_splash_become_idle (state->boot_splash,
1024+ (ply_boot_splash_on_idle_handler_t)
1025+ on_boot_splash_idle,
1026+ state);
1027+ }
1028+ else
1029+ {
1030+ ply_trace ("deactivating splash");
1031+ deactivate_splash (state);
1032+ }
1033+}
1034+
1035+static void
1036+on_reactivate (state_t *state)
1037+{
1038+ if (!state->is_inactive)
1039+ return;
1040+
1041+ if (state->terminal != NULL)
1042+ {
1043+ ply_terminal_watch_for_vt_changes (state->terminal);
1044+ ply_terminal_set_unbuffered_input (state->terminal);
1045+ ply_terminal_ignore_mode_changes (state->terminal, false);
1046+ }
1047+
1048+ if ((state->session != NULL) && state->should_be_attached)
1049+ {
1050+ ply_trace ("reactivating terminal session");
1051+ attach_to_running_session (state);
1052+ }
1053+
1054+ if (state->keyboard != NULL)
1055+ {
1056+ ply_trace ("activating keyboard");
1057+ ply_keyboard_watch_for_input (state->keyboard);
1058+ }
1059+
1060+ if (state->renderer != NULL)
1061+ {
1062+ ply_trace ("activating renderer");
1063+ ply_renderer_activate (state->renderer);
1064+ }
1065+
1066+ state->is_inactive = false;
1067+
1068+ update_display (state);
1069+}
1070+
1071+static void
1072+on_quit (state_t *state,
1073+ bool retain_splash,
1074+ ply_trigger_t *quit_trigger)
1075+{
1076+ if (state->quit_trigger != NULL)
1077+ {
1078+ ply_trigger_add_handler (state->quit_trigger,
1079+ (ply_trigger_handler_t)
1080+ ply_trigger_pull,
1081+ quit_trigger);
1082+ return;
1083+ }
1084+
1085+ state->quit_trigger = quit_trigger;
1086+ state->should_retain_splash = retain_splash;
1087+
1088+ ply_trace ("time to quit, closing log");
1089+ if (state->session != NULL)
1090+ ply_terminal_session_close_log (state->session);
1091+ ply_trace ("unloading splash");
1092+
1093+ if (state->is_inactive && !retain_splash)
1094+ {
1095+ /* We've been deactivated and X failed to start
1096+ */
1097+ dump_details_and_quit_splash (state);
1098+ quit_program (state);
1099+ }
1100+ else if (state->boot_splash != NULL)
1101+ {
1102+ ply_boot_splash_become_idle (state->boot_splash,
1103+ (ply_boot_splash_on_idle_handler_t)
1104+ on_boot_splash_idle,
1105+ state);
1106+ }
1107+ else
1108+ quit_program (state);
1109+}
1110+
1111+static bool
1112+on_has_active_vt (state_t *state)
1113+{
1114+ if (state->terminal != NULL)
1115+ return ply_terminal_is_active (state->terminal);
1116+ else
1117+ return false;
1118+}
1119+
1120+static ply_boot_server_t *
1121+start_boot_server (state_t *state)
1122+{
1123+ ply_boot_server_t *server;
1124+
1125+ server = ply_boot_server_new ((ply_boot_server_update_handler_t) on_update,
1126+ (ply_boot_server_ask_for_password_handler_t) on_ask_for_password,
1127+ (ply_boot_server_ask_question_handler_t) on_ask_question,
1128+ (ply_boot_server_display_message_handler_t) on_display_message,
1129+ (ply_boot_server_watch_for_keystroke_handler_t) on_watch_for_keystroke,
1130+ (ply_boot_server_ignore_keystroke_handler_t) on_ignore_keystroke,
1131+ (ply_boot_server_progress_pause_handler_t) on_progress_pause,
1132+ (ply_boot_server_progress_unpause_handler_t) on_progress_unpause,
1133+ (ply_boot_server_show_splash_handler_t) on_show_splash,
1134+ (ply_boot_server_hide_splash_handler_t) on_hide_splash,
1135+ (ply_boot_server_newroot_handler_t) on_newroot,
1136+ (ply_boot_server_system_initialized_handler_t) on_system_initialized,
1137+ (ply_boot_server_error_handler_t) on_error,
1138+ (ply_boot_server_deactivate_handler_t) on_deactivate,
1139+ (ply_boot_server_reactivate_handler_t) on_reactivate,
1140+ (ply_boot_server_quit_handler_t) on_quit,
1141+ (ply_boot_server_has_active_vt_handler_t) on_has_active_vt,
1142+ state);
1143+
1144+ if (!ply_boot_server_listen (server))
1145+ {
1146+ ply_save_errno ();
1147+ ply_boot_server_free (server);
1148+ ply_restore_errno ();
1149+ return NULL;
1150+ }
1151+
1152+ ply_boot_server_attach_to_event_loop (server, state->loop);
1153+
1154+ return server;
1155+}
1156+
1157+
1158+static void
1159+update_display (state_t *state)
1160+{
1161+ if (!state->boot_splash) return;
1162+
1163+ ply_list_node_t *node;
1164+ node = ply_list_get_first_node (state->entry_triggers);
1165+ if (node)
1166+ {
1167+ ply_entry_trigger_t* entry_trigger = ply_list_node_get_data (node);
1168+ if (entry_trigger->type == PLY_ENTRY_TRIGGER_TYPE_PASSWORD)
1169+ {
1170+ int bullets = ply_utf8_string_get_length (ply_buffer_get_bytes (state->entry_buffer),
1171+ ply_buffer_get_size (state->entry_buffer));
1172+ bullets = MAX(0, bullets);
1173+ ply_boot_splash_display_password (state->boot_splash,
1174+ entry_trigger->prompt,
1175+ bullets);
1176+ }
1177+ else if (entry_trigger->type == PLY_ENTRY_TRIGGER_TYPE_QUESTION)
1178+ {
1179+ ply_boot_splash_display_question (state->boot_splash,
1180+ entry_trigger->prompt,
1181+ ply_buffer_get_bytes (state->entry_buffer));
1182+ }
1183+ else {
1184+ ply_trace("unkown entry type");
1185+ }
1186+ }
1187+ else
1188+ {
1189+ ply_boot_splash_display_normal (state->boot_splash);
1190+ }
1191+
1192+}
1193+
1194+static void
1195+toggle_between_splash_and_details (state_t *state)
1196+{
1197+ ply_trace ("toggling between splash and details");
1198+ if (state->boot_splash != NULL)
1199+ {
1200+ ply_trace ("hiding and freeing current splash");
1201+ ply_boot_splash_hide (state->boot_splash);
1202+ ply_boot_splash_free (state->boot_splash);
1203+ state->boot_splash = NULL;
1204+ }
1205+
1206+ if (!state->showing_details)
1207+ {
1208+ show_detailed_splash (state);
1209+ state->showing_details = true;
1210+ }
1211+ else
1212+ {
1213+ show_default_splash (state);
1214+ state->showing_details = false;
1215+ }
1216+ update_display (state);
1217+}
1218+
1219+static void
1220+on_escape_pressed (state_t *state)
1221+{
1222+ ply_trace ("escape key pressed");
1223+ toggle_between_splash_and_details (state);
1224+}
1225+
1226+static void
1227+on_keyboard_input (state_t *state,
1228+ const char *keyboard_input,
1229+ size_t character_size)
1230+{
1231+ ply_list_node_t *node;
1232+ node = ply_list_get_first_node (state->entry_triggers);
1233+ if (node)
1234+ { /* \x3 (ETX) is Ctrl+C and \x4 (EOT) is Ctrl+D */
1235+ if (character_size == 1 && ( keyboard_input[0] == '\x3' || keyboard_input[0] == '\x4' ))
1236+ {
1237+ ply_entry_trigger_t* entry_trigger = ply_list_node_get_data (node);
1238+ ply_trigger_pull (entry_trigger->trigger, "\x3");
1239+ ply_buffer_clear (state->entry_buffer);
1240+ ply_list_remove_node (state->entry_triggers, node);
1241+ free (entry_trigger);
1242+ }
1243+ else
1244+ {
1245+ ply_buffer_append_bytes (state->entry_buffer, keyboard_input, character_size);
1246+ }
1247+ update_display (state);
1248+ }
1249+ else
1250+ {
1251+ for (node = ply_list_get_first_node (state->keystroke_triggers); node;
1252+ node = ply_list_get_next_node (state->keystroke_triggers, node))
1253+ {
1254+ ply_keystroke_watch_t* keystroke_trigger = ply_list_node_get_data (node);
1255+ if (!keystroke_trigger->keys || strstr(keystroke_trigger->keys, keyboard_input)) /* assume strstr works on utf8 arrays */
1256+ {
1257+ ply_trigger_pull (keystroke_trigger->trigger, keyboard_input);
1258+ ply_list_remove_node (state->keystroke_triggers, node);
1259+ free(keystroke_trigger);
1260+ return;
1261+ }
1262+ }
1263+ return;
1264+ }
1265+}
1266+
1267+static void
1268+on_backspace (state_t *state)
1269+{
1270+ ssize_t bytes_to_remove;
1271+ ssize_t previous_character_size;
1272+ const char *bytes;
1273+ size_t size;
1274+ ply_list_node_t *node = ply_list_get_first_node (state->entry_triggers);
1275+ if (!node) return;
1276+
1277+ bytes = ply_buffer_get_bytes (state->entry_buffer);
1278+ size = ply_buffer_get_size (state->entry_buffer);
1279+
1280+ bytes_to_remove = MIN(size, PLY_UTF8_CHARACTER_SIZE_MAX);
1281+ while ((previous_character_size = ply_utf8_character_get_size (bytes + size - bytes_to_remove, bytes_to_remove)) < bytes_to_remove)
1282+ {
1283+ if (previous_character_size > 0)
1284+ bytes_to_remove -= previous_character_size;
1285+ else
1286+ bytes_to_remove--;
1287+ }
1288+
1289+ ply_buffer_remove_bytes_at_end (state->entry_buffer, bytes_to_remove);
1290+ update_display (state);
1291+}
1292+
1293+static void
1294+on_enter (state_t *state,
1295+ const char *line)
1296+{
1297+ ply_list_node_t *node;
1298+ node = ply_list_get_first_node (state->entry_triggers);
1299+ if (node)
1300+ {
1301+ ply_entry_trigger_t* entry_trigger = ply_list_node_get_data (node);
1302+ const char* reply_text = ply_buffer_get_bytes (state->entry_buffer);
1303+ ply_trigger_pull (entry_trigger->trigger, reply_text);
1304+ ply_buffer_clear (state->entry_buffer);
1305+ ply_list_remove_node (state->entry_triggers, node);
1306+ free (entry_trigger);
1307+ update_display (state);
1308+ }
1309+ else
1310+ {
1311+ for (node = ply_list_get_first_node (state->keystroke_triggers); node;
1312+ node = ply_list_get_next_node (state->keystroke_triggers, node))
1313+ {
1314+ ply_keystroke_watch_t* keystroke_trigger = ply_list_node_get_data (node);
1315+ if (!keystroke_trigger->keys || strstr(keystroke_trigger->keys, "\n")) /* assume strstr works on utf8 arrays */
1316+ {
1317+ ply_trigger_pull (keystroke_trigger->trigger, line);
1318+ ply_list_remove_node (state->keystroke_triggers, node);
1319+ free(keystroke_trigger);
1320+ return;
1321+ }
1322+ }
1323+ return;
1324+ }
1325+}
1326+
1327+static void
1328+set_keyboard (state_t *state,
1329+ ply_keyboard_t *keyboard)
1330+{
1331+ state->keyboard = keyboard;
1332+
1333+ ply_keyboard_add_escape_handler (keyboard, (ply_keyboard_escape_handler_t)
1334+ on_escape_pressed, state);
1335+ ply_trace ("listening for keystrokes");
1336+ ply_keyboard_add_input_handler (keyboard,
1337+ (ply_keyboard_input_handler_t)
1338+ on_keyboard_input, state);
1339+ ply_trace ("listening for backspace");
1340+ ply_keyboard_add_backspace_handler (keyboard,
1341+ (ply_keyboard_backspace_handler_t)
1342+ on_backspace, state);
1343+ ply_trace ("listening for enter");
1344+ ply_keyboard_add_enter_handler (keyboard,
1345+ (ply_keyboard_enter_handler_t)
1346+ on_enter, state);
1347+}
1348+static void
1349+add_display_and_keyboard_for_terminal (state_t *state,
1350+ const char *tty_name)
1351+{
1352+ ply_text_display_t *display;
1353+ ply_keyboard_t *keyboard;
1354+
1355+ ply_trace ("adding display and keyboard for %s", tty_name);
1356+
1357+ state->terminal = ply_terminal_new (tty_name);
1358+
1359+ // urgh
1360+ if (!ply_terminal_open (state->terminal))
1361+ return;
1362+
1363+ keyboard = ply_keyboard_new_for_terminal (state->terminal);
1364+ display = ply_text_display_new (state->terminal);
1365+
1366+ ply_list_append_data (state->text_displays, display);
1367+ state->keyboard = keyboard;
1368+ set_keyboard (state, keyboard);
1369+}
1370+
1371+static void
1372+add_pixel_displays_from_renderer (state_t *state,
1373+ ply_renderer_t *renderer)
1374+{
1375+ ply_list_t *heads;
1376+ ply_list_node_t *node;
1377+
1378+ heads = ply_renderer_get_heads (renderer);
1379+
1380+ ply_trace ("Adding displays for %d heads",
1381+ ply_list_get_length (heads));
1382+
1383+ node = ply_list_get_first_node (heads);
1384+ while (node != NULL)
1385+ {
1386+ ply_list_node_t *next_node;
1387+ ply_renderer_head_t *head;
1388+ ply_pixel_display_t *display;
1389+
1390+ head = ply_list_node_get_data (node);
1391+ next_node = ply_list_get_next_node (heads, node);
1392+
1393+ display = ply_pixel_display_new (renderer, head);
1394+
1395+ ply_list_append_data (state->pixel_displays, display);
1396+
1397+ node = next_node;
1398+ }
1399+
1400+}
1401+
1402+static void
1403+add_default_displays_and_keyboard (state_t *state)
1404+{
1405+ ply_renderer_t *renderer;
1406+ ply_keyboard_t *keyboard;
1407+ ply_terminal_t *terminal;
1408+ ply_text_display_t *text_display;
1409+
1410+ ply_trace ("adding default displays and keyboard");
1411+
1412+ terminal = ply_terminal_new (state->default_tty);
1413+
1414+ renderer = ply_renderer_new (NULL, terminal);
1415+
1416+ if (!ply_renderer_open (renderer))
1417+ {
1418+ ply_trace ("could not open renderer /dev/fb");
1419+ ply_renderer_free (renderer);
1420+ ply_terminal_free (terminal);
1421+
1422+ add_display_and_keyboard_for_terminal (state, state->default_tty);
1423+ return;
1424+ }
1425+
1426+ state->terminal = terminal;
1427+
1428+ keyboard = ply_keyboard_new_for_renderer (renderer);
1429+ set_keyboard (state, keyboard);
1430+
1431+ add_pixel_displays_from_renderer (state, renderer);
1432+
1433+ text_display = ply_text_display_new (state->terminal);
1434+ ply_list_append_data (state->text_displays, text_display);
1435+
1436+ state->renderer = renderer;
1437+}
1438+
1439+static void
1440+add_displays_and_keyboard_to_boot_splash (state_t *state,
1441+ ply_boot_splash_t *splash)
1442+{
1443+ ply_list_node_t *node;
1444+
1445+ ply_trace ("setting keyboard on boot splash");
1446+ if (state->keyboard != NULL)
1447+ ply_boot_splash_set_keyboard (splash, state->keyboard);
1448+
1449+ node = ply_list_get_first_node (state->pixel_displays);
1450+ while (node != NULL)
1451+ {
1452+ ply_pixel_display_t *display;
1453+ ply_list_node_t *next_node;
1454+
1455+ display = ply_list_node_get_data (node);
1456+ next_node = ply_list_get_next_node (state->pixel_displays, node);
1457+ ply_trace ("adding pixel display on boot splash");
1458+ ply_boot_splash_add_pixel_display (splash, display);
1459+
1460+ node = next_node;
1461+ }
1462+
1463+ node = ply_list_get_first_node (state->text_displays);
1464+ while (node != NULL)
1465+ {
1466+ ply_text_display_t *display;
1467+ ply_list_node_t *next_node;
1468+
1469+ display = ply_list_node_get_data (node);
1470+ next_node = ply_list_get_next_node (state->text_displays, node);
1471+
1472+ ply_trace ("adding text display on boot splash");
1473+ ply_boot_splash_add_text_display (splash, display);
1474+
1475+ node = next_node;
1476+ }
1477+}
1478+
1479+static ply_boot_splash_t *
1480+start_boot_splash (state_t *state,
1481+ const char *theme_path)
1482+{
1483+ ply_boot_splash_t *splash;
1484+ ply_boot_splash_mode_t splash_mode;
1485+
1486+ ply_trace ("Loading boot splash theme '%s'",
1487+ theme_path);
1488+
1489+ splash = ply_boot_splash_new (theme_path,
1490+ PLYMOUTH_PLUGIN_PATH,
1491+ state->boot_buffer,
1492+ state->terminal);
1493+
1494+ if (!ply_boot_splash_load (splash))
1495+ {
1496+ ply_save_errno ();
1497+ ply_boot_splash_free (splash);
1498+ ply_restore_errno ();
1499+ return NULL;
1500+ }
1501+
1502+ ply_trace ("attaching plugin to event loop");
1503+ ply_boot_splash_attach_to_event_loop (splash, state->loop);
1504+
1505+ ply_trace ("attaching progress to plugin");
1506+ ply_boot_splash_attach_progress (splash, state->progress);
1507+
1508+ add_displays_and_keyboard_to_boot_splash (state, splash);
1509+
1510+ ply_trace ("showing plugin");
1511+ if (state->mode == PLY_MODE_SHUTDOWN)
1512+ splash_mode = PLY_BOOT_SPLASH_MODE_SHUTDOWN;
1513+ else
1514+ splash_mode = PLY_BOOT_SPLASH_MODE_BOOT_UP;
1515+
1516+ if (!ply_boot_splash_show (splash, splash_mode))
1517+ {
1518+ ply_save_errno ();
1519+ ply_boot_splash_unset_keyboard (splash);
1520+ ply_boot_splash_free (splash);
1521+ ply_restore_errno ();
1522+ return NULL;
1523+ }
1524+
1525+ ply_keyboard_watch_for_input (state->keyboard);
1526+
1527+ update_display (state);
1528+ return splash;
1529+}
1530+
1531+static bool
1532+attach_to_running_session (state_t *state)
1533+{
1534+ ply_terminal_session_t *session;
1535+ ply_terminal_session_flags_t flags;
1536+ bool should_be_redirected;
1537+
1538+ flags = 0;
1539+
1540+ should_be_redirected = !state->no_boot_log;
1541+
1542+ if (should_be_redirected)
1543+ flags |= PLY_TERMINAL_SESSION_FLAGS_REDIRECT_CONSOLE;
1544+
1545+ if (state->session == NULL)
1546+ {
1547+ ply_trace ("creating new terminal session");
1548+ session = ply_terminal_session_new (NULL);
1549+
1550+ ply_terminal_session_attach_to_event_loop (session, state->loop);
1551+ state->session = session;
1552+ }
1553+ else
1554+ {
1555+ session = state->session;
1556+ ply_trace ("session already created");
1557+ }
1558+
1559+ if (!ply_terminal_session_attach (session, flags,
1560+ (ply_terminal_session_output_handler_t)
1561+ on_session_output,
1562+ (ply_terminal_session_done_handler_t)
1563+ (should_be_redirected? on_session_finished: NULL),
1564+ -1, state))
1565+ {
1566+ state->is_redirected = false;
1567+ state->is_attached = false;
1568+ return false;
1569+ }
1570+
1571+ state->is_redirected = should_be_redirected;
1572+ state->is_attached = true;
1573+
1574+ return true;
1575+}
1576+
1577+static bool
1578+get_kernel_command_line (state_t *state)
1579+{
1580+ int fd;
1581+
1582+ ply_trace ("opening /proc/cmdline");
1583+ fd = open ("proc/cmdline", O_RDONLY);
1584+
1585+ if (fd < 0)
1586+ {
1587+ ply_trace ("couldn't open it: %m");
1588+ return false;
1589+ }
1590+
1591+ ply_trace ("reading kernel command line");
1592+ if (read (fd, state->kernel_command_line, sizeof (state->kernel_command_line)) < 0)
1593+ {
1594+ ply_trace ("couldn't read it: %m");
1595+ return false;
1596+ }
1597+
1598+ ply_trace ("Kernel command line is: '%s'", state->kernel_command_line);
1599+ close (fd);
1600+ return true;
1601+}
1602+
1603+static void
1604+check_verbosity (state_t *state)
1605+{
1606+ char *path;
1607+
1608+ ply_trace ("checking if tracing should be enabled");
1609+
1610+ path = NULL;
1611+ if ((strstr (state->kernel_command_line, " plymouth:debug ") != NULL)
1612+ || (strstr (state->kernel_command_line, "plymouth:debug ") != NULL)
1613+ || (strstr (state->kernel_command_line, " plymouth:debug") != NULL)
1614+ || (path = strstr (state->kernel_command_line, " plymouth:debug=file:")) != NULL)
1615+ {
1616+#ifdef LOG_TO_DEBUG_FILE
1617+ int fd;
1618+#endif
1619+
1620+ ply_trace ("tracing should be enabled!");
1621+ if (!ply_is_tracing ())
1622+ ply_toggle_tracing ();
1623+
1624+ if (path != NULL && debug_buffer_path == NULL)
1625+ {
1626+ char *end;
1627+
1628+ path += strlen (" plymouth:debug=file:");
1629+ debug_buffer_path = strdup (path);
1630+ end = strstr (debug_buffer_path, " ");
1631+
1632+ if (end != NULL)
1633+ *end = '\0';
1634+
1635+ debug_buffer_path = path;
1636+ }
1637+
1638+ if (debug_buffer == NULL)
1639+ debug_buffer = ply_buffer_new ();
1640+
1641+#ifdef LOG_TO_DEBUG_FILE
1642+ fd = open ("/dev/console", O_RDWR);
1643+ ply_logger_set_output_fd (ply_logger_get_error_default (), fd);
1644+#endif
1645+ }
1646+ else
1647+ ply_trace ("tracing shouldn't be enabled!");
1648+
1649+ if (debug_buffer != NULL)
1650+ {
1651+ if (debug_buffer_path == NULL)
1652+ debug_buffer_path = strdup (PLYMOUTH_LOG_DIRECTORY "/plymouth-debug.log");
1653+
1654+ ply_logger_add_filter (ply_logger_get_error_default (),
1655+ (ply_logger_filter_handler_t)
1656+ on_error_message,
1657+ debug_buffer);
1658+
1659+ }
1660+}
1661+
1662+static void
1663+check_logging (state_t *state)
1664+{
1665+ ply_trace ("checking if console messages should be redirected and logged");
1666+
1667+ if ((strstr (state->kernel_command_line, " plymouth:nolog ") != NULL)
1668+ || (strstr (state->kernel_command_line, "plymouth:nolog ") != NULL)
1669+ || (strstr (state->kernel_command_line, " plymouth:nolog") != NULL))
1670+ {
1671+ ply_trace ("logging won't be enabled!");
1672+ state->no_boot_log = true;
1673+ }
1674+ else
1675+ {
1676+ ply_trace ("logging will be enabled!");
1677+ state->no_boot_log = false;
1678+ }
1679+}
1680+
1681+static void
1682+check_for_consoles (state_t *state,
1683+ const char *default_tty,
1684+ bool should_add_displays)
1685+{
1686+ char *console_key;
1687+ char *remaining_command_line;
1688+
1689+ ply_trace ("checking for consoles%s",
1690+ should_add_displays? " and adding displays": "");
1691+
1692+ remaining_command_line = state->kernel_command_line;
1693+ while ((console_key = strstr (remaining_command_line, " console=")) != NULL)
1694+ {
1695+ char *end;
1696+ ply_trace ("serial console found!");
1697+
1698+ free (state->kernel_console_tty);
1699+ state->kernel_console_tty = strdup (console_key + strlen (" console="));
1700+
1701+ remaining_command_line = console_key + strlen (" console=");
1702+
1703+ end = strpbrk (state->kernel_console_tty, " \n\t\v,");
1704+
1705+ if (end != NULL)
1706+ {
1707+ *end = '\0';
1708+ remaining_command_line += end - state->kernel_console_tty;
1709+ }
1710+
1711+ if (strcmp (state->kernel_console_tty, "tty0") == 0 || strcmp (state->kernel_console_tty, "/dev/tty0") == 0)
1712+ {
1713+ free (state->kernel_console_tty);
1714+ state->kernel_console_tty = strdup (default_tty);
1715+ }
1716+
1717+ if (should_add_displays)
1718+ add_display_and_keyboard_for_terminal (state, state->kernel_console_tty);
1719+ }
1720+
1721+ ply_trace ("There are currently %d text displays",
1722+ ply_list_get_length (state->text_displays));
1723+ if (should_add_displays && ply_list_get_length (state->text_displays) == 0)
1724+ add_default_displays_and_keyboard (state);
1725+}
1726+
1727+static bool
1728+redirect_standard_io_to_device (const char *device)
1729+{
1730+ int fd;
1731+ char *file;
1732+
1733+ ply_trace ("redirecting stdio to %s", device);
1734+
1735+ if (strncmp (device, "/dev/", strlen ("/dev/")) == 0)
1736+ file = strdup (device);
1737+ else
1738+ asprintf (&file, "/dev/%s", device);
1739+
1740+ fd = open (file, O_RDWR | O_APPEND);
1741+
1742+ free (file);
1743+
1744+ if (fd < 0)
1745+ return false;
1746+
1747+ dup2 (fd, STDIN_FILENO);
1748+ dup2 (fd, STDOUT_FILENO);
1749+ dup2 (fd, STDERR_FILENO);
1750+
1751+ close (fd);
1752+
1753+ return true;
1754+}
1755+
1756+static bool
1757+initialize_environment (state_t *state)
1758+{
1759+ ply_trace ("initializing minimal work environment");
1760+
1761+ if (!get_kernel_command_line (state))
1762+ return false;
1763+
1764+ check_verbosity (state);
1765+ check_logging (state);
1766+
1767+ state->keystroke_triggers = ply_list_new ();
1768+ state->entry_triggers = ply_list_new ();
1769+ state->entry_buffer = ply_buffer_new();
1770+ state->pixel_displays = ply_list_new ();
1771+ state->text_displays = ply_list_new ();
1772+ state->pending_messages = ply_list_new ();
1773+ state->keyboard = NULL;
1774+
1775+ if (!state->default_tty)
1776+ {
1777+ if (state->mode == PLY_MODE_SHUTDOWN)
1778+ {
1779+ state->default_tty = SHUTDOWN_TTY;
1780+ }
1781+ else
1782+ state->default_tty = BOOT_TTY;
1783+ }
1784+
1785+ check_for_consoles (state, state->default_tty, false);
1786+
1787+ if (state->kernel_console_tty != NULL)
1788+ redirect_standard_io_to_device (state->kernel_console_tty);
1789+ else
1790+ redirect_standard_io_to_device (state->default_tty);
1791+
1792+ ply_trace ("initialized minimal work environment");
1793+ return true;
1794+}
1795+
1796+static void
1797+on_error_message (ply_buffer_t *debug_buffer,
1798+ const void *bytes,
1799+ size_t number_of_bytes)
1800+{
1801+ ply_buffer_append_bytes (debug_buffer, bytes, number_of_bytes);
1802+}
1803+
1804+static void
1805+dump_debug_buffer_to_file (void)
1806+{
1807+ int fd;
1808+ const char *bytes;
1809+ size_t size;
1810+
1811+ fd = open (debug_buffer_path,
1812+ O_WRONLY | O_CREAT | O_TRUNC, 0600);
1813+
1814+ if (fd < 0)
1815+ return;
1816+
1817+ size = ply_buffer_get_size (debug_buffer);
1818+ bytes = ply_buffer_get_bytes (debug_buffer);
1819+ ply_write (fd, bytes, size);
1820+ close (fd);
1821+}
1822+
1823+ #include <termios.h>
1824+ #include <unistd.h>
1825+static void
1826+on_crash (int signum)
1827+{
1828+ struct termios term_attributes;
1829+ int fd;
1830+
1831+ fd = open ("/dev/tty1", O_RDWR | O_NOCTTY);
1832+ if (fd < 0) fd = open ("/dev/hvc0", O_RDWR | O_NOCTTY);
1833+
1834+ ioctl (fd, KDSETMODE, KD_TEXT);
1835+
1836+ tcgetattr (fd, &term_attributes);
1837+
1838+ term_attributes.c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1839+ term_attributes.c_oflag |= OPOST;
1840+ term_attributes.c_lflag |= ECHO | ICANON | ISIG | IEXTEN;
1841+
1842+ tcsetattr (fd, TCSAFLUSH, &term_attributes);
1843+
1844+ close (fd);
1845+
1846+ if (debug_buffer != NULL)
1847+ {
1848+ dump_debug_buffer_to_file ();
1849+ pause ();
1850+ }
1851+
1852+ if (pid_file != NULL)
1853+ {
1854+ unlink (pid_file);
1855+ free (pid_file);
1856+ pid_file = NULL;
1857+ }
1858+
1859+ signal (signum, SIG_DFL);
1860+ raise(signum);
1861+}
1862+
1863+int
1864+main (int argc,
1865+ char **argv)
1866+{
1867+ state_t state = { 0 };
1868+ int exit_code;
1869+ bool should_help = false;
1870+ bool no_daemon = false;
1871+ bool debug = false;
1872+ bool attach_to_session;
1873+ ply_daemon_handle_t *daemon_handle;
1874+ char *mode_string = NULL;
1875+ char *tty = NULL;
1876+
1877+ state.command_parser = ply_command_parser_new ("plymouthd", "Boot splash control server");
1878+
1879+ state.loop = ply_event_loop_get_default ();
1880+
1881+ ply_command_parser_add_options (state.command_parser,
1882+ "help", "This help message", PLY_COMMAND_OPTION_TYPE_FLAG,
1883+ "attach-to-session", "Redirect console messages from screen to log", PLY_COMMAND_OPTION_TYPE_FLAG,
1884+ "no-daemon", "Do not daemonize", PLY_COMMAND_OPTION_TYPE_FLAG,
1885+ "debug", "Output debugging information", PLY_COMMAND_OPTION_TYPE_FLAG,
1886+ "debug-file", "File to output debugging information to", PLY_COMMAND_OPTION_TYPE_STRING,
1887+ "mode", "Mode is one of: boot, shutdown", PLY_COMMAND_OPTION_TYPE_STRING,
1888+ "pid-file", "Write the pid of the daemon to a file", PLY_COMMAND_OPTION_TYPE_STRING,
1889+ "tty", "TTY to use instead of default", PLY_COMMAND_OPTION_TYPE_STRING,
1890+ NULL);
1891+
1892+ if (!ply_command_parser_parse_arguments (state.command_parser, state.loop, argv, argc))
1893+ {
1894+ char *help_string;
1895+
1896+ help_string = ply_command_parser_get_help_string (state.command_parser);
1897+
1898+ ply_error ("%s", help_string);
1899+
1900+ free (help_string);
1901+ return EX_USAGE;
1902+ }
1903+
1904+ ply_command_parser_get_options (state.command_parser,
1905+ "help", &should_help,
1906+ "attach-to-session", &attach_to_session,
1907+ "mode", &mode_string,
1908+ "no-daemon", &no_daemon,
1909+ "debug", &debug,
1910+ "debug-file", &debug_buffer_path,
1911+ "pid-file", &pid_file,
1912+ "tty", &tty,
1913+ NULL);
1914+
1915+ if (should_help)
1916+ {
1917+ char *help_string;
1918+
1919+ help_string = ply_command_parser_get_help_string (state.command_parser);
1920+
1921+ if (argc < 2)
1922+ fprintf (stderr, "%s", help_string);
1923+ else
1924+ printf ("%s", help_string);
1925+
1926+ free (help_string);
1927+ return 0;
1928+ }
1929+
1930+ if (debug && !ply_is_tracing ())
1931+ ply_toggle_tracing ();
1932+
1933+ if (mode_string != NULL)
1934+ {
1935+ if (strcmp (mode_string, "shutdown") == 0)
1936+ state.mode = PLY_MODE_SHUTDOWN;
1937+ else
1938+ state.mode = PLY_MODE_BOOT;
1939+
1940+ free (mode_string);
1941+ }
1942+
1943+ if (tty != NULL)
1944+ {
1945+ state.default_tty = tty;
1946+ }
1947+
1948+ if (geteuid () != 0)
1949+ {
1950+ ply_error ("plymouthd must be run as root user");
1951+ return EX_OSERR;
1952+ }
1953+
1954+ chdir ("/");
1955+ signal (SIGPIPE, SIG_IGN);
1956+
1957+ if (! no_daemon)
1958+ {
1959+ daemon_handle = ply_create_daemon (pid_file);
1960+
1961+ if (daemon_handle == NULL)
1962+ {
1963+ ply_error ("cannot daemonize: %m");
1964+ return EX_UNAVAILABLE;
1965+ }
1966+ }
1967+
1968+ if (debug)
1969+ debug_buffer = ply_buffer_new ();
1970+
1971+ signal (SIGABRT, on_crash);
1972+ signal (SIGSEGV, on_crash);
1973+
1974+ /* If we're shutting down we don't want to die until killed
1975+ */
1976+ if (state.mode == PLY_MODE_SHUTDOWN)
1977+ signal (SIGTERM, SIG_IGN);
1978+
1979+ /* before do anything we need to make sure we have a working
1980+ * environment.
1981+ */
1982+ if (!initialize_environment (&state))
1983+ {
1984+ if (errno == 0)
1985+ {
1986+ if (! no_daemon)
1987+ ply_detach_daemon (daemon_handle, 0);
1988+ return 0;
1989+ }
1990+
1991+ ply_error ("could not setup basic operating environment: %m");
1992+ if (! no_daemon)
1993+ ply_detach_daemon (daemon_handle, EX_OSERR);
1994+ return EX_OSERR;
1995+ }
1996+
1997+ state.boot_buffer = ply_buffer_new ();
1998+
1999+ if (attach_to_session)
2000+ {
2001+ state.should_be_attached = attach_to_session;
2002+ if (!attach_to_running_session (&state))
2003+ ply_trace ("could not create session: %m");
2004+ }
2005+
2006+ state.boot_server = start_boot_server (&state);
2007+
2008+ if (state.boot_server == NULL)
2009+ {
2010+ ply_error ("could not log bootup: %m");
2011+ if (! no_daemon)
2012+ ply_detach_daemon (daemon_handle, EX_UNAVAILABLE);
2013+ return EX_UNAVAILABLE;
2014+ }
2015+
2016+ if (! no_daemon)
2017+ if (!ply_detach_daemon (daemon_handle, 0))
2018+ {
2019+ ply_error ("could not tell parent to exit: %m");
2020+ return EX_UNAVAILABLE;
2021+ }
2022+
2023+ state.progress = ply_progress_new ();
2024+
2025+ ply_progress_load_cache (state.progress,
2026+ get_cache_file_for_mode (state.mode));
2027+
2028+ ply_trace ("entering event loop");
2029+ exit_code = ply_event_loop_run (state.loop);
2030+ ply_trace ("exited event loop");
2031+
2032+ ply_progress_save_cache (state.progress,
2033+ get_cache_file_for_mode (state.mode));
2034+
2035+ ply_boot_splash_free (state.boot_splash);
2036+ state.boot_splash = NULL;
2037+
2038+ ply_command_parser_free (state.command_parser);
2039+
2040+ ply_boot_server_free (state.boot_server);
2041+ state.boot_server = NULL;
2042+
2043+ ply_trace ("freeing terminal session");
2044+ ply_terminal_session_free (state.session);
2045+
2046+ ply_buffer_free (state.boot_buffer);
2047+ ply_progress_free (state.progress);
2048+
2049+ ply_trace ("exiting with code %d", exit_code);
2050+
2051+ if (debug_buffer != NULL)
2052+ {
2053+ dump_debug_buffer_to_file ();
2054+ ply_buffer_free (debug_buffer);
2055+ }
2056+
2057+ ply_free_error_log();
2058+
2059+ return exit_code;
2060+}
2061+/* vim: set sts=4 ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
2062
2063=== added directory '.pc/initramfsless-boot.patch'
2064=== added directory '.pc/initramfsless-boot.patch/src'
2065=== added file '.pc/initramfsless-boot.patch/src/main.c'
2066--- .pc/initramfsless-boot.patch/src/main.c 1970-01-01 00:00:00 +0000
2067+++ .pc/initramfsless-boot.patch/src/main.c 2013-11-30 04:03:08 +0000
2068@@ -0,0 +1,2003 @@
2069+/* main.c - boot messages monitor
2070+ *
2071+ * Copyright (C) 2007 Red Hat, Inc
2072+ *
2073+ * This file is free software; you can redistribute it and/or modify
2074+ * it under the terms of the GNU General Public License as published
2075+ * by the Free Software Foundation; either version 2 of the License,
2076+ * or (at your option) any later version.
2077+ *
2078+ * This file is distributed in the hope that it will be useful, but
2079+ * WITHOUT ANY WARRANTY; without even the implied warranty of
2080+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2081+ * General Public License for more details.
2082+ *
2083+ * You should have received a copy of the GNU General Public License
2084+ * along with this; see the file COPYING. If not, write to the Free
2085+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
2086+ * 02111-1307, USA.
2087+ *
2088+ * Written by: Ray Strode <rstrode@redhat.com>
2089+ */
2090+#include "config.h"
2091+
2092+#include <sys/stat.h>
2093+#include <sys/types.h>
2094+#include <limits.h>
2095+#include <dirent.h>
2096+#include <fcntl.h>
2097+#include <stdlib.h>
2098+#include <stdio.h>
2099+#include <sysexits.h>
2100+#include <sys/ioctl.h>
2101+#include <unistd.h>
2102+#include <wchar.h>
2103+#include <paths.h>
2104+#include <assert.h>
2105+
2106+#include <linux/kd.h>
2107+#include <linux/vt.h>
2108+
2109+#include "ply-buffer.h"
2110+#include "ply-command-parser.h"
2111+#include "ply-boot-server.h"
2112+#include "ply-boot-splash.h"
2113+#include "ply-event-loop.h"
2114+#include "ply-list.h"
2115+#include "ply-logger.h"
2116+#include "ply-terminal-session.h"
2117+#include "ply-trigger.h"
2118+#include "ply-utils.h"
2119+#include "ply-progress.h"
2120+
2121+#ifndef PLY_MAX_COMMAND_LINE_SIZE
2122+#define PLY_MAX_COMMAND_LINE_SIZE 512
2123+#endif
2124+
2125+#define BOOT_DURATION_FILE PLYMOUTH_TIME_DIRECTORY "/boot-duration"
2126+#define SHUTDOWN_DURATION_FILE PLYMOUTH_TIME_DIRECTORY "/shutdown-duration"
2127+
2128+typedef enum {
2129+ PLY_MODE_BOOT,
2130+ PLY_MODE_SHUTDOWN
2131+} ply_mode_t;
2132+
2133+typedef struct
2134+{
2135+ const char *keys;
2136+ ply_trigger_t *trigger;
2137+} ply_keystroke_watch_t;
2138+
2139+typedef struct
2140+{
2141+ enum {PLY_ENTRY_TRIGGER_TYPE_PASSWORD,
2142+ PLY_ENTRY_TRIGGER_TYPE_QUESTION}
2143+ type;
2144+ const char *prompt;
2145+ ply_trigger_t *trigger;
2146+} ply_entry_trigger_t;
2147+
2148+typedef struct
2149+{
2150+ ply_event_loop_t *loop;
2151+ ply_boot_server_t *boot_server;
2152+ ply_list_t *pixel_displays;
2153+ ply_list_t *text_displays;
2154+ ply_keyboard_t *keyboard;
2155+ ply_boot_splash_t *boot_splash;
2156+ ply_terminal_session_t *session;
2157+ ply_buffer_t *boot_buffer;
2158+ ply_progress_t *progress;
2159+ ply_list_t *keystroke_triggers;
2160+ ply_list_t *entry_triggers;
2161+ ply_buffer_t *entry_buffer;
2162+ ply_command_parser_t *command_parser;
2163+ ply_mode_t mode;
2164+ ply_renderer_t *renderer;
2165+ ply_terminal_t *terminal;
2166+
2167+ ply_trigger_t *deactivate_trigger;
2168+ ply_trigger_t *quit_trigger;
2169+
2170+ char kernel_command_line[PLY_MAX_COMMAND_LINE_SIZE];
2171+ uint32_t no_boot_log : 1;
2172+ uint32_t showing_details : 1;
2173+ uint32_t system_initialized : 1;
2174+ uint32_t is_redirected : 1;
2175+ uint32_t is_attached : 1;
2176+ uint32_t should_be_attached : 1;
2177+ uint32_t should_retain_splash : 1;
2178+ uint32_t is_inactive : 1;
2179+
2180+ char *kernel_console_tty;
2181+ char *override_splash_path;
2182+ char *system_default_splash_path;
2183+ char *distribution_default_splash_path;
2184+ const char *default_tty;
2185+
2186+ int number_of_errors;
2187+ ply_list_t *pending_messages;
2188+} state_t;
2189+
2190+static ply_boot_splash_t *start_boot_splash (state_t *state,
2191+ const char *theme_path);
2192+
2193+static void add_display_and_keyboard_for_terminal (state_t *state,
2194+ const char *tty_name);
2195+
2196+static void add_default_displays_and_keyboard (state_t *state);
2197+
2198+static bool attach_to_running_session (state_t *state);
2199+static void on_escape_pressed (state_t *state);
2200+static void dump_details_and_quit_splash (state_t *state);
2201+static void update_display (state_t *state);
2202+
2203+static void on_error_message (ply_buffer_t *debug_buffer,
2204+ const void *bytes,
2205+ size_t number_of_bytes);
2206+static ply_buffer_t *debug_buffer;
2207+static char *debug_buffer_path = NULL;
2208+static char *pid_file = NULL;
2209+static void check_for_consoles (state_t *state,
2210+ const char *default_tty,
2211+ bool should_add_displays);
2212+static void toggle_between_splash_and_details (state_t *state);
2213+
2214+static void
2215+on_session_output (state_t *state,
2216+ const char *output,
2217+ size_t size)
2218+{
2219+ ply_buffer_append_bytes (state->boot_buffer, output, size);
2220+ if (state->boot_splash != NULL)
2221+ ply_boot_splash_update_output (state->boot_splash,
2222+ output, size);
2223+}
2224+
2225+static void
2226+on_session_finished (state_t *state)
2227+{
2228+ ply_trace ("got hang up on terminal session fd");
2229+}
2230+
2231+static void
2232+on_update (state_t *state,
2233+ const char *status)
2234+{
2235+ ply_trace ("updating status to '%s'", status);
2236+ if (strncmp (status, "fsck:", 5))
2237+ ply_progress_status_update (state->progress,
2238+ status);
2239+ if (state->boot_splash != NULL)
2240+ ply_boot_splash_update_status (state->boot_splash,
2241+ status);
2242+}
2243+
2244+static void
2245+flush_pending_messages (state_t *state)
2246+{
2247+ ply_list_node_t *node = ply_list_get_first_node (state->pending_messages);
2248+ while (node != NULL)
2249+ {
2250+ ply_list_node_t *next_node;
2251+ char *message = ply_list_node_get_data (node);
2252+
2253+ ply_trace ("displaying queued message");
2254+
2255+ ply_boot_splash_display_message (state->boot_splash, message);
2256+ next_node = ply_list_get_next_node (state->pending_messages, node);
2257+ ply_list_remove_node (state->pending_messages, node);
2258+ free(message);
2259+ node = next_node;
2260+ }
2261+}
2262+
2263+static void
2264+show_detailed_splash (state_t *state)
2265+{
2266+ if (state->boot_splash != NULL)
2267+ return;
2268+
2269+ ply_trace ("Showing detailed splash screen");
2270+ state->boot_splash = start_boot_splash (state,
2271+ PLYMOUTH_THEME_PATH "details/details.plymouth");
2272+
2273+ if (state->boot_splash == NULL)
2274+ {
2275+ ply_trace ("Could not start detailed splash screen, exiting");
2276+ exit (1);
2277+ }
2278+}
2279+
2280+static void
2281+find_override_splash (state_t *state)
2282+{
2283+ char *splash_string;
2284+
2285+ if (state->override_splash_path != NULL)
2286+ return;
2287+
2288+ splash_string = strstr (state->kernel_command_line, "plymouth:splash=");
2289+
2290+ if (splash_string != NULL)
2291+ {
2292+ char *end;
2293+ splash_string = strdup (splash_string + strlen ("plymouth:splash="));
2294+
2295+ end = strstr (splash_string, " ");
2296+
2297+ if (end != NULL)
2298+ *end = '\0';
2299+
2300+ ply_trace ("Splash is configured to be '%s'", splash_string);
2301+
2302+ asprintf (&state->override_splash_path,
2303+ PLYMOUTH_THEME_PATH "%s/%s.plymouth",
2304+ splash_string, splash_string);
2305+ }
2306+}
2307+
2308+static void
2309+find_system_default_splash (state_t *state)
2310+{
2311+ ply_key_file_t *key_file;
2312+ char *splash_string;
2313+
2314+ if (state->system_default_splash_path != NULL)
2315+ return;
2316+
2317+ ply_trace ("Trying to load " PLYMOUTH_CONF_DIR "plymouthd.conf");
2318+ key_file = ply_key_file_new (PLYMOUTH_CONF_DIR "plymouthd.conf");
2319+
2320+ if (!ply_key_file_load (key_file))
2321+ {
2322+ ply_trace ("failed to load " PLYMOUTH_CONF_DIR "plymouthd.conf");
2323+ ply_key_file_free (key_file);
2324+ return;
2325+ }
2326+
2327+ splash_string = ply_key_file_get_value (key_file, "Daemon", "Theme");
2328+
2329+ ply_trace ("System default splash is configured to be '%s'", splash_string);
2330+
2331+ asprintf (&state->system_default_splash_path,
2332+ PLYMOUTH_THEME_PATH "%s/%s.plymouth",
2333+ splash_string, splash_string);
2334+ free (splash_string);
2335+}
2336+
2337+static void
2338+find_distribution_default_splash (state_t *state)
2339+{
2340+ ply_key_file_t *key_file;
2341+ char *splash_string;
2342+
2343+ if (state->distribution_default_splash_path != NULL)
2344+ return;
2345+
2346+ ply_trace ("Trying to load " PLYMOUTH_POLICY_DIR "plymouthd.defaults");
2347+ key_file = ply_key_file_new (PLYMOUTH_POLICY_DIR "plymouthd.defaults");
2348+
2349+ if (!ply_key_file_load (key_file))
2350+ {
2351+ ply_trace ("failed to load " PLYMOUTH_POLICY_DIR "plymouthd.defaults");
2352+ ply_key_file_free (key_file);
2353+ return;
2354+ }
2355+
2356+ splash_string = ply_key_file_get_value (key_file, "Daemon", "Theme");
2357+
2358+ ply_trace ("Distribution default splash is configured to be '%s'", splash_string);
2359+
2360+ asprintf (&state->distribution_default_splash_path,
2361+ PLYMOUTH_THEME_PATH "%s/%s.plymouth",
2362+ splash_string, splash_string);
2363+ free (splash_string);
2364+}
2365+
2366+static void
2367+show_default_splash (state_t *state)
2368+{
2369+ if (state->boot_splash != NULL)
2370+ return;
2371+
2372+ ply_trace ("Showing splash screen");
2373+ find_override_splash (state);
2374+ if (state->override_splash_path != NULL)
2375+ {
2376+ ply_trace ("Trying override splash at '%s'", state->override_splash_path);
2377+ state->boot_splash = start_boot_splash (state,
2378+ state->override_splash_path);
2379+ }
2380+
2381+ find_system_default_splash (state);
2382+ if (state->boot_splash == NULL &&
2383+ state->system_default_splash_path != NULL)
2384+ {
2385+ ply_trace ("Trying system default splash");
2386+ state->boot_splash = start_boot_splash (state,
2387+ state->system_default_splash_path);
2388+ }
2389+
2390+ find_distribution_default_splash (state);
2391+ if (state->boot_splash == NULL &&
2392+ state->distribution_default_splash_path != NULL)
2393+ {
2394+ ply_trace ("Trying distribution default splash");
2395+ state->boot_splash = start_boot_splash (state,
2396+ state->distribution_default_splash_path);
2397+ }
2398+
2399+ if (state->boot_splash == NULL)
2400+ {
2401+ ply_trace ("Trying old scheme for default splash");
2402+ state->boot_splash = start_boot_splash (state,
2403+ PLYMOUTH_THEME_PATH "default.plymouth");
2404+ }
2405+
2406+ if (state->boot_splash == NULL)
2407+ {
2408+ ply_trace ("Could not start default splash screen,"
2409+ "showing text splash screen");
2410+ state->boot_splash = start_boot_splash (state,
2411+ PLYMOUTH_THEME_PATH "text.plymouth");
2412+ }
2413+
2414+ if (state->boot_splash == NULL)
2415+ {
2416+ if (errno != ENOENT)
2417+ ply_error ("could not start boot splash: %m");
2418+ show_detailed_splash (state);
2419+ }
2420+}
2421+
2422+static void
2423+on_ask_for_password (state_t *state,
2424+ const char *prompt,
2425+ ply_trigger_t *answer)
2426+{
2427+ ply_entry_trigger_t *entry_trigger;
2428+
2429+ /* No splash, client will have to get password
2430+ */
2431+ if (state->boot_splash == NULL)
2432+ {
2433+ ply_trace ("no splash loaded, replying immediately with no password");
2434+ ply_trigger_pull (answer, NULL);
2435+ return;
2436+ }
2437+
2438+ entry_trigger = calloc (1, sizeof (ply_entry_trigger_t));
2439+ entry_trigger->type = PLY_ENTRY_TRIGGER_TYPE_PASSWORD;
2440+ entry_trigger->prompt = prompt;
2441+ entry_trigger->trigger = answer;
2442+ ply_trace ("queuing password request with boot splash");
2443+ ply_list_append_data (state->entry_triggers, entry_trigger);
2444+ update_display (state);
2445+}
2446+
2447+static void
2448+on_ask_question (state_t *state,
2449+ const char *prompt,
2450+ ply_trigger_t *answer)
2451+{
2452+ ply_entry_trigger_t *entry_trigger;
2453+
2454+ entry_trigger = calloc (1, sizeof (ply_entry_trigger_t));
2455+ entry_trigger->type = PLY_ENTRY_TRIGGER_TYPE_QUESTION;
2456+ entry_trigger->prompt = prompt;
2457+ entry_trigger->trigger = answer;
2458+ ply_trace ("queuing question with boot splash");
2459+ ply_list_append_data (state->entry_triggers, entry_trigger);
2460+ update_display (state);
2461+}
2462+
2463+static void
2464+on_display_message (state_t *state,
2465+ const char *message)
2466+{
2467+ ply_trace ("displaying message %s", message);
2468+ if (state->boot_splash != NULL)
2469+ ply_boot_splash_display_message (state->boot_splash, message);
2470+ else
2471+ ply_list_append_data (state->pending_messages, strdup(message));
2472+}
2473+
2474+static void
2475+on_watch_for_keystroke (state_t *state,
2476+ const char *keys,
2477+ ply_trigger_t *trigger)
2478+{
2479+ ply_keystroke_watch_t *keystroke_trigger =
2480+ calloc (1, sizeof (ply_keystroke_watch_t));
2481+ ply_trace ("watching for keystroke");
2482+ keystroke_trigger->keys = keys;
2483+ keystroke_trigger->trigger = trigger;
2484+ ply_list_append_data (state->keystroke_triggers, keystroke_trigger);
2485+}
2486+
2487+static void
2488+on_ignore_keystroke (state_t *state,
2489+ const char *keys)
2490+{
2491+ ply_list_node_t *node;
2492+
2493+ ply_trace ("ignoring for keystroke");
2494+
2495+ for (node = ply_list_get_first_node (state->keystroke_triggers); node;
2496+ node = ply_list_get_next_node (state->keystroke_triggers, node))
2497+ {
2498+ ply_keystroke_watch_t* keystroke_trigger = ply_list_node_get_data (node);
2499+ if ((!keystroke_trigger->keys && !keys) ||
2500+ (keystroke_trigger->keys && keys && strcmp(keystroke_trigger->keys, keys)==0))
2501+ {
2502+ ply_trigger_pull (keystroke_trigger->trigger, NULL);
2503+ ply_list_remove_node (state->keystroke_triggers, node);
2504+ return;
2505+ }
2506+ }
2507+}
2508+
2509+static void
2510+on_progress_pause (state_t *state)
2511+{
2512+ ply_trace ("pausing progress");
2513+ ply_progress_pause (state->progress);
2514+}
2515+
2516+static void
2517+on_progress_unpause (state_t *state)
2518+{
2519+ ply_trace ("unpausing progress");
2520+ ply_progress_unpause (state->progress);
2521+}
2522+
2523+static void
2524+on_newroot (state_t *state,
2525+ const char *root_dir)
2526+{
2527+ if (state->mode != PLY_MODE_BOOT)
2528+ {
2529+ ply_trace ("new root is only supported in boot mode ");
2530+ return;
2531+ }
2532+
2533+ ply_trace ("new root mounted at \"%s\", switching to it", root_dir);
2534+ chdir(root_dir);
2535+ chroot(".");
2536+ chdir("/");
2537+ ply_progress_load_cache (state->progress, BOOT_DURATION_FILE);
2538+ if (state->boot_splash != NULL)
2539+ ply_boot_splash_root_mounted (state->boot_splash);
2540+}
2541+
2542+static const char *
2543+get_cache_file_for_mode (ply_mode_t mode)
2544+{
2545+ const char *filename;
2546+
2547+ switch ((int)mode)
2548+ {
2549+ case PLY_MODE_BOOT:
2550+ filename = BOOT_DURATION_FILE;
2551+ break;
2552+ case PLY_MODE_SHUTDOWN:
2553+ filename = SHUTDOWN_DURATION_FILE;
2554+ break;
2555+ default:
2556+ fprintf (stderr, "Unhandled case in %s line %d\n", __FILE__, __LINE__);
2557+ abort ();
2558+ break;
2559+ }
2560+
2561+ ply_trace ("returning cache file '%s'", filename);
2562+ return filename;
2563+}
2564+
2565+static const char *
2566+get_log_file_for_mode (ply_mode_t mode)
2567+{
2568+ const char *filename;
2569+
2570+ switch ((int)mode)
2571+ {
2572+ case PLY_MODE_BOOT:
2573+ filename = PLYMOUTH_LOG_DIRECTORY "/boot.log";
2574+ break;
2575+ case PLY_MODE_SHUTDOWN:
2576+ filename = _PATH_DEVNULL;
2577+ break;
2578+ default:
2579+ fprintf (stderr, "Unhandled case in %s line %d\n", __FILE__, __LINE__);
2580+ abort ();
2581+ break;
2582+ }
2583+
2584+ ply_trace ("returning log file '%s'", filename);
2585+ return filename;
2586+}
2587+
2588+static const char *
2589+get_log_spool_file_for_mode (ply_mode_t mode)
2590+{
2591+ const char *filename;
2592+
2593+ switch ((int)mode)
2594+ {
2595+ case PLY_MODE_BOOT:
2596+ filename = PLYMOUTH_SPOOL_DIRECTORY "/boot.log";
2597+ break;
2598+ case PLY_MODE_SHUTDOWN:
2599+ filename = NULL;
2600+ break;
2601+ default:
2602+ fprintf (stderr, "Unhandled case in %s line %d\n", __FILE__, __LINE__);
2603+ abort ();
2604+ break;
2605+ }
2606+
2607+ ply_trace ("returning spool file '%s'", filename);
2608+ return filename;
2609+}
2610+
2611+static void
2612+spool_error (state_t *state)
2613+{
2614+ const char *logfile;
2615+ const char *logspool;
2616+
2617+ ply_trace ("spooling error for viewer");
2618+
2619+ logfile = get_log_file_for_mode (state->mode);
2620+ logspool = get_log_spool_file_for_mode (state->mode);
2621+
2622+ if (logfile != NULL && logspool != NULL)
2623+ {
2624+ unlink (logspool);
2625+
2626+ ply_create_file_link (logfile, logspool);
2627+ }
2628+}
2629+
2630+static void
2631+prepare_logging (state_t *state)
2632+{
2633+ const char *logfile;
2634+
2635+ if (!state->system_initialized)
2636+ {
2637+ ply_trace ("not preparing logging yet, system not initialized");
2638+ return;
2639+ }
2640+
2641+ if (state->session == NULL)
2642+ {
2643+ ply_trace ("not preparing logging, no session");
2644+ return;
2645+ }
2646+
2647+ logfile = get_log_file_for_mode (state->mode);
2648+ if (logfile != NULL)
2649+ {
2650+ ply_trace ("opening log '%s'", logfile);
2651+ ply_terminal_session_open_log (state->session, logfile);
2652+
2653+ if (state->number_of_errors > 0)
2654+ spool_error (state);
2655+ }
2656+}
2657+
2658+static void
2659+on_system_initialized (state_t *state)
2660+{
2661+ ply_trace ("system now initialized, opening log");
2662+ state->system_initialized = true;
2663+
2664+ prepare_logging (state);
2665+}
2666+
2667+static void
2668+on_error (state_t *state)
2669+{
2670+ ply_trace ("encountered error during boot up");
2671+
2672+ if (state->system_initialized && state->number_of_errors == 0)
2673+ spool_error (state);
2674+ else
2675+ ply_trace ("not spooling because number of errors %d", state->number_of_errors);
2676+
2677+ state->number_of_errors++;
2678+}
2679+
2680+static bool
2681+plymouth_should_ignore_show_splash_calls (state_t *state)
2682+{
2683+ ply_trace ("checking if plymouth should be running");
2684+ if (state->mode != PLY_MODE_BOOT || ply_string_has_prefix (state->kernel_command_line, "plymouth:force-splash") || strstr (state->kernel_command_line, " plymouth:force-splash") != NULL)
2685+ return false;
2686+
2687+ return ply_string_has_prefix (state->kernel_command_line, "init=") || strstr (state->kernel_command_line, " init=") != NULL;
2688+}
2689+
2690+static bool
2691+plymouth_should_show_default_splash (state_t *state)
2692+{
2693+ ply_trace ("checking if plymouth should show default splash");
2694+
2695+ const char const *strings[] = {
2696+ " single ", " single\n", "^single ",
2697+ " 1 ", " 1\n", "^1 ",
2698+ " s ", " s\n", "^s ",
2699+ " S ", " S\n", "^S ",
2700+ " -s ", " -s\n", "^-s ",
2701+ NULL
2702+ };
2703+ int i;
2704+
2705+ if (state->kernel_console_tty != NULL)
2706+ return false;
2707+
2708+ for (i = 0; strings[i] != NULL; i++)
2709+ {
2710+ int cmp;
2711+ if (strings[i][0] == '^')
2712+ cmp = strncmp(state->kernel_command_line, strings[i]+1,
2713+ strlen(strings[i]+1)) == 0;
2714+ else
2715+ cmp = strstr (state->kernel_command_line, strings[i]) != NULL;
2716+
2717+ if (cmp)
2718+ {
2719+ ply_trace ("kernel command line has option \"%s\"", strings[i]);
2720+ return false;
2721+ }
2722+ }
2723+
2724+ return strstr (state->kernel_command_line, "rhgb") != NULL || (strstr (state->kernel_command_line, "splash") != NULL && strstr(state->kernel_command_line, "splash=verbose") == NULL);
2725+}
2726+
2727+static void
2728+remove_displays_and_keyboard (state_t *state)
2729+{
2730+ ply_list_node_t *node;
2731+ ply_trace ("removing displays and keyboard");
2732+
2733+ node = ply_list_get_first_node (state->pixel_displays);
2734+ while (node != NULL)
2735+ {
2736+ ply_list_node_t *next_node;
2737+ ply_pixel_display_t *display;
2738+
2739+ ply_trace ("removing pixel display");
2740+ next_node = ply_list_get_next_node (state->pixel_displays, node);
2741+ display = ply_list_node_get_data (node);
2742+ ply_pixel_display_free (display);
2743+
2744+ ply_list_remove_node (state->pixel_displays, node);
2745+
2746+ node = next_node;
2747+ }
2748+
2749+ node = ply_list_get_first_node (state->text_displays);
2750+ while (node != NULL)
2751+ {
2752+ ply_list_node_t *next_node;
2753+ ply_text_display_t *display;
2754+
2755+ ply_trace ("removing text display");
2756+ next_node = ply_list_get_next_node (state->text_displays, node);
2757+ display = ply_list_node_get_data (node);
2758+ ply_text_display_free (display);
2759+
2760+ ply_list_remove_node (state->text_displays, node);
2761+
2762+ node = next_node;
2763+ }
2764+
2765+ if (state->keyboard != NULL)
2766+ {
2767+ ply_trace ("removing keyboard");
2768+ ply_keyboard_stop_watching_for_input (state->keyboard);
2769+ ply_keyboard_free (state->keyboard);
2770+ state->keyboard = NULL;
2771+ }
2772+}
2773+
2774+static void
2775+on_show_splash (state_t *state)
2776+{
2777+ bool has_display;
2778+
2779+ if (state->is_inactive)
2780+ {
2781+ ply_trace ("show splash called while inactive");
2782+ return;
2783+ }
2784+
2785+ if (plymouth_should_ignore_show_splash_calls (state))
2786+ {
2787+ ply_trace ("show splash called while ignoring show splash calls");
2788+ dump_details_and_quit_splash (state);
2789+ return;
2790+ }
2791+
2792+ check_for_consoles (state, state->default_tty, true);
2793+
2794+ has_display = ply_list_get_length (state->pixel_displays) > 0 ||
2795+ ply_list_get_length (state->text_displays) > 0;
2796+
2797+ if (!state->is_attached && state->should_be_attached && has_display)
2798+ attach_to_running_session (state);
2799+
2800+ if (!has_display && state->is_attached)
2801+ {
2802+ ply_trace ("no open seats, detaching session");
2803+ ply_terminal_session_detach (state->session);
2804+ state->is_redirected = false;
2805+ state->is_attached = false;
2806+ }
2807+
2808+ if (plymouth_should_show_default_splash (state))
2809+ {
2810+ show_default_splash (state);
2811+ state->showing_details = false;
2812+ }
2813+ else
2814+ {
2815+ show_detailed_splash (state);
2816+ state->showing_details = true;
2817+ }
2818+ flush_pending_messages (state);
2819+}
2820+
2821+static void
2822+quit_splash (state_t *state)
2823+{
2824+ ply_trace ("quiting splash");
2825+ if (state->boot_splash != NULL)
2826+ {
2827+ ply_trace ("freeing splash");
2828+ ply_boot_splash_free (state->boot_splash);
2829+ state->boot_splash = NULL;
2830+ }
2831+
2832+ ply_trace ("removing displays and keyboard");
2833+ remove_displays_and_keyboard (state);
2834+
2835+ if (state->renderer != NULL)
2836+ {
2837+ ply_renderer_close (state->renderer);
2838+ ply_renderer_free (state->renderer);
2839+ state->renderer = NULL;
2840+ }
2841+
2842+ if (state->terminal != NULL)
2843+ {
2844+ if (!state->should_retain_splash)
2845+ {
2846+ ply_trace ("Not retaining splash, so deallocating VT");
2847+ ply_terminal_deactivate_vt (state->terminal);
2848+ }
2849+ ply_terminal_close (state->terminal);
2850+ ply_terminal_free (state->terminal);
2851+ state->terminal = NULL;
2852+ }
2853+
2854+ if (state->session != NULL)
2855+ {
2856+ ply_trace ("detaching session");
2857+ ply_terminal_session_detach (state->session);
2858+ state->is_redirected = false;
2859+ state->is_attached = false;
2860+ }
2861+}
2862+
2863+static void
2864+dump_details_and_quit_splash (state_t *state)
2865+{
2866+ state->showing_details = false;
2867+ toggle_between_splash_and_details (state);
2868+
2869+ if (state->renderer != NULL)
2870+ ply_renderer_deactivate (state->renderer);
2871+ if (state->boot_splash != NULL)
2872+ ply_boot_splash_hide (state->boot_splash);
2873+
2874+ quit_splash (state);
2875+}
2876+
2877+static void
2878+on_hide_splash (state_t *state)
2879+{
2880+ if (state->is_inactive)
2881+ return;
2882+
2883+ if (state->boot_splash == NULL)
2884+ return;
2885+
2886+ ply_trace ("hiding boot splash");
2887+ dump_details_and_quit_splash (state);
2888+}
2889+
2890+#ifdef PLY_ENABLE_GDM_TRANSITION
2891+static void
2892+tell_gdm_to_transition (void)
2893+{
2894+ int fd;
2895+
2896+ fd = creat ("/var/spool/gdm/force-display-on-active-vt", 0644);
2897+ close (fd);
2898+}
2899+#endif
2900+
2901+static void
2902+quit_program (state_t *state)
2903+{
2904+ ply_trace ("exiting event loop");
2905+ ply_event_loop_exit (state->loop, 0);
2906+
2907+ if (pid_file != NULL)
2908+ {
2909+ unlink (pid_file);
2910+ free (pid_file);
2911+ pid_file = NULL;
2912+ }
2913+
2914+#ifdef PLY_ENABLE_GDM_TRANSITION
2915+ if (state->should_retain_splash)
2916+ {
2917+ tell_gdm_to_transition ();
2918+ }
2919+#endif
2920+
2921+ if (state->deactivate_trigger != NULL)
2922+ {
2923+ ply_trigger_pull (state->deactivate_trigger, NULL);
2924+ state->deactivate_trigger = NULL;
2925+ }
2926+ if (state->quit_trigger != NULL)
2927+ {
2928+ ply_trigger_pull (state->quit_trigger, NULL);
2929+ state->quit_trigger = NULL;
2930+ }
2931+}
2932+
2933+static void
2934+deactivate_splash (state_t *state)
2935+{
2936+ assert (!state->is_inactive);
2937+
2938+ if (state->renderer != NULL)
2939+ {
2940+ ply_trace ("deactivating renderer");
2941+ ply_renderer_deactivate (state->renderer);
2942+ }
2943+
2944+ if (state->keyboard != NULL)
2945+ {
2946+ ply_trace ("deactivating keyboard");
2947+ ply_keyboard_stop_watching_for_input (state->keyboard);
2948+ }
2949+
2950+ if ((state->session != NULL) && state->is_attached)
2951+ {
2952+ ply_trace ("deactivating terminal session");
2953+ ply_terminal_session_detach (state->session);
2954+ state->is_redirected = false;
2955+ state->is_attached = false;
2956+ }
2957+
2958+ if (state->terminal != NULL)
2959+ {
2960+ ply_trace ("deactivating terminal");
2961+ ply_terminal_stop_watching_for_vt_changes (state->terminal);
2962+ ply_terminal_set_buffered_input (state->terminal);
2963+ ply_terminal_ignore_mode_changes (state->terminal, true);
2964+ }
2965+
2966+ state->is_inactive = true;
2967+
2968+ ply_trigger_pull (state->deactivate_trigger, NULL);
2969+ state->deactivate_trigger = NULL;
2970+}
2971+
2972+static void
2973+on_boot_splash_idle (state_t *state)
2974+{
2975+ ply_trace ("boot splash idle");
2976+
2977+ /* In the case where we've received both a deactivate command and a
2978+ * quit command, the quit command takes precedence.
2979+ */
2980+ if (state->quit_trigger != NULL)
2981+ {
2982+ if (!state->should_retain_splash)
2983+ {
2984+ ply_trace ("hiding splash");
2985+ if (state->renderer != NULL)
2986+ ply_renderer_deactivate (state->renderer);
2987+ if (state->boot_splash != NULL)
2988+ ply_boot_splash_hide (state->boot_splash);
2989+ }
2990+
2991+ ply_trace ("quitting splash");
2992+ quit_splash (state);
2993+ ply_trace ("quitting program");
2994+ quit_program (state);
2995+ }
2996+ else if (state->deactivate_trigger != NULL)
2997+ {
2998+ ply_trace ("deactivating splash");
2999+ deactivate_splash (state);
3000+ }
3001+}
3002+
3003+
3004+static void
3005+on_deactivate (state_t *state,
3006+ ply_trigger_t *deactivate_trigger)
3007+{
3008+ if ((state->deactivate_trigger != NULL) || state->is_inactive)
3009+ {
3010+ ply_trigger_add_handler (state->deactivate_trigger,
3011+ (ply_trigger_handler_t)
3012+ ply_trigger_pull,
3013+ deactivate_trigger);
3014+ return;
3015+ }
3016+
3017+ state->deactivate_trigger = deactivate_trigger;
3018+
3019+ ply_trace ("deactivating");
3020+ if (state->boot_splash != NULL)
3021+ {
3022+ ply_boot_splash_become_idle (state->boot_splash,
3023+ (ply_boot_splash_on_idle_handler_t)
3024+ on_boot_splash_idle,
3025+ state);
3026+ }
3027+ else
3028+ {
3029+ ply_trace ("deactivating splash");
3030+ deactivate_splash (state);
3031+ }
3032+}
3033+
3034+static void
3035+on_reactivate (state_t *state)
3036+{
3037+ if (!state->is_inactive)
3038+ return;
3039+
3040+ if (state->terminal != NULL)
3041+ {
3042+ ply_terminal_watch_for_vt_changes (state->terminal);
3043+ ply_terminal_set_unbuffered_input (state->terminal);
3044+ ply_terminal_ignore_mode_changes (state->terminal, false);
3045+ }
3046+
3047+ if ((state->session != NULL) && state->should_be_attached)
3048+ {
3049+ ply_trace ("reactivating terminal session");
3050+ attach_to_running_session (state);
3051+ }
3052+
3053+ if (state->keyboard != NULL)
3054+ {
3055+ ply_trace ("activating keyboard");
3056+ ply_keyboard_watch_for_input (state->keyboard);
3057+ }
3058+
3059+ if (state->renderer != NULL)
3060+ {
3061+ ply_trace ("activating renderer");
3062+ ply_renderer_activate (state->renderer);
3063+ }
3064+
3065+ state->is_inactive = false;
3066+
3067+ update_display (state);
3068+}
3069+
3070+static void
3071+on_quit (state_t *state,
3072+ bool retain_splash,
3073+ ply_trigger_t *quit_trigger)
3074+{
3075+ if (state->quit_trigger != NULL)
3076+ {
3077+ ply_trigger_add_handler (state->quit_trigger,
3078+ (ply_trigger_handler_t)
3079+ ply_trigger_pull,
3080+ quit_trigger);
3081+ return;
3082+ }
3083+
3084+ state->quit_trigger = quit_trigger;
3085+ state->should_retain_splash = retain_splash;
3086+
3087+ ply_trace ("time to quit, closing log");
3088+ if (state->session != NULL)
3089+ ply_terminal_session_close_log (state->session);
3090+ ply_trace ("unloading splash");
3091+
3092+ if (state->is_inactive && !retain_splash)
3093+ {
3094+ /* We've been deactivated and X failed to start
3095+ */
3096+ dump_details_and_quit_splash (state);
3097+ quit_program (state);
3098+ }
3099+ else if (state->boot_splash != NULL)
3100+ {
3101+ ply_boot_splash_become_idle (state->boot_splash,
3102+ (ply_boot_splash_on_idle_handler_t)
3103+ on_boot_splash_idle,
3104+ state);
3105+ }
3106+ else
3107+ quit_program (state);
3108+}
3109+
3110+static bool
3111+on_has_active_vt (state_t *state)
3112+{
3113+ if (state->terminal != NULL)
3114+ return ply_terminal_is_active (state->terminal);
3115+ else
3116+ return false;
3117+}
3118+
3119+static ply_boot_server_t *
3120+start_boot_server (state_t *state)
3121+{
3122+ ply_boot_server_t *server;
3123+
3124+ server = ply_boot_server_new ((ply_boot_server_update_handler_t) on_update,
3125+ (ply_boot_server_ask_for_password_handler_t) on_ask_for_password,
3126+ (ply_boot_server_ask_question_handler_t) on_ask_question,
3127+ (ply_boot_server_display_message_handler_t) on_display_message,
3128+ (ply_boot_server_watch_for_keystroke_handler_t) on_watch_for_keystroke,
3129+ (ply_boot_server_ignore_keystroke_handler_t) on_ignore_keystroke,
3130+ (ply_boot_server_progress_pause_handler_t) on_progress_pause,
3131+ (ply_boot_server_progress_unpause_handler_t) on_progress_unpause,
3132+ (ply_boot_server_show_splash_handler_t) on_show_splash,
3133+ (ply_boot_server_hide_splash_handler_t) on_hide_splash,
3134+ (ply_boot_server_newroot_handler_t) on_newroot,
3135+ (ply_boot_server_system_initialized_handler_t) on_system_initialized,
3136+ (ply_boot_server_error_handler_t) on_error,
3137+ (ply_boot_server_deactivate_handler_t) on_deactivate,
3138+ (ply_boot_server_reactivate_handler_t) on_reactivate,
3139+ (ply_boot_server_quit_handler_t) on_quit,
3140+ (ply_boot_server_has_active_vt_handler_t) on_has_active_vt,
3141+ state);
3142+
3143+ if (!ply_boot_server_listen (server))
3144+ {
3145+ ply_save_errno ();
3146+ ply_boot_server_free (server);
3147+ ply_restore_errno ();
3148+ return NULL;
3149+ }
3150+
3151+ ply_boot_server_attach_to_event_loop (server, state->loop);
3152+
3153+ return server;
3154+}
3155+
3156+
3157+static void
3158+update_display (state_t *state)
3159+{
3160+ if (!state->boot_splash) return;
3161+
3162+ ply_list_node_t *node;
3163+ node = ply_list_get_first_node (state->entry_triggers);
3164+ if (node)
3165+ {
3166+ ply_entry_trigger_t* entry_trigger = ply_list_node_get_data (node);
3167+ if (entry_trigger->type == PLY_ENTRY_TRIGGER_TYPE_PASSWORD)
3168+ {
3169+ int bullets = ply_utf8_string_get_length (ply_buffer_get_bytes (state->entry_buffer),
3170+ ply_buffer_get_size (state->entry_buffer));
3171+ bullets = MAX(0, bullets);
3172+ ply_boot_splash_display_password (state->boot_splash,
3173+ entry_trigger->prompt,
3174+ bullets);
3175+ }
3176+ else if (entry_trigger->type == PLY_ENTRY_TRIGGER_TYPE_QUESTION)
3177+ {
3178+ ply_boot_splash_display_question (state->boot_splash,
3179+ entry_trigger->prompt,
3180+ ply_buffer_get_bytes (state->entry_buffer));
3181+ }
3182+ else {
3183+ ply_trace("unkown entry type");
3184+ }
3185+ }
3186+ else
3187+ {
3188+ ply_boot_splash_display_normal (state->boot_splash);
3189+ }
3190+
3191+}
3192+
3193+static void
3194+toggle_between_splash_and_details (state_t *state)
3195+{
3196+ ply_trace ("toggling between splash and details");
3197+ if (state->boot_splash != NULL)
3198+ {
3199+ ply_trace ("hiding and freeing current splash");
3200+ ply_boot_splash_hide (state->boot_splash);
3201+ ply_boot_splash_free (state->boot_splash);
3202+ state->boot_splash = NULL;
3203+ }
3204+
3205+ if (!state->showing_details)
3206+ {
3207+ show_detailed_splash (state);
3208+ state->showing_details = true;
3209+ }
3210+ else
3211+ {
3212+ show_default_splash (state);
3213+ state->showing_details = false;
3214+ }
3215+ update_display (state);
3216+}
3217+
3218+static void
3219+on_escape_pressed (state_t *state)
3220+{
3221+ ply_trace ("escape key pressed");
3222+ toggle_between_splash_and_details (state);
3223+}
3224+
3225+static void
3226+on_keyboard_input (state_t *state,
3227+ const char *keyboard_input,
3228+ size_t character_size)
3229+{
3230+ ply_list_node_t *node;
3231+ node = ply_list_get_first_node (state->entry_triggers);
3232+ if (node)
3233+ { /* \x3 (ETX) is Ctrl+C and \x4 (EOT) is Ctrl+D */
3234+ if (character_size == 1 && ( keyboard_input[0] == '\x3' || keyboard_input[0] == '\x4' ))
3235+ {
3236+ ply_entry_trigger_t* entry_trigger = ply_list_node_get_data (node);
3237+ ply_trigger_pull (entry_trigger->trigger, "\x3");
3238+ ply_buffer_clear (state->entry_buffer);
3239+ ply_list_remove_node (state->entry_triggers, node);
3240+ free (entry_trigger);
3241+ }
3242+ else
3243+ {
3244+ ply_buffer_append_bytes (state->entry_buffer, keyboard_input, character_size);
3245+ }
3246+ update_display (state);
3247+ }
3248+ else
3249+ {
3250+ for (node = ply_list_get_first_node (state->keystroke_triggers); node;
3251+ node = ply_list_get_next_node (state->keystroke_triggers, node))
3252+ {
3253+ ply_keystroke_watch_t* keystroke_trigger = ply_list_node_get_data (node);
3254+ if (!keystroke_trigger->keys || strstr(keystroke_trigger->keys, keyboard_input)) /* assume strstr works on utf8 arrays */
3255+ {
3256+ ply_trigger_pull (keystroke_trigger->trigger, keyboard_input);
3257+ ply_list_remove_node (state->keystroke_triggers, node);
3258+ free(keystroke_trigger);
3259+ return;
3260+ }
3261+ }
3262+ return;
3263+ }
3264+}
3265+
3266+static void
3267+on_backspace (state_t *state)
3268+{
3269+ ssize_t bytes_to_remove;
3270+ ssize_t previous_character_size;
3271+ const char *bytes;
3272+ size_t size;
3273+ ply_list_node_t *node = ply_list_get_first_node (state->entry_triggers);
3274+ if (!node) return;
3275+
3276+ bytes = ply_buffer_get_bytes (state->entry_buffer);
3277+ size = ply_buffer_get_size (state->entry_buffer);
3278+
3279+ bytes_to_remove = MIN(size, PLY_UTF8_CHARACTER_SIZE_MAX);
3280+ while ((previous_character_size = ply_utf8_character_get_size (bytes + size - bytes_to_remove, bytes_to_remove)) < bytes_to_remove)
3281+ {
3282+ if (previous_character_size > 0)
3283+ bytes_to_remove -= previous_character_size;
3284+ else
3285+ bytes_to_remove--;
3286+ }
3287+
3288+ ply_buffer_remove_bytes_at_end (state->entry_buffer, bytes_to_remove);
3289+ update_display (state);
3290+}
3291+
3292+static void
3293+on_enter (state_t *state,
3294+ const char *line)
3295+{
3296+ ply_list_node_t *node;
3297+ node = ply_list_get_first_node (state->entry_triggers);
3298+ if (node)
3299+ {
3300+ ply_entry_trigger_t* entry_trigger = ply_list_node_get_data (node);
3301+ const char* reply_text = ply_buffer_get_bytes (state->entry_buffer);
3302+ ply_trigger_pull (entry_trigger->trigger, reply_text);
3303+ ply_buffer_clear (state->entry_buffer);
3304+ ply_list_remove_node (state->entry_triggers, node);
3305+ free (entry_trigger);
3306+ update_display (state);
3307+ }
3308+ else
3309+ {
3310+ for (node = ply_list_get_first_node (state->keystroke_triggers); node;
3311+ node = ply_list_get_next_node (state->keystroke_triggers, node))
3312+ {
3313+ ply_keystroke_watch_t* keystroke_trigger = ply_list_node_get_data (node);
3314+ if (!keystroke_trigger->keys || strstr(keystroke_trigger->keys, "\n")) /* assume strstr works on utf8 arrays */
3315+ {
3316+ ply_trigger_pull (keystroke_trigger->trigger, line);
3317+ ply_list_remove_node (state->keystroke_triggers, node);
3318+ free(keystroke_trigger);
3319+ return;
3320+ }
3321+ }
3322+ return;
3323+ }
3324+}
3325+
3326+static void
3327+set_keyboard (state_t *state,
3328+ ply_keyboard_t *keyboard)
3329+{
3330+ state->keyboard = keyboard;
3331+
3332+ ply_keyboard_add_escape_handler (keyboard, (ply_keyboard_escape_handler_t)
3333+ on_escape_pressed, state);
3334+ ply_trace ("listening for keystrokes");
3335+ ply_keyboard_add_input_handler (keyboard,
3336+ (ply_keyboard_input_handler_t)
3337+ on_keyboard_input, state);
3338+ ply_trace ("listening for backspace");
3339+ ply_keyboard_add_backspace_handler (keyboard,
3340+ (ply_keyboard_backspace_handler_t)
3341+ on_backspace, state);
3342+ ply_trace ("listening for enter");
3343+ ply_keyboard_add_enter_handler (keyboard,
3344+ (ply_keyboard_enter_handler_t)
3345+ on_enter, state);
3346+}
3347+static void
3348+add_display_and_keyboard_for_terminal (state_t *state,
3349+ const char *tty_name)
3350+{
3351+ ply_text_display_t *display;
3352+ ply_keyboard_t *keyboard;
3353+
3354+ ply_trace ("adding display and keyboard for %s", tty_name);
3355+
3356+ state->terminal = ply_terminal_new (tty_name);
3357+
3358+ // urgh
3359+ if (!ply_terminal_open (state->terminal))
3360+ return;
3361+
3362+ keyboard = ply_keyboard_new_for_terminal (state->terminal);
3363+ display = ply_text_display_new (state->terminal);
3364+
3365+ ply_list_append_data (state->text_displays, display);
3366+ state->keyboard = keyboard;
3367+ set_keyboard (state, keyboard);
3368+}
3369+
3370+static void
3371+add_pixel_displays_from_renderer (state_t *state,
3372+ ply_renderer_t *renderer)
3373+{
3374+ ply_list_t *heads;
3375+ ply_list_node_t *node;
3376+
3377+ heads = ply_renderer_get_heads (renderer);
3378+
3379+ ply_trace ("Adding displays for %d heads",
3380+ ply_list_get_length (heads));
3381+
3382+ node = ply_list_get_first_node (heads);
3383+ while (node != NULL)
3384+ {
3385+ ply_list_node_t *next_node;
3386+ ply_renderer_head_t *head;
3387+ ply_pixel_display_t *display;
3388+
3389+ head = ply_list_node_get_data (node);
3390+ next_node = ply_list_get_next_node (heads, node);
3391+
3392+ display = ply_pixel_display_new (renderer, head);
3393+
3394+ ply_list_append_data (state->pixel_displays, display);
3395+
3396+ node = next_node;
3397+ }
3398+
3399+}
3400+
3401+static void
3402+add_default_displays_and_keyboard (state_t *state)
3403+{
3404+ ply_renderer_t *renderer;
3405+ ply_keyboard_t *keyboard;
3406+ ply_terminal_t *terminal;
3407+ ply_text_display_t *text_display;
3408+
3409+ ply_trace ("adding default displays and keyboard");
3410+
3411+ terminal = ply_terminal_new (state->default_tty);
3412+
3413+ renderer = ply_renderer_new (NULL, terminal);
3414+
3415+ if (!ply_renderer_open (renderer))
3416+ {
3417+ ply_trace ("could not open renderer /dev/fb");
3418+ ply_renderer_free (renderer);
3419+ ply_terminal_free (terminal);
3420+
3421+ add_display_and_keyboard_for_terminal (state, state->default_tty);
3422+ return;
3423+ }
3424+
3425+ state->terminal = terminal;
3426+
3427+ keyboard = ply_keyboard_new_for_renderer (renderer);
3428+ set_keyboard (state, keyboard);
3429+
3430+ add_pixel_displays_from_renderer (state, renderer);
3431+
3432+ text_display = ply_text_display_new (state->terminal);
3433+ ply_list_append_data (state->text_displays, text_display);
3434+
3435+ state->renderer = renderer;
3436+}
3437+
3438+static void
3439+add_displays_and_keyboard_to_boot_splash (state_t *state,
3440+ ply_boot_splash_t *splash)
3441+{
3442+ ply_list_node_t *node;
3443+
3444+ ply_trace ("setting keyboard on boot splash");
3445+ if (state->keyboard != NULL)
3446+ ply_boot_splash_set_keyboard (splash, state->keyboard);
3447+
3448+ node = ply_list_get_first_node (state->pixel_displays);
3449+ while (node != NULL)
3450+ {
3451+ ply_pixel_display_t *display;
3452+ ply_list_node_t *next_node;
3453+
3454+ display = ply_list_node_get_data (node);
3455+ next_node = ply_list_get_next_node (state->pixel_displays, node);
3456+ ply_trace ("adding pixel display on boot splash");
3457+ ply_boot_splash_add_pixel_display (splash, display);
3458+
3459+ node = next_node;
3460+ }
3461+
3462+ node = ply_list_get_first_node (state->text_displays);
3463+ while (node != NULL)
3464+ {
3465+ ply_text_display_t *display;
3466+ ply_list_node_t *next_node;
3467+
3468+ display = ply_list_node_get_data (node);
3469+ next_node = ply_list_get_next_node (state->text_displays, node);
3470+
3471+ ply_trace ("adding text display on boot splash");
3472+ ply_boot_splash_add_text_display (splash, display);
3473+
3474+ node = next_node;
3475+ }
3476+}
3477+
3478+static ply_boot_splash_t *
3479+start_boot_splash (state_t *state,
3480+ const char *theme_path)
3481+{
3482+ ply_boot_splash_t *splash;
3483+ ply_boot_splash_mode_t splash_mode;
3484+
3485+ ply_trace ("Loading boot splash theme '%s'",
3486+ theme_path);
3487+
3488+ splash = ply_boot_splash_new (theme_path,
3489+ PLYMOUTH_PLUGIN_PATH,
3490+ state->boot_buffer,
3491+ state->terminal);
3492+
3493+ if (!ply_boot_splash_load (splash))
3494+ {
3495+ ply_save_errno ();
3496+ ply_boot_splash_free (splash);
3497+ ply_restore_errno ();
3498+ return NULL;
3499+ }
3500+
3501+ ply_trace ("attaching plugin to event loop");
3502+ ply_boot_splash_attach_to_event_loop (splash, state->loop);
3503+
3504+ ply_trace ("attaching progress to plugin");
3505+ ply_boot_splash_attach_progress (splash, state->progress);
3506+
3507+ add_displays_and_keyboard_to_boot_splash (state, splash);
3508+
3509+ ply_trace ("showing plugin");
3510+ if (state->mode == PLY_MODE_SHUTDOWN)
3511+ splash_mode = PLY_BOOT_SPLASH_MODE_SHUTDOWN;
3512+ else
3513+ splash_mode = PLY_BOOT_SPLASH_MODE_BOOT_UP;
3514+
3515+ if (!ply_boot_splash_show (splash, splash_mode))
3516+ {
3517+ ply_save_errno ();
3518+ ply_boot_splash_unset_keyboard (splash);
3519+ ply_boot_splash_free (splash);
3520+ ply_restore_errno ();
3521+ return NULL;
3522+ }
3523+
3524+ ply_keyboard_watch_for_input (state->keyboard);
3525+
3526+ update_display (state);
3527+ return splash;
3528+}
3529+
3530+static bool
3531+attach_to_running_session (state_t *state)
3532+{
3533+ ply_terminal_session_t *session;
3534+ ply_terminal_session_flags_t flags;
3535+ bool should_be_redirected;
3536+
3537+ flags = 0;
3538+
3539+ should_be_redirected = !state->no_boot_log;
3540+
3541+ if (should_be_redirected)
3542+ flags |= PLY_TERMINAL_SESSION_FLAGS_REDIRECT_CONSOLE;
3543+
3544+ if (state->session == NULL)
3545+ {
3546+ ply_trace ("creating new terminal session");
3547+ session = ply_terminal_session_new (NULL);
3548+
3549+ ply_terminal_session_attach_to_event_loop (session, state->loop);
3550+ }
3551+ else
3552+ {
3553+ session = state->session;
3554+ ply_trace ("session already created");
3555+ }
3556+
3557+ if (!ply_terminal_session_attach (session, flags,
3558+ (ply_terminal_session_output_handler_t)
3559+ on_session_output,
3560+ (ply_terminal_session_done_handler_t)
3561+ (should_be_redirected? on_session_finished: NULL),
3562+ -1, state))
3563+ {
3564+ ply_save_errno ();
3565+ ply_terminal_session_free (session);
3566+ ply_buffer_free (state->boot_buffer);
3567+ state->boot_buffer = NULL;
3568+ ply_restore_errno ();
3569+
3570+ state->is_redirected = false;
3571+ state->is_attached = false;
3572+ return false;
3573+ }
3574+
3575+ state->is_redirected = should_be_redirected;
3576+ state->is_attached = true;
3577+ state->session = session;
3578+
3579+ return true;
3580+}
3581+
3582+static bool
3583+get_kernel_command_line (state_t *state)
3584+{
3585+ int fd;
3586+
3587+ ply_trace ("opening /proc/cmdline");
3588+ fd = open ("proc/cmdline", O_RDONLY);
3589+
3590+ if (fd < 0)
3591+ {
3592+ ply_trace ("couldn't open it: %m");
3593+ return false;
3594+ }
3595+
3596+ ply_trace ("reading kernel command line");
3597+ if (read (fd, state->kernel_command_line, sizeof (state->kernel_command_line)) < 0)
3598+ {
3599+ ply_trace ("couldn't read it: %m");
3600+ return false;
3601+ }
3602+
3603+ ply_trace ("Kernel command line is: '%s'", state->kernel_command_line);
3604+ close (fd);
3605+ return true;
3606+}
3607+
3608+static void
3609+check_verbosity (state_t *state)
3610+{
3611+ char *path;
3612+
3613+ ply_trace ("checking if tracing should be enabled");
3614+
3615+ path = NULL;
3616+ if ((strstr (state->kernel_command_line, " plymouth:debug ") != NULL)
3617+ || (strstr (state->kernel_command_line, "plymouth:debug ") != NULL)
3618+ || (strstr (state->kernel_command_line, " plymouth:debug") != NULL)
3619+ || (path = strstr (state->kernel_command_line, " plymouth:debug=file:")) != NULL)
3620+ {
3621+#ifdef LOG_TO_DEBUG_FILE
3622+ int fd;
3623+#endif
3624+
3625+ ply_trace ("tracing should be enabled!");
3626+ if (!ply_is_tracing ())
3627+ ply_toggle_tracing ();
3628+
3629+ if (path != NULL && debug_buffer_path == NULL)
3630+ {
3631+ char *end;
3632+
3633+ path += strlen (" plymouth:debug=file:");
3634+ debug_buffer_path = strdup (path);
3635+ end = strstr (debug_buffer_path, " ");
3636+
3637+ if (end != NULL)
3638+ *end = '\0';
3639+
3640+ debug_buffer_path = path;
3641+ }
3642+
3643+ if (debug_buffer == NULL)
3644+ debug_buffer = ply_buffer_new ();
3645+
3646+#ifdef LOG_TO_DEBUG_FILE
3647+ fd = open ("/dev/console", O_RDWR);
3648+ ply_logger_set_output_fd (ply_logger_get_error_default (), fd);
3649+#endif
3650+ }
3651+ else
3652+ ply_trace ("tracing shouldn't be enabled!");
3653+
3654+ if (debug_buffer != NULL)
3655+ {
3656+ if (debug_buffer_path == NULL)
3657+ debug_buffer_path = strdup (PLYMOUTH_LOG_DIRECTORY "/plymouth-debug.log");
3658+
3659+ ply_logger_add_filter (ply_logger_get_error_default (),
3660+ (ply_logger_filter_handler_t)
3661+ on_error_message,
3662+ debug_buffer);
3663+
3664+ }
3665+}
3666+
3667+static void
3668+check_logging (state_t *state)
3669+{
3670+ ply_trace ("checking if console messages should be redirected and logged");
3671+
3672+ if ((strstr (state->kernel_command_line, " plymouth:nolog ") != NULL)
3673+ || (strstr (state->kernel_command_line, "plymouth:nolog ") != NULL)
3674+ || (strstr (state->kernel_command_line, " plymouth:nolog") != NULL))
3675+ {
3676+ ply_trace ("logging won't be enabled!");
3677+ state->no_boot_log = true;
3678+ }
3679+ else
3680+ {
3681+ ply_trace ("logging will be enabled!");
3682+ state->no_boot_log = false;
3683+ }
3684+}
3685+
3686+static void
3687+check_for_consoles (state_t *state,
3688+ const char *default_tty,
3689+ bool should_add_displays)
3690+{
3691+ char *console_key;
3692+ char *remaining_command_line;
3693+
3694+ ply_trace ("checking for consoles%s",
3695+ should_add_displays? " and adding displays": "");
3696+
3697+ remaining_command_line = state->kernel_command_line;
3698+ while ((console_key = strstr (remaining_command_line, " console=")) != NULL)
3699+ {
3700+ char *end;
3701+ ply_trace ("serial console found!");
3702+
3703+ free (state->kernel_console_tty);
3704+ state->kernel_console_tty = strdup (console_key + strlen (" console="));
3705+
3706+ remaining_command_line = console_key + strlen (" console=");
3707+
3708+ end = strpbrk (state->kernel_console_tty, " \n\t\v,");
3709+
3710+ if (end != NULL)
3711+ {
3712+ *end = '\0';
3713+ remaining_command_line += end - state->kernel_console_tty;
3714+ }
3715+
3716+ if (strcmp (state->kernel_console_tty, "tty0") == 0 || strcmp (state->kernel_console_tty, "/dev/tty0") == 0)
3717+ {
3718+ free (state->kernel_console_tty);
3719+ state->kernel_console_tty = strdup (default_tty);
3720+ }
3721+
3722+ if (should_add_displays)
3723+ add_display_and_keyboard_for_terminal (state, state->kernel_console_tty);
3724+ }
3725+
3726+ ply_trace ("There are currently %d text displays",
3727+ ply_list_get_length (state->text_displays));
3728+ if (should_add_displays && ply_list_get_length (state->text_displays) == 0)
3729+ add_default_displays_and_keyboard (state);
3730+}
3731+
3732+static bool
3733+redirect_standard_io_to_device (const char *device)
3734+{
3735+ int fd;
3736+ char *file;
3737+
3738+ ply_trace ("redirecting stdio to %s", device);
3739+
3740+ if (strncmp (device, "/dev/", strlen ("/dev/")) == 0)
3741+ file = strdup (device);
3742+ else
3743+ asprintf (&file, "/dev/%s", device);
3744+
3745+ fd = open (file, O_RDWR | O_APPEND);
3746+
3747+ free (file);
3748+
3749+ if (fd < 0)
3750+ return false;
3751+
3752+ dup2 (fd, STDIN_FILENO);
3753+ dup2 (fd, STDOUT_FILENO);
3754+ dup2 (fd, STDERR_FILENO);
3755+
3756+ close (fd);
3757+
3758+ return true;
3759+}
3760+
3761+static bool
3762+initialize_environment (state_t *state)
3763+{
3764+ ply_trace ("initializing minimal work environment");
3765+
3766+ if (!get_kernel_command_line (state))
3767+ return false;
3768+
3769+ check_verbosity (state);
3770+ check_logging (state);
3771+
3772+ state->keystroke_triggers = ply_list_new ();
3773+ state->entry_triggers = ply_list_new ();
3774+ state->entry_buffer = ply_buffer_new();
3775+ state->pixel_displays = ply_list_new ();
3776+ state->text_displays = ply_list_new ();
3777+ state->pending_messages = ply_list_new ();
3778+ state->keyboard = NULL;
3779+
3780+ if (!state->default_tty)
3781+ {
3782+ if (state->mode == PLY_MODE_SHUTDOWN)
3783+ {
3784+ state->default_tty = SHUTDOWN_TTY;
3785+ }
3786+ else
3787+ state->default_tty = BOOT_TTY;
3788+ }
3789+
3790+ check_for_consoles (state, state->default_tty, false);
3791+
3792+ if (state->kernel_console_tty != NULL)
3793+ redirect_standard_io_to_device (state->kernel_console_tty);
3794+ else
3795+ redirect_standard_io_to_device (state->default_tty);
3796+
3797+ ply_trace ("initialized minimal work environment");
3798+ return true;
3799+}
3800+
3801+static void
3802+on_error_message (ply_buffer_t *debug_buffer,
3803+ const void *bytes,
3804+ size_t number_of_bytes)
3805+{
3806+ ply_buffer_append_bytes (debug_buffer, bytes, number_of_bytes);
3807+}
3808+
3809+static void
3810+dump_debug_buffer_to_file (void)
3811+{
3812+ int fd;
3813+ const char *bytes;
3814+ size_t size;
3815+
3816+ fd = open (debug_buffer_path,
3817+ O_WRONLY | O_CREAT | O_TRUNC, 0600);
3818+
3819+ if (fd < 0)
3820+ return;
3821+
3822+ size = ply_buffer_get_size (debug_buffer);
3823+ bytes = ply_buffer_get_bytes (debug_buffer);
3824+ ply_write (fd, bytes, size);
3825+ close (fd);
3826+}
3827+
3828+ #include <termios.h>
3829+ #include <unistd.h>
3830+static void
3831+on_crash (int signum)
3832+{
3833+ struct termios term_attributes;
3834+ int fd;
3835+
3836+ fd = open ("/dev/tty1", O_RDWR | O_NOCTTY);
3837+ if (fd < 0) fd = open ("/dev/hvc0", O_RDWR | O_NOCTTY);
3838+
3839+ ioctl (fd, KDSETMODE, KD_TEXT);
3840+
3841+ tcgetattr (fd, &term_attributes);
3842+
3843+ term_attributes.c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
3844+ term_attributes.c_oflag |= OPOST;
3845+ term_attributes.c_lflag |= ECHO | ICANON | ISIG | IEXTEN;
3846+
3847+ tcsetattr (fd, TCSAFLUSH, &term_attributes);
3848+
3849+ close (fd);
3850+
3851+ if (debug_buffer != NULL)
3852+ {
3853+ dump_debug_buffer_to_file ();
3854+ pause ();
3855+ }
3856+
3857+ if (pid_file != NULL)
3858+ {
3859+ unlink (pid_file);
3860+ free (pid_file);
3861+ pid_file = NULL;
3862+ }
3863+
3864+ signal (signum, SIG_DFL);
3865+ raise(signum);
3866+}
3867+
3868+int
3869+main (int argc,
3870+ char **argv)
3871+{
3872+ state_t state = { 0 };
3873+ int exit_code;
3874+ bool should_help = false;
3875+ bool no_daemon = false;
3876+ bool debug = false;
3877+ bool attach_to_session;
3878+ ply_daemon_handle_t *daemon_handle;
3879+ char *mode_string = NULL;
3880+ char *tty = NULL;
3881+
3882+ state.command_parser = ply_command_parser_new ("plymouthd", "Boot splash control server");
3883+
3884+ state.loop = ply_event_loop_get_default ();
3885+
3886+ ply_command_parser_add_options (state.command_parser,
3887+ "help", "This help message", PLY_COMMAND_OPTION_TYPE_FLAG,
3888+ "attach-to-session", "Redirect console messages from screen to log", PLY_COMMAND_OPTION_TYPE_FLAG,
3889+ "no-daemon", "Do not daemonize", PLY_COMMAND_OPTION_TYPE_FLAG,
3890+ "debug", "Output debugging information", PLY_COMMAND_OPTION_TYPE_FLAG,
3891+ "debug-file", "File to output debugging information to", PLY_COMMAND_OPTION_TYPE_STRING,
3892+ "mode", "Mode is one of: boot, shutdown", PLY_COMMAND_OPTION_TYPE_STRING,
3893+ "pid-file", "Write the pid of the daemon to a file", PLY_COMMAND_OPTION_TYPE_STRING,
3894+ "tty", "TTY to use instead of default", PLY_COMMAND_OPTION_TYPE_STRING,
3895+ NULL);
3896+
3897+ if (!ply_command_parser_parse_arguments (state.command_parser, state.loop, argv, argc))
3898+ {
3899+ char *help_string;
3900+
3901+ help_string = ply_command_parser_get_help_string (state.command_parser);
3902+
3903+ ply_error ("%s", help_string);
3904+
3905+ free (help_string);
3906+ return EX_USAGE;
3907+ }
3908+
3909+ ply_command_parser_get_options (state.command_parser,
3910+ "help", &should_help,
3911+ "attach-to-session", &attach_to_session,
3912+ "mode", &mode_string,
3913+ "no-daemon", &no_daemon,
3914+ "debug", &debug,
3915+ "debug-file", &debug_buffer_path,
3916+ "pid-file", &pid_file,
3917+ "tty", &tty,
3918+ NULL);
3919+
3920+ if (should_help)
3921+ {
3922+ char *help_string;
3923+
3924+ help_string = ply_command_parser_get_help_string (state.command_parser);
3925+
3926+ if (argc < 2)
3927+ fprintf (stderr, "%s", help_string);
3928+ else
3929+ printf ("%s", help_string);
3930+
3931+ free (help_string);
3932+ return 0;
3933+ }
3934+
3935+ if (debug && !ply_is_tracing ())
3936+ ply_toggle_tracing ();
3937+
3938+ if (mode_string != NULL)
3939+ {
3940+ if (strcmp (mode_string, "shutdown") == 0)
3941+ state.mode = PLY_MODE_SHUTDOWN;
3942+ else
3943+ state.mode = PLY_MODE_BOOT;
3944+
3945+ free (mode_string);
3946+ }
3947+
3948+ if (tty != NULL)
3949+ {
3950+ state.default_tty = tty;
3951+ }
3952+
3953+ if (geteuid () != 0)
3954+ {
3955+ ply_error ("plymouthd must be run as root user");
3956+ return EX_OSERR;
3957+ }
3958+
3959+ chdir ("/");
3960+ signal (SIGPIPE, SIG_IGN);
3961+
3962+ if (! no_daemon)
3963+ {
3964+ daemon_handle = ply_create_daemon (pid_file);
3965+
3966+ if (daemon_handle == NULL)
3967+ {
3968+ ply_error ("cannot daemonize: %m");
3969+ return EX_UNAVAILABLE;
3970+ }
3971+ }
3972+
3973+ if (debug)
3974+ debug_buffer = ply_buffer_new ();
3975+
3976+ signal (SIGABRT, on_crash);
3977+ signal (SIGSEGV, on_crash);
3978+
3979+ /* If we're shutting down we don't want to die until killed
3980+ */
3981+ if (state.mode == PLY_MODE_SHUTDOWN)
3982+ signal (SIGTERM, SIG_IGN);
3983+
3984+ /* before do anything we need to make sure we have a working
3985+ * environment.
3986+ */
3987+ if (!initialize_environment (&state))
3988+ {
3989+ if (errno == 0)
3990+ {
3991+ if (! no_daemon)
3992+ ply_detach_daemon (daemon_handle, 0);
3993+ return 0;
3994+ }
3995+
3996+ ply_error ("could not setup basic operating environment: %m");
3997+ if (! no_daemon)
3998+ ply_detach_daemon (daemon_handle, EX_OSERR);
3999+ return EX_OSERR;
4000+ }
4001+
4002+ state.boot_buffer = ply_buffer_new ();
4003+
4004+ if (attach_to_session)
4005+ {
4006+ state.should_be_attached = attach_to_session;
4007+ if (!attach_to_running_session (&state))
4008+ {
4009+ ply_error ("could not create session: %m");
4010+ if (! no_daemon)
4011+ ply_detach_daemon (daemon_handle, EX_UNAVAILABLE);
4012+ return EX_UNAVAILABLE;
4013+ }
4014+ }
4015+
4016+ state.boot_server = start_boot_server (&state);
4017+
4018+ if (state.boot_server == NULL)
4019+ {
4020+ ply_error ("could not log bootup: %m");
4021+ if (! no_daemon)
4022+ ply_detach_daemon (daemon_handle, EX_UNAVAILABLE);
4023+ return EX_UNAVAILABLE;
4024+ }
4025+
4026+ if (! no_daemon)
4027+ if (!ply_detach_daemon (daemon_handle, 0))
4028+ {
4029+ ply_error ("could not tell parent to exit: %m");
4030+ return EX_UNAVAILABLE;
4031+ }
4032+
4033+ state.progress = ply_progress_new ();
4034+
4035+ ply_progress_load_cache (state.progress,
4036+ get_cache_file_for_mode (state.mode));
4037+
4038+ ply_trace ("entering event loop");
4039+ exit_code = ply_event_loop_run (state.loop);
4040+ ply_trace ("exited event loop");
4041+
4042+ ply_progress_save_cache (state.progress,
4043+ get_cache_file_for_mode (state.mode));
4044+
4045+ ply_boot_splash_free (state.boot_splash);
4046+ state.boot_splash = NULL;
4047+
4048+ ply_command_parser_free (state.command_parser);
4049+
4050+ ply_boot_server_free (state.boot_server);
4051+ state.boot_server = NULL;
4052+
4053+ ply_trace ("freeing terminal session");
4054+ ply_terminal_session_free (state.session);
4055+
4056+ ply_buffer_free (state.boot_buffer);
4057+ ply_progress_free (state.progress);
4058+
4059+ ply_trace ("exiting with code %d", exit_code);
4060+
4061+ if (debug_buffer != NULL)
4062+ {
4063+ dump_debug_buffer_to_file ();
4064+ ply_buffer_free (debug_buffer);
4065+ }
4066+
4067+ ply_free_error_log();
4068+
4069+ return exit_code;
4070+}
4071+/* vim: set sts=4 ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
4072
4073=== added directory '.pc/main-Don-t-watch-for-keyboard-input-if-no-keyboard.patch'
4074=== added directory '.pc/main-Don-t-watch-for-keyboard-input-if-no-keyboard.patch/src'
4075=== added file '.pc/main-Don-t-watch-for-keyboard-input-if-no-keyboard.patch/src/main.c'
4076--- .pc/main-Don-t-watch-for-keyboard-input-if-no-keyboard.patch/src/main.c 1970-01-01 00:00:00 +0000
4077+++ .pc/main-Don-t-watch-for-keyboard-input-if-no-keyboard.patch/src/main.c 2013-11-30 04:03:08 +0000
4078@@ -0,0 +1,1986 @@
4079+/* main.c - boot messages monitor
4080+ *
4081+ * Copyright (C) 2007 Red Hat, Inc
4082+ *
4083+ * This file is free software; you can redistribute it and/or modify
4084+ * it under the terms of the GNU General Public License as published
4085+ * by the Free Software Foundation; either version 2 of the License,
4086+ * or (at your option) any later version.
4087+ *
4088+ * This file is distributed in the hope that it will be useful, but
4089+ * WITHOUT ANY WARRANTY; without even the implied warranty of
4090+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4091+ * General Public License for more details.
4092+ *
4093+ * You should have received a copy of the GNU General Public License
4094+ * along with this; see the file COPYING. If not, write to the Free
4095+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
4096+ * 02111-1307, USA.
4097+ *
4098+ * Written by: Ray Strode <rstrode@redhat.com>
4099+ */
4100+#include "config.h"
4101+
4102+#include <sys/stat.h>
4103+#include <sys/types.h>
4104+#include <limits.h>
4105+#include <dirent.h>
4106+#include <fcntl.h>
4107+#include <stdlib.h>
4108+#include <stdio.h>
4109+#include <sysexits.h>
4110+#include <sys/ioctl.h>
4111+#include <unistd.h>
4112+#include <wchar.h>
4113+#include <paths.h>
4114+#include <assert.h>
4115+
4116+#include <linux/kd.h>
4117+#include <linux/vt.h>
4118+
4119+#include "ply-buffer.h"
4120+#include "ply-command-parser.h"
4121+#include "ply-boot-server.h"
4122+#include "ply-boot-splash.h"
4123+#include "ply-event-loop.h"
4124+#include "ply-list.h"
4125+#include "ply-logger.h"
4126+#include "ply-terminal-session.h"
4127+#include "ply-trigger.h"
4128+#include "ply-utils.h"
4129+#include "ply-progress.h"
4130+
4131+#ifndef PLY_MAX_COMMAND_LINE_SIZE
4132+#define PLY_MAX_COMMAND_LINE_SIZE 512
4133+#endif
4134+
4135+#define BOOT_DURATION_FILE PLYMOUTH_TIME_DIRECTORY "/boot-duration"
4136+#define SHUTDOWN_DURATION_FILE PLYMOUTH_TIME_DIRECTORY "/shutdown-duration"
4137+
4138+typedef enum {
4139+ PLY_MODE_BOOT,
4140+ PLY_MODE_SHUTDOWN
4141+} ply_mode_t;
4142+
4143+typedef struct
4144+{
4145+ const char *keys;
4146+ ply_trigger_t *trigger;
4147+} ply_keystroke_watch_t;
4148+
4149+typedef struct
4150+{
4151+ enum {PLY_ENTRY_TRIGGER_TYPE_PASSWORD,
4152+ PLY_ENTRY_TRIGGER_TYPE_QUESTION}
4153+ type;
4154+ const char *prompt;
4155+ ply_trigger_t *trigger;
4156+} ply_entry_trigger_t;
4157+
4158+typedef struct
4159+{
4160+ ply_event_loop_t *loop;
4161+ ply_boot_server_t *boot_server;
4162+ ply_list_t *pixel_displays;
4163+ ply_list_t *text_displays;
4164+ ply_keyboard_t *keyboard;
4165+ ply_boot_splash_t *boot_splash;
4166+ ply_terminal_session_t *session;
4167+ ply_buffer_t *boot_buffer;
4168+ ply_progress_t *progress;
4169+ ply_list_t *keystroke_triggers;
4170+ ply_list_t *entry_triggers;
4171+ ply_buffer_t *entry_buffer;
4172+ ply_command_parser_t *command_parser;
4173+ ply_mode_t mode;
4174+ ply_renderer_t *renderer;
4175+ ply_terminal_t *terminal;
4176+
4177+ ply_trigger_t *deactivate_trigger;
4178+ ply_trigger_t *quit_trigger;
4179+
4180+ char kernel_command_line[PLY_MAX_COMMAND_LINE_SIZE];
4181+ uint32_t no_boot_log : 1;
4182+ uint32_t showing_details : 1;
4183+ uint32_t system_initialized : 1;
4184+ uint32_t is_redirected : 1;
4185+ uint32_t is_attached : 1;
4186+ uint32_t should_be_attached : 1;
4187+ uint32_t should_retain_splash : 1;
4188+ uint32_t is_inactive : 1;
4189+
4190+ char *kernel_console_tty;
4191+ char *override_splash_path;
4192+ char *system_default_splash_path;
4193+ char *distribution_default_splash_path;
4194+ const char *default_tty;
4195+
4196+ int number_of_errors;
4197+ ply_list_t *pending_messages;
4198+} state_t;
4199+
4200+static ply_boot_splash_t *start_boot_splash (state_t *state,
4201+ const char *theme_path);
4202+
4203+static void add_display_and_keyboard_for_terminal (state_t *state,
4204+ const char *tty_name);
4205+
4206+static void add_default_displays_and_keyboard (state_t *state);
4207+
4208+static bool attach_to_running_session (state_t *state);
4209+static void on_escape_pressed (state_t *state);
4210+static void dump_details_and_quit_splash (state_t *state);
4211+static void update_display (state_t *state);
4212+
4213+static void on_error_message (ply_buffer_t *debug_buffer,
4214+ const void *bytes,
4215+ size_t number_of_bytes);
4216+static ply_buffer_t *debug_buffer;
4217+static char *debug_buffer_path = NULL;
4218+static char *pid_file = NULL;
4219+static void check_for_consoles (state_t *state,
4220+ const char *default_tty,
4221+ bool should_add_displays);
4222+static void toggle_between_splash_and_details (state_t *state);
4223+
4224+static void
4225+on_session_output (state_t *state,
4226+ const char *output,
4227+ size_t size)
4228+{
4229+ ply_buffer_append_bytes (state->boot_buffer, output, size);
4230+ if (state->boot_splash != NULL)
4231+ ply_boot_splash_update_output (state->boot_splash,
4232+ output, size);
4233+}
4234+
4235+static void
4236+on_session_finished (state_t *state)
4237+{
4238+ ply_trace ("got hang up on terminal session fd");
4239+}
4240+
4241+static void
4242+on_update (state_t *state,
4243+ const char *status)
4244+{
4245+ ply_trace ("updating status to '%s'", status);
4246+ if (strncmp (status, "fsck:", 5))
4247+ ply_progress_status_update (state->progress,
4248+ status);
4249+ if (state->boot_splash != NULL)
4250+ ply_boot_splash_update_status (state->boot_splash,
4251+ status);
4252+}
4253+
4254+static void
4255+flush_pending_messages (state_t *state)
4256+{
4257+ ply_list_node_t *node = ply_list_get_first_node (state->pending_messages);
4258+ while (node != NULL)
4259+ {
4260+ ply_list_node_t *next_node;
4261+ char *message = ply_list_node_get_data (node);
4262+
4263+ ply_trace ("displaying queued message");
4264+
4265+ ply_boot_splash_display_message (state->boot_splash, message);
4266+ next_node = ply_list_get_next_node (state->pending_messages, node);
4267+ ply_list_remove_node (state->pending_messages, node);
4268+ free(message);
4269+ node = next_node;
4270+ }
4271+}
4272+
4273+static void
4274+show_detailed_splash (state_t *state)
4275+{
4276+ if (state->boot_splash != NULL)
4277+ return;
4278+
4279+ ply_trace ("Showing detailed splash screen");
4280+ state->boot_splash = start_boot_splash (state,
4281+ PLYMOUTH_THEME_PATH "details/details.plymouth");
4282+
4283+ if (state->boot_splash == NULL)
4284+ {
4285+ ply_trace ("Could not start detailed splash screen, exiting");
4286+ exit (1);
4287+ }
4288+}
4289+
4290+static void
4291+find_override_splash (state_t *state)
4292+{
4293+ char *splash_string;
4294+
4295+ if (state->override_splash_path != NULL)
4296+ return;
4297+
4298+ splash_string = strstr (state->kernel_command_line, "plymouth:splash=");
4299+
4300+ if (splash_string != NULL)
4301+ {
4302+ char *end;
4303+ splash_string = strdup (splash_string + strlen ("plymouth:splash="));
4304+
4305+ end = splash_string + strcspn (splash_string, " \n");
4306+ *end = '\0';
4307+
4308+ ply_trace ("Splash is configured to be '%s'", splash_string);
4309+
4310+ asprintf (&state->override_splash_path,
4311+ PLYMOUTH_THEME_PATH "%s/%s.plymouth",
4312+ splash_string, splash_string);
4313+ }
4314+}
4315+
4316+static void
4317+find_system_default_splash (state_t *state)
4318+{
4319+ ply_key_file_t *key_file;
4320+ char *splash_string;
4321+
4322+ if (state->system_default_splash_path != NULL)
4323+ return;
4324+
4325+ ply_trace ("Trying to load " PLYMOUTH_CONF_DIR "plymouthd.conf");
4326+ key_file = ply_key_file_new (PLYMOUTH_CONF_DIR "plymouthd.conf");
4327+
4328+ if (!ply_key_file_load (key_file))
4329+ {
4330+ ply_trace ("failed to load " PLYMOUTH_CONF_DIR "plymouthd.conf");
4331+ ply_key_file_free (key_file);
4332+ return;
4333+ }
4334+
4335+ splash_string = ply_key_file_get_value (key_file, "Daemon", "Theme");
4336+
4337+ ply_trace ("System default splash is configured to be '%s'", splash_string);
4338+
4339+ asprintf (&state->system_default_splash_path,
4340+ PLYMOUTH_THEME_PATH "%s/%s.plymouth",
4341+ splash_string, splash_string);
4342+ free (splash_string);
4343+}
4344+
4345+static void
4346+find_distribution_default_splash (state_t *state)
4347+{
4348+ ply_key_file_t *key_file;
4349+ char *splash_string;
4350+
4351+ if (state->distribution_default_splash_path != NULL)
4352+ return;
4353+
4354+ ply_trace ("Trying to load " PLYMOUTH_POLICY_DIR "plymouthd.defaults");
4355+ key_file = ply_key_file_new (PLYMOUTH_POLICY_DIR "plymouthd.defaults");
4356+
4357+ if (!ply_key_file_load (key_file))
4358+ {
4359+ ply_trace ("failed to load " PLYMOUTH_POLICY_DIR "plymouthd.defaults");
4360+ ply_key_file_free (key_file);
4361+ return;
4362+ }
4363+
4364+ splash_string = ply_key_file_get_value (key_file, "Daemon", "Theme");
4365+
4366+ ply_trace ("Distribution default splash is configured to be '%s'", splash_string);
4367+
4368+ asprintf (&state->distribution_default_splash_path,
4369+ PLYMOUTH_THEME_PATH "%s/%s.plymouth",
4370+ splash_string, splash_string);
4371+ free (splash_string);
4372+}
4373+
4374+static void
4375+show_default_splash (state_t *state)
4376+{
4377+ if (state->boot_splash != NULL)
4378+ return;
4379+
4380+ ply_trace ("Showing splash screen");
4381+ find_override_splash (state);
4382+ if (state->override_splash_path != NULL)
4383+ {
4384+ ply_trace ("Trying override splash at '%s'", state->override_splash_path);
4385+ state->boot_splash = start_boot_splash (state,
4386+ state->override_splash_path);
4387+ }
4388+
4389+ find_system_default_splash (state);
4390+ if (state->boot_splash == NULL &&
4391+ state->system_default_splash_path != NULL)
4392+ {
4393+ ply_trace ("Trying system default splash");
4394+ state->boot_splash = start_boot_splash (state,
4395+ state->system_default_splash_path);
4396+ }
4397+
4398+ find_distribution_default_splash (state);
4399+ if (state->boot_splash == NULL &&
4400+ state->distribution_default_splash_path != NULL)
4401+ {
4402+ ply_trace ("Trying distribution default splash");
4403+ state->boot_splash = start_boot_splash (state,
4404+ state->distribution_default_splash_path);
4405+ }
4406+
4407+ if (state->boot_splash == NULL)
4408+ {
4409+ ply_trace ("Trying old scheme for default splash");
4410+ state->boot_splash = start_boot_splash (state,
4411+ PLYMOUTH_THEME_PATH "default.plymouth");
4412+ }
4413+
4414+ if (state->boot_splash == NULL)
4415+ {
4416+ ply_trace ("Could not start default splash screen,"
4417+ "showing text splash screen");
4418+ state->boot_splash = start_boot_splash (state,
4419+ PLYMOUTH_THEME_PATH "text.plymouth");
4420+ }
4421+
4422+ if (state->boot_splash == NULL)
4423+ {
4424+ if (errno != ENOENT)
4425+ ply_error ("could not start boot splash: %m");
4426+ show_detailed_splash (state);
4427+ }
4428+}
4429+
4430+static void
4431+on_ask_for_password (state_t *state,
4432+ const char *prompt,
4433+ ply_trigger_t *answer)
4434+{
4435+ ply_entry_trigger_t *entry_trigger;
4436+
4437+ /* No splash, client will have to get password
4438+ */
4439+ if (state->boot_splash == NULL)
4440+ {
4441+ ply_trace ("no splash loaded, replying immediately with no password");
4442+ ply_trigger_pull (answer, NULL);
4443+ return;
4444+ }
4445+
4446+ entry_trigger = calloc (1, sizeof (ply_entry_trigger_t));
4447+ entry_trigger->type = PLY_ENTRY_TRIGGER_TYPE_PASSWORD;
4448+ entry_trigger->prompt = prompt;
4449+ entry_trigger->trigger = answer;
4450+ ply_trace ("queuing password request with boot splash");
4451+ ply_list_append_data (state->entry_triggers, entry_trigger);
4452+ update_display (state);
4453+}
4454+
4455+static void
4456+on_ask_question (state_t *state,
4457+ const char *prompt,
4458+ ply_trigger_t *answer)
4459+{
4460+ ply_entry_trigger_t *entry_trigger;
4461+
4462+ entry_trigger = calloc (1, sizeof (ply_entry_trigger_t));
4463+ entry_trigger->type = PLY_ENTRY_TRIGGER_TYPE_QUESTION;
4464+ entry_trigger->prompt = prompt;
4465+ entry_trigger->trigger = answer;
4466+ ply_trace ("queuing question with boot splash");
4467+ ply_list_append_data (state->entry_triggers, entry_trigger);
4468+ update_display (state);
4469+}
4470+
4471+static void
4472+on_display_message (state_t *state,
4473+ const char *message)
4474+{
4475+ ply_trace ("displaying message %s", message);
4476+ if (state->boot_splash != NULL)
4477+ ply_boot_splash_display_message (state->boot_splash, message);
4478+ else
4479+ ply_list_append_data (state->pending_messages, strdup(message));
4480+}
4481+
4482+static void
4483+on_watch_for_keystroke (state_t *state,
4484+ const char *keys,
4485+ ply_trigger_t *trigger)
4486+{
4487+ ply_keystroke_watch_t *keystroke_trigger =
4488+ calloc (1, sizeof (ply_keystroke_watch_t));
4489+ ply_trace ("watching for keystroke");
4490+ keystroke_trigger->keys = keys;
4491+ keystroke_trigger->trigger = trigger;
4492+ ply_list_append_data (state->keystroke_triggers, keystroke_trigger);
4493+}
4494+
4495+static void
4496+on_ignore_keystroke (state_t *state,
4497+ const char *keys)
4498+{
4499+ ply_list_node_t *node;
4500+
4501+ ply_trace ("ignoring for keystroke");
4502+
4503+ for (node = ply_list_get_first_node (state->keystroke_triggers); node;
4504+ node = ply_list_get_next_node (state->keystroke_triggers, node))
4505+ {
4506+ ply_keystroke_watch_t* keystroke_trigger = ply_list_node_get_data (node);
4507+ if ((!keystroke_trigger->keys && !keys) ||
4508+ (keystroke_trigger->keys && keys && strcmp(keystroke_trigger->keys, keys)==0))
4509+ {
4510+ ply_trigger_pull (keystroke_trigger->trigger, NULL);
4511+ ply_list_remove_node (state->keystroke_triggers, node);
4512+ return;
4513+ }
4514+ }
4515+}
4516+
4517+static void
4518+on_progress_pause (state_t *state)
4519+{
4520+ ply_trace ("pausing progress");
4521+ ply_progress_pause (state->progress);
4522+}
4523+
4524+static void
4525+on_progress_unpause (state_t *state)
4526+{
4527+ ply_trace ("unpausing progress");
4528+ ply_progress_unpause (state->progress);
4529+}
4530+
4531+static void
4532+on_newroot (state_t *state,
4533+ const char *root_dir)
4534+{
4535+ if (state->mode != PLY_MODE_BOOT)
4536+ {
4537+ ply_trace ("new root is only supported in boot mode ");
4538+ return;
4539+ }
4540+
4541+ ply_trace ("new root mounted at \"%s\", switching to it", root_dir);
4542+ chdir(root_dir);
4543+ chroot(".");
4544+ chdir("/");
4545+ ply_progress_load_cache (state->progress, BOOT_DURATION_FILE);
4546+ if (state->boot_splash != NULL)
4547+ ply_boot_splash_root_mounted (state->boot_splash);
4548+}
4549+
4550+static const char *
4551+get_cache_file_for_mode (ply_mode_t mode)
4552+{
4553+ const char *filename;
4554+
4555+ switch ((int)mode)
4556+ {
4557+ case PLY_MODE_BOOT:
4558+ filename = BOOT_DURATION_FILE;
4559+ break;
4560+ case PLY_MODE_SHUTDOWN:
4561+ filename = SHUTDOWN_DURATION_FILE;
4562+ break;
4563+ default:
4564+ fprintf (stderr, "Unhandled case in %s line %d\n", __FILE__, __LINE__);
4565+ abort ();
4566+ break;
4567+ }
4568+
4569+ ply_trace ("returning cache file '%s'", filename);
4570+ return filename;
4571+}
4572+
4573+static const char *
4574+get_log_file_for_mode (ply_mode_t mode)
4575+{
4576+ const char *filename;
4577+
4578+ switch ((int)mode)
4579+ {
4580+ case PLY_MODE_BOOT:
4581+ filename = PLYMOUTH_LOG_DIRECTORY "/boot.log";
4582+ break;
4583+ case PLY_MODE_SHUTDOWN:
4584+ filename = _PATH_DEVNULL;
4585+ break;
4586+ default:
4587+ fprintf (stderr, "Unhandled case in %s line %d\n", __FILE__, __LINE__);
4588+ abort ();
4589+ break;
4590+ }
4591+
4592+ ply_trace ("returning log file '%s'", filename);
4593+ return filename;
4594+}
4595+
4596+static const char *
4597+get_log_spool_file_for_mode (ply_mode_t mode)
4598+{
4599+ const char *filename;
4600+
4601+ switch ((int)mode)
4602+ {
4603+ case PLY_MODE_BOOT:
4604+ filename = PLYMOUTH_SPOOL_DIRECTORY "/boot.log";
4605+ break;
4606+ case PLY_MODE_SHUTDOWN:
4607+ filename = NULL;
4608+ break;
4609+ default:
4610+ fprintf (stderr, "Unhandled case in %s line %d\n", __FILE__, __LINE__);
4611+ abort ();
4612+ break;
4613+ }
4614+
4615+ ply_trace ("returning spool file '%s'", filename);
4616+ return filename;
4617+}
4618+
4619+static void
4620+spool_error (state_t *state)
4621+{
4622+ const char *logfile;
4623+ const char *logspool;
4624+
4625+ ply_trace ("spooling error for viewer");
4626+
4627+ logfile = get_log_file_for_mode (state->mode);
4628+ logspool = get_log_spool_file_for_mode (state->mode);
4629+
4630+ if (logfile != NULL && logspool != NULL)
4631+ {
4632+ unlink (logspool);
4633+
4634+ ply_create_file_link (logfile, logspool);
4635+ }
4636+}
4637+
4638+static void
4639+prepare_logging (state_t *state)
4640+{
4641+ const char *logfile;
4642+
4643+ if (!state->system_initialized)
4644+ {
4645+ ply_trace ("not preparing logging yet, system not initialized");
4646+ return;
4647+ }
4648+
4649+ if (state->session == NULL)
4650+ {
4651+ ply_trace ("not preparing logging, no session");
4652+ return;
4653+ }
4654+
4655+ logfile = get_log_file_for_mode (state->mode);
4656+ if (logfile != NULL)
4657+ {
4658+ ply_trace ("opening log '%s'", logfile);
4659+ ply_terminal_session_open_log (state->session, logfile);
4660+
4661+ if (state->number_of_errors > 0)
4662+ spool_error (state);
4663+ }
4664+}
4665+
4666+static void
4667+on_system_initialized (state_t *state)
4668+{
4669+ ply_trace ("system now initialized, opening log");
4670+ state->system_initialized = true;
4671+
4672+ prepare_logging (state);
4673+}
4674+
4675+static void
4676+on_error (state_t *state)
4677+{
4678+ ply_trace ("encountered error during boot up");
4679+
4680+ if (state->system_initialized && state->number_of_errors == 0)
4681+ spool_error (state);
4682+ else
4683+ ply_trace ("not spooling because number of errors %d", state->number_of_errors);
4684+
4685+ state->number_of_errors++;
4686+}
4687+
4688+static bool
4689+plymouth_should_ignore_show_splash_calls (state_t *state)
4690+{
4691+ ply_trace ("checking if plymouth should be running");
4692+ if (state->mode != PLY_MODE_BOOT || ply_string_has_prefix (state->kernel_command_line, "plymouth:force-splash") || strstr (state->kernel_command_line, " plymouth:force-splash") != NULL)
4693+ return false;
4694+
4695+ return ply_string_has_prefix (state->kernel_command_line, "init=") || strstr (state->kernel_command_line, " init=") != NULL;
4696+}
4697+
4698+static bool
4699+plymouth_should_show_default_splash (state_t *state)
4700+{
4701+ ply_trace ("checking if plymouth should show default splash");
4702+
4703+ const char const *strings[] = {
4704+ " single ", " single\n", "^single ",
4705+ " 1 ", " 1\n", "^1 ",
4706+ " s ", " s\n", "^s ",
4707+ " S ", " S\n", "^S ",
4708+ " -s ", " -s\n", "^-s ",
4709+ NULL
4710+ };
4711+ int i;
4712+
4713+ if (state->kernel_console_tty != NULL)
4714+ return false;
4715+
4716+ for (i = 0; strings[i] != NULL; i++)
4717+ {
4718+ int cmp;
4719+ if (strings[i][0] == '^')
4720+ cmp = strncmp(state->kernel_command_line, strings[i]+1,
4721+ strlen(strings[i]+1)) == 0;
4722+ else
4723+ cmp = strstr (state->kernel_command_line, strings[i]) != NULL;
4724+
4725+ if (cmp)
4726+ {
4727+ ply_trace ("kernel command line has option \"%s\"", strings[i]);
4728+ return false;
4729+ }
4730+ }
4731+
4732+ return strstr (state->kernel_command_line, "rhgb") != NULL || (strstr (state->kernel_command_line, "splash") != NULL && strstr(state->kernel_command_line, "splash=verbose") == NULL);
4733+}
4734+
4735+static void
4736+remove_displays_and_keyboard (state_t *state)
4737+{
4738+ ply_list_node_t *node;
4739+ ply_trace ("removing displays and keyboard");
4740+
4741+ node = ply_list_get_first_node (state->pixel_displays);
4742+ while (node != NULL)
4743+ {
4744+ ply_list_node_t *next_node;
4745+ ply_pixel_display_t *display;
4746+
4747+ ply_trace ("removing pixel display");
4748+ next_node = ply_list_get_next_node (state->pixel_displays, node);
4749+ display = ply_list_node_get_data (node);
4750+ ply_pixel_display_free (display);
4751+
4752+ ply_list_remove_node (state->pixel_displays, node);
4753+
4754+ node = next_node;
4755+ }
4756+
4757+ node = ply_list_get_first_node (state->text_displays);
4758+ while (node != NULL)
4759+ {
4760+ ply_list_node_t *next_node;
4761+ ply_text_display_t *display;
4762+
4763+ ply_trace ("removing text display");
4764+ next_node = ply_list_get_next_node (state->text_displays, node);
4765+ display = ply_list_node_get_data (node);
4766+ ply_text_display_free (display);
4767+
4768+ ply_list_remove_node (state->text_displays, node);
4769+
4770+ node = next_node;
4771+ }
4772+
4773+ if (state->keyboard != NULL)
4774+ {
4775+ ply_trace ("removing keyboard");
4776+ ply_keyboard_stop_watching_for_input (state->keyboard);
4777+ ply_keyboard_free (state->keyboard);
4778+ state->keyboard = NULL;
4779+ }
4780+}
4781+
4782+static void
4783+on_show_splash (state_t *state)
4784+{
4785+ bool has_display;
4786+
4787+ if (state->is_inactive)
4788+ {
4789+ ply_trace ("show splash called while inactive");
4790+ return;
4791+ }
4792+
4793+ if (plymouth_should_ignore_show_splash_calls (state))
4794+ {
4795+ ply_trace ("show splash called while ignoring show splash calls");
4796+ dump_details_and_quit_splash (state);
4797+ return;
4798+ }
4799+
4800+ check_for_consoles (state, state->default_tty, true);
4801+
4802+ has_display = ply_list_get_length (state->pixel_displays) > 0 ||
4803+ ply_list_get_length (state->text_displays) > 0;
4804+
4805+ if (!state->is_attached && state->should_be_attached && has_display)
4806+ attach_to_running_session (state);
4807+
4808+ if (!has_display && state->is_attached)
4809+ {
4810+ ply_trace ("no open seats, detaching session");
4811+ ply_terminal_session_detach (state->session);
4812+ state->is_redirected = false;
4813+ state->is_attached = false;
4814+ }
4815+
4816+ if (plymouth_should_show_default_splash (state))
4817+ {
4818+ show_default_splash (state);
4819+ state->showing_details = false;
4820+ }
4821+ else
4822+ {
4823+ show_detailed_splash (state);
4824+ state->showing_details = true;
4825+ }
4826+ flush_pending_messages (state);
4827+}
4828+
4829+static void
4830+quit_splash (state_t *state)
4831+{
4832+ ply_trace ("quiting splash");
4833+ if (state->boot_splash != NULL)
4834+ {
4835+ ply_trace ("freeing splash");
4836+ ply_boot_splash_free (state->boot_splash);
4837+ state->boot_splash = NULL;
4838+ }
4839+
4840+ ply_trace ("removing displays and keyboard");
4841+ remove_displays_and_keyboard (state);
4842+
4843+ if (state->renderer != NULL)
4844+ {
4845+ ply_renderer_close (state->renderer);
4846+ ply_renderer_free (state->renderer);
4847+ state->renderer = NULL;
4848+ }
4849+
4850+ if (state->terminal != NULL)
4851+ {
4852+ if (!state->should_retain_splash)
4853+ {
4854+ ply_trace ("Not retaining splash, so deallocating VT");
4855+ ply_terminal_deactivate_vt (state->terminal);
4856+ }
4857+ ply_terminal_close (state->terminal);
4858+ ply_terminal_free (state->terminal);
4859+ state->terminal = NULL;
4860+ }
4861+
4862+ if (state->session != NULL)
4863+ {
4864+ ply_trace ("detaching session");
4865+ ply_terminal_session_detach (state->session);
4866+ state->is_redirected = false;
4867+ state->is_attached = false;
4868+ }
4869+}
4870+
4871+static void
4872+dump_details_and_quit_splash (state_t *state)
4873+{
4874+ state->showing_details = false;
4875+ toggle_between_splash_and_details (state);
4876+
4877+ if (state->renderer != NULL)
4878+ ply_renderer_deactivate (state->renderer);
4879+ if (state->boot_splash != NULL)
4880+ ply_boot_splash_hide (state->boot_splash);
4881+
4882+ quit_splash (state);
4883+}
4884+
4885+static void
4886+on_hide_splash (state_t *state)
4887+{
4888+ if (state->is_inactive)
4889+ return;
4890+
4891+ if (state->boot_splash == NULL)
4892+ return;
4893+
4894+ ply_trace ("hiding boot splash");
4895+ dump_details_and_quit_splash (state);
4896+}
4897+
4898+#ifdef PLY_ENABLE_GDM_TRANSITION
4899+static void
4900+tell_gdm_to_transition (void)
4901+{
4902+ int fd;
4903+
4904+ fd = creat ("/var/spool/gdm/force-display-on-active-vt", 0644);
4905+ close (fd);
4906+}
4907+#endif
4908+
4909+static void
4910+quit_program (state_t *state)
4911+{
4912+ ply_trace ("exiting event loop");
4913+ ply_event_loop_exit (state->loop, 0);
4914+
4915+ if (pid_file != NULL)
4916+ {
4917+ unlink (pid_file);
4918+ free (pid_file);
4919+ pid_file = NULL;
4920+ }
4921+
4922+#ifdef PLY_ENABLE_GDM_TRANSITION
4923+ if (state->should_retain_splash)
4924+ {
4925+ tell_gdm_to_transition ();
4926+ }
4927+#endif
4928+
4929+ if (state->deactivate_trigger != NULL)
4930+ {
4931+ ply_trigger_pull (state->deactivate_trigger, NULL);
4932+ state->deactivate_trigger = NULL;
4933+ }
4934+ if (state->quit_trigger != NULL)
4935+ {
4936+ ply_trigger_pull (state->quit_trigger, NULL);
4937+ state->quit_trigger = NULL;
4938+ }
4939+}
4940+
4941+static void
4942+deactivate_splash (state_t *state)
4943+{
4944+ assert (!state->is_inactive);
4945+
4946+ if (state->renderer != NULL)
4947+ {
4948+ ply_trace ("deactivating renderer");
4949+ ply_renderer_deactivate (state->renderer);
4950+ }
4951+
4952+ if (state->keyboard != NULL)
4953+ {
4954+ ply_trace ("deactivating keyboard");
4955+ ply_keyboard_stop_watching_for_input (state->keyboard);
4956+ }
4957+
4958+ if ((state->session != NULL) && state->is_attached)
4959+ {
4960+ ply_trace ("deactivating terminal session");
4961+ ply_terminal_session_detach (state->session);
4962+ state->is_redirected = false;
4963+ state->is_attached = false;
4964+ }
4965+
4966+ if (state->terminal != NULL)
4967+ {
4968+ ply_trace ("deactivating terminal");
4969+ ply_terminal_stop_watching_for_vt_changes (state->terminal);
4970+ ply_terminal_set_buffered_input (state->terminal);
4971+ ply_terminal_ignore_mode_changes (state->terminal, true);
4972+ }
4973+
4974+ state->is_inactive = true;
4975+
4976+ ply_trigger_pull (state->deactivate_trigger, NULL);
4977+ state->deactivate_trigger = NULL;
4978+}
4979+
4980+static void
4981+on_boot_splash_idle (state_t *state)
4982+{
4983+ ply_trace ("boot splash idle");
4984+
4985+ /* In the case where we've received both a deactivate command and a
4986+ * quit command, the quit command takes precedence.
4987+ */
4988+ if (state->quit_trigger != NULL)
4989+ {
4990+ if (!state->should_retain_splash)
4991+ {
4992+ ply_trace ("hiding splash");
4993+ if (state->renderer != NULL)
4994+ ply_renderer_deactivate (state->renderer);
4995+ if (state->boot_splash != NULL)
4996+ ply_boot_splash_hide (state->boot_splash);
4997+ }
4998+
4999+ ply_trace ("quitting splash");
5000+ quit_splash (state);
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes:
to status/vote changes: