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

systemd / systemd / 16280725298

14 Jul 2025 08:16PM UTC coverage: 72.166% (-0.006%) from 72.172%
16280725298

push

github

web-flow
Two fixlets for coverage test (#38183)

302135 of 418667 relevant lines covered (72.17%)

773261.64 hits per line

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

72.66
/src/systemctl/systemctl-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <fnmatch.h>
4
#include <unistd.h>
5

6
#include "sd-bus.h"
7
#include "sd-daemon.h"
8

9
#include "ask-password-agent.h"
10
#include "bus-common-errors.h"
11
#include "bus-locator.h"
12
#include "bus-map-properties.h"
13
#include "bus-unit-util.h"
14
#include "bus-util.h"
15
#include "chase.h"
16
#include "dropin.h"
17
#include "env-util.h"
18
#include "exit-status.h"
19
#include "format-table.h"
20
#include "format-util.h"
21
#include "glob-util.h"
22
#include "install.h"
23
#include "output-mode.h"
24
#include "path-lookup.h"
25
#include "path-util.h"
26
#include "pidref.h"
27
#include "polkit-agent.h"
28
#include "process-util.h"
29
#include "reboot-util.h"
30
#include "runtime-scope.h"
31
#include "set.h"
32
#include "string-util.h"
33
#include "strv.h"
34
#include "systemctl.h"
35
#include "systemctl-util.h"
36
#include "unit-file.h"
37
#include "unit-name.h"
38
#include "verbs.h"
39

40
static sd_bus *buses[_BUS_FOCUS_MAX] = {};
41

42
int acquire_bus_full(BusFocus focus, bool graceful, sd_bus **ret) {
12,328✔
43
        int r;
12,328✔
44

45
        assert(focus < _BUS_FOCUS_MAX);
12,328✔
46
        assert(ret);
12,328✔
47

48
        if (!IN_SET(arg_runtime_scope, RUNTIME_SCOPE_SYSTEM, RUNTIME_SCOPE_USER))
12,328✔
49
                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--global is not supported for this operation.");
×
50

51
        /* We only go directly to the manager, if we are using a local transport */
52
        if (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_CAPSULE))
12,328✔
53
                focus = BUS_FULL;
20✔
54

55
        if (getenv_bool("SYSTEMCTL_FORCE_BUS") > 0)
12,328✔
56
                focus = BUS_FULL;
×
57

58
        if (!buses[focus]) {
12,328✔
59
                if (focus == BUS_MANAGER)
12,238✔
60
                        r = bus_connect_transport_systemd(arg_transport, arg_host, arg_runtime_scope, &buses[focus]);
12,120✔
61
                else
62
                        r = bus_connect_transport(arg_transport, arg_host, arg_runtime_scope, &buses[focus]);
118✔
63
                if (r < 0)
12,238✔
64
                        return bus_log_connect_full(graceful && focus == BUS_FULL && r == -ECONNREFUSED ? LOG_DEBUG : LOG_ERR,
×
65
                                                    r, arg_transport, arg_runtime_scope);
66

67
                (void) sd_bus_set_allow_interactive_authorization(buses[focus], arg_ask_password);
12,238✔
68
        }
69

70
        *ret = buses[focus];
12,328✔
71
        return 0;
12,328✔
72
}
73

74
void release_busses(void) {
12,297✔
75
        FOREACH_ARRAY(w, buses, _BUS_FOCUS_MAX)
36,891✔
76
                *w = sd_bus_flush_close_unref(*w);
24,594✔
77
}
12,297✔
78

79
void ask_password_agent_open_maybe(void) {
2,003✔
80
        /* Open the password agent as a child process if necessary */
81

82
        if (arg_dry_run)
2,003✔
83
                return;
84

85
        if (arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)
1,999✔
86
                return;
87

88
        ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
1,989✔
89
}
90

91
void polkit_agent_open_maybe(void) {
2,832✔
92
        /* Open the polkit agent as a child process if necessary */
93

94
        if (arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)
2,832✔
95
                return;
96

97
        (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
2,638✔
98
}
99

100
int translate_bus_error_to_exit_status(int r, const sd_bus_error *error) {
66✔
101
        assert(error);
66✔
102

103
        if (!sd_bus_error_is_set(error))
66✔
104
                return r;
105

106
        if (sd_bus_error_has_names(error, SD_BUS_ERROR_ACCESS_DENIED,
66✔
107
                                          BUS_ERROR_ONLY_BY_DEPENDENCY,
108
                                          BUS_ERROR_NO_ISOLATION,
109
                                          BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
110
                return EXIT_NOPERMISSION;
111

112
        if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
65✔
113
                return EXIT_NOTINSTALLED;
114

115
        if (sd_bus_error_has_names(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE,
30✔
116
                                          SD_BUS_ERROR_NOT_SUPPORTED))
117
                return EXIT_NOTIMPLEMENTED;
118

119
        if (sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
30✔
120
                return EXIT_NOTCONFIGURED;
121

122
        if (r != 0)
30✔
123
                return r;
30✔
124

125
        return EXIT_FAILURE;
126
}
127

128
int get_state_one_unit(sd_bus *bus, const char *unit, UnitActiveState *ret_active_state) {
3,850✔
129
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
130
        _cleanup_free_ char *buf = NULL, *dbus_path = NULL;
3,850✔
131
        UnitActiveState state;
3,850✔
132
        int r;
3,850✔
133

134
        assert(bus);
3,850✔
135
        assert(unit);
3,850✔
136
        assert(ret_active_state);
3,850✔
137

138
        dbus_path = unit_dbus_path_from_name(unit);
3,850✔
139
        if (!dbus_path)
3,850✔
140
                return log_oom();
×
141

142
        r = sd_bus_get_property_string(
3,850✔
143
                        bus,
144
                        "org.freedesktop.systemd1",
145
                        dbus_path,
146
                        "org.freedesktop.systemd1.Unit",
147
                        "ActiveState",
148
                        &error,
149
                        &buf);
150
        if (r < 0)
3,850✔
151
                return log_error_errno(r, "Failed to retrieve unit state: %s", bus_error_message(&error, r));
×
152

153
        state = unit_active_state_from_string(buf);
3,850✔
154
        if (state < 0)
3,850✔
155
                return log_error_errno(state, "Invalid unit state '%s' for: %s", buf, unit);
×
156

157
        *ret_active_state = state;
3,850✔
158
        return 0;
3,850✔
159
}
160

161
int get_sub_state_one_unit(sd_bus *bus, const char *unit, char **ret_sub_state) {
169✔
162
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
163
        _cleanup_free_ char *sub_state = NULL, *dbus_path = NULL;
169✔
164
        int r;
169✔
165

166
        assert(bus);
169✔
167
        assert(unit);
169✔
168
        assert(ret_sub_state);
169✔
169

170
        dbus_path = unit_dbus_path_from_name(unit);
169✔
171
        if (!dbus_path)
169✔
172
                return log_oom();
×
173

174
        r = sd_bus_get_property_string(
169✔
175
                        bus,
176
                        "org.freedesktop.systemd1",
177
                        dbus_path,
178
                        "org.freedesktop.systemd1.Unit",
179
                        "SubState",
180
                        &error,
181
                        &sub_state);
182
        if (r < 0)
169✔
183
                return log_error_errno(r, "Failed to retrieve unit sub state: %s", bus_error_message(&error, r));
×
184

185
        *ret_sub_state = TAKE_PTR(sub_state);
169✔
186
        return 0;
169✔
187
}
188

189
int get_unit_list(
105✔
190
                sd_bus *bus,
191
                const char *machine,
192
                char **patterns,
193
                UnitInfo **unit_infos,
194
                int c,
195
                sd_bus_message **ret_reply) {
196

197
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
105✔
198
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
199
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
105✔
200
        int r;
105✔
201
        bool fallback = false;
105✔
202

203
        assert(bus);
105✔
204
        assert(unit_infos);
105✔
205
        assert(ret_reply);
105✔
206

207
        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitsByPatterns");
105✔
208
        if (r < 0)
105✔
209
                return bus_log_create_error(r);
×
210

211
        r = sd_bus_message_append_strv(m, arg_states);
105✔
212
        if (r < 0)
105✔
213
                return bus_log_create_error(r);
×
214

215
        r = sd_bus_message_append_strv(m, patterns);
105✔
216
        if (r < 0)
105✔
217
                return bus_log_create_error(r);
×
218

219
        r = sd_bus_call(bus, m, 0, &error, &reply);
105✔
220
        if (r < 0 && (sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_METHOD,
105✔
221
                                                     SD_BUS_ERROR_ACCESS_DENIED))) {
222
                /* Fallback to legacy ListUnitsFiltered method */
223
                fallback = true;
×
224
                log_debug_errno(r, "Failed to list units: %s Falling back to ListUnitsFiltered method.", bus_error_message(&error, r));
×
225
                m = sd_bus_message_unref(m);
×
226
                sd_bus_error_free(&error);
×
227

228
                r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitsFiltered");
×
229
                if (r < 0)
×
230
                        return bus_log_create_error(r);
×
231

232
                r = sd_bus_message_append_strv(m, arg_states);
×
233
                if (r < 0)
×
234
                        return bus_log_create_error(r);
×
235

236
                r = sd_bus_call(bus, m, 0, &error, &reply);
×
237
        }
238
        if (r < 0)
×
239
                return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
×
240

241
        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
105✔
242
        if (r < 0)
105✔
243
                return bus_log_parse_error(r);
×
244

245
        for (;;) {
8,718✔
246
                UnitInfo u;
8,718✔
247

248
                r = bus_parse_unit_info(reply, &u);
8,718✔
249
                if (r < 0)
8,718✔
250
                        return bus_log_parse_error(r);
×
251
                if (r == 0)
8,718✔
252
                        break;
253

254
                u.machine = machine;
8,613✔
255

256
                if (!output_show_unit(&u, fallback ? patterns : NULL))
17,226✔
257
                        continue;
1,550✔
258

259
                if (!GREEDY_REALLOC(*unit_infos, c+1))
7,063✔
260
                        return log_oom();
×
261

262
                (*unit_infos)[c++] = u;
7,063✔
263
        }
264

265
        r = sd_bus_message_exit_container(reply);
105✔
266
        if (r < 0)
105✔
267
                return bus_log_parse_error(r);
×
268

269
        *ret_reply = TAKE_PTR(reply);
105✔
270
        return c;
105✔
271
}
272

273
int expand_unit_names(
10,956✔
274
                sd_bus *bus,
275
                char * const *names,
276
                const char *suffix,
277
                char ***ret,
278
                bool *ret_expanded) {
279

280
        _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
10,956✔
281
        int r;
10,956✔
282

283
        assert(bus);
10,956✔
284
        assert(ret);
10,956✔
285

286
        STRV_FOREACH(name, names) {
21,993✔
287
                UnitNameMangle options = UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN);
11,037✔
288
                char *t;
11,037✔
289

290
                r = unit_name_mangle_with_suffix(*name, NULL, options, suffix ?: ".service", &t);
22,072✔
291
                if (r < 0)
11,037✔
292
                        return log_error_errno(r, "Failed to mangle name: %m");
×
293

294
                if (string_is_glob(t))
11,037✔
295
                        r = strv_consume(&globs, t);
29✔
296
                else
297
                        r = strv_consume(&mangled, t);
11,008✔
298
                if (r < 0)
11,037✔
299
                        return log_oom();
×
300
        }
301

302
        /* Query the manager only if any of the names are a glob, since this is fairly expensive */
303
        bool expanded = !strv_isempty(globs);
10,956✔
304
        if (expanded) {
29✔
305
                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
29✔
306
                _cleanup_free_ UnitInfo *unit_infos = NULL;
29✔
307

308
                r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
29✔
309
                if (r < 0)
29✔
310
                        return r;
311

312
                FOREACH_ARRAY(info, unit_infos, r)
142✔
313
                        if (strv_extend(&mangled, info->id) < 0)
113✔
314
                                return log_oom();
×
315
        }
316

317
        *ret = TAKE_PTR(mangled);
10,956✔
318
        if (ret_expanded)
10,956✔
319
                *ret_expanded = expanded;
1,998✔
320

321
        return 0;
322
}
323

324
int get_active_triggering_units(sd_bus *bus, const char *unit, bool ignore_masked, char ***ret) {
1,040✔
325
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1,040✔
326
        _cleanup_strv_free_ char **triggered_by = NULL, **active = NULL;
1,040✔
327
        _cleanup_free_ char *name = NULL, *dbus_path = NULL;
1,040✔
328
        int r;
1,040✔
329

330
        assert(bus);
1,040✔
331
        assert(unit);
1,040✔
332
        assert(ret);
1,040✔
333

334
        r = unit_name_mangle(unit, 0, &name);
1,040✔
335
        if (r < 0)
1,040✔
336
                return r;
337

338
        if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE))
1,040✔
339
                goto skip;
1✔
340

341
        if (ignore_masked) {
1,039✔
342
                r = unit_is_masked(bus, name);
1,032✔
343
                if (r < 0)
1,032✔
344
                        return r;
345
                if (r > 0)
1,032✔
346
                        goto skip;
2✔
347
        }
348

349
        dbus_path = unit_dbus_path_from_name(name);
1,037✔
350
        if (!dbus_path)
1,037✔
351
                return -ENOMEM;
352

353
        r = sd_bus_get_property_strv(
1,037✔
354
                        bus,
355
                        "org.freedesktop.systemd1",
356
                        dbus_path,
357
                        "org.freedesktop.systemd1.Unit",
358
                        "TriggeredBy",
359
                        &error,
360
                        &triggered_by);
361
        if (r < 0)
1,037✔
362
                return log_debug_errno(r, "Failed to get TriggeredBy property of unit '%s': %s",
×
363
                                       name, bus_error_message(&error, r));
364

365
        STRV_FOREACH(i, triggered_by) {
1,771✔
366
                UnitActiveState active_state;
734✔
367

368
                r = get_state_one_unit(bus, *i, &active_state);
734✔
369
                if (r < 0)
734✔
370
                        return r;
×
371

372
                if (!IN_SET(active_state, UNIT_ACTIVE, UNIT_RELOADING, UNIT_REFRESHING))
734✔
373
                        continue;
337✔
374

375
                r = strv_extend(&active, *i);
397✔
376
                if (r < 0)
397✔
377
                        return r;
378
        }
379

380
        *ret = TAKE_PTR(active);
1,037✔
381
        return 0;
1,037✔
382

383
skip:
3✔
384
        *ret = NULL;
3✔
385
        return 0;
3✔
386
}
387

388
void warn_triggering_units(sd_bus *bus, const char *unit, const char *operation, bool ignore_masked) {
1,040✔
389
        _cleanup_strv_free_ char **triggered_by = NULL;
×
390
        _cleanup_free_ char *joined = NULL;
1,040✔
391
        int r;
1,040✔
392

393
        assert(bus);
1,040✔
394
        assert(unit);
1,040✔
395
        assert(operation);
1,040✔
396

397
        r = get_active_triggering_units(bus, unit, ignore_masked, &triggered_by);
1,040✔
398
        if (r < 0) {
1,040✔
399
                if (r != -ENOENT) /* A linked unit might have disappeared after disabling */
×
400
                        log_warning_errno(r, "Failed to get triggering units for '%s', ignoring: %m", unit);
×
401
                return;
×
402
        }
403

404
        if (strv_isempty(triggered_by))
1,040✔
405
                return;
406

407
        joined = strv_join(triggered_by, ", ");
366✔
408
        if (!joined)
366✔
409
                return (void) log_oom();
×
410

411
        log_warning("%s '%s', but its triggering units are still active:\n"
366✔
412
                    "%s",
413
                    operation, unit, joined);
414
}
415

416
int need_daemon_reload(sd_bus *bus, const char *unit) {
2,105✔
417
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
2,105✔
418
        const char *path;
2,105✔
419
        int b, r;
2,105✔
420

421
        /* We ignore all errors here, since this is used to show a
422
         * warning only */
423

424
        /* We don't use unit_dbus_path_from_name() directly since we
425
         * don't want to load the unit if it isn't loaded. */
426

427
        r = bus_call_method(bus, bus_systemd_mgr, "GetUnit", NULL, &reply, "s", unit);
2,105✔
428
        if (r < 0)
2,105✔
429
                return r;
430

431
        r = sd_bus_message_read(reply, "o", &path);
1,991✔
432
        if (r < 0)
1,991✔
433
                return r;
434

435
        r = sd_bus_get_property_trivial(
1,991✔
436
                        bus,
437
                        "org.freedesktop.systemd1",
438
                        path,
439
                        "org.freedesktop.systemd1.Unit",
440
                        "NeedDaemonReload",
441
                        NULL,
442
                        'b', &b);
443
        if (r < 0)
1,991✔
444
                return r;
445

446
        return b;
1,991✔
447
}
448

449
void warn_unit_file_changed(const char *unit) {
1✔
450
        assert(unit);
1✔
451

452
        if (arg_no_warn)
1✔
453
                return;
454

455
        log_warning("Warning: The unit file, source configuration file or drop-ins of %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.",
1✔
456
                    unit,
457
                    arg_runtime_scope == RUNTIME_SCOPE_SYSTEM ? "" : " --user");
458
}
459

460
int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **ret_unit_path) {
×
461
        assert(lp);
×
462
        assert(unit_name);
×
463

464
        STRV_FOREACH(p, lp->search_path) {
×
465
                _cleanup_free_ char *path = NULL, *lpath = NULL;
×
466
                int r;
×
467

468
                path = path_join(*p, unit_name);
×
469
                if (!path)
×
470
                        return log_oom();
×
471

472
                r = chase(path, arg_root, 0, &lpath, NULL);
×
473
                if (r == -ENOENT)
×
474
                        continue;
×
475
                if (r == -ENOMEM)
×
476
                        return log_oom();
×
477
                if (r < 0)
×
478
                        return log_error_errno(r, "Failed to access path \"%s\": %m", path);
×
479

480
                if (ret_unit_path)
×
481
                        *ret_unit_path = TAKE_PTR(lpath);
×
482

483
                return 1;
484
        }
485

486
        if (ret_unit_path)
×
487
                *ret_unit_path = NULL;
×
488

489
        return 0;
490
}
491

492
int unit_find_paths(
137✔
493
                sd_bus *bus,
494
                const char *unit_name,
495
                LookupPaths *lp,
496
                bool force_client_side,
497
                Hashmap **cached_id_map,
498
                Hashmap **cached_name_map,
499
                char **ret_fragment_path,
500
                char ***ret_dropin_paths) {
501

502
        _cleanup_strv_free_ char **dropins = NULL;
×
503
        _cleanup_free_ char *path = NULL;
137✔
504
        int r;
137✔
505

506
        /**
507
         * Finds where the unit is defined on disk. Returns 0 if the unit is not found. Returns 1 if it is
508
         * found, and sets:
509
         *
510
         * - the path to the unit in *ret_frament_path, if it exists on disk,
511
         *
512
         * - and a strv of existing drop-ins in *ret_dropin_paths, if the arg is not NULL and any dropins
513
         *   were found.
514
         *
515
         * Returns -ERFKILL if the unit is masked, and -EKEYREJECTED if the unit file could not be loaded for
516
         * some reason (the latter only applies if we are going through the service manager). As special
517
         * exception it won't log for these two error cases.
518
         */
519

520
        assert(unit_name);
137✔
521
        assert(ret_fragment_path);
137✔
522
        assert(lp);
137✔
523

524
        /* Go via the bus to acquire the path, unless we are explicitly told not to, or when the unit name is a template */
525
        if (!force_client_side &&
274✔
526
            !install_client_side() &&
274✔
527
            !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
263✔
528
                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
529
                _cleanup_free_ char *load_state = NULL, *dbus_path = NULL;
132✔
530

531
                dbus_path = unit_dbus_path_from_name(unit_name);
132✔
532
                if (!dbus_path)
132✔
533
                        return log_oom();
×
534

535
                r = sd_bus_get_property_string(
132✔
536
                                bus,
537
                                "org.freedesktop.systemd1",
538
                                dbus_path,
539
                                "org.freedesktop.systemd1.Unit",
540
                                "LoadState",
541
                                &error,
542
                                &load_state);
543
                if (r < 0)
132✔
544
                        return log_error_errno(r, "Failed to get LoadState: %s", bus_error_message(&error, r));
×
545

546
                if (streq(load_state, "masked"))
132✔
547
                        return -ERFKILL; /* special case: no logging */
548
                if (streq(load_state, "not-found")) {
132✔
549
                        r = 0;
6✔
550
                        goto finish;
6✔
551
                }
552
                if (!STR_IN_SET(load_state, "loaded", "bad-setting"))
126✔
553
                        return -EKEYREJECTED; /* special case: no logging */
×
554

555
                r = sd_bus_get_property_string(
126✔
556
                                bus,
557
                                "org.freedesktop.systemd1",
558
                                dbus_path,
559
                                "org.freedesktop.systemd1.Unit",
560
                                "FragmentPath",
561
                                &error,
562
                                &path);
563
                if (r < 0)
126✔
564
                        return log_error_errno(r, "Failed to get FragmentPath: %s", bus_error_message(&error, r));
×
565

566
                if (ret_dropin_paths) {
126✔
567
                        r = sd_bus_get_property_strv(
126✔
568
                                        bus,
569
                                        "org.freedesktop.systemd1",
570
                                        dbus_path,
571
                                        "org.freedesktop.systemd1.Unit",
572
                                        "DropInPaths",
573
                                        &error,
574
                                        &dropins);
575
                        if (r < 0)
126✔
576
                                return log_error_errno(r, "Failed to get DropInPaths: %s", bus_error_message(&error, r));
×
577
                }
578
        } else {
579
                if (!*cached_name_map) {
5✔
580
                        r = unit_file_build_name_map(lp, NULL, cached_id_map, cached_name_map, NULL);
5✔
581
                        if (r < 0)
5✔
582
                                return r;
×
583
                }
584

585
                const char *_path;
5✔
586
                _cleanup_set_free_ Set *names = NULL;
5✔
587
                r = unit_file_find_fragment(*cached_id_map, *cached_name_map, unit_name, &_path, &names);
5✔
588
                if (r < 0)
5✔
589
                        return log_error_errno(r, "Failed to find fragment for '%s': %m", unit_name);
×
590

591
                if (_path) {
5✔
592
                        path = strdup(_path);
2✔
593
                        if (!path)
2✔
594
                                return log_oom();
×
595
                }
596

597
                if (ret_dropin_paths) {
5✔
598
                        r = unit_file_find_dropin_paths(arg_root, lp->search_path, NULL,
5✔
599
                                                        ".d", ".conf",
600
                                                        NULL, names, &dropins);
601
                        if (r < 0)
5✔
602
                                return r;
603
                }
604
        }
605

606
 finish:
137✔
607
        if (isempty(path)) {
137✔
608
                *ret_fragment_path = NULL;
10✔
609
                r = 0;
10✔
610
        } else {
611
                *ret_fragment_path = TAKE_PTR(path);
127✔
612
                r = 1;
127✔
613
        }
614

615
        if (ret_dropin_paths) {
137✔
616
                if (!strv_isempty(dropins)) {
137✔
617
                        *ret_dropin_paths = TAKE_PTR(dropins);
121✔
618
                        r = 1;
121✔
619
                } else
620
                        *ret_dropin_paths = NULL;
16✔
621
        }
622

623
        if (r == 0 && !arg_force)
137✔
624
                log_error("No files found for %s.", unit_name);
5✔
625

626
        return r;
627
}
628

629
static int unit_find_template_path(
×
630
                const char *unit_name,
631
                LookupPaths *lp,
632
                char **ret_fragment_path,
633
                char **ret_template) {
634

635
        _cleanup_free_ char *t = NULL, *f = NULL;
×
636
        int r;
×
637

638
        /* Returns 1 if a fragment was found, 0 if not found, negative on error. */
639

640
        r = unit_file_find_path(lp, unit_name, &f);
×
641
        if (r < 0)
×
642
                return r;
643
        if (r > 0) {
×
644
                if (ret_fragment_path)
×
645
                        *ret_fragment_path = TAKE_PTR(f);
×
646
                if (ret_template)
×
647
                        *ret_template = NULL;
×
648
                return r; /* found a real unit */
×
649
        }
650

651
        r = unit_name_template(unit_name, &t);
×
652
        if (r == -EINVAL) {
×
653
                if (ret_fragment_path)
×
654
                        *ret_fragment_path = NULL;
×
655
                if (ret_template)
×
656
                        *ret_template = NULL;
×
657

658
                return 0; /* not a template, does not exist */
×
659
        }
660
        if (r < 0)
×
661
                return log_error_errno(r, "Failed to determine template name: %m");
×
662

663
        r = unit_file_find_path(lp, t, ret_fragment_path);
×
664
        if (r < 0)
×
665
                return r;
666

667
        if (ret_template)
×
668
                *ret_template = r > 0 ? TAKE_PTR(t) : NULL;
×
669

670
        return r;
671
}
672

673
int unit_is_masked(sd_bus *bus, const char *unit) {
1,048✔
674
        _cleanup_free_ char *load_state = NULL;
1,048✔
675
        int r;
1,048✔
676

677
        assert(bus);
1,048✔
678
        assert(unit);
1,048✔
679

680
        if (unit_name_is_valid(unit, UNIT_NAME_TEMPLATE)) {
1,048✔
681
                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
682
                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
3✔
683
                const char *state;
3✔
684

685
                r = bus_call_method(bus, bus_systemd_mgr, "GetUnitFileState", &error, &reply, "s", unit);
3✔
686
                if (r < 0)
3✔
687
                        return log_debug_errno(r, "Failed to get UnitFileState for '%s': %s",
1✔
688
                                               unit, bus_error_message(&error, r));
689

690
                r = sd_bus_message_read(reply, "s", &state);
2✔
691
                if (r < 0)
2✔
692
                        return bus_log_parse_error_debug(r);
×
693

694
                return STR_IN_SET(state, "masked", "masked-runtime");
2✔
695
        }
696

697
        r = unit_load_state(bus, unit, &load_state);
1,045✔
698
        if (r < 0)
1,045✔
699
                return r;
700

701
        return streq(load_state, "masked");
1,045✔
702
}
703

704
int unit_exists(LookupPaths *lp, const char *unit) {
16✔
705
        typedef struct UnitStateInfo {
16✔
706
                const char *load_state;
707
                const char *active_state;
708
        } UnitStateInfo;
709

710
        static const struct bus_properties_map property_map[] = {
16✔
711
                { "LoadState",   "s", NULL, offsetof(UnitStateInfo, load_state)   },
712
                { "ActiveState", "s", NULL, offsetof(UnitStateInfo, active_state) },
713
                {},
714
        };
715

716
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
717
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
16✔
718
        _cleanup_free_ char *path = NULL;
16✔
719
        UnitStateInfo info = {};
16✔
720
        sd_bus *bus;
16✔
721
        int r;
16✔
722

723
        if (unit_name_is_valid(unit, UNIT_NAME_TEMPLATE))
16✔
724
                return unit_find_template_path(unit, lp, NULL, NULL);
×
725

726
        path = unit_dbus_path_from_name(unit);
16✔
727
        if (!path)
16✔
728
                return log_oom();
×
729

730
        r = acquire_bus(BUS_MANAGER, &bus);
16✔
731
        if (r < 0)
16✔
732
                return r;
733

734
        r = bus_map_all_properties(bus, "org.freedesktop.systemd1", path, property_map, 0, &error, &m, &info);
16✔
735
        if (r < 0)
16✔
736
                return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
×
737

738
        return !streq_ptr(info.load_state, "not-found") || !streq_ptr(info.active_state, "inactive");
16✔
739
}
740

741
int append_unit_dependencies(sd_bus *bus, char **names, char ***ret) {
3✔
742
        _cleanup_strv_free_ char **with_deps = NULL;
3✔
743

744
        assert(bus);
3✔
745
        assert(ret);
3✔
746

747
        STRV_FOREACH(name, names) {
6✔
748
                char **deps;
3✔
749

750
                if (strv_extend(&with_deps, *name) < 0)
3✔
751
                        return log_oom();
×
752

753
                (void) unit_get_dependencies(bus, *name, &deps);
3✔
754

755
                if (strv_extend_strv_consume(&with_deps, deps, /* filter_duplicates = */ true) < 0)
3✔
756
                        return log_oom();
×
757
        }
758

759
        *ret = TAKE_PTR(with_deps);
3✔
760

761
        return 0;
3✔
762
}
763

764
int maybe_extend_with_unit_dependencies(sd_bus *bus, char ***list) {
6,268✔
765
        _cleanup_strv_free_ char **list_with_deps = NULL;
6,268✔
766
        int r;
6,268✔
767

768
        assert(bus);
6,268✔
769
        assert(list);
6,268✔
770

771
        if (!arg_with_dependencies)
6,268✔
772
                return 0;
773

774
        r = append_unit_dependencies(bus, *list, &list_with_deps);
×
775
        if (r < 0)
×
776
                return log_error_errno(r, "Failed to append unit dependencies: %m");
×
777

778
        return strv_free_and_replace(*list, list_with_deps);
×
779
}
780

781
int unit_get_dependencies(sd_bus *bus, const char *name, char ***ret) {
66✔
782
        _cleanup_strv_free_ char **deps = NULL;
66✔
783

784
        static const struct bus_properties_map map[_DEPENDENCY_MAX][7] = {
66✔
785
                [DEPENDENCY_FORWARD] = {
786
                        { "Requires",    "as", NULL, 0 },
787
                        { "Requisite",   "as", NULL, 0 },
788
                        { "Wants",       "as", NULL, 0 },
789
                        { "ConsistsOf",  "as", NULL, 0 },
790
                        { "BindsTo",     "as", NULL, 0 },
791
                        { "Upholds",     "as", NULL, 0 },
792
                        {}
793
                },
794
                [DEPENDENCY_REVERSE] = {
795
                        { "RequiredBy",  "as", NULL, 0 },
796
                        { "RequisiteOf", "as", NULL, 0 },
797
                        { "WantedBy",    "as", NULL, 0 },
798
                        { "PartOf",      "as", NULL, 0 },
799
                        { "BoundBy",     "as", NULL, 0 },
800
                        { "UpheldBy",    "as", NULL, 0 },
801
                        {}
802
                },
803
                [DEPENDENCY_AFTER] = {
804
                        { "After",       "as", NULL, 0 },
805
                        {}
806
                },
807
                [DEPENDENCY_BEFORE] = {
808
                        { "Before",      "as", NULL, 0 },
809
                        {}
810
                },
811
        };
812

813
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
814
        _cleanup_free_ char *dbus_path = NULL;
66✔
815
        int r;
66✔
816

817
        assert(bus);
66✔
818
        assert(name);
66✔
819
        assert(ret);
66✔
820

821
        dbus_path = unit_dbus_path_from_name(name);
66✔
822
        if (!dbus_path)
66✔
823
                return log_oom();
×
824

825
        r = bus_map_all_properties(bus,
132✔
826
                                   "org.freedesktop.systemd1",
827
                                   dbus_path,
828
                                   map[arg_dependency],
66✔
829
                                   BUS_MAP_STRDUP,
830
                                   &error,
831
                                   NULL,
832
                                   &deps);
833
        if (r < 0)
66✔
834
                return log_error_errno(r, "Failed to get properties of %s: %s", name, bus_error_message(&error, r));
×
835

836
        strv_uniq(deps); /* Sometimes a unit might have multiple deps on the other unit,
66✔
837
                          * but we still want to show it just once. */
838
        *ret = TAKE_PTR(deps);
66✔
839

840
        return 0;
66✔
841
}
842

843
const char* unit_type_suffix(const char *unit) {
19,883✔
844
        const char *dot;
19,883✔
845

846
        dot = strrchr(unit, '.');
19,883✔
847
        if (!dot)
19,883✔
848
                return "";
849

850
        return dot + 1;
19,883✔
851
}
852

853
bool output_show_unit(const UnitInfo *u, char **patterns) {
8,613✔
854
        assert(u);
8,613✔
855

856
        if (!strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE))
8,613✔
857
                return false;
858

859
        if (arg_types && !strv_contains(arg_types, unit_type_suffix(u->id)))
8,613✔
860
                return false;
861

862
        if (arg_all)
7,759✔
863
                return true;
864

865
        /* Note that '--all' is not purely a state filter, but also a filter that hides units that "follow"
866
         * other units (which is used for device units that appear under different names). */
867
        if (!isempty(u->following))
1,864✔
868
                return false;
869

870
        if (!strv_isempty(arg_states))
1,864✔
871
                return true;
872

873
        /* By default show all units except the ones in inactive state and with no pending job */
874
        if (u->job_id > 0)
1,459✔
875
                return true;
876

877
        if (streq(u->active_state, "inactive"))
1,447✔
878
                return false;
696✔
879

880
        return true;
881
}
882

883
bool install_client_side(void) {
691✔
884
        /* Decides when to execute enable/disable/... operations client-side rather than server-side. */
885

886
        if (running_in_chroot_or_offline())
691✔
887
                return true;
888

889
        if (sd_booted() <= 0)
691✔
890
                return true;
891

892
        if (!isempty(arg_root))
691✔
893
                return true;
894

895
        if (arg_runtime_scope == RUNTIME_SCOPE_GLOBAL)
648✔
896
                return true;
897

898
        /* Unsupported environment variable, mostly for debugging purposes */
899
        if (getenv_bool("SYSTEMCTL_INSTALL_CLIENT_SIDE") > 0)
648✔
900
                return true;
×
901

902
        return false;
903
}
904

905
int output_table(Table *table) {
104✔
906
        int r;
104✔
907

908
        assert(table);
104✔
909

910
        if (OUTPUT_MODE_IS_JSON(arg_output))
104✔
911
                r = table_print_json(table, NULL, output_mode_to_json_format_flags(arg_output) | SD_JSON_FORMAT_COLOR_AUTO);
×
912
        else
913
                r = table_print(table, NULL);
104✔
914
        if (r < 0)
104✔
915
                return table_log_print_error(r);
×
916

917
        return 0;
918
}
919

920
bool show_preset_for_state(UnitFileState state) {
1,488✔
921
        /* Don't show preset state in those unit file states, it'll only confuse users. */
922
        return !IN_SET(state,
1,488✔
923
                       UNIT_FILE_ALIAS,
924
                       UNIT_FILE_STATIC,
925
                       UNIT_FILE_GENERATED,
926
                       UNIT_FILE_TRANSIENT);
927
}
928

929
UnitFileFlags unit_file_flags_from_args(void) {
17✔
930
        return (arg_runtime ? UNIT_FILE_RUNTIME : 0) |
34✔
931
               (arg_force   ? UNIT_FILE_FORCE   : 0);
17✔
932
}
933

934
int mangle_names(const char *operation, char * const *original_names, char ***ret) {
488✔
935
        _cleanup_strv_free_ char **l = NULL;
488✔
936
        int r;
488✔
937

938
        assert(operation);
488✔
939
        assert(ret);
488✔
940

941
        STRV_FOREACH(name, original_names) {
977✔
942
                char *mangled;
489✔
943

944
                if (is_path(*name))
489✔
945
                        /* When enabling units qualified path names are OK, too, hence allow them explicitly. */
946
                        r = path_make_absolute_cwd(*name, &mangled);
×
947
                else
948
                        r = unit_name_mangle_with_suffix(*name, operation,
489✔
949
                                                         arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
489✔
950
                                                         ".service", &mangled);
951
                if (r < 0)
489✔
952
                        return log_error_errno(r, "Failed to mangle unit name or path '%s': %m", *name);
×
953

954
                if (strv_consume(&l, mangled) < 0)
489✔
955
                        return log_oom();
×
956
        }
957

958
        *ret = TAKE_PTR(l);
488✔
959

960
        return 0;
488✔
961
}
962

963
int halt_now(enum action a) {
3✔
964
        /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need
965
         * to be synced explicitly in advance. */
966
        if (!arg_no_sync && !arg_dry_run)
3✔
967
                sync();
×
968

969
        /* Make sure C-A-D is handled by the kernel from this point on... */
970
        if (!arg_dry_run)
3✔
971
                (void) reboot(RB_ENABLE_CAD);
×
972

973
        switch (a) {
3✔
974

975
        case ACTION_HALT:
1✔
976
                if (!arg_quiet)
1✔
977
                        log_info("Halting.");
1✔
978
                if (arg_dry_run)
1✔
979
                        return 0;
980
                (void) reboot(RB_HALT_SYSTEM);
×
981
                return -errno;
×
982

983
        case ACTION_POWEROFF:
1✔
984
                if (!arg_quiet)
1✔
985
                        log_info("Powering off.");
1✔
986
                if (arg_dry_run)
1✔
987
                        return 0;
988
                (void) reboot(RB_POWER_OFF);
×
989
                return -errno;
×
990

991
        case ACTION_KEXEC:
1✔
992
        case ACTION_REBOOT:
993
                return reboot_with_parameter(REBOOT_FALLBACK |
1✔
994
                                             (arg_quiet ? 0 : REBOOT_LOG) |
1✔
995
                                             (arg_dry_run ? REBOOT_DRY_RUN : 0));
1✔
996

997
        default:
×
998
                assert_not_reached();
×
999
        }
1000
}
1001

1002
int get_unit_by_pid(sd_bus *bus, pid_t pid, char **ret_unit, char **ret_path) {
1✔
1003
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
1004
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1✔
1005
        int r;
1✔
1006

1007
        assert(bus);
1✔
1008
        assert(pid >= 0); /* 0 is accepted by GetUnitByPID for querying our own process. */
1✔
1009

1010
        r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPID", &error, &reply, "u", (uint32_t) pid);
1✔
1011
        if (r < 0) {
1✔
1012
                if (sd_bus_error_has_name(&error, BUS_ERROR_NO_UNIT_FOR_PID))
×
1013
                        return log_error_errno(r, "%s", bus_error_message(&error, r));
×
1014

1015
                return log_error_errno(r,
×
1016
                                       "Failed to get unit that PID " PID_FMT " belongs to: %s",
1017
                                       pid > 0 ? pid : getpid_cached(),
1018
                                       bus_error_message(&error, r));
1019
        }
1020

1021
        _cleanup_free_ char *u = NULL, *p = NULL;
1✔
1022
        const char *path;
1✔
1023

1024
        r = sd_bus_message_read_basic(reply, 'o', &path);
1✔
1025
        if (r < 0)
1✔
1026
                return bus_log_parse_error(r);
×
1027

1028
        if (ret_unit) {
1✔
1029
                r = unit_name_from_dbus_path(path, &u);
1✔
1030
                if (r < 0)
1✔
1031
                        return log_error_errno(r,
×
1032
                                               "Failed to extract unit name from D-Bus object path '%s': %m",
1033
                                               path);
1034
        }
1035

1036
        if (ret_path) {
1✔
1037
                p = strdup(path);
×
1038
                if (!p)
×
1039
                        return log_oom();
×
1040
        }
1041

1042
        if (ret_unit)
1✔
1043
                *ret_unit = TAKE_PTR(u);
1✔
1044
        if (ret_path)
1✔
1045
                *ret_path = TAKE_PTR(p);
×
1046

1047
        return 0;
1048
}
1049

1050
static int get_unit_by_pidfd(sd_bus *bus, const PidRef *pid, char **ret_unit, char **ret_path) {
5✔
1051
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
1052
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
5✔
1053
        int r;
5✔
1054

1055
        assert(bus);
5✔
1056
        assert(pidref_is_set(pid));
5✔
1057

1058
        if (pid->fd < 0)
5✔
1059
                return -EOPNOTSUPP;
1060

1061
        r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPIDFD", &error, &reply, "h", pid->fd);
5✔
1062
        if (r < 0) {
5✔
1063
                if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
×
1064
                        return -EOPNOTSUPP;
1065

1066
                if (sd_bus_error_has_names(&error, BUS_ERROR_NO_UNIT_FOR_PID, BUS_ERROR_NO_SUCH_PROCESS))
×
1067
                        return log_error_errno(r, "%s", bus_error_message(&error, r));
×
1068

1069
                return log_error_errno(r,
×
1070
                                       "Failed to get unit that PID " PID_FMT " belongs to: %s",
1071
                                       pid->pid, bus_error_message(&error, r));
1072
        }
1073

1074
        _cleanup_free_ char *u = NULL, *p = NULL;
5✔
1075
        const char *path, *unit;
5✔
1076

1077
        r = sd_bus_message_read(reply, "os", &path, &unit);
5✔
1078
        if (r < 0)
5✔
1079
                return bus_log_parse_error(r);
×
1080

1081
        if (ret_unit) {
5✔
1082
                u = strdup(unit);
5✔
1083
                if (!u)
5✔
1084
                        return log_oom();
×
1085
        }
1086

1087
        if (ret_path) {
5✔
1088
                p = strdup(path);
1✔
1089
                if (!p)
1✔
1090
                        return log_oom();
×
1091
        }
1092

1093
        if (ret_unit)
5✔
1094
                *ret_unit = TAKE_PTR(u);
5✔
1095
        if (ret_path)
5✔
1096
                *ret_path = TAKE_PTR(p);
1✔
1097

1098
        return 0;
1099
}
1100

1101
int lookup_unit_by_pidref(sd_bus *bus, pid_t pid, char **ret_unit, char **ret_path) {
5✔
1102
        int r;
5✔
1103

1104
        assert(bus);
5✔
1105
        assert(pid >= 0); /* 0 means our own process */
5✔
1106

1107
        if (arg_transport != BUS_TRANSPORT_LOCAL)
5✔
1108
                return get_unit_by_pid(bus, pid, ret_unit, ret_path);
5✔
1109

1110
        static bool use_pidfd = true;
5✔
1111
        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
5✔
1112

1113
        r = pidref_set_pid(&pidref, pid);
5✔
1114
        if (r < 0)
5✔
1115
                return log_error_errno(r,
×
1116
                                       r == -ESRCH ?
1117
                                       "PID " PID_FMT " doesn't exist or is already gone." :
1118
                                       "Failed to create reference to PID " PID_FMT ": %m",
1119
                                       pid);
1120

1121
        if (use_pidfd) {
5✔
1122
                r = get_unit_by_pidfd(bus, &pidref, ret_unit, ret_path);
5✔
1123
                if (r != -EOPNOTSUPP)
5✔
1124
                        return r;
1125

1126
                use_pidfd = false;
×
1127
                log_debug_errno(r, "Unable to look up process using pidfd, falling back to pid.");
×
1128
        }
1129

1130
        _cleanup_free_ char *u = NULL, *p = NULL;
×
1131

1132
        r = get_unit_by_pid(bus, pidref.pid, ret_unit ? &u : NULL, ret_path ? &p : NULL);
×
1133
        if (r < 0)
×
1134
                return r;
1135

1136
        r = pidref_verify(&pidref);
×
1137
        if (r < 0)
×
1138
                return log_error_errno(r, "Failed to verify our reference to PID " PID_FMT ": %m", pidref.pid);
×
1139

1140
        if (ret_unit)
×
1141
                *ret_unit = TAKE_PTR(u);
×
1142
        if (ret_path)
×
1143
                *ret_path = TAKE_PTR(p);
×
1144

1145
        return 0;
1146
}
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