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