]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-libudev.c
Merge pull request #7376 from keszybz/simplify-root-options
[thirdparty/systemd.git] / src / test / test-libudev.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
1298001e
KS
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***/
33a5cc29 20
b2d9e4f2 21#include <getopt.h>
07630cea 22#include <stdio.h>
f2fd4d27 23#include <sys/epoll.h>
07630cea 24#include <unistd.h>
ba6929f6 25
33a5cc29 26#include "libudev.h"
b4bbcaa9 27
cc4c1d22
ZJS
28#include "fd-util.h"
29#include "log.h"
d054f0a4 30#include "stdio-util.h"
07630cea 31#include "string-util.h"
1ca208fb 32#include "udev-util.h"
33502ffe 33#include "util.h"
33a5cc29 34
f168c273 35static void print_device(struct udev_device *device) {
912541b0
KS
36 const char *str;
37 dev_t devnum;
38 int count;
39 struct udev_list_entry *list_entry;
40
cc4c1d22 41 log_info("*** device: %p ***", device);
912541b0
KS
42 str = udev_device_get_action(device);
43 if (str != NULL)
cc4c1d22 44 log_info("action: '%s'", str);
912541b0
KS
45
46 str = udev_device_get_syspath(device);
cc4c1d22 47 log_info("syspath: '%s'", str);
912541b0
KS
48
49 str = udev_device_get_sysname(device);
cc4c1d22 50 log_info("sysname: '%s'", str);
912541b0
KS
51
52 str = udev_device_get_sysnum(device);
53 if (str != NULL)
cc4c1d22 54 log_info("sysnum: '%s'", str);
912541b0
KS
55
56 str = udev_device_get_devpath(device);
cc4c1d22 57 log_info("devpath: '%s'", str);
912541b0
KS
58
59 str = udev_device_get_subsystem(device);
60 if (str != NULL)
cc4c1d22 61 log_info("subsystem: '%s'", str);
912541b0
KS
62
63 str = udev_device_get_devtype(device);
64 if (str != NULL)
cc4c1d22 65 log_info("devtype: '%s'", str);
912541b0
KS
66
67 str = udev_device_get_driver(device);
68 if (str != NULL)
cc4c1d22 69 log_info("driver: '%s'", str);
912541b0
KS
70
71 str = udev_device_get_devnode(device);
72 if (str != NULL)
cc4c1d22 73 log_info("devname: '%s'", str);
912541b0
KS
74
75 devnum = udev_device_get_devnum(device);
76 if (major(devnum) > 0)
cc4c1d22 77 log_info("devnum: %u:%u", major(devnum), minor(devnum));
912541b0
KS
78
79 count = 0;
80 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
cc4c1d22 81 log_info("link: '%s'", udev_list_entry_get_name(list_entry));
912541b0
KS
82 count++;
83 }
84 if (count > 0)
cc4c1d22 85 log_info("found %i links", count);
912541b0
KS
86
87 count = 0;
88 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) {
cc4c1d22 89 log_info("property: '%s=%s'",
912541b0
KS
90 udev_list_entry_get_name(list_entry),
91 udev_list_entry_get_value(list_entry));
92 count++;
93 }
94 if (count > 0)
cc4c1d22 95 log_info("found %i properties", count);
912541b0
KS
96
97 str = udev_device_get_property_value(device, "MAJOR");
98 if (str != NULL)
cc4c1d22 99 log_info("MAJOR: '%s'", str);
912541b0
KS
100
101 str = udev_device_get_sysattr_value(device, "dev");
102 if (str != NULL)
cc4c1d22 103 log_info("attr{dev}: '%s'", str);
ba6929f6
KS
104}
105
cc4c1d22 106static void test_device(struct udev *udev, const char *syspath) {
1ca208fb 107 _cleanup_udev_device_unref_ struct udev_device *device;
912541b0 108
cc4c1d22 109 log_info("looking at device: %s", syspath);
912541b0 110 device = udev_device_new_from_syspath(udev, syspath);
cc4c1d22
ZJS
111 if (device == NULL)
112 log_warning_errno(errno, "udev_device_new_from_syspath: %m");
113 else
114 print_device(device);
33a5cc29
KS
115}
116
cc4c1d22 117static void test_device_parents(struct udev *udev, const char *syspath) {
1ca208fb 118 _cleanup_udev_device_unref_ struct udev_device *device;
912541b0
KS
119 struct udev_device *device_parent;
120
cc4c1d22 121 log_info("looking at device: %s", syspath);
912541b0
KS
122 device = udev_device_new_from_syspath(udev, syspath);
123 if (device == NULL)
cc4c1d22 124 return;
912541b0 125
cc4c1d22 126 log_info("looking at parents");
912541b0
KS
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
cc4c1d22 133 log_info("looking at parents again");
912541b0
KS
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);
4ad3a37f
KS
139}
140
cc4c1d22 141static void test_device_devnum(struct udev *udev) {
912541b0 142 dev_t devnum = makedev(1, 3);
cc4c1d22 143 _cleanup_udev_device_unref_ struct udev_device *device;
912541b0 144
cc4c1d22 145 log_info("looking up device: %u:%u", major(devnum), minor(devnum));
912541b0
KS
146 device = udev_device_new_from_devnum(udev, 'c', devnum);
147 if (device == NULL)
cc4c1d22
ZJS
148 log_warning_errno(errno, "udev_device_new_from_devnum: %m");
149 else
150 print_device(device);
4c9dff47
KS
151}
152
cc4c1d22
ZJS
153static void test_device_subsys_name(struct udev *udev, const char *subsys, const char *dev) {
154 _cleanup_udev_device_unref_ struct udev_device *device;
912541b0 155
cc4c1d22
ZJS
156 log_info("looking up device: '%s:%s'", subsys, dev);
157 device = udev_device_new_from_subsystem_sysname(udev, subsys, dev);
912541b0 158 if (device == NULL)
cc4c1d22
ZJS
159 log_warning_errno(errno, "udev_device_new_from_subsystem_sysname: %m");
160 else
161 print_device(device);
90d80c2e
KS
162}
163
f168c273 164static int test_enumerate_print_list(struct udev_enumerate *enumerate) {
912541b0
KS
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) {
cc4c1d22
ZJS
174 log_info("device: '%s' (%s)",
175 udev_device_get_syspath(device),
176 udev_device_get_subsystem(device));
912541b0
KS
177 udev_device_unref(device);
178 count++;
179 }
180 }
cc4c1d22 181 log_info("found %i devices", count);
912541b0 182 return count;
ba6929f6
KS
183}
184
cc4c1d22
ZJS
185static 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 };
912541b0
KS
195
196 fd_ep = epoll_create1(EPOLL_CLOEXEC);
cc4c1d22 197 assert_se(fd_ep >= 0);
912541b0
KS
198
199 udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
cc4c1d22 200 assert_se(udev_monitor != NULL);
912541b0 201
cc4c1d22
ZJS
202 fd_udev = udev_monitor_get_fd(udev_monitor);
203 ep_udev.data.fd = fd_udev;
912541b0 204
cc4c1d22
ZJS
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);
912541b0 208
cc4c1d22 209 assert_se(udev_monitor_enable_receiving(udev_monitor) >= 0);
912541b0 210
cc4c1d22
ZJS
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);
912541b0
KS
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");
cc4c1d22 221 fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1);
912541b0
KS
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");
cc4c1d22 235 return;
912541b0
KS
236 }
237 }
238 }
33a5cc29
KS
239}
240
cc4c1d22 241static void test_queue(struct udev *udev) {
912541b0 242 struct udev_queue *udev_queue;
cc4c1d22 243 bool empty;
912541b0
KS
244
245 udev_queue = udev_queue_new(udev);
cc4c1d22 246 assert_se(udev_queue);
912541b0 247
cc4c1d22
ZJS
248 empty = udev_queue_get_queue_is_empty(udev_queue);
249 log_info("queue is %s", empty ? "empty" : "not empty");
912541b0 250 udev_queue_unref(udev_queue);
64ccdf82
KS
251}
252
f168c273 253static int test_enumerate(struct udev *udev, const char *subsystem) {
912541b0 254 struct udev_enumerate *udev_enumerate;
c0c6a4fc 255 int r;
912541b0 256
cc4c1d22 257 log_info("enumerate '%s'", subsystem == NULL ? "<all>" : subsystem);
912541b0
KS
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
cc4c1d22 266 log_info("enumerate 'net' + duplicated scan + null + zero");
912541b0
KS
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
cc4c1d22 286 log_info("enumerate 'block'");
912541b0
KS
287 udev_enumerate = udev_enumerate_new(udev);
288 if (udev_enumerate == NULL)
289 return -1;
290 udev_enumerate_add_match_subsystem(udev_enumerate,"block");
c0c6a4fc 291 r = udev_enumerate_add_match_is_initialized(udev_enumerate);
86ff9f11
TA
292 if (r < 0) {
293 udev_enumerate_unref(udev_enumerate);
c0c6a4fc 294 return r;
86ff9f11 295 }
912541b0
KS
296 udev_enumerate_scan_devices(udev_enumerate);
297 test_enumerate_print_list(udev_enumerate);
298 udev_enumerate_unref(udev_enumerate);
299
cc4c1d22 300 log_info("enumerate 'not block'");
912541b0
KS
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
cc4c1d22 309 log_info("enumerate 'pci, mem, vc'");
912541b0
KS
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
cc4c1d22 320 log_info("enumerate 'subsystem'");
912541b0
KS
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
cc4c1d22 328 log_info("enumerate 'property IF_FS_*=filesystem'");
912541b0
KS
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;
90d80c2e
KS
337}
338
872c8faa 339static void test_hwdb(struct udev *udev, const char *modalias) {
960787ae 340 struct udev_hwdb *hwdb;
2001208c
KS
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))
cc4c1d22 346 log_info("'%s'='%s'", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
2001208c
KS
347
348 hwdb = udev_hwdb_unref(hwdb);
bdf7026e 349 assert_se(hwdb == NULL);
2001208c
KS
350}
351
f168c273 352int main(int argc, char *argv[]) {
cc4c1d22 353 _cleanup_udev_unref_ struct udev *udev = NULL;
301a9c67 354 bool arg_monitor = false;
912541b0 355 static const struct option options[] = {
cc4c1d22 356 { "syspath", required_argument, NULL, 'p' },
912541b0 357 { "subsystem", required_argument, NULL, 's' },
cc4c1d22
ZJS
358 { "debug", no_argument, NULL, 'd' },
359 { "help", no_argument, NULL, 'h' },
360 { "version", no_argument, NULL, 'V' },
301a9c67 361 { "monitor", no_argument, NULL, 'm' },
912541b0
KS
362 {}
363 };
364 const char *syspath = "/devices/virtual/mem/null";
365 const char *subsystem = NULL;
601185b4 366 int c;
912541b0
KS
367
368 udev = udev_new();
cc4c1d22 369 log_info("context: %p", udev);
912541b0 370 if (udev == NULL) {
cc4c1d22 371 log_info("no context");
912541b0
KS
372 return 1;
373 }
912541b0 374
601185b4
ZJS
375 while ((c = getopt_long(argc, argv, "p:s:dhV", options, NULL)) >= 0)
376 switch (c) {
912541b0 377
912541b0
KS
378 case 'p':
379 syspath = optarg;
380 break;
601185b4 381
912541b0
KS
382 case 's':
383 subsystem = optarg;
384 break;
601185b4 385
912541b0 386 case 'd':
25e773ee
KS
387 if (log_get_max_level() < LOG_INFO)
388 log_set_max_level(LOG_INFO);
912541b0 389 break;
601185b4 390
912541b0
KS
391 case 'h':
392 printf("--debug --syspath= --subsystem= --help\n");
cc4c1d22 393 return EXIT_SUCCESS;
601185b4 394
912541b0 395 case 'V':
948aaa7c 396 printf("%s\n", PACKAGE_VERSION);
cc4c1d22 397 return EXIT_SUCCESS;
601185b4 398
301a9c67
ZJS
399 case 'm':
400 arg_monitor = true;
401 break;
402
601185b4 403 case '?':
cc4c1d22 404 return EXIT_FAILURE;
601185b4
ZJS
405
406 default:
407 assert_not_reached("Unhandled option code.");
912541b0 408 }
601185b4 409
912541b0 410
912541b0 411 /* add sys path if needed */
cc4c1d22
ZJS
412 if (!startswith(syspath, "/sys"))
413 syspath = strjoina("/sys/", syspath);
912541b0
KS
414
415 test_device(udev, syspath);
416 test_device_devnum(udev);
cc4c1d22
ZJS
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
912541b0
KS
422 test_device_parents(udev, syspath);
423
424 test_enumerate(udev, subsystem);
425
426 test_queue(udev);
427
2001208c
KS
428 test_hwdb(udev, "usb:v0D50p0011*");
429
301a9c67
ZJS
430 if (arg_monitor)
431 test_monitor(udev);
cc4c1d22
ZJS
432
433 return EXIT_SUCCESS;
33a5cc29 434}