]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-libudev.c
libudev: make util_resolve_subsys_kernel() return negative errno
[thirdparty/systemd.git] / src / test / test-libudev.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
33a5cc29 2
5ea78a39 3#include <errno.h>
b2d9e4f2 4#include <getopt.h>
07630cea 5#include <stdio.h>
f2fd4d27 6#include <sys/epoll.h>
07630cea 7#include <unistd.h>
ba6929f6 8
01cbafe1 9#include "alloc-util.h"
cc4c1d22 10#include "fd-util.h"
5ea78a39 11#include "libudev-util.h"
cc4c1d22 12#include "log.h"
d054f0a4 13#include "stdio-util.h"
07630cea 14#include "string-util.h"
33a5cc29 15
f168c273 16static void print_device(struct udev_device *device) {
912541b0
KS
17 const char *str;
18 dev_t devnum;
19 int count;
20 struct udev_list_entry *list_entry;
21
cc4c1d22 22 log_info("*** device: %p ***", device);
912541b0
KS
23 str = udev_device_get_action(device);
24 if (str != NULL)
cc4c1d22 25 log_info("action: '%s'", str);
912541b0
KS
26
27 str = udev_device_get_syspath(device);
cc4c1d22 28 log_info("syspath: '%s'", str);
912541b0
KS
29
30 str = udev_device_get_sysname(device);
cc4c1d22 31 log_info("sysname: '%s'", str);
912541b0
KS
32
33 str = udev_device_get_sysnum(device);
34 if (str != NULL)
cc4c1d22 35 log_info("sysnum: '%s'", str);
912541b0
KS
36
37 str = udev_device_get_devpath(device);
cc4c1d22 38 log_info("devpath: '%s'", str);
912541b0
KS
39
40 str = udev_device_get_subsystem(device);
41 if (str != NULL)
cc4c1d22 42 log_info("subsystem: '%s'", str);
912541b0
KS
43
44 str = udev_device_get_devtype(device);
45 if (str != NULL)
cc4c1d22 46 log_info("devtype: '%s'", str);
912541b0
KS
47
48 str = udev_device_get_driver(device);
49 if (str != NULL)
cc4c1d22 50 log_info("driver: '%s'", str);
912541b0
KS
51
52 str = udev_device_get_devnode(device);
53 if (str != NULL)
cc4c1d22 54 log_info("devname: '%s'", str);
912541b0
KS
55
56 devnum = udev_device_get_devnum(device);
57 if (major(devnum) > 0)
cc4c1d22 58 log_info("devnum: %u:%u", major(devnum), minor(devnum));
912541b0
KS
59
60 count = 0;
61 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
cc4c1d22 62 log_info("link: '%s'", udev_list_entry_get_name(list_entry));
912541b0
KS
63 count++;
64 }
65 if (count > 0)
cc4c1d22 66 log_info("found %i links", count);
912541b0
KS
67
68 count = 0;
69 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) {
cc4c1d22 70 log_info("property: '%s=%s'",
912541b0
KS
71 udev_list_entry_get_name(list_entry),
72 udev_list_entry_get_value(list_entry));
73 count++;
74 }
75 if (count > 0)
cc4c1d22 76 log_info("found %i properties", count);
912541b0
KS
77
78 str = udev_device_get_property_value(device, "MAJOR");
79 if (str != NULL)
cc4c1d22 80 log_info("MAJOR: '%s'", str);
912541b0
KS
81
82 str = udev_device_get_sysattr_value(device, "dev");
83 if (str != NULL)
cc4c1d22 84 log_info("attr{dev}: '%s'", str);
ba6929f6
KS
85}
86
cc4c1d22 87static void test_device(struct udev *udev, const char *syspath) {
8e766630 88 _cleanup_(udev_device_unrefp) struct udev_device *device;
912541b0 89
cc4c1d22 90 log_info("looking at device: %s", syspath);
912541b0 91 device = udev_device_new_from_syspath(udev, syspath);
cc4c1d22
ZJS
92 if (device == NULL)
93 log_warning_errno(errno, "udev_device_new_from_syspath: %m");
94 else
95 print_device(device);
33a5cc29
KS
96}
97
cc4c1d22 98static void test_device_parents(struct udev *udev, const char *syspath) {
8e766630 99 _cleanup_(udev_device_unrefp) struct udev_device *device;
912541b0
KS
100 struct udev_device *device_parent;
101
cc4c1d22 102 log_info("looking at device: %s", syspath);
912541b0
KS
103 device = udev_device_new_from_syspath(udev, syspath);
104 if (device == NULL)
cc4c1d22 105 return;
912541b0 106
cc4c1d22 107 log_info("looking at parents");
912541b0
KS
108 device_parent = device;
109 do {
110 print_device(device_parent);
111 device_parent = udev_device_get_parent(device_parent);
112 } while (device_parent != NULL);
113
cc4c1d22 114 log_info("looking at parents again");
912541b0
KS
115 device_parent = device;
116 do {
117 print_device(device_parent);
118 device_parent = udev_device_get_parent(device_parent);
119 } while (device_parent != NULL);
4ad3a37f
KS
120}
121
cc4c1d22 122static void test_device_devnum(struct udev *udev) {
912541b0 123 dev_t devnum = makedev(1, 3);
8e766630 124 _cleanup_(udev_device_unrefp) struct udev_device *device;
912541b0 125
cc4c1d22 126 log_info("looking up device: %u:%u", major(devnum), minor(devnum));
912541b0
KS
127 device = udev_device_new_from_devnum(udev, 'c', devnum);
128 if (device == NULL)
cc4c1d22
ZJS
129 log_warning_errno(errno, "udev_device_new_from_devnum: %m");
130 else
131 print_device(device);
4c9dff47
KS
132}
133
cc4c1d22 134static void test_device_subsys_name(struct udev *udev, const char *subsys, const char *dev) {
8e766630 135 _cleanup_(udev_device_unrefp) struct udev_device *device;
912541b0 136
cc4c1d22
ZJS
137 log_info("looking up device: '%s:%s'", subsys, dev);
138 device = udev_device_new_from_subsystem_sysname(udev, subsys, dev);
912541b0 139 if (device == NULL)
cc4c1d22
ZJS
140 log_warning_errno(errno, "udev_device_new_from_subsystem_sysname: %m");
141 else
142 print_device(device);
90d80c2e
KS
143}
144
f168c273 145static int test_enumerate_print_list(struct udev_enumerate *enumerate) {
912541b0
KS
146 struct udev_list_entry *list_entry;
147 int count = 0;
148
149 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) {
150 struct udev_device *device;
151
152 device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate),
153 udev_list_entry_get_name(list_entry));
154 if (device != NULL) {
cc4c1d22
ZJS
155 log_info("device: '%s' (%s)",
156 udev_device_get_syspath(device),
157 udev_device_get_subsystem(device));
912541b0
KS
158 udev_device_unref(device);
159 count++;
160 }
161 }
cc4c1d22 162 log_info("found %i devices", count);
912541b0 163 return count;
ba6929f6
KS
164}
165
cc4c1d22 166static void test_monitor(struct udev *udev) {
8e766630 167 _cleanup_(udev_monitor_unrefp) struct udev_monitor *udev_monitor;
cc4c1d22
ZJS
168 _cleanup_close_ int fd_ep;
169 int fd_udev;
170 struct epoll_event ep_udev = {
171 .events = EPOLLIN,
172 }, ep_stdin = {
173 .events = EPOLLIN,
174 .data.fd = STDIN_FILENO,
175 };
912541b0
KS
176
177 fd_ep = epoll_create1(EPOLL_CLOEXEC);
cc4c1d22 178 assert_se(fd_ep >= 0);
912541b0
KS
179
180 udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
cc4c1d22 181 assert_se(udev_monitor != NULL);
912541b0 182
cc4c1d22
ZJS
183 fd_udev = udev_monitor_get_fd(udev_monitor);
184 ep_udev.data.fd = fd_udev;
912541b0 185
cc4c1d22
ZJS
186 assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) >= 0);
187 assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) >= 0);
188 assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") >= 0);
912541b0 189
cc4c1d22 190 assert_se(udev_monitor_enable_receiving(udev_monitor) >= 0);
912541b0 191
cc4c1d22
ZJS
192 assert_se(epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) >= 0);
193 assert_se(epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) >= 0);
912541b0
KS
194
195 for (;;) {
196 int fdcount;
197 struct epoll_event ev[4];
198 struct udev_device *device;
199 int i;
200
201 printf("waiting for events from udev, press ENTER to exit\n");
cc4c1d22 202 fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1);
912541b0
KS
203 printf("epoll fd count: %i\n", fdcount);
204
205 for (i = 0; i < fdcount; i++) {
206 if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) {
207 device = udev_monitor_receive_device(udev_monitor);
208 if (device == NULL) {
209 printf("no device from socket\n");
210 continue;
211 }
212 print_device(device);
213 udev_device_unref(device);
214 } else if (ev[i].data.fd == STDIN_FILENO && ev[i].events & EPOLLIN) {
215 printf("exiting loop\n");
cc4c1d22 216 return;
912541b0
KS
217 }
218 }
219 }
33a5cc29
KS
220}
221
cc4c1d22 222static void test_queue(struct udev *udev) {
912541b0 223 struct udev_queue *udev_queue;
cc4c1d22 224 bool empty;
912541b0
KS
225
226 udev_queue = udev_queue_new(udev);
cc4c1d22 227 assert_se(udev_queue);
912541b0 228
cc4c1d22
ZJS
229 empty = udev_queue_get_queue_is_empty(udev_queue);
230 log_info("queue is %s", empty ? "empty" : "not empty");
912541b0 231 udev_queue_unref(udev_queue);
64ccdf82
KS
232}
233
f168c273 234static int test_enumerate(struct udev *udev, const char *subsystem) {
912541b0 235 struct udev_enumerate *udev_enumerate;
c0c6a4fc 236 int r;
912541b0 237
cc4c1d22 238 log_info("enumerate '%s'", subsystem == NULL ? "<all>" : subsystem);
912541b0
KS
239 udev_enumerate = udev_enumerate_new(udev);
240 if (udev_enumerate == NULL)
241 return -1;
242 udev_enumerate_add_match_subsystem(udev_enumerate, subsystem);
243 udev_enumerate_scan_devices(udev_enumerate);
244 test_enumerate_print_list(udev_enumerate);
245 udev_enumerate_unref(udev_enumerate);
246
cc4c1d22 247 log_info("enumerate 'net' + duplicated scan + null + zero");
912541b0
KS
248 udev_enumerate = udev_enumerate_new(udev);
249 if (udev_enumerate == NULL)
250 return -1;
251 udev_enumerate_add_match_subsystem(udev_enumerate, "net");
252 udev_enumerate_scan_devices(udev_enumerate);
253 udev_enumerate_scan_devices(udev_enumerate);
254 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
255 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
256 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
257 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
258 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
259 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
260 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
261 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
262 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
263 udev_enumerate_scan_devices(udev_enumerate);
264 test_enumerate_print_list(udev_enumerate);
265 udev_enumerate_unref(udev_enumerate);
266
cc4c1d22 267 log_info("enumerate 'block'");
912541b0
KS
268 udev_enumerate = udev_enumerate_new(udev);
269 if (udev_enumerate == NULL)
270 return -1;
271 udev_enumerate_add_match_subsystem(udev_enumerate,"block");
c0c6a4fc 272 r = udev_enumerate_add_match_is_initialized(udev_enumerate);
86ff9f11
TA
273 if (r < 0) {
274 udev_enumerate_unref(udev_enumerate);
c0c6a4fc 275 return r;
86ff9f11 276 }
912541b0
KS
277 udev_enumerate_scan_devices(udev_enumerate);
278 test_enumerate_print_list(udev_enumerate);
279 udev_enumerate_unref(udev_enumerate);
280
cc4c1d22 281 log_info("enumerate 'not block'");
912541b0
KS
282 udev_enumerate = udev_enumerate_new(udev);
283 if (udev_enumerate == NULL)
284 return -1;
285 udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block");
286 udev_enumerate_scan_devices(udev_enumerate);
287 test_enumerate_print_list(udev_enumerate);
288 udev_enumerate_unref(udev_enumerate);
289
cc4c1d22 290 log_info("enumerate 'pci, mem, vc'");
912541b0
KS
291 udev_enumerate = udev_enumerate_new(udev);
292 if (udev_enumerate == NULL)
293 return -1;
294 udev_enumerate_add_match_subsystem(udev_enumerate, "pci");
295 udev_enumerate_add_match_subsystem(udev_enumerate, "mem");
296 udev_enumerate_add_match_subsystem(udev_enumerate, "vc");
297 udev_enumerate_scan_devices(udev_enumerate);
298 test_enumerate_print_list(udev_enumerate);
299 udev_enumerate_unref(udev_enumerate);
300
cc4c1d22 301 log_info("enumerate 'subsystem'");
912541b0
KS
302 udev_enumerate = udev_enumerate_new(udev);
303 if (udev_enumerate == NULL)
304 return -1;
305 udev_enumerate_scan_subsystems(udev_enumerate);
306 test_enumerate_print_list(udev_enumerate);
307 udev_enumerate_unref(udev_enumerate);
308
cc4c1d22 309 log_info("enumerate 'property IF_FS_*=filesystem'");
912541b0
KS
310 udev_enumerate = udev_enumerate_new(udev);
311 if (udev_enumerate == NULL)
312 return -1;
313 udev_enumerate_add_match_property(udev_enumerate, "ID_FS*", "filesystem");
314 udev_enumerate_scan_devices(udev_enumerate);
315 test_enumerate_print_list(udev_enumerate);
316 udev_enumerate_unref(udev_enumerate);
317 return 0;
90d80c2e
KS
318}
319
872c8faa 320static void test_hwdb(struct udev *udev, const char *modalias) {
960787ae 321 struct udev_hwdb *hwdb;
2001208c
KS
322 struct udev_list_entry *entry;
323
324 hwdb = udev_hwdb_new(udev);
325
326 udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0))
cc4c1d22 327 log_info("'%s'='%s'", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
2001208c
KS
328
329 hwdb = udev_hwdb_unref(hwdb);
bdf7026e 330 assert_se(hwdb == NULL);
2001208c
KS
331}
332
01cbafe1
YW
333static void test_util_replace_whitespace_one_len(const char *str, size_t len, const char *expected) {
334 _cleanup_free_ char *result = NULL;
335 int r;
336
337 result = new(char, len + 1);
338 assert_se(result);
339 r = util_replace_whitespace(str, result, len);
340 assert_se((size_t) r == strlen(expected));
341 assert_se(streq(result, expected));
342}
343
344static void test_util_replace_whitespace_one(const char *str, const char *expected) {
345 test_util_replace_whitespace_one_len(str, strlen(str), expected);
346}
347
348static void test_util_replace_whitespace(void) {
349 test_util_replace_whitespace_one("hogehoge", "hogehoge");
350 test_util_replace_whitespace_one("hoge hoge", "hoge_hoge");
351 test_util_replace_whitespace_one(" hoge hoge ", "hoge_hoge");
352 test_util_replace_whitespace_one(" ", "");
353 test_util_replace_whitespace_one("hoge ", "hoge");
354
355 test_util_replace_whitespace_one_len("hoge hoge ", 9, "hoge_hoge");
356 test_util_replace_whitespace_one_len("hoge hoge ", 8, "hoge_hog");
357 test_util_replace_whitespace_one_len("hoge hoge ", 7, "hoge_ho");
358 test_util_replace_whitespace_one_len("hoge hoge ", 6, "hoge_h");
359 test_util_replace_whitespace_one_len("hoge hoge ", 5, "hoge");
360 test_util_replace_whitespace_one_len("hoge hoge ", 4, "hoge");
361 test_util_replace_whitespace_one_len("hoge hoge ", 3, "hog");
362 test_util_replace_whitespace_one_len("hoge hoge ", 2, "ho");
363 test_util_replace_whitespace_one_len("hoge hoge ", 1, "h");
364 test_util_replace_whitespace_one_len("hoge hoge ", 0, "");
365
366 test_util_replace_whitespace_one_len(" hoge hoge ", 9, "hoge_hoge");
367 test_util_replace_whitespace_one_len(" hoge hoge ", 8, "hoge_hog");
368 test_util_replace_whitespace_one_len(" hoge hoge ", 7, "hoge_ho");
369 test_util_replace_whitespace_one_len(" hoge hoge ", 6, "hoge_h");
370 test_util_replace_whitespace_one_len(" hoge hoge ", 5, "hoge");
371 test_util_replace_whitespace_one_len(" hoge hoge ", 4, "hoge");
372 test_util_replace_whitespace_one_len(" hoge hoge ", 3, "hog");
373 test_util_replace_whitespace_one_len(" hoge hoge ", 2, "ho");
374 test_util_replace_whitespace_one_len(" hoge hoge ", 1, "h");
375 test_util_replace_whitespace_one_len(" hoge hoge ", 0, "");
376}
377
f168c273 378int main(int argc, char *argv[]) {
8e766630 379 _cleanup_(udev_unrefp) struct udev *udev = NULL;
301a9c67 380 bool arg_monitor = false;
912541b0 381 static const struct option options[] = {
cc4c1d22 382 { "syspath", required_argument, NULL, 'p' },
912541b0 383 { "subsystem", required_argument, NULL, 's' },
cc4c1d22
ZJS
384 { "debug", no_argument, NULL, 'd' },
385 { "help", no_argument, NULL, 'h' },
386 { "version", no_argument, NULL, 'V' },
301a9c67 387 { "monitor", no_argument, NULL, 'm' },
912541b0
KS
388 {}
389 };
390 const char *syspath = "/devices/virtual/mem/null";
391 const char *subsystem = NULL;
601185b4 392 int c;
912541b0
KS
393
394 udev = udev_new();
cc4c1d22 395 log_info("context: %p", udev);
912541b0 396 if (udev == NULL) {
cc4c1d22 397 log_info("no context");
912541b0
KS
398 return 1;
399 }
912541b0 400
63547675 401 while ((c = getopt_long(argc, argv, "p:s:dhVm", options, NULL)) >= 0)
601185b4 402 switch (c) {
912541b0 403
912541b0
KS
404 case 'p':
405 syspath = optarg;
406 break;
601185b4 407
912541b0
KS
408 case 's':
409 subsystem = optarg;
410 break;
601185b4 411
912541b0 412 case 'd':
25e773ee
KS
413 if (log_get_max_level() < LOG_INFO)
414 log_set_max_level(LOG_INFO);
912541b0 415 break;
601185b4 416
912541b0
KS
417 case 'h':
418 printf("--debug --syspath= --subsystem= --help\n");
cc4c1d22 419 return EXIT_SUCCESS;
601185b4 420
912541b0 421 case 'V':
948aaa7c 422 printf("%s\n", PACKAGE_VERSION);
cc4c1d22 423 return EXIT_SUCCESS;
601185b4 424
301a9c67
ZJS
425 case 'm':
426 arg_monitor = true;
427 break;
428
601185b4 429 case '?':
cc4c1d22 430 return EXIT_FAILURE;
601185b4
ZJS
431
432 default:
433 assert_not_reached("Unhandled option code.");
912541b0 434 }
601185b4 435
912541b0 436 /* add sys path if needed */
cc4c1d22
ZJS
437 if (!startswith(syspath, "/sys"))
438 syspath = strjoina("/sys/", syspath);
912541b0
KS
439
440 test_device(udev, syspath);
441 test_device_devnum(udev);
cc4c1d22
ZJS
442 test_device_subsys_name(udev, "block", "sda");
443 test_device_subsys_name(udev, "subsystem", "pci");
444 test_device_subsys_name(udev, "drivers", "scsi:sd");
445 test_device_subsys_name(udev, "module", "printk");
912541b0
KS
446 test_device_parents(udev, syspath);
447
448 test_enumerate(udev, subsystem);
449
450 test_queue(udev);
451
2001208c
KS
452 test_hwdb(udev, "usb:v0D50p0011*");
453
301a9c67
ZJS
454 if (arg_monitor)
455 test_monitor(udev);
cc4c1d22 456
01cbafe1
YW
457 test_util_replace_whitespace();
458
cc4c1d22 459 return EXIT_SUCCESS;
33a5cc29 460}