2424static bool arg_verbose = false;
2525static bool arg_dry_run = false;
2626static bool arg_quiet = false;
27+ static bool arg_uuid = false;
2728
28- static int exec_list (sd_device_enumerator * e , sd_device_action_t action , Set * * settle_set ) {
29+ static int exec_list (
30+ sd_device_enumerator * e ,
31+ sd_device_action_t action ,
32+ Hashmap * settle_hashmap ) {
33+
34+ bool skip_uuid_logic = false;
2935 const char * action_str ;
3036 sd_device * d ;
3137 int r , ret = 0 ;
3238
3339 action_str = device_action_to_string (action );
3440
3541 FOREACH_DEVICE_AND_SUBSYSTEM (e , d ) {
42+ sd_id128_t id = SD_ID128_NULL ;
3643 const char * syspath ;
3744
38- if (sd_device_get_syspath (d , & syspath ) < 0 )
45+ r = sd_device_get_syspath (d , & syspath );
46+ if (r < 0 ) {
47+ log_debug_errno (r , "Failed to get syspath of enumerated devices, ignoring: %m" );
3948 continue ;
49+ }
4050
4151 if (arg_verbose )
42- printf ("%s\n" , strna ( syspath ) );
52+ printf ("%s\n" , syspath );
4353
4454 if (arg_dry_run )
4555 continue ;
4656
47- r = sd_device_trigger (d , action );
57+ /* Use the UUID mode if the user explicitly asked for it, or if --settle has been specified,
58+ * so that we can recognize our own uevent. */
59+ r = sd_device_trigger_with_uuid (d , action , (arg_uuid || settle_hashmap ) && !skip_uuid_logic ? & id : NULL );
60+ if (r == - EINVAL && !arg_uuid && settle_hashmap && !skip_uuid_logic ) {
61+ /* If we specified a UUID because of the settling logic, and we got EINVAL this might
62+ * be caused by an old kernel which doesn't know the UUID logic (pre-4.13). Let's try
63+ * if it works without the UUID logic then. */
64+ r = sd_device_trigger (d , action );
65+ if (r != - EINVAL )
66+ skip_uuid_logic = true; /* dropping the uuid stuff changed the return code,
67+ * hence don't bother next time */
68+ }
4869 if (r < 0 ) {
4970 /* ENOENT may be returned when a device does not have /uevent or is already
5071 * removed. Hence, this is logged at debug level and ignored.
@@ -86,35 +107,80 @@ static int exec_list(sd_device_enumerator *e, sd_device_action_t action, Set **s
86107 continue ;
87108 }
88109
89- if (settle_set ) {
90- r = set_put_strdup (settle_set , syspath );
110+ /* If the user asked for it, write event UUID to stdout */
111+ if (arg_uuid )
112+ printf (SD_ID128_FORMAT_STR "\n" , SD_ID128_FORMAT_VAL (id ));
113+
114+ if (settle_hashmap ) {
115+ _cleanup_free_ sd_id128_t * mid = NULL ;
116+ _cleanup_free_ char * sp = NULL ;
117+
118+ sp = strdup (syspath );
119+ if (!sp )
120+ return log_oom ();
121+
122+ mid = newdup (sd_id128_t , & id , 1 );
123+ if (!d )
124+ return log_oom ();
125+
126+ r = hashmap_put (settle_hashmap , sp , mid );
91127 if (r < 0 )
92128 return log_oom ();
129+
130+ TAKE_PTR (sp );
131+ TAKE_PTR (mid );
93132 }
94133 }
95134
96135 return ret ;
97136}
98137
99138static int device_monitor_handler (sd_device_monitor * m , sd_device * dev , void * userdata ) {
100- _cleanup_free_ char * val = NULL ;
101- Set * settle_set = userdata ;
139+ Hashmap * settle_hashmap = userdata ;
140+ sd_id128_t * settle_id ;
102141 const char * syspath ;
142+ char * k ;
143+ int r ;
103144
104145 assert (dev );
105- assert (settle_set );
146+ assert (settle_hashmap );
106147
107- if (sd_device_get_syspath (dev , & syspath ) < 0 )
148+ r = sd_device_get_syspath (dev , & syspath );
149+ if (r < 0 ) {
150+ log_debug_errno (r , "Failed to get syspath of device event, ignoring: %m" );
108151 return 0 ;
152+ }
153+
154+ settle_id = hashmap_get2 (settle_hashmap , syspath , (void * * ) & k );
155+ if (!settle_id ) {
156+ log_debug ("Got uevent for unexpected device '%s', ignoring." , syspath );
157+ return 0 ;
158+ }
159+ 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 */
160+ sd_id128_t event_id ;
161+
162+ r = sd_device_get_trigger_uuid (dev , & event_id );
163+ if (r < 0 ) {
164+ log_debug_errno (r , "Got uevent without synthetic UUID for device '%s', ignoring: %m" , syspath );
165+ return 0 ;
166+ }
167+
168+ if (!sd_id128_equal (event_id , * settle_id )) {
169+ log_debug ("Got uevent not matching expected UUID for device '%s', ignoring." , syspath );
170+ return 0 ;
171+ }
172+ }
109173
110174 if (arg_verbose )
111175 printf ("settle %s\n" , syspath );
112176
113- val = set_remove (settle_set , syspath );
114- if (!val )
115- log_debug ("Got epoll event on syspath %s not present in syspath set" , syspath );
177+ if (arg_uuid )
178+ printf ("settle " SD_ID128_FORMAT_STR "\n" , SD_ID128_FORMAT_VAL (* settle_id ));
179+
180+ free (hashmap_remove (settle_hashmap , syspath ));
181+ free (k );
116182
117- if (set_isempty ( settle_set ))
183+ if (hashmap_isempty ( settle_hashmap ))
118184 return sd_event_exit (sd_device_monitor_get_event (m ), 0 );
119185
120186 return 0 ;
@@ -162,7 +228,8 @@ static int help(void) {
162228 " -b --parent-match=NAME Trigger devices with that parent device\n"
163229 " -w --settle Wait for the triggered events to complete\n"
164230 " --wait-daemon[=SECONDS] Wait for udevd daemon to be initialized\n"
165- " before triggering uevents\n" ,
231+ " before triggering uevents\n"
232+ " --uuid Print synthetic uevent UUID\n" ,
166233 program_invocation_short_name );
167234
168235 return 0 ;
@@ -172,6 +239,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
172239 enum {
173240 ARG_NAME = 0x100 ,
174241 ARG_PING ,
242+ ARG_UUID ,
175243 };
176244
177245 static const struct option options [] = {
@@ -193,6 +261,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
193261 { "wait-daemon" , optional_argument , NULL , ARG_PING },
194262 { "version" , no_argument , NULL , 'V' },
195263 { "help" , no_argument , NULL , 'h' },
264+ { "uuid" , no_argument , NULL , ARG_UUID },
196265 {}
197266 };
198267 enum {
@@ -203,7 +272,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
203272 _cleanup_ (sd_device_enumerator_unrefp ) sd_device_enumerator * e = NULL ;
204273 _cleanup_ (sd_device_monitor_unrefp ) sd_device_monitor * m = NULL ;
205274 _cleanup_ (sd_event_unrefp ) sd_event * event = NULL ;
206- _cleanup_set_free_ Set * settle_set = NULL ;
275+ _cleanup_hashmap_free_ Hashmap * settle_hashmap = NULL ;
207276 usec_t ping_timeout_usec = 5 * USEC_PER_SEC ;
208277 bool settle = false, ping = false;
209278 int c , r ;
@@ -327,15 +396,18 @@ int trigger_main(int argc, char *argv[], void *userdata) {
327396 break ;
328397 }
329398
330- case ARG_PING : {
399+ case ARG_PING :
331400 ping = true;
332401 if (optarg ) {
333402 r = parse_sec (optarg , & ping_timeout_usec );
334403 if (r < 0 )
335404 log_error_errno (r , "Failed to parse timeout value '%s', ignoring: %m" , optarg );
336405 }
337406 break ;
338- }
407+
408+ case ARG_UUID :
409+ arg_uuid = true;
410+ break ;
339411
340412 case 'V' :
341413 return print_version ();
@@ -377,8 +449,8 @@ int trigger_main(int argc, char *argv[], void *userdata) {
377449 }
378450
379451 if (settle ) {
380- settle_set = set_new ( & string_hash_ops_free );
381- if (!settle_set )
452+ settle_hashmap = hashmap_new ( & path_hash_ops_free_free );
453+ if (!settle_hashmap )
382454 return log_oom ();
383455
384456 r = sd_event_default (& event );
@@ -393,7 +465,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
393465 if (r < 0 )
394466 return log_error_errno (r , "Failed to attach event to device monitor: %m" );
395467
396- r = sd_device_monitor_start (m , device_monitor_handler , settle_set );
468+ r = sd_device_monitor_start (m , device_monitor_handler , settle_hashmap );
397469 if (r < 0 )
398470 return log_error_errno (r , "Failed to start device monitor: %m" );
399471 }
@@ -413,11 +485,11 @@ int trigger_main(int argc, char *argv[], void *userdata) {
413485 assert_not_reached ("Unknown device type" );
414486 }
415487
416- r = exec_list (e , action , settle ? & settle_set : NULL );
488+ r = exec_list (e , action , settle_hashmap );
417489 if (r < 0 )
418490 return r ;
419491
420- if (event && !set_isempty ( settle_set )) {
492+ if (event && !hashmap_isempty ( settle_hashmap )) {
421493 r = sd_event_loop (event );
422494 if (r < 0 )
423495 return log_error_errno (r , "Event loop failed: %m" );
0 commit comments