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

systemd / systemd / 21887594812

10 Feb 2026 10:59PM UTC coverage: 72.432% (-0.3%) from 72.697%
21887594812

push

github

web-flow
terminal-util: handle the case where no system console is active (#40630)

/dev/console might have no backing driver, in which case
/sys/class/tty/console/active is empty. Unlike get_kernel_consoles()
resolve_dev_console() currently proceeds with empty devnode, resulting
in setup_input() -> acquire_terminal() emitting -EISDIR as we're trying
to open /dev/. Let's catch this and report -ENXIO.

2 of 6 new or added lines in 1 file covered. (33.33%)

3086 existing lines in 47 files now uncovered.

311026 of 429403 relevant lines covered (72.43%)

1239369.43 hits per line

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

70.31
/src/sysupdate/sysupdate-partition.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <sys/file.h>
4

5
#include "alloc-util.h"
6
#include "fdisk-util.h"
7
#include "gpt.h"
8
#include "log.h"
9
#include "string-util.h"
10
#include "sysupdate-partition.h"
11

12
void partition_info_destroy(PartitionInfo *p) {
15,806✔
13
        assert(p);
15,806✔
14

15
        p->label = mfree(p->label);
15,806✔
16
        p->device = mfree(p->device);
15,806✔
17
}
15,806✔
18

19
int partition_info_copy(PartitionInfo *dest, const PartitionInfo *src) {
48✔
20
        int r;
48✔
21

22
        assert(dest);
48✔
23
        assert(src);
48✔
24

25
        r = free_and_strdup_warn(&dest->label, src->label);
48✔
26
        if (r < 0)
48✔
27
                return r;
28

29
        r = free_and_strdup_warn(&dest->device, src->device);
48✔
30
        if (r < 0)
48✔
31
                return r;
32

33
        dest->partno = src->partno;
48✔
34
        dest->start = src->start;
48✔
35
        dest->size = src->size;
48✔
36
        dest->flags = src->flags;
48✔
37
        dest->type = src->type;
48✔
38
        dest->uuid = src->uuid;
48✔
39
        dest->no_auto = src->no_auto;
48✔
40
        dest->read_only = src->read_only;
48✔
41
        dest->growfs = src->growfs;
48✔
42

43
        return 0;
48✔
44
}
45

46
int read_partition_info(
2,976✔
47
                struct fdisk_context *c,
48
                struct fdisk_table *t,
49
                size_t i,
50
                PartitionInfo *ret) {
51

52
        _cleanup_free_ char *label_copy = NULL, *device = NULL;
2,976✔
53
        const char *label;
2,976✔
54
        struct fdisk_partition *p;
2,976✔
55
        uint64_t start, size, flags;
2,976✔
56
        unsigned long ssz;
2,976✔
57
        sd_id128_t ptid, id;
2,976✔
58
        GptPartitionType type;
2,976✔
59
        size_t partno;
2,976✔
60
        int r;
2,976✔
61

62
        assert(c);
2,976✔
63
        assert(t);
2,976✔
64
        assert(ret);
2,976✔
65

66
        p = fdisk_table_get_partition(t, i);
2,976✔
67
        if (!p)
2,976✔
UNCOV
68
                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read partition metadata.");
×
69

70
        if (fdisk_partition_is_used(p) <= 0) {
2,976✔
UNCOV
71
                *ret = (PartitionInfo) PARTITION_INFO_NULL;
×
UNCOV
72
                return 0; /* not found! */
×
73
        }
74

75
        if (fdisk_partition_has_partno(p) <= 0 ||
5,952✔
76
            fdisk_partition_has_start(p) <= 0 ||
5,952✔
77
            fdisk_partition_has_size(p) <= 0)
2,976✔
78
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Found a partition without a number, position or size.");
×
79

80
        partno = fdisk_partition_get_partno(p);
2,976✔
81

82
        start = fdisk_partition_get_start(p);
2,976✔
83
        ssz = fdisk_get_sector_size(c);
2,976✔
84
        assert(start <= UINT64_MAX / ssz);
2,976✔
85
        start *= ssz;
2,976✔
86

87
        size = fdisk_partition_get_size(p);
2,976✔
88
        assert(size <= UINT64_MAX / ssz);
2,976✔
89
        size *= ssz;
2,976✔
90

91
        label = fdisk_partition_get_name(p);
2,976✔
92
        if (!label)
2,976✔
UNCOV
93
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Found a partition without a label.");
×
94

95
        r = fdisk_partition_get_type_as_id128(p, &ptid);
2,976✔
96
        if (r < 0)
2,976✔
UNCOV
97
                return log_error_errno(r, "Failed to read partition type UUID: %m");
×
98

99
        r = fdisk_partition_get_uuid_as_id128(p, &id);
2,976✔
100
        if (r < 0)
2,976✔
UNCOV
101
                return log_error_errno(r, "Failed to read partition UUID: %m");
×
102

103
        r = fdisk_partition_get_attrs_as_uint64(p, &flags);
2,976✔
104
        if (r < 0)
2,976✔
UNCOV
105
                return log_error_errno(r, "Failed to get partition flags: %m");
×
106

107
        r = fdisk_partition_to_string(p, c, FDISK_FIELD_DEVICE, &device);
2,976✔
108
        if (r != 0)
2,976✔
UNCOV
109
                return log_error_errno(r, "Failed to get partition device name: %m");
×
110

111
        label_copy = strdup(label);
2,976✔
112
        if (!label_copy)
2,976✔
113
                return log_oom();
×
114

115
        type = gpt_partition_type_from_uuid(ptid);
2,976✔
116

117
        *ret = (PartitionInfo) {
5,952✔
118
                .partno = partno,
119
                .start = start,
120
                .size = size,
121
                .flags = flags,
122
                .type = ptid,
123
                .uuid = id,
124
                .label = TAKE_PTR(label_copy),
2,976✔
125
                .device = TAKE_PTR(device),
2,976✔
126
                .no_auto = FLAGS_SET(flags, SD_GPT_FLAG_NO_AUTO) && gpt_partition_type_knows_no_auto(type),
2,976✔
127
                .read_only = FLAGS_SET(flags, SD_GPT_FLAG_READ_ONLY) && gpt_partition_type_knows_read_only(type),
2,976✔
128
                .growfs = FLAGS_SET(flags, SD_GPT_FLAG_GROWFS) && gpt_partition_type_knows_growfs(type),
2,976✔
129
        };
130

131
        return 1; /* found! */
2,976✔
132
}
133

134
int find_suitable_partition(
84✔
135
                const char *device,
136
                uint64_t space,
137
                sd_id128_t *partition_type,
138
                PartitionInfo *ret) {
139

UNCOV
140
        _cleanup_(partition_info_destroy) PartitionInfo smallest = PARTITION_INFO_NULL;
×
141
        _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
84✔
142
        _cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL;
84✔
143
        size_t n_partitions;
84✔
144
        int r;
84✔
145

146
        assert(device);
84✔
147
        assert(ret);
84✔
148

149
        r = fdisk_new_context_at(AT_FDCWD, device, /* read_only= */ true, /* sector_size= */ UINT32_MAX, &c);
84✔
150
        if (r < 0)
84✔
151
                return log_error_errno(r, "Failed to create fdisk context from '%s': %m", device);
×
152

153
        if (!fdisk_is_labeltype(c, FDISK_DISKLABEL_GPT))
84✔
UNCOV
154
                return log_error_errno(SYNTHETIC_ERRNO(EHWPOISON), "Disk %s has no GPT disk label, not suitable.", device);
×
155

156
        r = fdisk_get_partitions(c, &t);
84✔
157
        if (r < 0)
84✔
UNCOV
158
                return log_error_errno(r, "Failed to acquire partition table: %m");
×
159

160
        n_partitions = fdisk_table_get_nents(t);
84✔
161
        for (size_t i = 0; i < n_partitions; i++)  {
420✔
162
                _cleanup_(partition_info_destroy) PartitionInfo pinfo = PARTITION_INFO_NULL;
252✔
163

164
                r = read_partition_info(c, t, i, &pinfo);
336✔
165
                if (r < 0)
336✔
UNCOV
166
                        return r;
×
167
                if (r == 0) /* not assigned */
336✔
UNCOV
168
                        continue;
×
169

170
                /* Filter out non-matching partition types */
171
                if (partition_type && !sd_id128_equal(pinfo.type, *partition_type))
504✔
172
                        continue;
168✔
173

174
                if (!streq_ptr(pinfo.label, "_empty")) /* used */
168✔
175
                        continue;
72✔
176

177
                if (space != UINT64_MAX && pinfo.size < space) /* too small */
96✔
UNCOV
178
                        continue;
×
179

180
                if (smallest.partno != SIZE_MAX && smallest.size <= pinfo.size) /* already found smaller */
96✔
181
                        continue;
12✔
182

183
                smallest = pinfo;
84✔
184
                pinfo = (PartitionInfo) PARTITION_INFO_NULL;
84✔
185
        }
186

187
        if (smallest.partno == SIZE_MAX)
84✔
UNCOV
188
                return log_error_errno(SYNTHETIC_ERRNO(ENOSPC), "No available partition of a suitable size found.");
×
189

190
        *ret = smallest;
84✔
191
        smallest = (PartitionInfo) PARTITION_INFO_NULL;
84✔
192

193
        return 0;
84✔
194
}
195

196
int patch_partition(
312✔
197
                const char *device,
198
                const PartitionInfo *info,
199
                PartitionChange change) {
200

201
        _cleanup_(fdisk_unref_partitionp) struct fdisk_partition *pa = NULL;
312✔
202
        _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
312✔
203
        bool tweak_no_auto, tweak_read_only, tweak_growfs;
312✔
204
        GptPartitionType type;
312✔
205
        int r, fd;
312✔
206

207
        assert(device);
312✔
208
        assert(info);
312✔
209
        assert(change <= _PARTITION_CHANGE_MAX);
312✔
210

211
        if (change == 0) /* Nothing to do */
312✔
212
                return 0;
213

214
        r = fdisk_new_context_at(AT_FDCWD, device, /* read_only= */ false, /* sector_size= */ UINT32_MAX, &c);
312✔
215
        if (r < 0)
312✔
UNCOV
216
                return log_error_errno(r, "Failed to create fdisk context from '%s': %m", device);
×
217

218
        assert_se((fd = fdisk_get_devfd(c)) >= 0);
312✔
219

220
        /* Make sure udev doesn't read the device while we make changes (this lock is released automatically
221
         * by the kernel when the fd is closed, i.e. when the fdisk context is freed, hence no explicit
222
         * unlock by us here anywhere.) */
223
        if (flock(fd, LOCK_EX) < 0)
312✔
UNCOV
224
                return log_error_errno(errno, "Failed to lock block device '%s': %m", device);
×
225

226
        if (!fdisk_is_labeltype(c, FDISK_DISKLABEL_GPT))
312✔
UNCOV
227
                return log_error_errno(SYNTHETIC_ERRNO(EHWPOISON), "Disk %s has no GPT disk label, not suitable.", device);
×
228

229
        r = fdisk_get_partition(c, info->partno, &pa);
312✔
230
        if (r < 0)
312✔
UNCOV
231
                return log_error_errno(r, "Failed to read partition %zu of GPT label of '%s': %m", info->partno, device);
×
232

233
        if (change & PARTITION_LABEL) {
312✔
234
                r = fdisk_partition_set_name(pa, info->label);
312✔
235
                if (r < 0)
312✔
236
                        return log_error_errno(r, "Failed to update partition label: %m");
×
237
        }
238

239
        if (change & PARTITION_UUID) {
312✔
240
                r = fdisk_partition_set_uuid(pa, SD_ID128_TO_UUID_STRING(info->uuid));
×
241
                if (r < 0)
×
242
                        return log_error_errno(r, "Failed to update partition UUID: %m");
×
243
        }
244

245
        type = gpt_partition_type_from_uuid(info->type);
312✔
246

247
        /* Tweak the read-only flag, but only if supported by the partition type */
248
        tweak_no_auto =
624✔
249
                FLAGS_SET(change, PARTITION_NO_AUTO) &&
312✔
UNCOV
250
                gpt_partition_type_knows_no_auto(type);
×
251
        tweak_read_only =
624✔
252
                FLAGS_SET(change, PARTITION_READ_ONLY) &&
312✔
UNCOV
253
                gpt_partition_type_knows_read_only(type);
×
254
        tweak_growfs =
624✔
255
                FLAGS_SET(change, PARTITION_GROWFS) &&
312✔
256
                gpt_partition_type_knows_growfs(type);
×
257

258
        if (change & PARTITION_FLAGS) {
312✔
259
                uint64_t flags;
×
260

261
                /* Update the full flags parameter, and import the read-only flag into it */
262

263
                flags = info->flags;
×
264
                if (tweak_no_auto)
×
UNCOV
265
                        SET_FLAG(flags, SD_GPT_FLAG_NO_AUTO, info->no_auto);
×
266
                if (tweak_read_only)
×
267
                        SET_FLAG(flags, SD_GPT_FLAG_READ_ONLY, info->read_only);
×
268
                if (tweak_growfs)
×
269
                        SET_FLAG(flags, SD_GPT_FLAG_GROWFS, info->growfs);
×
270

UNCOV
271
                r = fdisk_partition_set_attrs_as_uint64(pa, flags);
×
UNCOV
272
                if (r < 0)
×
UNCOV
273
                        return log_error_errno(r, "Failed to update partition flags: %m");
×
274

275
        } else if (tweak_no_auto || tweak_read_only || tweak_growfs) {
312✔
UNCOV
276
                uint64_t old_flags, new_flags;
×
277

278
                /* So we aren't supposed to update the full flags parameter, but we are supposed to update
279
                 * the RO flag of it. */
280

UNCOV
281
                r = fdisk_partition_get_attrs_as_uint64(pa, &old_flags);
×
UNCOV
282
                if (r < 0)
×
UNCOV
283
                        return log_error_errno(r, "Failed to get old partition flags: %m");
×
284

UNCOV
285
                new_flags = old_flags;
×
UNCOV
286
                if (tweak_no_auto)
×
UNCOV
287
                        SET_FLAG(new_flags, SD_GPT_FLAG_NO_AUTO, info->no_auto);
×
UNCOV
288
                if (tweak_read_only)
×
UNCOV
289
                        SET_FLAG(new_flags, SD_GPT_FLAG_READ_ONLY, info->read_only);
×
UNCOV
290
                if (tweak_growfs)
×
UNCOV
291
                        SET_FLAG(new_flags, SD_GPT_FLAG_GROWFS, info->growfs);
×
292

UNCOV
293
                if (new_flags != old_flags) {
×
UNCOV
294
                        r = fdisk_partition_set_attrs_as_uint64(pa, new_flags);
×
UNCOV
295
                        if (r < 0)
×
UNCOV
296
                                return log_error_errno(r, "Failed to update partition flags: %m");
×
297
                }
298
        }
299

300
        r = fdisk_set_partition(c, info->partno, pa);
312✔
301
        if (r < 0)
312✔
UNCOV
302
                return log_error_errno(r, "Failed to update partition: %m");
×
303

304
        r = fdisk_write_disklabel(c);
312✔
305
        if (r < 0)
312✔
UNCOV
306
                return log_error_errno(r, "Failed to write updated partition table: %m");
×
307

308
        return 0;
309
}
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