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
, "(sv)(sv)(sv)",
60 "Description", "s", description
,
62 "CollectMode", "s", "inactive-or-failed");
64 return bus_log_create_error(r
);
66 _cleanup_(pidref_done
) PidRef pidref
= PIDREF_NULL
;
67 r
= pidref_set_self(&pidref
);
69 return log_error_errno(r
, "Failed to allocate PID reference: %m");
71 r
= bus_append_scope_pidref(m
, &pidref
, allow_pidfd
);
73 return bus_log_create_error(r
);
75 r
= sd_bus_message_close_container(m
);
77 return bus_log_create_error(r
);
79 /* No auxiliary units */
80 r
= sd_bus_message_append(
85 return bus_log_create_error(r
);
87 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
89 /* If this failed with a property we couldn't write, this is quite likely because the server
90 * doesn't support PIDFDs yet, let's try without. */
92 sd_bus_error_has_names(&error
, SD_BUS_ERROR_UNKNOWN_PROPERTY
, SD_BUS_ERROR_PROPERTY_READ_ONLY
))
93 return start_transient_scope(bus
, machine_name
, false, ret_scope
);
95 return log_error_errno(r
, "Failed to start transient scope unit: %s", bus_error_message(&error
, r
));
98 r
= sd_bus_message_read(reply
, "o", &object
);
100 return bus_log_parse_error(r
);
102 r
= bus_wait_for_jobs_one(w
, object
, /* quiet */ false, NULL
);
107 *ret_scope
= TAKE_PTR(scope
);
112 static int message_add_commands(sd_bus_message
*m
, const char *exec_type
, char ***commands
, size_t n_commands
) {
117 assert(commands
|| n_commands
== 0);
119 /* A small helper for adding an ExecStart / ExecStopPost / etc.. property to an sd_bus_message */
121 r
= sd_bus_message_open_container(m
, 'r', "sv");
123 return bus_log_create_error(r
);
125 r
= sd_bus_message_append(m
, "s", exec_type
);
127 return bus_log_create_error(r
);
129 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
131 return bus_log_create_error(r
);
133 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
135 return bus_log_create_error(r
);
137 FOREACH_ARRAY(cmd
, commands
, n_commands
) {
138 char **cmdline
= *cmd
;
140 r
= sd_bus_message_open_container(m
, 'r', "sasb");
142 return bus_log_create_error(r
);
144 r
= sd_bus_message_append(m
, "s", cmdline
[0]);
146 return bus_log_create_error(r
);
148 r
= sd_bus_message_append_strv(m
, cmdline
);
150 return bus_log_create_error(r
);
152 r
= sd_bus_message_append(m
, "b", 0);
154 return bus_log_create_error(r
);
156 r
= sd_bus_message_close_container(m
);
158 return bus_log_create_error(r
);
161 r
= sd_bus_message_close_container(m
);
163 return bus_log_create_error(r
);
165 r
= sd_bus_message_close_container(m
);
167 return bus_log_create_error(r
);
169 r
= sd_bus_message_close_container(m
);
171 return bus_log_create_error(r
);
176 void socket_service_pair_done(SocketServicePair
*p
) {
179 p
->exec_start_pre
= strv_free(p
->exec_start_pre
);
180 p
->exec_start
= strv_free(p
->exec_start
);
181 p
->exec_stop_post
= strv_free(p
->exec_stop_post
);
182 p
->unit_name_prefix
= mfree(p
->unit_name_prefix
);
183 p
->runtime_directory
= mfree(p
->runtime_directory
);
184 p
->listen_address
= mfree(p
->listen_address
);
188 int start_socket_service_pair(sd_bus
*bus
, const char *scope
, SocketServicePair
*p
) {
189 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
190 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
191 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
192 _cleanup_free_
char *service_desc
= NULL
, *service_name
= NULL
, *socket_name
= NULL
;
193 const char *object
, *socket_type_str
;
196 /* Starts a socket/service unit pair bound to the given scope. */
201 assert(p
->unit_name_prefix
);
202 assert(p
->exec_start
);
203 assert(p
->listen_address
);
205 r
= bus_wait_for_jobs_new(bus
, &w
);
207 return log_error_errno(r
, "Could not watch job: %m");
209 socket_name
= strjoin(p
->unit_name_prefix
, ".socket");
213 service_name
= strjoin(p
->unit_name_prefix
, ".service");
217 service_desc
= quote_command_line(p
->exec_start
, SHELL_ESCAPE_EMPTY
);
221 socket_type_str
= socket_address_type_to_string(p
->socket_type
);
222 if (!socket_type_str
)
223 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Invalid socket type: %d", p
->socket_type
);
225 r
= bus_message_new_method_call(bus
, &m
, bus_systemd_mgr
, "StartTransientUnit");
227 return bus_log_create_error(r
);
229 r
= sd_bus_message_append(m
, "ssa(sv)",
230 /* ss - name, mode */
232 /* a(sv) - Properties */
234 "Description", "s", p
->listen_address
,
236 "BindsTo", "as", 1, scope
,
237 "Listen", "a(ss)", 1, socket_type_str
, p
->listen_address
,
238 "CollectMode", "s", "inactive-or-failed");
240 return bus_log_create_error(r
);
243 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
245 return bus_log_create_error(r
);
247 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
249 return bus_log_create_error(r
);
251 r
= sd_bus_message_append(m
, "s", service_name
);
253 return bus_log_create_error(r
);
255 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
257 return bus_log_create_error(r
);
259 r
= sd_bus_message_append(m
, "(sv)(sv)(sv)(sv)",
260 "Description", "s", service_desc
,
262 "BindsTo", "as", 1, scope
,
263 "CollectMode", "s", "inactive-or-failed");
265 return bus_log_create_error(r
);
267 if (p
->runtime_directory
) {
268 r
= sd_bus_message_append(m
, "(sv)", "RuntimeDirectory", "as", 1, p
->runtime_directory
);
270 return bus_log_create_error(r
);
273 if (p
->exec_start_pre
) {
274 r
= message_add_commands(m
, "ExecStartPre", &p
->exec_start_pre
, 1);
279 r
= message_add_commands(m
, "ExecStart", &p
->exec_start
, 1);
283 if (p
->exec_stop_post
) {
284 r
= message_add_commands(m
, "ExecStopPost", &p
->exec_stop_post
, 1);
289 r
= sd_bus_message_close_container(m
);
291 return bus_log_create_error(r
);
293 r
= sd_bus_message_close_container(m
);
295 return bus_log_create_error(r
);
297 r
= sd_bus_message_close_container(m
);
299 return bus_log_create_error(r
);
301 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
303 return log_error_errno(r
, "Failed to start %s as transient unit: %s", p
->exec_start
[0], bus_error_message(&error
, r
));
305 r
= sd_bus_message_read(reply
, "o", &object
);
307 return bus_log_parse_error(r
);
309 return bus_wait_for_jobs_one(w
, object
, /* quiet */ false, NULL
);