1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "bus-locator.h"
9 #include "bus-unit-util.h"
11 #include "bus-wait-for-jobs.h"
14 #include "process-util.h"
15 #include "random-util.h"
16 #include "socket-util.h"
19 #include "unit-name.h"
20 #include "vmspawn-scope.h"
22 int start_transient_scope(sd_bus
*bus
, const char *machine_name
, bool allow_pidfd
, char **ret_scope
) {
23 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
24 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
25 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
, *m
= NULL
;
26 _cleanup_free_
char *scope
= NULL
, *description
= NULL
;
33 /* Creates a transient scope unit which tracks the lifetime of the current process */
35 r
= bus_wait_for_jobs_new(bus
, &w
);
37 return log_error_errno(r
, "Could not watch job: %m");
39 if (asprintf(&scope
, "machine-%"PRIu64
"-%s.scope", random_u64(), machine_name
) < 0)
42 description
= strjoin("Virtual Machine ", machine_name
);
46 r
= bus_message_new_method_call(bus
, &m
, bus_systemd_mgr
, "StartTransientUnit");
48 return bus_log_create_error(r
);
50 r
= sd_bus_message_append(m
, "ss", /* name */ scope
, /* mode */ "fail");
52 return bus_log_create_error(r
);
55 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
57 return bus_log_create_error(r
);
59 r
= sd_bus_message_append(m
, "(sa)(sa)(sa)",
60 "Description", "s", description
,
62 "CollectMode", "s", "inactive-or-failed");
64 _cleanup_(pidref_done
) PidRef pidref
= PIDREF_NULL
;
65 r
= pidref_set_self(&pidref
);
67 return log_error_errno(r
, "Failed to allocate PID reference: %m");
69 r
= bus_append_scope_pidref(m
, &pidref
, allow_pidfd
);
71 return bus_log_create_error(r
);
73 r
= sd_bus_message_close_container(m
);
75 return bus_log_create_error(r
);
77 /* No auxiliary units */
78 r
= sd_bus_message_append(
83 return bus_log_create_error(r
);
85 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
87 /* If this failed with a property we couldn't write, this is quite likely because the server
88 * doesn't support PIDFDs yet, let's try without. */
90 sd_bus_error_has_names(&error
, SD_BUS_ERROR_UNKNOWN_PROPERTY
, SD_BUS_ERROR_PROPERTY_READ_ONLY
))
91 return start_transient_scope(bus
, machine_name
, false, ret_scope
);
93 return log_error_errno(r
, "Failed to start transient scope unit: %s", bus_error_message(&error
, r
));
96 r
= sd_bus_message_read(reply
, "o", &object
);
98 return bus_log_parse_error(r
);
100 r
= bus_wait_for_jobs_one(w
, object
, /* quiet */ false, NULL
);
105 *ret_scope
= TAKE_PTR(scope
);
110 static int message_add_commands(sd_bus_message
*m
, const char *exec_type
, char ***commands
, size_t n_commands
) {
115 assert(commands
|| n_commands
== 0);
117 /* A small helper for adding an ExecStart / ExecStopPost / etc.. property to an sd_bus_message */
119 r
= sd_bus_message_open_container(m
, 'r', "sv");
121 return bus_log_create_error(r
);
123 r
= sd_bus_message_append(m
, "s", exec_type
);
125 return bus_log_create_error(r
);
127 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
129 return bus_log_create_error(r
);
131 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
133 return bus_log_create_error(r
);
135 FOREACH_ARRAY(cmd
, commands
, n_commands
) {
136 char **cmdline
= *cmd
;
138 r
= sd_bus_message_open_container(m
, 'r', "sasb");
140 return bus_log_create_error(r
);
142 r
= sd_bus_message_append(m
, "s", cmdline
[0]);
144 return bus_log_create_error(r
);
146 r
= sd_bus_message_append_strv(m
, cmdline
);
148 return bus_log_create_error(r
);
150 r
= sd_bus_message_append(m
, "b", 0);
152 return bus_log_create_error(r
);
154 r
= sd_bus_message_close_container(m
);
156 return bus_log_create_error(r
);
159 r
= sd_bus_message_close_container(m
);
161 return bus_log_create_error(r
);
163 r
= sd_bus_message_close_container(m
);
165 return bus_log_create_error(r
);
167 r
= sd_bus_message_close_container(m
);
169 return bus_log_create_error(r
);
174 void socket_service_pair_done(SocketServicePair
*p
) {
177 p
->exec_start_pre
= strv_free(p
->exec_start_pre
);
178 p
->exec_start
= strv_free(p
->exec_start
);
179 p
->exec_stop_post
= strv_free(p
->exec_stop_post
);
180 p
->unit_name_prefix
= mfree(p
->unit_name_prefix
);
181 p
->runtime_directory
= mfree(p
->runtime_directory
);
182 p
->listen_address
= mfree(p
->listen_address
);
186 int start_socket_service_pair(sd_bus
*bus
, const char *scope
, SocketServicePair
*p
) {
187 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
188 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
189 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
190 _cleanup_free_
char *service_desc
= NULL
, *service_name
= NULL
, *socket_name
= NULL
;
191 const char *object
, *socket_type_str
;
194 /* Starts a socket/service unit pair bound to the given scope. */
199 assert(p
->unit_name_prefix
);
200 assert(p
->exec_start
);
201 assert(p
->listen_address
);
203 r
= bus_wait_for_jobs_new(bus
, &w
);
205 return log_error_errno(r
, "Could not watch job: %m");
207 socket_name
= strjoin(p
->unit_name_prefix
, ".socket");
211 service_name
= strjoin(p
->unit_name_prefix
, ".service");
215 service_desc
= quote_command_line(p
->exec_start
, SHELL_ESCAPE_EMPTY
);
219 socket_type_str
= socket_address_type_to_string(p
->socket_type
);
220 if (!socket_type_str
)
221 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Invalid socket type: %d", p
->socket_type
);
223 r
= bus_message_new_method_call(bus
, &m
, bus_systemd_mgr
, "StartTransientUnit");
225 return bus_log_create_error(r
);
227 r
= sd_bus_message_append(m
, "ssa(sv)",
228 /* ss - name, mode */
230 /* a(sv) - Properties */
232 "Description", "s", p
->listen_address
,
234 "BindsTo", "as", 1, scope
,
235 "Listen", "a(ss)", 1, socket_type_str
, p
->listen_address
,
236 "CollectMode", "s", "inactive-or-failed");
238 return bus_log_create_error(r
);
241 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
243 return bus_log_create_error(r
);
245 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
247 return bus_log_create_error(r
);
249 r
= sd_bus_message_append(m
, "s", service_name
);
251 return bus_log_create_error(r
);
253 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
255 return bus_log_create_error(r
);
257 r
= sd_bus_message_append(m
, "(sv)(sv)(sv)(sv)",
258 "Description", "s", service_desc
,
260 "BindsTo", "as", 1, scope
,
261 "CollectMode", "s", "inactive-or-failed");
263 return bus_log_create_error(r
);
265 if (p
->runtime_directory
) {
266 r
= sd_bus_message_append(m
, "(sv)", "RuntimeDirectory", "as", 1, p
->runtime_directory
);
268 return bus_log_create_error(r
);
271 if (p
->exec_start_pre
) {
272 r
= message_add_commands(m
, "ExecStartPre", &p
->exec_start_pre
, 1);
277 r
= message_add_commands(m
, "ExecStart", &p
->exec_start
, 1);
281 if (p
->exec_stop_post
) {
282 r
= message_add_commands(m
, "ExecStopPost", &p
->exec_stop_post
, 1);
287 r
= sd_bus_message_close_container(m
);
289 return bus_log_create_error(r
);
291 r
= sd_bus_message_close_container(m
);
293 return bus_log_create_error(r
);
295 r
= sd_bus_message_close_container(m
);
297 return bus_log_create_error(r
);
299 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
301 return log_error_errno(r
, "Failed to start %s as transient unit: %s", p
->exec_start
[0], bus_error_message(&error
, r
));
303 r
= sd_bus_message_read(reply
, "o", &object
);
305 return bus_log_parse_error(r
);
307 return bus_wait_for_jobs_one(w
, object
, /* quiet */ false, NULL
);