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