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

systemd / systemd / 25409762285

05 May 2026 08:45PM UTC coverage: 72.658% (-0.02%) from 72.674%
25409762285

push

github

web-flow
Couple of coverity fixes (#41951)

0 of 11 new or added lines in 2 files covered. (0.0%)

2705 existing lines in 63 files now uncovered.

326249 of 449021 relevant lines covered (72.66%)

1212712.0 hits per line

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

89.52
/src/shared/verbs.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <getopt.h>
4

5
#include "env-util.h"
6
#include "format-table.h"
7
#include "log.h"
8
#include "string-util.h"
9
#include "strv.h"
10
#include "verbs.h"
11
#include "virt.h"
12

13
/* Wraps running_in_chroot() which is used in various places, but also adds an environment variable check
14
 * so external processes can reliably force this on. */
15
bool running_in_chroot_or_offline(void) {
12,821✔
16
        int r;
12,821✔
17

18
        /* Added to support use cases like rpm-ostree, where from %post scripts we only want to execute "preset",
19
         * but not "start"/"restart" for example.
20
         *
21
         * See docs/ENVIRONMENT.md for docs.
22
         */
23
        r = getenv_bool("SYSTEMD_OFFLINE");
12,821✔
24
        if (r >= 0)
12,821✔
25
                return r > 0;
×
26
        if (r != -ENXIO)
12,821✔
27
                log_debug_errno(r, "Failed to parse $SYSTEMD_OFFLINE, ignoring: %m");
×
28

29
        /* We've had this condition check for a long time which basically checks for legacy chroot case like Fedora's
30
         * "mock", which is used for package builds.  We don't want to try to start systemd services there, since
31
         * without --new-chroot we don't even have systemd running, and even if we did, adding a concept of background
32
         * daemons to builds would be an enormous change, requiring considering things like how the journal output is
33
         * handled, etc.  And there's really not a use case today for a build talking to a service.
34
         *
35
         * Note this call itself also looks for a different variable SYSTEMD_IGNORE_CHROOT=1.
36
         */
37
        r = running_in_chroot();
12,821✔
38
        if (r < 0)
12,821✔
39
                log_debug_errno(r, "Failed to check if we're running in chroot, assuming not: %m");
170✔
40
        return r > 0;
12,821✔
41
}
42

43
bool should_bypass(const char *env_prefix) {
828✔
44
        char *env;
828✔
45
        int r;
828✔
46

47
        assert(env_prefix);
828✔
48

49
        env = strjoina(env_prefix, "_BYPASS");
4,140✔
50

51
        r = getenv_bool(env);
828✔
52
        if (r < 0 && r != -ENXIO)
828✔
53
                log_debug_errno(r, "Failed to parse $%s, assuming no: %m", env);
×
54
        if (r <= 0)
828✔
55
                return false;
56

57
        log_debug("$%s is enabled, skipping execution.", env);
×
58
        return true;
59
}
60

61
static bool verb_is_metadata(const Verb *verb) {
723,759✔
62
        /* A metadata entry that is not a real verb, like the group marker */
63
        return FLAGS_SET(ASSERT_PTR(verb)->flags, VERB_GROUP_MARKER);
723,759✔
64
}
65

66
const Verb* verbs_find_verb(const char *name, const Verb verbs[], const Verb verbs_end[]) {
49,857✔
67
        assert(verbs);
49,857✔
68

69
        for (const Verb *verb = verbs; verb < verbs_end; verb++) {
723,615✔
70
                if (verb_is_metadata(verb))
723,596✔
71
                        continue;
9,411✔
72

73
                if (name ? streq(name, verb->verb) : FLAGS_SET(verb->flags, VERB_DEFAULT))
714,185✔
74
                        return verb;
75
        }
76

77
        /* At the end of the list? */
78
        return NULL;
79
}
80

81
int _dispatch_verb_with_args(char **args, const Verb verbs[], const Verb verbs_end[], void *userdata) {
39,115✔
82
        int r;
39,115✔
83

84
        assert(verbs);
39,115✔
85
        assert(verbs_end > verbs);
39,115✔
86
        assert(verbs[0].dispatch);
39,115✔
87
        assert(verbs[0].verb);
39,115✔
88

89
        const char *name = args ? args[0] : NULL;
39,115✔
90
        size_t left = strv_length(args);
39,115✔
91

92
        const Verb *verb = verbs_find_verb(name, verbs, verbs_end);
39,115✔
93
        if (!verb) {
39,115✔
94
                _cleanup_strv_free_ char **verb_strv = NULL;
19✔
95

96
                for (verb = verbs; verb < verbs_end; verb++) {
182✔
97
                        if (verb_is_metadata(verb))
163✔
98
                                continue;
12✔
99

100
                        r = strv_extend(&verb_strv, verb->verb);
151✔
101
                        if (r < 0)
151✔
102
                                return log_oom();
×
103
                }
104

105
                if (name) {
19✔
106
                        /* Be more helpful to the user, and give a hint what the user might have wanted to type. */
107
                        const char *found = strv_find_closest(verb_strv, name);
15✔
108
                        if (found)
15✔
109
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
9✔
110
                                                       "Unknown command verb '%s', did you mean '%s'?", name, found);
111

112
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown command verb '%s'.", name);
6✔
113
                }
114

115
                if (strv_length(verb_strv) >= 2) {
4✔
116
                        _cleanup_free_ char *joined = strv_join(verb_strv, ", ");
6✔
117
                        if (!joined)
3✔
118
                                return log_oom();
×
119

120
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
3✔
121
                                               "Command verb required (one of %s).", joined);
122
                }
123

124
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Command verb '%s' required.", verbs[0].verb);
1✔
125
        }
126

127
        if (!name)
39,096✔
128
                left = 1;
520✔
129

130
        if (verb->min_args != VERB_ANY && left < verb->min_args)
39,096✔
131
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too few arguments.");
10✔
132

133
        if (verb->max_args != VERB_ANY && left > verb->max_args)
39,086✔
134
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too many arguments.");
1✔
135

136
        if ((verb->flags & VERB_ONLINE_ONLY) && running_in_chroot_or_offline()) {
39,085✔
137
                log_info("Running in chroot, ignoring command '%s'", name ?: verb->verb);
×
138
                return 0;
139
        }
140

141
        if (!name)
39,085✔
142
                return verb->dispatch(1, STRV_MAKE(verb->verb), verb->data, userdata);
520✔
143

144
        assert(left < INT_MAX);  /* args are derived from argc+argv, so their size must fit in an int. */
38,565✔
145
        return verb->dispatch(left, args, verb->data, userdata);
38,565✔
146
}
147

148
int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) {
17,298✔
149
        /* getopt wrapper for _dispatch_verb_with_args.
150
         * TBD: remove this function when all programs with verbs have been converted. */
151

152
        assert(argc >= 0);
17,298✔
153
        assert(argv);
17,298✔
154
        assert(argc >= optind);
17,298✔
155

156
        size_t n = 0;
157
        while (verbs[n].verb)
1,001,321✔
158
                n++;
984,023✔
159

160
        return _dispatch_verb_with_args(strv_skip(argv, optind), verbs, verbs + n, userdata);
17,298✔
161
}
162

163
int _verbs_get_help_table(
28✔
164
                const Verb verbs[],
165
                const Verb verbs_end[],
166
                const char *group,
167
                Table **ret) {
168
        int r;
28✔
169

170
        assert(ret);
28✔
171

172
        _cleanup_(table_unrefp) Table *table = table_new("verb", "help");
56✔
173
        if (!table)
28✔
174
                return log_oom();
×
175

176
        bool in_group = group == NULL;  /* Are we currently in the section on the array that forms
28✔
177
                                         * group <group>? The first part is the default group, so
178
                                         * if the group was not specified, we are in. */
179

180
        for (const Verb *verb = verbs; verb < verbs_end; verb++) {
361✔
181
                assert(verb->verb);
346✔
182

183
                bool group_marker = FLAGS_SET(verb->flags, VERB_GROUP_MARKER);
346✔
184
                if (!in_group) {
346✔
185
                        in_group = group_marker && streq(group, verb->verb);
179✔
186
                        continue;
190✔
187
                }
188
                if (group_marker)
167✔
189
                        break;  /* End of group */
190

191
                if (!verb->help)
154✔
192
                        /* No help string — we do not show the verb */
193
                        continue;
11✔
194

195
                bool is_default = FLAGS_SET(verb->flags, VERB_DEFAULT);
143✔
196

197
                /* We indent the option string by two spaces. We could set the minimum cell width and
198
                 * right-align for a similar result, but that'd be more work. This is only used for
199
                 * display. */
200
                r = table_add_cell_stringf(table, NULL, "  %s%s%s%s%s",
394✔
201
                                           is_default ? "[" : "",
202
                                           verb->verb,
203
                                           is_default ? "]" : "",
204
                                           verb->argspec ? " " : "",
205
                                           strempty(verb->argspec));
206
                if (r < 0)
143✔
207
                        return table_log_add_error(r);
×
208

209
                _cleanup_strv_free_ char **s = strv_split(verb->help, /* separators= */ NULL);
286✔
210
                if (!s)
143✔
211
                        return log_oom();
×
212

213
                r = table_add_many(table, TABLE_STRV_WRAPPED, s);
143✔
214
                if (r < 0)
143✔
UNCOV
215
                        return table_log_add_error(r);
×
216
        }
217

218
        table_set_header(table, false);
28✔
219
        *ret = TAKE_PTR(table);
28✔
220
        return 0;
28✔
221
}
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