1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <errno.h>
4 #include <getopt.h>
5 
6 #include "sd-device.h"
7 #include "sd-event.h"
8 
9 #include "device-enumerator-private.h"
10 #include "device-private.h"
11 #include "device-util.h"
12 #include "fd-util.h"
13 #include "fileio.h"
14 #include "parse-util.h"
15 #include "path-util.h"
16 #include "process-util.h"
17 #include "set.h"
18 #include "string-util.h"
19 #include "strv.h"
20 #include "udevadm.h"
21 #include "udevadm-util.h"
22 #include "udev-ctrl.h"
23 #include "virt.h"
24 
25 static bool arg_verbose = false;
26 static bool arg_dry_run = false;
27 static bool arg_quiet = false;
28 static bool arg_uuid = false;
29 
exec_list(sd_device_enumerator * e,sd_device_action_t action,Hashmap * settle_hashmap)30 static int exec_list(
31                 sd_device_enumerator *e,
32                 sd_device_action_t action,
33                 Hashmap *settle_hashmap) {
34 
35         bool skip_uuid_logic = false;
36         const char *action_str;
37         sd_device *d;
38         int r, ret = 0;
39 
40         action_str = device_action_to_string(action);
41 
42         FOREACH_DEVICE_AND_SUBSYSTEM(e, d) {
43                 sd_id128_t id = SD_ID128_NULL;
44                 const char *syspath;
45 
46                 r = sd_device_get_syspath(d, &syspath);
47                 if (r < 0) {
48                         log_debug_errno(r, "Failed to get syspath of enumerated devices, ignoring: %m");
49                         continue;
50                 }
51 
52                 if (arg_verbose)
53                         printf("%s\n", syspath);
54 
55                 if (arg_dry_run)
56                         continue;
57 
58                 /* Use the UUID mode if the user explicitly asked for it, or if --settle has been specified,
59                  * so that we can recognize our own uevent. */
60                 r = sd_device_trigger_with_uuid(d, action, (arg_uuid || settle_hashmap) && !skip_uuid_logic ? &id : NULL);
61                 if (r == -EINVAL && !arg_uuid && settle_hashmap && !skip_uuid_logic) {
62                         /* If we specified a UUID because of the settling logic, and we got EINVAL this might
63                          * be caused by an old kernel which doesn't know the UUID logic (pre-4.13). Let's try
64                          * if it works without the UUID logic then. */
65                         r = sd_device_trigger(d, action);
66                         if (r != -EINVAL)
67                                 skip_uuid_logic = true; /* dropping the uuid stuff changed the return code,
68                                                          * hence don't bother next time */
69                 }
70                 if (r < 0) {
71                         /* ENOENT may be returned when a device does not have /uevent or is already
72                          * removed. Hence, this is logged at debug level and ignored.
73                          *
74                          * ENODEV may be returned by some buggy device drivers e.g. /sys/devices/vio.
75                          * See,
76                          * https://github.com/systemd/systemd/issues/13652#issuecomment-535129791 and
77                          * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1845319.
78                          * So, this error is ignored, but logged at warning level to encourage people to
79                          * fix the driver.
80                          *
81                          * EROFS is returned when /sys is read only. In that case, all subsequent
82                          * writes will also fail, hence return immediately.
83                          *
84                          * EACCES or EPERM may be returned when this is invoked by non-priviledged user.
85                          * We do NOT return immediately, but continue operation and propagate the error.
86                          * Why? Some device can be owned by a user, e.g., network devices configured in
87                          * a network namespace. See, https://github.com/systemd/systemd/pull/18559 and
88                          * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ebb4a4bf76f164457184a3f43ebc1552416bc823
89                          *
90                          * All other errors are logged at error level, but let's continue the operation,
91                          * and propagate the error.
92                          */
93 
94                         bool ignore = IN_SET(r, -ENOENT, -ENODEV);
95                         int level =
96                                 arg_quiet ? LOG_DEBUG :
97                                 r == -ENOENT ? LOG_DEBUG :
98                                 r == -ENODEV ? LOG_WARNING : LOG_ERR;
99 
100                         log_device_full_errno(d, level, r,
101                                               "Failed to write '%s' to '%s/uevent'%s: %m",
102                                               action_str, syspath, ignore ? ", ignoring" : "");
103 
104                         if (r == -EROFS)
105                                 return r;
106                         if (ret == 0 && !ignore)
107                                 ret = r;
108                         continue;
109                 }
110 
111                 /* If the user asked for it, write event UUID to stdout */
112                 if (arg_uuid)
113                         printf(SD_ID128_UUID_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(id));
114 
115                 if (settle_hashmap) {
116                         _cleanup_free_ sd_id128_t *mid = NULL;
117                         _cleanup_free_ char *sp = NULL;
118 
119                         sp = strdup(syspath);
120                         if (!sp)
121                                 return log_oom();
122 
123                         mid = newdup(sd_id128_t, &id, 1);
124                         if (!d)
125                                 return log_oom();
126 
127                         r = hashmap_put(settle_hashmap, sp, mid);
128                         if (r < 0)
129                                 return log_oom();
130 
131                         TAKE_PTR(sp);
132                         TAKE_PTR(mid);
133                 }
134         }
135 
136         return ret;
137 }
138 
device_monitor_handler(sd_device_monitor * m,sd_device * dev,void * userdata)139 static int device_monitor_handler(sd_device_monitor *m, sd_device *dev, void *userdata) {
140         Hashmap *settle_hashmap = userdata;
141         sd_id128_t *settle_id;
142         const char *syspath;
143         char *k;
144         int r;
145 
146         assert(dev);
147         assert(settle_hashmap);
148 
149         r = sd_device_get_syspath(dev, &syspath);
150         if (r < 0) {
151                 log_debug_errno(r, "Failed to get syspath of device event, ignoring: %m");
152                 return 0;
153         }
154 
155         settle_id = hashmap_get2(settle_hashmap, syspath, (void**) &k);
156         if (!settle_id) {
157                 log_debug("Got uevent for unexpected device '%s', ignoring.", syspath);
158                 return 0;
159         }
160         if (!sd_id128_is_null(*settle_id)) { /* If this is SD_ID128_NULL then we are on pre-4.13 and have no UUID to check, hence don't */
161                 sd_id128_t event_id;
162 
163                 r = sd_device_get_trigger_uuid(dev, &event_id);
164                 if (r < 0) {
165                         log_debug_errno(r, "Got uevent without synthetic UUID for device '%s', ignoring: %m", syspath);
166                         return 0;
167                 }
168 
169                 if (!sd_id128_equal(event_id, *settle_id)) {
170                         log_debug("Got uevent not matching expected UUID for device '%s', ignoring.", syspath);
171                         return 0;
172                 }
173         }
174 
175         if (arg_verbose)
176                 printf("settle %s\n", syspath);
177 
178         if (arg_uuid)
179                 printf("settle " SD_ID128_UUID_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(*settle_id));
180 
181         free(hashmap_remove(settle_hashmap, syspath));
182         free(k);
183 
184         if (hashmap_isempty(settle_hashmap))
185                 return sd_event_exit(sd_device_monitor_get_event(m), 0);
186 
187         return 0;
188 }
189 
keyval(const char * str,const char ** key,const char ** val)190 static char* keyval(const char *str, const char **key, const char **val) {
191         char *buf, *pos;
192 
193         buf = strdup(str);
194         if (!buf)
195                 return NULL;
196 
197         pos = strchr(buf, '=');
198         if (pos) {
199                 pos[0] = 0;
200                 pos++;
201         }
202 
203         *key = buf;
204         *val = pos;
205 
206         return buf;
207 }
208 
help(void)209 static int help(void) {
210         printf("%s trigger [OPTIONS] DEVPATH\n\n"
211                "Request events from the kernel.\n\n"
212                "  -h --help                         Show this help\n"
213                "  -V --version                      Show package version\n"
214                "  -v --verbose                      Print the list of devices while running\n"
215                "  -n --dry-run                      Do not actually trigger the events\n"
216                "  -q --quiet                        Suppress error logging in triggering events\n"
217                "  -t --type=                        Type of events to trigger\n"
218                "          devices                     sysfs devices (default)\n"
219                "          subsystems                  sysfs subsystems and drivers\n"
220                "  -c --action=ACTION|help           Event action value, default is \"change\"\n"
221                "  -s --subsystem-match=SUBSYSTEM    Trigger devices from a matching subsystem\n"
222                "  -S --subsystem-nomatch=SUBSYSTEM  Exclude devices from a matching subsystem\n"
223                "  -a --attr-match=FILE[=VALUE]      Trigger devices with a matching attribute\n"
224                "  -A --attr-nomatch=FILE[=VALUE]    Exclude devices with a matching attribute\n"
225                "  -p --property-match=KEY=VALUE     Trigger devices with a matching property\n"
226                "  -g --tag-match=TAG                Trigger devices with a matching tag\n"
227                "  -y --sysname-match=NAME           Trigger devices with this /sys path\n"
228                "     --name-match=NAME              Trigger devices with this /dev name\n"
229                "  -b --parent-match=NAME            Trigger devices with that parent device\n"
230                "     --initialized-match            Trigger devices that are already initialized\n"
231                "     --initialized-nomatch          Trigger devices that are not initialized yet\n"
232                "  -w --settle                       Wait for the triggered events to complete\n"
233                "     --wait-daemon[=SECONDS]        Wait for udevd daemon to be initialized\n"
234                "                                    before triggering uevents\n"
235                "     --uuid                         Print synthetic uevent UUID\n"
236                "     --prioritized-subsystem=SUBSYSTEM[,SUBSYSTEM…]\n"
237                "                                    Trigger devices from a matching subsystem first\n",
238                program_invocation_short_name);
239 
240         return 0;
241 }
242 
trigger_main(int argc,char * argv[],void * userdata)243 int trigger_main(int argc, char *argv[], void *userdata) {
244         enum {
245                 ARG_NAME = 0x100,
246                 ARG_PING,
247                 ARG_UUID,
248                 ARG_PRIORITIZED_SUBSYSTEM,
249                 ARG_INITIALIZED_MATCH,
250                 ARG_INITIALIZED_NOMATCH,
251         };
252 
253         static const struct option options[] = {
254                 { "verbose",               no_argument,       NULL, 'v'                       },
255                 { "dry-run",               no_argument,       NULL, 'n'                       },
256                 { "quiet",                 no_argument,       NULL, 'q'                       },
257                 { "type",                  required_argument, NULL, 't'                       },
258                 { "action",                required_argument, NULL, 'c'                       },
259                 { "subsystem-match",       required_argument, NULL, 's'                       },
260                 { "subsystem-nomatch",     required_argument, NULL, 'S'                       },
261                 { "attr-match",            required_argument, NULL, 'a'                       },
262                 { "attr-nomatch",          required_argument, NULL, 'A'                       },
263                 { "property-match",        required_argument, NULL, 'p'                       },
264                 { "tag-match",             required_argument, NULL, 'g'                       },
265                 { "sysname-match",         required_argument, NULL, 'y'                       },
266                 { "name-match",            required_argument, NULL, ARG_NAME                  },
267                 { "parent-match",          required_argument, NULL, 'b'                       },
268                 { "initialized-match",     no_argument,       NULL, ARG_INITIALIZED_MATCH     },
269                 { "initialized-nomatch",   no_argument,       NULL, ARG_INITIALIZED_NOMATCH   },
270                 { "settle",                no_argument,       NULL, 'w'                       },
271                 { "wait-daemon",           optional_argument, NULL, ARG_PING                  },
272                 { "version",               no_argument,       NULL, 'V'                       },
273                 { "help",                  no_argument,       NULL, 'h'                       },
274                 { "uuid",                  no_argument,       NULL, ARG_UUID                  },
275                 { "prioritized-subsystem", required_argument, NULL, ARG_PRIORITIZED_SUBSYSTEM },
276                 {}
277         };
278         enum {
279                 TYPE_DEVICES,
280                 TYPE_SUBSYSTEMS,
281                 TYPE_ALL,
282         } device_type = TYPE_DEVICES;
283         sd_device_action_t action = SD_DEVICE_CHANGE;
284         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
285         _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL;
286         _cleanup_(sd_event_unrefp) sd_event *event = NULL;
287         _cleanup_hashmap_free_ Hashmap *settle_hashmap = NULL;
288         usec_t ping_timeout_usec = 5 * USEC_PER_SEC;
289         bool settle = false, ping = false;
290         int c, r;
291 
292         if (running_in_chroot() > 0) {
293                 log_info("Running in chroot, ignoring request.");
294                 return 0;
295         }
296 
297         r = sd_device_enumerator_new(&e);
298         if (r < 0)
299                 return r;
300 
301         r = sd_device_enumerator_allow_uninitialized(e);
302         if (r < 0)
303                 return r;
304 
305         while ((c = getopt_long(argc, argv, "vnqt:c:s:S:a:A:p:g:y:b:wVh", options, NULL)) >= 0) {
306                 _cleanup_free_ char *buf = NULL;
307                 const char *key, *val;
308 
309                 switch (c) {
310                 case 'v':
311                         arg_verbose = true;
312                         break;
313                 case 'n':
314                         arg_dry_run = true;
315                         break;
316                 case 'q':
317                         arg_quiet = true;
318                         break;
319                 case 't':
320                         if (streq(optarg, "devices"))
321                                 device_type = TYPE_DEVICES;
322                         else if (streq(optarg, "subsystems"))
323                                 device_type = TYPE_SUBSYSTEMS;
324                         else if (streq(optarg, "all"))
325                                 device_type = TYPE_ALL;
326                         else
327                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown type --type=%s", optarg);
328                         break;
329                 case 'c':
330                         r = parse_device_action(optarg, &action);
331                         if (r < 0)
332                                 return log_error_errno(r, "Unknown action '%s'", optarg);
333                         if (r == 0)
334                                 return 0;
335                         break;
336                 case 's':
337                         r = sd_device_enumerator_add_match_subsystem(e, optarg, true);
338                         if (r < 0)
339                                 return log_error_errno(r, "Failed to add subsystem match '%s': %m", optarg);
340                         break;
341                 case 'S':
342                         r = sd_device_enumerator_add_match_subsystem(e, optarg, false);
343                         if (r < 0)
344                                 return log_error_errno(r, "Failed to add negative subsystem match '%s': %m", optarg);
345                         break;
346                 case 'a':
347                         buf = keyval(optarg, &key, &val);
348                         if (!buf)
349                                 return log_oom();
350                         r = sd_device_enumerator_add_match_sysattr(e, key, val, true);
351                         if (r < 0)
352                                 return log_error_errno(r, "Failed to add sysattr match '%s=%s': %m", key, val);
353                         break;
354                 case 'A':
355                         buf = keyval(optarg, &key, &val);
356                         if (!buf)
357                                 return log_oom();
358                         r = sd_device_enumerator_add_match_sysattr(e, key, val, false);
359                         if (r < 0)
360                                 return log_error_errno(r, "Failed to add negative sysattr match '%s=%s': %m", key, val);
361                         break;
362                 case 'p':
363                         buf = keyval(optarg, &key, &val);
364                         if (!buf)
365                                 return log_oom();
366                         r = sd_device_enumerator_add_match_property(e, key, val);
367                         if (r < 0)
368                                 return log_error_errno(r, "Failed to add property match '%s=%s': %m", key, val);
369                         break;
370                 case 'g':
371                         r = sd_device_enumerator_add_match_tag(e, optarg);
372                         if (r < 0)
373                                 return log_error_errno(r, "Failed to add tag match '%s': %m", optarg);
374                         break;
375                 case 'y':
376                         r = sd_device_enumerator_add_match_sysname(e, optarg);
377                         if (r < 0)
378                                 return log_error_errno(r, "Failed to add sysname match '%s': %m", optarg);
379                         break;
380                 case 'b': {
381                         _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
382 
383                         r = find_device(optarg, "/sys", &dev);
384                         if (r < 0)
385                                 return log_error_errno(r, "Failed to open the device '%s': %m", optarg);
386 
387                         r = device_enumerator_add_match_parent_incremental(e, dev);
388                         if (r < 0)
389                                 return log_error_errno(r, "Failed to add parent match '%s': %m", optarg);
390                         break;
391                 }
392                 case 'w':
393                         settle = true;
394                         break;
395 
396                 case ARG_NAME: {
397                         _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
398 
399                         r = find_device(optarg, "/dev", &dev);
400                         if (r < 0)
401                                 return log_error_errno(r, "Failed to open the device '%s': %m", optarg);
402 
403                         r = device_enumerator_add_match_parent_incremental(e, dev);
404                         if (r < 0)
405                                 return log_error_errno(r, "Failed to add parent match '%s': %m", optarg);
406                         break;
407                 }
408 
409                 case ARG_PING:
410                         ping = true;
411                         if (optarg) {
412                                 r = parse_sec(optarg, &ping_timeout_usec);
413                                 if (r < 0)
414                                         log_error_errno(r, "Failed to parse timeout value '%s', ignoring: %m", optarg);
415                         }
416                         break;
417 
418                 case ARG_UUID:
419                         arg_uuid = true;
420                         break;
421 
422                 case ARG_PRIORITIZED_SUBSYSTEM: {
423                         _cleanup_strv_free_ char **subsystems = NULL;
424 
425                         subsystems = strv_split(optarg, ",");
426                         if (!subsystems)
427                                 return log_error_errno(r, "Failed to parse prioritized subsystem '%s': %m", optarg);
428 
429                         STRV_FOREACH(p, subsystems) {
430                                 r = device_enumerator_add_prioritized_subsystem(e, *p);
431                                 if (r < 0)
432                                         return log_error_errno(r, "Failed to add prioritized subsystem '%s': %m", *p);
433                         }
434                         break;
435                 }
436                 case ARG_INITIALIZED_MATCH:
437                 case ARG_INITIALIZED_NOMATCH:
438                         r = device_enumerator_add_match_is_initialized(e, c == ARG_INITIALIZED_MATCH ? MATCH_INITIALIZED_YES : MATCH_INITIALIZED_NO);
439                         if (r < 0)
440                                 return log_error_errno(r, "Failed to set initialized filter: %m");
441                         break;
442                 case 'V':
443                         return print_version();
444                 case 'h':
445                         return help();
446                 case '?':
447                         return -EINVAL;
448                 default:
449                         assert_not_reached();
450                 }
451         }
452 
453         if (ping) {
454                 _cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL;
455 
456                 r = udev_ctrl_new(&uctrl);
457                 if (r < 0)
458                         return log_error_errno(r, "Failed to initialize udev control: %m");
459 
460                 r = udev_ctrl_send_ping(uctrl);
461                 if (r < 0)
462                         return log_error_errno(r, "Failed to connect to udev daemon: %m");
463 
464                 r = udev_ctrl_wait(uctrl, ping_timeout_usec);
465                 if (r < 0)
466                         return log_error_errno(r, "Failed to wait for daemon to reply: %m");
467         }
468 
469         for (; optind < argc; optind++) {
470                 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
471 
472                 r = find_device(argv[optind], NULL, &dev);
473                 if (r < 0)
474                         return log_error_errno(r, "Failed to open the device '%s': %m", argv[optind]);
475 
476                 r = device_enumerator_add_match_parent_incremental(e, dev);
477                 if (r < 0)
478                         return log_error_errno(r, "Failed to add parent match '%s': %m", argv[optind]);
479         }
480 
481         if (settle) {
482                 settle_hashmap = hashmap_new(&path_hash_ops_free_free);
483                 if (!settle_hashmap)
484                         return log_oom();
485 
486                 r = sd_event_default(&event);
487                 if (r < 0)
488                         return log_error_errno(r, "Failed to get default event: %m");
489 
490                 r = sd_device_monitor_new(&m);
491                 if (r < 0)
492                         return log_error_errno(r, "Failed to create device monitor object: %m");
493 
494                 r = sd_device_monitor_attach_event(m, event);
495                 if (r < 0)
496                         return log_error_errno(r, "Failed to attach event to device monitor: %m");
497 
498                 r = sd_device_monitor_start(m, device_monitor_handler, settle_hashmap);
499                 if (r < 0)
500                         return log_error_errno(r, "Failed to start device monitor: %m");
501         }
502 
503         switch (device_type) {
504         case TYPE_SUBSYSTEMS:
505                 r = device_enumerator_scan_subsystems(e);
506                 if (r < 0)
507                         return log_error_errno(r, "Failed to scan subsystems: %m");
508                 break;
509         case TYPE_DEVICES:
510                 r = device_enumerator_scan_devices(e);
511                 if (r < 0)
512                         return log_error_errno(r, "Failed to scan devices: %m");
513                 break;
514         case TYPE_ALL:
515                 r = device_enumerator_scan_devices_and_subsystems(e);
516                 if (r < 0)
517                         return log_error_errno(r, "Failed to scan devices and subsystems: %m");
518                 break;
519         default:
520                 assert_not_reached();
521         }
522 
523         r = exec_list(e, action, settle_hashmap);
524         if (r < 0)
525                 return r;
526 
527         if (event && !hashmap_isempty(settle_hashmap)) {
528                 r = sd_event_loop(event);
529                 if (r < 0)
530                         return log_error_errno(r, "Event loop failed: %m");
531         }
532 
533         return 0;
534 }
535