summaryrefslogtreecommitdiffstats
path: root/compat
diff options
context:
space:
mode:
authorNicholas Marriott <nicholas.marriott@gmail.com>2023-04-03 08:50:49 +0100
committerNicholas Marriott <nicholas.marriott@gmail.com>2023-04-03 08:54:06 +0100
commitb9524f5b72d16bd634fc47ad1a4a9d3240bd4370 (patch)
tree3ba1c13ceb700287d649b6caeb20fc2fe63be977 /compat
parent22eb0334c325245e7a49610f91c7842cb6408f4d (diff)
Add support for spawning panes in separate cgroups with systemd and a configure
flag to disable. From Eric T Johnson yut23 AT gvljohnsons DOT com in GitHub issue 3514.
Diffstat (limited to 'compat')
-rw-r--r--compat/systemd.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/compat/systemd.c b/compat/systemd.c
index cce42ed4..6f790a32 100644
--- a/compat/systemd.c
+++ b/compat/systemd.c
@@ -19,7 +19,10 @@
#include <sys/types.h>
#include <sys/un.h>
+#include <systemd/sd-bus.h>
#include <systemd/sd-daemon.h>
+#include <systemd/sd-login.h>
+#include <systemd/sd-id128.h>
#include <string.h>
@@ -64,3 +67,149 @@ fail:
xasprintf(cause, "systemd socket error (%s)", strerror(errno));
return (-1);
}
+
+int
+systemd_move_pid_to_new_cgroup(pid_t pid, char **cause)
+{
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus_message *m = NULL, *reply = NULL;
+ sd_bus *bus = NULL;
+ char *name, *desc, *slice;
+ sd_id128_t uuid;
+ int r;
+ pid_t parent_pid;
+
+ /* Connect to the session bus. */
+ r = sd_bus_default_user(&bus);
+ if (r < 0) {
+ xasprintf(cause, "failed to connect to session bus: %s",
+ strerror(-r));
+ goto finish;
+ }
+
+ /* Start building the method call. */
+ r = sd_bus_message_new_method_call(bus, &m,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StartTransientUnit");
+ if (r < 0) {
+ xasprintf(cause, "failed to create bus message: %s",
+ strerror(-r));
+ goto finish;
+ }
+
+ /* Generate a unique name for the new scope, to avoid collisions. */
+ r = sd_id128_randomize(&uuid);
+ if (r < 0) {
+ xasprintf(cause, "failed to generate uuid: %s", strerror(-r));
+ goto finish;
+ }
+ xasprintf(&name, "tmux-spawn-" SD_ID128_UUID_FORMAT_STR ".scope",
+ SD_ID128_FORMAT_VAL(uuid));
+ r = sd_bus_message_append(m, "s", name);
+ free(name);
+ if (r < 0) {
+ xasprintf(cause, "failed to append to bus message: %s",
+ strerror(-r));
+ goto finish;
+ }
+
+ /* Mode: fail if there's a queued unit with the same name. */
+ r = sd_bus_message_append(m, "s", "fail");
+ if (r < 0) {
+ xasprintf(cause, "failed to append to bus message: %s",
+ strerror(-r));
+ goto finish;
+ }
+
+ /* Start properties array. */
+ r = sd_bus_message_open_container(m, 'a', "(sv)");
+ if (r < 0) {
+ xasprintf(cause, "failed to start properties array: %s",
+ strerror(-r));
+ goto finish;
+ }
+
+ parent_pid = getpid();
+ xasprintf(&desc, "tmux child pane %ld launched by process %ld",
+ (long)pid, (long)parent_pid);
+ r = sd_bus_message_append(m, "(sv)", "Description", "s", desc);
+ free(desc);
+ if (r < 0) {
+ xasprintf(cause, "failed to append to properties: %s",
+ strerror(-r));
+ goto finish;
+ }
+
+ /*
+ * Inherit the slice from the parent process, or default to
+ * "app-tmux.slice" if that fails.
+ */
+ r = sd_pid_get_user_slice(parent_pid, &slice);
+ if (r < 0) {
+ slice = xstrdup("app-tmux.slice");
+ }
+ r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
+ free(slice);
+ if (r < 0) {
+ xasprintf(cause, "failed to append to properties: %s",
+ strerror(-r));
+ goto finish;
+ }
+
+ /* PIDs to add to the scope: length - 1 array of uint32_t. */
+ r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
+ if (r < 0) {
+ xasprintf(cause, "failed to append to properties: %s",
+ strerror(-r));
+ goto finish;
+ }
+
+ /* Clean up the scope even if it fails. */
+ r = sd_bus_message_append(m, "(sv)", "CollectMode", "s",
+ "inactive-or-failed");
+ if (r < 0) {
+ xasprintf(cause, "failed to append to properties: %s",
+ strerror(-r));
+ goto finish;
+ }
+
+ /* End properties array. */
+ r = sd_bus_message_close_container(m);
+ if (r < 0) {
+ xasprintf(cause, "failed to end properties array: %s",
+ strerror(-r));
+ goto finish;
+ }
+
+ /* aux is currently unused and should be passed an empty array. */
+ r = sd_bus_message_append(m, "a(sa(sv))", 0);
+ if (r < 0) {
+ xasprintf(cause, "failed to append to bus message: %s",
+ strerror(-r));
+ goto finish;
+ }
+
+ /* Call the method with a timeout of 1 second = 1e6 us. */
+ r = sd_bus_call(bus, m, 1000000, &error, &reply);
+ if (r < 0) {
+ if (error.message != NULL) {
+ /* We have a specific error message from sd-bus. */
+ xasprintf(cause, "StartTransientUnit call failed: %s",
+ error.message);
+ } else {
+ xasprintf(cause, "StartTransientUnit call failed: %s",
+ strerror(-r));
+ }
+ goto finish;
+ }
+
+finish:
+ sd_bus_error_free(&error);
+ sd_bus_message_unref(m);
+ sd_bus_message_unref(reply);
+ sd_bus_unref(bus);
+
+ return (r);
+}