1 /* SPDX-License-Identifier: GPL-2.0+ */
10 #include "alloc-util.h"
11 #include "device-monitor-private.h"
12 #include "device-private.h"
13 #include "device-util.h"
15 #include "format-util.h"
18 #include "signal-util.h"
19 #include "string-util.h"
23 static bool arg_show_property
= false;
24 static bool arg_print_kernel
= false;
25 static bool arg_print_udev
= false;
26 static Set
*arg_tag_filter
= NULL
;
27 static Hashmap
*arg_subsystem_filter
= NULL
;
29 static int device_monitor_handler(sd_device_monitor
*monitor
, sd_device
*device
, void *userdata
) {
30 DeviceAction action
= _DEVICE_ACTION_INVALID
;
31 const char *devpath
= NULL
, *subsystem
= NULL
;
32 MonitorNetlinkGroup group
= PTR_TO_INT(userdata
);
36 assert(IN_SET(group
, MONITOR_GROUP_UDEV
, MONITOR_GROUP_KERNEL
));
38 (void) device_get_action(device
, &action
);
39 (void) sd_device_get_devpath(device
, &devpath
);
40 (void) sd_device_get_subsystem(device
, &subsystem
);
42 assert_se(clock_gettime(CLOCK_MONOTONIC
, &ts
) == 0);
44 printf("%-6s[%"PRI_TIME
".%06"PRI_NSEC
"] %-8s %s (%s)\n",
45 group
== MONITOR_GROUP_UDEV
? "UDEV" : "KERNEL",
46 ts
.tv_sec
, (nsec_t
)ts
.tv_nsec
/1000,
47 strna(device_action_to_string(action
)),
50 if (arg_show_property
) {
51 const char *key
, *value
;
53 FOREACH_DEVICE_PROPERTY(device
, key
, value
)
54 printf("%s=%s\n", key
, value
);
62 static int setup_monitor(MonitorNetlinkGroup sender
, sd_event
*event
, sd_device_monitor
**ret
) {
63 _cleanup_(sd_device_monitor_unrefp
) sd_device_monitor
*monitor
= NULL
;
64 const char *subsystem
, *devtype
, *tag
;
68 r
= device_monitor_new_full(&monitor
, sender
, -1);
70 return log_error_errno(r
, "Failed to create netlink socket: %m");
72 (void) sd_device_monitor_set_receive_buffer_size(monitor
, 128*1024*1024);
74 r
= sd_device_monitor_attach_event(monitor
, event
);
76 return log_error_errno(r
, "Failed to attach event: %m");
78 HASHMAP_FOREACH_KEY(devtype
, subsystem
, arg_subsystem_filter
, i
) {
79 r
= sd_device_monitor_filter_add_match_subsystem_devtype(monitor
, subsystem
, devtype
);
81 return log_error_errno(r
, "Failed to apply subsystem filter '%s%s%s': %m",
82 subsystem
, devtype
? "/" : "", strempty(devtype
));
85 SET_FOREACH(tag
, arg_tag_filter
, i
) {
86 r
= sd_device_monitor_filter_add_match_tag(monitor
, tag
);
88 return log_error_errno(r
, "Failed to apply tag filter '%s': %m", tag
);
91 r
= sd_device_monitor_start(monitor
, device_monitor_handler
, INT_TO_PTR(sender
));
93 return log_error_errno(r
, "Failed to start device monitor: %m");
95 (void) sd_event_source_set_description(sd_device_monitor_get_event_source(monitor
),
96 sender
== MONITOR_GROUP_UDEV
? "device-monitor-udev" : "device-monitor-kernel");
98 *ret
= TAKE_PTR(monitor
);
102 static int help(void) {
103 printf("%s monitor [OPTIONS]\n\n"
104 "Listen to kernel and udev events.\n\n"
105 " -h --help Show this help\n"
106 " -V --version Show package version\n"
107 " -p --property Print the event properties\n"
108 " -k --kernel Print kernel uevents\n"
109 " -u --udev Print udev events\n"
110 " -s --subsystem-match=SUBSYSTEM[/DEVTYPE] Filter events by subsystem\n"
111 " -t --tag-match=TAG Filter events by tag\n"
112 , program_invocation_short_name
);
117 static int parse_argv(int argc
, char *argv
[]) {
118 static const struct option options
[] = {
119 { "property", no_argument
, NULL
, 'p' },
120 { "environment", no_argument
, NULL
, 'e' }, /* alias for -p */
121 { "kernel", no_argument
, NULL
, 'k' },
122 { "udev", no_argument
, NULL
, 'u' },
123 { "subsystem-match", required_argument
, NULL
, 's' },
124 { "tag-match", required_argument
, NULL
, 't' },
125 { "version", no_argument
, NULL
, 'V' },
126 { "help", no_argument
, NULL
, 'h' },
132 while ((c
= getopt_long(argc
, argv
, "pekus:t:Vh", options
, NULL
)) >= 0)
136 arg_show_property
= true;
139 arg_print_kernel
= true;
142 arg_print_udev
= true;
145 _cleanup_free_
char *subsystem
= NULL
, *devtype
= NULL
;
148 slash
= strchr(optarg
, '/');
150 devtype
= strdup(slash
+ 1);
154 subsystem
= strndup(optarg
, slash
- optarg
);
156 subsystem
= strdup(optarg
);
161 r
= hashmap_ensure_allocated(&arg_subsystem_filter
, NULL
);
165 r
= hashmap_put(arg_subsystem_filter
, subsystem
, devtype
);
169 subsystem
= devtype
= NULL
;
173 _cleanup_free_
char *tag
= NULL
;
175 r
= set_ensure_allocated(&arg_tag_filter
, &string_hash_ops
);
179 tag
= strdup(optarg
);
183 r
= set_put(arg_tag_filter
, tag
);
191 return print_version();
197 assert_not_reached("Unknown option.");
200 if (!arg_print_kernel
&& !arg_print_udev
) {
201 arg_print_kernel
= true;
202 arg_print_udev
= true;
208 int monitor_main(int argc
, char *argv
[], void *userdata
) {
209 _cleanup_(sd_device_monitor_unrefp
) sd_device_monitor
*kernel_monitor
= NULL
, *udev_monitor
= NULL
;
210 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
213 r
= parse_argv(argc
, argv
);
217 if (running_in_chroot() > 0) {
218 log_info("Running in chroot, ignoring request.");
222 /* Callers are expecting to see events as they happen: Line buffering */
225 r
= sd_event_default(&event
);
227 log_error_errno(r
, "Failed to initialize event: %m");
231 assert_se(sigprocmask_many(SIG_UNBLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
232 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
233 (void) sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
235 printf("monitor will print the received events for:\n");
236 if (arg_print_udev
) {
237 r
= setup_monitor(MONITOR_GROUP_UDEV
, event
, &udev_monitor
);
241 printf("UDEV - the event which udev sends out after rule processing\n");
244 if (arg_print_kernel
) {
245 r
= setup_monitor(MONITOR_GROUP_KERNEL
, event
, &kernel_monitor
);
249 printf("KERNEL - the kernel uevent\n");
253 r
= sd_event_loop(event
);
255 log_error_errno(r
, "Failed to run event loop: %m");
262 hashmap_free_free_free(arg_subsystem_filter
);
263 set_free_free(arg_tag_filter
);