static void ply_boot_client_process_pending_requests (ply_boot_client_t *client) { ply_list_node_t *request_node; ply_boot_client_request_t *request; assert (ply_list_get_length (client->requests_to_send) != 0); assert (client->daemon_can_take_request_watch != NULL); request_node = ply_list_get_first_node (client->requests_to_send); assert (request_node != NULL); request = (ply_boot_client_request_t *) ply_list_node_get_data (request_node); assert (request != NULL); ply_list_remove_node (client->requests_to_send, request_node); if (ply_boot_client_send_request (client, request)) ply_list_append_data (client->requests_waiting_for_replies, request); if (ply_list_get_length (client->requests_to_send) == 0) { if (client->daemon_has_reply_watch != NULL) { assert (client->loop != NULL); ply_event_loop_stop_watching_fd (client->loop, client->daemon_can_take_request_watch); client->daemon_can_take_request_watch = NULL; } } }
static void ply_boot_client_cancel_unsent_requests (ply_boot_client_t *client) { ply_list_node_t *node; if (ply_list_get_length (client->requests_to_send) == 0) return; node = ply_list_get_first_node (client->requests_to_send); while (node != NULL) { ply_list_node_t *next_node; ply_boot_client_request_t *request; request = (ply_boot_client_request_t *) ply_list_node_get_data (node); next_node = ply_list_get_next_node (client->requests_to_send, node); ply_boot_client_cancel_request (client, request); ply_list_remove_node (client->requests_to_send, node); node = next_node; } if (client->daemon_can_take_request_watch != NULL) { assert (client->loop != NULL); ply_event_loop_stop_watching_fd (client->loop, client->daemon_can_take_request_watch); client->daemon_can_take_request_watch = NULL; } }
static void unmap_from_device (ply_renderer_backend_t *backend) { ply_list_node_t *node; bool should_set_to_black; /* We only copy what's on screen back to the fb console * if there's one head (since in multihead set ups the fb console * is cloned). */ should_set_to_black = ply_list_get_length (backend->heads) > 1; node = ply_list_get_first_node (backend->heads); while (node != NULL) { ply_list_node_t *next_node; ply_renderer_head_t *head; head = (ply_renderer_head_t *) ply_list_node_get_data (node); next_node = ply_list_get_next_node (backend->heads, node); if (backend->is_active) { ply_trace ("scanning out %s directly to console", should_set_to_black? "black" : "splash"); ply_renderer_head_set_scan_out_buffer_to_console (backend, head, should_set_to_black); } ply_renderer_head_unmap (backend, head); node = next_node; } }
static bool ply_boot_client_send_request (ply_boot_client_t *client, ply_boot_client_request_t *request) { char *request_string; size_t request_size; assert (client != NULL); assert (request != NULL); request_string = ply_boot_client_get_request_string (client, request, &request_size); if (!ply_write (client->socket_fd, request_string, request_size)) { free (request_string); ply_boot_client_cancel_request (client, request); return false; } free (request_string); if (client->daemon_has_reply_watch == NULL) { assert (ply_list_get_length (client->requests_waiting_for_replies) == 0); client->daemon_has_reply_watch = ply_event_loop_watch_fd (client->loop, client->socket_fd, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA, (ply_event_handler_t) ply_boot_client_process_incoming_replies, NULL, client); } return true; }
static void add_pixel_displays (ply_seat_t *seat) { ply_list_t *heads; ply_list_node_t *node; heads = ply_renderer_get_heads (seat->renderer); ply_trace ("Adding displays for %d heads", ply_list_get_length (heads)); node = ply_list_get_first_node (heads); while (node != NULL) { ply_list_node_t *next_node; ply_renderer_head_t *head; ply_pixel_display_t *display; head = ply_list_node_get_data (node); next_node = ply_list_get_next_node (heads, node); display = ply_pixel_display_new (seat->renderer, head); ply_list_append_data (seat->pixel_displays, display); 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) { assert (plugin != NULL); if (ply_list_get_length (plugin->displays) == 0) { ply_trace ("no pixel displays"); return false; } plugin->loop = loop; plugin->mode = mode; ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t) detach_from_event_loop, plugin); ply_event_loop_watch_signal (plugin->loop, SIGINT, (ply_event_handler_t) on_interrupt, plugin); ply_trace ("starting boot animation"); return start_animation (plugin); }
void ply_boot_client_flush (ply_boot_client_t *client) { assert (client != NULL); while (ply_list_get_length (client->requests_to_send) > 0) { ply_event_loop_process_pending_events (client->loop); } }
static void ply_boot_client_queue_request (ply_boot_client_t *client, const char *request_command, const char *request_argument, ply_boot_client_response_handler_t handler, ply_boot_client_response_handler_t failed_handler, void *user_data) { assert (client != NULL); assert (client->loop != NULL); assert (request_command != NULL); assert (request_argument == NULL || strlen (request_argument) <= UCHAR_MAX); assert (handler != NULL); if (client->daemon_can_take_request_watch == NULL && client->socket_fd >= 0) { assert (ply_list_get_length (client->requests_to_send) == 0); client->daemon_can_take_request_watch = ply_event_loop_watch_fd (client->loop, client->socket_fd, PLY_EVENT_LOOP_FD_STATUS_CAN_TAKE_DATA, (ply_event_handler_t) ply_boot_client_process_pending_requests, NULL, client); } if (!client->is_connected) { if (failed_handler != NULL) { failed_handler (user_data, client); } } else { ply_boot_client_request_t *request; request = ply_boot_client_request_new (client, request_command, request_argument, handler, failed_handler, user_data); ply_list_append_data (client->requests_to_send, request); } }
static void free_text_displays (ply_seat_t *seat) { ply_list_node_t *node; ply_trace ("freeing %d text displays", ply_list_get_length (seat->text_displays)); node = ply_list_get_first_node (seat->text_displays); while (node != NULL) { ply_list_node_t *next_node; ply_text_display_t *display; next_node = ply_list_get_next_node (seat->text_displays, node); display = ply_list_node_get_data (node); ply_text_display_free (display); ply_list_remove_node (seat->text_displays, node); node = next_node; } }
static void ply_boot_connection_on_request (ply_boot_connection_t *connection) { ply_boot_server_t *server; char *command, *argument; assert (connection != NULL); assert (connection->fd >= 0); server = connection->server; assert (server != NULL); if (!ply_boot_connection_read_request (connection, &command, &argument)) { ply_trace ("could not read connection request"); return; } if (!ply_boot_connection_is_from_root (connection)) { ply_error ("request came from non-root user"); if (!ply_write (connection->fd, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_NAK, strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_NAK))) ply_error ("could not write bytes: %m"); free (command); return; } if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_UPDATE) == 0) { ply_trace ("got update request"); if (server->update_handler != NULL) server->update_handler (server->user_data, argument, server); free (argument); } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_SYSTEM_INITIALIZED) == 0) { ply_trace ("got system initialized notification"); if (server->system_initialized_handler != NULL) server->system_initialized_handler (server->user_data, server); } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_ERROR) == 0) { ply_trace ("got error notification"); if (server->error_handler != NULL) server->error_handler (server->user_data, server); } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_SHOW_SPLASH) == 0) { ply_trace ("got show splash request"); if (server->show_splash_handler != NULL) server->show_splash_handler (server->user_data, server); } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_HIDE_SPLASH) == 0) { ply_trace ("got hide splash request"); if (server->hide_splash_handler != NULL) server->hide_splash_handler (server->user_data, server); } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_DEACTIVATE) == 0) { ply_trigger_t *deactivate_trigger; ply_trace ("got deactivate request"); deactivate_trigger = ply_trigger_new (NULL); ply_trigger_add_handler (deactivate_trigger, (ply_trigger_handler_t) ply_boot_connection_on_deactivated, connection); if (server->deactivate_handler != NULL) server->deactivate_handler (server->user_data, deactivate_trigger, server); free (argument); free (command); return; } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_REACTIVATE) == 0) { ply_trace ("got reactivate request"); if (server->reactivate_handler != NULL) server->reactivate_handler (server->user_data, server); } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_QUIT) == 0) { bool retain_splash; ply_trigger_t *quit_trigger; retain_splash = (bool) argument[0]; ply_trace ("got quit %srequest", retain_splash? "--retain-splash " : ""); quit_trigger = ply_trigger_new (NULL); ply_trigger_add_handler (quit_trigger, (ply_trigger_handler_t) ply_boot_connection_on_quit_complete, connection); if (server->quit_handler != NULL) server->quit_handler (server->user_data, retain_splash, quit_trigger, server); free(argument); free(command); return; } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_PASSWORD) == 0) { ply_trigger_t *answer; ply_trace ("got password request"); answer = ply_trigger_new (NULL); ply_trigger_add_handler (answer, (ply_trigger_handler_t) ply_boot_connection_on_password_answer, connection); if (server->ask_for_password_handler != NULL) server->ask_for_password_handler (server->user_data, argument, answer, server); /* will reply later */ free(command); return; } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_CACHED_PASSWORD) == 0) { ply_list_node_t *node; ply_buffer_t *buffer; size_t buffer_size; uint32_t size; ply_trace ("got cached password request"); buffer = ply_buffer_new (); node = ply_list_get_first_node (server->cached_passwords); ply_trace ("There are %d cached passwords", ply_list_get_length (server->cached_passwords)); /* Add each answer separated by their NUL terminators into * a buffer that we write out to the client */ while (node != NULL) { ply_list_node_t *next_node; const char *password; next_node = ply_list_get_next_node (server->cached_passwords, node); password = (const char *) ply_list_node_get_data (node); ply_buffer_append_bytes (buffer, password, strlen (password) + 1); node = next_node; } buffer_size = ply_buffer_get_size (buffer); /* splash plugin doesn't have any cached passwords */ if (buffer_size == 0) { if (!ply_write (connection->fd, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_NO_ANSWER, strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_NO_ANSWER))) ply_error ("could not write bytes: %m"); } else { size = buffer_size; ply_trace ("writing %d cached answers", ply_list_get_length (server->cached_passwords)); if (!ply_write (connection->fd, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_MULTIPLE_ANSWERS, strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_MULTIPLE_ANSWERS)) || !ply_write_uint32 (connection->fd, size) || !ply_write (connection->fd, ply_buffer_get_bytes (buffer), size)) ply_error ("could not write bytes: %m"); } ply_buffer_free (buffer); free(command); return; } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_QUESTION) == 0) { ply_trigger_t *answer; ply_trace ("got question request"); answer = ply_trigger_new (NULL); ply_trigger_add_handler (answer, (ply_trigger_handler_t) ply_boot_connection_on_question_answer, connection); if (server->ask_question_handler != NULL) server->ask_question_handler (server->user_data, argument, answer, server); /* will reply later */ free(command); return; } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_MESSAGE) == 0) { ply_trace ("got message request"); if (server->display_message_handler != NULL) server->display_message_handler(server->user_data, argument, server); } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_KEYSTROKE) == 0) { ply_trigger_t *answer; ply_trace ("got keystroke request"); answer = ply_trigger_new (NULL); ply_trigger_add_handler (answer, (ply_trigger_handler_t) ply_boot_connection_on_keystroke_answer, connection); if (server->watch_for_keystroke_handler != NULL) server->watch_for_keystroke_handler (server->user_data, argument, answer, server); /* will reply later */ free(command); return; } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_KEYSTROKE_REMOVE) == 0) { ply_trace ("got keystroke remove request"); if (server->ignore_keystroke_handler != NULL) server->ignore_keystroke_handler (server->user_data, argument, server); } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_PROGRESS_PAUSE) == 0) { ply_trace ("got progress pause request"); if (server->progress_pause_handler != NULL) server->progress_pause_handler (server->user_data, server); } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_PROGRESS_UNPAUSE) == 0) { ply_trace ("got progress unpause request"); if (server->progress_unpause_handler != NULL) server->progress_unpause_handler (server->user_data, server); } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_NEWROOT) == 0) { ply_trace ("got newroot request"); if (server->newroot_handler != NULL) server->newroot_handler(server->user_data, argument, server); } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_HAS_ACTIVE_VT) == 0) { bool answer = false; ply_trace ("got has_active vt? request"); if (server->has_active_vt_handler != NULL) answer = server->has_active_vt_handler(server->user_data, server); if (!answer) { if (!ply_write (connection->fd, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_NAK, strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_NAK))) ply_error ("could not write bytes: %m"); free(command); return; } } else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_PING) != 0) { ply_error ("received unknown command '%s' from client", command); if (!ply_write (connection->fd, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_NAK, strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_NAK))) ply_error ("could not write bytes: %m"); free(command); return; } if (!ply_write (connection->fd, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK, strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK))) { ply_error ("could not write bytes: %m"); } free(command); }
static void ply_boot_client_process_incoming_replies (ply_boot_client_t *client) { ply_list_node_t *request_node; ply_boot_client_request_t *request; bool processed_reply; uint8_t byte[2] = ""; uint32_t size; assert (client != NULL); processed_reply = false; if (ply_list_get_length (client->requests_waiting_for_replies) == 0) { ply_error ("received unexpected response from boot status daemon"); return; } if (!ply_read (client->socket_fd, byte, sizeof (uint8_t))) goto out; for (request_node = ply_list_get_first_node (client->requests_waiting_for_replies); request_node; request_node = ply_list_get_next_node (client->requests_waiting_for_replies, request_node)) { assert (request_node != NULL); request = (ply_boot_client_request_t *) ply_list_node_get_data (request_node); assert (request != NULL); if (! strcmp (request->command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_PASSWORD) || ! strcmp (request->command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_QUESTION) || ! strcmp (request->command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_KEYSTROKE)) { if (! memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ANSWER, sizeof (uint8_t)) || ! memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_NO_ANSWER, sizeof (uint8_t))) break; } else { if (memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ANSWER, sizeof (uint8_t)) && memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_NO_ANSWER, sizeof (uint8_t))) break; } } if (memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK, sizeof (uint8_t)) == 0) request->handler (request->user_data, client); else if (memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ANSWER, sizeof (uint8_t)) == 0) { char *answer; if (!ply_read_uint32 (client->socket_fd, &size)) goto out; answer = malloc ((size+1) * sizeof(char)); if (size > 0) { if (!ply_read (client->socket_fd, answer, size)) goto out; } answer[size] = '\0'; ((ply_boot_client_answer_handler_t) request->handler) (request->user_data, answer, client); free(answer); } else if (memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_MULTIPLE_ANSWERS, sizeof (uint8_t)) == 0) { ply_array_t *array; char **answers; char *answer; char *p; char *q; uint8_t i; array = NULL; answers = NULL; if (!ply_read_uint32 (client->socket_fd, &size)) goto out; assert (size > 0); answer = malloc (size); if (!ply_read (client->socket_fd, answer, size)) { free (answer); goto out; } array = ply_array_new (); p = answer; q = p; for (i = 0; i < size; i++, q++) { if (*q == '\0') { ply_array_add_element (array, strdup (p)); p = q + 1; } } free (answer); answers = (char **) ply_array_steal_elements (array); ply_array_free (array); ((ply_boot_client_multiple_answers_handler_t) request->handler) (request->user_data, (const char * const *) answers, client); ply_free_string_array (answers); } else if (memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_NO_ANSWER, sizeof (uint8_t)) == 0) { ((ply_boot_client_answer_handler_t) request->handler) (request->user_data, NULL, client); } else goto out; processed_reply = true; out: if (!processed_reply) { if (request->failed_handler != NULL) request->failed_handler (request->user_data, client); } ply_list_remove_node (client->requests_waiting_for_replies, request_node); if (ply_list_get_length (client->requests_waiting_for_replies) == 0) { if (client->daemon_has_reply_watch != NULL) { assert (client->loop != NULL); ply_event_loop_stop_watching_fd (client->loop, client->daemon_has_reply_watch); client->daemon_has_reply_watch = NULL; } } }
static bool create_heads_for_active_connectors (ply_renderer_backend_t *backend) { int i; drmModeConnector *connector; ply_hashtable_t *heads_by_controller_id; heads_by_controller_id = ply_hashtable_new (NULL, NULL); for (i = 0; i < backend->resources->count_connectors; i++) { ply_renderer_head_t *head; drmModeEncoder *encoder; uint32_t encoder_id; drmModeCrtc *controller; uint32_t controller_id; uint32_t console_buffer_id; int connector_mode_index; connector = drmModeGetConnector (backend->device_fd, backend->resources->connectors[i]); if (connector == NULL) continue; if (connector->connection != DRM_MODE_CONNECTED) { drmModeFreeConnector (connector); continue; } if (connector->count_modes <= 0) { drmModeFreeConnector (connector); continue; } encoder = find_encoder_for_connector (backend, connector); if (encoder == NULL) { drmModeFreeConnector (connector); continue; } encoder_id = encoder->encoder_id; controller = find_controller_for_encoder (backend, encoder); drmModeFreeEncoder (encoder); if (controller == NULL) { drmModeFreeConnector (connector); continue; } controller_id = controller->crtc_id; connector_mode_index = get_index_of_active_mode (backend, controller, connector); /* If we couldn't find the current active mode, fall back to the first available. */ if (connector_mode_index < 0) { ply_trace ("falling back to first available mode"); connector_mode_index = 0; } console_buffer_id = controller->buffer_id; drmModeFreeCrtc (controller); head = ply_hashtable_lookup (heads_by_controller_id, (void *) (intptr_t) controller_id); if (head == NULL) { head = ply_renderer_head_new (backend, connector, connector_mode_index, encoder_id, controller_id, console_buffer_id); ply_list_append_data (backend->heads, head); ply_hashtable_insert (heads_by_controller_id, (void *) (intptr_t) controller_id, head); } else { if (!ply_renderer_head_add_connector (head, connector, connector_mode_index)) { ply_trace ("couldn't connect monitor to existing head"); } drmModeFreeConnector (connector); } } ply_hashtable_free (heads_by_controller_id); #ifdef PLY_ENABLE_DEPRECATED_GDM_TRANSITION /* If the driver doesn't support mapping the fb console * then we can't get a smooth crossfade transition to * the display manager unless we use the /dev/fb interface * or the plymouth deactivate interface. * * In multihead configurations, we'd rather have working * multihead, but otherwise bail now. */ if (!backend->driver_supports_mapping_console && ply_list_get_length (backend->heads) == 1) { ply_list_node_t *node; ply_renderer_head_t *head; node = ply_list_get_first_node (backend->heads); head = (ply_renderer_head_t *) ply_list_node_get_data (node); if (ply_array_get_size (head->connector_ids) == 1) { ply_trace ("Only one monitor configured, and driver doesn't " "support mapping console, so letting frame-buffer " "take over"); free_heads (backend); return false; } } #endif return ply_list_get_length (backend->heads) > 0; }
static bool create_heads_for_active_connectors (ply_renderer_backend_t *backend) { int i; drmModeConnector *connector; for (i = 0; i < backend->resources->count_connectors; i++) { ply_renderer_head_t *head; drmModeEncoder *encoder; uint32_t controller_id; uint32_t encoder_id; uint32_t console_buffer_id; drmModeModeInfo *mode; connector = drmModeGetConnector (backend->device_fd, backend->resources->connectors[i]); if (connector == NULL) continue; if (connector->connection != DRM_MODE_CONNECTED) { drmModeFreeConnector (connector); continue; } if (connector->count_modes <= 0) { drmModeFreeConnector (connector); continue; } encoder = find_encoder_for_connector (backend, connector); if (encoder == NULL) { drmModeFreeConnector (connector); continue; } encoder_id = encoder->encoder_id; controller_id = find_controller_for_encoder (backend, encoder); drmModeFreeEncoder (encoder); if (controller_id == 0) { drmModeFreeConnector (connector); continue; } mode = get_active_mode_for_connector (backend, connector); console_buffer_id = get_console_buffer_id (backend, controller_id); head = ply_renderer_head_new (backend, connector, encoder_id, controller_id, console_buffer_id, mode); ply_list_append_data (backend->heads, head); } #ifdef PLY_ENABLE_GDM_TRANSITION /* If the driver doesn't support mapping the fb console * then we can't get a smooth crossfade transition to * the display manager unless we use the /dev/fb interface * or the plymouth deactivate interface. * * In multihead configurations, we'd rather have working * multihead, but otherwise bail now. */ if (!backend->driver_supports_mapping_console && ply_list_get_length (backend->heads) == 1) { ply_trace ("Only one monitor configured, and driver doesn't " "support mapping console, so letting frame-buffer " "take over"); free_heads (backend); return false; } #endif return ply_list_get_length (backend->heads) > 0; }
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; }