xref: /netbsd-src/external/bsd/tmux/dist/compat/systemd.c (revision f8cf1a9151c7af1cb0bd8b09c13c66bca599c027)
16db26757Swiz /* $OpenBSD$ */
26db26757Swiz 
36db26757Swiz /*
46db26757Swiz  * Copyright (c) 2022 Nicholas Marriott <nicholas.marriott@gmail.com>
56db26757Swiz  *
66db26757Swiz  * Permission to use, copy, modify, and distribute this software for any
76db26757Swiz  * purpose with or without fee is hereby granted, provided that the above
86db26757Swiz  * copyright notice and this permission notice appear in all copies.
96db26757Swiz  *
106db26757Swiz  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
116db26757Swiz  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
126db26757Swiz  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
136db26757Swiz  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
146db26757Swiz  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
156db26757Swiz  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
166db26757Swiz  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176db26757Swiz  */
186db26757Swiz 
196db26757Swiz #include <sys/types.h>
206db26757Swiz #include <sys/un.h>
216db26757Swiz 
22c23f9150Swiz #include <systemd/sd-bus.h>
236db26757Swiz #include <systemd/sd-daemon.h>
24c23f9150Swiz #include <systemd/sd-login.h>
25c23f9150Swiz #include <systemd/sd-id128.h>
26c23f9150Swiz 
27*f8cf1a91Swiz #include <stdlib.h>
28c23f9150Swiz #include <string.h>
29*f8cf1a91Swiz #include <unistd.h>
306db26757Swiz 
316db26757Swiz #include "tmux.h"
326db26757Swiz 
336db26757Swiz int
34c23f9150Swiz systemd_activated(void)
35c23f9150Swiz {
36c23f9150Swiz 	return (sd_listen_fds(0) >= 1);
37c23f9150Swiz }
38c23f9150Swiz 
39c23f9150Swiz int
406db26757Swiz systemd_create_socket(int flags, char **cause)
416db26757Swiz {
426db26757Swiz 	int			fds;
436db26757Swiz 	int			fd;
446db26757Swiz 	struct sockaddr_un	sa;
45c23f9150Swiz 	socklen_t		addrlen = sizeof sa;
466db26757Swiz 
476db26757Swiz 	fds = sd_listen_fds(0);
486db26757Swiz 	if (fds > 1) { /* too many file descriptors */
496db26757Swiz 		errno = E2BIG;
506db26757Swiz 		goto fail;
516db26757Swiz 	}
526db26757Swiz 
536db26757Swiz 	if (fds == 1) { /* socket-activated */
546db26757Swiz 		fd = SD_LISTEN_FDS_START;
556db26757Swiz 		if (!sd_is_socket_unix(fd, SOCK_STREAM, 1, NULL, 0)) {
566db26757Swiz 			errno = EPFNOSUPPORT;
576db26757Swiz 			goto fail;
586db26757Swiz 		}
596db26757Swiz 		if (getsockname(fd, (struct sockaddr *)&sa, &addrlen) == -1)
606db26757Swiz 			goto fail;
616db26757Swiz 		socket_path = xstrdup(sa.sun_path);
626db26757Swiz 		return (fd);
636db26757Swiz 	}
646db26757Swiz 
656db26757Swiz 	return (server_create_socket(flags, cause));
666db26757Swiz 
676db26757Swiz fail:
686db26757Swiz 	if (cause != NULL)
696db26757Swiz 		xasprintf(cause, "systemd socket error (%s)", strerror(errno));
706db26757Swiz 	return (-1);
716db26757Swiz }
72c23f9150Swiz 
73c23f9150Swiz int
74c23f9150Swiz systemd_move_pid_to_new_cgroup(pid_t pid, char **cause)
75c23f9150Swiz {
76c23f9150Swiz 	sd_bus_error	 error = SD_BUS_ERROR_NULL;
77c23f9150Swiz 	sd_bus_message	*m = NULL, *reply = NULL;
78c23f9150Swiz 	sd_bus 		*bus = NULL;
79c23f9150Swiz 	char		*name, *desc, *slice;
80c23f9150Swiz 	sd_id128_t	 uuid;
81c23f9150Swiz 	int		 r;
82c23f9150Swiz 	pid_t		 parent_pid;
83c23f9150Swiz 
84c23f9150Swiz 	/* Connect to the session bus. */
85c23f9150Swiz 	r = sd_bus_default_user(&bus);
86c23f9150Swiz 	if (r < 0) {
87c23f9150Swiz 		xasprintf(cause, "failed to connect to session bus: %s",
88c23f9150Swiz 		    strerror(-r));
89c23f9150Swiz 		goto finish;
90c23f9150Swiz 	}
91c23f9150Swiz 
92c23f9150Swiz 	/* Start building the method call. */
93c23f9150Swiz 	r = sd_bus_message_new_method_call(bus, &m,
94c23f9150Swiz 	    "org.freedesktop.systemd1",
95c23f9150Swiz 	    "/org/freedesktop/systemd1",
96c23f9150Swiz 	    "org.freedesktop.systemd1.Manager",
97c23f9150Swiz 	    "StartTransientUnit");
98c23f9150Swiz 	if (r < 0) {
99c23f9150Swiz 		xasprintf(cause, "failed to create bus message: %s",
100c23f9150Swiz 		    strerror(-r));
101c23f9150Swiz 		goto finish;
102c23f9150Swiz 	}
103c23f9150Swiz 
104c23f9150Swiz 	/* Generate a unique name for the new scope, to avoid collisions. */
105c23f9150Swiz 	r = sd_id128_randomize(&uuid);
106c23f9150Swiz 	if (r < 0) {
107c23f9150Swiz 		xasprintf(cause, "failed to generate uuid: %s", strerror(-r));
108c23f9150Swiz 		goto finish;
109c23f9150Swiz 	}
110c23f9150Swiz 	xasprintf(&name, "tmux-spawn-" SD_ID128_UUID_FORMAT_STR ".scope",
111c23f9150Swiz 	    SD_ID128_FORMAT_VAL(uuid));
112c23f9150Swiz 	r = sd_bus_message_append(m, "s", name);
113c23f9150Swiz 	free(name);
114c23f9150Swiz 	if (r < 0) {
115c23f9150Swiz 		xasprintf(cause, "failed to append to bus message: %s",
116c23f9150Swiz 		    strerror(-r));
117c23f9150Swiz 		goto finish;
118c23f9150Swiz 	}
119c23f9150Swiz 
120c23f9150Swiz 	/* Mode: fail if there's a queued unit with the same name. */
121c23f9150Swiz 	r = sd_bus_message_append(m, "s", "fail");
122c23f9150Swiz 	if (r < 0) {
123c23f9150Swiz 		xasprintf(cause, "failed to append to bus message: %s",
124c23f9150Swiz 		    strerror(-r));
125c23f9150Swiz 		goto finish;
126c23f9150Swiz 	}
127c23f9150Swiz 
128c23f9150Swiz 	/* Start properties array. */
129c23f9150Swiz 	r = sd_bus_message_open_container(m, 'a', "(sv)");
130c23f9150Swiz 	if (r < 0) {
131c23f9150Swiz 		xasprintf(cause, "failed to start properties array: %s",
132c23f9150Swiz 		    strerror(-r));
133c23f9150Swiz 		goto finish;
134c23f9150Swiz 	}
135c23f9150Swiz 
136c23f9150Swiz 	parent_pid = getpid();
137c23f9150Swiz 	xasprintf(&desc, "tmux child pane %ld launched by process %ld",
138c23f9150Swiz 	    (long)pid, (long)parent_pid);
139c23f9150Swiz 	r = sd_bus_message_append(m, "(sv)", "Description", "s", desc);
140c23f9150Swiz 	free(desc);
141c23f9150Swiz 	if (r < 0) {
142c23f9150Swiz 		xasprintf(cause, "failed to append to properties: %s",
143c23f9150Swiz 		    strerror(-r));
144c23f9150Swiz 		goto finish;
145c23f9150Swiz 	}
146c23f9150Swiz 
147c23f9150Swiz 	/*
148*f8cf1a91Swiz 	 * Make sure that the session shells are terminated with SIGHUP since
149*f8cf1a91Swiz 	 * bash and friends tend to ignore SIGTERM.
150*f8cf1a91Swiz 	 */
151*f8cf1a91Swiz 	r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", 1);
152*f8cf1a91Swiz 	if (r < 0) {
153*f8cf1a91Swiz 		xasprintf(cause, "failed to append to properties: %s",
154*f8cf1a91Swiz 		    strerror(-r));
155*f8cf1a91Swiz 		goto finish;
156*f8cf1a91Swiz 	}
157*f8cf1a91Swiz 
158*f8cf1a91Swiz 	/*
159c23f9150Swiz 	 * Inherit the slice from the parent process, or default to
160c23f9150Swiz 	 * "app-tmux.slice" if that fails.
161c23f9150Swiz 	 */
162c23f9150Swiz 	r = sd_pid_get_user_slice(parent_pid, &slice);
163c23f9150Swiz 	if (r < 0) {
164c23f9150Swiz 		slice = xstrdup("app-tmux.slice");
165c23f9150Swiz 	}
166c23f9150Swiz 	r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
167c23f9150Swiz 	free(slice);
168c23f9150Swiz 	if (r < 0) {
169c23f9150Swiz 		xasprintf(cause, "failed to append to properties: %s",
170c23f9150Swiz 		    strerror(-r));
171c23f9150Swiz 		goto finish;
172c23f9150Swiz 	}
173c23f9150Swiz 
174c23f9150Swiz 	/* PIDs to add to the scope: length - 1 array of uint32_t. */
175c23f9150Swiz 	r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
176c23f9150Swiz 	if (r < 0) {
177c23f9150Swiz 		xasprintf(cause, "failed to append to properties: %s",
178c23f9150Swiz 		    strerror(-r));
179c23f9150Swiz 		goto finish;
180c23f9150Swiz 	}
181c23f9150Swiz 
182c23f9150Swiz 	/* Clean up the scope even if it fails. */
183c23f9150Swiz 	r = sd_bus_message_append(m, "(sv)", "CollectMode", "s",
184c23f9150Swiz 	    "inactive-or-failed");
185c23f9150Swiz 	if (r < 0) {
186c23f9150Swiz 		xasprintf(cause, "failed to append to properties: %s",
187c23f9150Swiz 		    strerror(-r));
188c23f9150Swiz 		goto finish;
189c23f9150Swiz 	}
190c23f9150Swiz 
191c23f9150Swiz 	/* End properties array. */
192c23f9150Swiz 	r = sd_bus_message_close_container(m);
193c23f9150Swiz 	if (r < 0) {
194c23f9150Swiz 		xasprintf(cause, "failed to end properties array: %s",
195c23f9150Swiz 		    strerror(-r));
196c23f9150Swiz 		goto finish;
197c23f9150Swiz 	}
198c23f9150Swiz 
199c23f9150Swiz 	/* aux is currently unused and should be passed an empty array. */
200c23f9150Swiz 	r = sd_bus_message_append(m, "a(sa(sv))", 0);
201c23f9150Swiz 	if (r < 0) {
202c23f9150Swiz 		xasprintf(cause, "failed to append to bus message: %s",
203c23f9150Swiz 		    strerror(-r));
204c23f9150Swiz 		goto finish;
205c23f9150Swiz 	}
206c23f9150Swiz 
207c23f9150Swiz 	/* Call the method with a timeout of 1 second = 1e6 us. */
208c23f9150Swiz 	r = sd_bus_call(bus, m, 1000000, &error, &reply);
209c23f9150Swiz 	if (r < 0) {
210c23f9150Swiz 		if (error.message != NULL) {
211c23f9150Swiz 			/* We have a specific error message from sd-bus. */
212c23f9150Swiz 			xasprintf(cause, "StartTransientUnit call failed: %s",
213c23f9150Swiz 			    error.message);
214c23f9150Swiz 		} else {
215c23f9150Swiz 			xasprintf(cause, "StartTransientUnit call failed: %s",
216c23f9150Swiz 			    strerror(-r));
217c23f9150Swiz 		}
218c23f9150Swiz 		goto finish;
219c23f9150Swiz 	}
220c23f9150Swiz 
221c23f9150Swiz finish:
222c23f9150Swiz 	sd_bus_error_free(&error);
223c23f9150Swiz 	sd_bus_message_unref(m);
224c23f9150Swiz 	sd_bus_message_unref(reply);
225c23f9150Swiz 	sd_bus_unref(bus);
226c23f9150Swiz 
227c23f9150Swiz 	return (r);
228c23f9150Swiz }
229