X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev%2Fudevadm-monitor.c;h=f3a72cf17e3d283a4d2a5ced43d06934567a4995;hp=10b2f2e71b8c1ce0f2d4b49f153bcb30342b7115;hb=8958da13c72024c4eaa2996b86fce2959e452db4;hpb=dacea9ff6be55f1b115c13b1ab530812d0d66879 diff --git a/udev/udevadm-monitor.c b/udev/udevadm-monitor.c index 10b2f2e71..f3a72cf17 100644 --- a/udev/udevadm-monitor.c +++ b/udev/udevadm-monitor.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2008 Kay Sievers + * Copyright (C) 2004-2010 Kay Sievers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,21 +27,21 @@ #include #include #include -#include +#include #include #include #include "udev.h" -static int udev_exit; +static bool udev_exit; -static void asmlinkage sig_handler(int signum) +static void sig_handler(int signum) { if (signum == SIGINT || signum == SIGTERM) - udev_exit = 1; + udev_exit = true; } -static void print_device(struct udev_device *device, const char *source, int env) +static void print_device(struct udev_device *device, const char *source, int prop) { struct timeval tv; struct timezone tz; @@ -53,7 +53,7 @@ static void print_device(struct udev_device *device, const char *source, int env udev_device_get_action(device), udev_device_get_devpath(device), udev_device_get_subsystem(device)); - if (env) { + if (prop) { struct udev_list_entry *list_entry; udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) @@ -67,67 +67,101 @@ static void print_device(struct udev_device *device, const char *source, int env int udevadm_monitor(struct udev *udev, int argc, char *argv[]) { struct sigaction act; + sigset_t mask; int option; - int env = 0; - int print_kernel = 0; - int print_udev = 0; + bool prop = false; + bool print_kernel = false; + bool print_udev = false; struct udev_list_node subsystem_match_list; + struct udev_list_node tag_match_list; struct udev_monitor *udev_monitor = NULL; struct udev_monitor *kernel_monitor = NULL; - fd_set readfds; + int fd_ep = -1; + int fd_kernel = -1, fd_udev = -1; + struct epoll_event ep_kernel, ep_udev; int rc = 0; static const struct option options[] = { + { "property", no_argument, NULL, 'p' }, { "environment", no_argument, NULL, 'e' }, { "kernel", no_argument, NULL, 'k' }, { "udev", no_argument, NULL, 'u' }, { "subsystem-match", required_argument, NULL, 's' }, + { "tag-match", required_argument, NULL, 't' }, { "help", no_argument, NULL, 'h' }, {} }; udev_list_init(&subsystem_match_list); - while (1) { - option = getopt_long(argc, argv, "ekus:h", options, NULL); + udev_list_init(&tag_match_list); + + for (;;) { + option = getopt_long(argc, argv, "pekus:t:h", options, NULL); if (option == -1) break; switch (option) { + case 'p': case 'e': - env = 1; + prop = true; break; case 'k': - print_kernel = 1; + print_kernel = true; break; case 'u': - print_udev = 1; + print_udev = true; break; case 's': - udev_list_entry_add(udev, &subsystem_match_list, optarg, NULL, 1, 0); + { + char subsys[UTIL_NAME_SIZE]; + char *devtype; + + util_strscpy(subsys, sizeof(subsys), optarg); + devtype = strchr(subsys, '/'); + if (devtype != NULL) { + devtype[0] = '\0'; + devtype++; + } + udev_list_entry_add(udev, &subsystem_match_list, subsys, devtype, 0); + break; + } + case 't': + udev_list_entry_add(udev, &tag_match_list, optarg, NULL, 0); break; case 'h': - printf("Usage: udevadm monitor [--environment] [--kernel] [--udev] [--help]\n" - " --env print the whole event environment\n" - " --kernel print kernel uevents\n" - " --udev print udev events\n" + printf("Usage: udevadm monitor [--property] [--kernel] [--udev] [--help]\n" + " --property print the event properties\n" + " --kernel print kernel uevents\n" + " --udev print udev events\n" + " --subsystem-match= filter events by subsystem\n" + " --tag-match= filter events by tag\n" " --help\n\n"); - default: goto out; } } if (!print_kernel && !print_udev) { - print_kernel = 1; - print_udev =1; + print_kernel = true; + print_udev = true; } /* set signal handlers */ memset(&act, 0x00, sizeof(struct sigaction)); - act.sa_handler = (void (*)(int)) sig_handler; + act.sa_handler = sig_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_RESTART; sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGTERM); + sigprocmask(SIG_UNBLOCK, &mask, NULL); + + fd_ep = epoll_create1(EPOLL_CLOEXEC); + if (fd_ep < 0) { + err(udev, "error creating epoll fd: %m\n"); + goto out; + } printf("monitor will print the received events for:\n"); if (print_udev) { @@ -139,78 +173,116 @@ int udevadm_monitor(struct udev *udev, int argc, char *argv[]) rc = 1; goto out; } + udev_monitor_set_receive_buffer_size(udev_monitor, 128*1024*1024); + fd_udev = udev_monitor_get_fd(udev_monitor); udev_list_entry_foreach(entry, udev_list_get_entry(&subsystem_match_list)) { const char *subsys = udev_list_entry_get_name(entry); + const char *devtype = udev_list_entry_get_value(entry); - if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, subsys, NULL) < 0) + if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, subsys, devtype) < 0) fprintf(stderr, "error: unable to apply subsystem filter '%s'\n", subsys); } + udev_list_entry_foreach(entry, udev_list_get_entry(&tag_match_list)) { + const char *tag = udev_list_entry_get_name(entry); + + if (udev_monitor_filter_add_match_tag(udev_monitor, tag) < 0) + fprintf(stderr, "error: unable to apply tag filter '%s'\n", tag); + } + if (udev_monitor_enable_receiving(udev_monitor) < 0) { fprintf(stderr, "error: unable to subscribe to udev events\n"); rc = 2; goto out; } + + memset(&ep_udev, 0, sizeof(struct epoll_event)); + ep_udev.events = EPOLLIN; + ep_udev.data.fd = fd_udev; + if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) { + err(udev, "fail to add fd to epoll: %m\n"); + goto out; + } + printf("UDEV - the event which udev sends out after rule processing\n"); } + if (print_kernel) { + struct udev_list_entry *entry; + kernel_monitor = udev_monitor_new_from_netlink(udev, "kernel"); if (kernel_monitor == NULL) { fprintf(stderr, "error: unable to create netlink socket\n"); rc = 3; goto out; } + udev_monitor_set_receive_buffer_size(kernel_monitor, 128*1024*1024); + fd_kernel = udev_monitor_get_fd(kernel_monitor); + + udev_list_entry_foreach(entry, udev_list_get_entry(&subsystem_match_list)) { + const char *subsys = udev_list_entry_get_name(entry); + + if (udev_monitor_filter_add_match_subsystem_devtype(kernel_monitor, subsys, NULL) < 0) + fprintf(stderr, "error: unable to apply subsystem filter '%s'\n", subsys); + } + if (udev_monitor_enable_receiving(kernel_monitor) < 0) { fprintf(stderr, "error: unable to subscribe to kernel events\n"); rc = 4; goto out; } + + memset(&ep_kernel, 0, sizeof(struct epoll_event)); + ep_kernel.events = EPOLLIN; + ep_kernel.data.fd = fd_kernel; + if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_kernel, &ep_kernel) < 0) { + err(udev, "fail to add fd to epoll: %m\n"); + goto out; + } + printf("KERNEL - the kernel uevent\n"); } printf("\n"); while (!udev_exit) { int fdcount; + struct epoll_event ev[4]; + int i; - FD_ZERO(&readfds); - if (kernel_monitor != NULL) - FD_SET(udev_monitor_get_fd(kernel_monitor), &readfds); - if (udev_monitor != NULL) - FD_SET(udev_monitor_get_fd(udev_monitor), &readfds); - - fdcount = select(UDEV_MAX(udev_monitor_get_fd(kernel_monitor), udev_monitor_get_fd(udev_monitor))+1, - &readfds, NULL, NULL, NULL); + fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1); if (fdcount < 0) { if (errno != EINTR) fprintf(stderr, "error receiving uevent message: %m\n"); continue; } - if ((kernel_monitor != NULL) && FD_ISSET(udev_monitor_get_fd(kernel_monitor), &readfds)) { - struct udev_device *device; + for (i = 0; i < fdcount; i++) { + if (ev[i].data.fd == fd_kernel && ev[i].events & EPOLLIN) { + struct udev_device *device; - device = udev_monitor_receive_device(kernel_monitor); - if (device == NULL) - continue; - print_device(device, "KERNEL", env); - udev_device_unref(device); - } - - if ((udev_monitor != NULL) && FD_ISSET(udev_monitor_get_fd(udev_monitor), &readfds)) { - struct udev_device *device; + device = udev_monitor_receive_device(kernel_monitor); + if (device == NULL) + continue; + print_device(device, "KERNEL", prop); + udev_device_unref(device); + } else if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) { + struct udev_device *device; - device = udev_monitor_receive_device(udev_monitor); - if (device == NULL) - continue; - print_device(device, "UDEV", env); - udev_device_unref(device); + device = udev_monitor_receive_device(udev_monitor); + if (device == NULL) + continue; + print_device(device, "UDEV", prop); + udev_device_unref(device); + } } } - out: + if (fd_ep >= 0) + close(fd_ep); udev_monitor_unref(udev_monitor); udev_monitor_unref(kernel_monitor); udev_list_cleanup_entries(udev, &subsystem_match_list); + udev_list_cleanup_entries(udev, &tag_match_list); return rc; }