Blob Blame Raw
From 113b2e27726c5d95c31034dc5e9db1e8b985c963 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 11 May 2011 10:28:47 -0400
Subject: [PATCH] keyboard: handle kernel terminal EIO better

In commit 89096d735f78fab300248962030d6554f9894011 we added
reopen retries when the kernel returns EIO to ply-terminal.c.

This is because when the kernel is closing a tty down, that
tty is unavailable to userspace to reopen.

Unfortunately, that commit neglected to inform the ply-keyboard
part of the code when the terminal retry was successful.  The
upshot of this, is that if plymouthd needs to retry opening the
tty, then the splash screens lose control over the keyboard.

This commit changes how input notification is sent to the keyboard
handling code, so the tty disconnects are transparent.
---
 src/libply-splash-core/ply-keyboard.c |   27 ++-------
 src/libply-splash-core/ply-terminal.c |  100 +++++++++++++++++++++++++++++++-
 src/libply-splash-core/ply-terminal.h |   10 +++-
 3 files changed, 112 insertions(+), 25 deletions(-)

diff --git a/src/libply-splash-core/ply-keyboard.c b/src/libply-splash-core/ply-keyboard.c
index b5b4c39..624f906 100644
--- a/src/libply-splash-core/ply-keyboard.c
+++ b/src/libply-splash-core/ply-keyboard.c
@@ -65,7 +65,6 @@ typedef enum
 typedef struct
 {
   ply_terminal_t *terminal;
-  ply_fd_watch_t *input_watch;
   ply_buffer_t   *key_buffer;
 } ply_keyboard_terminal_provider_t;
 
@@ -342,15 +341,6 @@ on_terminal_data (ply_keyboard_t *keyboard)
   on_key_event (keyboard, keyboard->provider.if_terminal->key_buffer);
 }
 
-static void
-on_terminal_disconnected (ply_keyboard_t *keyboard)
-{
-  ply_trace ("keyboard input terminal watch invalidated, rewatching");
-  keyboard->provider.if_terminal->input_watch = NULL;
-
-  ply_keyboard_watch_for_terminal_input (keyboard);
-}
-
 static bool
 ply_keyboard_watch_for_terminal_input (ply_keyboard_t *keyboard)
 {
@@ -366,10 +356,9 @@ ply_keyboard_watch_for_terminal_input (ply_keyboard_t *keyboard)
       return false;
     }
 
-  keyboard->provider.if_terminal->input_watch = ply_event_loop_watch_fd (keyboard->loop, terminal_fd, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
-                                                                         (ply_event_handler_t) on_terminal_data,
-                                                                         (ply_event_handler_t) on_terminal_disconnected,
-                                                                         keyboard);
+  ply_terminal_watch_for_input (keyboard->provider.if_terminal->terminal,
+                                (ply_terminal_input_handler_t) on_terminal_data,
+                                keyboard);
 
   return true;
 }
@@ -377,12 +366,10 @@ ply_keyboard_watch_for_terminal_input (ply_keyboard_t *keyboard)
 static void
 ply_keyboard_stop_watching_for_terminal_input (ply_keyboard_t *keyboard)
 {
-  if (keyboard->provider.if_terminal->input_watch == NULL)
-    return;
-
-  ply_event_loop_stop_watching_fd (keyboard->loop,
-                                   keyboard->provider.if_terminal->input_watch);
-  keyboard->provider.if_terminal->input_watch = NULL;
+  ply_terminal_stop_watching_for_input (keyboard->provider.if_terminal->terminal,
+                                        (ply_terminal_input_handler_t)
+                                        on_terminal_data,
+                                        keyboard);
 }
 
 bool
diff --git a/src/libply-splash-core/ply-terminal.c b/src/libply-splash-core/ply-terminal.c
index c11a6dd..8876aa0 100644
--- a/src/libply-splash-core/ply-terminal.c
+++ b/src/libply-splash-core/ply-terminal.c
@@ -60,6 +60,12 @@
 
 typedef struct
 {
+  ply_terminal_input_handler_t handler;
+  void *user_data;
+} ply_terminal_input_closure_t;
+
+typedef struct
+{
   ply_terminal_active_vt_changed_handler_t handler;
   void *user_data;
 } ply_terminal_active_vt_changed_closure_t;
@@ -78,6 +84,7 @@ struct _ply_terminal
   int   number_of_reopen_tries;
 
   ply_list_t *vt_change_closures;
+  ply_list_t *input_closures;
   ply_fd_watch_t *fd_watch;
   ply_terminal_color_t foreground_color;
   ply_terminal_color_t background_color;
@@ -118,6 +125,7 @@ ply_terminal_new (const char *device_name)
 
   terminal->loop = ply_event_loop_get_default ();
   terminal->vt_change_closures = ply_list_new ();
+  terminal->input_closures = ply_list_new ();
 
   if (strncmp (device_name, "/dev/", strlen ("/dev/")) == 0)
     terminal->name = strdup (device_name);
@@ -361,6 +369,28 @@ ply_terminal_reopen_device (ply_terminal_t *terminal)
 }
 
 static void
+on_tty_input (ply_terminal_t *terminal)
+{
+
+  ply_list_node_t *node;
+
+  node = ply_list_get_first_node (terminal->input_closures);
+  while (node != NULL)
+    {
+      ply_terminal_input_closure_t *closure;
+      ply_list_node_t *next_node;
+
+      closure = ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (terminal->input_closures, node);
+
+      if (closure->handler != NULL)
+        closure->handler (closure->user_data, terminal);
+
+      node = next_node;
+    }
+}
+
+static void
 on_tty_disconnected (ply_terminal_t *terminal)
 {
   ply_trace ("tty disconnected (fd %d)", terminal->fd);
@@ -559,10 +589,10 @@ ply_terminal_open_device (ply_terminal_t *terminal)
     }
 
   terminal->fd_watch = ply_event_loop_watch_fd (terminal->loop, terminal->fd,
-                                                   PLY_EVENT_LOOP_FD_STATUS_NONE,
-                                                   (ply_event_handler_t) NULL,
-                                                   (ply_event_handler_t) on_tty_disconnected,
-                                                   terminal);
+                                                PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
+                                                (ply_event_handler_t) on_tty_input,
+                                                (ply_event_handler_t) on_tty_disconnected,
+                                                terminal);
 
   ply_terminal_check_for_vt (terminal);
 
@@ -805,6 +835,26 @@ free_vt_change_closures (ply_terminal_t *terminal)
   ply_list_free (terminal->vt_change_closures);
 }
 
+static void
+free_input_closures (ply_terminal_t *terminal)
+{
+  ply_list_node_t *node;
+
+  node = ply_list_get_first_node (terminal->input_closures);
+  while (node != NULL)
+    {
+      ply_terminal_input_closure_t *closure;
+      ply_list_node_t *next_node;
+
+      closure = ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (terminal->input_closures, node);
+
+      free (closure);
+      node = next_node;
+    }
+  ply_list_free (terminal->input_closures);
+}
+
 void
 ply_terminal_free (ply_terminal_t *terminal)
 {
@@ -830,6 +880,7 @@ ply_terminal_free (ply_terminal_t *terminal)
     ply_terminal_close (terminal);
 
   free_vt_change_closures (terminal);
+  free_input_closures (terminal);
   free (terminal->name);
   free (terminal);
 }
@@ -1001,4 +1052,45 @@ ply_terminal_stop_watching_for_active_vt_change (ply_terminal_t *terminal,
     }
 }
 
+void
+ply_terminal_watch_for_input (ply_terminal_t               *terminal,
+                              ply_terminal_input_handler_t  input_handler,
+                              void                         *user_data)
+{
+  ply_terminal_input_closure_t *closure;
+
+  closure = calloc (1, sizeof (*closure));
+  closure->handler = input_handler;
+  closure->user_data = user_data;
+
+  ply_list_append_data (terminal->input_closures, closure);
+}
+
+void
+ply_terminal_stop_watching_for_input (ply_terminal_t               *terminal,
+                                      ply_terminal_input_handler_t  input_handler,
+                                      void                         *user_data)
+{
+  ply_list_node_t *node;
+
+  node = ply_list_get_first_node (terminal->input_closures);
+  while (node != NULL)
+    {
+      ply_terminal_input_closure_t *closure;
+      ply_list_node_t *next_node;
+
+      closure = ply_list_node_get_data (node);
+      next_node = ply_list_get_next_node (terminal->input_closures, node);
+
+      if (closure->handler == input_handler &&
+          closure->user_data == user_data)
+        {
+          free (closure);
+          ply_list_remove_node (terminal->input_closures, node);
+        }
+
+      node = next_node;
+    }
+}
+
 /* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
diff --git a/src/libply-splash-core/ply-terminal.h b/src/libply-splash-core/ply-terminal.h
index 2eb9950..8b4b017 100644
--- a/src/libply-splash-core/ply-terminal.h
+++ b/src/libply-splash-core/ply-terminal.h
@@ -33,7 +33,8 @@
 typedef struct _ply_terminal ply_terminal_t;
 typedef void (* ply_terminal_active_vt_changed_handler_t) (void           *user_data,
                                                            ply_terminal_t *terminal);
-
+typedef void (* ply_terminal_input_handler_t) (void           *user_data,
+                                               ply_terminal_t *terminal);
 typedef enum
 {
   PLY_TERMINAL_COLOR_BLACK = 0,
@@ -104,6 +105,13 @@ void ply_terminal_stop_watching_for_active_vt_change (ply_terminal_t *terminal,
                                                       ply_terminal_active_vt_changed_handler_t active_vt_changed_handler,
                                                       void *user_data);
 
+void ply_terminal_watch_for_input (ply_terminal_t *terminal,
+                                   ply_terminal_input_handler_t input_handler,
+                                   void *user_data);
+void ply_terminal_stop_watching_for_input (ply_terminal_t *terminal,
+                                           ply_terminal_input_handler_t input_handler,
+                                           void *user_data);
+
 #endif
 
 #endif /* PLY_TERMINAL_H */
-- 
1.7.5