chiark / gitweb /
libudev: rework list handling
[elogind.git] / udev / udevadm-monitor.c
1 /*
2  * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stddef.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <signal.h>
26 #include <getopt.h>
27 #include <sys/time.h>
28 #include <sys/socket.h>
29 #include <sys/un.h>
30 #include <sys/select.h>
31 #include <linux/types.h>
32 #include <linux/netlink.h>
33
34 #include "udev.h"
35
36 static int udev_exit;
37
38 static void asmlinkage sig_handler(int signum)
39 {
40         if (signum == SIGINT || signum == SIGTERM)
41                 udev_exit = 1;
42 }
43
44 int udevadm_monitor(struct udev *udev, int argc, char *argv[])
45 {
46         struct sigaction act;
47         int option;
48         int env = 0;
49         int print_kernel = 0;
50         int print_udev = 0;
51         struct udev_monitor *udev_monitor = NULL;
52         struct udev_monitor *kernel_monitor = NULL;
53         fd_set readfds;
54         int rc = 0;
55
56         static const struct option options[] = {
57                 { "environment", 0, NULL, 'e' },
58                 { "kernel", 0, NULL, 'k' },
59                 { "udev", 0, NULL, 'u' },
60                 { "help", 0, NULL, 'h' },
61                 {}
62         };
63
64         while (1) {
65                 option = getopt_long(argc, argv, "ekuh", options, NULL);
66                 if (option == -1)
67                         break;
68
69                 switch (option) {
70                 case 'e':
71                         env = 1;
72                         break;
73                 case 'k':
74                         print_kernel = 1;
75                         break;
76                 case 'u':
77                         print_udev = 1;
78                         break;
79                 case 'h':
80                         printf("Usage: udevadm monitor [--environment] [--kernel] [--udev] [--help]\n"
81                                "  --env    print the whole event environment\n"
82                                "  --kernel print kernel uevents\n"
83                                "  --udev   print udev events\n"
84                                "  --help   print this help text\n\n");
85                 default:
86                         goto out;
87                 }
88         }
89
90         if (!print_kernel && !print_udev) {
91                 print_kernel = 1;
92                 print_udev =1;
93         }
94
95         if (getuid() != 0 && print_kernel) {
96                 fprintf(stderr, "root privileges needed to subscribe to kernel events\n");
97                 goto out;
98         }
99
100         /* set signal handlers */
101         memset(&act, 0x00, sizeof(struct sigaction));
102         act.sa_handler = (void (*)(int)) sig_handler;
103         sigemptyset(&act.sa_mask);
104         act.sa_flags = SA_RESTART;
105         sigaction(SIGINT, &act, NULL);
106         sigaction(SIGTERM, &act, NULL);
107
108         printf("monitor will print the received events for:\n");
109         if (print_udev) {
110                 udev_monitor = udev_monitor_new_from_socket(udev, "@/org/kernel/udev/monitor");
111                 if (udev_monitor == NULL) {
112                         rc = 1;
113                         goto out;
114                 }
115                 if (udev_monitor_enable_receiving(udev_monitor) < 0) {
116                         rc = 2;
117                         goto out;
118                 }
119                 printf("UDEV the event which udev sends out after rule processing\n");
120         }
121         if (print_kernel) {
122                 kernel_monitor = udev_monitor_new_from_netlink(udev);
123                 if (kernel_monitor == NULL) {
124                         rc = 3;
125                         goto out;
126                 }
127                 if (udev_monitor_enable_receiving(kernel_monitor) < 0) {
128                         rc = 4;
129                         goto out;
130                 }
131                 printf("UEVENT the kernel uevent\n");
132         }
133         printf("\n");
134
135         while (!udev_exit) {
136                 int fdcount;
137                 struct timeval tv;
138                 struct timezone tz;
139                 char timestr[64];
140
141                 FD_ZERO(&readfds);
142                 if (kernel_monitor != NULL)
143                         FD_SET(udev_monitor_get_fd(kernel_monitor), &readfds);
144                 if (udev_monitor != NULL)
145                         FD_SET(udev_monitor_get_fd(udev_monitor), &readfds);
146
147                 fdcount = select(UDEV_MAX(udev_monitor_get_fd(kernel_monitor), udev_monitor_get_fd(udev_monitor))+1,
148                                  &readfds, NULL, NULL, NULL);
149                 if (fdcount < 0) {
150                         if (errno != EINTR)
151                                 fprintf(stderr, "error receiving uevent message: %s\n", strerror(errno));
152                         continue;
153                 }
154
155                 if (gettimeofday(&tv, &tz) == 0) {
156                         snprintf(timestr, sizeof(timestr), "%llu.%06u",
157                                  (unsigned long long) tv.tv_sec, (unsigned int) tv.tv_usec);
158                 } else
159                         timestr[0] = '\0';
160
161                 if ((kernel_monitor != NULL) && FD_ISSET(udev_monitor_get_fd(kernel_monitor), &readfds)) {
162                         struct udev_device *device = udev_monitor_receive_device(kernel_monitor);
163                         if (device == NULL)
164                                 continue;
165                         printf("UEVENT[%s] %-8s %s (%s)\n", timestr,
166                                udev_device_get_action(device),
167                                udev_device_get_devpath(device),
168                                udev_device_get_subsystem(device));
169                         if (env) {
170                                 struct udev_list *list;
171
172                                 list = udev_device_get_properties_list(device);
173                                 while (list != NULL) {
174                                         printf("%s=%s\n", udev_list_entry_get_name(list), udev_list_entry_get_value(list));
175                                         list = udev_list_entry_get_next(list);
176                                 }
177                                 printf("\n");
178                         }
179                         udev_device_unref(device);
180                 }
181
182                 if ((udev_monitor != NULL) && FD_ISSET(udev_monitor_get_fd(udev_monitor), &readfds)) {
183                         struct udev_device *device = udev_monitor_receive_device(udev_monitor);
184                         if (device == NULL)
185                                 continue;
186                         printf("UDEV  [%s] %-8s %s (%s)\n", timestr,
187                                udev_device_get_action(device),
188                                udev_device_get_devpath(device),
189                                udev_device_get_subsystem(device));
190                         if (env) {
191                                 struct udev_list *list;
192
193                                 list = udev_device_get_properties_list(device);
194                                 while (list != NULL) {
195                                         printf("%s=%s\n", udev_list_entry_get_name(list), udev_list_entry_get_value(list));
196                                         list = udev_list_entry_get_next(list);
197                                 }
198                                 printf("\n");
199                         }
200                         udev_device_unref(device);
201                 }
202         }
203
204 out:
205         udev_monitor_unref(udev_monitor);
206         udev_monitor_unref(kernel_monitor);
207         return rc;
208 }