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"
22 static bool arg_show_property
= false;
23 static bool arg_print_kernel
= false;
24 static bool arg_print_udev
= false;
25 static Set
*arg_tag_filter
= NULL
;
26 static Hashmap
*arg_subsystem_filter
= NULL
;
28 static int device_monitor_handler(sd_device_monitor
*monitor
, sd_device
*device
, void *userdata
) {
29 const char *action
= NULL
, *devpath
= NULL
, *subsystem
= NULL
;
30 MonitorNetlinkGroup group
= PTR_TO_INT(userdata
);
34 assert(IN_SET(group
, MONITOR_GROUP_UDEV
, MONITOR_GROUP_KERNEL
));
36 (void) sd_device_get_property_value(device
, "ACTION", &action
);
37 (void) sd_device_get_devpath(device
, &devpath
);
38 (void) sd_device_get_subsystem(device
, &subsystem
);
40 assert_se(clock_gettime(CLOCK_MONOTONIC
, &ts
) == 0);
42 printf("%-6s[%"PRI_TIME
".%06"PRI_NSEC
"] %-8s %s (%s)\n",
43 group
== MONITOR_GROUP_UDEV
? "UDEV" : "KERNEL",
44 ts
.tv_sec
, (nsec_t
)ts
.tv_nsec
/1000,
45 action
, devpath
, subsystem
);
47 if (arg_show_property
) {
48 const char *key
, *value
;
50 FOREACH_DEVICE_PROPERTY(device
, key
, value
)
51 printf("%s=%s\n", key
, value
);
59 static int setup_monitor(MonitorNetlinkGroup sender
, sd_event
*event
, sd_device_monitor
**ret
) {
60 _cleanup_(sd_device_monitor_unrefp
) sd_device_monitor
*monitor
= NULL
;
61 const char *subsystem
, *devtype
, *tag
;
65 r
= device_monitor_new_full(&monitor
, sender
, -1);
67 return log_error_errno(r
, "Failed to create netlink socket: %m");
69 (void) sd_device_monitor_set_receive_buffer_size(monitor
, 128*1024*1024);
71 r
= sd_device_monitor_attach_event(monitor
, event
);
73 return log_error_errno(r
, "Failed to attach event: %m");
75 HASHMAP_FOREACH_KEY(devtype
, subsystem
, arg_subsystem_filter
, i
) {
76 r
= sd_device_monitor_filter_add_match_subsystem_devtype(monitor
, subsystem
, devtype
);
78 return log_error_errno(r
, "Failed to apply subsystem filter '%s%s%s': %m",
79 subsystem
, devtype
? "/" : "", strempty(devtype
));
82 SET_FOREACH(tag
, arg_tag_filter
, i
) {
83 r
= sd_device_monitor_filter_add_match_tag(monitor
, tag
);
85 return log_error_errno(r
, "Failed to apply tag filter '%s': %m", tag
);
88 r
= sd_device_monitor_start(monitor
, device_monitor_handler
, INT_TO_PTR(sender
));
90 return log_error_errno(r
, "Failed to start device monitor: %m");
92 (void) sd_event_source_set_description(sd_device_monitor_get_event_source(monitor
),
93 sender
== MONITOR_GROUP_UDEV
? "device-monitor-udev" : "device-monitor-kernel");
95 *ret
= TAKE_PTR(monitor
);
99 static int help(void) {
100 printf("%s monitor [OPTIONS]\n\n"
101 "Listen to kernel and udev events.\n\n"
102 " -h --help Show this help\n"
103 " -V --version Show package version\n"
104 " -p --property Print the event properties\n"
105 " -k --kernel Print kernel uevents\n"
106 " -u --udev Print udev events\n"
107 " -s --subsystem-match=SUBSYSTEM[/DEVTYPE] Filter events by subsystem\n"
108 " -t --tag-match=TAG Filter events by tag\n"
109 , program_invocation_short_name
);
114 static int parse_argv(int argc
, char *argv
[]) {
115 static const struct option options
[] = {
116 { "property", no_argument
, NULL
, 'p' },
117 { "environment", no_argument
, NULL
, 'e' }, /* alias for -p */
118 { "kernel", no_argument
, NULL
, 'k' },
119 { "udev", no_argument
, NULL
, 'u' },
120 { "subsystem-match", required_argument
, NULL
, 's' },
121 { "tag-match", required_argument
, NULL
, 't' },
122 { "version", no_argument
, NULL
, 'V' },
123 { "help", no_argument
, NULL
, 'h' },
129 while ((c
= getopt_long(argc
, argv
, "pekus:t:Vh", options
, NULL
)) >= 0)
133 arg_show_property
= true;
136 arg_print_kernel
= true;
139 arg_print_udev
= true;
142 _cleanup_free_
char *subsystem
= NULL
, *devtype
= NULL
;
145 slash
= strchr(optarg
, '/');
147 devtype
= strdup(devtype
+ 1);
151 subsystem
= strndup(optarg
, devtype
- optarg
);
153 subsystem
= strdup(optarg
);
158 r
= hashmap_ensure_allocated(&arg_subsystem_filter
, NULL
);
162 r
= hashmap_put(arg_subsystem_filter
, subsystem
, devtype
);
166 subsystem
= devtype
= NULL
;
170 _cleanup_free_
char *tag
= NULL
;
172 r
= set_ensure_allocated(&arg_tag_filter
, &string_hash_ops
);
176 tag
= strdup(optarg
);
180 r
= set_put(arg_tag_filter
, tag
);
188 return print_version();
194 assert_not_reached("Unknown option.");
197 if (!arg_print_kernel
&& !arg_print_udev
) {
198 arg_print_kernel
= true;
199 arg_print_udev
= true;
205 int monitor_main(int argc
, char *argv
[], void *userdata
) {
206 _cleanup_(sd_device_monitor_unrefp
) sd_device_monitor
*kernel_monitor
= NULL
, *udev_monitor
= NULL
;
207 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
210 r
= parse_argv(argc
, argv
);
214 if (running_in_chroot() > 0) {
215 log_info("Running in chroot, ignoring request.");
219 /* Callers are expecting to see events as they happen: Line buffering */
222 r
= sd_event_default(&event
);
224 log_error_errno(r
, "Failed to initialize event: %m");
228 assert_se(sigprocmask_many(SIG_UNBLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
229 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
230 (void) sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
232 printf("monitor will print the received events for:\n");
233 if (arg_print_udev
) {
234 r
= setup_monitor(MONITOR_GROUP_UDEV
, event
, &udev_monitor
);
238 printf("UDEV - the event which udev sends out after rule processing\n");
241 if (arg_print_kernel
) {
242 r
= setup_monitor(MONITOR_GROUP_KERNEL
, event
, &kernel_monitor
);
246 printf("KERNEL - the kernel uevent\n");
250 r
= sd_event_loop(event
);
252 log_error_errno(r
, "Failed to run event loop: %m");
259 hashmap_free_free_free(arg_subsystem_filter
);
260 set_free_free(arg_tag_filter
);