/* details.c - boot splash plugin * * Copyright (C) 2008 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Written by: Ray Strode */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ply-boot-splash-plugin.h" #include "ply-buffer.h" #include "ply-event-loop.h" #include "ply-key-file.h" #include "ply-list.h" #include "ply-logger.h" #include "ply-text-display.h" #include "ply-trigger.h" #include "ply-utils.h" #include #define CLEAR_LINE_SEQUENCE "\033[2K\r" typedef enum { PLY_BOOT_SPLASH_DISPLAY_NORMAL, PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY, PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY } ply_boot_splash_display_type_t; typedef struct { ply_boot_splash_plugin_t *plugin; ply_text_display_t *display; } view_t; ply_boot_splash_plugin_interface_t *ply_boot_splash_plugin_get_interface (void); struct _ply_boot_splash_plugin { ply_event_loop_t *loop; ply_boot_splash_mode_t mode; ply_list_t *views; ply_boot_splash_display_type_t state; ply_list_t *messages; }; static view_t * view_new (ply_boot_splash_plugin_t *plugin, ply_text_display_t *display) { view_t *view; view = calloc (1, sizeof (view_t)); view->plugin = plugin; view->display = display; return view; } static void view_free (view_t *view) { free (view); } static void free_views (ply_boot_splash_plugin_t *plugin) { ply_list_node_t *node; node = ply_list_get_first_node (plugin->views); while (node != NULL) { ply_list_node_t *next_node; view_t *view; view = ply_list_node_get_data (node); next_node = ply_list_get_next_node (plugin->views, node); view_free (view); ply_list_remove_node (plugin->views, node); node = next_node; } ply_list_free (plugin->views); plugin->views = NULL; } static void free_messages (ply_boot_splash_plugin_t *plugin) { ply_list_node_t *node; node = ply_list_get_first_node (plugin->messages); while (node != NULL) { ply_list_node_t *next_node; char *message; message = ply_list_node_get_data (node); next_node = ply_list_get_next_node (plugin->messages, node); free (message); ply_list_remove_node (plugin->messages, node); node = next_node; } ply_list_free (plugin->messages); plugin->messages = NULL; } static ply_boot_splash_plugin_t * create_plugin (ply_key_file_t *key_file) { ply_boot_splash_plugin_t *plugin; ply_trace ("creating plugin"); plugin = calloc (1, sizeof (ply_boot_splash_plugin_t)); plugin->views = ply_list_new (); plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL; plugin->messages = ply_list_new (); return plugin; } static void destroy_plugin (ply_boot_splash_plugin_t *plugin) { ply_trace ("destroying plugin"); if (plugin == NULL) return; free_messages (plugin); free_views (plugin); free (plugin); } static void detach_from_event_loop (ply_boot_splash_plugin_t *plugin) { plugin->loop = NULL; ply_trace ("detaching from event loop"); } static void view_write (view_t *view, const char *text, size_t number_of_bytes) { ply_terminal_t *terminal; terminal = ply_text_display_get_terminal (view->display); ply_terminal_write (terminal, "%.*s", (int) number_of_bytes, text); } static void write_on_views (ply_boot_splash_plugin_t *plugin, const char *text, size_t number_of_bytes) { ply_list_node_t *node; if (number_of_bytes == 0) return; node = ply_list_get_first_node (plugin->views); while (node != NULL) { ply_list_node_t *next_node; view_t *view; view = ply_list_node_get_data (node); next_node = ply_list_get_next_node (plugin->views, node); view_write (view, text, number_of_bytes); node = next_node; } } static void add_text_display (ply_boot_splash_plugin_t *plugin, ply_text_display_t *display) { view_t *view; ply_terminal_t *terminal; view = view_new (plugin, display); terminal = ply_text_display_get_terminal (view->display); if (ply_terminal_open (terminal)) { ply_terminal_set_mode (terminal, PLY_TERMINAL_MODE_TEXT); ply_terminal_activate_vt (terminal); } ply_list_append_data (plugin->views, view); } static void remove_text_display (ply_boot_splash_plugin_t *plugin, ply_text_display_t *display) { ply_list_node_t *node; node = ply_list_get_first_node (plugin->views); while (node != NULL) { view_t *view; ply_list_node_t *next_node; view = ply_list_node_get_data (node); next_node = ply_list_get_next_node (plugin->views, node); if (view->display == display) { ply_list_remove_node (plugin->views, node); return; } node = next_node; } } static bool show_splash_screen (ply_boot_splash_plugin_t *plugin, ply_event_loop_t *loop, ply_buffer_t *boot_buffer, ply_boot_splash_mode_t mode) { size_t size; assert (plugin != NULL); plugin->loop = loop; plugin->mode = mode; ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t) detach_from_event_loop, plugin); size = ply_buffer_get_size (boot_buffer); write_on_views (plugin, ply_buffer_get_bytes (boot_buffer), size); return true; } static void update_status (ply_boot_splash_plugin_t *plugin, const char *status) { assert (plugin != NULL); ply_trace ("status update"); } static void on_boot_output (ply_boot_splash_plugin_t *plugin, const char *output, size_t size) { ply_trace ("writing '%s' to all views (%d bytes)", output, (int) size); write_on_views (plugin, output, size); } static void hide_splash_screen (ply_boot_splash_plugin_t *plugin, ply_event_loop_t *loop) { assert (plugin != NULL); ply_trace ("hiding splash screen"); ply_event_loop_stop_watching_for_exit (plugin->loop, (ply_event_loop_exit_handler_t) detach_from_event_loop, plugin); detach_from_event_loop (plugin); } static void display_normal (ply_boot_splash_plugin_t *plugin) { ply_list_node_t *node; if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_NORMAL) write_on_views (plugin, "\r\n", strlen ("\r\n")); plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL; node = ply_list_get_first_node (plugin->messages); while (node != NULL) { const char *message; ply_list_node_t *next_node; message = ply_list_node_get_data (node); next_node = ply_list_get_next_node (plugin->messages, node); write_on_views (plugin, message, strlen (message)); write_on_views (plugin, "\r\n", strlen ("\r\n")); ply_list_remove_node (plugin->messages, node); node = next_node; } } /* @shorten_prompt: * * Points prompt to the character immediately after the * last '\n' in prompt */ static void shorten_prompt(const char ** prompt) { int last_nl=-1, i=0; const char * str = *prompt; for(i=0; str[i] != '\0'; i++) { if(str[i] == '\n') { last_nl = i; } } if (last_nl >= 0) { if((str[last_nl] == '\n') && (last_nl < i)){ *prompt = &str[last_nl + 1]; } } } static void display_password (ply_boot_splash_plugin_t *plugin, const char *prompt, int bullets) { int i; if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY) write_on_views (plugin, "\r\n", strlen ("\r\n")); else write_on_views (plugin, CLEAR_LINE_SEQUENCE, strlen (CLEAR_LINE_SEQUENCE)); plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY; if (prompt) { if (bullets > 0) shorten_prompt(&prompt); write_on_views (plugin, prompt, strlen (prompt)); } else write_on_views (plugin, "Password:", strlen ("Password:")); for (i = 0; i < bullets; i++) write_on_views (plugin, "*", strlen ("*")); } static void display_question (ply_boot_splash_plugin_t *plugin, const char *prompt, const char *entry_text) { if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY) write_on_views (plugin, "\r\n", strlen ("\r\n")); else write_on_views (plugin, CLEAR_LINE_SEQUENCE, strlen (CLEAR_LINE_SEQUENCE)); plugin->state = PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY; if (prompt) write_on_views (plugin, prompt, strlen (prompt)); write_on_views (plugin, ":", strlen (":")); write_on_views (plugin, entry_text, strlen (entry_text)); } static void display_message (ply_boot_splash_plugin_t *plugin, const char *message) { const char *message_to_display; if (!strncmp (message, "keys:", strlen ("keys:"))) message_to_display = message + strlen ("keys:"); else message_to_display = message; if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL) { write_on_views (plugin, message_to_display, strlen (message_to_display)); write_on_views (plugin, "\r\n", strlen ("\r\n")); } else ply_list_append_data (plugin->messages, strdup (message_to_display)); } ply_boot_splash_plugin_interface_t * ply_boot_splash_plugin_get_interface (void) { static ply_boot_splash_plugin_interface_t plugin_interface = { .create_plugin = create_plugin, .destroy_plugin = destroy_plugin, .add_text_display = add_text_display, .remove_text_display = remove_text_display, .show_splash_screen = show_splash_screen, .update_status = update_status, .on_boot_output = on_boot_output, .hide_splash_screen = hide_splash_screen, .display_normal = display_normal, .display_password = display_password, .display_question = display_question, .display_message = display_message, }; return &plugin_interface; } /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */