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

systemd / systemd / 25084703852

28 Apr 2026 09:34PM UTC coverage: 71.849% (-0.02%) from 71.865%
25084703852

push

github

daandemeyer
ci: Reduce noise from claude-review workflow

322528 of 448894 relevant lines covered (71.85%)

1177215.84 hits per line

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

50.0
/src/shared/machine-register.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <unistd.h>
4

5
#include "sd-bus.h"
6
#include "sd-id128.h"
7
#include "sd-json.h"
8
#include "sd-varlink.h"
9

10
#include "bus-error.h"
11
#include "bus-locator.h"
12
#include "bus-util.h"
13
#include "errno-util.h"
14
#include "json-util.h"
15
#include "log.h"
16
#include "machine-register.h"
17
#include "path-lookup.h"
18
#include "pidref.h"
19
#include "runtime-scope.h"
20
#include "socket-util.h"
21
#include "string-util.h"
22
#include "terminal-util.h"
23

24
static int register_machine_dbus_ex(
×
25
                sd_bus *bus,
26
                const MachineRegistration *reg,
27
                sd_bus_error *error) {
28

29
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
×
30
        int r;
×
31

32
        assert(bus);
×
33
        assert(reg);
×
34
        assert(reg->name);
×
35
        assert(reg->service);
×
36
        assert(reg->class);
×
37
        assert(error);
×
38

39
        r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "RegisterMachineEx");
×
40
        if (r < 0)
×
41
                return bus_log_create_error(r);
×
42

43
        r = sd_bus_message_append(m, "s", reg->name);
×
44
        if (r < 0)
×
45
                return bus_log_create_error(r);
×
46

47
        r = sd_bus_message_open_container(m, 'a', "(sv)");
×
48
        if (r < 0)
×
49
                return bus_log_create_error(r);
×
50

51
        r = sd_bus_message_append(
×
52
                        m,
53
                        "(sv)(sv)(sv)",
54
                        "Id", "ay", SD_BUS_MESSAGE_APPEND_ID128(reg->id),
×
55
                        "Service", "s", reg->service,
×
56
                        "Class", "s", reg->class);
×
57
        if (r < 0)
×
58
                return bus_log_create_error(r);
×
59

60
        if (pidref_is_set(reg->pidref)) {
×
61
                if (reg->pidref->fd >= 0) {
×
62
                        r = sd_bus_message_append(m, "(sv)", "LeaderPIDFD", "h", reg->pidref->fd);
×
63
                        if (r < 0)
×
64
                                return bus_log_create_error(r);
×
65
                }
66

67
                if (reg->pidref->fd_id > 0) {
×
68
                        r = sd_bus_message_append(m, "(sv)", "LeaderPIDFDID", "t", reg->pidref->fd_id);
×
69
                        if (r < 0)
×
70
                                return bus_log_create_error(r);
×
71

72
                        r = sd_bus_message_append(m, "(sv)", "LeaderPID", "u", reg->pidref->pid);
×
73
                        if (r < 0)
×
74
                                return bus_log_create_error(r);
×
75
                }
76
        }
77

78
        if (!isempty(reg->root_directory)) {
×
79
                r = sd_bus_message_append(m, "(sv)", "RootDirectory", "s", reg->root_directory);
×
80
                if (r < 0)
×
81
                        return bus_log_create_error(r);
×
82
        }
83

84
        if (reg->local_ifindex > 0) {
×
85
                r = sd_bus_message_append(m, "(sv)", "NetworkInterfaces", "ai", 1, reg->local_ifindex);
×
86
                if (r < 0)
×
87
                        return bus_log_create_error(r);
×
88
        }
89

90
        r = sd_bus_message_close_container(m);
×
91
        if (r < 0)
×
92
                return bus_log_create_error(r);
×
93

94
        return sd_bus_call(bus, m, 0, error, NULL);
×
95
}
96

97
static int register_machine_dbus(
×
98
                sd_bus *bus,
99
                const MachineRegistration *reg) {
100

101
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
102
        int r;
×
103

104
        assert(bus);
×
105
        assert(reg);
×
106
        assert(reg->name);
×
107
        assert(reg->service);
×
108
        assert(reg->class);
×
109

110
        /* First try RegisterMachineEx which supports PIDFD-based leader tracking. */
111
        r = register_machine_dbus_ex(bus, reg, &error);
×
112
        if (r >= 0)
×
113
                return 0;
114
        if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
×
115
                return log_debug_errno(r, "Failed to register machine via D-Bus: %s", bus_error_message(&error, r));
×
116

117
        sd_bus_error_free(&error);
×
118

119
        r = bus_call_method(
×
120
                        bus,
121
                        bus_machine_mgr,
122
                        "RegisterMachineWithNetwork",
123
                        &error,
124
                        NULL,
125
                        "sayssusai",
126
                        reg->name,
×
127
                        SD_BUS_MESSAGE_APPEND_ID128(reg->id),
×
128
                        reg->service,
×
129
                        reg->class,
×
130
                        pidref_is_set(reg->pidref) ? (uint32_t) reg->pidref->pid : 0,
×
131
                        strempty(reg->root_directory),
×
132
                        reg->local_ifindex > 0 ? 1 : 0, reg->local_ifindex);
×
133
        if (r < 0)
×
134
                return log_debug_errno(r, "Failed to register machine via D-Bus: %s", bus_error_message(&error, r));
×
135

136
        return 0;
137
}
138

139
int register_machine(
55✔
140
                sd_bus *bus,
141
                const MachineRegistration *reg,
142
                RuntimeScope scope) {
143

144
        _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
55✔
145
        int r;
55✔
146

147
        assert(reg);
55✔
148
        assert(reg->name);
55✔
149
        assert(reg->service);
55✔
150
        assert(reg->class);
55✔
151

152
        /* First try to use varlink, as it provides more features (such as SSH support). */
153
        _cleanup_free_ char *p = NULL;
55✔
154
        r = runtime_directory_generic(scope, "systemd/machine/io.systemd.Machine", &p);
55✔
155
        if (r >= 0)
55✔
156
                r = sd_varlink_connect_address(&vl, p);
55✔
157
        if (r == -ENOENT || ERRNO_IS_DISCONNECT(r)) {
55✔
158
                log_debug_errno(r, "Failed to connect to machined via varlink%s%s, falling back to D-Bus: %m",
×
159
                                p ? " on " : "", strempty(p));
160

161
                /* In case we are running with an older machined, fall back to D-Bus. Note that the D-Bus
162
                 * methods do not support the allocateUnit feature — machined will look up the caller's
163
                 * existing cgroup unit instead of creating a dedicated scope. Callers that skip client-side
164
                 * scope allocation when allocate_unit is set should be aware that on the D-Bus path no scope
165
                 * will be created at all. */
166
                if (!bus)
×
167
                        return log_debug_errno(SYNTHETIC_ERRNO(ESRCH), "Varlink connection to machined not available and no bus provided.");
×
168

169
                return register_machine_dbus(bus, reg);
×
170
        }
171
        if (r < 0)
55✔
172
                return log_debug_errno(r, "Failed to connect to machined on %s: %m", strna(p));
×
173
        sd_json_variant *reply = NULL;
55✔
174
        const char *error_id = NULL;
55✔
175
        r = sd_varlink_callbo(
165✔
176
                        vl,
177
                        "io.systemd.Machine.Register",
178
                        &reply,
179
                        &error_id,
180
                        SD_JSON_BUILD_PAIR_STRING("name", reg->name),
181
                        SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(reg->id), "id", SD_JSON_BUILD_ID128(reg->id)),
182
                        SD_JSON_BUILD_PAIR_STRING("service", reg->service),
183
                        SD_JSON_BUILD_PAIR_STRING("class", reg->class),
184
                        SD_JSON_BUILD_PAIR_CONDITION(VSOCK_CID_IS_REGULAR(reg->vsock_cid), "vSockCid", SD_JSON_BUILD_UNSIGNED(reg->vsock_cid)),
185
                        SD_JSON_BUILD_PAIR_CONDITION(reg->local_ifindex > 0, "ifIndices", SD_JSON_BUILD_ARRAY(SD_JSON_BUILD_INTEGER(reg->local_ifindex))),
186
                        SD_JSON_BUILD_PAIR_CONDITION(!!reg->root_directory, "rootDirectory", SD_JSON_BUILD_STRING(reg->root_directory)),
187
                        SD_JSON_BUILD_PAIR_CONDITION(!!reg->ssh_address, "sshAddress", SD_JSON_BUILD_STRING(reg->ssh_address)),
188
                        SD_JSON_BUILD_PAIR_CONDITION(!!reg->ssh_private_key_path, "sshPrivateKeyPath", SD_JSON_BUILD_STRING(reg->ssh_private_key_path)),
189
                        SD_JSON_BUILD_PAIR_CONDITION(!!reg->control_address, "controlAddress", SD_JSON_BUILD_STRING(reg->control_address)),
190
                        SD_JSON_BUILD_PAIR_CONDITION(isatty_safe(STDIN_FILENO), "allowInteractiveAuthentication", SD_JSON_BUILD_BOOLEAN(true)),
191
                        SD_JSON_BUILD_PAIR_CONDITION(reg->allocate_unit, "allocateUnit", SD_JSON_BUILD_BOOLEAN(true)),
192
                        SD_JSON_BUILD_PAIR_CONDITION(pidref_is_set(reg->pidref), "leaderProcessId", JSON_BUILD_PIDREF(reg->pidref)));
193
        if (r < 0)
55✔
194
                return log_debug_errno(r, "Failed to register machine via varlink: %m");
×
195
        if (error_id)
55✔
196
                return log_debug_errno(sd_varlink_error_to_errno(error_id, reply),
×
197
                                       "Failed to register machine via varlink: %s", error_id);
198

199
        return 0;
200
}
201

202
static const char* machine_registration_scope_string(RuntimeScope scope, bool registered_system, bool registered_user) {
36✔
203
        if (scope == _RUNTIME_SCOPE_INVALID) {
36✔
204
                if (!registered_system && !registered_user)
3✔
205
                        return "system and user";
206
                if (!registered_system)
1✔
207
                        return "system";
208
                return "user";
1✔
209
        }
210

211
        return runtime_scope_to_string(scope);
33✔
212
}
213

214
int register_machine_with_fallback_and_log(
50✔
215
                MachineRegistrationContext *ctx,
216
                const MachineRegistration *reg,
217
                bool graceful) {
218

219
        int r = 0;
50✔
220

221
        assert(ctx);
50✔
222
        assert(IN_SET(ctx->scope, RUNTIME_SCOPE_SYSTEM, RUNTIME_SCOPE_USER, _RUNTIME_SCOPE_INVALID));
50✔
223
        assert(ctx->system_bus || !IN_SET(ctx->scope, RUNTIME_SCOPE_SYSTEM, _RUNTIME_SCOPE_INVALID));
50✔
224
        assert(ctx->user_bus || !IN_SET(ctx->scope, RUNTIME_SCOPE_USER, _RUNTIME_SCOPE_INVALID));
50✔
225
        assert(reg);
50✔
226
        assert(reg->name);
50✔
227
        assert(reg->service);
50✔
228
        assert(reg->class);
50✔
229

230
        if (IN_SET(ctx->scope, RUNTIME_SCOPE_SYSTEM, _RUNTIME_SCOPE_INVALID)) {
50✔
231
                MachineRegistration system_reg = *reg;
50✔
232
                if (ctx->scope != RUNTIME_SCOPE_SYSTEM)
50✔
233
                        system_reg.allocate_unit = false;
5✔
234

235
                int q = register_machine(ctx->system_bus, &system_reg, RUNTIME_SCOPE_SYSTEM);
50✔
236
                if (q < 0)
50✔
237
                        RET_GATHER(r, q);
238
                else
239
                        ctx->registered_system = true;
50✔
240
        }
241

242
        if (IN_SET(ctx->scope, RUNTIME_SCOPE_USER, _RUNTIME_SCOPE_INVALID)) {
50✔
243
                int q = register_machine(ctx->user_bus, reg, RUNTIME_SCOPE_USER);
5✔
244
                if (q < 0)
5✔
245
                        RET_GATHER(r, q);
×
246
                else
247
                        ctx->registered_user = true;
5✔
248
        }
249

250
        if (r < 0) {
50✔
251
                if (graceful) {
×
252
                        log_notice_errno(r, "Failed to register machine in %s context, ignoring: %m",
×
253
                                         machine_registration_scope_string(ctx->scope, ctx->registered_system, ctx->registered_user));
254
                        r = 0;
255
                } else
256
                        r = log_error_errno(r, "Failed to register machine in %s context: %m",
×
257
                                            machine_registration_scope_string(ctx->scope, ctx->registered_system, ctx->registered_user));
258
        }
259

260
        return r;
50✔
261
}
262

263
void unregister_machine_with_fallback_and_log(
183✔
264
                const MachineRegistrationContext *ctx,
265
                const char *machine_name) {
266

267
        int r = 0;
183✔
268
        bool failed_system = false, failed_user = false;
183✔
269

270
        assert(ctx);
183✔
271

272
        if (ctx->registered_system) {
183✔
273
                int q = unregister_machine(ctx->system_bus, machine_name, RUNTIME_SCOPE_SYSTEM);
47✔
274
                if (q < 0) {
47✔
275
                        RET_GATHER(r, q);
276
                        failed_system = true;
277
                }
278
        }
279

280
        if (ctx->registered_user) {
183✔
281
                int q = unregister_machine(ctx->user_bus, machine_name, RUNTIME_SCOPE_USER);
5✔
282
                if (q < 0) {
5✔
283
                        RET_GATHER(r, q);
3✔
284
                        failed_user = true;
285
                }
286
        }
287

288
        if (r < 0)
180✔
289
                log_notice_errno(r, "Failed to unregister machine in %s context, ignoring: %m",
36✔
290
                                 machine_registration_scope_string(
291
                                                 ctx->registered_system && ctx->registered_user ? _RUNTIME_SCOPE_INVALID :
292
                                                 ctx->registered_system ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
293
                                                 !failed_system, !failed_user));
294
}
183✔
295

296
int unregister_machine(sd_bus *bus, const char *machine_name, RuntimeScope scope) {
52✔
297
        int r;
52✔
298

299
        assert(machine_name);
52✔
300

301
        /* First try varlink */
302
        _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
52✔
303
        _cleanup_free_ char *p = NULL;
52✔
304
        r = runtime_directory_generic(scope, "systemd/machine/io.systemd.Machine", &p);
52✔
305
        if (r >= 0)
52✔
306
                r = sd_varlink_connect_address(&vl, p);
52✔
307
        if (r >= 0) {
52✔
308
                sd_json_variant *reply = NULL;
52✔
309
                const char *error_id = NULL;
52✔
310
                r = sd_varlink_callbo(
52✔
311
                                vl,
312
                                "io.systemd.Machine.Unregister",
313
                                &reply,
314
                                &error_id,
315
                                SD_JSON_BUILD_PAIR_STRING("name", machine_name));
316
                if (r >= 0 && !error_id)
52✔
317
                        return 0;
14✔
318
                if (r >= 0)
36✔
319
                        r = sd_varlink_error_to_errno(error_id, reply);
36✔
320
        }
321

322
        log_debug_errno(r, "Failed to unregister machine via varlink, falling back to D-Bus: %m");
38✔
323

324
        /* Fall back to D-Bus */
325
        if (!bus)
38✔
326
                return log_debug_errno(SYNTHETIC_ERRNO(ESRCH), "Varlink connection to machined not available and no bus provided.");
×
327

328
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
38✔
329
        r = bus_call_method(bus, bus_machine_mgr, "UnregisterMachine", &error, NULL, "s", machine_name);
38✔
330
        if (r < 0)
38✔
331
                return log_debug_errno(r, "Failed to unregister machine via D-Bus: %s", bus_error_message(&error, r));
38✔
332

333
        return 0;
334
}
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