1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
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.
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.
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/>.
23 #include <sys/epoll.h>
30 #include "stdio-util.h"
31 #include "string-util.h"
32 #include "udev-util.h"
35 static void print_device(struct udev_device
*device
) {
39 struct udev_list_entry
*list_entry
;
41 log_info("*** device: %p ***", device
);
42 str
= udev_device_get_action(device
);
44 log_info("action: '%s'", str
);
46 str
= udev_device_get_syspath(device
);
47 log_info("syspath: '%s'", str
);
49 str
= udev_device_get_sysname(device
);
50 log_info("sysname: '%s'", str
);
52 str
= udev_device_get_sysnum(device
);
54 log_info("sysnum: '%s'", str
);
56 str
= udev_device_get_devpath(device
);
57 log_info("devpath: '%s'", str
);
59 str
= udev_device_get_subsystem(device
);
61 log_info("subsystem: '%s'", str
);
63 str
= udev_device_get_devtype(device
);
65 log_info("devtype: '%s'", str
);
67 str
= udev_device_get_driver(device
);
69 log_info("driver: '%s'", str
);
71 str
= udev_device_get_devnode(device
);
73 log_info("devname: '%s'", str
);
75 devnum
= udev_device_get_devnum(device
);
76 if (major(devnum
) > 0)
77 log_info("devnum: %u:%u", major(devnum
), minor(devnum
));
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
));
85 log_info("found %i links", count
);
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
));
95 log_info("found %i properties", count
);
97 str
= udev_device_get_property_value(device
, "MAJOR");
99 log_info("MAJOR: '%s'", str
);
101 str
= udev_device_get_sysattr_value(device
, "dev");
103 log_info("attr{dev}: '%s'", str
);
106 static void test_device(struct udev
*udev
, const char *syspath
) {
107 _cleanup_udev_device_unref_
struct udev_device
*device
;
109 log_info("looking at device: %s", syspath
);
110 device
= udev_device_new_from_syspath(udev
, syspath
);
112 log_warning_errno(errno
, "udev_device_new_from_syspath: %m");
114 print_device(device
);
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
;
121 log_info("looking at device: %s", syspath
);
122 device
= udev_device_new_from_syspath(udev
, syspath
);
126 log_info("looking at parents");
127 device_parent
= device
;
129 print_device(device_parent
);
130 device_parent
= udev_device_get_parent(device_parent
);
131 } while (device_parent
!= NULL
);
133 log_info("looking at parents again");
134 device_parent
= device
;
136 print_device(device_parent
);
137 device_parent
= udev_device_get_parent(device_parent
);
138 } while (device_parent
!= NULL
);
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
;
145 log_info("looking up device: %u:%u", major(devnum
), minor(devnum
));
146 device
= udev_device_new_from_devnum(udev
, 'c', devnum
);
148 log_warning_errno(errno
, "udev_device_new_from_devnum: %m");
150 print_device(device
);
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
;
156 log_info("looking up device: '%s:%s'", subsys
, dev
);
157 device
= udev_device_new_from_subsystem_sysname(udev
, subsys
, dev
);
159 log_warning_errno(errno
, "udev_device_new_from_subsystem_sysname: %m");
161 print_device(device
);
164 static int test_enumerate_print_list(struct udev_enumerate
*enumerate
) {
165 struct udev_list_entry
*list_entry
;
168 udev_list_entry_foreach(list_entry
, udev_enumerate_get_list_entry(enumerate
)) {
169 struct udev_device
*device
;
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
);
181 log_info("found %i devices", count
);
185 static void test_monitor(struct udev
*udev
) {
186 _cleanup_udev_monitor_unref_
struct udev_monitor
*udev_monitor
;
187 _cleanup_close_
int fd_ep
;
189 struct epoll_event ep_udev
= {
193 .data
.fd
= STDIN_FILENO
,
196 fd_ep
= epoll_create1(EPOLL_CLOEXEC
);
197 assert_se(fd_ep
>= 0);
199 udev_monitor
= udev_monitor_new_from_netlink(udev
, "udev");
200 assert_se(udev_monitor
!= NULL
);
202 fd_udev
= udev_monitor_get_fd(udev_monitor
);
203 ep_udev
.data
.fd
= fd_udev
;
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);
209 assert_se(udev_monitor_enable_receiving(udev_monitor
) >= 0);
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);
216 struct epoll_event ev
[4];
217 struct udev_device
*device
;
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
);
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");
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");
241 static void test_queue(struct udev
*udev
) {
242 struct udev_queue
*udev_queue
;
245 udev_queue
= udev_queue_new(udev
);
246 assert_se(udev_queue
);
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
);
253 static int test_enumerate(struct udev
*udev
, const char *subsystem
) {
254 struct udev_enumerate
*udev_enumerate
;
257 log_info("enumerate '%s'", subsystem
== NULL
? "<all>" : subsystem
);
258 udev_enumerate
= udev_enumerate_new(udev
);
259 if (udev_enumerate
== NULL
)
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
);
266 log_info("enumerate 'net' + duplicated scan + null + zero");
267 udev_enumerate
= udev_enumerate_new(udev
);
268 if (udev_enumerate
== NULL
)
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
);
286 log_info("enumerate 'block'");
287 udev_enumerate
= udev_enumerate_new(udev
);
288 if (udev_enumerate
== NULL
)
290 udev_enumerate_add_match_subsystem(udev_enumerate
,"block");
291 r
= udev_enumerate_add_match_is_initialized(udev_enumerate
);
293 udev_enumerate_unref(udev_enumerate
);
296 udev_enumerate_scan_devices(udev_enumerate
);
297 test_enumerate_print_list(udev_enumerate
);
298 udev_enumerate_unref(udev_enumerate
);
300 log_info("enumerate 'not block'");
301 udev_enumerate
= udev_enumerate_new(udev
);
302 if (udev_enumerate
== NULL
)
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
);
309 log_info("enumerate 'pci, mem, vc'");
310 udev_enumerate
= udev_enumerate_new(udev
);
311 if (udev_enumerate
== NULL
)
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
);
320 log_info("enumerate 'subsystem'");
321 udev_enumerate
= udev_enumerate_new(udev
);
322 if (udev_enumerate
== NULL
)
324 udev_enumerate_scan_subsystems(udev_enumerate
);
325 test_enumerate_print_list(udev_enumerate
);
326 udev_enumerate_unref(udev_enumerate
);
328 log_info("enumerate 'property IF_FS_*=filesystem'");
329 udev_enumerate
= udev_enumerate_new(udev
);
330 if (udev_enumerate
== NULL
)
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
);
339 static void test_hwdb(struct udev
*udev
, const char *modalias
) {
340 struct udev_hwdb
*hwdb
;
341 struct udev_list_entry
*entry
;
343 hwdb
= udev_hwdb_new(udev
);
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
));
348 hwdb
= udev_hwdb_unref(hwdb
);
349 assert_se(hwdb
== NULL
);
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' },
364 const char *syspath
= "/devices/virtual/mem/null";
365 const char *subsystem
= NULL
;
369 log_info("context: %p", udev
);
371 log_info("no context");
375 while ((c
= getopt_long(argc
, argv
, "p:s:dhV", options
, NULL
)) >= 0)
387 if (log_get_max_level() < LOG_INFO
)
388 log_set_max_level(LOG_INFO
);
392 printf("--debug --syspath= --subsystem= --help\n");
396 printf("%s\n", PACKAGE_VERSION
);
407 assert_not_reached("Unhandled option code.");
411 /* add sys path if needed */
412 if (!startswith(syspath
, "/sys"))
413 syspath
= strjoina("/sys/", syspath
);
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");
422 test_device_parents(udev
, syspath
);
424 test_enumerate(udev
, subsystem
);
428 test_hwdb(udev
, "usb:v0D50p0011*");