[PATCH] Add support for scrolling boot log messages

Ray Strode halfline at gmail.com
Tue Mar 4 05:05:54 PST 2014


Hey Pali,

Sorry for the sluggish response.  Would you mind putting the patch in
bugzilla? I do appreciate you working on this, and I don't want it to
get lost. I'm hoping to look at the patch soon, I just haven't had an
opportunity to read through it carefully yet.

--Ray

On Sat, Nov 23, 2013 at 1:13 PM, Pali Rohár <pali.rohar at gmail.com> wrote:
> On Wednesday 27 June 2012 21:51:51 Ray Strode wrote:
>> hi,
>>
>> > and current argument is status name (const char *). Command
>> > and argument are passing to function
>> > ply_boot_client_queue_request.
>> >
>> > How to add to this protocol/function operation-id argument?
>>
>> So the code does:
>>
>>   request_string = NULL;
>>   asprintf (&request_string, "%s\002%c%s", request->command,
>>             (char) (strlen (request->argument) + 1),
>> request->argument); *request_size = strlen (request_string) +
>> 1;
>>
>> I guess I would change it to:
>>
>>   request_string = NULL;
>>   asprintf (&request_string, "%s\002%c%s\035%c%s",
>> request->command, (char) (strlen (request->argument_1) + 1),
>> request->argument_1, (char) (strlen (request->argument_2) +
>> 1), request->argument_2); *request_size = strlen
>> (request_string) + 1;
>>
>> (or so)
>>
>>  \035 is just a random control character from "man ascii" that
>> seemed reasonable enough to use
>>
>> --Ray
>
> Hello Ray,
>
> after long time I finished my patch for boot log messages. I added
> register-operation and unregister-operation commands for it as
> you suggested. Here is patch generated by git format-patch:
>
> From a0a797d05208c8a134e5f6cfe185965b5f788755 Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali.rohar at gmail.com>
> Date: Sat, 23 Nov 2013 17:39:53 +0100
> Subject: [PATCH] Add support for operation log messages
>
> This patch adding support for operation log messages and updating upstart
> bridge code to use it. This is usefull for verbose log output (e.g daemon
> starting, stopping).
>
> Example:
>
>  Register operation ssh:
>  $ plymouth register-operation --operation-id=ssh --name='Starting OpenSSH server ssh'
>
>  Set state of operation ssh to wait:
>  $ plymouth update --operation-id=ssh --status="wait"
>  Details plugin will show: 'Starting OpenSSH server ssh... [wait]'
>
>  Set state of operation ssh to done:
>  $ plymouth update --operation-id=ssh --status="done"
>  Details plugin will show: 'Starting OpenSSH server ssh... [done]'
>
>  Unregister operation ssh:
>  $ plymouth unregister-operation --operation-id=ssh
> ---
>  src/client/ply-boot-client.c                    |  126 ++++++++++----
>  src/client/ply-boot-client.h                    |   13 ++
>  src/client/plymouth.c                           |   99 ++++++++++-
>  src/libply-splash-core/ply-boot-splash-plugin.h |    9 +-
>  src/libply-splash-core/ply-boot-splash.c        |   32 +++-
>  src/libply-splash-core/ply-boot-splash.h        |    8 +-
>  src/libply/ply-progress.c                       |   40 +++--
>  src/libply/ply-progress.h                       |    2 +-
>  src/main.c                                      |   35 +++-
>  src/plugins/splash/details/plugin.c             |  146 +++++++++++++++-
>  src/plugins/splash/fade-throbber/plugin.c       |    3 +-
>  src/plugins/splash/script/plugin.c              |   28 +++-
>  src/plugins/splash/script/script-lib-plymouth.c |   54 +++++-
>  src/plugins/splash/script/script-lib-plymouth.h |   12 +-
>  src/plugins/splash/space-flares/plugin.c        |    3 +-
>  src/plugins/splash/text/plugin.c                |    3 +-
>  src/plugins/splash/throbgress/plugin.c          |    3 +-
>  src/plugins/splash/two-step/plugin.c            |    3 +-
>  src/ply-boot-protocol.h                         |    2 +
>  src/ply-boot-server.c                           |  144 ++++++++++++----
>  src/ply-boot-server.h                           |   14 +-
>  src/upstart-bridge/ply-upstart-monitor.c        |    2 +-
>  src/upstart-bridge/plymouth-upstart-bridge.c    |  205 +++++++----------------
>  23 files changed, 739 insertions(+), 247 deletions(-)
>
> diff --git a/src/client/ply-boot-client.c b/src/client/ply-boot-client.c
> index 56458ce..a3425df 100644
> --- a/src/client/ply-boot-client.c
> +++ b/src/client/ply-boot-client.c
> @@ -1,6 +1,7 @@
>  /* ply-boot-client.h - APIs for talking to the boot status daemon
>   *
>   * Copyright (C) 2007 Red Hat, Inc.
> + * Copyright (C) 2012 Pali Rohár <pali.rohar at gmail.com>
>   *
>   * 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
> @@ -55,7 +56,8 @@ typedef struct
>  {
>    ply_boot_client_t *client;
>    char *command;
> -  char *argument;
> +  char *argument_1;
> +  char *argument_2;
>    ply_boot_client_response_handler_t handler;
>    ply_boot_client_response_handler_t failed_handler;
>    void *user_data;
> @@ -208,7 +210,8 @@ ply_boot_client_connect (ply_boot_client_t *client,
>  static ply_boot_client_request_t *
>  ply_boot_client_request_new (ply_boot_client_t                  *client,
>                               const char                         *request_command,
> -                             const char                         *request_argument,
> +                             const char                         *request_argument_1,
> +                             const char                         *request_argument_2,
>                               ply_boot_client_response_handler_t  handler,
>                               ply_boot_client_response_handler_t  failed_handler,
>                               void                               *user_data)
> @@ -221,8 +224,10 @@ ply_boot_client_request_new (ply_boot_client_t                  *client,
>    request = calloc (1, sizeof (ply_boot_client_request_t));
>    request->client = client;
>    request->command = strdup (request_command);
> -  if (request_argument != NULL)
> -    request->argument = strdup (request_argument);
> +  if (request_argument_1 != NULL)
> +    request->argument_1 = strdup (request_argument_1);
> +  if (request_argument_2 != NULL)
> +    request->argument_2 = strdup (request_argument_2);
>    request->handler = handler;
>    request->failed_handler = failed_handler;
>    request->user_data = user_data;
> @@ -236,8 +241,8 @@ ply_boot_client_request_free (ply_boot_client_request_t *request)
>    if (request == NULL)
>      return;
>    free (request->command);
> -  if (request->argument != NULL)
> -    free (request->argument);
> +  free (request->argument_1);
> +  free (request->argument_2);
>    free (request);
>  }
>
> @@ -389,6 +394,7 @@ ply_boot_client_get_request_string (ply_boot_client_t         *client,
>                                      size_t                    *request_size)
>  {
>    char *request_string;
> +  int ret;
>
>    assert (client != NULL);
>    assert (request != NULL);
> @@ -396,19 +402,37 @@ ply_boot_client_get_request_string (ply_boot_client_t         *client,
>
>    assert (request->command != NULL);
>
> -  if (request->argument == NULL)
> +  if (request->argument_1 == NULL && request->argument_2 == NULL)
>      {
>        request_string = strdup (request->command);
>        *request_size = strlen (request_string) + 1;
>        return request_string;
>      }
>
> -  assert (strlen (request->argument) <= UCHAR_MAX);
> +  assert (strlen (request->argument_1) <= UCHAR_MAX);
>
>    request_string = NULL;
> -  asprintf (&request_string, "%s\002%c%s", request->command,
> -            (char) (strlen (request->argument) + 1), request->argument);
> -  *request_size = strlen (request_string) + 1;
> +
> +  if (request->argument_2 == NULL)
> +    {
> +      ret = asprintf (&request_string, "%s\002%c%s", request->command,
> +                (char) (strlen (request->argument_1) + 1), request->argument_1);
> +    }
> +  else
> +    {
> +      assert (request->argument_1 != NULL);
> +      assert (strlen (request->argument_2) <= UCHAR_MAX);
> +      ret = asprintf (&request_string, "%s\003%c%s%c%c%s", request->command,
> +                (char) (strlen (request->argument_1) + 1),
> +                request->argument_1,
> +                0,
> +                (char) (strlen (request->argument_2) + 1),
> +                request->argument_2);
> +    }
> +
> +  assert (ret > 0);
> +
> +  *request_size = (size_t)ret + 1;
>
>    return request_string;
>  }
> @@ -482,7 +506,8 @@ ply_boot_client_process_pending_requests (ply_boot_client_t *client)
>  static void
>  ply_boot_client_queue_request (ply_boot_client_t                  *client,
>                                 const char                         *request_command,
> -                               const char                         *request_argument,
> +                               const char                         *request_argument_1,
> +                               const char                         *request_argument_2,
>                                 ply_boot_client_response_handler_t  handler,
>                                 ply_boot_client_response_handler_t  failed_handler,
>                                 void                               *user_data)
> @@ -490,7 +515,8 @@ ply_boot_client_queue_request (ply_boot_client_t                  *client,
>    assert (client != NULL);
>    assert (client->loop != NULL);
>    assert (request_command != NULL);
> -  assert (request_argument == NULL || strlen (request_argument) <= UCHAR_MAX);
> +  assert (request_argument_1 == NULL || strlen (request_argument_1) <= UCHAR_MAX);
> +  assert (request_argument_2 == NULL || strlen (request_argument_2) <= UCHAR_MAX);
>
>    if (client->daemon_can_take_request_watch == NULL &&
>        client->socket_fd >= 0)
> @@ -516,7 +542,8 @@ ply_boot_client_queue_request (ply_boot_client_t                  *client,
>        ply_boot_client_request_t *request;
>
>        request = ply_boot_client_request_new (client, request_command,
> -                                             request_argument,
> +                                             request_argument_1,
> +                                             request_argument_2,
>                                               handler, failed_handler, user_data);
>        ply_list_append_data (client->requests_to_send, request);
>      }
> @@ -531,12 +558,39 @@ ply_boot_client_ping_daemon (ply_boot_client_t                  *client,
>    assert (client != NULL);
>
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_PING,
> -                                 NULL, handler, failed_handler, user_data);
> +                                 NULL, NULL, handler, failed_handler, user_data);
> +}
> +
> +void ply_boot_client_register_operation (ply_boot_client_t                  *client,
> +                                         const char                         *operation_id,
> +                                         const char                         *name,
> +                                         ply_boot_client_response_handler_t  handler,
> +                                         ply_boot_client_response_handler_t  failed_handler,
> +                                         void                               *user_data)
> +{
> +  assert (client != NULL);
> +
> +  ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_REGISTER,
> +                                 operation_id, name, handler, failed_handler, user_data);
> +
> +
> +}
> +void ply_boot_client_unregister_operation (ply_boot_client_t                  *client,
> +                                           const char                         *operation_id,
> +                                           ply_boot_client_response_handler_t  handler,
> +                                           ply_boot_client_response_handler_t  failed_handler,
> +                                           void                               *user_data)
> +{
> +  assert (client != NULL);
> +
> +  ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_UNREGISTER,
> +                                 operation_id, NULL, handler, failed_handler, user_data);
>  }
>
>  void
>  ply_boot_client_update_daemon (ply_boot_client_t                  *client,
>                                 const char                         *status,
> +                               const char                         *operation_id,
>                                 ply_boot_client_response_handler_t  handler,
>                                 ply_boot_client_response_handler_t  failed_handler,
>                                 void                               *user_data)
> @@ -544,7 +598,7 @@ ply_boot_client_update_daemon (ply_boot_client_t                  *client,
>    assert (client != NULL);
>
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_UPDATE,
> -                                 status, handler, failed_handler, user_data);
> +                                 status, operation_id, handler, failed_handler, user_data);
>  }
>
>  void
> @@ -557,7 +611,7 @@ ply_boot_client_change_mode (ply_boot_client_t                  *client,
>    assert (client != NULL);
>
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_CHANGE_MODE,
> -                                 new_mode, handler, failed_handler, user_data);
> +                                 new_mode, NULL, handler, failed_handler, user_data);
>  }
>
>  void
> @@ -570,7 +624,7 @@ ply_boot_client_system_update (ply_boot_client_t                  *client,
>    assert (client != NULL);
>
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_SYSTEM_UPDATE,
> -                                 progress, handler, failed_handler, user_data);
> +                                 progress, NULL, handler, failed_handler, user_data);
>  }
>
>  void
> @@ -584,7 +638,7 @@ ply_boot_client_tell_daemon_to_change_root (ply_boot_client_t                  *
>    assert (root_dir != NULL);
>
>    ply_boot_client_queue_request(client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_NEWROOT,
> -                                root_dir, handler, failed_handler, user_data);
> +                                root_dir, NULL, handler, failed_handler, user_data);
>  }
>
>  void
> @@ -598,7 +652,7 @@ ply_boot_client_tell_daemon_to_display_message (ply_boot_client_t
>    assert (message != NULL);
>
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_SHOW_MESSAGE,
> -                                 message, handler, failed_handler, user_data);
> +                                 message, NULL, handler, failed_handler, user_data);
>  }
>
>  void
> @@ -612,7 +666,7 @@ ply_boot_client_tell_daemon_to_hide_message (ply_boot_client_t
>    assert (message != NULL);
>
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_HIDE_MESSAGE,
> -                                 message, handler, failed_handler, user_data);
> +                                 message, NULL, handler, failed_handler, user_data);
>  }
>
>  void
> @@ -625,7 +679,7 @@ ply_boot_client_tell_daemon_system_is_initialized (ply_boot_client_t
>
>    ply_boot_client_queue_request (client,
>                                   PLY_BOOT_PROTOCOL_REQUEST_TYPE_SYSTEM_INITIALIZED,
> -                                 NULL, handler, failed_handler, user_data);
> +                                 NULL, NULL, handler, failed_handler, user_data);
>  }
>
>  void
> @@ -639,7 +693,7 @@ ply_boot_client_ask_daemon_for_password (ply_boot_client_t                  *cli
>    assert (client != NULL);
>
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_PASSWORD,
> -                                 prompt, (ply_boot_client_response_handler_t)
> +                                 prompt, NULL, (ply_boot_client_response_handler_t)
>                                   handler, failed_handler, user_data);
>  }
>
> @@ -652,7 +706,7 @@ ply_boot_client_ask_daemon_for_cached_passwords (ply_boot_client_t
>    assert (client != NULL);
>
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_CACHED_PASSWORD,
> -                                 NULL, (ply_boot_client_response_handler_t)
> +                                 NULL, NULL, (ply_boot_client_response_handler_t)
>                                   handler, failed_handler, user_data);
>  }
>
> @@ -666,7 +720,7 @@ ply_boot_client_ask_daemon_question     (ply_boot_client_t                    *c
>    assert (client != NULL);
>
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_QUESTION,
> -                                 prompt, (ply_boot_client_response_handler_t)
> +                                 prompt, NULL, (ply_boot_client_response_handler_t)
>                                   handler, failed_handler, user_data);
>  }
>
> @@ -680,7 +734,7 @@ ply_boot_client_ask_daemon_to_watch_for_keystroke (ply_boot_client_t           *
>    assert (client != NULL);
>
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_KEYSTROKE,
> -                                 keys, (ply_boot_client_response_handler_t)
> +                                 keys, NULL, (ply_boot_client_response_handler_t)
>                                   handler, failed_handler, user_data);
>  }
>
> @@ -694,7 +748,7 @@ ply_boot_client_ask_daemon_to_ignore_keystroke (ply_boot_client_t
>    assert (client != NULL);
>
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_KEYSTROKE_REMOVE,
> -                                 keys, (ply_boot_client_response_handler_t)
> +                                 keys, NULL, (ply_boot_client_response_handler_t)
>                                   handler, failed_handler, user_data);
>  }
>
> @@ -707,7 +761,7 @@ ply_boot_client_tell_daemon_to_show_splash (ply_boot_client_t                  *
>    assert (client != NULL);
>
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_SHOW_SPLASH,
> -                                 NULL, handler, failed_handler, user_data);
> +                                 NULL, NULL, handler, failed_handler, user_data);
>  }
>
>  void
> @@ -719,7 +773,7 @@ ply_boot_client_tell_daemon_to_hide_splash (ply_boot_client_t                  *
>    assert (client != NULL);
>
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_HIDE_SPLASH,
> -                                 NULL, handler, failed_handler, user_data);
> +                                 NULL, NULL, handler, failed_handler, user_data);
>  }
>
>  void
> @@ -731,7 +785,7 @@ ply_boot_client_tell_daemon_to_deactivate (ply_boot_client_t                  *c
>    assert (client != NULL);
>
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_DEACTIVATE,
> -                                 NULL, handler, failed_handler, user_data);
> +                                 NULL, NULL, handler, failed_handler, user_data);
>  }
>
>  void
> @@ -743,7 +797,7 @@ ply_boot_client_tell_daemon_to_reactivate (ply_boot_client_t                  *c
>    assert (client != NULL);
>
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_REACTIVATE,
> -                                 NULL, handler, failed_handler, user_data);
> +                                 NULL, NULL, handler, failed_handler, user_data);
>  }
>
>  void
> @@ -759,7 +813,7 @@ ply_boot_client_tell_daemon_to_quit (ply_boot_client_t                  *client,
>
>    arg[0] = (char) (retain_splash != false);
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_QUIT,
> -                                 arg, handler, failed_handler, user_data);
> +                                 arg, NULL, handler, failed_handler, user_data);
>  }
>
>  void
> @@ -769,7 +823,7 @@ ply_boot_client_tell_daemon_to_progress_pause (ply_boot_client_t
>                                                 void                               *user_data)
>  {
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_PROGRESS_PAUSE,
> -                                 NULL, handler, failed_handler, user_data);
> +                                 NULL, NULL, handler, failed_handler, user_data);
>  }
>
>  void
> @@ -779,7 +833,7 @@ ply_boot_client_tell_daemon_to_progress_unpause (ply_boot_client_t
>                                                   void                               *user_data)
>  {
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_PROGRESS_UNPAUSE,
> -                                 NULL, handler, failed_handler, user_data);
> +                                 NULL, NULL, handler, failed_handler, user_data);
>  }
>
>  void
> @@ -789,7 +843,7 @@ ply_boot_client_ask_daemon_has_active_vt (ply_boot_client_t                  *cl
>                                            void                               *user_data)
>  {
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_HAS_ACTIVE_VT,
> -                                 NULL, handler, failed_handler, user_data);
> +                                 NULL, NULL, handler, failed_handler, user_data);
>  }
>
>  void
> @@ -799,7 +853,7 @@ ply_boot_client_tell_daemon_about_error (ply_boot_client_t                  *cli
>                                           void                               *user_data)
>  {
>    ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_ERROR,
> -                                 NULL, handler, failed_handler, user_data);
> +                                 NULL, NULL, handler, failed_handler, user_data);
>  }
>
>  void
> diff --git a/src/client/ply-boot-client.h b/src/client/ply-boot-client.h
> index 24939f7..8154a5c 100644
> --- a/src/client/ply-boot-client.h
> +++ b/src/client/ply-boot-client.h
> @@ -1,6 +1,7 @@
>  /* ply-boot-client.h - APIs for talking to the boot status daemon
>   *
>   * Copyright (C) 2007 Red Hat, Inc.
> + * Copyright (C) 2012 Pali Rohár <pali.rohar at gmail.com>
>   *
>   * 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
> @@ -53,8 +54,20 @@ void ply_boot_client_ping_daemon (ply_boot_client_t                  *client,
>                                    ply_boot_client_response_handler_t  handler,
>                                    ply_boot_client_response_handler_t  failed_handler,
>                                    void                               *user_data);
> +void ply_boot_client_register_operation (ply_boot_client_t                  *client,
> +                                         const char                         *operation_id,
> +                                         const char                         *name,
> +                                         ply_boot_client_response_handler_t  handler,
> +                                         ply_boot_client_response_handler_t  failed_handler,
> +                                         void                               *user_data);
> +void ply_boot_client_unregister_operation (ply_boot_client_t                  *client,
> +                                           const char                         *operation_id,
> +                                           ply_boot_client_response_handler_t  handler,
> +                                           ply_boot_client_response_handler_t  failed_handler,
> +                                           void                               *user_data);
>  void ply_boot_client_update_daemon (ply_boot_client_t                  *client,
>                                      const char                         *new_status,
> +                                    const char                         *operation_id,
>                                      ply_boot_client_response_handler_t  handler,
>                                      ply_boot_client_response_handler_t  failed_handler,
>                                      void                               *user_data);
> diff --git a/src/client/plymouth.c b/src/client/plymouth.c
> index e00208d..d103025 100644
> --- a/src/client/plymouth.c
> +++ b/src/client/plymouth.c
> @@ -1,6 +1,7 @@
>  /* plymouth.c - updates boot status
>   *
>   * Copyright (C) 2007 Red Hat, Inc
> + * Copyright (C) 2012 Pali Rohár <pali.rohar at gmail.com>
>   *
>   * This file is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License as published
> @@ -841,10 +842,72 @@ on_hide_splash_request (state_t    *state,
>  }
>
>  static void
> +on_register_operation_request (state_t    *state,
> +                               const char *command)
> +{
> +  char *operation_id;
> +  char *name;
> +
> +  operation_id = NULL;
> +  ply_command_parser_get_command_options (state->command_parser,
> +                                          command,
> +                                          "operation-id", &operation_id,
> +                                          NULL);
> +
> +  name = NULL;
> +  ply_command_parser_get_command_options (state->command_parser,
> +                                          command,
> +                                          "name", &name,
> +                                          NULL);
> +
> +  if (operation_id != NULL && name != NULL)
> +    {
> +      ply_boot_client_register_operation(state->client, operation_id, name,
> +                                         (ply_boot_client_response_handler_t)
> +                                         on_success,
> +                                         (ply_boot_client_response_handler_t)
> +                                         on_failure, state);
> +    }
> +  else
> +    {
> +      ply_error ("unknown operation id or name");
> +      ply_event_loop_exit (state->loop, 1);
> +    }
> +}
> +
> +static void
> +on_unregister_operation_request (state_t    *state,
> +                               const char *command)
> +{
> +  char *operation_id;
> +
> +  operation_id = NULL;
> +  ply_command_parser_get_command_options (state->command_parser,
> +                                          command,
> +                                          "operation-id", &operation_id,
> +                                          NULL);
> +
> +  if (operation_id != NULL)
> +    {
> +      ply_boot_client_unregister_operation(state->client, operation_id,
> +                                         (ply_boot_client_response_handler_t)
> +                                         on_success,
> +                                         (ply_boot_client_response_handler_t)
> +                                         on_failure, state);
> +    }
> +  else
> +    {
> +      ply_error ("unknown operation id");
> +      ply_event_loop_exit (state->loop, 1);
> +    }
> +}
> +
> +static void
>  on_update_request (state_t    *state,
>                     const char *command)
>  {
>    char *status;
> +  const char *operation_id;
>
>    status = NULL;
>    ply_command_parser_get_command_options (state->command_parser,
> @@ -852,9 +915,19 @@ on_update_request (state_t    *state,
>                                            "status", &status,
>                                            NULL);
>
> +  operation_id = NULL;
> +  ply_command_parser_get_command_options (state->command_parser,
> +                                          command,
> +                                          "operation-id", &operation_id,
> +                                          NULL);
> +
> +  if (operation_id == NULL)
> +    operation_id = "";
> +
>    if (status != NULL)
>      {
> -      ply_boot_client_update_daemon (state->client, status,
> +
> +      ply_boot_client_update_daemon (state->client, status, operation_id,
>                                       (ply_boot_client_response_handler_t)
>                                       on_success,
>                                       (ply_boot_client_response_handler_t)
> @@ -974,6 +1047,8 @@ main (int    argc,
>                                    "hide-splash", "Hide splash screen", PLY_COMMAND_OPTION_TYPE_FLAG,
>                                    "ask-for-password", "Ask user for password", PLY_COMMAND_OPTION_TYPE_FLAG,
>                                    "ignore-keystroke", "Remove sensitivity to a keystroke", PLY_COMMAND_OPTION_TYPE_STRING,
> +                                  "register-operation", "Tell boot daemon to register operation", PLY_COMMAND_OPTION_TYPE_STRING,
> +                                  "unregister-operation", "Tell boot daemon to unregister operation", PLY_COMMAND_OPTION_TYPE_STRING,
>                                    "update", "Tell boot daemon an update about boot progress", PLY_COMMAND_OPTION_TYPE_STRING,
>                                    "details", "Tell boot daemon there were errors during boot", PLY_COMMAND_OPTION_TYPE_FLAG,
>                                    "wait", "Wait for boot daemon to quit", PLY_COMMAND_OPTION_TYPE_FLAG,
> @@ -1000,9 +1075,29 @@ main (int    argc,
>                                    NULL);
>
>    ply_command_parser_add_command (state.command_parser,
> +                                  "register-operation", "Tell boot daemon to register operation",
> +                                  (ply_command_handler_t)
> +                                  on_register_operation_request, &state,
> +                                  "operation-id", "Operation id",
> +                                  PLY_COMMAND_OPTION_TYPE_STRING,
> +                                  "name", "Operation name",
> +                                  PLY_COMMAND_OPTION_TYPE_STRING,
> +                                  NULL);
> +
> +  ply_command_parser_add_command (state.command_parser,
> +                                  "unregister-operation", "Tell boot daemon to unregister operation",
> +                                  (ply_command_handler_t)
> +                                  on_unregister_operation_request, &state,
> +                                  "operation-id", "Operation id",
> +                                  PLY_COMMAND_OPTION_TYPE_STRING,
> +                                  NULL);
> +
> +  ply_command_parser_add_command (state.command_parser,
>                                    "update", "Tell daemon about boot status changes",
>                                    (ply_command_handler_t)
>                                    on_update_request, &state,
> +                                  "operation-id", "Tell daemon operation id",
> +                                  PLY_COMMAND_OPTION_TYPE_STRING,
>                                    "status", "Tell daemon the current boot status",
>                                    PLY_COMMAND_OPTION_TYPE_STRING,
>                                    NULL);
> @@ -1245,7 +1340,7 @@ main (int    argc,
>                                                (ply_boot_client_response_handler_t)
>                                                on_failure, &state);
>    else if (status != NULL)
> -    ply_boot_client_update_daemon (state.client, status,
> +    ply_boot_client_update_daemon (state.client, status, NULL,
>                                     (ply_boot_client_response_handler_t)
>                                     on_success,
>                                     (ply_boot_client_response_handler_t)
> diff --git a/src/libply-splash-core/ply-boot-splash-plugin.h b/src/libply-splash-core/ply-boot-splash-plugin.h
> index 2d73d66..c44a9a2 100644
> --- a/src/libply-splash-core/ply-boot-splash-plugin.h
> +++ b/src/libply-splash-core/ply-boot-splash-plugin.h
> @@ -1,6 +1,7 @@
>  /* ply-boot-splash-plugin.h - plugin interface for ply_boot_splash_t
>   *
>   * Copyright (C) 2007 Red Hat, Inc.
> + * Copyright (C) 2012 Pali Rohár <pali.rohar at gmail.com>
>   *
>   * 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
> @@ -67,8 +68,14 @@ typedef struct
>                                 ply_boot_splash_mode_t    mode);
>    void (* system_update) (ply_boot_splash_plugin_t *plugin,
>                            int                       progress);
> +  void (* register_operation) (ply_boot_splash_plugin_t *plugin,
> +                               const char               *operation_id,
> +                               const char               *name);
> +  void (* unregister_operation) (ply_boot_splash_plugin_t *plugin,
> +                                 const char               *operation_id);
>    void (* update_status) (ply_boot_splash_plugin_t *plugin,
> -                          const char               *status);
> +                          const char               *status,
> +                          const char               *operation_id);
>    void (* on_boot_output) (ply_boot_splash_plugin_t *plugin,
>                             const char               *output,
>                             size_t                    size);
> diff --git a/src/libply-splash-core/ply-boot-splash.c b/src/libply-splash-core/ply-boot-splash.c
> index 93d9345..7c1fb24 100644
> --- a/src/libply-splash-core/ply-boot-splash.c
> +++ b/src/libply-splash-core/ply-boot-splash.c
> @@ -1,6 +1,7 @@
>  /* ply-boot-splash.h - APIs for putting up a splash screen
>   *
>   * Copyright (C) 2007 Red Hat, Inc.
> + * Copyright (C) 2012 Pali Rohár <pali.rohar at gmail.com>
>   *
>   * 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
> @@ -623,9 +624,36 @@ ply_boot_splash_system_update (ply_boot_splash_t *splash,
>    return true;
>  }
>
> +void ply_boot_splash_register_operation (ply_boot_splash_t *splash,
> +                                         const char        *operation_id,
> +                                         const char        *name)
> +{
> +  assert (splash != NULL);
> +  assert (operation_id != NULL);
> +  assert (name != NULL);
> +  assert (splash->plugin_interface != NULL);
> +  assert (splash->plugin != NULL);
> +  assert (splash->plugin_interface->register_operation != NULL);
> +
> +  splash->plugin_interface->register_operation (splash->plugin, operation_id, name);
> +}
> +
> +void ply_boot_splash_unregister_operation (ply_boot_splash_t *splash,
> +                                           const char        *operation_id)
> +{
> +  assert (splash != NULL);
> +  assert (operation_id != NULL);
> +  assert (splash->plugin_interface != NULL);
> +  assert (splash->plugin != NULL);
> +  assert (splash->plugin_interface->register_operation != NULL);
> +
> +  splash->plugin_interface->unregister_operation (splash->plugin, operation_id);
> +}
> +
>  void
>  ply_boot_splash_update_status (ply_boot_splash_t *splash,
> -                               const char        *status)
> +                               const char        *status,
> +                               const char        *operation_id)
>  {
>    assert (splash != NULL);
>    assert (status != NULL);
> @@ -634,7 +662,7 @@ ply_boot_splash_update_status (ply_boot_splash_t *splash,
>    assert (splash->plugin_interface->update_status != NULL);
>    assert (splash->mode != PLY_BOOT_SPLASH_MODE_INVALID);
>
> -  splash->plugin_interface->update_status (splash->plugin, status);
> +  splash->plugin_interface->update_status (splash->plugin, status, operation_id);
>  }
>
>  void
> diff --git a/src/libply-splash-core/ply-boot-splash.h b/src/libply-splash-core/ply-boot-splash.h
> index a79e939..af67a0e 100644
> --- a/src/libply-splash-core/ply-boot-splash.h
> +++ b/src/libply-splash-core/ply-boot-splash.h
> @@ -64,8 +64,14 @@ bool ply_boot_splash_show (ply_boot_splash_t *splash,
>                             ply_boot_splash_mode_t mode);
>  bool ply_boot_splash_system_update (ply_boot_splash_t *splash,
>                                      int                progress);
> +void ply_boot_splash_register_operation (ply_boot_splash_t *splash,
> +                                         const char        *operation_id,
> +                                         const char        *name);
> +void ply_boot_splash_unregister_operation (ply_boot_splash_t *splash,
> +                                           const char        *operation_id);
>  void ply_boot_splash_update_status (ply_boot_splash_t *splash,
> -                                    const char        *status);
> +                                    const char        *status,
> +                                    const char        *operation_id);
>  void ply_boot_splash_update_output (ply_boot_splash_t *splash,
>                                      const char        *output,
>                                      size_t             size);
> diff --git a/src/libply/ply-progress.c b/src/libply/ply-progress.c
> index cf372cd..0fa5a52 100644
> --- a/src/libply/ply-progress.c
> +++ b/src/libply/ply-progress.c
> @@ -1,6 +1,7 @@
>  /* ply-progress.c - calculats boot progress
>   *
>   * Copyright (C) 2007 Red Hat, Inc.
> + * Copyright (C) 2012 Pali Rohár <pali.rohar at gmail.com>
>   *
>   * 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
> @@ -68,6 +69,7 @@ struct _ply_progress
>  typedef struct
>  {
>    double time;
> +  char* id;
>    char* string;
>    uint32_t disabled : 1;
>  } ply_progress_message_t;
> @@ -103,6 +105,7 @@ ply_progress_free (ply_progress_t* progress)
>        ply_progress_message_t *message = ply_list_node_get_data (node);
>        next_node = ply_list_get_next_node (progress->current_message_list, node);
>
> +      free (message->id);
>        free (message->string);
>        free (message);
>        node = next_node;
> @@ -117,6 +120,7 @@ ply_progress_free (ply_progress_t* progress)
>        ply_progress_message_t *message = ply_list_node_get_data (node);
>        next_node = ply_list_get_next_node (progress->previous_message_list, node);
>
> +      free (message->id);
>        free (message->string);
>        free (message);
>        node = next_node;
> @@ -128,7 +132,7 @@ ply_progress_free (ply_progress_t* progress)
>
>
>  static ply_progress_message_t*
> -ply_progress_message_search (ply_list_t *message_list, const char* string)
> +ply_progress_message_search (ply_list_t *message_list, const char* id, const char* string)
>  {
>    ply_list_node_t *node;
>    node = ply_list_get_first_node (message_list);
> @@ -136,7 +140,7 @@ ply_progress_message_search (ply_list_t *message_list, const char* string)
>    while (node)
>      {
>        ply_progress_message_t *message = ply_list_node_get_data (node);
> -      if (strcmp(string, message->string)==0)
> +      if (strcmp(id, message->id)==0 && strcmp(string, message->string)==0)
>            return message;
>        node = ply_list_get_next_node (message_list, node);
>      }
> @@ -145,7 +149,7 @@ ply_progress_message_search (ply_list_t *message_list, const char* string)
>
>
>  static ply_progress_message_t*
> -ply_progress_message_search_next (ply_list_t *message_list, double time)
> +ply_progress_message_search_next (ply_list_t *message_list, const char* id, double time)
>  {
>    ply_list_node_t *node;
>    node = ply_list_get_first_node (message_list);
> @@ -153,7 +157,7 @@ ply_progress_message_search_next (ply_list_t *message_list, double time)
>    while (node)
>      {
>        ply_progress_message_t *message = ply_list_node_get_data (node);
> -      if (message->time > time && (!best || message->time < best->time))
> +      if (strcmp(id, message->id)==0 && message->time > time && (!best || message->time < best->time))
>            best = message;
>        node = ply_list_get_next_node (message_list, node);
>      }
> @@ -175,6 +179,8 @@ ply_progress_load_cache (ply_progress_t* progress,
>        int items_matched;
>        double time;
>        int string_size=81;
> +      char *ptr;
> +      char *id;
>        char *string;
>        char colon;
>        int i=0;
> @@ -200,8 +206,20 @@ ply_progress_load_cache (ply_progress_t* progress,
>              }
>            i++;
>          }
> +
> +      ptr = strchr(string, ':');
> +      if (!ptr)
> +          id = strdup("");
> +      else
> +        {
> +          *ptr = 0;
> +          id = string;
> +          string = strdup(ptr+1);
> +        }
> +
>        ply_progress_message_t* message = malloc(sizeof(ply_progress_message_t));
>        message->time = time;
> +      message->id = id;
>        message->string = string;
>        ply_list_append_data(progress->previous_message_list, message);
>      }
> @@ -227,7 +245,7 @@ ply_progress_save_cache (ply_progress_t* progress,
>        ply_progress_message_t *message = ply_list_node_get_data (node);
>        double percentage = message->time / cur_time;
>        if (!message->disabled)
> -          fprintf (fp, "%.3lf:%s\n", percentage, message->string);
> +          fprintf (fp, "%.3lf:%s:%s\n", percentage, message->id, message->string);
>        node = ply_list_get_next_node (progress->current_message_list, node);
>      }
>    fclose (fp);
> @@ -300,20 +318,21 @@ ply_progress_unpause (ply_progress_t* progress)
>
>  void
>  ply_progress_status_update (ply_progress_t* progress,
> -                             const char  *status)
> +                             const char  *status,
> +                             const char  *operation_id)
>  {
>    ply_progress_message_t *message, *message_next;
> -  message = ply_progress_message_search(progress->current_message_list, status);
> +  message = ply_progress_message_search(progress->current_message_list, operation_id, status);
>    if (message)
>      {
>        message->disabled = true;
>      }                                                   /* Remove duplicates as they confuse things*/
>    else
>      {
> -      message = ply_progress_message_search(progress->previous_message_list, status);
> +      message = ply_progress_message_search(progress->previous_message_list, operation_id, status);
>        if (message)
>          {
> -          message_next = ply_progress_message_search_next(progress->previous_message_list, message->time);
> +          message_next = ply_progress_message_search_next(progress->previous_message_list, operation_id, message->time);
>            if (message_next)
>                progress->next_message_percentage = message_next->time;
>            else
> @@ -324,6 +343,7 @@ ply_progress_status_update (ply_progress_t* progress,
>          }
>        message = malloc(sizeof(ply_progress_message_t));
>        message->time = ply_progress_get_time (progress);
> +      message->id = strdup(operation_id);
>        message->string = strdup(status);
>        message->disabled = false;
>        ply_list_append_data(progress->current_message_list, message);
> @@ -366,7 +386,7 @@ main (int    argc,
>
>    for (i=0; i<10; i++)
>      {
> -      ply_progress_status_update (progress, strings[i]);
> +      ply_progress_status_update (progress, strings[i], NULL);
>        usleep ((rand () % slowness+slowness));
>        percent = ply_progress_get_percentage (progress);
>        time = ply_progress_get_time (progress);
> diff --git a/src/libply/ply-progress.h b/src/libply/ply-progress.h
> index 434636a..54bb7b9 100644
> --- a/src/libply/ply-progress.h
> +++ b/src/libply/ply-progress.h
> @@ -36,7 +36,7 @@ double ply_progress_get_time (ply_progress_t* progress);
>  void ply_progress_pause (ply_progress_t* progress);
>  void ply_progress_unpause (ply_progress_t* progress);
>  void ply_progress_save_cache (ply_progress_t* progress, const char *filename);
> -void ply_progress_status_update (ply_progress_t* progress, const char  *status);
> +void ply_progress_status_update (ply_progress_t* progress, const char *status, const char *operation_id);
>
>  #endif /* PLY_PROGRESS_H */
>  /* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */
> diff --git a/src/main.c b/src/main.c
> index 9c450c0..baef2db 100644
> --- a/src/main.c
> +++ b/src/main.c
> @@ -1,6 +1,7 @@
>  /* main.c - boot messages monitor
>   *
>   * Copyright (C) 2007 Red Hat, Inc
> + * Copyright (C) 2012 Pali Rohár <pali.rohar at gmail.com>
>   *
>   * This file is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License as published
> @@ -174,15 +175,37 @@ on_session_hangup (state_t *state)
>  }
>
>  static void
> +on_register (state_t     *state,
> +             const char  *operation_id,
> +             const char  *name)
> +{
> +  ply_trace ("register operation '%s' with name '%s'", operation_id, name);
> +  if (state->boot_splash != NULL)
> +    ply_boot_splash_register_operation (state->boot_splash,
> +                                        operation_id, name);
> +}
> +
> +static void
> +on_unregister (state_t     *state,
> +               const char  *operation_id)
> +{
> +  ply_trace ("register operation '%s'", operation_id);
> +  if (state->boot_splash != NULL)
> +    ply_boot_splash_unregister_operation (state->boot_splash,
> +                                        operation_id);
> +}
> +
> +static void
>  on_update (state_t     *state,
> -           const char  *status)
> +           const char  *status,
> +           const char  *operation_id)
>  {
> -  ply_trace ("updating status to '%s'", status);
> +  ply_trace ("updating status of operation '%s' to '%s'", operation_id, status);
>    ply_progress_status_update (state->progress,
> -                               status);
> +                               status, operation_id);
>    if (state->boot_splash != NULL)
>      ply_boot_splash_update_status (state->boot_splash,
> -                                   status);
> +                                   status, operation_id);
>  }
>
>  static void
> @@ -1297,7 +1320,9 @@ start_boot_server (state_t *state)
>  {
>    ply_boot_server_t *server;
>
> -  server = ply_boot_server_new ((ply_boot_server_update_handler_t) on_update,
> +  server = ply_boot_server_new ((ply_boot_server_register_handler_t) on_register,
> +                                (ply_boot_server_unregister_handler_t) on_unregister,
> +                                (ply_boot_server_update_handler_t) on_update,
>                                  (ply_boot_server_change_mode_handler_t) on_change_mode,
>                                  (ply_boot_server_system_update_handler_t) on_system_update,
>                                  (ply_boot_server_ask_for_password_handler_t) on_ask_for_password,
> diff --git a/src/plugins/splash/details/plugin.c b/src/plugins/splash/details/plugin.c
> index aff2f1c..ef62ffe 100644
> --- a/src/plugins/splash/details/plugin.c
> +++ b/src/plugins/splash/details/plugin.c
> @@ -1,6 +1,7 @@
>  /* details.c - boot splash plugin
>   *
>   * Copyright (C) 2008 Red Hat, Inc.
> + * Copyright (C) 2012 Pali Rohár <pali.rohar at gmail.com>
>   *
>   * 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
> @@ -66,6 +67,12 @@ typedef struct
>    ply_text_display_t *display;
>  } view_t;
>
> +typedef struct
> +{
> +  char *operation_id;
> +  char *name;
> +} operation_t;
> +
>  ply_boot_splash_plugin_interface_t *ply_boot_splash_plugin_get_interface (void);
>  static void detach_from_event_loop (ply_boot_splash_plugin_t *plugin);
>
> @@ -76,7 +83,7 @@ struct _ply_boot_splash_plugin
>    ply_list_t *views;
>    ply_boot_splash_display_type_t state;
>    ply_list_t *messages;
> -
> +  ply_list_t *operations;
>  };
>
>  static view_t *
> @@ -148,6 +155,75 @@ free_messages (ply_boot_splash_plugin_t *plugin)
>    plugin->messages = NULL;
>  }
>
> +static operation_t *
> +operation_new (ply_boot_splash_plugin_t *plugin,
> +               const char               *operation_id,
> +               const char               *name)
> +{
> +  operation_t *operation;
> +  operation = malloc (sizeof(operation_t));
> +  operation->operation_id = strdup (operation_id);
> +  operation->name = strdup (name);
> +  return operation;
> +}
> +
> +static void
> +operation_free (operation_t *operation)
> +{
> +  free (operation->operation_id);
> +  free (operation->name);
> +  free (operation);
> +}
> +
> +static void
> +free_operations (ply_boot_splash_plugin_t *plugin)
> +{
> +  ply_list_node_t *node;
> +
> +  node = ply_list_get_first_node (plugin->operations);
> +
> +  while (node != NULL)
> +    {
> +      ply_list_node_t *next_node;
> +      operation_t     *operation;
> +
> +      operation = ply_list_node_get_data (node);
> +      next_node = ply_list_get_next_node (plugin->operations, node);
> +
> +      operation_free (operation);
> +      ply_list_remove_node (plugin->operations, node);
> +
> +      node = next_node;
> +    }
> +
> +  ply_list_free (plugin->operations);
> +  plugin->operations = NULL;
> +}
> +
> +static const char *
> +get_operation_name (ply_boot_splash_plugin_t *plugin, const char *id)
> +{
> +  ply_list_node_t *node;
> +
> +  node = ply_list_get_first_node (plugin->operations);
> +
> +  while (node != NULL)
> +    {
> +      operation_t     *operation;
> +
> +      operation = ply_list_node_get_data (node);
> +      if (strcmp(operation->operation_id, id) == 0)
> +        {
> +          return operation->name;
> +        }
> +
> +      node = ply_list_get_next_node (plugin->operations, node);
> +
> +    }
> +
> +  return NULL;
> +}
> +
>  static ply_boot_splash_plugin_t *
>  create_plugin (ply_key_file_t *key_file)
>  {
> @@ -158,6 +234,7 @@ create_plugin (ply_key_file_t *key_file)
>    plugin = calloc (1, sizeof (ply_boot_splash_plugin_t));
>    plugin->views = ply_list_new ();
>    plugin->state = PLY_BOOT_SPLASH_DISPLAY_NORMAL;
> +  plugin->operations = ply_list_new ();
>    plugin->messages = ply_list_new ();
>    return plugin;
>  }
> @@ -178,6 +255,7 @@ destroy_plugin (ply_boot_splash_plugin_t *plugin)
>        detach_from_event_loop (plugin);
>      }
>
> +  free_operations (plugin);
>    free_messages (plugin);
>    free_views (plugin);
>
> @@ -299,12 +377,74 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin,
>  }
>
>  static void
> +register_operation (ply_boot_splash_plugin_t *plugin,
> +                    const char               *operation_id,
> +                    const char               *name)
> +{
> +  operation_t *operation;
> +  assert (plugin != NULL);
> +  assert (operation_id != NULL);
> +  assert (name != NULL);
> +
> +  ply_trace ("register operation");
> +
> +  operation = operation_new (plugin, operation_id, name);
> +  ply_list_append_data (plugin->operations, operation);
> +}
> +
> +static void
> +unregister_operation (ply_boot_splash_plugin_t *plugin,
> +                      const char               *operation_id)
> +{
> +  assert (plugin != NULL);
> +  assert (operation_id != NULL);
> +
> +  ply_trace ("unregister operation");
> +
> +  ply_list_node_t *node;
> +
> +  node = ply_list_get_first_node (plugin->operations);
> +
> +  while (node != NULL)
> +    {
> +      operation_t *operation;
> +
> +      operation = ply_list_node_get_data (node);
> +      if (strcmp(operation->operation_id, operation_id) == 0)
> +        {
> +          ply_list_remove_node(plugin->operations, node);
> +          return;
> +        }
> +
> +      node = ply_list_get_next_node (plugin->operations, node);
> +
> +    }
> +}
> +
> +static void
>  update_status (ply_boot_splash_plugin_t *plugin,
> -               const char               *status)
> +               const char               *status,
> +               const char               *operation_id)
>  {
>    assert (plugin != NULL);
> +  assert (status != NULL);
>
>    ply_trace ("status update");
> +
> +  if (operation_id != NULL)
> +    {
> +      const char *operation_name = get_operation_name (plugin, operation_id);
> +      if (operation_name != NULL)
> +        {
> +          char *message;
> +          asprintf (&message, "%s... [%s]\r\n", operation_name, status);
> +          if (message != NULL)
> +            {
> +              write_on_views (plugin, message, strlen (message));
> +              free(message);
> +            }
> +        }
> +    }
>  }
>
>  static void
> @@ -431,6 +571,8 @@ ply_boot_splash_plugin_get_interface (void)
>        .add_text_display = add_text_display,
>        .remove_text_display = remove_text_display,
>        .show_splash_screen = show_splash_screen,
> +      .register_operation = register_operation,
> +      .unregister_operation = unregister_operation,
>        .update_status = update_status,
>        .on_boot_output = on_boot_output,
>        .hide_splash_screen = hide_splash_screen,
> diff --git a/src/plugins/splash/fade-throbber/plugin.c b/src/plugins/splash/fade-throbber/plugin.c
> index 4af6cae..8ed79bf 100644
> --- a/src/plugins/splash/fade-throbber/plugin.c
> +++ b/src/plugins/splash/fade-throbber/plugin.c
> @@ -927,7 +927,8 @@ add_stars (ply_boot_splash_plugin_t *plugin)
>
>  static void
>  update_status (ply_boot_splash_plugin_t *plugin,
> -               const char               *status)
> +               const char               *status,
> +               const char               *operation_id)
>  {
>    assert (plugin != NULL);
>
> diff --git a/src/plugins/splash/script/plugin.c b/src/plugins/splash/script/plugin.c
> index c5c1e16..6eccedf 100644
> --- a/src/plugins/splash/script/plugin.c
> +++ b/src/plugins/splash/script/plugin.c
> @@ -430,12 +430,34 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin,
>  }
>
>  static void
> +register_operation (ply_boot_splash_plugin_t *plugin,
> +                    const char               *operation_id,
> +                    const char               *name)
> +{
> +  script_lib_plymouth_on_register_operation (plugin->script_state,
> +                                             plugin->script_plymouth_lib,
> +                                             operation_id,
> +                                             name);
> +}
> +
> +static void
> +unregister_operation (ply_boot_splash_plugin_t *plugin,
> +                      const char               *operation_id)
> +{
> +  script_lib_plymouth_on_unregister_operation (plugin->script_state,
> +                                               plugin->script_plymouth_lib,
> +                                               operation_id);
> +}
> +
> +static void
>  update_status (ply_boot_splash_plugin_t *plugin,
> -               const char               *status)
> +               const char               *status,
> +               const char               *operation_id)
>  {
>    script_lib_plymouth_on_update_status (plugin->script_state,
>                                          plugin->script_plymouth_lib,
> -                                        status);
> +                                        status,
> +                                        operation_id);
>  }
>
>  static void
> @@ -539,6 +561,8 @@ ply_boot_splash_plugin_get_interface (void)
>      .add_pixel_display = add_pixel_display,
>      .remove_pixel_display = remove_pixel_display,
>      .show_splash_screen = show_splash_screen,
> +    .register_operation = register_operation,
> +    .unregister_operation = unregister_operation,
>      .update_status = update_status,
>      .on_boot_progress = on_boot_progress,
>      .hide_splash_screen = hide_splash_screen,
> diff --git a/src/plugins/splash/script/script-lib-plymouth.c b/src/plugins/splash/script/script-lib-plymouth.c
> index ab2ec44..6cb1a25 100644
> --- a/src/plugins/splash/script/script-lib-plymouth.c
> +++ b/src/plugins/splash/script/script-lib-plymouth.c
> @@ -81,6 +81,8 @@ script_lib_plymouth_data_t *script_lib_plymouth_setup (script_state_t         *s
>    data->script_boot_progress_func = script_obj_new_null ();
>    data->script_root_mounted_func = script_obj_new_null ();
>    data->script_keyboard_input_func = script_obj_new_null ();
> +  data->script_register_operation_func = script_obj_new_null ();
> +  data->script_unregister_operation_func = script_obj_new_null ();
>    data->script_update_status_func = script_obj_new_null ();
>    data->script_display_normal_func = script_obj_new_null ();
>    data->script_display_password_func = script_obj_new_null ();
> @@ -116,6 +118,18 @@ script_lib_plymouth_data_t *script_lib_plymouth_setup (script_state_t         *s
>                                "function",
>                                NULL);
>    script_add_native_function (plymouth_hash,
> +                              "SetRegisterOperationFunction",
> +                              plymouth_set_function,
> +                              &data->script_register_operation_func,
> +                              "function",
> +                              NULL);
> +  script_add_native_function (plymouth_hash,
> +                              "SetUnregisterOperationFunction",
> +                              plymouth_set_function,
> +                              &data->script_unregister_operation_func,
> +                              "function",
> +                              NULL);
> +  script_add_native_function (plymouth_hash,
>                                "SetUpdateStatusFunction",
>                                plymouth_set_function,
>                                &data->script_update_status_func,
> @@ -178,6 +192,8 @@ void script_lib_plymouth_destroy (script_lib_plymouth_data_t *data)
>    script_obj_unref (data->script_boot_progress_func);
>    script_obj_unref (data->script_root_mounted_func);
>    script_obj_unref (data->script_keyboard_input_func);
> +  script_obj_unref (data->script_register_operation_func);
> +  script_obj_unref (data->script_unregister_operation_func);
>    script_obj_unref (data->script_update_status_func);
>    script_obj_unref (data->script_display_normal_func);
>    script_obj_unref (data->script_display_password_func);
> @@ -240,17 +256,53 @@ void script_lib_plymouth_on_keyboard_input (script_state_t             *state,
>    script_obj_unref (ret.object);
>  }
>
> +void script_lib_plymouth_on_register_operation (script_state_t             *state,
> +                                                script_lib_plymouth_data_t *data,
> +                                                const char                 *operation_id,
> +                                                const char                 *name)
> +{
> +  script_obj_t *new_name_obj = script_obj_new_string (name);
> +  script_obj_t *new_operation_id_obj = script_obj_new_string (operation_id);
> +  script_return_t ret = script_execute_object (state,
> +                                               data->script_register_operation_func,
> +                                               NULL,
> +                                               new_operation_id_obj,
> +                                               new_name_obj,
> +                                               NULL);
> +  script_obj_unref (new_name_obj);
> +  script_obj_unref (new_operation_id_obj);
> +  script_obj_unref (ret.object);
> +}
> +
> +void script_lib_plymouth_on_unregister_operation (script_state_t             *state,
> +                                                  script_lib_plymouth_data_t *data,
> +                                                  const char                 *operation_id)
> +{
> +  script_obj_t *new_operation_id_obj = script_obj_new_string (operation_id);
> +  script_return_t ret = script_execute_object (state,
> +                                               data->script_unregister_operation_func,
> +                                               NULL,
> +                                               new_operation_id_obj,
> +                                               NULL);
> +  script_obj_unref (new_operation_id_obj);
> +  script_obj_unref (ret.object);
> +}
> +
>  void script_lib_plymouth_on_update_status (script_state_t             *state,
>                                             script_lib_plymouth_data_t *data,
> -                                           const char                 *new_status)
> +                                           const char                 *new_status,
> +                                           const char                 *operation_id)
>  {
>    script_obj_t *new_status_obj = script_obj_new_string (new_status);
> +  script_obj_t *new_operation_id_obj = script_obj_new_string (operation_id);
>    script_return_t ret = script_execute_object (state,
>                                                 data->script_update_status_func,
>                                                 NULL,
>                                                 new_status_obj,
> +                                               new_operation_id_obj,
>                                                 NULL);
>    script_obj_unref (new_status_obj);
> +  script_obj_unref (new_operation_id_obj);
>    script_obj_unref (ret.object);
>  }
>
> diff --git a/src/plugins/splash/script/script-lib-plymouth.h b/src/plugins/splash/script/script-lib-plymouth.h
> index c4ec5a6..fef5a0f 100644
> --- a/src/plugins/splash/script/script-lib-plymouth.h
> +++ b/src/plugins/splash/script/script-lib-plymouth.h
> @@ -32,6 +32,8 @@ typedef struct
>    script_obj_t           *script_boot_progress_func;
>    script_obj_t           *script_root_mounted_func;
>    script_obj_t           *script_keyboard_input_func;
> +  script_obj_t           *script_register_operation_func;
> +  script_obj_t           *script_unregister_operation_func;
>    script_obj_t           *script_update_status_func;
>    script_obj_t           *script_display_normal_func;
>    script_obj_t           *script_display_password_func;
> @@ -57,9 +59,17 @@ void script_lib_plymouth_on_root_mounted (script_state_t             *state,
>  void script_lib_plymouth_on_keyboard_input (script_state_t             *state,
>                                              script_lib_plymouth_data_t *data,
>                                              const char                 *keyboard_input);
> +void script_lib_plymouth_on_register_operation (script_state_t             *state,
> +                                                script_lib_plymouth_data_t *data,
> +                                                const char                 *operation_id,
> +                                                const char                 *name);
> +void script_lib_plymouth_on_unregister_operation (script_state_t             *state,
> +                                                  script_lib_plymouth_data_t *data,
> +                                                  const char                 *operation_id);
>  void script_lib_plymouth_on_update_status (script_state_t             *state,
>                                             script_lib_plymouth_data_t *data,
> -                                           const char                 *new_status);
> +                                           const char                 *new_status,
> +                                           const char                 *operation_id);
>  void script_lib_plymouth_on_display_normal (script_state_t             *state,
>                                              script_lib_plymouth_data_t *data);
>  void script_lib_plymouth_on_display_password (script_state_t             *state,
> diff --git a/src/plugins/splash/space-flares/plugin.c b/src/plugins/splash/space-flares/plugin.c
> index e31dce8..05754e6 100644
> --- a/src/plugins/splash/space-flares/plugin.c
> +++ b/src/plugins/splash/space-flares/plugin.c
> @@ -1708,7 +1708,8 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin,
>
>  static void
>  update_status (ply_boot_splash_plugin_t *plugin,
> -               const char               *status)
> +               const char               *status,
> +               const char               *operation_id)
>  {
>    assert (plugin != NULL);
>  }
> diff --git a/src/plugins/splash/text/plugin.c b/src/plugins/splash/text/plugin.c
> index fb97c14..078cd02 100644
> --- a/src/plugins/splash/text/plugin.c
> +++ b/src/plugins/splash/text/plugin.c
> @@ -537,7 +537,8 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin,
>
>  static void
>  update_status (ply_boot_splash_plugin_t *plugin,
> -               const char               *status)
> +               const char               *status,
> +               const char               *operation_id)
>  {
>    assert (plugin != NULL);
>
> diff --git a/src/plugins/splash/throbgress/plugin.c b/src/plugins/splash/throbgress/plugin.c
> index fba809b..a10c5b3 100644
> --- a/src/plugins/splash/throbgress/plugin.c
> +++ b/src/plugins/splash/throbgress/plugin.c
> @@ -713,7 +713,8 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin,
>
>  static void
>  update_status (ply_boot_splash_plugin_t *plugin,
> -               const char               *status)
> +               const char               *status,
> +               const char               *operation_id)
>  {
>    assert (plugin != NULL);
>  }
> diff --git a/src/plugins/splash/two-step/plugin.c b/src/plugins/splash/two-step/plugin.c
> index 773e9bf..4d74a52 100644
> --- a/src/plugins/splash/two-step/plugin.c
> +++ b/src/plugins/splash/two-step/plugin.c
> @@ -1157,7 +1157,8 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin,
>
>  static void
>  update_status (ply_boot_splash_plugin_t *plugin,
> -               const char               *status)
> +               const char               *status,
> +               const char               *operation_id)
>  {
>    assert (plugin != NULL);
>  }
> diff --git a/src/ply-boot-protocol.h b/src/ply-boot-protocol.h
> index 23dfc8d..31cff34 100644
> --- a/src/ply-boot-protocol.h
> +++ b/src/ply-boot-protocol.h
> @@ -25,6 +25,8 @@
>  #define PLY_BOOT_PROTOCOL_TRIMMED_ABSTRACT_SOCKET_PATH "/org/freedesktop/plymouthd"
>  #define PLY_BOOT_PROTOCOL_OLD_ABSTRACT_SOCKET_PATH "/ply-boot-protocol"
>  #define PLY_BOOT_PROTOCOL_REQUEST_TYPE_PING "P"
> +#define PLY_BOOT_PROTOCOL_REQUEST_TYPE_REGISTER "O"
> +#define PLY_BOOT_PROTOCOL_REQUEST_TYPE_UNREGISTER "o"
>  #define PLY_BOOT_PROTOCOL_REQUEST_TYPE_UPDATE "U"
>  #define PLY_BOOT_PROTOCOL_REQUEST_TYPE_CHANGE_MODE "C"
>  #define PLY_BOOT_PROTOCOL_REQUEST_TYPE_SYSTEM_UPDATE "u"
> diff --git a/src/ply-boot-server.c b/src/ply-boot-server.c
> index 2d2a5b8..409534f 100644
> --- a/src/ply-boot-server.c
> +++ b/src/ply-boot-server.c
> @@ -1,6 +1,7 @@
>  /* ply-boot-server.c - listens for and processes boot-status events
>   *
>   * Copyright (C) 2007 Red Hat, Inc.
> + * Copyright (C) 2012 Pali Rohár <pali.rohar at gmail.com>
>   *
>   * 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
> @@ -57,6 +58,8 @@ struct _ply_boot_server
>    ply_list_t *cached_passwords;
>    int socket_fd;
>
> +  ply_boot_server_register_handler_t register_handler;
> +  ply_boot_server_unregister_handler_t unregister_handler;
>    ply_boot_server_update_handler_t update_handler;
>    ply_boot_server_change_mode_handler_t change_mode_handler;
>    ply_boot_server_system_update_handler_t system_update_handler;
> @@ -83,7 +86,9 @@ struct _ply_boot_server
>  };
>
>  ply_boot_server_t *
> -ply_boot_server_new (ply_boot_server_update_handler_t  update_handler,
> +ply_boot_server_new (ply_boot_server_register_handler_t  register_handler,
> +                     ply_boot_server_unregister_handler_t  unregister_handler,
> +                     ply_boot_server_update_handler_t  update_handler,
>                       ply_boot_server_change_mode_handler_t  change_mode_handler,
>                       ply_boot_server_system_update_handler_t  system_update_handler,
>                       ply_boot_server_ask_for_password_handler_t ask_for_password_handler,
> @@ -112,6 +117,8 @@ ply_boot_server_new (ply_boot_server_update_handler_t  update_handler,
>    server->cached_passwords = ply_list_new ();
>    server->loop = NULL;
>    server->is_listening = false;
> +  server->register_handler = register_handler;
> +  server->unregister_handler = unregister_handler;
>    server->update_handler = update_handler;
>    server->change_mode_handler = change_mode_handler;
>    server->system_update_handler = system_update_handler;
> @@ -203,9 +210,12 @@ ply_boot_server_stop_listening (ply_boot_server_t *server)
>  static bool
>  ply_boot_connection_read_request (ply_boot_connection_t  *connection,
>                                    char                  **command,
> -                                  char                  **argument)
> +                                  char                  **argument_1,
> +                                  char                  **argument_2)
>  {
>    uint8_t header[2];
> +  uint8_t argument_1_size = 0;
> +  uint8_t argument_2_size = 0;
>
>    assert (connection != NULL);
>    assert (connection->fd >= 0);
> @@ -218,22 +228,41 @@ ply_boot_connection_read_request (ply_boot_connection_t  *connection,
>    *command = calloc (2, sizeof (char));
>    *command[0] = header[0];
>
> -  *argument = NULL;
> -  if (header[1] == '\002')
> +  *argument_1 = NULL;
> +  *argument_2 = NULL;
> +  if (header[1] == '\002' || header[1] == '\003')
>      {
> -      uint8_t argument_size;
> +      if (!ply_read (connection->fd, &argument_1_size, sizeof (uint8_t)))
> +        {
> +          free (*command);
> +          return false;
> +        }
> +
> +      *argument_1 = calloc (argument_1_size, sizeof (char));
>
> -      if (!ply_read (connection->fd, &argument_size, sizeof (uint8_t)))
> +      if (!ply_read (connection->fd, *argument_1, argument_1_size))
>          {
> +          free (*argument_1);
>            free (*command);
>            return false;
>          }
> +    }
>
> -      *argument = calloc (argument_size, sizeof (char));
> +  if (header[1] == '\003')
> +    {
> +      if (!ply_read (connection->fd, &argument_2_size, sizeof (uint8_t)))
> +        {
> +          free (*argument_1);
> +          free (*command);
> +          return false;
> +        }
> +
> +      *argument_2 = calloc (argument_2_size, sizeof (char));
>
> -      if (!ply_read (connection->fd, *argument, argument_size))
> +      if (!ply_read (connection->fd, *argument_2, argument_2_size))
>          {
> -          free (*argument);
> +          free (*argument_1);
> +          free (*argument_2);
>            free (*command);
>            return false;
>          }
> @@ -242,7 +271,8 @@ ply_boot_connection_read_request (ply_boot_connection_t  *connection,
>    if (!ply_get_credentials_from_fd (connection->fd, &connection->pid, &connection->uid, NULL))
>      {
>        ply_trace ("couldn't read credentials from connection: %m");
> -      free (*argument);
> +      free (*argument_1);
> +      free (*argument_2);
>        free (*command);
>        return false;
>      }
> @@ -379,7 +409,7 @@ static void
>  ply_boot_connection_on_request (ply_boot_connection_t *connection)
>  {
>    ply_boot_server_t *server;
> -  char *command, *argument;
> +  char *command, *argument_1, *argument_2;
>
>    assert (connection != NULL);
>    assert (connection->fd >= 0);
> @@ -388,7 +418,7 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
>    assert (server != NULL);
>
>    if (!ply_boot_connection_read_request (connection,
> -                                         &command, &argument))
> +                                         &command, &argument_1, &argument_2))
>      {
>        ply_trace ("could not read connection request");
>        return;
> @@ -420,8 +450,36 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
>
>        ply_trace ("got update request");
>        if (server->update_handler != NULL)
> -        server->update_handler (server->user_data, argument, server);
> -      free (argument);
> +        server->update_handler (server->user_data, argument_1, argument_2, server);
> +      free (argument_1);
> +      free (argument_2);
> +      free (command);
> +      return;
> +    }
> +  else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_REGISTER) == 0)
> +    {
> +      if (!ply_write (connection->fd,
> +                      PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK,
> +                      strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK)))
> +        ply_trace ("could not finish writing update reply: %m");
> +
> +      if (server->register_handler != NULL)
> +        server->register_handler (server->user_data, argument_1, argument_2, server);
> +      free (argument_1);
> +      free (argument_2);
> +      free (command);
> +      return;
> +    }
> +  else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_UNREGISTER) == 0)
> +    {
> +        if (!ply_write (connection->fd,
> +                      PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK,
> +                      strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK)))
> +        ply_trace ("could not finish writing update reply: %m");
> +
> +      if (server->unregister_handler != NULL)
> +        server->unregister_handler (server->user_data, argument_1, server);
> +      free (argument_1);
>        free (command);
>        return;
>      }
> @@ -434,8 +492,9 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
>
>        ply_trace ("got change mode notification");
>        if (server->change_mode_handler != NULL)
> -        server->change_mode_handler (server->user_data, argument, server);
> -      free (argument);
> +        server->change_mode_handler (server->user_data, argument_1, server);
> +      free (argument_1);
> +      free (argument_2);
>        free (command);
>        return;
>      }
> @@ -444,10 +503,10 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
>        long int value;
>        char *endptr = NULL;
>
> -      value = strtol (argument, &endptr, 10);
> +      value = strtol (argument_1, &endptr, 10);
>        if (endptr == NULL || *endptr != '\0' || value < 0 || value > 100)
>          {
> -          ply_error ("failed to parse percentage %s", argument);
> +          ply_error ("failed to parse percentage %s", argument_1);
>            value = 0;
>          }
>
> @@ -459,7 +518,8 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
>
>        if (server->system_update_handler != NULL)
>          server->system_update_handler (server->user_data, value, server);
> -      free (argument);
> +      free (argument_1);
> +      free (argument_2);
>        free (command);
>        return;
>      }
> @@ -503,7 +563,8 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
>        if (server->deactivate_handler != NULL)
>          server->deactivate_handler (server->user_data, deactivate_trigger, server);
>
> -      free (argument);
> +      free (argument_1);
> +      free (argument_2);
>        free (command);
>        return;
>      }
> @@ -518,7 +579,7 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
>        bool retain_splash;
>        ply_trigger_t *quit_trigger;
>
> -      retain_splash = (bool) argument[0];
> +      retain_splash = (bool) argument_1[0];
>
>        ply_trace ("got quit %srequest", retain_splash? "--retain-splash " : "");
>
> @@ -532,7 +593,8 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
>        if (server->quit_handler != NULL)
>          server->quit_handler (server->user_data, retain_splash, quit_trigger, server);
>
> -      free(argument);
> +      free(argument_1);
> +      free(argument_2);
>        free(command);
>        return;
>      }
> @@ -550,7 +612,7 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
>
>        if (server->ask_for_password_handler != NULL)
>          server->ask_for_password_handler (server->user_data,
> -                                          argument,
> +                                          argument_1,
>                                            answer,
>                                            server);
>        /* will reply later
> @@ -638,7 +700,7 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
>
>        if (server->ask_question_handler != NULL)
>          server->ask_question_handler (server->user_data,
> -                                          argument,
> +                                          argument_1,
>                                            answer,
>                                            server);
>        /* will reply later
> @@ -650,13 +712,13 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
>      {
>        ply_trace ("got show message request");
>        if (server->display_message_handler != NULL)
> -        server->display_message_handler(server->user_data, argument, server);
> +        server->display_message_handler(server->user_data, argument_1, server);
>      }
>    else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_HIDE_MESSAGE) == 0)
>      {
>        ply_trace ("got hide message request");
>        if (server->hide_message_handler != NULL)
> -        server->hide_message_handler(server->user_data, argument, server);
> +        server->hide_message_handler(server->user_data, argument_1, server);
>      }
>    else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_KEYSTROKE) == 0)
>      {
> @@ -672,7 +734,7 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
>
>        if (server->watch_for_keystroke_handler != NULL)
>          server->watch_for_keystroke_handler (server->user_data,
> -                                          argument,
> +                                          argument_1,
>                                            answer,
>                                            server);
>        /* will reply later
> @@ -685,7 +747,7 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
>        ply_trace ("got keystroke remove request");
>        if (server->ignore_keystroke_handler != NULL)
>          server->ignore_keystroke_handler (server->user_data,
> -                                          argument,
> +                                          argument_1,
>                                            server);
>      }
>    else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_PROGRESS_PAUSE) == 0)
> @@ -706,7 +768,7 @@ ply_boot_connection_on_request (ply_boot_connection_t *connection)
>      {
>        ply_trace ("got newroot request");
>        if (server->newroot_handler != NULL)
> -        server->newroot_handler(server->user_data, argument, server);
> +        server->newroot_handler(server->user_data, argument_1, server);
>      }
>    else if (strcmp (command, PLY_BOOT_PROTOCOL_REQUEST_TYPE_HAS_ACTIVE_VT) == 0)
>      {
> @@ -838,11 +900,27 @@ ply_boot_server_attach_to_event_loop (ply_boot_server_t *server,
>  #include "ply-event-loop.h"
>  #include "ply-boot-server.h"
>
> +static void
> +on_register (ply_event_loop_t  *loop,
> +             const char        *operation_id,
> +             const char        *name)
> +{
> +  printf ("register operation id '%s' name '%s'\n", operation_id, name);
> +}
> +
> +static void
> +on_unregister (ply_event_loop_t  *loop,
> +               const char        *operation_id)
> +{
> +  printf ("unregister operation id '%s'\n", operation_id);
> +}
> +
>  static void
>  on_update (ply_event_loop_t  *loop,
> -           const char        *status)
> +           const char        *status,
> +           const char        *operation_id)
>  {
> -  printf ("new status is '%s'\n", status);
> +  printf ("new status for operation '%s' is '%s'\n", operation_id, status);
>  }
>
>  static void
> @@ -974,7 +1052,9 @@ main (int    argc,
>
>    loop = ply_event_loop_new ();
>
> -  server = ply_boot_server_new ((ply_boot_server_update_handler_t) on_update,
> +  server = ply_boot_server_new ((ply_boot_server_register_handler_t) on_register,
> +                                (ply_boot_server_unregister_handler_t) on_unregister,
> +                                (ply_boot_server_update_handler_t) on_update,
>                                  (ply_boot_server_change_mode_handler_t) on_change_mode,
>                                  (ply_boot_server_system_update_handler_t) on_system_update,
>                                  (ply_boot_server_ask_for_password_handler_t) on_ask_for_password,
> diff --git a/src/ply-boot-server.h b/src/ply-boot-server.h
> index b885a81..56e50bb 100644
> --- a/src/ply-boot-server.h
> +++ b/src/ply-boot-server.h
> @@ -32,8 +32,18 @@
>
>  typedef struct _ply_boot_server ply_boot_server_t;
>
> +typedef void (* ply_boot_server_register_handler_t) (void              *user_data,
> +                                                     const char        *operation_id,
> +                                                     const char        *name,
> +                                                     ply_boot_server_t *server);
> +
> +typedef void (* ply_boot_server_unregister_handler_t) (void              *user_data,
> +                                                       const char        *operation_id,
> +                                                       ply_boot_server_t *server);
> +
>  typedef void (* ply_boot_server_update_handler_t) (void              *user_data,
>                                                     const char        *status,
> +                                                   const char        *operation_id,
>                                                     ply_boot_server_t *server);
>
>  typedef void (* ply_boot_server_change_mode_handler_t) (void              *user_data,
> @@ -104,7 +114,9 @@ typedef bool (* ply_boot_server_has_active_vt_handler_t) (void              *use
>                                                            ply_boot_server_t *server);
>
>  #ifndef PLY_HIDE_FUNCTION_DECLARATIONS
> -ply_boot_server_t *ply_boot_server_new (ply_boot_server_update_handler_t update_handler,
> +ply_boot_server_t *ply_boot_server_new (ply_boot_server_register_handler_t register_handler,
> +                                        ply_boot_server_unregister_handler_t unregister_handler,
> +                                        ply_boot_server_update_handler_t update_handler,
>                                          ply_boot_server_change_mode_handler_t change_mode_handler,
>                                          ply_boot_server_system_update_handler_t system_update_handler,
>                                          ply_boot_server_ask_for_password_handler_t ask_for_password_handler,
> diff --git a/src/upstart-bridge/ply-upstart-monitor.c b/src/upstart-bridge/ply-upstart-monitor.c
> index b19d95a..5c49d8a 100644
> --- a/src/upstart-bridge/ply-upstart-monitor.c
> +++ b/src/upstart-bridge/ply-upstart-monitor.c
> @@ -110,7 +110,7 @@ instance_is_initialized (ply_upstart_monitor_instance_t *instance)
>  {
>    /* Note that the job may not have a description. */
>    if (instance->job->properties.name &&
> -      instance->properties.name && instance->properties.goal &&
> +      instance->properties.goal &&
>        instance->properties.state)
>      return true;
>    else
> diff --git a/src/upstart-bridge/plymouth-upstart-bridge.c b/src/upstart-bridge/plymouth-upstart-bridge.c
> index 7fe1f42..f9e0b6e 100644
> --- a/src/upstart-bridge/plymouth-upstart-bridge.c
> +++ b/src/upstart-bridge/plymouth-upstart-bridge.c
> @@ -1,6 +1,7 @@
>  /* plymouth-upstart-bridge.c - bridge Upstart job state changes to Plymouth
>   *
>   * Copyright (C) 2010, 2011 Canonical Ltd.
> + * Copyright (C) 2012       Pali Rohár <pali.rohar at gmail.com>
>   *
>   * 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
> @@ -28,14 +29,6 @@
>  #include <string.h>
>  #include <unistd.h>
>
> -#if defined(HAVE_NCURSESW_TERM_H)
> -#include <ncursesw/term.h>
> -#elif defined(HAVE_NCURSES_TERM_H)
> -#include <ncurses/term.h>
> -#else
> -#include <term.h>
> -#endif
> -
>  #include "ply-boot-client.h"
>  #include "ply-command-parser.h"
>  #include "ply-event-loop.h"
> @@ -50,152 +43,70 @@ typedef struct
>    ply_command_parser_t  *command_parser;
>  } state_t;
>
> -#ifndef TERMINAL_COLOR_RED
> -#define TERMINAL_COLOR_RED 1
> -#endif
> -
> -/* We don't care about the difference between "not a string capability" and
> - * "cancelled or absent".
> - */
> -static const char *
> -get_string_capability (const char *name)
> -{
> -  const char *value;
> -
> -  value = tigetstr ((char *) name);
> -  if (value == (const char *) -1)
> -    value = NULL;
> -
> -  return value;
> -}
> -
> -static bool
> -terminal_ignores_new_line_after_80_chars (void)
> -{
> -  return tigetflag ((char *) "xenl") != 0;
> -}
> -
> -static int
> -get_number_of_columns (void)
> -{
> -  int number_of_columns;
> -
> -  number_of_columns = tigetnum ((char *) "cols");
> -
> -  return number_of_columns;
> -}
> -
> -static bool
> -can_set_cursor_column (void)
> -{
> -  const char *capability;
> -
> -  capability = get_string_capability ("hpa");
> -
> -  return capability != NULL;
> -}
> -
> -static void
> -set_cursor_column (int column)
> -{
> -  const char *capability;
> -  const char *terminal_string;
> -
> -  capability = get_string_capability ("hpa");
> -  terminal_string = tiparm (capability, column);
> -  fputs (terminal_string, stdout);
> -}
> -
> -static bool
> -can_set_fg_color (void)
> -{
> -  const char *capability;
> -
> -  capability = get_string_capability ("setaf");
> -
> -  return capability != NULL;
> -}
> -
> -static void
> -set_fg_color (int color)
> -{
> -  const char *capability;
> -  const char *terminal_string;
> -
> -  capability = get_string_capability ("setaf");
> -  terminal_string = tiparm (capability, color);
> -  fputs (terminal_string, stdout);
> -}
> -
> -static void
> -unset_fg_color (void)
> -{
> -  const char *terminal_string;
> -
> -  terminal_string = get_string_capability ("op");
> -
> -  if (terminal_string == NULL)
> -    return;
> -
> -  fputs (terminal_string, stdout);
> -}
> -
>  static void
>  update_status (state_t                                   *state,
>                 ply_upstart_monitor_job_properties_t      *job,
>                 ply_upstart_monitor_instance_properties_t *instance,
>                 const char                                *action,
> -               bool                                       is_okay)
> +               const char                                *status,
> +               bool                                       init,
> +               bool                                       finished)
>  {
> -  ply_boot_client_update_daemon (state->client, job->name, NULL, NULL, state);
> +  size_t size = 0;
> +  char *description = NULL;
> +  char *ptr;
>
> -  if (job->description == NULL)
> +  if (job->name == NULL || status == NULL)
>      return;
>
> -  printf (" * %s%s%s",
> -          action ? action : "", action ? " " : "", job->description);
> +  if (finished && strcmp(status, "failed") != 0)
> +    {
> +      status = "done";
> +    }
>
> -  if (terminal_ignores_new_line_after_80_chars () && can_set_cursor_column ())
> +  if (init)
>      {
> -      int number_of_columns, column;
>
> -      number_of_columns = get_number_of_columns ();
> +      if (action != NULL)
> +          size += strlen(action) + 1;
>
> -      if (number_of_columns < (int) strlen("[fail]"))
> -        number_of_columns = 80;
> +      if (job->description != NULL)
> +          size += strlen(job->description) + 1;
>
> -      column = number_of_columns - strlen ("[fail]") - 1;
> +      size += strlen(job->name) + 1;
>
> -      set_cursor_column (column);
> +      ptr = description = malloc(size);
>
> -      if (is_okay)
> -        puts ("[ OK ]");
> -      else
> +      if (description != NULL)
>          {
> -          bool supports_color;
>
> -          supports_color = can_set_fg_color ();
> +          if (action != NULL)
> +            {
> +              ptr += sprintf (ptr, "%s ", action);
> +            }
>
> -          fputs ("[", stdout);
> +          if (job->description != NULL)
> +            {
> +              ptr += sprintf (ptr, "%s ", job->description);
> +            }
>
> -          if (supports_color)
> -            set_fg_color (TERMINAL_COLOR_RED);
> +          ptr += sprintf (ptr, "%s", job->name);
>
> -          fputs ("fail", stdout);
> +          ply_boot_client_register_operation (state->client, job->name, description, NULL, NULL, state);
>
> -          if (supports_color)
> -            unset_fg_color ();
> +          free(description);
>
> -          puts ("]");
>          }
> +
>      }
> -  else
> +
> +  ply_boot_client_update_daemon (state->client, status, job->name, NULL, NULL, state);
> +
> +  if (finished)
>      {
> -      if (is_okay)
> -        puts ("   ...done.");
> -      else
> -        puts ("   ...fail!");
> +      ply_boot_client_unregister_operation (state->client, job->name, NULL, NULL, state);
>      }
> +
>  }
>
>  static void
> @@ -206,15 +117,9 @@ on_failed (void                                      *data,
>  {
>    state_t *state = data;
>
> -  if (job->is_task)
> -    update_status (state, job, instance, NULL, false);
> -  else
> -    {
> -      if (strcmp (instance->goal, "start") == 0)
> -        update_status (state, job, instance, "Starting", false);
> -      else if (strcmp (instance->goal, "stop") == 0)
> -        update_status (state, job, instance, "Stopping", false);
> -    }
> +  ply_trace ("state: %s goal: %s is_task: %d", instance->state, instance->goal, job->is_task);
> +
> +  update_status (state, job, instance, NULL, "failed", false, true);
>  }
>
>  static void
> @@ -223,25 +128,39 @@ on_state_changed (state_t                                   *state,
>                    ply_upstart_monitor_job_properties_t      *job,
>                    ply_upstart_monitor_instance_properties_t *instance)
>  {
> +  bool init = false;
> +  bool finish = false;
> +
> +  ply_trace ("state: %s goal: %s is_task: %d", instance->state, instance->goal, job->is_task);
> +
>    if (instance->failed)
>      return;
>
>    if (job->is_task)
>      {
> -      if (strcmp (instance->state, "waiting") == 0)
> -        update_status (state, job, instance, NULL, true);
> +      if (strcmp (instance->state, "starting") == 0)
> +        init = true;
> +      else if (strcmp (instance->state, "waiting") == 0)
> +        finish = true;
> +      update_status (state, job, instance, NULL, instance->state, init, finish);
>      }
>    else
>      {
>        if (strcmp (instance->goal, "start") == 0)
>          {
> -          if (strcmp (instance->state, "running") == 0)
> -            update_status (state, job, instance, "Starting", true);
> +          if (strcmp (instance->state, "starting") == 0)
> +            init = true;
> +          else if (strcmp (instance->state, "running") == 0)
> +            finish = true;
> +          update_status (state, job, instance, "Starting", instance->state, init, finish);
>          }
>        else if (strcmp (instance->goal, "stop") == 0)
>          {
> -          if (strcmp (instance->state, "waiting") == 0)
> -            update_status (state, job, instance, "Stopping", true);
> +          if (strcmp (instance->state, "pre-stop") == 0)
> +            init = true;
> +          else if (strcmp (instance->state, "waiting") == 0)
> +            finish = true;
> +          update_status (state, job, instance, "Stopping", instance->state, init, finish);
>          }
>      }
>  }
> @@ -307,8 +226,6 @@ main (int    argc,
>    if (should_be_verbose && !ply_is_tracing ())
>      ply_toggle_tracing ();
>
> -  setupterm (NULL, STDOUT_FILENO, NULL);
> -
>    is_connected = ply_boot_client_connect (state.client,
>                                            (ply_boot_client_disconnect_handler_t)
>                                            on_disconnect, &state);
> --
> 1.7.9.5
>
> --
> Pali Rohár
> pali.rohar at gmail.com


More information about the plymouth mailing list