• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 14630481637

23 Apr 2025 07:04PM UTC coverage: 72.178% (-0.002%) from 72.18%
14630481637

push

github

DaanDeMeyer
mkosi: Run clangd within the tools tree instead of the build container

Running within the build sandbox has a number of disadvantages:
- We have a separate clangd cache for each distribution/release combo
- It requires to build the full image before clangd can be used
- It breaks every time the image becomes out of date and requires a
  rebuild
- We can't look at system headers as we don't have the knowledge to map
  them from inside the build sandbox to the corresponding path on the host

Instead, let's have mkosi.clangd run clangd within the tools tree. We
already require building systemd for both the host and the target anyway,
and all the dependencies to build systemd are installed in the tools tree
already for that, as well as clangd since it's installed together with the
other clang tooling we install in the tools tree. Unlike the previous approach,
this approach only requires the mkosi tools tree to be built upfront, which has
a much higher chance of not invalidating its cache. We can also trivially map
system header lookups from within the sandbox to the path within mkosi.tools
on the host so that starts working as well.

297054 of 411557 relevant lines covered (72.18%)

686269.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.4
/src/machine/machine-dbus.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <errno.h>
4
#include <sys/mount.h>
5
#include <sys/wait.h>
6

7
#include "alloc-util.h"
8
#include "bus-common-errors.h"
9
#include "bus-get-properties.h"
10
#include "bus-internal.h"
11
#include "bus-label.h"
12
#include "bus-locator.h"
13
#include "bus-polkit.h"
14
#include "bus-util.h"
15
#include "copy.h"
16
#include "env-file.h"
17
#include "env-util.h"
18
#include "fd-util.h"
19
#include "fileio.h"
20
#include "format-util.h"
21
#include "fs-util.h"
22
#include "in-addr-util.h"
23
#include "local-addresses.h"
24
#include "machine-dbus.h"
25
#include "machine.h"
26
#include "machined.h"
27
#include "mkdir.h"
28
#include "mount-util.h"
29
#include "mountpoint-util.h"
30
#include "namespace-util.h"
31
#include "operation.h"
32
#include "os-util.h"
33
#include "path-util.h"
34
#include "process-util.h"
35
#include "signal-util.h"
36
#include "strv.h"
37
#include "terminal-util.h"
38
#include "tmpfile-util.h"
39
#include "user-util.h"
40

41
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
31✔
42
static BUS_DEFINE_PROPERTY_GET2(property_get_state, "s", Machine, machine_get_state, machine_state_to_string);
31✔
43

44
static int property_get_netif(
31✔
45
                sd_bus *bus,
46
                const char *path,
47
                const char *interface,
48
                const char *property,
49
                sd_bus_message *reply,
50
                void *userdata,
51
                sd_bus_error *error) {
52

53
        Machine *m = ASSERT_PTR(userdata);
31✔
54

55
        assert(bus);
31✔
56
        assert(reply);
31✔
57

58
        assert_cc(sizeof(int) == sizeof(int32_t));
31✔
59

60
        return sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
31✔
61
}
62

63
int bus_machine_method_unregister(sd_bus_message *message, void *userdata, sd_bus_error *error) {
36✔
64
        Machine *m = ASSERT_PTR(userdata);
36✔
65
        int r;
36✔
66

67
        assert(message);
36✔
68

69
        const char *details[] = {
36✔
70
                "machine", m->name,
36✔
71
                "verb", "unregister",
72
                NULL
73
        };
74

75
        r = bus_verify_polkit_async(
72✔
76
                        message,
77
                        "org.freedesktop.machine1.manage-machines",
78
                        details,
79
                        &m->manager->polkit_registry,
36✔
80
                        error);
81
        if (r < 0)
36✔
82
                return r;
36✔
83
        if (r == 0)
36✔
84
                return 1; /* Will call us back */
85

86
        r = machine_finalize(m);
36✔
87
        if (r < 0)
36✔
88
                return r;
89

90
        return sd_bus_reply_method_return(message, NULL);
36✔
91
}
92

93
int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
3✔
94
        Machine *m = ASSERT_PTR(userdata);
3✔
95
        int r;
3✔
96

97
        assert(message);
3✔
98

99
        const char *details[] = {
3✔
100
                "machine", m->name,
3✔
101
                "verb", "terminate",
102
                NULL
103
        };
104

105
        r = bus_verify_polkit_async(
6✔
106
                        message,
107
                        "org.freedesktop.machine1.manage-machines",
108
                        details,
109
                        &m->manager->polkit_registry,
3✔
110
                        error);
111
        if (r < 0)
3✔
112
                return r;
3✔
113
        if (r == 0)
3✔
114
                return 1; /* Will call us back */
115

116
        r = machine_stop(m);
3✔
117
        if (r < 0)
3✔
118
                return r;
119

120
        return sd_bus_reply_method_return(message, NULL);
3✔
121
}
122

123
int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
19✔
124
        Machine *m = ASSERT_PTR(userdata);
19✔
125
        const char *swho;
19✔
126
        int32_t signo;
19✔
127
        KillWhom whom;
19✔
128
        int r;
19✔
129

130
        assert(message);
19✔
131

132
        r = sd_bus_message_read(message, "si", &swho, &signo);
19✔
133
        if (r < 0)
19✔
134
                return r;
19✔
135

136
        if (isempty(swho))
19✔
137
                whom = KILL_ALL;
138
        else {
139
                whom = kill_whom_from_string(swho);
19✔
140
                if (whom < 0)
19✔
141
                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
×
142
        }
143

144
        if (!SIGNAL_VALID(signo))
19✔
145
                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
×
146

147
        const char *details[] = {
19✔
148
                "machine", m->name,
19✔
149
                "verb", "kill",
150
                NULL
151
        };
152

153
        r = bus_verify_polkit_async(
38✔
154
                        message,
155
                        "org.freedesktop.machine1.manage-machines",
156
                        details,
157
                        &m->manager->polkit_registry,
19✔
158
                        error);
159
        if (r < 0)
19✔
160
                return r;
161
        if (r == 0)
19✔
162
                return 1; /* Will call us back */
163

164
        r = machine_kill(m, whom, signo);
19✔
165
        if (r < 0)
19✔
166
                return r;
167

168
        return sd_bus_reply_method_return(message, NULL);
19✔
169
}
170

171
int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
99✔
172
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
99✔
173
        _cleanup_free_ struct local_address *addresses = NULL;
99✔
174
        Machine *m = ASSERT_PTR(userdata);
99✔
175
        int r;
99✔
176

177
        assert(message);
99✔
178

179
        r = sd_bus_message_new_method_return(message, &reply);
99✔
180
        if (r < 0)
99✔
181
                return r;
182

183
        r = sd_bus_message_open_container(reply, 'a', "(iay)");
99✔
184
        if (r < 0)
99✔
185
                return r;
186

187
        int n = machine_get_addresses(m, &addresses);
99✔
188
        if (n == -ENONET)
99✔
189
                return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
×
190
        if (ERRNO_IS_NEG_NOT_SUPPORTED(n))
99✔
191
                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines.");
×
192
        if (n < 0)
99✔
193
                return sd_bus_error_set_errnof(error, n, "Failed to get addresses: %m");
×
194

195
        for (int i = 0; i < n; i++) {
1,331✔
196
                r = sd_bus_message_open_container(reply, 'r', "iay");
1,232✔
197
                if (r < 0)
1,232✔
198
                        return r;
199

200
                r = sd_bus_message_append(reply, "i", addresses[i].family);
1,232✔
201
                if (r < 0)
1,232✔
202
                        return r;
203

204
                r = sd_bus_message_append_array(reply, 'y', &addresses[i].address, FAMILY_ADDRESS_SIZE(addresses[i].family));
1,232✔
205
                if (r < 0)
1,232✔
206
                        return r;
207

208
                r = sd_bus_message_close_container(reply);
1,232✔
209
                if (r < 0)
1,232✔
210
                        return r;
211
        }
212

213
        r = sd_bus_message_close_container(reply);
99✔
214
        if (r < 0)
99✔
215
                return r;
216

217
        return sd_bus_send(NULL, reply, NULL);
99✔
218
}
219

220
int bus_machine_method_get_ssh_info(sd_bus_message *message, void *userdata, sd_bus_error *error) {
×
221
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
×
222
        Machine *m = ASSERT_PTR(userdata);
×
223
        int r;
×
224

225
        assert(message);
×
226

227
        r = sd_bus_message_new_method_return(message, &reply);
×
228
        if (r < 0)
×
229
                return r;
230

231
        if (!m->ssh_address || !m->ssh_private_key_path)
×
232
                return -ENOENT;
233

234
        r = sd_bus_message_append(reply, "ss", m->ssh_address, m->ssh_private_key_path);
×
235
        if (r < 0)
×
236
                return r;
237

238
        return sd_bus_send(NULL, reply, NULL);
×
239
}
240

241
int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
27✔
242
        _cleanup_strv_free_ char **l = NULL;
27✔
243
        Machine *m = ASSERT_PTR(userdata);
27✔
244
        int r;
27✔
245

246
        assert(message);
27✔
247

248
        r = machine_get_os_release(m, &l);
27✔
249
        if (r == -ENONET)
27✔
250
                return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, "Machine does not contain OS release information.");
×
251
        if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
27✔
252
                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines.");
×
253
        if (r < 0)
27✔
254
                return sd_bus_error_set_errnof(error, r, "Failed to get OS release: %m");
×
255

256
        return bus_reply_pair_array(message, l);
27✔
257
}
258

259
int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1✔
260
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1✔
261
        _cleanup_free_ char *pty_name = NULL;
1✔
262
        _cleanup_close_ int master = -EBADF;
1✔
263
        Machine *m = ASSERT_PTR(userdata);
1✔
264
        int r;
1✔
265

266
        assert(message);
1✔
267

268
        const char *details[] = {
1✔
269
                "machine", m->name,
1✔
270
                NULL
271
        };
272

273
        r = bus_verify_polkit_async(
2✔
274
                        message,
275
                        m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-open-pty" : "org.freedesktop.machine1.open-pty",
1✔
276
                        details,
277
                        &m->manager->polkit_registry,
1✔
278
                        error);
279
        if (r < 0)
1✔
280
                return r;
281
        if (r == 0)
1✔
282
                return 1; /* Will call us back */
283

284
        master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC, &pty_name);
1✔
285
        if (master < 0)
1✔
286
                return master;
287

288
        r = sd_bus_message_new_method_return(message, &reply);
1✔
289
        if (r < 0)
1✔
290
                return r;
291

292
        r = sd_bus_message_append(reply, "hs", master, pty_name);
1✔
293
        if (r < 0)
1✔
294
                return r;
295

296
        return sd_bus_send(NULL, reply, NULL);
1✔
297
}
298

299
int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
×
300
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
×
301
        _cleanup_free_ char *pty_name = NULL;
×
302
        _cleanup_close_ int master = -EBADF;
×
303
        Machine *m = ASSERT_PTR(userdata);
×
304
        int r;
×
305

306
        assert(message);
×
307

308
        const char *details[] = {
×
309
                "machine", m->name,
×
310
                "verb", "login",
311
                NULL
312
        };
313

314
        r = bus_verify_polkit_async(
×
315
                        message,
316
                        m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login",
×
317
                        details,
318
                        &m->manager->polkit_registry,
×
319
                        error);
320
        if (r < 0)
×
321
                return r;
322
        if (r == 0)
×
323
                return 1; /* Will call us back */
324

325
        master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC, &pty_name);
×
326
        if (master < 0)
×
327
                return master;
328

329
        r = machine_start_getty(m, pty_name, error);
×
330
        if (r < 0)
×
331
                return r;
332

333
        r = sd_bus_message_new_method_return(message, &reply);
×
334
        if (r < 0)
×
335
                return r;
336

337
        r = sd_bus_message_append(reply, "hs", master, pty_name);
×
338
        if (r < 0)
×
339
                return r;
340

341
        return sd_bus_send(NULL, reply, NULL);
×
342
}
343

344
int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) {
2✔
345
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
2✔
346
        _cleanup_free_ char *pty_name = NULL;
2✔
347
        _cleanup_close_ int master = -EBADF;
2✔
348
        _cleanup_strv_free_ char **env = NULL, **args_wire = NULL, **args = NULL;
2✔
349
        _cleanup_free_ char *command_line = NULL;
2✔
350
        Machine *m = ASSERT_PTR(userdata);
2✔
351
        const char *user, *path;
2✔
352
        int r;
2✔
353

354
        assert(message);
2✔
355

356
        r = sd_bus_message_read(message, "ss", &user, &path);
2✔
357
        if (r < 0)
2✔
358
                return r;
359
        user = isempty(user) ? "root" : user;
2✔
360
        r = sd_bus_message_read_strv(message, &args_wire);
2✔
361
        if (r < 0)
2✔
362
                return r;
363
        if (isempty(path)) {
2✔
364
                path = machine_default_shell_path();
×
365
                args = machine_default_shell_args(user);
×
366
                if (!args)
×
367
                        return -ENOMEM;
368
        } else {
369
                if (!path_is_absolute(path))
2✔
370
                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified path '%s' is not absolute", path);
×
371
                args = TAKE_PTR(args_wire);
2✔
372
                if (strv_isempty(args)) {
2✔
373
                        args = strv_free(args);
×
374

375
                        args = strv_new(path);
×
376
                        if (!args)
×
377
                                return -ENOMEM;
378
                }
379
        }
380

381
        r = sd_bus_message_read_strv(message, &env);
2✔
382
        if (r < 0)
2✔
383
                return r;
384
        if (!strv_env_is_valid(env))
2✔
385
                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
×
386

387
        command_line = strv_join(args, " ");
2✔
388
        if (!command_line)
2✔
389
                return -ENOMEM;
390
        const char *details[] = {
2✔
391
                "machine", m->name,
2✔
392
                "user", user,
393
                "program", path,
394
                "command_line", command_line,
395
                NULL
396
        };
397

398
        r = bus_verify_polkit_async(
4✔
399
                        message,
400
                        m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell",
2✔
401
                        details,
402
                        &m->manager->polkit_registry,
2✔
403
                        error);
404
        if (r < 0)
2✔
405
                return r;
406
        if (r == 0)
2✔
407
                return 1; /* Will call us back */
408

409
        master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC, &pty_name);
2✔
410
        if (master < 0)
2✔
411
                return master;
412

413
        r = machine_start_shell(m, master, pty_name, user, path, args, env, error);
2✔
414
        if (r < 0)
2✔
415
                return r;
416

417
        r = sd_bus_message_new_method_return(message, &reply);
2✔
418
        if (r < 0)
2✔
419
                return r;
420

421
        r = sd_bus_message_append(reply, "hs", master, pty_name);
2✔
422
        if (r < 0)
2✔
423
                return r;
424

425
        return sd_bus_send(NULL, reply, NULL);
2✔
426
}
427

428
int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1✔
429
        int read_only, make_file_or_directory;
1✔
430
        const char *dest, *src, *propagate_directory;
1✔
431
        Machine *m = ASSERT_PTR(userdata);
1✔
432
        MountInNamespaceFlags flags = 0;
1✔
433
        uid_t uid;
1✔
434
        int r;
1✔
435

436
        assert(message);
1✔
437

438
        if (m->class != MACHINE_CONTAINER)
1✔
439
                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
×
440

441
        r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_file_or_directory);
1✔
442
        if (r < 0)
1✔
443
                return r;
444

445
        if (!path_is_absolute(src) || !path_is_normalized(src))
1✔
446
                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and normalized.");
×
447

448
        if (isempty(dest))
1✔
449
                dest = src;
1✔
450
        else if (!path_is_absolute(dest) || !path_is_normalized(dest))
×
451
                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized.");
×
452

453
        const char *details[] = {
1✔
454
                "machine", m->name,
1✔
455
                "verb", "bind",
456
                "src", src,
457
                "dest", dest,
458
                NULL
459
        };
460

461
        r = bus_verify_polkit_async(
2✔
462
                        message,
463
                        "org.freedesktop.machine1.manage-machines",
464
                        details,
465
                        &m->manager->polkit_registry,
1✔
466
                        error);
467
        if (r < 0)
1✔
468
                return r;
469
        if (r == 0)
1✔
470
                return 1; /* Will call us back */
471

472
        r = machine_get_uid_shift(m, &uid);
1✔
473
        if (r < 0)
1✔
474
                return r;
475
        if (uid != 0)
1✔
476
                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Can't bind mount on container with user namespacing applied.");
×
477

478
        if (read_only)
1✔
479
                flags |= MOUNT_IN_NAMESPACE_READ_ONLY;
×
480
        if (make_file_or_directory)
1✔
481
                flags |= MOUNT_IN_NAMESPACE_MAKE_FILE_OR_DIRECTORY;
1✔
482

483
        propagate_directory = strjoina("/run/systemd/nspawn/propagate/", m->name);
5✔
484
        r = bind_mount_in_namespace(
2✔
485
                        &m->leader,
1✔
486
                        propagate_directory,
487
                        "/run/host/incoming/",
488
                        src, dest,
489
                        flags);
490
        if (r < 0)
1✔
491
                return sd_bus_error_set_errnof(error, r, "Failed to mount %s on %s in machine's namespace: %m", src, dest);
×
492

493
        return sd_bus_reply_method_return(message, NULL);
1✔
494
}
495

496
int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
3✔
497
        const char *src, *dest, *host_path, *container_path;
3✔
498
        CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS;
3✔
499
        Machine *m = ASSERT_PTR(userdata);
3✔
500
        Manager *manager = m->manager;
3✔
501
        bool copy_from;
3✔
502
        int r;
3✔
503

504
        assert(message);
3✔
505

506
        if (m->manager->n_operations >= OPERATIONS_MAX)
3✔
507
                return sd_bus_error_set(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
×
508

509
        if (m->class != MACHINE_CONTAINER)
3✔
510
                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
×
511

512
        r = sd_bus_message_read(message, "ss", &src, &dest);
3✔
513
        if (r < 0)
3✔
514
                return r;
515

516
        if (endswith(sd_bus_message_get_member(message), "WithFlags")) {
3✔
517
                uint64_t raw_flags;
×
518

519
                r = sd_bus_message_read(message, "t", &raw_flags);
×
520
                if (r < 0)
×
521
                        return r;
×
522

523
                if ((raw_flags & ~_MACHINE_COPY_FLAGS_MASK_PUBLIC) != 0)
×
524
                        return -EINVAL;
525

526
                if (raw_flags & MACHINE_COPY_REPLACE)
×
527
                        copy_flags |= COPY_REPLACE;
×
528
        }
529

530
        if (!path_is_absolute(src))
3✔
531
                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute.");
×
532

533
        if (isempty(dest))
3✔
534
                dest = src;
×
535
        else if (!path_is_absolute(dest))
3✔
536
                return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute.");
×
537

538
        const char *details[] = {
3✔
539
                "machine", m->name,
3✔
540
                "verb", "copy",
541
                "src", src,
542
                "dest", dest,
543
                NULL
544
        };
545

546
        r = bus_verify_polkit_async(
3✔
547
                        message,
548
                        "org.freedesktop.machine1.manage-machines",
549
                        details,
550
                        &manager->polkit_registry,
551
                        error);
552
        if (r < 0)
3✔
553
                return r;
554
        if (r == 0)
3✔
555
                return 1; /* Will call us back */
556

557
        copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
3✔
558

559
        if (copy_from) {
3✔
560
                container_path = src;
1✔
561
                host_path = dest;
1✔
562
        } else {
563
                host_path = src;
2✔
564
                container_path = dest;
2✔
565
        }
566

567
        Operation *op;
3✔
568
        r = machine_copy_from_to_operation(manager, m, host_path, container_path, copy_from, copy_flags, &op);
3✔
569
        if (r < 0)
3✔
570
                return sd_bus_error_set_errnof(error, r, "Failed to copy from/to machine '%s': %m", m->name);
×
571

572
        operation_attach_bus_reply(op, message);
3✔
573
        return 1;
574
}
575

576
int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1✔
577
        _cleanup_close_ int fd = -EBADF;
1✔
578
        Machine *m = ASSERT_PTR(userdata);
1✔
579
        int r;
1✔
580

581
        assert(message);
1✔
582

583
        const char *details[] = {
1✔
584
                "machine", m->name,
1✔
585
                "verb", "open_root_directory",
586
                NULL
587
        };
588

589
        r = bus_verify_polkit_async(
2✔
590
                        message,
591
                        "org.freedesktop.machine1.manage-machines",
592
                        details,
593
                        &m->manager->polkit_registry,
1✔
594
                        error);
595
        if (r < 0)
1✔
596
                return r;
597
        if (r == 0)
1✔
598
                return 1; /* Will call us back */
599

600
        fd = machine_open_root_directory(m);
1✔
601
        if (ERRNO_IS_NEG_NOT_SUPPORTED(fd))
1✔
602
                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening the root directory is only supported on container machines.");
×
603
        if (fd < 0)
1✔
604
                return sd_bus_error_set_errnof(error, fd, "Failed to open root directory of machine '%s': %m", m->name);
×
605

606
        return sd_bus_reply_method_return(message, "h", fd);
1✔
607
}
608

609
int bus_machine_method_get_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error) {
24✔
610
        Machine *m = ASSERT_PTR(userdata);
24✔
611
        uid_t shift = 0;
24✔
612
        int r;
24✔
613

614
        assert(message);
24✔
615

616
        /* You wonder why this is a method and not a property? Well, properties are not supposed to return errors, but
617
         * we kinda have to for this. */
618

619
        if (m->class == MACHINE_HOST)
24✔
620
                return sd_bus_reply_method_return(message, "u", UINT32_C(0));
×
621

622
        if (m->class != MACHINE_CONTAINER)
24✔
623
                return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "UID/GID shift may only be determined for container machines.");
×
624

625
        r = machine_get_uid_shift(m, &shift);
24✔
626
        if (r == -ENXIO)
24✔
627
                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Machine %s uses a complex UID/GID mapping, cannot determine shift", m->name);
×
628
        if (r < 0)
24✔
629
                return r;
630

631
        return sd_bus_reply_method_return(message, "u", (uint32_t) shift);
24✔
632
}
633

634
static int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
31✔
635
        Manager *m = ASSERT_PTR(userdata);
31✔
636
        Machine *machine;
31✔
637
        int r;
31✔
638

639
        assert(bus);
31✔
640
        assert(path);
31✔
641
        assert(interface);
31✔
642
        assert(found);
31✔
643

644
        if (streq(path, "/org/freedesktop/machine1/machine/self")) {
31✔
645
                _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
×
646
                _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
×
647
                sd_bus_message *message;
×
648

649
                message = sd_bus_get_current_message(bus);
×
650
                if (!message)
×
651
                        return 0;
652

653
                r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID|SD_BUS_CREDS_PIDFD, &creds);
×
654
                if (r < 0)
×
655
                        return r;
656

657
                r = bus_creds_get_pidref(creds, &pidref);
×
658
                if (r < 0)
×
659
                        return r;
660

661
                r = manager_get_machine_by_pidref(m, &pidref, &machine);
×
662
                if (r <= 0)
×
663
                        return 0;
664
        } else {
665
                _cleanup_free_ char *e = NULL;
31✔
666
                const char *p;
31✔
667

668
                p = startswith(path, "/org/freedesktop/machine1/machine/");
31✔
669
                if (!p)
31✔
670
                        return 0;
671

672
                e = bus_label_unescape(p);
31✔
673
                if (!e)
31✔
674
                        return -ENOMEM;
675

676
                machine = hashmap_get(m->machines, e);
31✔
677
                if (!machine)
31✔
678
                        return 0;
679
        }
680

681
        *found = machine;
31✔
682
        return 1;
31✔
683
}
684

685
char* machine_bus_path(Machine *m) {
290✔
686
        _cleanup_free_ char *e = NULL;
290✔
687

688
        assert(m);
290✔
689

690
        e = bus_label_escape(m->name);
290✔
691
        if (!e)
290✔
692
                return NULL;
693

694
        return strjoin("/org/freedesktop/machine1/machine/", e);
290✔
695
}
696

697
static int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
×
698
        _cleanup_strv_free_ char **l = NULL;
×
699
        Machine *machine = NULL;
×
700
        Manager *m = userdata;
×
701
        int r;
×
702

703
        assert(bus);
×
704
        assert(path);
×
705
        assert(nodes);
×
706

707
        HASHMAP_FOREACH(machine, m->machines) {
×
708
                char *p;
×
709

710
                p = machine_bus_path(machine);
×
711
                if (!p)
×
712
                        return -ENOMEM;
×
713

714
                r = strv_consume(&l, p);
×
715
                if (r < 0)
×
716
                        return r;
717
        }
718

719
        *nodes = TAKE_PTR(l);
×
720

721
        return 1;
×
722
}
723

724
static const sd_bus_vtable machine_vtable[] = {
725
        SD_BUS_VTABLE_START(0),
726
        SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
727
        SD_BUS_PROPERTY("Id", "ay", bus_property_get_id128, offsetof(Machine, id), SD_BUS_VTABLE_PROPERTY_CONST),
728
        BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
729
        SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
730
        SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
731
        SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
732
        SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader.pid), SD_BUS_VTABLE_PROPERTY_CONST),
733
        SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
734
        SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
735
        SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
736
        SD_BUS_PROPERTY("VSockCID", "u", NULL, offsetof(Machine, vsock_cid), SD_BUS_VTABLE_PROPERTY_CONST),
737
        SD_BUS_PROPERTY("SSHAddress", "s", NULL, offsetof(Machine, ssh_address), SD_BUS_VTABLE_PROPERTY_CONST),
738
        SD_BUS_PROPERTY("SSHPrivateKeyPath", "s", NULL, offsetof(Machine, ssh_private_key_path), SD_BUS_VTABLE_PROPERTY_CONST),
739
        SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
740

741
        SD_BUS_METHOD("Terminate",
742
                      NULL,
743
                      NULL,
744
                      bus_machine_method_terminate,
745
                      SD_BUS_VTABLE_UNPRIVILEGED),
746
        SD_BUS_METHOD_WITH_ARGS("Kill",
747
                                SD_BUS_ARGS("s", whom, "i", signal),
748
                                SD_BUS_NO_RESULT,
749
                                bus_machine_method_kill,
750
                                SD_BUS_VTABLE_UNPRIVILEGED),
751
        SD_BUS_METHOD_WITH_ARGS("GetAddresses",
752
                                SD_BUS_NO_ARGS,
753
                                SD_BUS_RESULT("a(iay)", addresses),
754
                                bus_machine_method_get_addresses,
755
                                SD_BUS_VTABLE_UNPRIVILEGED),
756
        SD_BUS_METHOD_WITH_ARGS("GetSSHInfo",
757
                                SD_BUS_NO_ARGS,
758
                                SD_BUS_RESULT("s", ssh_address, "s", ssh_private_key_path),
759
                                bus_machine_method_get_ssh_info,
760
                                SD_BUS_VTABLE_UNPRIVILEGED),
761
        SD_BUS_METHOD_WITH_ARGS("GetOSRelease",
762
                                SD_BUS_NO_ARGS,
763
                                SD_BUS_RESULT("a{ss}", fields),
764
                                bus_machine_method_get_os_release,
765
                                SD_BUS_VTABLE_UNPRIVILEGED),
766
        SD_BUS_METHOD_WITH_ARGS("GetUIDShift",
767
                                SD_BUS_NO_ARGS,
768
                                SD_BUS_RESULT("u", shift),
769
                                bus_machine_method_get_uid_shift,
770
                                SD_BUS_VTABLE_UNPRIVILEGED),
771
        SD_BUS_METHOD_WITH_ARGS("OpenPTY",
772
                                SD_BUS_NO_ARGS,
773
                                SD_BUS_RESULT("h", pty, "s", pty_path),
774
                                bus_machine_method_open_pty,
775
                                SD_BUS_VTABLE_UNPRIVILEGED),
776
        SD_BUS_METHOD_WITH_ARGS("OpenLogin",
777
                                SD_BUS_NO_ARGS,
778
                                SD_BUS_RESULT("h", pty, "s", pty_path),
779
                                bus_machine_method_open_login,
780
                                SD_BUS_VTABLE_UNPRIVILEGED),
781
        SD_BUS_METHOD_WITH_ARGS("OpenShell",
782
                                SD_BUS_ARGS("s", user, "s", path, "as", args, "as", environment),
783
                                SD_BUS_RESULT("h", pty, "s", pty_path),
784
                                bus_machine_method_open_shell,
785
                                SD_BUS_VTABLE_UNPRIVILEGED),
786
        SD_BUS_METHOD_WITH_ARGS("BindMount",
787
                                SD_BUS_ARGS("s", source, "s", destination, "b", read_only, "b", mkdir),
788
                                SD_BUS_NO_RESULT,
789
                                bus_machine_method_bind_mount,
790
                                SD_BUS_VTABLE_UNPRIVILEGED),
791
        SD_BUS_METHOD_WITH_ARGS("CopyFrom",
792
                                SD_BUS_ARGS("s", source, "s", destination),
793
                                SD_BUS_NO_RESULT,
794
                                bus_machine_method_copy,
795
                                SD_BUS_VTABLE_UNPRIVILEGED),
796
        SD_BUS_METHOD_WITH_ARGS("CopyTo",
797
                                SD_BUS_ARGS("s", source, "s", destination),
798
                                SD_BUS_NO_RESULT,
799
                                bus_machine_method_copy,
800
                                SD_BUS_VTABLE_UNPRIVILEGED),
801
        SD_BUS_METHOD_WITH_ARGS("CopyFromWithFlags",
802
                                SD_BUS_ARGS("s", source, "s", destination, "t", flags),
803
                                SD_BUS_NO_RESULT,
804
                                bus_machine_method_copy,
805
                                SD_BUS_VTABLE_UNPRIVILEGED),
806
        SD_BUS_METHOD_WITH_ARGS("CopyToWithFlags",
807
                                SD_BUS_ARGS("s", source, "s", destination, "t", flags),
808
                                SD_BUS_NO_RESULT,
809
                                bus_machine_method_copy,
810
                                SD_BUS_VTABLE_UNPRIVILEGED),
811
        SD_BUS_METHOD_WITH_ARGS("OpenRootDirectory",
812
                                SD_BUS_NO_ARGS,
813
                                SD_BUS_RESULT("h", fd),
814
                                bus_machine_method_open_root_directory,
815
                                SD_BUS_VTABLE_UNPRIVILEGED),
816

817
        SD_BUS_VTABLE_END
818
};
819

820
const BusObjectImplementation machine_object = {
821
        "/org/freedesktop/machine1/machine",
822
        "org.freedesktop.machine1.Machine",
823
        .fallback_vtables = BUS_FALLBACK_VTABLES({machine_vtable, machine_object_find}),
824
        .node_enumerator = machine_node_enumerator,
825
};
826

827
int machine_send_signal(Machine *m, bool new_machine) {
170✔
828
        _cleanup_free_ char *p = NULL;
170✔
829

830
        assert(m);
170✔
831

832
        p = machine_bus_path(m);
170✔
833
        if (!p)
170✔
834
                return -ENOMEM;
835

836
        return sd_bus_emit_signal(
170✔
837
                        m->manager->bus,
170✔
838
                        "/org/freedesktop/machine1",
839
                        "org.freedesktop.machine1.Manager",
840
                        new_machine ? "MachineNew" : "MachineRemoved",
841
                        "so", m->name, p);
842
}
843

844
int machine_send_create_reply(Machine *m, sd_bus_error *error) {
68✔
845
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL;
68✔
846
        _cleanup_free_ char *p = NULL;
68✔
847

848
        assert(m);
68✔
849

850
        if (!m->create_message)
68✔
851
                return 0;
852

853
        c = TAKE_PTR(m->create_message);
66✔
854

855
        if (error)
66✔
856
                return sd_bus_reply_method_error(c, error);
×
857

858
        /* Update the machine state file before we notify the client
859
         * about the result. */
860
        machine_save(m);
66✔
861

862
        p = machine_bus_path(m);
66✔
863
        if (!p)
66✔
864
                return -ENOMEM;
865

866
        return sd_bus_reply_method_return(c, "o", p);
66✔
867
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc