Add --register command-line option to LegacyAppHandler
authorJonathan Maw <jonathan.maw@codethink.co.uk>
Tue, 26 Jun 2012 14:44:00 +0000 (15:44 +0100)
committerJonathan Maw <jonathan.maw@codethink.co.uk>
Fri, 29 Jun 2012 10:21:50 +0000 (11:21 +0100)
When legacy-app-handler is called without arguments, it starts as a
service, and as the primary instance of the LegacyAppHandler
GApplication.

When legacy-app-handler is called with arguments, it is started as a
remote instance of the LegacyAppHandler GApplication, which passes its
command-line arguments to the primary instance.

On receiving command-line arguments from a remote instance, the Primary
instance will parse those arguments, expecting a command like the
following:
  legacy-app-handler --register --unit="foo" --timeout=120 \
  --shutdown-mode="normal"

Timeout and shutdown-mode are optional, and if omitted will default to
0, and "normal", respectively.

Because interaction with the Node State Manager is not yet implemented,
the Legacy App Handler will print the arguments to DLT, instead of
registering the app as a shutdown consumer.

legacy-app-handler/la-handler-application.c
legacy-app-handler/la-handler-application.h
legacy-app-handler/main.c

index 0ce2b78..7295bcb 100644 (file)
 #include <config.h>
 #endif
 
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
 #include <glib-object.h>
 #include <gio/gio.h>
 
+#include <dlt/dlt.h>
+
 #include <common/watchdog-client.h>
 
 #include <legacy-app-handler/la-handler-dbus.h>
 
 
 
+DLT_IMPORT_CONTEXT (la_handler_context);
+
+
+
 /* property identifiers */
 enum
 {
@@ -31,16 +41,18 @@ enum
 
 
 
-static void la_handler_application_finalize     (GObject      *object);
-static void la_handler_application_get_property (GObject      *object,
-                                                 guint         prop_id,
-                                                 GValue       *value,
-                                                 GParamSpec   *pspec);
-static void la_handler_application_set_property (GObject      *object,
-                                                 guint         prop_id,
-                                                 const GValue *value,
-                                                 GParamSpec   *pspec);
-static void la_handler_application_startup      (GApplication *application);
+static void la_handler_application_finalize     (GObject                 *object);
+static void la_handler_application_get_property (GObject                 *object,
+                                                 guint                    prop_id,
+                                                 GValue                  *value,
+                                                 GParamSpec              *pspec);
+static void la_handler_application_set_property (GObject                 *object,
+                                                 guint                    prop_id,
+                                                 const GValue            *value,
+                                                 GParamSpec              *pspec);
+static void la_handler_application_startup      (GApplication            *application);
+static int  la_handler_application_command_line (GApplication            *application,
+                                                 GApplicationCommandLine *cmdline);
 
 
 
@@ -80,6 +92,7 @@ la_handler_application_class_init (LAHandlerApplicationClass *klass)
 
   gapplication_class = G_APPLICATION_CLASS (klass);
   gapplication_class->startup = la_handler_application_startup;
+  gapplication_class->command_line = la_handler_application_command_line;
 
   g_object_class_install_property (gobject_class,
                                    PROP_LA_HANDLER_SERVICE,
@@ -107,7 +120,8 @@ la_handler_application_finalize (GObject *object)
   LAHandlerApplication *application = LA_HANDLER_APPLICATION (object);
 
   /* release the watchdog client */
-  g_object_unref (application->watchdog_client);
+  if (application->watchdog_client != NULL)
+    g_object_unref (application->watchdog_client);
 
   /* release the Legacy App Handler service implementation */
   if (application->service != NULL)
@@ -165,18 +179,115 @@ la_handler_application_startup (GApplication *app)
 {
   LAHandlerApplication *application = LA_HANDLER_APPLICATION (app);
 
+  /* chain up to the parent class */
+  (*G_APPLICATION_CLASS (la_handler_application_parent_class)->startup) (app);
+
   /* update systemd's watchdog timestamp every 120 seconds */
   application->watchdog_client = watchdog_client_new (120);
+
+  /* the Legacy Application Handler should keep running until it is shut down by the Node
+   * State Manager. */
+  g_application_hold (app);
+}
+
+
+
+static int
+la_handler_application_command_line (GApplication            *application,
+                                     GApplicationCommandLine *cmdline)
+{
+  GOptionContext *context;
+  gboolean        do_register;
+  GError         *error;
+  gchar         **args;
+  gchar         **argv;
+  gchar          *message;
+  gchar          *mode = NULL;
+  gchar          *unit = NULL;
+  gint            argc;
+  gint            timeout;
+  gint            i;
+
+  GOptionEntry entries[] = {
+    {"register",      0, 0, G_OPTION_ARG_NONE,   &do_register, NULL, NULL},
+    {"unit",          0, 0, G_OPTION_ARG_STRING, &unit,     NULL, NULL},
+    {"timeout",       0, 0, G_OPTION_ARG_INT,    &timeout,  NULL, NULL},
+    {"shutdown-mode", 0, 0, G_OPTION_ARG_STRING, &mode,     NULL, NULL},
+    {NULL},
+  };
+
+  /* keep the application running until we have finished */
+  g_application_hold (application);
+
+  /* retrieve the command-line arguments */
+  args = g_application_command_line_get_arguments (cmdline, &argc);
+
+  /* copy the args array, because g_option_context_parse() removes elements without
+   * freeing them */
+  argv = g_new (gchar *, argc + 1);
+  for (i = 0; i <= argc; i++)
+    argv[i] = args[i];
+
+  /* set up the option context */
+  context = g_option_context_new (NULL);
+  g_option_context_set_help_enabled (context, FALSE);
+  g_option_context_add_main_entries (context, entries, NULL);
+
+  /* parse the arguments into the argument data */
+  if (!g_option_context_parse (context, &argc, &argv, &error))
+    {
+      /* an error occurred */
+      g_application_command_line_printerr (cmdline, "%s\n", error->message);
+      g_error_free (error);
+      g_application_command_line_set_exit_status (cmdline, EXIT_FAILURE);
+    }
+  else if (do_register)
+    {
+      if (unit != NULL && *unit != '\0' && timeout >= 0)
+        {
+          /* register was called correctly */
+          message =
+            g_strdup_printf ("Register application \"%s\" with mode \"%s\"and "
+                             "timeout %dms",
+                             unit,
+                             (mode != NULL) ? mode : "normal",
+                             timeout);
+          DLT_LOG (la_handler_context, DLT_LOG_INFO, DLT_STRING (message));
+          g_free (message);
+        }
+      else
+        {
+          /* register was called incorrectly */
+          g_application_command_line_printerr (cmdline,
+                                               "Invalid arguments. A unit must be "
+                                               "specified and the timeout must be "
+                                               "positive.\n");
+        }
+    }
+
+  /* clean up */
+  g_free (argv);
+  g_strfreev (args);
+  g_option_context_free (context);
+
+  g_free (mode);
+  g_free (unit);
+
+  /* allow the application to stop */
+  g_application_release (application);
+
+  return EXIT_SUCCESS;
 }
 
 
 
 LAHandlerApplication *
-la_handler_application_new (LAHandlerService *service)
+la_handler_application_new (LAHandlerService *service,
+                            GApplicationFlags flags)
 {
   return g_object_new (LA_HANDLER_TYPE_APPLICATION,
                        "application-id", "org.genivi.LegacyAppHandler1",
-                       "flags", G_APPLICATION_IS_SERVICE,
+                       "flags", flags,
                        "la-handler-service", service,
                        NULL);
 }
index e77cfa6..57160e2 100644 (file)
@@ -24,9 +24,10 @@ G_BEGIN_DECLS
 typedef struct _LAHandlerApplicationClass LAHandlerApplicationClass;
 typedef struct _LAHandlerApplication      LAHandlerApplication;
 
-GType                        la_handler_application_get_type (void) G_GNUC_CONST;
+GType                 la_handler_application_get_type (void) G_GNUC_CONST;
 
-LAHandlerApplication *la_handler_application_new      (LAHandlerService *service) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+LAHandlerApplication *la_handler_application_new      (LAHandlerService *service,
+                                                       GApplicationFlags flags) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
 
 G_END_DECLS
 
index df81e05..f19dbfd 100644 (file)
 #include <glib.h>
 #include <gio/gio.h>
 
+#include <dlt/dlt.h>
+
 #include <legacy-app-handler/la-handler-application.h>
 #include <legacy-app-handler/la-handler-service.h>
 
 
 
+DLT_DECLARE_CONTEXT (la_handler_context);
+
+
+
+static void
+dlt_cleanup (void)
+{
+  DLT_UNREGISTER_CONTEXT (la_handler_context);
+  DLT_UNREGISTER_APP ();
+}
+
+
+
 int
 main (int    argc,
       char **argv)
@@ -30,8 +45,24 @@ main (int    argc,
   LAHandlerApplication *application;
   LAHandlerService     *service;
   GDBusConnection      *connection;
+  gboolean              is_remote;
   GError               *error = NULL;
-  gint                  exit_status = EXIT_SUCCESS;
+  int                   exit_status;
+
+  /* check if this program execution is meant as a remote application.
+   * if it is a remote application, then it will be called with command-line arguments. */
+  is_remote = (argc > 1) ? TRUE : FALSE;
+
+  /* register the application and context in DLT */
+  if (!is_remote)
+    {
+      DLT_REGISTER_APP ("BMGR", "GENIVI Boot Manager");
+      DLT_REGISTER_CONTEXT (la_handler_context, "LAH",
+                            "Context of the legacy application handler that hooks legacy "
+                            "applications up with the shutdown concept of the Node State "
+                            "Manager");
+      atexit (dlt_cleanup);
+    }
 
   /* initialize the GType type system */
   g_type_init ();
@@ -63,8 +94,24 @@ main (int    argc,
     }
 
   /* create and run the main application */
-  application = la_handler_application_new (service);
-  exit_status = g_application_run (G_APPLICATION (application), 0, NULL);
+  if (is_remote)
+    {
+      /* an application with the flag G_APPLICATION_IS_SERVICE tries to be the primary
+       * instance of the application, and fails if another instance already exists.
+       * setting G_APPLICATION_IS_LAUNCHER indicates that it shouldn't try to be the
+       * primary instance */
+      application =
+        la_handler_application_new (service, G_APPLICATION_HANDLES_COMMAND_LINE |
+                                             G_APPLICATION_IS_LAUNCHER);
+    }
+  else
+    {
+      /* this application is meant to be the primary instance, so
+       * G_APPLICATION_IS_LAUNCHER is not set */
+      application =
+        la_handler_application_new (service, G_APPLICATION_IS_SERVICE);
+    }
+  exit_status = g_application_run (G_APPLICATION (application), argc, argv);
   g_object_unref (application);
 
   /* release allocated objects */