Rewrite legacy app handler's command-line to use D-Bus
authorJonathan Maw <jonathan.maw@codethink.co.uk>
Mon, 9 Jul 2012 15:15:07 +0000 (16:15 +0100)
committerJonathan Maw <jonathan.maw@codethink.co.uk>
Tue, 10 Jul 2012 11:18:46 +0000 (12:18 +0100)
The GApplication object's command-line method does not work when the
application is running on the system bus. The solution is to use D-Bus
calls to communicate with the primary instance instead.

If the executable is called with command-line arguments, instead of
starting a GApplication it calls the Register() and Deregister()
methods instead.

This commit also adds all the necessary changes so that the legacy app
handler can be D-Bus activated on the system bus and started with
systemd.

configure.ac
legacy-app-handler/Makefile.am
legacy-app-handler/dbus/Makefile.am [new file with mode: 0644]
legacy-app-handler/dbus/org.genivi.LegacyAppHandler1.service.in [moved from legacy-app-handler/org.genivi.LegacyAppHandler1.service.in with 70% similarity]
legacy-app-handler/la-handler-application.c
legacy-app-handler/main.c
legacy-app-handler/systemd/Makefile.am [new file with mode: 0644]
legacy-app-handler/systemd/org.genivi.LegacyAppHandler1.service.in [new file with mode: 0644]

index 9e16a83..7f25c54 100644 (file)
@@ -137,7 +137,9 @@ AC_OUTPUT([
 Makefile
 common/Makefile
 boot-manager/Makefile
+legacy-app-handler/dbus/Makefile
 legacy-app-handler/Makefile
+legacy-app-handler/systemd/Makefile
 luc-handler/Makefile
 luc-handler/org.genivi.LUCHandler1.gschema.xml
 tests/Makefile
index 9ac1c0c..0e037bc 100644 (file)
@@ -1,5 +1,9 @@
 # vi:set ts=8 sw=8 noet ai nocindent:
 
+SUBDIRS =                                                              \
+       dbus                                                            \
+       systemd
+
 legacy_app_handler_confdir = /etc/dbus-1/system.d
 
 legacy_app_handler_conf_DATA =                                         \
@@ -52,21 +56,7 @@ legacy_app_handler_LDADD =                                           \
        $(SYSTEMD_DAEMON_LIBS)                                          \
        $(top_builddir)/common/libcommon.la
 
-servicedir = $(datadir)/dbus-1/services
-service_in_files =                                                     \
-       org.genivi.LegacyAppHandler1.service.in
-
-service_DATA = $(service_in_files:.service.in=.service)
-
-%.service: %.service.in
-       sed -e "s,\@libdir\@,$(libdir),g"                               \
-           -e "s,\@BOOT_MANAGER_VERSION_API\@,$(BOOT_MANAGER_VERSION_API),g" < $< > $@
-
-CLEANFILES =                                                           \
-       $(service_DATA)
-
 EXTRA_DIST =                                                           \
-       $(service_in_files)                                             \
        $(gsettingsschema_in_files)                                     \
        la-handler-dbus.xml
 
diff --git a/legacy-app-handler/dbus/Makefile.am b/legacy-app-handler/dbus/Makefile.am
new file mode 100644 (file)
index 0000000..1ba7717
--- /dev/null
@@ -0,0 +1,20 @@
+# vi:set ts=8 sw=8 noet ai nocindent:
+
+bus_servicedir = $(datadir)/dbus-1/system-services
+
+bus_service_in_files =                                                 \
+       org.genivi.LegacyAppHandler1.service.in
+
+bus_service_DATA = $(bus_service_in_files:.service.in=.service)
+
+%.service: %.service.in
+       sed -e "s,\@libdir\@,$(libdir),g"                               \
+           -e "s,\@BOOT_MANAGER_VERSION_API\@,$(BOOT_MANAGER_VERSION_API),g" < $< > $@
+
+CLEANFILES =                                                           \
+       $(bus_service_DATA)
+
+EXTRA_DIST =                                                           \
+       $(bus_service_in_files)
+
+
@@ -1,3 +1,4 @@
 [D-BUS Service]
 Name=org.genivi.LegacyAppHandler1
+SystemdService = org.genivi.LegacyAppHandler1.service
 Exec=@libdir@/legacy-app-handler-@BOOT_MANAGER_VERSION_API@/legacy-app-handler
index 7352b80..05b9167 100644 (file)
@@ -51,8 +51,6 @@ static void la_handler_application_set_property (GObject                 *object
                                                  const GValue            *value,
                                                  GParamSpec              *pspec);
 static void la_handler_application_startup      (GApplication            *application);
-static int  la_handler_application_command_line (GApplication            *application,
-                                                 GApplicationCommandLine *cmdline);
 
 
 
@@ -92,7 +90,6 @@ 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,
@@ -192,88 +189,6 @@ la_handler_application_startup (GApplication *app)
 
 
 
-static int
-la_handler_application_command_line (GApplication            *application,
-                                     GApplicationCommandLine *cmdline)
-{
-  GOptionContext *context;
-  gboolean        do_register;
-  GError         *error = NULL;
-  gchar         **args;
-  gchar         **argv;
-  gchar          *mode = NULL;
-  gchar          *unit = NULL;
-  gint            argc;
-  gint            timeout = 0;
-  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) || error != NULL)
-    {
-      /* 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 */
-          la_handler_service_register (LA_HANDLER_APPLICATION (application)->service,
-                                       unit, mode ? mode : "normal", (guint) timeout);
-        }
-      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,
                             GApplicationFlags flags)
index a7a9d93..398ac04 100644 (file)
@@ -21,6 +21,7 @@
 #include <dlt/dlt.h>
 
 #include <legacy-app-handler/la-handler-application.h>
+#include <legacy-app-handler/la-handler-dbus.h>
 #include <legacy-app-handler/la-handler-service.h>
 
 
@@ -38,6 +39,177 @@ dlt_cleanup (void)
 
 
 
+static gboolean
+handle_command_line (int              argc,
+                     char           **argv,
+                     GDBusConnection *connection)
+{
+  GOptionContext *context = g_option_context_new (NULL);
+  LAHandler      *legacy_app_handler;
+  gboolean        do_register = FALSE;
+  gboolean        do_deregister = FALSE;
+  GError         *error = NULL;
+  gchar          *unit = NULL;
+  gchar          *log_message = NULL;
+  gchar          *mode = NULL;
+  gint            timeout = 0;
+
+  GOptionEntry entries[] = {
+    {"deregister",    0, 0, G_OPTION_ARG_NONE,   &do_deregister, NULL, NULL},
+    {"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},
+  };
+
+  /* set up the option context */
+  g_option_context_set_help_enabled (context, FALSE);
+  g_option_context_add_main_entries (context, entries, NULL);
+
+  /* parse the arguments into argument data */
+  if (!g_option_context_parse (context, &argc, &argv, &error) || error != NULL)
+    {
+      /* an error occurred */
+      log_message =
+        g_strdup_printf ("Error occurred parsing arguments: %s\n", error->message);
+      DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_message));
+
+      g_error_free (error);
+      g_free (log_message);
+
+      return FALSE;
+    }
+  else if (do_register && !do_deregister)
+    {
+      if (unit == NULL || *unit == '\0' || timeout < 0)
+        {
+          /* register was called incorrectly */
+          log_message =
+            g_strdup_printf ("Invalid arguments for --register. A unit must be specified"
+                             " and the timeout must be positive.");
+          DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_message));
+
+          g_free (log_message);
+
+          return FALSE;
+        }
+
+      /* get a legacy app handler interface */
+      legacy_app_handler =
+        la_handler_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE,
+                                   "org.genivi.LegacyAppHandler1",
+                                   "/org/genivi/LegacyAppHandler1", NULL, &error);
+      if (error != NULL)
+        {
+          /* failed to connect to the legacy app handler */
+          log_message =
+            g_strdup_printf ("Error occurred connecting to legacy app handler "
+                             "interface: %s", error->message);
+          DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_message));
+
+          g_free (log_message);
+          g_error_free (error);
+
+          return FALSE;
+        }
+
+      /* call the legacy app handler's Register() method */
+      la_handler_call_register_sync (legacy_app_handler, unit,
+                                     mode ? mode : "normal", (guint) timeout, NULL,
+                                     &error);
+      if (error != NULL)
+        {
+          /* failed to register the legacy app */
+          log_message = g_strdup_printf ("Error occurred registering legacy app: %s",
+                                         error->message);
+          DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_message));
+
+          g_object_unref (legacy_app_handler);
+          g_free (log_message);
+          g_error_free (error);
+
+          return FALSE;
+        }
+
+      g_object_unref (legacy_app_handler);
+
+      return TRUE;
+
+    }
+  else if (do_deregister && !do_register)
+    {
+      if (unit == NULL || *unit == '\0')
+        {
+          /* deregister was called incorrectly */
+          log_message =
+            g_strdup_printf ("Invalid arguments for --deregister. A unit must be "
+                             "specified.");
+          DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_message));
+
+          g_free (log_message);
+
+          return FALSE;
+        }
+
+      /* get a legacy app handler interface */
+      legacy_app_handler =
+        la_handler_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE,
+                                   "org.genivi.LegacyAppHandler1",
+                                   "/org/genivi/LegacyAppHandler1", NULL, &error);
+      if (error != NULL)
+        {
+          log_message =
+            g_strdup_printf ("Error occurred connecting to legacy app handler "
+                             "interface: %s", error->message);
+          DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_message));
+
+          g_free (log_message);
+          g_error_free (error);
+
+          return FALSE;
+        }
+
+      /* call the legacy app handler's Deregister() method */
+      la_handler_call_deregister_sync (legacy_app_handler, unit, NULL, &error);
+      if (error != NULL)
+        {
+          log_message = g_strdup_printf ("Error occurred deregistering legacy "
+                                         "app: %s", error->message);
+          DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_message));
+
+          g_object_unref (legacy_app_handler);
+          g_free (log_message);
+          g_error_free (error);
+
+          return FALSE;
+        }
+
+      g_object_unref (legacy_app_handler);
+
+      return TRUE;
+    }
+  else if (do_register && do_deregister)
+    {
+      log_message =
+        g_strdup_printf ("Invalid arguments. Please choose either --register or "
+                         "--deregister.");
+        DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_message));
+
+        g_free (log_message);
+
+        return FALSE;
+    }
+  else
+    {
+        DLT_LOG (la_handler_context, DLT_LOG_ERROR,
+                 DLT_STRING ("No arguments recognised"));
+        return FALSE;
+    }
+}
+
+
+
 int
 main (int    argc,
       char **argv)
@@ -82,48 +254,43 @@ main (int    argc,
       return EXIT_FAILURE;
     }
 
-  /* instantiate the LegacyAppHandler service implementation */
-  service = la_handler_service_new (connection);
-  if (!la_handler_service_start (service, &error))
-    {
-      log_text = g_strdup_printf ("Failed to start the legacy app handler service: %s",
-                                  error->message);
-      DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_text));
-
-      /* clean up */
-      g_free (log_text);
-      g_error_free (error);
-      g_object_unref (service);
-      g_object_unref (connection);
-
-      return EXIT_FAILURE;
-    }
-
-  /* create and run the main application */
   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);
+      if (!handle_command_line (argc, argv, connection))
+        exit_status = EXIT_FAILURE;
+      else
+        exit_status = EXIT_SUCCESS;
     }
   else
     {
-      /* this application is meant to be the primary instance, so
-       * G_APPLICATION_IS_LAUNCHER is not set */
+      /* instantiate the LegacyAppHandler service implementation */
+      service = la_handler_service_new (connection);
+      if (!la_handler_service_start (service, &error))
+        {
+          log_text = g_strdup_printf ("Failed to start the legacy app handler service: %s",
+                                      error->message);
+          DLT_LOG (la_handler_context, DLT_LOG_ERROR, DLT_STRING (log_text));
+
+          /* clean up */
+          g_free (log_text);
+          g_error_free (error);
+          g_object_unref (service);
+          g_object_unref (connection);
+
+          return EXIT_FAILURE;
+        }
+
+      /* create and run the main application */
       application =
         la_handler_application_new (service, G_APPLICATION_IS_SERVICE);
-    }
 
-  /* run the application */
-  exit_status = g_application_run (G_APPLICATION (application), argc, argv);
-  g_object_unref (application);
+      exit_status = g_application_run (G_APPLICATION (application), argc, argv);
+      g_object_unref (application);
+
+      /* release allocated objects */
+      g_object_unref (service);
+    }
 
-  /* release allocated objects */
-  g_object_unref (service);
   g_object_unref (connection);
 
   return exit_status;
diff --git a/legacy-app-handler/systemd/Makefile.am b/legacy-app-handler/systemd/Makefile.am
new file mode 100644 (file)
index 0000000..874d9e6
--- /dev/null
@@ -0,0 +1,20 @@
+# vi:set ts=8 sw=8 noet ai nocindent:
+
+systemd_servicedir = $(libdir)/systemd/system
+
+systemd_service_in_files =                                                     \
+       org.genivi.LegacyAppHandler1.service.in
+
+systemd_service_DATA = $(systmd_service_in_files:.service.in=.service)
+
+%.service: %.service.in
+       sed -e "s,\@libdir\@,$(libdir),g"                               \
+           -e "s,\@BOOT_MANAGER_VERSION_API\@,$(BOOT_MANAGER_VERSION_API),g" < $< > $@
+
+CLEANFILES =                                                           \
+       $(systemd_service_DATA)
+
+EXTRA_DIST =                                                           \
+       $(systemd_service_in_files)
+
+
diff --git a/legacy-app-handler/systemd/org.genivi.LegacyAppHandler1.service.in b/legacy-app-handler/systemd/org.genivi.LegacyAppHandler1.service.in
new file mode 100644 (file)
index 0000000..bc1f4b4
--- /dev/null
@@ -0,0 +1,3 @@
+[Service]
+BusName = org.genivi.LegacyAppHandler1.service
+ExecStart = @libdir@/legacy-app-handler-@BOOT_MANAGER_VERSION_API@/legacy-app-handler