[gnome-shell/benzea/systemd-scopes: 1/3] utils: Add utility function to place a PID into a systemd scope



commit e0bd7883f6dc565e9a38725afd725daeddb50661
Author: Benjamin Berg <bberg redhat com>
Date:   Tue Nov 26 19:44:43 2019 +0100

    utils: Add utility function to place a PID into a systemd scope
    
    If we put children into their own scope, then we can fix a number of
    issues that we were seeing with systemd managed sessions.
    
    This will fix two bis issues, the first one that a child getting killed
    by OOM was affecting the gnome-shell service (setting OOMPolicy would
    also work). The second issue is that a full restart of gnome-shell (e.g.
    after a crash) would also kill all children.
    
    https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/863

 src/shell-util.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/shell-util.h |  4 +++
 2 files changed, 97 insertions(+)
---
diff --git a/src/shell-util.c b/src/shell-util.c
index f344ec50bb..765a3c22e3 100644
--- a/src/shell-util.c
+++ b/src/shell-util.c
@@ -28,6 +28,7 @@
 
 #ifdef HAVE_SYSTEMD
 #include <systemd/sd-daemon.h>
+#include <systemd/sd-login.h>
 #else
 /* So we don't need to add ifdef's everywhere */
 #define sd_notify(u, m)            do {} while (0)
@@ -632,6 +633,98 @@ shell_util_stop_systemd_unit (const char  *unit,
   return shell_util_systemd_call ("StopUnit", unit, mode, error);
 }
 
+
+gboolean
+shell_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
 shell_util_sd_notify (void)
 {
diff --git a/src/shell-util.h b/src/shell-util.h
index acd031048f..a7e69cfd62 100644
--- a/src/shell-util.h
+++ b/src/shell-util.h
@@ -64,6 +64,10 @@ gboolean shell_util_stop_systemd_unit  (const char  *unit,
                                         const char  *mode,
                                         GError     **error);
 
+gboolean shell_util_start_systemd_scope (const gchar *app_id,
+                                         gint32       pid,
+                                         GError     **error);
+
 void shell_util_sd_notify (void);
 
 G_END_DECLS


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