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

systemd / systemd / 21419361949

27 Jan 2026 02:53PM UTC coverage: 72.793% (-0.03%) from 72.821%
21419361949

push

github

keszybz
kernel-install: handle removal unsuccessful UKIs and loader entries separately

When a tries file exists, 90-uki-copy.install removes a previous UKI of the
same kernel version and all it's unbooted variants. This removal is guarded
behind a check for the existence of the already booted UKI, i.e. if uki.efi
already exists, uki.efi and uki+*.efi will be removed.

This leaves the edge case that if uki.efi does not exist, but only an unbooted,
e.g. uki+3.efi, it will not be removed. This is not a problem, if the number of
tries is constant between both builds, since a new uki+3.efi would overwrite
the existing one, but if the number of tries is changed to, e.g. uki+5.efi, we
are left with both uki+3.efi and uki+5.efi.

The same is done for loader entries.

311334 of 427698 relevant lines covered (72.79%)

1157141.18 hits per line

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

45.95
/src/shared/boot-entry.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include "alloc-util.h"
4
#include "boot-entry.h"
5
#include "chase.h"
6
#include "fd-util.h"
7
#include "fileio.h"
8
#include "log.h"
9
#include "os-util.h"
10
#include "path-util.h"
11
#include "string-table.h"
12
#include "string-util.h"
13
#include "strv.h"
14
#include "utf8.h"
15

16
bool boot_entry_token_valid(const char *p) {
185✔
17
        return utf8_is_valid(p) && string_is_safe(p) && filename_is_valid(p);
185✔
18
}
19

20
static int entry_token_load_one(int rfd, const char *dir, BootEntryTokenType *type, char **token) {
189✔
21
        _cleanup_free_ char *buf = NULL, *p = NULL;
189✔
22
        _cleanup_fclose_ FILE *f = NULL;
189✔
23
        int r;
189✔
24

25
        assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
189✔
26
        assert(dir);
189✔
27
        assert(type);
189✔
28
        assert(*type == BOOT_ENTRY_TOKEN_AUTO);
189✔
29
        assert(token);
189✔
30

31
        p = path_join(dir, "entry-token");
189✔
32
        if (!p)
189✔
33
                return log_oom();
×
34

35
        r = chase_and_fopenat_unlocked(rfd, p, CHASE_AT_RESOLVE_IN_ROOT, "re", NULL, &f);
189✔
36
        if (r == -ENOENT)
189✔
37
                return 0;
38
        if (r < 0)
185✔
39
                return log_error_errno(r, "Failed to chase and open '%s': %m", p);
×
40

41
        r = read_line(f, NAME_MAX, &buf);
185✔
42
        if (r < 0)
185✔
43
                return log_error_errno(r, "Failed to read %s: %m", p);
×
44

45
        if (isempty(buf))
374✔
46
                return 0;
47

48
        if (!boot_entry_token_valid(buf)) {
185✔
49
                log_debug("Invalid entry token specified in %s, ignoring.", p);
×
50
                return 0;
×
51
        }
52

53
        *token = TAKE_PTR(buf);
185✔
54
        *type = BOOT_ENTRY_TOKEN_LITERAL;
185✔
55
        return 1;
185✔
56
}
57

58
static int entry_token_load(int rfd, const char *conf_root, BootEntryTokenType *type, char **token) {
187✔
59
        int r;
187✔
60

61
        assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
187✔
62
        assert(type);
187✔
63
        assert(*type == BOOT_ENTRY_TOKEN_AUTO);
187✔
64
        assert(token);
187✔
65

66
        if (conf_root)
187✔
67
                return entry_token_load_one(rfd, conf_root, type, token);
×
68

69
        FOREACH_STRING(path, "/etc/kernel", "/usr/lib/kernel") {
191✔
70
                r = entry_token_load_one(rfd, path, type, token);
189✔
71
                if (r != 0)
189✔
72
                        return r;
185✔
73
        }
74

75
        return 0;
2✔
76
}
77

78
static int entry_token_from_machine_id(sd_id128_t machine_id, BootEntryTokenType *type, char **token) {
2✔
79
        char *p;
2✔
80

81
        assert(type);
2✔
82
        assert(IN_SET(*type, BOOT_ENTRY_TOKEN_AUTO, BOOT_ENTRY_TOKEN_MACHINE_ID));
2✔
83
        assert(token);
2✔
84

85
        if (sd_id128_is_null(machine_id))
2✔
86
                return 0;
×
87

88
        p = strdup(SD_ID128_TO_STRING(machine_id));
2✔
89
        if (!p)
2✔
90
                return log_oom();
×
91

92
        *token = p;
2✔
93
        *type = BOOT_ENTRY_TOKEN_MACHINE_ID;
2✔
94
        return 1;
2✔
95
}
96

97
static int entry_token_from_os_release(int rfd, BootEntryTokenType *type, char **token) {
×
98
        _cleanup_free_ char *id = NULL, *image_id = NULL;
×
99
        int r;
×
100

101
        assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
×
102
        assert(type);
×
103
        assert(IN_SET(*type, BOOT_ENTRY_TOKEN_AUTO, BOOT_ENTRY_TOKEN_OS_IMAGE_ID, BOOT_ENTRY_TOKEN_OS_ID));
×
104
        assert(token);
×
105

106
        switch (*type) {
×
107
        case BOOT_ENTRY_TOKEN_AUTO:
×
108
                r = parse_os_release_at(rfd,
×
109
                                        "IMAGE_ID", &image_id,
110
                                        "ID",       &id);
111
                break;
112

113
        case BOOT_ENTRY_TOKEN_OS_IMAGE_ID:
×
114
                r = parse_os_release_at(rfd, "IMAGE_ID", &image_id);
×
115
                break;
116

117
        case BOOT_ENTRY_TOKEN_OS_ID:
×
118
                r = parse_os_release_at(rfd, "ID", &id);
×
119
                break;
120

121
        default:
×
122
                assert_not_reached();
×
123
        }
124
        if (r == -ENOENT)
×
125
                return 0;
126
        if (r < 0)
×
127
                return log_error_errno(r, "Failed to load /etc/os-release: %m");
×
128

129
        if (!isempty(image_id) && boot_entry_token_valid(image_id)) {
×
130
                *token = TAKE_PTR(image_id);
×
131
                *type = BOOT_ENTRY_TOKEN_OS_IMAGE_ID;
×
132
                return 1;
×
133
        }
134

135
        if (!isempty(id) && boot_entry_token_valid(id)) {
×
136
                *token = TAKE_PTR(id);
×
137
                *type = BOOT_ENTRY_TOKEN_OS_ID;
×
138
                return 1;
×
139
        }
140

141
        return 0;
142
}
143

144
int boot_entry_token_ensure_at(
187✔
145
                int rfd,
146
                const char *conf_root,
147
                sd_id128_t machine_id,
148
                bool machine_id_is_random,
149
                BootEntryTokenType *type,
150
                char **token) {
151

152
        int r;
187✔
153

154
        assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
187✔
155
        assert(type);
187✔
156
        assert(token);
187✔
157

158
        if (*token)
187✔
159
                return 0; /* Already set. */
160

161
        switch (*type) {
187✔
162

163
        case BOOT_ENTRY_TOKEN_AUTO:
187✔
164
                r = entry_token_load(rfd, conf_root, type, token);
187✔
165
                if (r != 0)
187✔
166
                        return r;
167

168
                if (!machine_id_is_random) {
2✔
169
                        r = entry_token_from_machine_id(machine_id, type, token);
2✔
170
                        if (r != 0)
2✔
171
                                return r;
172
                }
173

174
                r = entry_token_from_os_release(rfd, type, token);
×
175
                if (r != 0)
×
176
                        return r;
177

178
                if (machine_id_is_random) {
×
179
                        r = entry_token_from_machine_id(machine_id, type, token);
×
180
                        if (r != 0)
×
181
                                return r;
182
                }
183

184
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
185
                                       "No machine ID set, and /etc/os-release carries no ID=/IMAGE_ID= fields.");
186

187
        case BOOT_ENTRY_TOKEN_MACHINE_ID:
×
188
                r = entry_token_from_machine_id(machine_id, type, token);
×
189
                if (r != 0)
×
190
                        return r;
191

192
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No machine ID set.");
×
193

194
        case BOOT_ENTRY_TOKEN_OS_IMAGE_ID:
×
195
                r = entry_token_from_os_release(rfd, type, token);
×
196
                if (r != 0)
×
197
                        return r;
198

199
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
200
                                       "IMAGE_ID= field not set in /etc/os-release.");
201

202
        case BOOT_ENTRY_TOKEN_OS_ID:
×
203
                r = entry_token_from_os_release(rfd, type, token);
×
204
                if (r != 0)
×
205
                        return r;
206

207
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
208
                                       "ID= field not set in /etc/os-release.");
209

210
        case BOOT_ENTRY_TOKEN_LITERAL:
211
                /* In this case, the token should be already set by the user input. */
212
                return -EINVAL;
213

214
        default:
×
215
                assert_not_reached();
×
216
        }
217
}
218

219
int boot_entry_token_ensure(
187✔
220
                const char *root,
221
                const char *conf_root,
222
                sd_id128_t machine_id,
223
                bool machine_id_is_random,
224
                BootEntryTokenType *type,
225
                char **token) {
226

227
        assert(token);
187✔
228

229
        if (*token)
187✔
230
                return 0; /* Already set. */
187✔
231

232
        _cleanup_close_ int rfd = XAT_FDROOT;
187✔
233
        if (!empty_or_root(root)) {
187✔
234
                rfd = open(root, O_CLOEXEC | O_DIRECTORY | O_PATH);
26✔
235
                if (rfd < 0)
26✔
236
                        return -errno;
×
237
        }
238

239
        return boot_entry_token_ensure_at(rfd, conf_root, machine_id, machine_id_is_random, type, token);
187✔
240
}
241

242
int parse_boot_entry_token_type(const char *s, BootEntryTokenType *type, char **token) {
×
243
        assert(s);
×
244
        assert(type);
×
245
        assert(token);
×
246

247
        /*
248
         * This function is intended to be used in command line parsers, to handle token that are passed in.
249
         *
250
         * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON SUCCESS!
251
         * Hence, do not pass in uninitialized pointers.
252
         */
253

254
        if (streq(s, "machine-id")) {
×
255
                *type = BOOT_ENTRY_TOKEN_MACHINE_ID;
×
256
                *token = mfree(*token);
×
257
                return 0;
×
258
        }
259

260
        if (streq(s, "os-image-id")) {
×
261
                *type = BOOT_ENTRY_TOKEN_OS_IMAGE_ID;
×
262
                *token = mfree(*token);
×
263
                return 0;
×
264
        }
265

266
        if (streq(s, "os-id")) {
×
267
                *type = BOOT_ENTRY_TOKEN_OS_ID;
×
268
                *token = mfree(*token);
×
269
                return 0;
×
270
        }
271

272
        const char *e = startswith(s, "literal:");
×
273
        if (e) {
×
274
                if (!boot_entry_token_valid(e))
×
275
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
276
                                               "Invalid entry token literal is specified for --entry-token=.");
277

278
                *type = BOOT_ENTRY_TOKEN_LITERAL;
×
279
                return free_and_strdup_warn(token, e);
×
280
        }
281

282
        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
283
                               "Unexpected parameter for --entry-token=: %s", s);
284
}
285

286
static const char *const boot_entry_token_type_table[] = {
287
        [BOOT_ENTRY_TOKEN_MACHINE_ID]  = "machine-id",
288
        [BOOT_ENTRY_TOKEN_OS_IMAGE_ID] = "os-image-id",
289
        [BOOT_ENTRY_TOKEN_OS_ID]       = "os-id",
290
        [BOOT_ENTRY_TOKEN_LITERAL]     = "literal",
291
        [BOOT_ENTRY_TOKEN_AUTO]        = "auto",
292
};
293

294
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(boot_entry_token_type, BootEntryTokenType);
×
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