mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							
								
								
									
										1
									
								
								compat.h
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								compat.h
									
									
									
									
									
								
							@@ -425,6 +425,7 @@ void		*recallocarray(void *, size_t, size_t, size_t);
 | 
			
		||||
/* systemd.c */
 | 
			
		||||
int		 systemd_activated(void);
 | 
			
		||||
int		 systemd_create_socket(int, char **);
 | 
			
		||||
int		 systemd_move_pid_to_new_cgroup(pid_t, char **);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_UTF8PROC
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										149
									
								
								compat/systemd.c
									
									
									
									
									
								
							
							
						
						
									
										149
									
								
								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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								configure.ac
									
									
									
									
									
								
							@@ -420,6 +420,21 @@ if test x"$enable_systemd" = xyes; then
 | 
			
		||||
	fi
 | 
			
		||||
fi
 | 
			
		||||
AM_CONDITIONAL(HAVE_SYSTEMD, [test "x$found_systemd" = xyes])
 | 
			
		||||
AC_ARG_ENABLE(
 | 
			
		||||
	cgroups,
 | 
			
		||||
	AS_HELP_STRING(--disable-cgroups, disable adding panes to new cgroups with systemd)
 | 
			
		||||
)
 | 
			
		||||
if test "x$enable_cgroups" = x; then
 | 
			
		||||
	# Default to the same as $enable_systemd.
 | 
			
		||||
	enable_cgroups=$enable_systemd
 | 
			
		||||
fi
 | 
			
		||||
if test "x$enable_cgroups" = xyes; then
 | 
			
		||||
	if test "x$found_systemd" = xyes; then
 | 
			
		||||
		AC_DEFINE(ENABLE_CGROUPS)
 | 
			
		||||
	else
 | 
			
		||||
		AC_MSG_ERROR("cgroups requires systemd to be enabled")
 | 
			
		||||
	fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well.
 | 
			
		||||
AC_MSG_CHECKING(for b64_ntop)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								spawn.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								spawn.c
									
									
									
									
									
								
							@@ -380,8 +380,20 @@ spawn_pane(struct spawn_context *sc, char **cause)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* In the parent process, everything is done now. */
 | 
			
		||||
	if (new_wp->pid != 0)
 | 
			
		||||
	if (new_wp->pid != 0) {
 | 
			
		||||
#if defined(HAVE_SYSTEMD) && defined(ENABLE_CGROUPS)
 | 
			
		||||
		/*
 | 
			
		||||
		 * Move the child process into a new cgroup for systemd-oomd
 | 
			
		||||
		 * isolation.
 | 
			
		||||
		 */
 | 
			
		||||
		if (systemd_move_pid_to_new_cgroup(new_wp->pid, cause) < 0) {
 | 
			
		||||
			log_debug("%s: moving pane to new cgroup failed: %s",
 | 
			
		||||
			    __func__, *cause);
 | 
			
		||||
			free (*cause);
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
		goto complete;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Child process. Change to the working directory or home if that
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user