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

systemd / systemd / 25026908423

27 Apr 2026 07:14PM UTC coverage: 71.865% (-0.3%) from 72.175%
25026908423

push

github

daandemeyer
udev: don't assert on worker cap after killing a broken idle worker

manager_can_process_event() considers an event processable if either
there is room below children_max to spawn, or an idle worker exists.
When only the latter holds, event_run() picks the idle worker and
tries device_monitor_send(). If that send fails, event_run() SIGKILLs
the worker, marks it WORKER_KILLED and continues the loop. With no
other idle worker available, it falls through to worker_spawn(),
guarded by:

    assert(hashmap_size(manager->workers) < manager->config.children_max);

The just-killed worker is still in manager->workers until its SIGCHLD
is reaped by on_worker_exit(), so at the cap this assertion trips and
udevd aborts:

    Assertion 'hashmap_size(manager->workers) < manager->config.children_max'
    failed at src/udev/udev-manager.c:635, function event_run(). Aborting.

Instead of asserting, bail out when we are already at the worker
limit. The event remains in EVENT_QUEUED; once the killed worker's
SIGCHLD arrives and frees it from the hashmap, on_post() re-runs
event_queue_start() and the event is retried.

1 of 1 new or added line in 1 file covered. (100.0%)

7309 existing lines in 125 files now uncovered.

322519 of 448782 relevant lines covered (71.87%)

1173939.78 hits per line

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

50.0
/src/ssh-generator/ssh-issue.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <sys/stat.h>
4
#include <unistd.h>
5

6
#include "alloc-util.h"
7
#include "ansi-color.h"
8
#include "build.h"
9
#include "fd-util.h"
10
#include "format-table.h"
11
#include "fs-util.h"
12
#include "log.h"
13
#include "main-func.h"
14
#include "mkdir.h"
15
#include "options.h"
16
#include "parse-argument.h"
17
#include "pretty-print.h"
18
#include "ssh-util.h"
19
#include "string-util.h"
20
#include "strv.h"
21
#include "tmpfile-util.h"
22
#include "verbs.h"
23
#include "virt.h"
24

25
static char *arg_issue_path = NULL;
26
static bool arg_issue_stdout = false;
27

28
STATIC_DESTRUCTOR_REGISTER(arg_issue_path, freep);
128✔
29

30
static int acquire_cid(unsigned *ret_cid) {
64✔
31
        int r;
64✔
32

33
        assert(ret_cid);
64✔
34

35
        Virtualization v = detect_virtualization();
64✔
36
        if (v < 0)
64✔
37
                return log_error_errno(v, "Failed to detect if we run in a VM: %m");
×
38
        if (!VIRTUALIZATION_IS_VM(v)) {
64✔
39
                /* NB: if we are running in a container inside a VM, then we'll *not* do AF_VSOCK stuff */
40
                log_debug("Not running in a VM, not creating issue file.");
×
41
                *ret_cid = 0;
×
42
                return 0;
×
43
        }
44

45
        r = vsock_open_or_warn(/* ret= */ NULL);
64✔
46
        if (r <= 0)
64✔
47
                return r;
48

49
        return vsock_get_local_cid_or_warn(ret_cid);
64✔
50
}
51

52
VERB_NOARG(verb_make_vsock, "make-vsock",
53
           "Generate the issue file");
54
static int verb_make_vsock(int argc, char *argv[], uintptr_t _data, void *_userdata) {
64✔
55
        unsigned cid;
64✔
56
        int r;
64✔
57

58
        r = acquire_cid(&cid);
64✔
59
        if (r < 0)
64✔
60
                return r;
64✔
61
        if (r == 0) {
64✔
62
                log_debug("Not running in a VSOCK enabled VM, skipping.");
×
63
                return 0;
×
64
        }
65

66
        _cleanup_(unlink_and_freep) char *t = NULL;
×
67
        _cleanup_(fclosep) FILE *f = NULL;
64✔
68
        FILE *out;
64✔
69

70
        if (arg_issue_path)  {
64✔
71
                r = mkdir_parents(arg_issue_path, 0755);
64✔
72
                if (r < 0)
64✔
73
                        return log_error_errno(r, "Failed to create parent directories of '%s': %m", arg_issue_path);
×
74

75
                r = fopen_tmpfile_linkable(arg_issue_path, O_WRONLY|O_CLOEXEC, &t, &f);
64✔
76
                if (r < 0)
64✔
77
                        return log_error_errno(r, "Failed to create '%s': %m", arg_issue_path);
×
78

79
                out = f;
64✔
80
        } else
81
                out = stdout;
×
82

83
        fprintf(out,
64✔
84
                "Try contacting this VM's SSH server via 'ssh vsock%%%u' from host.\n"
85
                "\n", cid);
86

87
        if (f) {
64✔
88
                if (fchmod(fileno(f), 0644) < 0)
64✔
89
                        return log_error_errno(errno, "Failed to adjust access mode of '%s': %m", arg_issue_path);
×
90

91
                r = flink_tmpfile(f, t, arg_issue_path, LINK_TMPFILE_REPLACE);
64✔
92
                if (r < 0)
64✔
93
                        return log_error_errno(r, "Failed to move '%s' into place: %m", arg_issue_path);
×
94
        }
95

96
        return 0;
97
}
98

99
VERB_NOARG(verb_rm_vsock, "rm-vsock",
100
           "Remove the issue file");
101
static int verb_rm_vsock(int argc, char *argv[], uintptr_t _data, void *_userdata) {
64✔
102
        if (arg_issue_path) {
64✔
103
                if (unlink(arg_issue_path) < 0) {
64✔
104
                        if (errno != ENOENT)
×
105
                                return log_error_errno(errno, "Failed to remove '%s': %m", arg_issue_path);
×
106

107
                        log_debug_errno(errno, "File '%s' does not exist, no operation executed.", arg_issue_path);
×
108
                } else
109
                        log_debug("Successfully removed '%s'.", arg_issue_path);
64✔
110
        } else
111
                log_notice("STDOUT selected for issue file, not removing.");
×
112

113
        return 0;
114
}
115

116
static int help(void) {
×
117
        _cleanup_free_ char *link = NULL;
×
118
        _cleanup_(table_unrefp) Table *options = NULL, *verbs = NULL;
×
119
        int r;
×
120

121
        r = terminal_urlify_man("systemd-ssh-issue", "1", &link);
×
122
        if (r < 0)
×
123
                return log_oom();
×
124

125
        r = verbs_get_help_table(&verbs);
×
126
        if (r < 0)
×
127
                return r;
128

129
        r = option_parser_get_help_table(&options);
×
130
        if (r < 0)
×
131
                return r;
132

133
        (void) table_sync_column_widths(0, verbs, options);
×
134

135
        printf("%s [OPTIONS...] COMMAND\n"
×
136
               "\n%sCreate/remove ssh /run/issue.d/ file reporting VSOCK address.%s\n"
137
               "\n%sCommands:%s\n",
138
               program_invocation_short_name,
139
               ansi_highlight(), ansi_normal(),
140
               ansi_underline(), ansi_normal());
141

142
        r = table_print_or_warn(verbs);
×
143
        if (r < 0)
×
144
                return r;
145

146
        printf("\n%sOptions:%s\n",
×
147
               ansi_underline(), ansi_normal());
148

149
        r = table_print_or_warn(options);
×
150
        if (r < 0)
×
151
                return r;
152

153
        printf("\nSee the %s for details.\n", link);
×
154
        return 0;
155
}
156

157
static int parse_argv(int argc, char *argv[], char ***ret_args) {
128✔
158
        assert(argc >= 0);
128✔
159
        assert(argv);
128✔
160
        assert(ret_args);
128✔
161

162
        OptionParser opts = { argc, argv };
128✔
163
        const char *verb = NULL;
128✔
164
        int r;
128✔
165

166
        FOREACH_OPTION(c, &opts, /* on_error= */ return c)
128✔
UNCOV
167
                switch (c) {
×
168

UNCOV
169
                OPTION_COMMON_HELP:
×
170
                        return help();
×
171

UNCOV
172
                OPTION_COMMON_VERSION:
×
173
                        return version();
×
174

UNCOV
175
                OPTION_LONG("make-vsock", NULL, /* help= */ NULL): {}
×
176
                OPTION_LONG("rm-vsock", NULL, /* help= */ NULL):
×
177
                        verb = opts.opt->long_code;
×
178
                        break;
×
179

UNCOV
180
                OPTION_LONG("issue-path", "PATH",
×
181
                            "Change path to /run/issue.d/50-ssh-vsock.issue"):
UNCOV
182
                        if (empty_or_dash(opts.arg)) {
×
183
                                arg_issue_path = mfree(arg_issue_path);
×
184
                                arg_issue_stdout = true;
×
185
                                break;
×
186
                        }
187

UNCOV
188
                        r = parse_path_argument(opts.arg, /* suppress_root= */ false, &arg_issue_path);
×
189
                        if (r < 0)
×
190
                                return r;
191

UNCOV
192
                        arg_issue_stdout = false;
×
193
                        break;
×
194
                }
195

196
        if (!arg_issue_path && !arg_issue_stdout) {
128✔
197
                arg_issue_path = strdup("/run/issue.d/50-ssh-vsock.issue");
128✔
198
                if (!arg_issue_path)
128✔
UNCOV
199
                        return log_oom();
×
200
        }
201

202
        char **args;
128✔
203
        if (verb) {
128✔
UNCOV
204
                if (option_parser_get_n_args(&opts) > 0)
×
205
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid use of compat option --make-vsock/--rm-vsock.");
×
206
                log_warning("Options --make-vsock/--rm-vsock have been replaced by make-vsock/rm-vsock verbs.");
×
207
                args = strv_new(verb);
×
208
        } else
209
                args = strv_copy(option_parser_get_args(&opts));
128✔
210
        if (!args)
128✔
UNCOV
211
                return log_oom();
×
212

213
        *ret_args = args;
128✔
214
        return 1;
128✔
215
}
216

217
static int run(int argc, char* argv[]) {
128✔
218
        _cleanup_strv_free_ char **args = NULL;
128✔
219
        int r;
128✔
220

221
        log_setup();
128✔
222

223
        r = parse_argv(argc, argv, &args);
128✔
224
        if (r <= 0)
128✔
225
                return r;
226

227
        return dispatch_verb_with_args(args, NULL);
128✔
228
}
229

230
DEFINE_MAIN_FUNCTION(run);
128✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc