File indexing completed on 2024-05-19 05:47:17

0001 /*
0002  * Copyright (C) 2016 Harald Sitter <sitter@kde.org>
0003  * Copyright (C) 2010 Canonical Ltd.
0004  * Copyright (C) 2008-2012 Red Hat, Inc.
0005  *
0006  * This program is free software; you can redistribute it and/or modify
0007  * it under the terms of the GNU General Public License as published by
0008  * the Free Software Foundation; either version 2, or (at your option)
0009  * any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License
0017  * along with this program; if not, write to the Free Software
0018  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
0019  * 02111-1307, USA.
0020  *
0021  */
0022 
0023 #include "ply-text-progress-bar.h"
0024 #include <assert.h>
0025 #include <errno.h>
0026 #include <fcntl.h>
0027 #include <math.h>
0028 #include <signal.h>
0029 #include <stdbool.h>
0030 #include <stdio.h>
0031 #include <stdint.h>
0032 #include <stdlib.h>
0033 #include <string.h>
0034 #include <sys/ioctl.h>
0035 #include <sys/stat.h>
0036 #include <sys/time.h>
0037 #include <sys/types.h>
0038 #include <termios.h>
0039 #include <unistd.h>
0040 #include <values.h>
0041 #include <wchar.h>
0042 
0043 #include <ply-trigger.h>
0044 #include <ply-boot-splash-plugin.h>
0045 #include <ply-buffer.h>
0046 #include <ply-event-loop.h>
0047 #include <ply-key-file.h>
0048 #include <ply-list.h>
0049 #include <ply-logger.h>
0050 #include <ply-text-display.h>
0051 #include <ply-utils.h>
0052 
0053 #include <linux/kd.h>
0054 
0055 #define CLEAR_LINE_SEQUENCE "\033[2K\r\n"
0056 #define BACKSPACE "\b\033[0K"
0057 #define PLUGIN_NAME "breeze-text"
0058 
0059 typedef enum {
0060    PLY_BOOT_SPLASH_DISPLAY_NORMAL,
0061    PLY_BOOT_SPLASH_DISPLAY_QUESTION_ENTRY,
0062    PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY
0063 } ply_boot_splash_display_type_t;
0064 
0065 struct _ply_boot_splash_plugin
0066 {
0067   ply_event_loop_t *loop;
0068   ply_boot_splash_mode_t mode;
0069 
0070   ply_list_t *views;
0071 
0072   ply_boot_splash_display_type_t state;
0073 
0074   char *message;
0075 
0076   uint32_t is_animating : 1;
0077   uint32_t black;
0078   uint32_t white;
0079   uint32_t brown;
0080   uint32_t blue;
0081   char *title;
0082 };
0083 
0084 typedef struct
0085 {
0086   ply_boot_splash_plugin_t *plugin;
0087   ply_text_display_t *display;
0088   breeze_text_progress_bar_t *progress_bar;
0089 } view_t;
0090 
0091 static void hide_splash_screen (ply_boot_splash_plugin_t *plugin,
0092                                 ply_event_loop_t         *loop);
0093 
0094 static view_t *
0095 view_new (ply_boot_splash_plugin_t *plugin,
0096           ply_text_display_t       *display)
0097 {
0098   view_t *view;
0099 
0100   view = calloc (1, sizeof (view_t));
0101   view->plugin = plugin;
0102   view->display = display;
0103 
0104   view->progress_bar = breeze_text_progress_bar_new ();
0105 
0106   return view;
0107 }
0108 
0109 static void
0110 view_free (view_t *view)
0111 {
0112   breeze_text_progress_bar_free (view->progress_bar);
0113 
0114   free (view);
0115 }
0116 
0117 static void
0118 view_show_message (view_t *view)
0119 {
0120   ply_boot_splash_plugin_t *plugin;
0121   int display_width, display_height, y;
0122   ply_terminal_color_t color;
0123   char *message;
0124 
0125   plugin = view->plugin;
0126 
0127   display_width = ply_text_display_get_number_of_columns (view->display);
0128   display_height = ply_text_display_get_number_of_rows (view->display);
0129 
0130   if (!strncmp (plugin->message, "keys:", 5))
0131     {
0132       message = plugin->message + 5;
0133       color = PLY_TERMINAL_COLOR_WHITE;
0134       y = display_height - 4;
0135     }
0136   else
0137     {
0138       message = plugin->message;
0139       color = PLY_TERMINAL_COLOR_BLUE;
0140       y = display_height / 2 + 7;
0141     }
0142 
0143   ply_text_display_set_cursor_position (view->display, 0, y);
0144   ply_text_display_clear_line (view->display);
0145   ply_text_display_set_cursor_position (view->display,
0146                                         (display_width -
0147                                         strlen (message)) / 2,
0148                                         y);
0149 
0150   ply_text_display_set_foreground_color (view->display, color);
0151   ply_text_display_write (view->display, "%s", message);
0152 }
0153 
0154 static void
0155 view_show_prompt (view_t     *view,
0156                   const char *prompt,
0157                   const char *entered_text)
0158 {
0159   int display_width, display_height;
0160 
0161   display_width = ply_text_display_get_number_of_columns (view->display);
0162   display_height = ply_text_display_get_number_of_rows (view->display);
0163 
0164   ply_text_display_set_cursor_position (view->display, 0,
0165                                         display_height / 2 + 8);
0166   ply_text_display_clear_line (view->display);
0167   ply_text_display_set_cursor_position (view->display,
0168                                         display_width / 2 - (strlen (prompt)),
0169                                         display_height / 2 + 8);
0170 
0171   ply_text_display_write (view->display, "%s:%s", prompt, entered_text);
0172 
0173   ply_text_display_show_cursor (view->display);
0174 }
0175 
0176 static void
0177 view_start_animation (view_t *view)
0178 {
0179   ply_boot_splash_plugin_t *plugin;
0180   ply_terminal_t *terminal;
0181 
0182   assert (view != NULL);
0183 
0184   plugin = view->plugin;
0185 
0186   terminal = ply_text_display_get_terminal (view->display);
0187 
0188   ply_terminal_set_color_hex_value (terminal,
0189                                     PLY_TERMINAL_COLOR_BLACK,
0190                                     plugin->black);
0191   ply_terminal_set_color_hex_value (terminal,
0192                                     PLY_TERMINAL_COLOR_WHITE,
0193                                     plugin->white);
0194   ply_terminal_set_color_hex_value (terminal,
0195                                     PLY_TERMINAL_COLOR_BLUE,
0196                                     plugin->blue);
0197   ply_terminal_set_color_hex_value (terminal,
0198                                     PLY_TERMINAL_COLOR_BROWN,
0199                                     plugin->brown);
0200 
0201   ply_text_display_set_background_color (view->display,
0202                                          PLY_TERMINAL_COLOR_BLACK);
0203   ply_text_display_clear_screen (view->display);
0204   ply_text_display_hide_cursor (view->display);
0205 
0206   if (plugin->mode == PLY_BOOT_SPLASH_MODE_SHUTDOWN)
0207     {
0208       breeze_text_progress_bar_hide (view->progress_bar);
0209       return;
0210     }
0211 
0212   breeze_text_progress_bar_show (view->progress_bar,
0213                               view->display);
0214 }
0215 
0216 static void
0217 view_redraw (view_t *view)
0218 {
0219   unsigned long screen_width, screen_height;
0220 
0221   screen_width = ply_text_display_get_number_of_columns (view->display);
0222   screen_height = ply_text_display_get_number_of_rows (view->display);
0223 
0224   ply_text_display_draw_area (view->display, 0, 0,
0225                               screen_width, screen_height);
0226 }
0227 
0228 static void
0229 redraw_views (ply_boot_splash_plugin_t *plugin)
0230 {
0231   ply_list_node_t *node;
0232 
0233   node = ply_list_get_first_node (plugin->views);
0234   while (node != NULL)
0235     {
0236       ply_list_node_t *next_node;
0237       view_t *view;
0238 
0239       view = ply_list_node_get_data (node);
0240       next_node = ply_list_get_next_node (plugin->views, node);
0241 
0242       view_redraw (view);
0243 
0244       node = next_node;
0245     }
0246 }
0247 
0248 static void
0249 view_hide (view_t *view)
0250 {
0251   if (view->display != NULL)
0252     {
0253       ply_terminal_t *terminal;
0254 
0255       terminal = ply_text_display_get_terminal (view->display);
0256 
0257       ply_text_display_set_background_color (view->display, PLY_TERMINAL_COLOR_DEFAULT);
0258       ply_text_display_clear_screen (view->display);
0259       ply_text_display_show_cursor (view->display);
0260 
0261       ply_terminal_reset_colors (terminal);
0262     }
0263 }
0264 
0265 static void
0266 hide_views (ply_boot_splash_plugin_t *plugin)
0267 {
0268   ply_list_node_t *node;
0269 
0270   node = ply_list_get_first_node (plugin->views);
0271   while (node != NULL)
0272     {
0273       ply_list_node_t *next_node;
0274       view_t *view;
0275 
0276       view = ply_list_node_get_data (node);
0277       next_node = ply_list_get_next_node (plugin->views, node);
0278 
0279       view_hide (view);
0280 
0281       node = next_node;
0282     }
0283 }
0284 
0285 static void
0286 pause_views (ply_boot_splash_plugin_t *plugin)
0287 {
0288   ply_list_node_t *node;
0289 
0290   node = ply_list_get_first_node (plugin->views);
0291   while (node != NULL)
0292     {
0293       ply_list_node_t *next_node;
0294       view_t *view;
0295 
0296       view = ply_list_node_get_data (node);
0297       next_node = ply_list_get_next_node (plugin->views, node);
0298 
0299       ply_text_display_pause_updates (view->display);
0300 
0301       node = next_node;
0302     }
0303 }
0304 
0305 static void
0306 unpause_views (ply_boot_splash_plugin_t *plugin)
0307 {
0308   ply_list_node_t *node;
0309 
0310   node = ply_list_get_first_node (plugin->views);
0311   while (node != NULL)
0312     {
0313       ply_list_node_t *next_node;
0314       view_t *view;
0315 
0316       view = ply_list_node_get_data (node);
0317       next_node = ply_list_get_next_node (plugin->views, node);
0318 
0319       ply_text_display_unpause_updates (view->display);
0320 
0321       node = next_node;
0322     }
0323 }
0324 
0325 static ply_boot_splash_plugin_t *
0326 create_plugin (ply_key_file_t *key_file)
0327 {
0328   char *option;
0329 
0330   ply_boot_splash_plugin_t *plugin;
0331 
0332   ply_trace ("creating plugin");
0333 
0334   plugin = calloc (1, sizeof (ply_boot_splash_plugin_t));
0335   plugin->message = NULL;
0336 
0337   plugin->views = ply_list_new ();
0338 
0339   /* Not a pretty API for setting defaults for your config file... */
0340   plugin->black = 0x000000;
0341   plugin->white = 0xeff0f1; // progress bar block 1
0342   plugin->blue  = 0xeff0f1; // progress bar block 2
0343   plugin->brown = 0xeff0f1; // progress bar block 3
0344 
0345   option = ply_key_file_get_value (key_file, PLUGIN_NAME, "black");
0346   if (option)
0347     sscanf(option, "0x%x", &plugin->black);
0348   option = ply_key_file_get_value (key_file, PLUGIN_NAME, "white");
0349   if (option)
0350     sscanf(option, "0x%x", &plugin->white);
0351   option = ply_key_file_get_value (key_file, PLUGIN_NAME, "brown");
0352   if (option)
0353     sscanf(option, "0x%x", &plugin->brown);
0354   option = ply_key_file_get_value (key_file, PLUGIN_NAME, "blue");
0355   if (option)
0356     sscanf(option, "0x%x", &plugin->blue);
0357 
0358   plugin->title = ply_key_file_get_value (key_file, PLUGIN_NAME, "title");
0359 
0360   return plugin;
0361 }
0362 
0363 static void
0364 detach_from_event_loop (ply_boot_splash_plugin_t *plugin)
0365 {
0366   plugin->loop = NULL;
0367 
0368   ply_trace ("detaching from event loop");
0369 }
0370 
0371 static void
0372 free_views (ply_boot_splash_plugin_t *plugin)
0373 {
0374   ply_list_node_t *node;
0375 
0376   node = ply_list_get_first_node (plugin->views);
0377 
0378   while (node != NULL)
0379     {
0380       ply_list_node_t *next_node;
0381       view_t *view;
0382 
0383       view = ply_list_node_get_data (node);
0384       next_node = ply_list_get_next_node (plugin->views, node);
0385 
0386       view_free (view);
0387       ply_list_remove_node (plugin->views, node);
0388 
0389       node = next_node;
0390     }
0391 
0392   ply_list_free (plugin->views);
0393   plugin->views = NULL;
0394 }
0395 
0396 static void
0397 destroy_plugin (ply_boot_splash_plugin_t *plugin)
0398 {
0399   ply_trace ("destroying plugin");
0400 
0401   if (plugin == NULL)
0402     return;
0403 
0404   /* It doesn't ever make sense to keep this plugin on screen
0405    * after exit
0406    */
0407   hide_splash_screen (plugin, plugin->loop);
0408 
0409   free_views (plugin);
0410   if (plugin->message != NULL)
0411     free (plugin->message);
0412 
0413   free (plugin);
0414 }
0415 
0416 static void
0417 show_message (ply_boot_splash_plugin_t *plugin)
0418 {
0419   ply_list_node_t *node;
0420 
0421   node = ply_list_get_first_node (plugin->views);
0422   while (node != NULL)
0423     {
0424       ply_list_node_t *next_node;
0425       view_t *view;
0426 
0427       view = ply_list_node_get_data (node);
0428       next_node = ply_list_get_next_node (plugin->views, node);
0429 
0430       view_show_message (view);
0431 
0432       node = next_node;
0433     }
0434 }
0435 
0436 static void
0437 start_animation (ply_boot_splash_plugin_t *plugin)
0438 {
0439   ply_list_node_t *node;
0440 
0441   assert (plugin != NULL);
0442   assert (plugin->loop != NULL);
0443 
0444   redraw_views (plugin);
0445 
0446   if (plugin->message != NULL)
0447     show_message (plugin);
0448 
0449   if (plugin->is_animating)
0450      return;
0451 
0452   node = ply_list_get_first_node (plugin->views);
0453   while (node != NULL)
0454     {
0455       ply_list_node_t *next_node;
0456       view_t *view;
0457 
0458       view = ply_list_node_get_data (node);
0459       next_node = ply_list_get_next_node (plugin->views, node);
0460 
0461       view_start_animation (view);
0462 
0463       node = next_node;
0464     }
0465 
0466   plugin->is_animating = true;
0467 }
0468 
0469 static void
0470 stop_animation (ply_boot_splash_plugin_t *plugin)
0471 {
0472   ply_list_node_t *node;
0473 
0474   assert (plugin != NULL);
0475   assert (plugin->loop != NULL);
0476 
0477   if (!plugin->is_animating)
0478      return;
0479 
0480   plugin->is_animating = false;
0481 
0482   node = ply_list_get_first_node (plugin->views);
0483   while (node != NULL)
0484     {
0485       ply_list_node_t *next_node;
0486       view_t *view;
0487 
0488       view = ply_list_node_get_data (node);
0489       next_node = ply_list_get_next_node (plugin->views, node);
0490 
0491       breeze_text_progress_bar_hide (view->progress_bar);
0492 
0493       node = next_node;
0494     }
0495   redraw_views (plugin);
0496 }
0497 
0498 static void
0499 on_draw (view_t                   *view,
0500          ply_terminal_t           *terminal,
0501          int                       x,
0502          int                       y,
0503          int                       width,
0504          int                       height)
0505 {
0506   ply_text_display_clear_screen (view->display);
0507 }
0508 
0509 static void
0510 add_text_display (ply_boot_splash_plugin_t *plugin,
0511                   ply_text_display_t       *display)
0512 {
0513   view_t *view;
0514   ply_terminal_t *terminal;
0515 
0516   view = view_new (plugin, display);
0517 
0518   terminal = ply_text_display_get_terminal (view->display);
0519   if (ply_terminal_open (terminal))
0520     {
0521       ply_terminal_set_mode (terminal, PLY_TERMINAL_MODE_TEXT);
0522       ply_terminal_activate_vt (terminal);
0523     }
0524 
0525   ply_text_display_set_draw_handler (view->display,
0526                                      (ply_text_display_draw_handler_t)
0527                                      on_draw, view);
0528 
0529   ply_list_append_data (plugin->views, view);
0530 }
0531 
0532 static void
0533 remove_text_display (ply_boot_splash_plugin_t *plugin,
0534                      ply_text_display_t       *display)
0535 {
0536   ply_list_node_t *node;
0537 
0538   node = ply_list_get_first_node (plugin->views);
0539   while (node != NULL)
0540     {
0541       view_t *view;
0542       ply_list_node_t *next_node;
0543 
0544       view = ply_list_node_get_data (node);
0545       next_node = ply_list_get_next_node (plugin->views, node);
0546 
0547       if (view->display == display)
0548         {
0549           ply_text_display_set_draw_handler (view->display,
0550                                              NULL, NULL);
0551           view_free (view);
0552           ply_list_remove_node (plugin->views, node);
0553           return;
0554         }
0555 
0556       node = next_node;
0557     }
0558 }
0559 
0560 static bool
0561 show_splash_screen (ply_boot_splash_plugin_t *plugin,
0562                     ply_event_loop_t         *loop,
0563                     ply_buffer_t             *boot_buffer,
0564                     ply_boot_splash_mode_t    mode)
0565 {
0566   assert (plugin != NULL);
0567 
0568   plugin->loop = loop;
0569   plugin->mode = mode;
0570   ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t)
0571                                  detach_from_event_loop,
0572                                  plugin);
0573 
0574   ply_show_new_kernel_messages (false);
0575   start_animation (plugin);
0576 
0577   return true;
0578 }
0579 
0580 static void
0581 update_status (ply_boot_splash_plugin_t *plugin,
0582                const char               *status)
0583 {
0584   assert (plugin != NULL);
0585 
0586   ply_trace ("status update");
0587 }
0588 
0589 static void
0590 on_boot_progress (ply_boot_splash_plugin_t *plugin,
0591                   double                    duration,
0592                   double                    percent_done)
0593 {
0594   ply_list_node_t *node;
0595   double total_duration;
0596 
0597   total_duration = duration / percent_done;
0598 
0599   /* Fun made-up smoothing function to make the growth asymptotic:
0600    * fraction(time,estimate)=1-2^(-(time^1.45)/estimate) */
0601   percent_done = 1.0 - pow (2.0, -pow (duration, 1.45) / total_duration) * (1.0 - percent_done);
0602 
0603   node = ply_list_get_first_node (plugin->views);
0604 
0605   while (node != NULL)
0606     {
0607       ply_list_node_t *next_node;
0608       view_t *view;
0609 
0610       view = ply_list_node_get_data (node);
0611       next_node = ply_list_get_next_node (plugin->views, node);
0612 
0613       {
0614         int display_width = ply_text_display_get_number_of_columns (view->display);
0615         int display_height = ply_text_display_get_number_of_rows (view->display);
0616 
0617         ply_text_display_set_cursor_position (view->display,
0618                                               (display_width - 12) / 2,
0619                                               display_height / 2);
0620 
0621         ply_text_display_set_background_color (view->display, PLY_TERMINAL_COLOR_BLACK);
0622         ply_text_display_set_foreground_color (view->display, PLY_TERMINAL_COLOR_WHITE);
0623         ply_text_display_write (view->display, "%s", plugin->title);
0624       }
0625 
0626       breeze_text_progress_bar_set_percent_done (view->progress_bar, percent_done);
0627       breeze_text_progress_bar_draw (view->progress_bar);
0628 
0629       node = next_node;
0630     }
0631 }
0632 
0633 static void
0634 hide_splash_screen (ply_boot_splash_plugin_t *plugin,
0635                     ply_event_loop_t         *loop)
0636 {
0637   assert (plugin != NULL);
0638 
0639   ply_trace ("hiding splash screen");
0640 
0641   if (plugin->loop != NULL)
0642     {
0643       stop_animation (plugin);
0644 
0645       ply_event_loop_stop_watching_for_exit (plugin->loop,
0646                                              (ply_event_loop_exit_handler_t)
0647                                              detach_from_event_loop,
0648                                              plugin);
0649       detach_from_event_loop (plugin);
0650     }
0651 
0652   hide_views (plugin);
0653   ply_show_new_kernel_messages (true);
0654 }
0655 
0656 static void
0657 display_normal (ply_boot_splash_plugin_t *plugin)
0658 {
0659   pause_views (plugin);
0660   if (plugin->state != PLY_BOOT_SPLASH_DISPLAY_NORMAL)
0661     {
0662       plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL;
0663       start_animation (plugin);
0664       redraw_views (plugin);
0665     }
0666   unpause_views (plugin);
0667 }
0668 
0669 static void
0670 display_message (ply_boot_splash_plugin_t *plugin,
0671                  const char               *message)
0672 {
0673   if (plugin->message != NULL)
0674     free (plugin->message);
0675 
0676   plugin->message = strdup (message);
0677   start_animation (plugin);
0678 }
0679 
0680 static void
0681 show_password_prompt (ply_boot_splash_plugin_t *plugin,
0682                       const char               *prompt,
0683                       int                       bullets)
0684 {
0685   ply_list_node_t *node;
0686   int i;
0687   char *entered_text;
0688 
0689   entered_text = calloc (bullets + 1, sizeof (char));
0690 
0691   for (i = 0; i < bullets; i++)
0692     entered_text[i] = '*';
0693 
0694   node = ply_list_get_first_node (plugin->views);
0695   while (node != NULL)
0696     {
0697       ply_list_node_t *next_node;
0698       view_t *view;
0699 
0700       view = ply_list_node_get_data (node);
0701       next_node = ply_list_get_next_node (plugin->views, node);
0702 
0703       view_show_prompt (view, prompt, entered_text);
0704 
0705       node = next_node;
0706     }
0707   free (entered_text);
0708 }
0709 
0710 static void
0711 show_prompt (ply_boot_splash_plugin_t *plugin,
0712              const char               *prompt,
0713              const char               *text)
0714 {
0715   ply_list_node_t *node;
0716 
0717   node = ply_list_get_first_node (plugin->views);
0718   while (node != NULL)
0719     {
0720       ply_list_node_t *next_node;
0721       view_t *view;
0722 
0723       view = ply_list_node_get_data (node);
0724       next_node = ply_list_get_next_node (plugin->views, node);
0725 
0726       view_show_prompt (view, prompt, text);
0727 
0728       node = next_node;
0729     }
0730 }
0731 
0732 static void
0733 display_password (ply_boot_splash_plugin_t *plugin,
0734                   const char               *prompt,
0735                   int                       bullets)
0736 {
0737   pause_views (plugin);
0738   if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL)
0739     stop_animation (plugin);
0740 
0741   plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY;
0742 
0743   if (!prompt)
0744     prompt = "Password";
0745 
0746   show_password_prompt (plugin, prompt, bullets);
0747 
0748   unpause_views (plugin);
0749 }
0750 
0751 static void
0752 display_question (ply_boot_splash_plugin_t *plugin,
0753                   const char               *prompt,
0754                   const char               *entry_text)
0755 {
0756   pause_views (plugin);
0757   if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL)
0758     stop_animation (plugin);
0759 
0760   plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY;
0761 
0762   if (!prompt)
0763     prompt = "Password";
0764 
0765   show_prompt (plugin, prompt, entry_text);
0766 
0767   unpause_views (plugin);
0768 }
0769 
0770 ply_boot_splash_plugin_interface_t *
0771 ply_boot_splash_plugin_get_interface (void)
0772 {
0773   static ply_boot_splash_plugin_interface_t plugin_interface =
0774     {
0775       .create_plugin = create_plugin,
0776       .destroy_plugin = destroy_plugin,
0777       .add_text_display = add_text_display,
0778       .remove_text_display = remove_text_display,
0779       .show_splash_screen = show_splash_screen,
0780       .update_status = update_status,
0781       .on_boot_progress = on_boot_progress,
0782       .hide_splash_screen = hide_splash_screen,
0783       .display_normal = display_normal,
0784       .display_message = display_message,
0785       .display_password = display_password,
0786       .display_question = display_question,
0787     };
0788 
0789   return &plugin_interface;
0790 }
0791 
0792 /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */