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 */
 | 
					/* systemd.c */
 | 
				
			||||||
int		 systemd_activated(void);
 | 
					int		 systemd_activated(void);
 | 
				
			||||||
int		 systemd_create_socket(int, char **);
 | 
					int		 systemd_create_socket(int, char **);
 | 
				
			||||||
 | 
					int		 systemd_move_pid_to_new_cgroup(pid_t, char **);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAVE_UTF8PROC
 | 
					#ifdef HAVE_UTF8PROC
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										149
									
								
								compat/systemd.c
									
									
									
									
									
								
							
							
						
						
									
										149
									
								
								compat/systemd.c
									
									
									
									
									
								
							@@ -19,7 +19,10 @@
 | 
				
			|||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
#include <sys/un.h>
 | 
					#include <sys/un.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <systemd/sd-bus.h>
 | 
				
			||||||
#include <systemd/sd-daemon.h>
 | 
					#include <systemd/sd-daemon.h>
 | 
				
			||||||
 | 
					#include <systemd/sd-login.h>
 | 
				
			||||||
 | 
					#include <systemd/sd-id128.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -64,3 +67,149 @@ fail:
 | 
				
			|||||||
		xasprintf(cause, "systemd socket error (%s)", strerror(errno));
 | 
							xasprintf(cause, "systemd socket error (%s)", strerror(errno));
 | 
				
			||||||
	return (-1);
 | 
						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
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
AM_CONDITIONAL(HAVE_SYSTEMD, [test "x$found_systemd" = xyes])
 | 
					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.
 | 
					# Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well.
 | 
				
			||||||
AC_MSG_CHECKING(for b64_ntop)
 | 
					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. */
 | 
						/* 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;
 | 
							goto complete;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Child process. Change to the working directory or home if that
 | 
						 * Child process. Change to the working directory or home if that
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user