3535#include "device-monitor-private.h"
3636#include "device-private.h"
3737#include "device-util.h"
38+ #include "errno-list.h"
3839#include "event-util.h"
3940#include "fd-util.h"
4041#include "fileio.h"
@@ -157,11 +158,15 @@ typedef struct Worker {
157158
158159/* passed from worker to main process */
159160typedef enum EventResult {
160- EVENT_RESULT_SUCCESS ,
161- EVENT_RESULT_FAILED ,
162- EVENT_RESULT_TRY_AGAIN , /* when the block device is locked by another process. */
161+ EVENT_RESULT_NERRNO_MIN = - ERRNO_MAX ,
162+ EVENT_RESULT_NERRNO_MAX = -1 ,
163+ EVENT_RESULT_EXIT_STATUS_BASE = 0 ,
164+ EVENT_RESULT_EXIT_STATUS_MAX = 255 ,
165+ EVENT_RESULT_TRY_AGAIN = 256 , /* when the block device is locked by another process. */
166+ EVENT_RESULT_SIGNAL_BASE = 257 ,
167+ EVENT_RESULT_SIGNAL_MAX = EVENT_RESULT_SIGNAL_BASE + _NSIG ,
163168 _EVENT_RESULT_MAX ,
164- _EVENT_RESULT_INVALID = - EINVAL ,
169+ _EVENT_RESULT_INVALID = - EINVAL ,
165170} EventResult ;
166171
167172static Event * event_free (Event * event ) {
@@ -356,7 +361,7 @@ static int on_kill_workers_event(sd_event_source *s, uint64_t usec, void *userda
356361 return 1 ;
357362}
358363
359- static void device_broadcast (sd_device_monitor * monitor , sd_device * dev ) {
364+ static void device_broadcast (sd_device_monitor * monitor , sd_device * dev , int result ) {
360365 int r ;
361366
362367 assert (dev );
@@ -365,13 +370,40 @@ static void device_broadcast(sd_device_monitor *monitor, sd_device *dev) {
365370 if (!monitor )
366371 return ;
367372
373+ if (result != 0 ) {
374+ (void ) device_add_property (dev , "UDEV_WORKER_FAILED" , "1" );
375+
376+ switch (result ) {
377+ case EVENT_RESULT_NERRNO_MIN ... EVENT_RESULT_NERRNO_MAX :
378+ (void ) device_add_propertyf (dev , "UDEV_WORKER_ERRNO" , "%i" , - result );
379+ (void ) device_add_propertyf (dev , "UDEV_WORKER_ERRNO_NAME" , "%s" , strna (errno_to_name (result )));
380+ break ;
381+
382+ case EVENT_RESULT_EXIT_STATUS_BASE ... EVENT_RESULT_EXIT_STATUS_MAX :
383+ (void ) device_add_propertyf (dev , "UDEV_WORKER_EXIT_STATUS" , "%i" , result - EVENT_RESULT_EXIT_STATUS_BASE );
384+ break ;
385+
386+ case EVENT_RESULT_TRY_AGAIN :
387+ assert_not_reached ();
388+ break ;
389+
390+ case EVENT_RESULT_SIGNAL_BASE ... EVENT_RESULT_SIGNAL_MAX :
391+ (void ) device_add_propertyf (dev , "UDEV_WORKER_SIGNAL" , "%i" , result - EVENT_RESULT_SIGNAL_BASE );
392+ (void ) device_add_propertyf (dev , "UDEV_WORKER_SIGNAL_NAME" , "%s" , strna (signal_to_string (result - EVENT_RESULT_SIGNAL_BASE )));
393+ break ;
394+
395+ default :
396+ log_device_warning (dev , "Unknown event result \"%i\", ignoring." , result );
397+ }
398+ }
399+
368400 r = device_monitor_send_device (monitor , NULL , dev );
369401 if (r < 0 )
370402 log_device_warning_errno (dev , r ,
371403 "Failed to broadcast event to libudev listeners, ignoring: %m" );
372404}
373405
374- static int worker_send_result (Manager * manager , EventResult result ) {
406+ static int worker_send_result (Manager * manager , int result ) {
375407 assert (manager );
376408 assert (manager -> worker_watch [WRITE_END ] >= 0 );
377409
@@ -536,6 +568,8 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
536568 *
537569 * The user-facing side of this: https://systemd.io/BLOCK_DEVICE_LOCKING */
538570 r = worker_lock_block_device (dev , & fd_lock );
571+ if (r == - EAGAIN )
572+ return EVENT_RESULT_TRY_AGAIN ;
539573 if (r < 0 )
540574 return r ;
541575
@@ -568,29 +602,25 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
568602
569603static int worker_device_monitor_handler (sd_device_monitor * monitor , sd_device * dev , void * userdata ) {
570604 Manager * manager = userdata ;
571- EventResult result ;
572605 int r ;
573606
574607 assert (dev );
575608 assert (manager );
576609
577610 r = worker_process_device (manager , dev );
578- if (r == - EAGAIN ) {
611+ if (r == EVENT_RESULT_TRY_AGAIN )
579612 /* if we couldn't acquire the flock(), then requeue the event */
580- result = EVENT_RESULT_TRY_AGAIN ;
581- log_device_debug_errno (dev , r , "Block device is currently locked, requeueing the event." );
582- } else if (r < 0 ) {
583- result = EVENT_RESULT_FAILED ;
584- log_device_warning_errno (dev , r , "Failed to process device, ignoring: %m" );
585- } else
586- result = EVENT_RESULT_SUCCESS ;
613+ log_device_debug (dev , "Block device is currently locked, requeueing the event." );
614+ else {
615+ if (r < 0 )
616+ log_device_warning_errno (dev , r , "Failed to process device, ignoring: %m" );
587617
588- if (result != EVENT_RESULT_TRY_AGAIN )
589618 /* send processed event back to libudev listeners */
590- device_broadcast (monitor , dev );
619+ device_broadcast (monitor , dev , r );
620+ }
591621
592622 /* send udevd the result of the event execution */
593- r = worker_send_result (manager , result );
623+ r = worker_send_result (manager , r );
594624 if (r < 0 )
595625 log_device_warning_errno (dev , r , "Failed to send signal to main daemon, ignoring: %m" );
596626
@@ -1150,7 +1180,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
11501180 assert (manager );
11511181
11521182 for (;;) {
1153- EventResult result ;
1183+ int result ;
11541184 struct iovec iovec = IOVEC_MAKE (& result , sizeof (result ));
11551185 CMSG_BUFFER_TYPE (CMSG_SPACE (sizeof (struct ucred ))) control ;
11561186 struct msghdr msghdr = {
@@ -1174,7 +1204,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
11741204
11751205 cmsg_close_all (& msghdr );
11761206
1177- if (size != sizeof (EventResult )) {
1207+ if (size != sizeof (result )) {
11781208 log_warning ("Ignoring worker message with invalid size %zi bytes" , size );
11791209 continue ;
11801210 }
@@ -1201,7 +1231,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat
12011231 /* worker returned */
12021232 if (result == EVENT_RESULT_TRY_AGAIN &&
12031233 event_requeue (worker -> event ) < 0 )
1204- device_broadcast (manager -> monitor , worker -> event -> dev );
1234+ device_broadcast (manager -> monitor , worker -> event -> dev , - ETIMEDOUT );
12051235
12061236 /* When event_requeue() succeeds, worker->event is NULL, and event_free() handles NULL gracefully. */
12071237 event_free (worker -> event );
@@ -1543,7 +1573,9 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi
15431573 device_tag_index (worker -> event -> dev , NULL , false);
15441574
15451575 /* Forward kernel event to libudev listeners */
1546- device_broadcast (manager -> monitor , worker -> event -> dev );
1576+ device_broadcast (manager -> monitor , worker -> event -> dev ,
1577+ WIFEXITED (status ) ? EVENT_RESULT_EXIT_STATUS_BASE + WEXITSTATUS (status ):
1578+ WIFSIGNALED (status ) ? EVENT_RESULT_SIGNAL_BASE + WTERMSIG (status ) : 0 );
15471579 }
15481580
15491581 worker_free (worker );
0 commit comments