[gnome-session/benzea/systemd-gnome-launched-drop-in] util: Add utility function to place a PID into a systemd scope



commit 2acf01f909882f086f56324d81a5f7a10b60c19a
Author: Benjamin Berg <bberg redhat com>
Date:   Thu Nov 28 14:54:15 2019 +0100

    util: Add utility function to place a PID into a systemd scope
    
    It makes sense to put children into their own systemd scope when
    possible. This helper allows to do so, it is a direct copy of the
    gnome-shell code.
    
    In the gnome-session context we could short-cut e.g. the check whether
    we are running on systemd, but keeping it as is does not add much
    overhead either and means it is possible to unconditionally call the
    functions without it resulting in unwanted warnings.

 gnome-session/gsm-util.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++
 gnome-session/gsm-util.h |   3 ++
 2 files changed, 113 insertions(+)
---
diff --git a/gnome-session/gsm-util.c b/gnome-session/gsm-util.c
index 02bc4a57..6678c27c 100644
--- a/gnome-session/gsm-util.c
+++ b/gnome-session/gsm-util.c
@@ -32,6 +32,10 @@
 
 #include "gsm-util.h"
 
+#ifdef HAVE_SYSTEMD
+#include <systemd/sd-login.h>
+#endif
+
 static gchar *_saved_session_dir = NULL;
 static gchar **child_environment;
 
@@ -768,8 +772,114 @@ gsm_util_start_systemd_unit (const char  *unit,
 
         return TRUE;
 }
+
+static void
+on_systemd_call_cb (GObject      *source,
+                    GAsyncResult *res,
+                    gpointer      user_data)
+{
+  g_autoptr (GVariant) reply = NULL;
+  g_autoptr (GError) error = NULL;
+  const gchar *command = user_data;
+
+  reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source),
+                                         res, &error);
+  if (error)
+    g_warning ("Could not issue '%s' systemd call", command);
+}
 #endif
 
+gboolean
+gsm_util_start_systemd_scope (const gchar *app_id,
+                              gint32       pid,
+                              GError     **error)
+{
+#ifdef HAVE_SYSTEMD
+  GVariantBuilder builder;
+  const char *valid_chars =
+    "-._1234567890"
+    "abcdefghijklmnopqrstuvwxyz"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  g_autofree gchar *mangled_app_id = NULL;
+  g_autofree gchar *unit_name = NULL;
+  g_autofree gchar *own_unit = NULL;
+  g_autoptr (GDBusConnection) connection = NULL;
+  gint res;
+
+  /* We cannot do anything if this process is not managed by the
+   * systemd user instance. */
+  res = sd_pid_get_user_unit (getpid (), &own_unit);
+  if (res == -ENODATA) {
+    g_debug ("Not systemd managed, will not move PID %d into transient scope\n", pid);
+    return TRUE;
+  }
+  if (res < 0) {
+    g_propagate_error (error,
+                       g_error_new (G_IO_ERROR,
+                                    g_io_error_from_errno (-res),
+                                    "Error fetching user unit for own pid: %d", -res));
+
+    return FALSE;
+  }
+
+  connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error);
+
+  if (connection == NULL)
+    return FALSE;
+
+  g_debug ("Trying to create transient scope for PID %d\n", pid);
+
+  /* Create a nice and (mangled) name to embed into the unit */
+  if (app_id == NULL)
+    app_id = "anonymous";
+  if (app_id[0] == '/')
+    app_id++;
+
+  mangled_app_id = g_str_to_ascii (app_id, "C");
+  g_strdelimit (mangled_app_id, "/", '-');
+  g_strcanon (mangled_app_id, valid_chars, '_');
+
+  /* This needs to be unique, hopefully the pid will be enough. */
+  unit_name = g_strdup_printf ("gnome-launched-%s-%d.scope", mangled_app_id, pid);
+
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ssa(sv)a(sa(sv)))"));
+  g_variant_builder_add (&builder, "s", unit_name);
+  g_variant_builder_add (&builder, "s", "fail");
+
+  g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(sv)"));
+  /* Note that futher settings are controlled using a drop-in. */
+  g_variant_builder_add (&builder,
+                         "(sv)",
+                         "Description",
+                         g_variant_new_string ("Application launched by gnome-shell"));
+  g_variant_builder_add (&builder,
+                         "(sv)",
+                         "PIDs",
+                          g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, &pid, 1, 4));
+
+  g_variant_builder_close (&builder);
+
+  g_variant_builder_open (&builder, G_VARIANT_TYPE ("a(sa(sv))"));
+  g_variant_builder_close (&builder);
+
+  g_dbus_connection_call (connection,
+                          "org.freedesktop.systemd1",
+                          "/org/freedesktop/systemd1",
+                          "org.freedesktop.systemd1.Manager",
+                          "StartTransientUnit",
+                          g_variant_builder_end (&builder),
+                          G_VARIANT_TYPE ("(o)"),
+                          G_DBUS_CALL_FLAGS_NO_AUTO_START,
+                          1000,
+                          NULL,
+                          on_systemd_call_cb,
+                          (gpointer) "StartTransientUnit");
+#endif
+
+  return TRUE;
+}
+
 void
 gsm_util_setenv (const char *variable,
                  const char *value)
diff --git a/gnome-session/gsm-util.h b/gnome-session/gsm-util.h
index bd7b6986..2735e45c 100644
--- a/gnome-session/gsm-util.h
+++ b/gnome-session/gsm-util.h
@@ -59,6 +59,9 @@ gboolean    gsm_util_start_systemd_unit             (const char  *unit,
                                                      const char  *mode,
                                                      GError     **error);
 #endif
+gboolean    gsm_util_start_systemd_scope            (const gchar *app_id,
+                                                     gint32       pid,
+                                                     GError     **error);
 
 void        gsm_quit                                (void);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]