xref: /third_party/eudev/test/test-libudev.c (revision 99ca880a)
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
38static 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
111static 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
125static 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
151static 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
164static 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
197static 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
218static 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        }
290out:
291        if (fd_ep >= 0)
292                close(fd_ep);
293        udev_monitor_unref(udev_monitor);
294        return 0;
295}
296
297static 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
311static 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
392static 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
406int 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);
478out:
479        udev_unref(udev);
480        return 0;
481}
482