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"
22 #include "time-util.h"
24 static bool arg_show_property
= false;
25 static bool arg_print_kernel
= false;
26 static bool arg_print_udev
= false;
27 static Set
*arg_tag_filter
= NULL
;
28 static Hashmap
*arg_subsystem_filter
= NULL
;
30 static int device_monitor_handler(sd_device_monitor
*monitor
, sd_device
*device
, void *userdata
) {
31 DeviceAction action
= _DEVICE_ACTION_INVALID
;
32 const char *devpath
= NULL
, *subsystem
= NULL
;
33 MonitorNetlinkGroup group
= PTR_TO_INT(userdata
);
37 assert(IN_SET(group
, MONITOR_GROUP_UDEV
, MONITOR_GROUP_KERNEL
));
39 (void) device_get_action(device
, &action
);
40 (void) sd_device_get_devpath(device
, &devpath
);
41 (void) sd_device_get_subsystem(device
, &subsystem
);
43 assert_se(clock_gettime(CLOCK_MONOTONIC
, &ts
) == 0);
45 printf("%-6s[%"PRI_TIME
".%06"PRI_NSEC
"] %-8s %s (%s)\n",
46 group
== MONITOR_GROUP_UDEV
? "UDEV" : "KERNEL",
47 ts
.tv_sec
, (nsec_t
)ts
.tv_nsec
/1000,
48 strna(device_action_to_string(action
)),
51 if (arg_show_property
) {
52 const char *key
, *value
;
54 FOREACH_DEVICE_PROPERTY(device
, key
, value
)
55 printf("%s=%s\n", key
, value
);
63 static int setup_monitor(MonitorNetlinkGroup sender
, sd_event
*event
, sd_device_monitor
**ret
) {
64 _cleanup_(sd_device_monitor_unrefp
) sd_device_monitor
*monitor
= NULL
;
65 const char *subsystem
, *devtype
, *tag
;
69 r
= device_monitor_new_full(&monitor
, sender
, -1);
71 return log_error_errno(r
, "Failed to create netlink socket: %m");
73 (void) sd_device_monitor_set_receive_buffer_size(monitor
, 128*1024*1024);
75 r
= sd_device_monitor_attach_event(monitor
, event
);
77 return log_error_errno(r
, "Failed to attach event: %m");
79 HASHMAP_FOREACH_KEY(devtype
, subsystem
, arg_subsystem_filter
, i
) {
80 r
= sd_device_monitor_filter_add_match_subsystem_devtype(monitor
, subsystem
, devtype
);
82 return log_error_errno(r
, "Failed to apply subsystem filter '%s%s%s': %m",
83 subsystem
, devtype
? "/" : "", strempty(devtype
));
86 SET_FOREACH(tag
, arg_tag_filter
, i
) {
87 r
= sd_device_monitor_filter_add_match_tag(monitor
, tag
);
89 return log_error_errno(r
, "Failed to apply tag filter '%s': %m", tag
);
92 r
= sd_device_monitor_start(monitor
, device_monitor_handler
, INT_TO_PTR(sender
));
94 return log_error_errno(r
, "Failed to start device monitor: %m");
96 (void) sd_event_source_set_description(sd_device_monitor_get_event_source(monitor
),
97 sender
== MONITOR_GROUP_UDEV
? "device-monitor-udev" : "device-monitor-kernel");
99 *ret
= TAKE_PTR(monitor
);
103 static int help(void) {
104 printf("%s monitor [OPTIONS]\n\n"
105 "Listen to kernel and udev events.\n\n"
106 " -h --help Show this help\n"
107 " -V --version Show package version\n"
108 " -p --property Print the event properties\n"
109 " -k --kernel Print kernel uevents\n"
110 " -u --udev Print udev events\n"
111 " -s --subsystem-match=SUBSYSTEM[/DEVTYPE] Filter events by subsystem\n"
112 " -t --tag-match=TAG Filter events by tag\n"
113 , program_invocation_short_name
);
118 static int parse_argv(int argc
, char *argv
[]) {
119 static const struct option options
[] = {
120 { "property", no_argument
, NULL
, 'p' },
121 { "environment", no_argument
, NULL
, 'e' }, /* alias for -p */
122 { "kernel", no_argument
, NULL
, 'k' },
123 { "udev", no_argument
, NULL
, 'u' },
124 { "subsystem-match", required_argument
, NULL
, 's' },
125 { "tag-match", required_argument
, NULL
, 't' },
126 { "version", no_argument
, NULL
, 'V' },
127 { "help", no_argument
, NULL
, 'h' },
133 while ((c
= getopt_long(argc
, argv
, "pekus:t:Vh", options
, NULL
)) >= 0)
137 arg_show_property
= true;
140 arg_print_kernel
= true;
143 arg_print_udev
= true;
146 _cleanup_free_
char *subsystem
= NULL
, *devtype
= NULL
;
149 slash
= strchr(optarg
, '/');
151 devtype
= strdup(slash
+ 1);
155 subsystem
= strndup(optarg
, slash
- optarg
);
157 subsystem
= strdup(optarg
);
162 r
= hashmap_ensure_allocated(&arg_subsystem_filter
, NULL
);
166 r
= hashmap_put(arg_subsystem_filter
, subsystem
, devtype
);
170 subsystem
= devtype
= NULL
;
174 _cleanup_free_
char *tag
= NULL
;
176 r
= set_ensure_allocated(&arg_tag_filter
, &string_hash_ops
);
180 tag
= strdup(optarg
);
184 r
= set_put(arg_tag_filter
, tag
);
192 return print_version();
198 assert_not_reached("Unknown option.");
201 if (!arg_print_kernel
&& !arg_print_udev
) {
202 arg_print_kernel
= true;
203 arg_print_udev
= true;
209 int monitor_main(int argc
, char *argv
[], void *userdata
) {
210 _cleanup_(sd_device_monitor_unrefp
) sd_device_monitor
*kernel_monitor
= NULL
, *udev_monitor
= NULL
;
211 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
214 r
= parse_argv(argc
, argv
);
218 if (running_in_chroot() > 0) {
219 log_info("Running in chroot, ignoring request.");
223 /* Callers are expecting to see events as they happen: Line buffering */
226 r
= sd_event_default(&event
);
228 log_error_errno(r
, "Failed to initialize event: %m");
232 assert_se(sigprocmask_many(SIG_UNBLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
233 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
234 (void) sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
236 printf("monitor will print the received events for:\n");
237 if (arg_print_udev
) {
238 r
= setup_monitor(MONITOR_GROUP_UDEV
, event
, &udev_monitor
);
242 printf("UDEV - the event which udev sends out after rule processing\n");
245 if (arg_print_kernel
) {
246 r
= setup_monitor(MONITOR_GROUP_KERNEL
, event
, &kernel_monitor
);
250 printf("KERNEL - the kernel uevent\n");
254 r
= sd_event_loop(event
);
256 log_error_errno(r
, "Failed to run event loop: %m");
263 hashmap_free_free_free(arg_subsystem_filter
);
264 set_free_free(arg_tag_filter
);