/* * Copyright (C) 2004-2006 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "udev.h" static int udev_exit; static void asmlinkage sig_handler(int signum) { if (signum == SIGINT || signum == SIGTERM) udev_exit = 1; } static int print_properties_cb(struct udev_device *udev_device, const char *key, const char *value, void *data) { printf("%s=%s\n", key, value); return 0; } static void print_properties(struct udev_device *device) { udev_device_get_properties(device, print_properties_cb, NULL); printf("\n"); } int udevadm_monitor(struct udev *udev, int argc, char *argv[]) { struct sigaction act; int option; int env = 0; int print_kernel = 0; int print_udev = 0; struct udev_monitor *udev_monitor = NULL; struct udev_monitor *kernel_monitor = NULL; fd_set readfds; int rc = 0; static const struct option options[] = { { "environment", 0, NULL, 'e' }, { "kernel", 0, NULL, 'k' }, { "udev", 0, NULL, 'u' }, { "help", 0, NULL, 'h' }, {} }; while (1) { option = getopt_long(argc, argv, "ekuh", options, NULL); if (option == -1) break; switch (option) { case 'e': env = 1; break; case 'k': print_kernel = 1; break; case 'u': print_udev = 1; 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"); default: goto out; } } if (!print_kernel && !print_udev) { print_kernel = 1; print_udev =1; } if (getuid() != 0 && print_kernel) { fprintf(stderr, "root privileges needed to subscribe to kernel events\n"); goto out; } /* set signal handlers */ memset(&act, 0x00, sizeof(struct sigaction)); act.sa_handler = (void (*)(int)) sig_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_RESTART; sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); printf("monitor will print the received events for:\n"); if (print_udev) { udev_monitor = udev_monitor_new_from_socket(udev, "@/org/kernel/udev/monitor"); if (udev_monitor == NULL) { rc = 1; goto out; } if (udev_monitor_enable_receiving(udev_monitor) < 0) { rc = 2; goto out; } printf("UDEV the event which udev sends out after rule processing\n"); } if (print_kernel) { kernel_monitor = udev_monitor_new_from_netlink(udev); if (kernel_monitor == NULL) { rc = 3; goto out; } if (udev_monitor_enable_receiving(kernel_monitor) < 0) { rc = 4; goto out; } printf("UEVENT the kernel uevent\n"); } printf("\n"); while (!udev_exit) { int fdcount; struct timeval tv; struct timezone tz; char timestr[64]; 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); if (fdcount < 0) { if (errno != EINTR) fprintf(stderr, "error receiving uevent message: %s\n", strerror(errno)); 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 = udev_monitor_receive_device(kernel_monitor); if (device == NULL) continue; printf("UEVENT[%s] %-8s %s (%s)\n", timestr, udev_device_get_action(device), udev_device_get_devpath(device), udev_device_get_subsystem(device)); if (env) print_properties(device); udev_device_unref(device); } if ((udev_monitor != NULL) && FD_ISSET(udev_monitor_get_fd(udev_monitor), &readfds)) { struct udev_device *device = udev_monitor_receive_device(udev_monitor); if (device == NULL) continue; printf("UDEV [%s] %-8s %s (%s)\n", timestr, udev_device_get_action(device), udev_device_get_devpath(device), udev_device_get_subsystem(device)); if (env) print_properties(device); udev_device_unref(device); } } out: udev_monitor_unref(udev_monitor); udev_monitor_unref(kernel_monitor); return rc; }