From b96ff001587de11eaf98ace71b196cc5ab4cf007 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 14 Jul 2014 08:04:54 -0400 Subject: [PATCH 1/5] seat: be a little more forgiving in the case there's no open terminal We can end up in a situation where a seat object doesn't have a terminal associated with it. In that case we shouldn't crash, but continue on with no input available for that seat. https://bugs.freedesktop.org/show_bug.cgi?id=80553 --- src/libply-splash-core/ply-seat.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/libply-splash-core/ply-seat.c b/src/libply-splash-core/ply-seat.c index 2ac8bf7..cd7e5bc 100644 --- a/src/libply-splash-core/ply-seat.c +++ b/src/libply-splash-core/ply-seat.c @@ -127,68 +127,83 @@ ply_seat_open (ply_seat_t *seat, if (renderer_type != PLY_RENDERER_TYPE_NONE) { ply_renderer_t *renderer; renderer = ply_renderer_new (renderer_type, device, seat->terminal); if (!ply_renderer_open (renderer)) { ply_trace ("could not open renderer for %s", device); ply_renderer_free (renderer); seat->renderer = NULL; seat->renderer_active = false; if (renderer_type != PLY_RENDERER_TYPE_AUTO) return false; } else { seat->renderer = renderer; seat->renderer_active = true; } } if (seat->renderer != NULL) { seat->keyboard = ply_keyboard_new_for_renderer (seat->renderer); add_pixel_displays (seat); } - else + else if (seat->terminal != NULL) { seat->keyboard = ply_keyboard_new_for_terminal (seat->terminal); } - add_text_displays (seat); - ply_keyboard_watch_for_input (seat->keyboard); - seat->keyboard_active = true; + if (seat->terminal != NULL) + { + add_text_displays (seat); + } + else + { + ply_trace ("not adding text display for seat, since seat has no associated terminal"); + } + + if (seat->keyboard != NULL) + { + ply_keyboard_watch_for_input (seat->keyboard); + seat->keyboard_active = true; + } + else + { + ply_trace ("not watching seat for input"); + } return true; } bool ply_seat_is_open (ply_seat_t *seat) { return ply_list_get_length (seat->pixel_displays) > 0 || ply_list_get_length (seat->text_displays) > 0; } void ply_seat_deactivate_keyboard (ply_seat_t *seat) { if (!seat->keyboard_active) return; seat->keyboard_active = false; if (seat->keyboard == NULL) return; ply_trace ("deactivating keybord"); ply_keyboard_stop_watching_for_input (seat->keyboard); } void ply_seat_deactivate_renderer (ply_seat_t *seat) { if (!seat->renderer_active) -- 2.3.7 From b5ed92bc2efd0b52e901a67ea8e5afa809ca3598 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 3 Jul 2015 09:29:39 -0400 Subject: [PATCH 2/5] main: show cursor on crash --- src/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main.c b/src/main.c index 77fa96f..db5c281 100644 --- a/src/main.c +++ b/src/main.c @@ -2051,66 +2051,69 @@ on_error_message (ply_buffer_t *debug_buffer, { ply_buffer_append_bytes (debug_buffer, bytes, number_of_bytes); } static void dump_debug_buffer_to_file (void) { int fd; const char *bytes; size_t size; fd = open (debug_buffer_path, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd < 0) return; size = ply_buffer_get_size (debug_buffer); bytes = ply_buffer_get_bytes (debug_buffer); ply_write (fd, bytes, size); close (fd); } #include #include static void on_crash (int signum) { struct termios term_attributes; int fd; + static const char *show_cursor_sequence = "\033[?25h"; fd = open ("/dev/tty1", O_RDWR | O_NOCTTY); if (fd < 0) fd = open ("/dev/hvc0", O_RDWR | O_NOCTTY); ioctl (fd, KDSETMODE, KD_TEXT); + write (fd, show_cursor_sequence, sizeof (show_cursor_sequence) - 1); + tcgetattr (fd, &term_attributes); term_attributes.c_iflag |= BRKINT | IGNPAR | ICRNL | IXON; term_attributes.c_oflag |= OPOST; term_attributes.c_lflag |= ECHO | ICANON | ISIG | IEXTEN; tcsetattr (fd, TCSAFLUSH, &term_attributes); close (fd); if (debug_buffer != NULL) { dump_debug_buffer_to_file (); sleep (30); } if (pid_file != NULL) { unlink (pid_file); free (pid_file); pid_file = NULL; } signal (signum, SIG_DFL); raise(signum); } static void write_pid_file (const char *filename) { -- 2.3.7 From 4278596f4f5a6856aff50e97b7c0ff05aed67372 Mon Sep 17 00:00:00 2001 From: Frederic Crozat Date: Thu, 12 Jun 2014 15:01:37 +0200 Subject: [PATCH 3/5] device-manager: only call ply_terminal_free ply_terminal_free will call ply_terminal_close anyway and is guarded against NULL terminal (ply_terminal_close is not). --- src/libply-splash-core/ply-device-manager.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libply-splash-core/ply-device-manager.c b/src/libply-splash-core/ply-device-manager.c index 8f5360c..17607f4 100644 --- a/src/libply-splash-core/ply-device-manager.c +++ b/src/libply-splash-core/ply-device-manager.c @@ -415,61 +415,60 @@ free_seats (ply_device_manager_t *manager) { ply_list_node_t *node; ply_trace ("removing seats"); node = ply_list_get_first_node (manager->seats); while (node != NULL) { ply_seat_t *seat; ply_list_node_t *next_node; seat = ply_list_node_get_data (node); next_node = ply_list_get_next_node (manager->seats, node); if (manager->seat_removed_handler != NULL) manager->seat_removed_handler (manager->seat_event_handler_data, seat); ply_seat_free (seat); ply_list_remove_node (manager->seats, node); node = next_node; } } static void free_terminal (char *device, ply_terminal_t *terminal, ply_device_manager_t *manager) { ply_hashtable_remove (manager->terminals, device); - ply_terminal_close (terminal); ply_terminal_free (terminal); } static void free_terminals (ply_device_manager_t *manager) { ply_hashtable_foreach (manager->terminals, (ply_hashtable_foreach_func_t *) free_terminal, manager); } static ply_terminal_t * get_terminal (ply_device_manager_t *manager, const char *device_name) { char *full_name = NULL; ply_terminal_t *terminal; if (strncmp (device_name, "/dev/", strlen ("/dev/")) == 0) full_name = strdup (device_name); else asprintf (&full_name, "/dev/%s", device_name); if (strcmp (full_name, "/dev/tty0") == 0 || strcmp (full_name, "/dev/tty") == 0 || strcmp (full_name, ply_terminal_get_name (manager->local_console_terminal)) == 0) { terminal = manager->local_console_terminal; -- 2.3.7 From e7048fdd1a40ed683fc706a40816cc490a693ba9 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 7 Jan 2015 16:24:57 -0500 Subject: [PATCH 4/5] device-manager: try fb device if drm device failed If the drm device failed to work, then fall back to the fb device. Right now, we ignore fb devices that have associated drm devices. This may fix vmwgfx. --- src/libply-splash-core/ply-device-manager.c | 39 ++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/libply-splash-core/ply-device-manager.c b/src/libply-splash-core/ply-device-manager.c index 17607f4..cc153e2 100644 --- a/src/libply-splash-core/ply-device-manager.c +++ b/src/libply-splash-core/ply-device-manager.c @@ -88,95 +88,132 @@ attach_to_event_loop (ply_device_manager_t *manager, } static bool device_is_for_local_console (ply_device_manager_t *manager, struct udev_device *device) { const char *device_path; struct udev_device *bus_device; char *bus_device_path; const char *boot_vga; bool for_local_console; /* Look at the associated bus device to see if this card is the * card the kernel is using for its console. */ device_path = udev_device_get_syspath (device); asprintf (&bus_device_path, "%s/device", device_path); bus_device = udev_device_new_from_syspath (manager->udev_context, bus_device_path); boot_vga = udev_device_get_sysattr_value (bus_device, "boot_vga"); free (bus_device_path); if (boot_vga != NULL && strcmp (boot_vga, "1") == 0) for_local_console = true; else for_local_console = false; return for_local_console; } static bool +drm_device_in_use (ply_device_manager_t *manager, + const char *device_path) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (manager->seats); + while (node != NULL) + { + ply_seat_t *seat; + ply_renderer_t *renderer; + ply_list_node_t *next_node; + const char *renderer_device_path; + + seat = ply_list_node_get_data (node); + next_node = ply_list_get_next_node (manager->seats, node); + renderer = ply_seat_get_renderer (seat); + + if (renderer != NULL) + { + renderer_device_path = ply_renderer_get_device_name (renderer); + + if (renderer_device_path != NULL) + { + if (strcmp (device_path, renderer_device_path) == 0) + { + return true; + } + } + } + + node = next_node; + } + + return false; +} + +static bool fb_device_has_drm_device (ply_device_manager_t *manager, struct udev_device *fb_device) { struct udev_enumerate *card_matches; struct udev_list_entry *card_entry; const char *id_path; bool has_drm_device = false; /* We want to see if the framebuffer is associated with a DRM-capable * graphics card, if it is, we'll use the DRM device */ card_matches = udev_enumerate_new (manager->udev_context); udev_enumerate_add_match_is_initialized(card_matches); udev_enumerate_add_match_parent (card_matches, udev_device_get_parent (fb_device)); udev_enumerate_add_match_subsystem (card_matches, "drm"); id_path = udev_device_get_property_value (fb_device, "ID_PATH"); udev_enumerate_add_match_property (card_matches, "ID_PATH", id_path); ply_trace ("trying to find associated drm node for fb device (path: %s)", id_path); udev_enumerate_scan_devices (card_matches); /* there should only ever be at most one match so we don't iterate through * the list, but just look at the first entry */ card_entry = udev_enumerate_get_list_entry (card_matches); if (card_entry != NULL) { struct udev_device *card_device = NULL; const char *card_node; const char *card_path; card_path = udev_list_entry_get_name (card_entry); card_device = udev_device_new_from_syspath (manager->udev_context, card_path); card_node = udev_device_get_devnode (card_device); - if (card_node != NULL) + if (card_node != NULL && drm_device_in_use (manager, card_node)) has_drm_device = true; else ply_trace ("no card node!"); udev_device_unref (card_device); } else { ply_trace ("no card entry!"); } udev_enumerate_unref (card_matches); return has_drm_device; } static void create_seat_for_udev_device (ply_device_manager_t *manager, struct udev_device *device) { bool for_local_console; const char *device_path; ply_terminal_t *terminal = NULL; for_local_console = device_is_for_local_console (manager, device); ply_trace ("device is for local console: %s", for_local_console? "yes" : "no"); if (for_local_console) terminal = manager->local_console_terminal; -- 2.3.7 From b9989b912fb394c00d3d4740eb72a25f80a8bc71 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 3 Jul 2015 10:38:47 -0400 Subject: [PATCH 5/5] device-manager: don't try to load graphical splash after using text splash We only support loading one splash at a time at the moment, so this commit makes sure we don't load a graphical splash after already loading a text splash --- src/libply-splash-core/ply-device-manager.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/libply-splash-core/ply-device-manager.c b/src/libply-splash-core/ply-device-manager.c index cc153e2..a7890d0 100644 --- a/src/libply-splash-core/ply-device-manager.c +++ b/src/libply-splash-core/ply-device-manager.c @@ -379,61 +379,69 @@ create_seats_for_subsystem (ply_device_manager_t *manager, return found_device; } static void on_udev_event (ply_device_manager_t *manager) { struct udev_device *device; const char *action; device = udev_monitor_receive_device (manager->udev_monitor); if (device == NULL) return; action = udev_device_get_action (device); ply_trace ("got %s event for device %s", action, udev_device_get_sysname (device)); if (action == NULL) return; if (strcmp (action, "add") == 0) { const char *subsystem; bool coldplug_complete = manager->udev_queue_fd_watch == NULL; subsystem = udev_device_get_subsystem (device); if (strcmp (subsystem, SUBSYSTEM_DRM) == 0 || coldplug_complete) { - create_seat_for_udev_device (manager, device); + ply_list_t *local_pixel_displays = NULL; + + if (manager->local_console_seat != NULL) + local_pixel_displays = ply_seat_get_pixel_displays (manager->local_console_seat); + + if (coldplug_complete && manager->local_console_seat != NULL && local_pixel_displays == NULL) + ply_trace ("ignoring since we're already using text splash for local console"); + else + create_seat_for_udev_device (manager, device); } else { ply_trace ("ignoring since we only handle subsystem %s devices after coldplug completes", subsystem); } } else if (strcmp (action, "remove") == 0) { free_seat_for_udev_device (manager, device); } udev_device_unref (device); } static void watch_for_udev_events (ply_device_manager_t *manager) { int fd; assert (manager != NULL); assert (manager->udev_monitor == NULL); ply_trace ("watching for udev graphics device add and remove events"); manager->udev_monitor = udev_monitor_new_from_netlink (manager->udev_context, "udev"); udev_monitor_filter_add_match_subsystem_devtype (manager->udev_monitor, SUBSYSTEM_DRM, NULL); udev_monitor_filter_add_match_subsystem_devtype (manager->udev_monitor, SUBSYSTEM_FRAME_BUFFER, NULL); udev_monitor_filter_add_match_tag (manager->udev_monitor, "seat"); udev_monitor_enable_receiving (manager->udev_monitor); -- 2.3.7