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