1515 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1616 */
1717
18+ #include <assert.h>
19+ #include <fcntl.h>
1820#include <stdio.h>
1921#include <unistd.h>
2022#include <string.h>
2123#include <stdlib.h>
2224#include <limits.h>
25+ #include <spawn.h>
2326#include <sys/stat.h>
27+ #include <sys/wait.h>
2428#include <linux/input.h>
2529
2630#include "udev.h"
5256#define INPUT_PROP_CNT 0x20
5357#endif
5458
59+ #ifndef RULES_HELPER_PATH
60+ #error "RULES_HELPER_PATH not specified"
61+ #endif
62+
63+ #ifndef UEVENT_NUM_ENVP
64+ #define UEVENT_NUM_ENVP 64
65+ #endif
66+
67+ #ifndef UEVENT_BUFFER_SIZE
68+ #define UEVENT_BUFFER_SIZE 2048
69+ #endif
70+
5571struct udev_device {
5672 struct udev_list_entry properties ;
5773 struct udev_list_entry sysattrs ;
@@ -349,19 +365,10 @@ static char *read_symlink(const char *syspath, const char *name)
349365 return strdup (strrchr (link , '/' ) + 1 );
350366}
351367
352- static int set_properties_from_uevent (struct udev_device * udev_device , const char * syspath )
368+ static void set_properties_from_file (struct udev_device * udev_device , FILE * file )
353369{
354- char line [LINE_MAX ], path [PATH_MAX + sizeof ("/uevent" )], devnode [PATH_MAX ];
355- FILE * file ;
370+ char line [LINE_MAX ], devnode [PATH_MAX ];
356371 char * pos ;
357-
358- snprintf (path , sizeof (path ), "%s/uevent" , syspath );
359- file = fopen (path , "r" );
360-
361- if (!file ) {
362- return -1 ;
363- }
364-
365372 while (fgets (line , sizeof (line ), file )) {
366373 line [strlen (line ) - 1 ] = '\0' ;
367374
@@ -374,7 +381,21 @@ static int set_properties_from_uevent(struct udev_device *udev_device, const cha
374381 udev_list_entry_add (& udev_device -> properties , line , pos + 1 , 0 );
375382 }
376383 }
384+ }
385+
386+ static int set_properties_from_uevent (struct udev_device * udev_device , const char * syspath )
387+ {
388+ char path [PATH_MAX + sizeof ("/uevent" )];
389+ FILE * file ;
390+
391+ snprintf (path , sizeof (path ), "%s/uevent" , syspath );
392+ file = fopen (path , "r" );
377393
394+ if (!file ) {
395+ return -1 ;
396+ }
397+
398+ set_properties_from_file (udev_device , file );
378399 fclose (file );
379400 return 0 ;
380401}
@@ -540,6 +561,80 @@ static void set_properties_from_props(struct udev_device *udev_device)
540561 udev_list_entry_add (& udev_device -> properties , "ID_PATH" , id , 0 );
541562}
542563
564+ static int set_properties_from_helper (struct udev_device * udev_device )
565+ {
566+ char * envp [UEVENT_NUM_ENVP ];
567+ char env [UEVENT_BUFFER_SIZE ];
568+
569+ size_t env_offset = 0 ;
570+ size_t env_idx = 0 ;
571+ struct udev_list_entry * entry ;
572+
573+ for (entry = udev_device_get_properties_list_entry (udev_device );
574+ entry ;
575+ entry = udev_list_entry_get_next (entry )) {
576+ const char * name = entry -> name ;
577+ const char * value = entry -> value ? entry -> value : "" ;
578+
579+ // '{name}={value}\0'
580+ size_t max_size = strlen (name ) + 1 + strlen (value ) + 1 ;
581+
582+ assert (env_offset + max_size < UEVENT_BUFFER_SIZE );
583+ snprintf (& env [env_offset ], max_size , "%s=%s" , name , value );
584+
585+ assert (env_idx < UEVENT_NUM_ENVP );
586+ envp [env_idx ] = & env [env_offset ];
587+
588+ env_offset += max_size ;
589+ env_idx ++ ;
590+ }
591+
592+ assert (env_idx < UEVENT_NUM_ENVP );
593+ envp [env_idx ] = NULL ;
594+
595+ int out_pipe [2 ];
596+
597+ if (pipe2 (out_pipe , O_CLOEXEC )) {
598+ return -1 ;
599+ }
600+
601+ posix_spawn_file_actions_t actions ;
602+
603+ posix_spawn_file_actions_init (& actions );
604+ posix_spawn_file_actions_addclose (& actions , out_pipe [0 ]);
605+ posix_spawn_file_actions_addopen (& actions , STDIN_FILENO , "/dev/null" , O_RDONLY , 0 );
606+ posix_spawn_file_actions_adddup2 (& actions , out_pipe [1 ], STDOUT_FILENO );
607+ posix_spawn_file_actions_addopen (& actions , STDERR_FILENO , "/dev/null" , O_WRONLY , 0 );
608+ posix_spawn_file_actions_addclose (& actions , out_pipe [1 ]);
609+
610+ pid_t pid ;
611+
612+ char argv0 [] = RULES_HELPER_PATH ;
613+ char * argv [] = { argv0 , NULL };
614+
615+ if (posix_spawn (& pid , argv0 , & actions , NULL , argv , envp )) {
616+ return -1 ;
617+ }
618+
619+ posix_spawn_file_actions_destroy (& actions );
620+ close (out_pipe [1 ]);
621+
622+ FILE * file = fdopen (out_pipe [0 ], "r" );
623+
624+ if (!file ) {
625+ return -1 ;
626+ }
627+
628+ set_properties_from_file (udev_device , file );
629+
630+ fclose (file );
631+
632+ int status ;
633+ waitpid (pid , & status , 0 );
634+
635+ return 0 ;
636+ }
637+
543638struct udev_device * udev_device_new_from_syspath (struct udev * udev , const char * syspath )
544639{
545640 char * subsystem , * driver , * sysname ;
@@ -593,6 +688,7 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *
593688
594689 set_properties_from_evdev (udev_device );
595690 set_properties_from_props (udev_device );
691+ set_properties_from_helper (udev_device );
596692
597693 free (driver );
598694 free (subsystem );
@@ -712,6 +808,7 @@ struct udev_device *udev_device_new_from_uevent(struct udev *udev, char *buf, si
712808
713809 set_properties_from_props (udev_device );
714810 set_properties_from_evdev (udev_device );
811+ set_properties_from_helper (udev_device );
715812 return udev_device ;
716813}
717814
0 commit comments