X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev%2Fudevadm-monitor.c;h=10b2f2e71b8c1ce0f2d4b49f153bcb30342b7115;hp=3b65bcae9b3ae7270e345d1df5a974744b79751d;hb=dacea9ff6be55f1b115c13b1ab530812d0d66879;hpb=e4255f115330b949c1caeb561cbe0e39f5225f50 diff --git a/udev/udevadm-monitor.c b/udev/udevadm-monitor.c index 3b65bcae9..10b2f2e71 100644 --- a/udev/udevadm-monitor.c +++ b/udev/udevadm-monitor.c @@ -1,19 +1,18 @@ /* - * Copyright (C) 2004-2006 Kay Sievers + * Copyright (C) 2004-2008 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 the - * Free Software Foundation version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * 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 + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ #include @@ -33,69 +32,8 @@ #include #include "udev.h" -#include "udevd.h" - -static int uevent_netlink_sock = -1; -static int udev_monitor_sock = -1; -static volatile int udev_exit; - -static int init_udev_monitor_socket(void) -{ - struct sockaddr_un saddr; - socklen_t addrlen; - int retval; - - memset(&saddr, 0x00, sizeof(saddr)); - saddr.sun_family = AF_LOCAL; - /* use abstract namespace for socket path */ - strcpy(&saddr.sun_path[1], "/org/kernel/udev/monitor"); - addrlen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&saddr.sun_path[1]); - - udev_monitor_sock = socket(AF_LOCAL, SOCK_DGRAM, 0); - if (udev_monitor_sock == -1) { - fprintf(stderr, "error getting socket: %s\n", strerror(errno)); - return -1; - } - - /* the bind takes care of ensuring only one copy running */ - retval = bind(udev_monitor_sock, (struct sockaddr *) &saddr, addrlen); - if (retval < 0) { - fprintf(stderr, "bind failed: %s\n", strerror(errno)); - close(udev_monitor_sock); - udev_monitor_sock = -1; - return -1; - } - - return 0; -} -static int init_uevent_netlink_sock(void) -{ - struct sockaddr_nl snl; - int retval; - - memset(&snl, 0x00, sizeof(struct sockaddr_nl)); - snl.nl_family = AF_NETLINK; - snl.nl_pid = getpid(); - snl.nl_groups = 1; - - uevent_netlink_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); - if (uevent_netlink_sock == -1) { - fprintf(stderr, "error getting socket: %s\n", strerror(errno)); - return -1; - } - - retval = bind(uevent_netlink_sock, (struct sockaddr *) &snl, - sizeof(struct sockaddr_nl)); - if (retval < 0) { - fprintf(stderr, "bind failed: %s\n", strerror(errno)); - close(uevent_netlink_sock); - uevent_netlink_sock = -1; - return -1; - } - - return 0; -} +static int udev_exit; static void asmlinkage sig_handler(int signum) { @@ -103,46 +41,54 @@ static void asmlinkage sig_handler(int signum) udev_exit = 1; } -static const char *search_key(const char *searchkey, const char *buf, size_t buflen) +static void print_device(struct udev_device *device, const char *source, int env) { - size_t bufpos = 0; - size_t searchkeylen = strlen(searchkey); - - while (bufpos < buflen) { - const char *key; - int keylen; - - key = &buf[bufpos]; - keylen = strlen(key); - if (keylen == 0) - break; - if ((strncmp(searchkey, key, searchkeylen) == 0) && key[searchkeylen] == '=') - return &key[searchkeylen + 1]; - bufpos += keylen + 1; + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + printf("%-6s[%llu.%06u] %-8s %s (%s)\n", + source, + (unsigned long long) tv.tv_sec, (unsigned int) tv.tv_usec, + udev_device_get_action(device), + udev_device_get_devpath(device), + udev_device_get_subsystem(device)); + if (env) { + struct udev_list_entry *list_entry; + + udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) + printf("%s=%s\n", + udev_list_entry_get_name(list_entry), + udev_list_entry_get_value(list_entry)); + printf("\n"); } - return NULL; } -int udevmonitor(int argc, char *argv[]) +int udevadm_monitor(struct udev *udev, int argc, char *argv[]) { struct sigaction act; int option; int env = 0; - int kernel = 0; - int udev = 0; + int print_kernel = 0; + int print_udev = 0; + struct udev_list_node subsystem_match_list; + struct udev_monitor *udev_monitor = NULL; + struct udev_monitor *kernel_monitor = NULL; fd_set readfds; - int retval = 0; + int rc = 0; static const struct option options[] = { - { "environment", 0, NULL, 'e' }, - { "kernel", 0, NULL, 'k' }, - { "udev", 0, NULL, 'u' }, - { "help", 0, NULL, 'h' }, + { "environment", no_argument, NULL, 'e' }, + { "kernel", no_argument, NULL, 'k' }, + { "udev", no_argument, NULL, 'u' }, + { "subsystem-match", required_argument, NULL, 's' }, + { "help", no_argument, NULL, 'h' }, {} }; + udev_list_init(&subsystem_match_list); while (1) { - option = getopt_long(argc, argv, "ekuh", options, NULL); + option = getopt_long(argc, argv, "ekus:h", options, NULL); if (option == -1) break; @@ -151,30 +97,28 @@ int udevmonitor(int argc, char *argv[]) env = 1; break; case 'k': - kernel = 1; + print_kernel = 1; break; case 'u': - udev = 1; + print_udev = 1; + break; + case 's': + udev_list_entry_add(udev, &subsystem_match_list, optarg, NULL, 1, 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" - " --help print this help text\n\n"); + " --help\n\n"); default: goto out; } } - if (!kernel && !udev) { - kernel = 1; - udev =1; - } - - if (getuid() != 0 && kernel) { - fprintf(stderr, "root privileges needed to subscribe to kernel events\n"); - goto out; + if (!print_kernel && !print_udev) { + print_kernel = 1; + print_udev =1; } /* set signal handlers */ @@ -185,105 +129,88 @@ int udevmonitor(int argc, char *argv[]) sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); - printf("udevmonitor will print the received events for:\n"); - if (udev) { - retval = init_udev_monitor_socket(); - if (retval) + printf("monitor will print the received events for:\n"); + if (print_udev) { + struct udev_list_entry *entry; + + udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (udev_monitor == NULL) { + fprintf(stderr, "error: unable to create netlink socket\n"); + rc = 1; goto out; - printf("UDEV the event which udev sends out after rule processing\n"); + } + + 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(udev_monitor, subsys, NULL) < 0) + fprintf(stderr, "error: unable to apply subsystem filter '%s'\n", subsys); + } + + if (udev_monitor_enable_receiving(udev_monitor) < 0) { + fprintf(stderr, "error: unable to subscribe to udev events\n"); + rc = 2; + goto out; + } + printf("UDEV - the event which udev sends out after rule processing\n"); } - if (kernel) { - retval = init_uevent_netlink_sock(); - if (retval) + if (print_kernel) { + 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; - printf("UEVENT the kernel uevent\n"); + } + if (udev_monitor_enable_receiving(kernel_monitor) < 0) { + fprintf(stderr, "error: unable to subscribe to kernel events\n"); + rc = 4; + goto out; + } + printf("KERNEL - the kernel uevent\n"); } printf("\n"); while (!udev_exit) { - char buf[UEVENT_BUFFER_SIZE*2]; - ssize_t buflen; - ssize_t bufpos; - ssize_t keys; int fdcount; - struct timeval tv; - struct timezone tz; - char timestr[64]; - const char *source = NULL; - const char *devpath, *action, *subsys; - buflen = 0; FD_ZERO(&readfds); - if (uevent_netlink_sock >= 0) - FD_SET(uevent_netlink_sock, &readfds); - if (udev_monitor_sock >= 0) - FD_SET(udev_monitor_sock, &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(uevent_netlink_sock, udev_monitor_sock)+1, &readfds, NULL, NULL, NULL); + fdcount = select(UDEV_MAX(udev_monitor_get_fd(kernel_monitor), udev_monitor_get_fd(udev_monitor))+1, + &readfds, NULL, NULL, NULL); if (fdcount < 0) { if (errno != EINTR) - fprintf(stderr, "error receiving uevent message: %s\n", strerror(errno)); + fprintf(stderr, "error receiving uevent message: %m\n"); continue; } - if (gettimeofday(&tv, &tz) == 0) { - snprintf(timestr, sizeof(timestr), "%llu.%06u", - (unsigned long long) tv.tv_sec, (unsigned int) tv.tv_usec); - } else - timestr[0] = '\0'; + if ((kernel_monitor != NULL) && FD_ISSET(udev_monitor_get_fd(kernel_monitor), &readfds)) { + struct udev_device *device; - if ((uevent_netlink_sock >= 0) && FD_ISSET(uevent_netlink_sock, &readfds)) { - buflen = recv(uevent_netlink_sock, &buf, sizeof(buf), 0); - if (buflen <= 0) { - fprintf(stderr, "error receiving uevent message: %s\n", strerror(errno)); + device = udev_monitor_receive_device(kernel_monitor); + if (device == NULL) continue; - } - source = "UEVENT"; + print_device(device, "KERNEL", env); + udev_device_unref(device); } - if ((udev_monitor_sock >= 0) && FD_ISSET(udev_monitor_sock, &readfds)) { - buflen = recv(udev_monitor_sock, &buf, sizeof(buf), 0); - if (buflen <= 0) { - fprintf(stderr, "error receiving udev message: %s\n", strerror(errno)); - continue; - } - source = "UDEV "; - } + if ((udev_monitor != NULL) && FD_ISSET(udev_monitor_get_fd(udev_monitor), &readfds)) { + struct udev_device *device; - if (buflen == 0) - continue; - - keys = strlen(buf) + 1; /* start of payload */ - devpath = search_key("DEVPATH", &buf[keys], buflen); - action = search_key("ACTION", &buf[keys], buflen); - subsys = search_key("SUBSYSTEM", &buf[keys], buflen); - printf("%s[%s] %-8s %s (%s)\n", source, timestr, action, devpath, subsys); - - /* print environment */ - bufpos = keys; - if (env) { - while (bufpos < buflen) { - int keylen; - char *key; - - key = &buf[bufpos]; - keylen = strlen(key); - if (keylen == 0) - break; - printf("%s\n", key); - bufpos += keylen + 1; - } - printf("\n"); + device = udev_monitor_receive_device(udev_monitor); + if (device == NULL) + continue; + print_device(device, "UDEV", env); + udev_device_unref(device); } } out: - if (uevent_netlink_sock >= 0) - close(uevent_netlink_sock); - if (udev_monitor_sock >= 0) - close(udev_monitor_sock); - - if (retval) - return 1; - return 0; + udev_monitor_unref(udev_monitor); + udev_monitor_unref(kernel_monitor); + udev_list_cleanup_entries(udev, &subsystem_match_list); + return rc; }