makefile: fixup bad merge
[tmux.git] / compat / systemd.c
blob6f790a3242d5b17db8ff8380661d7c9425711161
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2022 Nicholas Marriott <nicholas.marriott@gmail.com>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
20 #include <sys/un.h>
22 #include <systemd/sd-bus.h>
23 #include <systemd/sd-daemon.h>
24 #include <systemd/sd-login.h>
25 #include <systemd/sd-id128.h>
27 #include <string.h>
29 #include "tmux.h"
31 int
32 systemd_activated(void)
34 return (sd_listen_fds(0) >= 1);
37 int
38 systemd_create_socket(int flags, char **cause)
40 int fds;
41 int fd;
42 struct sockaddr_un sa;
43 socklen_t addrlen = sizeof sa;
45 fds = sd_listen_fds(0);
46 if (fds > 1) { /* too many file descriptors */
47 errno = E2BIG;
48 goto fail;
51 if (fds == 1) { /* socket-activated */
52 fd = SD_LISTEN_FDS_START;
53 if (!sd_is_socket_unix(fd, SOCK_STREAM, 1, NULL, 0)) {
54 errno = EPFNOSUPPORT;
55 goto fail;
57 if (getsockname(fd, (struct sockaddr *)&sa, &addrlen) == -1)
58 goto fail;
59 socket_path = xstrdup(sa.sun_path);
60 return (fd);
63 return (server_create_socket(flags, cause));
65 fail:
66 if (cause != NULL)
67 xasprintf(cause, "systemd socket error (%s)", strerror(errno));
68 return (-1);
71 int
72 systemd_move_pid_to_new_cgroup(pid_t pid, char **cause)
74 sd_bus_error error = SD_BUS_ERROR_NULL;
75 sd_bus_message *m = NULL, *reply = NULL;
76 sd_bus *bus = NULL;
77 char *name, *desc, *slice;
78 sd_id128_t uuid;
79 int r;
80 pid_t parent_pid;
82 /* Connect to the session bus. */
83 r = sd_bus_default_user(&bus);
84 if (r < 0) {
85 xasprintf(cause, "failed to connect to session bus: %s",
86 strerror(-r));
87 goto finish;
90 /* Start building the method call. */
91 r = sd_bus_message_new_method_call(bus, &m,
92 "org.freedesktop.systemd1",
93 "/org/freedesktop/systemd1",
94 "org.freedesktop.systemd1.Manager",
95 "StartTransientUnit");
96 if (r < 0) {
97 xasprintf(cause, "failed to create bus message: %s",
98 strerror(-r));
99 goto finish;
102 /* Generate a unique name for the new scope, to avoid collisions. */
103 r = sd_id128_randomize(&uuid);
104 if (r < 0) {
105 xasprintf(cause, "failed to generate uuid: %s", strerror(-r));
106 goto finish;
108 xasprintf(&name, "tmux-spawn-" SD_ID128_UUID_FORMAT_STR ".scope",
109 SD_ID128_FORMAT_VAL(uuid));
110 r = sd_bus_message_append(m, "s", name);
111 free(name);
112 if (r < 0) {
113 xasprintf(cause, "failed to append to bus message: %s",
114 strerror(-r));
115 goto finish;
118 /* Mode: fail if there's a queued unit with the same name. */
119 r = sd_bus_message_append(m, "s", "fail");
120 if (r < 0) {
121 xasprintf(cause, "failed to append to bus message: %s",
122 strerror(-r));
123 goto finish;
126 /* Start properties array. */
127 r = sd_bus_message_open_container(m, 'a', "(sv)");
128 if (r < 0) {
129 xasprintf(cause, "failed to start properties array: %s",
130 strerror(-r));
131 goto finish;
134 parent_pid = getpid();
135 xasprintf(&desc, "tmux child pane %ld launched by process %ld",
136 (long)pid, (long)parent_pid);
137 r = sd_bus_message_append(m, "(sv)", "Description", "s", desc);
138 free(desc);
139 if (r < 0) {
140 xasprintf(cause, "failed to append to properties: %s",
141 strerror(-r));
142 goto finish;
146 * Inherit the slice from the parent process, or default to
147 * "app-tmux.slice" if that fails.
149 r = sd_pid_get_user_slice(parent_pid, &slice);
150 if (r < 0) {
151 slice = xstrdup("app-tmux.slice");
153 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
154 free(slice);
155 if (r < 0) {
156 xasprintf(cause, "failed to append to properties: %s",
157 strerror(-r));
158 goto finish;
161 /* PIDs to add to the scope: length - 1 array of uint32_t. */
162 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
163 if (r < 0) {
164 xasprintf(cause, "failed to append to properties: %s",
165 strerror(-r));
166 goto finish;
169 /* Clean up the scope even if it fails. */
170 r = sd_bus_message_append(m, "(sv)", "CollectMode", "s",
171 "inactive-or-failed");
172 if (r < 0) {
173 xasprintf(cause, "failed to append to properties: %s",
174 strerror(-r));
175 goto finish;
178 /* End properties array. */
179 r = sd_bus_message_close_container(m);
180 if (r < 0) {
181 xasprintf(cause, "failed to end properties array: %s",
182 strerror(-r));
183 goto finish;
186 /* aux is currently unused and should be passed an empty array. */
187 r = sd_bus_message_append(m, "a(sa(sv))", 0);
188 if (r < 0) {
189 xasprintf(cause, "failed to append to bus message: %s",
190 strerror(-r));
191 goto finish;
194 /* Call the method with a timeout of 1 second = 1e6 us. */
195 r = sd_bus_call(bus, m, 1000000, &error, &reply);
196 if (r < 0) {
197 if (error.message != NULL) {
198 /* We have a specific error message from sd-bus. */
199 xasprintf(cause, "StartTransientUnit call failed: %s",
200 error.message);
201 } else {
202 xasprintf(cause, "StartTransientUnit call failed: %s",
203 strerror(-r));
205 goto finish;
208 finish:
209 sd_bus_error_free(&error);
210 sd_bus_message_unref(m);
211 sd_bus_message_unref(reply);
212 sd_bus_unref(bus);
214 return (r);