]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-libudev.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / test / test-libudev.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <getopt.h>
22 #include <stdio.h>
23 #include <sys/epoll.h>
24 #include <unistd.h>
25
26 #include "libudev.h"
27
28 #include "fd-util.h"
29 #include "log.h"
30 #include "stdio-util.h"
31 #include "string-util.h"
32 #include "udev-util.h"
33 #include "util.h"
34
35 static void print_device(struct udev_device *device) {
36 const char *str;
37 dev_t devnum;
38 int count;
39 struct udev_list_entry *list_entry;
40
41 log_info("*** device: %p ***", device);
42 str = udev_device_get_action(device);
43 if (str != NULL)
44 log_info("action: '%s'", str);
45
46 str = udev_device_get_syspath(device);
47 log_info("syspath: '%s'", str);
48
49 str = udev_device_get_sysname(device);
50 log_info("sysname: '%s'", str);
51
52 str = udev_device_get_sysnum(device);
53 if (str != NULL)
54 log_info("sysnum: '%s'", str);
55
56 str = udev_device_get_devpath(device);
57 log_info("devpath: '%s'", str);
58
59 str = udev_device_get_subsystem(device);
60 if (str != NULL)
61 log_info("subsystem: '%s'", str);
62
63 str = udev_device_get_devtype(device);
64 if (str != NULL)
65 log_info("devtype: '%s'", str);
66
67 str = udev_device_get_driver(device);
68 if (str != NULL)
69 log_info("driver: '%s'", str);
70
71 str = udev_device_get_devnode(device);
72 if (str != NULL)
73 log_info("devname: '%s'", str);
74
75 devnum = udev_device_get_devnum(device);
76 if (major(devnum) > 0)
77 log_info("devnum: %u:%u", major(devnum), minor(devnum));
78
79 count = 0;
80 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
81 log_info("link: '%s'", udev_list_entry_get_name(list_entry));
82 count++;
83 }
84 if (count > 0)
85 log_info("found %i links", count);
86
87 count = 0;
88 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) {
89 log_info("property: '%s=%s'",
90 udev_list_entry_get_name(list_entry),
91 udev_list_entry_get_value(list_entry));
92 count++;
93 }
94 if (count > 0)
95 log_info("found %i properties", count);
96
97 str = udev_device_get_property_value(device, "MAJOR");
98 if (str != NULL)
99 log_info("MAJOR: '%s'", str);
100
101 str = udev_device_get_sysattr_value(device, "dev");
102 if (str != NULL)
103 log_info("attr{dev}: '%s'", str);
104 }
105
106 static void test_device(struct udev *udev, const char *syspath) {
107 _cleanup_udev_device_unref_ struct udev_device *device;
108
109 log_info("looking at device: %s", syspath);
110 device = udev_device_new_from_syspath(udev, syspath);
111 if (device == NULL)
112 log_warning_errno(errno, "udev_device_new_from_syspath: %m");
113 else
114 print_device(device);
115 }
116
117 static void test_device_parents(struct udev *udev, const char *syspath) {
118 _cleanup_udev_device_unref_ struct udev_device *device;
119 struct udev_device *device_parent;
120
121 log_info("looking at device: %s", syspath);
122 device = udev_device_new_from_syspath(udev, syspath);
123 if (device == NULL)
124 return;
125
126 log_info("looking at parents");
127 device_parent = device;
128 do {
129 print_device(device_parent);
130 device_parent = udev_device_get_parent(device_parent);
131 } while (device_parent != NULL);
132
133 log_info("looking at parents again");
134 device_parent = device;
135 do {
136 print_device(device_parent);
137 device_parent = udev_device_get_parent(device_parent);
138 } while (device_parent != NULL);
139 }
140
141 static void test_device_devnum(struct udev *udev) {
142 dev_t devnum = makedev(1, 3);
143 _cleanup_udev_device_unref_ struct udev_device *device;
144
145 log_info("looking up device: %u:%u", major(devnum), minor(devnum));
146 device = udev_device_new_from_devnum(udev, 'c', devnum);
147 if (device == NULL)
148 log_warning_errno(errno, "udev_device_new_from_devnum: %m");
149 else
150 print_device(device);
151 }
152
153 static void test_device_subsys_name(struct udev *udev, const char *subsys, const char *dev) {
154 _cleanup_udev_device_unref_ struct udev_device *device;
155
156 log_info("looking up device: '%s:%s'", subsys, dev);
157 device = udev_device_new_from_subsystem_sysname(udev, subsys, dev);
158 if (device == NULL)
159 log_warning_errno(errno, "udev_device_new_from_subsystem_sysname: %m");
160 else
161 print_device(device);
162 }
163
164 static int test_enumerate_print_list(struct udev_enumerate *enumerate) {
165 struct udev_list_entry *list_entry;
166 int count = 0;
167
168 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) {
169 struct udev_device *device;
170
171 device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate),
172 udev_list_entry_get_name(list_entry));
173 if (device != NULL) {
174 log_info("device: '%s' (%s)",
175 udev_device_get_syspath(device),
176 udev_device_get_subsystem(device));
177 udev_device_unref(device);
178 count++;
179 }
180 }
181 log_info("found %i devices", count);
182 return count;
183 }
184
185 static void test_monitor(struct udev *udev) {
186 _cleanup_udev_monitor_unref_ struct udev_monitor *udev_monitor;
187 _cleanup_close_ int fd_ep;
188 int fd_udev;
189 struct epoll_event ep_udev = {
190 .events = EPOLLIN,
191 }, ep_stdin = {
192 .events = EPOLLIN,
193 .data.fd = STDIN_FILENO,
194 };
195
196 fd_ep = epoll_create1(EPOLL_CLOEXEC);
197 assert_se(fd_ep >= 0);
198
199 udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
200 assert_se(udev_monitor != NULL);
201
202 fd_udev = udev_monitor_get_fd(udev_monitor);
203 ep_udev.data.fd = fd_udev;
204
205 assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) >= 0);
206 assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) >= 0);
207 assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") >= 0);
208
209 assert_se(udev_monitor_enable_receiving(udev_monitor) >= 0);
210
211 assert_se(epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) >= 0);
212 assert_se(epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) >= 0);
213
214 for (;;) {
215 int fdcount;
216 struct epoll_event ev[4];
217 struct udev_device *device;
218 int i;
219
220 printf("waiting for events from udev, press ENTER to exit\n");
221 fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1);
222 printf("epoll fd count: %i\n", fdcount);
223
224 for (i = 0; i < fdcount; i++) {
225 if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) {
226 device = udev_monitor_receive_device(udev_monitor);
227 if (device == NULL) {
228 printf("no device from socket\n");
229 continue;
230 }
231 print_device(device);
232 udev_device_unref(device);
233 } else if (ev[i].data.fd == STDIN_FILENO && ev[i].events & EPOLLIN) {
234 printf("exiting loop\n");
235 return;
236 }
237 }
238 }
239 }
240
241 static void test_queue(struct udev *udev) {
242 struct udev_queue *udev_queue;
243 bool empty;
244
245 udev_queue = udev_queue_new(udev);
246 assert_se(udev_queue);
247
248 empty = udev_queue_get_queue_is_empty(udev_queue);
249 log_info("queue is %s", empty ? "empty" : "not empty");
250 udev_queue_unref(udev_queue);
251 }
252
253 static int test_enumerate(struct udev *udev, const char *subsystem) {
254 struct udev_enumerate *udev_enumerate;
255 int r;
256
257 log_info("enumerate '%s'", subsystem == NULL ? "<all>" : subsystem);
258 udev_enumerate = udev_enumerate_new(udev);
259 if (udev_enumerate == NULL)
260 return -1;
261 udev_enumerate_add_match_subsystem(udev_enumerate, subsystem);
262 udev_enumerate_scan_devices(udev_enumerate);
263 test_enumerate_print_list(udev_enumerate);
264 udev_enumerate_unref(udev_enumerate);
265
266 log_info("enumerate 'net' + duplicated scan + null + zero");
267 udev_enumerate = udev_enumerate_new(udev);
268 if (udev_enumerate == NULL)
269 return -1;
270 udev_enumerate_add_match_subsystem(udev_enumerate, "net");
271 udev_enumerate_scan_devices(udev_enumerate);
272 udev_enumerate_scan_devices(udev_enumerate);
273 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
274 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
275 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
276 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
277 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
278 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
279 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
280 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
281 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
282 udev_enumerate_scan_devices(udev_enumerate);
283 test_enumerate_print_list(udev_enumerate);
284 udev_enumerate_unref(udev_enumerate);
285
286 log_info("enumerate 'block'");
287 udev_enumerate = udev_enumerate_new(udev);
288 if (udev_enumerate == NULL)
289 return -1;
290 udev_enumerate_add_match_subsystem(udev_enumerate,"block");
291 r = udev_enumerate_add_match_is_initialized(udev_enumerate);
292 if (r < 0) {
293 udev_enumerate_unref(udev_enumerate);
294 return r;
295 }
296 udev_enumerate_scan_devices(udev_enumerate);
297 test_enumerate_print_list(udev_enumerate);
298 udev_enumerate_unref(udev_enumerate);
299
300 log_info("enumerate 'not block'");
301 udev_enumerate = udev_enumerate_new(udev);
302 if (udev_enumerate == NULL)
303 return -1;
304 udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block");
305 udev_enumerate_scan_devices(udev_enumerate);
306 test_enumerate_print_list(udev_enumerate);
307 udev_enumerate_unref(udev_enumerate);
308
309 log_info("enumerate 'pci, mem, vc'");
310 udev_enumerate = udev_enumerate_new(udev);
311 if (udev_enumerate == NULL)
312 return -1;
313 udev_enumerate_add_match_subsystem(udev_enumerate, "pci");
314 udev_enumerate_add_match_subsystem(udev_enumerate, "mem");
315 udev_enumerate_add_match_subsystem(udev_enumerate, "vc");
316 udev_enumerate_scan_devices(udev_enumerate);
317 test_enumerate_print_list(udev_enumerate);
318 udev_enumerate_unref(udev_enumerate);
319
320 log_info("enumerate 'subsystem'");
321 udev_enumerate = udev_enumerate_new(udev);
322 if (udev_enumerate == NULL)
323 return -1;
324 udev_enumerate_scan_subsystems(udev_enumerate);
325 test_enumerate_print_list(udev_enumerate);
326 udev_enumerate_unref(udev_enumerate);
327
328 log_info("enumerate 'property IF_FS_*=filesystem'");
329 udev_enumerate = udev_enumerate_new(udev);
330 if (udev_enumerate == NULL)
331 return -1;
332 udev_enumerate_add_match_property(udev_enumerate, "ID_FS*", "filesystem");
333 udev_enumerate_scan_devices(udev_enumerate);
334 test_enumerate_print_list(udev_enumerate);
335 udev_enumerate_unref(udev_enumerate);
336 return 0;
337 }
338
339 static void test_hwdb(struct udev *udev, const char *modalias) {
340 struct udev_hwdb *hwdb;
341 struct udev_list_entry *entry;
342
343 hwdb = udev_hwdb_new(udev);
344
345 udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0))
346 log_info("'%s'='%s'", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
347
348 hwdb = udev_hwdb_unref(hwdb);
349 assert_se(hwdb == NULL);
350 }
351
352 int main(int argc, char *argv[]) {
353 _cleanup_udev_unref_ struct udev *udev = NULL;
354 bool arg_monitor = false;
355 static const struct option options[] = {
356 { "syspath", required_argument, NULL, 'p' },
357 { "subsystem", required_argument, NULL, 's' },
358 { "debug", no_argument, NULL, 'd' },
359 { "help", no_argument, NULL, 'h' },
360 { "version", no_argument, NULL, 'V' },
361 { "monitor", no_argument, NULL, 'm' },
362 {}
363 };
364 const char *syspath = "/devices/virtual/mem/null";
365 const char *subsystem = NULL;
366 int c;
367
368 udev = udev_new();
369 log_info("context: %p", udev);
370 if (udev == NULL) {
371 log_info("no context");
372 return 1;
373 }
374
375 while ((c = getopt_long(argc, argv, "p:s:dhV", options, NULL)) >= 0)
376 switch (c) {
377
378 case 'p':
379 syspath = optarg;
380 break;
381
382 case 's':
383 subsystem = optarg;
384 break;
385
386 case 'd':
387 if (log_get_max_level() < LOG_INFO)
388 log_set_max_level(LOG_INFO);
389 break;
390
391 case 'h':
392 printf("--debug --syspath= --subsystem= --help\n");
393 return EXIT_SUCCESS;
394
395 case 'V':
396 printf("%s\n", PACKAGE_VERSION);
397 return EXIT_SUCCESS;
398
399 case 'm':
400 arg_monitor = true;
401 break;
402
403 case '?':
404 return EXIT_FAILURE;
405
406 default:
407 assert_not_reached("Unhandled option code.");
408 }
409
410
411 /* add sys path if needed */
412 if (!startswith(syspath, "/sys"))
413 syspath = strjoina("/sys/", syspath);
414
415 test_device(udev, syspath);
416 test_device_devnum(udev);
417 test_device_subsys_name(udev, "block", "sda");
418 test_device_subsys_name(udev, "subsystem", "pci");
419 test_device_subsys_name(udev, "drivers", "scsi:sd");
420 test_device_subsys_name(udev, "module", "printk");
421
422 test_device_parents(udev, syspath);
423
424 test_enumerate(udev, subsystem);
425
426 test_queue(udev);
427
428 test_hwdb(udev, "usb:v0D50p0011*");
429
430 if (arg_monitor)
431 test_monitor(udev);
432
433 return EXIT_SUCCESS;
434 }