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

systemd / systemd / 14815796853

02 May 2025 11:41AM UTC coverage: 72.24% (-0.003%) from 72.243%
14815796853

push

github

web-flow
Various changes to prepare for running IWYU on the repository (#37319)

These are various commits that were required to get things compiling
after running IWYU. I think all of them make sense on their own, hence
this split PR to merge them ahead of time.

81 of 96 new or added lines in 48 files covered. (84.38%)

209 existing lines in 39 files now uncovered.

297219 of 411432 relevant lines covered (72.24%)

693693.2 hits per line

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

85.95
/src/libsystemd/sd-device/test-sd-device.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <ctype.h>
4
#include <fcntl.h>
5
#include <unistd.h>
6

7
#include "device-enumerator-private.h"
8
#include "device-internal.h"
9
#include "device-private.h"
10
#include "device-util.h"
11
#include "errno-util.h"
12
#include "fd-util.h"
13
#include "hashmap.h"
14
#include "mountpoint-util.h"
15
#include "nulstr-util.h"
16
#include "path-util.h"
17
#include "rm-rf.h"
18
#include "stat-util.h"
19
#include "string-util.h"
20
#include "tests.h"
21
#include "time-util.h"
22
#include "tmpfile-util.h"
23
#include "udev-util.h"
24

25
static void test_sd_device_one(sd_device *d) {
832✔
26
        _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
1,664✔
27
        const char *syspath, *sysname, *subsystem = NULL, *devname, *val;
832✔
28
        bool is_block = false;
832✔
29
        dev_t devnum;
832✔
30
        usec_t usec;
832✔
31
        int ifindex, r;
832✔
32

33
        ASSERT_OK(sd_device_get_syspath(d, &syspath));
832✔
34
        ASSERT_NOT_NULL(path_startswith(syspath, "/sys"));
832✔
35
        ASSERT_OK(sd_device_get_sysname(d, &sysname));
832✔
36

37
        log_info("%s(%s)", __func__, syspath);
832✔
38

39
        ASSERT_OK(sd_device_new_from_syspath(&dev, syspath));
832✔
40
        ASSERT_OK(sd_device_get_syspath(dev, &val));
832✔
41
        ASSERT_STREQ(syspath, val);
832✔
42
        ASSERT_NULL(dev = sd_device_unref(dev));
832✔
43

44
        ASSERT_OK(sd_device_new_from_path(&dev, syspath));
832✔
45
        ASSERT_OK(sd_device_get_syspath(dev, &val));
832✔
46
        ASSERT_STREQ(syspath, val);
832✔
47
        ASSERT_NULL(dev = sd_device_unref(dev));
832✔
48

49
        r = sd_device_get_ifindex(d, &ifindex);
832✔
50
        if (r < 0)
832✔
51
                ASSERT_ERROR(r, ENOENT);
832✔
52
        else {
53
                ASSERT_GT(ifindex, 0);
×
54

55
                const char *ifname;
×
56
                ASSERT_OK(device_get_ifname(d, &ifname));
×
57
                ASSERT_NOT_NULL(endswith(syspath, ifname));
×
58
                if (strchr(sysname, '/'))
×
59
                        ASSERT_FALSE(streq(ifname, sysname));
×
60
                else
61
                        ASSERT_STREQ(ifname, sysname);
×
62

63
                r = sd_device_new_from_ifindex(&dev, ifindex);
×
64
                if (r < 0) {
×
65
                        ASSERT_ERROR(r, ENODEV);
×
66
                        log_device_warning_errno(d, r,
×
67
                                                 "Failed to create sd-device object from ifindex %i. "
68
                                                 "Maybe running on a non-host network namespace.", ifindex);
69
                } else {
70
                        ASSERT_OK(sd_device_get_syspath(dev, &val));
×
71
                        ASSERT_STREQ(syspath, val);
×
72
                        ASSERT_NULL(dev = sd_device_unref(dev));
×
73
                }
74

75
                /* This does not require the interface really exists on the network namespace.
76
                 * Hence, this should always succeed. */
77
                ASSERT_OK(sd_device_new_from_ifname(&dev, sysname));
×
78
                ASSERT_OK(sd_device_get_syspath(dev, &val));
×
79
                ASSERT_STREQ(syspath, val);
×
80
                ASSERT_NULL(dev = sd_device_unref(dev));
×
81
        }
82

83
        r = sd_device_get_subsystem(d, &subsystem);
832✔
84
        if (r < 0)
832✔
85
                ASSERT_ERROR(r, ENOENT);
×
86
        else {
87
                const char *name, *id;
832✔
88

89
                if (streq(subsystem, "drivers")) {
832✔
90
                        const char *driver_subsystem;
154✔
91
                        ASSERT_OK(sd_device_get_driver_subsystem(d, &driver_subsystem));
154✔
92
                        name = strjoina(driver_subsystem, ":", sysname);
1,078✔
93
                } else
94
                        name = sysname;
678✔
95

96
                r = sd_device_new_from_subsystem_sysname(&dev, subsystem, name);
832✔
97
                if (r < 0)
832✔
98
                        ASSERT_ERROR(r, ETOOMANYREFS);
3✔
99
                else {
100
                        ASSERT_OK(sd_device_get_syspath(dev, &val));
829✔
101
                        ASSERT_STREQ(syspath, val);
829✔
102
                        ASSERT_NULL(dev = sd_device_unref(dev));
829✔
103
                }
104

105
                /* The device ID depends on subsystem. */
106
                ASSERT_OK(sd_device_get_device_id(d, &id));
832✔
107
                r = sd_device_new_from_device_id(&dev, id);
832✔
108
                if (r < 0) {
832✔
109
                        if (r == -ENODEV && ifindex > 0)
3✔
110
                                log_device_warning_errno(d, r,
×
111
                                                         "Failed to create sd-device object from device ID \"%s\". "
112
                                                         "Maybe running on a non-host network namespace.", id);
113
                        else
114
                                ASSERT_ERROR(r, ETOOMANYREFS);
3✔
115
                } else {
116
                        ASSERT_OK(sd_device_get_syspath(dev, &val));
829✔
117
                        ASSERT_STREQ(syspath, val);
829✔
118
                        ASSERT_NULL(dev = sd_device_unref(dev));
829✔
119
                }
120

121
                /* These require udev database, and reading database requires device ID. */
122
                ASSERT_OK(r = sd_device_get_is_initialized(d));
832✔
123
                if (r > 0) {
832✔
124
                        r = sd_device_get_usec_since_initialized(d, &usec);
×
125
                        if (r < 0)
×
126
                                ASSERT_ERROR(r, ENODATA);
×
127
                        else
128
                                ASSERT_GT(usec, 0U);
×
129
                }
130

131
                r = sd_device_get_property_value(d, "ID_NET_DRIVER", &val);
832✔
132
                if (r < 0)
832✔
133
                        ASSERT_ERROR(r, ENOENT);
832✔
134
        }
135

136
        is_block = streq_ptr(subsystem, "block");
832✔
137

138
        r = sd_device_get_devname(d, &devname);
832✔
139
        if (r < 0)
832✔
140
                ASSERT_ERROR(r, ENOENT);
652✔
141
        else {
142
                r = sd_device_new_from_devname(&dev, devname);
180✔
143
                if (r < 0)
180✔
144
                        ASSERT_TRUE(r == -ENODEV || ERRNO_IS_NEG_PRIVILEGE(r));
171✔
145
                else {
146
                        ASSERT_OK(sd_device_get_syspath(dev, &val));
9✔
147
                        ASSERT_STREQ(syspath, val);
9✔
148
                        ASSERT_NULL(dev = sd_device_unref(dev));
9✔
149
                }
150

151
                r = sd_device_new_from_path(&dev, devname);
180✔
152
                if (r < 0)
180✔
153
                        ASSERT_TRUE(r == -ENODEV || ERRNO_IS_NEG_PRIVILEGE(r));
171✔
154
                else {
155
                        ASSERT_OK(sd_device_get_syspath(dev, &val));
9✔
156
                        ASSERT_STREQ(syspath, val);
9✔
157
                        ASSERT_NULL(dev = sd_device_unref(dev));
9✔
158

159
                        _cleanup_close_ int fd = -EBADF;
×
160
                        fd = sd_device_open(d, O_CLOEXEC| O_NONBLOCK | (is_block ? O_RDONLY : O_NOCTTY | O_PATH));
18✔
161
                        ASSERT_TRUE(fd >= 0 || ERRNO_IS_NEG_PRIVILEGE(fd));
9✔
162
                }
163
        }
164

165
        r = sd_device_get_devnum(d, &devnum);
832✔
166
        if (r < 0)
832✔
167
                ASSERT_ERROR(r, ENOENT);
652✔
168
        else {
169
                _cleanup_free_ char *p = NULL;
180✔
170

171
                ASSERT_GT(major(devnum), 0U);
180✔
172

173
                ASSERT_OK(sd_device_new_from_devnum(&dev, is_block ? 'b' : 'c', devnum));
353✔
174
                ASSERT_OK(sd_device_get_syspath(dev, &val));
180✔
175
                ASSERT_STREQ(syspath, val);
180✔
176
                ASSERT_NULL(dev = sd_device_unref(dev));
180✔
177

178
                ASSERT_OK(asprintf(&p, "/dev/%s/%u:%u", is_block ? "block" : "char", major(devnum), minor(devnum)));
353✔
179
                ASSERT_OK(sd_device_new_from_devname(&dev, p));
180✔
180
                ASSERT_OK(sd_device_get_syspath(dev, &val));
180✔
181
                ASSERT_STREQ(syspath, val);
180✔
182
                ASSERT_NULL(dev = sd_device_unref(dev));
180✔
183

184
                ASSERT_OK(sd_device_new_from_path(&dev, p));
180✔
185
                ASSERT_OK(sd_device_get_syspath(dev, &val));
180✔
186
                ASSERT_STREQ(syspath, val);
180✔
187
                ASSERT_NULL(dev = sd_device_unref(dev));
180✔
188
        }
189

190
        ASSERT_OK(sd_device_get_devpath(d, &val));
832✔
191

192
        r = sd_device_get_devtype(d, NULL);
832✔
193
        if (r < 0)
832✔
194
                ASSERT_ERROR(r, ENOENT);
778✔
195

196
        r = sd_device_get_driver(d, NULL);
832✔
197
        if (r < 0)
832✔
198
                ASSERT_ERROR(r, ENOENT);
758✔
199

200
        r = sd_device_get_sysnum(d, &val);
832✔
201
        if (r < 0)
832✔
202
                ASSERT_ERROR(r, ENOENT);
289✔
203
        else {
204
                ASSERT_TRUE(val > sysname);
543✔
205
                ASSERT_TRUE(val < sysname + strlen(sysname));
543✔
206
                ASSERT_TRUE(in_charset(val, DIGITS));
543✔
207
                ASSERT_FALSE(ascii_isdigit(val[-1]));
543✔
208

209
                r = device_get_sysnum_unsigned(d, NULL);
543✔
210
                if (r < 0)
543✔
UNCOV
211
                        ASSERT_ERROR(r, ERANGE); /* sysnum may be too large. */
×
212
        }
213

214
        r = sd_device_get_sysattr_value(d, "nsid", NULL);
832✔
215
        if (r < 0)
832✔
216
                ASSERT_TRUE(ERRNO_IS_NEG_PRIVILEGE(r) || IN_SET(r, -ENOENT, -EINVAL));
832✔
217
        else {
218
                unsigned x;
×
219
                ASSERT_OK(r = device_get_sysattr_unsigned(d, "nsid", &x));
×
220
                ASSERT_EQ(x > 0, r > 0);
×
221
        }
222
}
832✔
223

224
static void exclude_problematic_devices(sd_device_enumerator *e) {
4✔
225
        /* On some CI environments, it seems some loop block devices and corresponding bdi devices sometimes
226
         * disappear during running this test. Let's exclude them here for stability. */
227
        ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "bdi", false));
4✔
228
        ASSERT_OK(sd_device_enumerator_add_nomatch_sysname(e, "loop*"));
4✔
229
        /* On CentOS CI, systemd-networkd-tests.py may be running when this test is invoked. The networkd
230
         * test creates and removes many network interfaces, and may interfere with this test. */
231
        ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "net", false));
4✔
232
}
4✔
233

234
TEST(sd_device_enumerator_devices) {
1✔
235
        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
2✔
236

237
        ASSERT_OK(sd_device_enumerator_new(&e));
1✔
238
        ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
1✔
239
        exclude_problematic_devices(e);
1✔
240

241
        FOREACH_DEVICE(e, d)
641✔
242
                test_sd_device_one(d);
640✔
243
}
1✔
244

245
TEST(sd_device_enumerator_subsystems) {
1✔
246
        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
2✔
247

248
        ASSERT_OK(sd_device_enumerator_new(&e));
1✔
249
        ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
1✔
250
        FOREACH_SUBSYSTEM(e, d)
193✔
251
                test_sd_device_one(d);
192✔
252
}
1✔
253

254
static void test_sd_device_enumerator_filter_subsystem_one(
37✔
255
                const char *subsystem,
256
                Hashmap *h,
257
                unsigned *ret_n_new_dev,
258
                unsigned *ret_n_removed_dev) {
259

260
        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
74✔
261
        unsigned n_new_dev = 0, n_removed_dev = 0;
37✔
262
        sd_device *dev;
37✔
263

264
        ASSERT_OK(sd_device_enumerator_new(&e));
37✔
265
        ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, subsystem, true));
37✔
266
        ASSERT_OK(sd_device_enumerator_add_nomatch_sysname(e, "loop*"));
37✔
267

268
        FOREACH_DEVICE(e, d) {
497✔
269
                const char *syspath;
460✔
270
                sd_device *t;
460✔
271

272
                ASSERT_OK(sd_device_get_syspath(d, &syspath));
460✔
273
                t = hashmap_remove(h, syspath);
460✔
274

275
                if (!t) {
460✔
276
                        log_warning("New device found: subsystem:%s syspath:%s", subsystem, syspath);
×
277
                        n_new_dev++;
×
278
                }
279

280
                ASSERT_NULL(sd_device_unref(t));
460✔
281
        }
282

283
        HASHMAP_FOREACH(dev, h) {
37✔
284
                const char *syspath;
×
285

286
                ASSERT_OK(sd_device_get_syspath(dev, &syspath));
×
287
                log_warning("Device removed: subsystem:%s syspath:%s", subsystem, syspath);
×
288
                n_removed_dev++;
×
289

290
                ASSERT_NULL(sd_device_unref(dev));
×
291
        }
292

293
        hashmap_free(h);
37✔
294

295
        *ret_n_new_dev = n_new_dev;
37✔
296
        *ret_n_removed_dev = n_removed_dev;
37✔
297
}
37✔
298

299
static bool test_sd_device_enumerator_filter_subsystem_trial(void) {
1✔
300
        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
2✔
301
        _cleanup_hashmap_free_ Hashmap *subsystems = NULL;
×
302
        unsigned n_new_dev = 0, n_removed_dev = 0;
1✔
303
        Hashmap *h;
1✔
304
        char *s;
1✔
305

306
        ASSERT_NOT_NULL((subsystems = hashmap_new(&string_hash_ops)));
1✔
307
        ASSERT_OK(sd_device_enumerator_new(&e));
1✔
308
        exclude_problematic_devices(e);
1✔
309

310
        FOREACH_DEVICE(e, d) {
461✔
311
                const char *syspath, *subsystem;
460✔
312
                int r;
460✔
313

314
                ASSERT_OK(sd_device_get_syspath(d, &syspath));
460✔
315

316
                r = sd_device_get_subsystem(d, &subsystem);
460✔
317
                if (r < 0) {
460✔
318
                        ASSERT_ERROR(r, ENOENT);
×
319
                        continue;
×
320
                }
321

322
                h = hashmap_get(subsystems, subsystem);
460✔
323
                if (!h) {
460✔
324
                        char *str;
37✔
325
                        ASSERT_NOT_NULL((str = strdup(subsystem)));
37✔
326
                        ASSERT_NOT_NULL((h = hashmap_new(&string_hash_ops)));
37✔
327
                        ASSERT_OK(hashmap_put(subsystems, str, h));
37✔
328
                }
329

330
                ASSERT_OK(hashmap_put(h, syspath, d));
460✔
331
                ASSERT_NOT_NULL(sd_device_ref(d));
460✔
332

333
                log_debug("Added subsystem:%s syspath:%s", subsystem, syspath);
460✔
334
        }
335

336
        while ((h = hashmap_steal_first_key_and_value(subsystems, (void**) &s))) {
38✔
337
                unsigned n, m;
37✔
338

339
                test_sd_device_enumerator_filter_subsystem_one(s, TAKE_PTR(h), &n, &m);
37✔
340
                free(s);
37✔
341

342
                n_new_dev += n;
37✔
343
                n_removed_dev += m;
37✔
344
        }
345

346
        if (n_new_dev > 0)
1✔
347
                log_warning("%u new devices are found in re-scan", n_new_dev);
×
348
        if (n_removed_dev > 0)
1✔
349
                log_warning("%u devices removed in re-scan", n_removed_dev);
×
350

351
        return n_new_dev + n_removed_dev == 0;
2✔
352
}
353

354
static bool test_sd_device_enumerator_filter_subsystem_trial_many(void) {
1✔
355
        for (unsigned i = 0; i < 20; i++) {
1✔
356
                log_debug("%s(): trial %u", __func__, i);
1✔
357
                if (test_sd_device_enumerator_filter_subsystem_trial())
1✔
358
                        return true;
359
        }
360

361
        return false;
362
}
363

364
static int on_inotify(sd_event_source *s, const struct inotify_event *event, void *userdata) {
×
365
        if (test_sd_device_enumerator_filter_subsystem_trial_many())
×
366
                return sd_event_exit(sd_event_source_get_event(s), 0);
×
367

368
        return sd_event_exit(sd_event_source_get_event(s), -EBUSY);
×
369
}
370

371
TEST(sd_device_enumerator_filter_subsystem) {
1✔
372
        /* The test test_sd_device_enumerator_filter_subsystem_trial() is quite racy. Let's run the function
373
         * several times after the udev queue becomes empty. */
374

375
        if (!udev_available() || (access("/run/udev", F_OK) < 0 && errno == ENOENT)) {
1✔
376
                ASSERT_TRUE(test_sd_device_enumerator_filter_subsystem_trial_many());
1✔
377
                return;
1✔
378
        }
379

380
        _cleanup_(sd_event_unrefp) sd_event *event = NULL;
×
381
        ASSERT_OK(sd_event_default(&event));
×
382
        ASSERT_OK(sd_event_add_inotify(event, NULL, "/run/udev" , IN_DELETE, on_inotify, NULL));
×
383

384
        if (udev_queue_is_empty() == 0) {
×
385
                log_debug("udev queue is not empty, waiting for all queued events to be processed.");
×
386
                ASSERT_OK(sd_event_loop(event));
×
387
        } else
388
                ASSERT_TRUE(test_sd_device_enumerator_filter_subsystem_trial_many());
×
389
}
390

391
TEST(sd_device_enumerator_add_match_sysattr) {
1✔
392
        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
2✔
393
        sd_device *dev;
1✔
394
        int ifindex;
1✔
395

396
        ASSERT_OK(sd_device_enumerator_new(&e));
1✔
397
        ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
1✔
398
        ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "net", true));
1✔
399
        ASSERT_OK(sd_device_enumerator_add_match_sysattr(e, "ifindex", "1", true));
1✔
400
        ASSERT_OK(sd_device_enumerator_add_match_sysattr(e, "ifindex", "hoge", true));
1✔
401
        ASSERT_OK(sd_device_enumerator_add_match_sysattr(e, "ifindex", "foo", true));
1✔
402
        ASSERT_OK(sd_device_enumerator_add_match_sysattr(e, "ifindex", "bar", false));
1✔
403
        ASSERT_OK(sd_device_enumerator_add_match_sysattr(e, "ifindex", "baz", false));
1✔
404

405
        ASSERT_NOT_NULL((dev = sd_device_enumerator_get_device_first(e)));
1✔
406
        ASSERT_OK(sd_device_get_ifindex(dev, &ifindex));
1✔
407
        ASSERT_EQ(ifindex, 1);
1✔
408

409
        ASSERT_NULL(sd_device_enumerator_get_device_next(e));
1✔
410
}
1✔
411

412
TEST(sd_device_enumerator_add_match_property) {
1✔
413
        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
2✔
414
        sd_device *dev;
1✔
415
        int ifindex;
1✔
416

417
        ASSERT_OK(sd_device_enumerator_new(&e));
1✔
418
        ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
1✔
419
        ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "net", true));
1✔
420
        ASSERT_OK(sd_device_enumerator_add_match_sysattr(e, "ifindex", "1", true));
1✔
421
        ASSERT_OK(sd_device_enumerator_add_match_property(e, "IFINDE*", "1*"));
1✔
422
        ASSERT_OK(sd_device_enumerator_add_match_property(e, "IFINDE*", "hoge"));
1✔
423
        ASSERT_OK(sd_device_enumerator_add_match_property(e, "IFINDE*", NULL));
1✔
424
        ASSERT_OK(sd_device_enumerator_add_match_property(e, "AAAAA", "BBBB"));
1✔
425
        ASSERT_OK(sd_device_enumerator_add_match_property(e, "FOOOO", NULL));
1✔
426

427
        ASSERT_NOT_NULL((dev = sd_device_enumerator_get_device_first(e)));
1✔
428
        ASSERT_OK(sd_device_get_ifindex(dev, &ifindex));
1✔
429
        ASSERT_EQ(ifindex, 1);
1✔
430
}
1✔
431

432
TEST(sd_device_enumerator_add_match_property_required) {
1✔
433
        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
2✔
434
        sd_device *dev;
1✔
435
        int ifindex;
1✔
436

437
        ASSERT_OK(sd_device_enumerator_new(&e));
1✔
438
        ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
1✔
439
        ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "net", true));
1✔
440
        ASSERT_OK(sd_device_enumerator_add_match_sysattr(e, "ifindex", "1", true));
1✔
441
        ASSERT_OK(sd_device_enumerator_add_match_property_required(e, "IFINDE*", "1*"));
1✔
442

443
        /* Only one required match which should be satisfied. */
444
        ASSERT_NOT_NULL((dev = sd_device_enumerator_get_device_first(e)));
1✔
445
        ASSERT_OK(sd_device_get_ifindex(dev, &ifindex));
1✔
446
        ASSERT_EQ(ifindex, 1);
1✔
447

448
        /* Now let's add a bunch of garbage properties which should not be satisfied. */
449
        ASSERT_OK(sd_device_enumerator_add_match_property_required(e, "IFINDE*", "hoge"));
1✔
450
        ASSERT_OK(sd_device_enumerator_add_match_property_required(e, "IFINDE*", NULL));
1✔
451
        ASSERT_OK(sd_device_enumerator_add_match_property_required(e, "AAAAA", "BBBB"));
1✔
452
        ASSERT_OK(sd_device_enumerator_add_match_property_required(e, "FOOOO", NULL));
1✔
453

454
        ASSERT_NULL(sd_device_enumerator_get_device_first(e));
1✔
455
}
1✔
456

457
static void check_parent_match(sd_device_enumerator *e, sd_device *dev) {
14✔
458
        const char *syspath;
14✔
459
        bool found = false;
14✔
460

461
        ASSERT_OK(sd_device_get_syspath(dev, &syspath));
14✔
462

463
        FOREACH_DEVICE(e, d) {
27✔
464
                const char *s;
27✔
465

466
                ASSERT_OK(sd_device_get_syspath(d, &s));
27✔
467
                if (streq(s, syspath)) {
27✔
468
                        found = true;
14✔
469
                        break;
14✔
470
                }
471
        }
472

473
        if (!found) {
14✔
474
                log_device_debug(dev, "not enumerated, already removed??");
×
475
                /* If the original device not found, then the device should be already removed. */
476
                ASSERT_FAIL(access(syspath, F_OK));
×
477
                ASSERT_EQ(errno, ENOENT);
×
478
        }
479
}
14✔
480

481
TEST(sd_device_enumerator_add_match_parent) {
1✔
482
        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
2✔
483
        /* Some devices have thousands of children. Avoid spending too much time in the double loop below. */
484
        unsigned iterations = 200;
1✔
485
        int r;
1✔
486

487
        ASSERT_OK(sd_device_enumerator_new(&e));
1✔
488
        ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
1✔
489
        exclude_problematic_devices(e);
1✔
490

491
        ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "memory", false));
1✔
492

493
        if (!slow_tests_enabled())
1✔
494
                ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "block", true));
1✔
495

496
        FOREACH_DEVICE(e, dev) {
8✔
497
                _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *p = NULL;
7✔
498
                const char *syspath;
7✔
499
                sd_device *parent;
7✔
500

501
                if (iterations-- == 0)
7✔
502
                        break;
503

504
                ASSERT_OK(sd_device_get_syspath(dev, &syspath));
7✔
505

506
                r = sd_device_get_parent(dev, &parent);
7✔
507
                if (r < 0) {
7✔
508
                        ASSERT_TRUE(ERRNO_IS_NEG_DEVICE_ABSENT(r));
×
509
                        continue;
×
510
                }
511

512
                log_debug("> %s", syspath);
7✔
513

514
                ASSERT_OK(sd_device_enumerator_new(&p));
7✔
515
                ASSERT_OK(sd_device_enumerator_allow_uninitialized(p));
7✔
516
                ASSERT_OK(sd_device_enumerator_add_match_parent(p, parent));
7✔
517

518
                check_parent_match(p, dev);
7✔
519

520
                /* If the device does not have subsystem, then it is not enumerated. */
521
                r = sd_device_get_subsystem(parent, NULL);
7✔
522
                if (r < 0) {
7✔
523
                        ASSERT_ERROR(r, ENOENT);
×
524
                        continue;
×
525
                }
526
                check_parent_match(p, parent);
7✔
527
        }
528
}
1✔
529

530
TEST(sd_device_enumerator_add_all_parents) {
1✔
531
        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
2✔
532

533
        /* STEP 1: enumerate all block devices without all_parents() */
534
        ASSERT_OK(sd_device_enumerator_new(&e));
1✔
535
        ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
1✔
536

537
        /* filter in only a subsystem */
538
        ASSERT_OK(sd_device_enumerator_add_nomatch_sysname(e, "loop*"));
1✔
539
        ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "block", true));
1✔
540
        ASSERT_OK(sd_device_enumerator_add_match_property(e, "DEVTYPE", "partition"));
1✔
541

542
        unsigned devices_count_with_parents = 0;
1✔
543
        unsigned devices_count_without_parents = 0;
1✔
544
        FOREACH_DEVICE(e, dev) {
6✔
545
                ASSERT_TRUE(device_in_subsystem(dev, "block"));
5✔
546
                ASSERT_TRUE(device_is_devtype(dev, "partition"));
5✔
547
                devices_count_without_parents++;
5✔
548
        }
549

550
        log_debug("found %u devices", devices_count_without_parents);
1✔
551

552
        /* STEP 2: enumerate again with all_parents() */
553
        ASSERT_OK(sd_device_enumerator_add_all_parents(e));
1✔
554

555
        unsigned not_filtered_parent_count = 0;
1✔
556
        FOREACH_DEVICE(e, dev) {
21✔
557
                if (!device_in_subsystem(dev, "block") || !device_is_devtype(dev, "partition"))
20✔
558
                        not_filtered_parent_count++;
15✔
559
                devices_count_with_parents++;
20✔
560
        }
561
        log_debug("found %u devices out of %u that would have been excluded without all_parents()",
1✔
562
                  not_filtered_parent_count,
563
                  devices_count_with_parents);
564
        ASSERT_EQ(devices_count_with_parents, devices_count_without_parents + not_filtered_parent_count);
1✔
565
}
1✔
566

567
TEST(sd_device_get_child) {
1✔
568
        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
1✔
569
        /* Some devices have thousands of children. Avoid spending too much time in the double loop below. */
570
        unsigned iterations = 3000;
1✔
571
        int r;
1✔
572

573
        ASSERT_OK(sd_device_enumerator_new(&e));
1✔
574
        ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
1✔
575
        exclude_problematic_devices(e);
1✔
576

577
        if (!slow_tests_enabled())
1✔
578
                ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "block", true));
1✔
579

580
        FOREACH_DEVICE(e, dev) {
8✔
581
                const char *syspath, *parent_syspath, *expected_suffix, *suffix;
7✔
582
                sd_device *parent;
7✔
583
                bool found = false;
7✔
584

585
                ASSERT_OK(sd_device_get_syspath(dev, &syspath));
7✔
586

587
                r = sd_device_get_parent(dev, &parent);
7✔
588
                if (r < 0) {
7✔
589
                        ASSERT_TRUE(ERRNO_IS_NEG_DEVICE_ABSENT(r));
×
590
                        continue;
×
591
                }
592

593
                ASSERT_OK(sd_device_get_syspath(parent, &parent_syspath));
7✔
594
                ASSERT_NOT_NULL((expected_suffix = path_startswith(syspath, parent_syspath)));
7✔
595

596
                log_debug("> %s", syspath);
7✔
597

598
                FOREACH_DEVICE_CHILD_WITH_SUFFIX(parent, child, suffix) {
44✔
599
                        const char *s;
44✔
600

601
                        if (iterations-- == 0)
44✔
602
                                return;
×
603

604
                        ASSERT_NOT_NULL(child);
44✔
605
                        ASSERT_NOT_NULL(suffix);
44✔
606

607
                        if (!streq(suffix, expected_suffix))
44✔
608
                                continue;
37✔
609

610
                        ASSERT_OK(sd_device_get_syspath(child, &s));
7✔
611
                        ASSERT_STREQ(s, syspath);
7✔
612
                        found = true;
7✔
613
                        break;
7✔
614
                }
615
                ASSERT_TRUE(found);
7✔
616
        }
617
}
618

619
TEST(sd_device_new_from_nulstr) {
1✔
620
        const char *devlinks =
1✔
621
                "/dev/disk/by-partuuid/1290d63a-42cc-4c71-b87c-xxxxxxxxxxxx\0"
622
                "/dev/disk/by-path/pci-0000:00:0f.0-scsi-0:0:0:0-part3\0"
623
                "/dev/disk/by-label/Arch\\x20Linux\0"
624
                "/dev/disk/by-uuid/a07b87e5-4af5-4a59-bde9-yyyyyyyyyyyy\0"
625
                "/dev/disk/by-partlabel/Arch\\x20Linux\0"
626
                "\0";
627

628
        _cleanup_(sd_device_unrefp) sd_device *device = NULL, *from_nulstr = NULL;
1✔
629
        _cleanup_free_ char *nulstr_copy = NULL;
1✔
630
        const char *nulstr;
1✔
631
        size_t len;
1✔
632

633
        ASSERT_OK(sd_device_new_from_syspath(&device, "/sys/class/net/lo"));
1✔
634

635
        /* Yeah, of course, setting devlink to the loopback interface is nonsense. But this is just a
636
         * test for generating and parsing nulstr. For issue #17772. */
637
        NULSTR_FOREACH(devlink, devlinks) {
6✔
638
                log_device_info(device, "setting devlink: %s", devlink);
5✔
639
                ASSERT_OK(device_add_devlink(device, devlink));
5✔
640
                ASSERT_TRUE(set_contains(device->devlinks, devlink));
5✔
641
        }
642

643
        /* For issue #23799 */
644
        ASSERT_OK(device_add_tag(device, "tag1", false));
1✔
645
        ASSERT_OK(device_add_tag(device, "tag2", false));
1✔
646
        ASSERT_OK(device_add_tag(device, "current-tag1", true));
1✔
647
        ASSERT_OK(device_add_tag(device, "current-tag2", true));
1✔
648

649
        /* These properties are necessary for device_new_from_nulstr(). See device_verify(). */
650
        ASSERT_OK(device_add_property_internal(device, "SEQNUM", "1"));
1✔
651
        ASSERT_OK(device_add_property_internal(device, "ACTION", "change"));
1✔
652

653
        ASSERT_OK(device_get_properties_nulstr(device, &nulstr, &len));
1✔
654
        ASSERT_NOT_NULL((nulstr_copy = newdup(char, nulstr, len)));
1✔
655
        ASSERT_OK(device_new_from_nulstr(&from_nulstr, nulstr_copy, len));
1✔
656

657
        ASSERT_OK_POSITIVE(sd_device_has_tag(from_nulstr, "tag1"));
1✔
658
        ASSERT_OK_POSITIVE(sd_device_has_tag(from_nulstr, "tag2"));
1✔
659
        ASSERT_OK_POSITIVE(sd_device_has_tag(from_nulstr, "current-tag1"));
1✔
660
        ASSERT_OK_POSITIVE(sd_device_has_tag(from_nulstr, "current-tag2"));
1✔
661
        ASSERT_OK_ZERO(sd_device_has_current_tag(from_nulstr, "tag1"));
1✔
662
        ASSERT_OK_ZERO(sd_device_has_current_tag(from_nulstr, "tag2"));
1✔
663
        ASSERT_OK_POSITIVE(sd_device_has_current_tag(from_nulstr, "current-tag1"));
1✔
664
        ASSERT_OK_POSITIVE(sd_device_has_current_tag(from_nulstr, "current-tag2"));
1✔
665

666
        NULSTR_FOREACH(devlink, devlinks) {
6✔
667
                log_device_info(from_nulstr, "checking devlink: %s", devlink);
5✔
668
                ASSERT_TRUE(set_contains(from_nulstr->devlinks, devlink));
5✔
669
        }
670
}
1✔
671

672
TEST(sd_device_new_from_path) {
1✔
673
        _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
2✔
674
        _cleanup_(rm_rf_physical_and_freep) char *tmpdir = NULL;
1✔
675
        int r;
1✔
676

677
        ASSERT_OK(mkdtemp_malloc("/tmp/test-sd-device.XXXXXXX", &tmpdir));
1✔
678

679
        ASSERT_OK(sd_device_enumerator_new(&e));
1✔
680
        ASSERT_OK(sd_device_enumerator_allow_uninitialized(e));
1✔
681
        ASSERT_OK(sd_device_enumerator_add_match_subsystem(e, "block", true));
1✔
682
        ASSERT_OK(sd_device_enumerator_add_nomatch_sysname(e, "loop*"));
1✔
683
        ASSERT_OK(sd_device_enumerator_add_match_property(e, "DEVNAME", "*"));
1✔
684

685
        FOREACH_DEVICE(e, dev) {
8✔
686
                _cleanup_(sd_device_unrefp) sd_device *d = NULL;
7✔
687
                const char *syspath, *devpath, *sysname, *s;
7✔
688
                _cleanup_free_ char *path = NULL;
7✔
689

690
                ASSERT_OK(sd_device_get_sysname(dev, &sysname));
7✔
691

692
                log_debug("%s(%s)", __func__, sysname);
7✔
693

694
                ASSERT_OK(sd_device_get_syspath(dev, &syspath));
7✔
695
                ASSERT_OK(sd_device_new_from_path(&d, syspath));
7✔
696
                ASSERT_OK(sd_device_get_syspath(d, &s));
7✔
697
                ASSERT_STREQ(s, syspath);
7✔
698
                ASSERT_NULL(d = sd_device_unref(d));
7✔
699

700
                ASSERT_OK(sd_device_get_devname(dev, &devpath));
7✔
701
                r = sd_device_new_from_path(&d, devpath);
7✔
702
                if (r < 0)
7✔
703
                        ASSERT_TRUE(r == -ENODEV || ERRNO_IS_NEG_PRIVILEGE(r));
7✔
704
                else {
705
                        ASSERT_OK(sd_device_get_syspath(d, &s));
×
706
                        ASSERT_STREQ(s, syspath);
×
707
                        ASSERT_NULL(d = sd_device_unref(d));
×
708
                }
709

710
                ASSERT_NOT_NULL((path = path_join(tmpdir, sysname)));
7✔
711
                ASSERT_OK_ERRNO(symlink(syspath, path));
7✔
712
                ASSERT_OK(sd_device_new_from_path(&d, path));
7✔
713
                ASSERT_OK(sd_device_get_syspath(d, &s));
7✔
714
                ASSERT_STREQ(s, syspath);
7✔
715
        }
716
}
1✔
717

718
static void test_devname_from_devnum_one(const char *path) {
8✔
719
        _cleanup_free_ char *resolved = NULL;
8✔
720
        struct stat st;
8✔
721

722
        log_debug("> %s", path);
8✔
723

724
        if (stat(path, &st) < 0) {
8✔
725
                log_notice("Path %s not found, skipping test", path);
×
726
                return;
×
727
        }
728

729
        ASSERT_OK(devname_from_devnum(st.st_mode, st.st_rdev, &resolved));
8✔
730
        ASSERT_TRUE(path_equal(path, resolved));
8✔
731
        ASSERT_NULL(resolved = mfree(resolved));
8✔
732
        ASSERT_OK(devname_from_stat_rdev(&st, &resolved));
8✔
733
        ASSERT_TRUE(path_equal(path, resolved));
8✔
734
}
735

736
TEST(devname_from_devnum) {
1✔
737
        test_devname_from_devnum_one("/dev/null");
1✔
738
        test_devname_from_devnum_one("/dev/zero");
1✔
739
        test_devname_from_devnum_one("/dev/full");
1✔
740
        test_devname_from_devnum_one("/dev/random");
1✔
741
        test_devname_from_devnum_one("/dev/urandom");
1✔
742
        test_devname_from_devnum_one("/dev/tty");
1✔
743

744
        if (is_device_node("/run/systemd/inaccessible/blk") > 0) {
1✔
745
                test_devname_from_devnum_one("/run/systemd/inaccessible/chr");
1✔
746
                test_devname_from_devnum_one("/run/systemd/inaccessible/blk");
1✔
747
        }
748
}
1✔
749

750
static int intro(void) {
1✔
751
        if (path_is_mount_point("/sys") <= 0)
1✔
752
                return log_tests_skipped("/sys is not mounted");
×
753

754
        return EXIT_SUCCESS;
755
}
756

757
DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);
1✔
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