1 /* SPDX-License-Identifier: GPL-2.0+ */
10 #include "alloc-util.h"
11 #include "device-monitor-private.h"
12 #include "device-util.h"
14 #include "format-util.h"
17 #include "signal-util.h"
18 #include "string-util.h"
21 static bool arg_show_property
= false;
22 static bool arg_print_kernel
= false;
23 static bool arg_print_udev
= false;
24 static Set
*arg_tag_filter
= NULL
;
25 static Hashmap
*arg_subsystem_filter
= NULL
;
27 static int device_monitor_handler(sd_device_monitor
*monitor
, sd_device
*device
, void *userdata
) {
28 const char *action
= NULL
, *devpath
= NULL
, *subsystem
= NULL
;
29 MonitorNetlinkGroup group
= PTR_TO_INT(userdata
);
33 assert(IN_SET(group
, MONITOR_GROUP_UDEV
, MONITOR_GROUP_KERNEL
));
35 (void) sd_device_get_property_value(device
, "ACTION", &action
);
36 (void) sd_device_get_devpath(device
, &devpath
);
37 (void) sd_device_get_subsystem(device
, &subsystem
);
39 assert_se(clock_gettime(CLOCK_MONOTONIC
, &ts
) == 0);
41 printf("%-6s[%"PRI_TIME
".%06"PRI_NSEC
"] %-8s %s (%s)\n",
42 group
== MONITOR_GROUP_UDEV
? "UDEV" : "KERNEL",
43 ts
.tv_sec
, (nsec_t
)ts
.tv_nsec
/1000,
44 action
, devpath
, subsystem
);
46 if (arg_show_property
) {
47 const char *key
, *value
;
49 FOREACH_DEVICE_PROPERTY(device
, key
, value
)
50 printf("%s=%s\n", key
, value
);
58 static int setup_monitor(MonitorNetlinkGroup sender
, sd_event
*event
, sd_device_monitor
**ret
) {
59 _cleanup_(sd_device_monitor_unrefp
) sd_device_monitor
*monitor
= NULL
;
60 const char *subsystem
, *devtype
, *tag
;
64 r
= device_monitor_new_full(&monitor
, sender
, -1);
66 return log_error_errno(r
, "Failed to create netlink socket: %m");
68 (void) sd_device_monitor_set_receive_buffer_size(monitor
, 128*1024*1024);
70 r
= sd_device_monitor_attach_event(monitor
, event
);
72 return log_error_errno(r
, "Failed to attach event: %m");
74 HASHMAP_FOREACH_KEY(devtype
, subsystem
, arg_subsystem_filter
, i
) {
75 r
= sd_device_monitor_filter_add_match_subsystem_devtype(monitor
, subsystem
, devtype
);
77 return log_error_errno(r
, "Failed to apply subsystem filter '%s%s%s': %m",
78 subsystem
, devtype
? "/" : "", strempty(devtype
));
81 SET_FOREACH(tag
, arg_tag_filter
, i
) {
82 r
= sd_device_monitor_filter_add_match_tag(monitor
, tag
);
84 return log_error_errno(r
, "Failed to apply tag filter '%s': %m", tag
);
87 r
= sd_device_monitor_start(monitor
, device_monitor_handler
, INT_TO_PTR(sender
));
89 return log_error_errno(r
, "Failed to start device monitor: %m");
91 (void) sd_event_source_set_description(sd_device_monitor_get_event_source(monitor
),
92 sender
== MONITOR_GROUP_UDEV
? "device-monitor-udev" : "device-monitor-kernel");
94 *ret
= TAKE_PTR(monitor
);
98 static int help(void) {
99 printf("%s monitor [OPTIONS]\n\n"
100 "Listen to kernel and udev events.\n\n"
101 " -h --help Show this help\n"
102 " -V --version Show package version\n"
103 " -p --property Print the event properties\n"
104 " -k --kernel Print kernel uevents\n"
105 " -u --udev Print udev events\n"
106 " -s --subsystem-match=SUBSYSTEM[/DEVTYPE] Filter events by subsystem\n"
107 " -t --tag-match=TAG Filter events by tag\n"
108 , program_invocation_short_name
);
113 static int parse_argv(int argc
, char *argv
[]) {
114 static const struct option options
[] = {
115 { "property", no_argument
, NULL
, 'p' },
116 { "environment", no_argument
, NULL
, 'e' }, /* alias for -p */
117 { "kernel", no_argument
, NULL
, 'k' },
118 { "udev", no_argument
, NULL
, 'u' },
119 { "subsystem-match", required_argument
, NULL
, 's' },
120 { "tag-match", required_argument
, NULL
, 't' },
121 { "version", no_argument
, NULL
, 'V' },
122 { "help", no_argument
, NULL
, 'h' },
128 while ((c
= getopt_long(argc
, argv
, "pekus:t:Vh", options
, NULL
)) >= 0)
132 arg_show_property
= true;
135 arg_print_kernel
= true;
138 arg_print_udev
= true;
141 _cleanup_free_
char *subsystem
= NULL
, *devtype
= NULL
;
144 slash
= strchr(optarg
, '/');
146 devtype
= strdup(devtype
+ 1);
150 subsystem
= strndup(optarg
, devtype
- optarg
);
152 subsystem
= strdup(optarg
);
157 r
= hashmap_ensure_allocated(&arg_subsystem_filter
, NULL
);
161 r
= hashmap_put(arg_subsystem_filter
, subsystem
, devtype
);
165 subsystem
= devtype
= NULL
;
169 _cleanup_free_
char *tag
= NULL
;
171 r
= set_ensure_allocated(&arg_tag_filter
, &string_hash_ops
);
175 tag
= strdup(optarg
);
179 r
= set_put(arg_tag_filter
, tag
);
187 return print_version();
193 assert_not_reached("Unknown option.");
196 if (!arg_print_kernel
&& !arg_print_udev
) {
197 arg_print_kernel
= true;
198 arg_print_udev
= true;
204 int monitor_main(int argc
, char *argv
[], void *userdata
) {
205 _cleanup_(sd_device_monitor_unrefp
) sd_device_monitor
*kernel_monitor
= NULL
, *udev_monitor
= NULL
;
206 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
209 r
= parse_argv(argc
, argv
);
213 /* Callers are expecting to see events as they happen: Line buffering */
216 r
= sd_event_default(&event
);
218 log_error_errno(r
, "Failed to initialize event: %m");
222 assert_se(sigprocmask_many(SIG_UNBLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
223 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
224 (void) sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
226 printf("monitor will print the received events for:\n");
227 if (arg_print_udev
) {
228 r
= setup_monitor(MONITOR_GROUP_UDEV
, event
, &udev_monitor
);
232 printf("UDEV - the event which udev sends out after rule processing\n");
235 if (arg_print_kernel
) {
236 r
= setup_monitor(MONITOR_GROUP_KERNEL
, event
, &kernel_monitor
);
240 printf("KERNEL - the kernel uevent\n");
244 r
= sd_event_loop(event
);
246 log_error_errno(r
, "Failed to run event loop: %m");
253 hashmap_free_free_free(arg_subsystem_filter
);
254 set_free_free(arg_tag_filter
);