2424#include <string.h>
2525#include <unistd.h>
2626
27+ #include "fd-util.h"
28+ #include "set.h"
2729#include "string-util.h"
2830#include "udev-util.h"
2931#include "udev.h"
3335static int verbose ;
3436static int dry_run ;
3537
36- static void exec_list (struct udev_enumerate * udev_enumerate , const char * action ) {
38+ static int exec_list (struct udev_enumerate * udev_enumerate , const char * action , Set * settle_set ) {
3739 struct udev_list_entry * entry ;
40+ int r ;
3841
3942 udev_list_entry_foreach (entry , udev_enumerate_get_list_entry (udev_enumerate )) {
4043 char filename [UTIL_PATH_SIZE ];
44+ const char * syspath ;
4145 int fd ;
4246
47+ syspath = udev_list_entry_get_name (entry );
4348 if (verbose )
44- printf ("%s\n" , udev_list_entry_get_name ( entry ) );
49+ printf ("%s\n" , syspath );
4550 if (dry_run )
4651 continue ;
47- strscpyl (filename , sizeof (filename ), udev_list_entry_get_name (entry ), "/uevent" , NULL );
52+
53+ strscpyl (filename , sizeof (filename ), syspath , "/uevent" , NULL );
4854 fd = open (filename , O_WRONLY |O_CLOEXEC );
4955 if (fd < 0 )
5056 continue ;
57+ if (settle_set ) {
58+ r = set_put_strdup (settle_set , syspath );
59+ if (r < 0 )
60+ return log_oom ();
61+ }
5162 if (write (fd , action , strlen (action )) < 0 )
5263 log_debug_errno (errno , "error writing '%s' to '%s': %m" , action , filename );
5364 close (fd );
5465 }
66+
67+ return 0 ;
5568}
5669
5770static const char * keyval (const char * str , const char * * val , char * buf , size_t size ) {
@@ -87,6 +100,7 @@ static void help(void) {
87100 " -y --sysname-match=NAME Trigger devices with this /sys path\n"
88101 " --name-match=NAME Trigger devices with this /dev name\n"
89102 " -b --parent-match=NAME Trigger devices with that parent device\n"
103+ " -w --settle Wait for the triggered events to complete\n"
90104 , program_invocation_short_name );
91105}
92106
@@ -109,6 +123,7 @@ static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
109123 { "sysname-match" , required_argument , NULL , 'y' },
110124 { "name-match" , required_argument , NULL , ARG_NAME },
111125 { "parent-match" , required_argument , NULL , 'b' },
126+ { "settle" , no_argument , NULL , 'w' },
112127 { "version" , no_argument , NULL , 'V' },
113128 { "help" , no_argument , NULL , 'h' },
114129 {}
@@ -119,13 +134,19 @@ static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
119134 } device_type = TYPE_DEVICES ;
120135 const char * action = "change" ;
121136 _cleanup_udev_enumerate_unref_ struct udev_enumerate * udev_enumerate = NULL ;
137+ _cleanup_udev_monitor_unref_ struct udev_monitor * udev_monitor = NULL ;
138+ _cleanup_close_ int fd_ep = -1 ;
139+ int fd_udev = -1 ;
140+ struct epoll_event ep_udev ;
141+ bool settle = false;
142+ _cleanup_set_free_free_ Set * settle_set = NULL ;
122143 int c , r ;
123144
124145 udev_enumerate = udev_enumerate_new (udev );
125- if (udev_enumerate == NULL )
146+ if (! udev_enumerate )
126147 return 1 ;
127148
128- while ((c = getopt_long (argc , argv , "vnt:c:s:S:a:A:p:g:y:b:Vh " , options , NULL )) >= 0 ) {
149+ while ((c = getopt_long (argc , argv , "vnt:c:s:S:a:A:p:g:y:b:wVh " , options , NULL )) >= 0 ) {
129150 const char * key ;
130151 const char * val ;
131152 char buf [UTIL_PATH_SIZE ];
@@ -211,7 +232,7 @@ static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
211232 _cleanup_udev_device_unref_ struct udev_device * dev ;
212233
213234 dev = find_device (udev , optarg , "/sys" );
214- if (dev == NULL ) {
235+ if (! dev ) {
215236 log_error ("unable to open the device '%s'" , optarg );
216237 return 2 ;
217238 }
@@ -223,12 +244,15 @@ static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
223244 }
224245 break ;
225246 }
247+ case 'w' :
248+ settle = true;
249+ break ;
226250
227251 case ARG_NAME : {
228252 _cleanup_udev_device_unref_ struct udev_device * dev ;
229253
230254 dev = find_device (udev , optarg , "/dev/" );
231- if (dev == NULL ) {
255+ if (! dev ) {
232256 log_error ("unable to open the device '%s'" , optarg );
233257 return 2 ;
234258 }
@@ -258,7 +282,7 @@ static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
258282 _cleanup_udev_device_unref_ struct udev_device * dev ;
259283
260284 dev = find_device (udev , argv [optind ], NULL );
261- if (dev == NULL ) {
285+ if (! dev ) {
262286 log_error ("unable to open the device '%s'" , argv [optind ]);
263287 return 2 ;
264288 }
@@ -270,18 +294,83 @@ static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
270294 }
271295 }
272296
297+ if (settle ) {
298+ fd_ep = epoll_create1 (EPOLL_CLOEXEC );
299+ if (fd_ep < 0 ) {
300+ log_error_errno (errno , "error creating epoll fd: %m" );
301+ return 1 ;
302+ }
303+
304+ udev_monitor = udev_monitor_new_from_netlink (udev , "udev" );
305+ if (!udev_monitor ) {
306+ log_error ("error: unable to create netlink socket" );
307+ return 3 ;
308+ }
309+ fd_udev = udev_monitor_get_fd (udev_monitor );
310+
311+ if (udev_monitor_enable_receiving (udev_monitor ) < 0 ) {
312+ log_error ("error: unable to subscribe to udev events" );
313+ return 4 ;
314+ }
315+
316+ ep_udev = (struct epoll_event ) { .events = EPOLLIN , .data .fd = fd_udev };
317+ if (epoll_ctl (fd_ep , EPOLL_CTL_ADD , fd_udev , & ep_udev ) < 0 ) {
318+ log_error_errno (errno , "fail to add fd to epoll: %m" );
319+ return 5 ;
320+ }
321+
322+ settle_set = set_new (& string_hash_ops );
323+ if (!settle_set ) {
324+ log_oom ();
325+ return 1 ;
326+ }
327+ }
328+
273329 switch (device_type ) {
274330 case TYPE_SUBSYSTEMS :
275331 udev_enumerate_scan_subsystems (udev_enumerate );
276- exec_list (udev_enumerate , action );
277- return 0 ;
332+ break ;
278333 case TYPE_DEVICES :
279334 udev_enumerate_scan_devices (udev_enumerate );
280- exec_list (udev_enumerate , action );
281- return 0 ;
335+ break ;
282336 default :
283337 assert_not_reached ("device_type" );
284338 }
339+ r = exec_list (udev_enumerate , action , settle_set );
340+ if (r < 0 )
341+ return 1 ;
342+
343+ while (!set_isempty (settle_set )) {
344+ int fdcount ;
345+ struct epoll_event ev [4 ];
346+ int i ;
347+
348+ fdcount = epoll_wait (fd_ep , ev , ELEMENTSOF (ev ), -1 );
349+ if (fdcount < 0 ) {
350+ if (errno != EINTR )
351+ log_error_errno (errno , "error receiving uevent message: %m" );
352+ continue ;
353+ }
354+
355+ for (i = 0 ; i < fdcount ; i ++ ) {
356+ if (ev [i ].data .fd == fd_udev && ev [i ].events & EPOLLIN ) {
357+ _cleanup_udev_device_unref_ struct udev_device * device ;
358+ const char * syspath = NULL ;
359+
360+ device = udev_monitor_receive_device (udev_monitor );
361+ if (!device )
362+ continue ;
363+
364+ syspath = udev_device_get_syspath (device );
365+ if (verbose )
366+ printf ("settle %s\n" , syspath );
367+ if (!set_remove (settle_set , syspath ))
368+ log_debug ("Got epoll event on syspath %s not present in syspath set" , syspath );
369+ }
370+ }
371+ }
372+
373+ return 0 ;
285374}
286375
287376const struct udevadm_cmd udevadm_trigger = {
0 commit comments