2020#include <string.h>
2121#include <stdlib.h>
2222#include <limits.h>
23+ #include <spawn.h>
2324#include <sys/stat.h>
25+ #include <sys/wait.h>
2426#include <linux/input.h>
2527
2628#include "udev.h"
5254#define INPUT_PROP_CNT 0x20
5355#endif
5456
57+ #ifndef RULES_HELPER_PATH
58+ #define RULES_HELPER_PATH "/sbin/libudev-zero-rules-helper"
59+ #endif
60+
61+ #ifndef UEVENT_NUM_ENVP
62+ #define UEVENT_NUM_ENVP 64
63+ #endif
64+
65+ #ifndef UEVENT_BUFFER_SIZE
66+ #define UEVENT_BUFFER_SIZE 2048
67+ #endif
68+
5569struct udev_device {
5670 struct udev_list_entry properties ;
5771 struct udev_list_entry sysattrs ;
@@ -349,19 +363,10 @@ static char *read_symlink(const char *syspath, const char *name)
349363 return strdup (strrchr (link , '/' ) + 1 );
350364}
351365
352- static int set_properties_from_uevent (struct udev_device * udev_device , const char * syspath )
366+ static void set_properties_from_file (struct udev_device * udev_device , FILE * file )
353367{
354- char line [LINE_MAX ], path [PATH_MAX + sizeof ("/uevent" )], devnode [PATH_MAX ];
355- FILE * file ;
368+ char line [LINE_MAX ], devnode [PATH_MAX ];
356369 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-
365370 while (fgets (line , sizeof (line ), file )) {
366371 line [strlen (line ) - 1 ] = '\0' ;
367372
@@ -374,7 +379,21 @@ static int set_properties_from_uevent(struct udev_device *udev_device, const cha
374379 udev_list_entry_add (& udev_device -> properties , line , pos + 1 , 0 );
375380 }
376381 }
382+ }
383+
384+ static int set_properties_from_uevent (struct udev_device * udev_device , const char * syspath )
385+ {
386+ char path [PATH_MAX + sizeof ("/uevent" )];
387+ FILE * file ;
388+
389+ snprintf (path , sizeof (path ), "%s/uevent" , syspath );
390+ file = fopen (path , "r" );
391+
392+ if (!file ) {
393+ return -1 ;
394+ }
377395
396+ set_properties_from_file (udev_device , file );
378397 fclose (file );
379398 return 0 ;
380399}
@@ -540,6 +559,70 @@ static void set_properties_from_props(struct udev_device *udev_device)
540559 udev_list_entry_add (& udev_device -> properties , "ID_PATH" , id , 0 );
541560}
542561
562+ static int set_properties_from_helper (struct udev_device * udev_device )
563+ {
564+ char * envp [UEVENT_NUM_ENVP ];
565+ char env [UEVENT_BUFFER_SIZE ];
566+
567+ char * ptr = env ;
568+ size_t i = 0 ;
569+ struct udev_list_entry * entry ;
570+
571+ for (entry = udev_device_get_properties_list_entry (udev_device );
572+ entry ;
573+ entry = udev_list_entry_get_next (entry )) {
574+ const char * name = entry -> name ;
575+ const char * value = entry -> value ? entry -> value : "" ;
576+
577+ // '{name}={value}\0'
578+ size_t max_size = strlen (name ) + 1 + strlen (value ) + 1 ;
579+ snprintf (ptr , max_size , "%s=%s" , name , value );
580+
581+ envp [i ] = ptr ;
582+ ptr += max_size ;
583+ i ++ ;
584+ }
585+
586+ envp [i ] = NULL ;
587+
588+ int out_pipe [2 ];
589+
590+ if (pipe (out_pipe )) {
591+ return -1 ;
592+ }
593+
594+ posix_spawn_file_actions_t actions ;
595+
596+ posix_spawn_file_actions_init (& actions );
597+ posix_spawn_file_actions_addclose (& actions , out_pipe [0 ]);
598+ posix_spawn_file_actions_adddup2 (& actions , out_pipe [1 ], 1 );
599+ posix_spawn_file_actions_addclose (& actions , out_pipe [1 ]);
600+
601+ pid_t pid ;
602+
603+ char argv0 [] = RULES_HELPER_PATH ;
604+ char * argv [] = { argv0 , NULL };
605+
606+ if (posix_spawn (& pid , argv0 , & actions , NULL , argv , envp )) {
607+ return -1 ;
608+ }
609+
610+ close (out_pipe [1 ]);
611+
612+ FILE * file = fdopen (out_pipe [0 ], "r" );
613+
614+ if (!file ) {
615+ return -1 ;
616+ }
617+
618+ set_properties_from_file (udev_device , file );
619+
620+ int status ;
621+ waitpid (pid , & status , 0 );
622+ fclose (file );
623+ return 0 ;
624+ }
625+
543626struct udev_device * udev_device_new_from_syspath (struct udev * udev , const char * syspath )
544627{
545628 char * subsystem , * driver , * sysname ;
@@ -593,6 +676,7 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *
593676
594677 set_properties_from_evdev (udev_device );
595678 set_properties_from_props (udev_device );
679+ set_properties_from_helper (udev_device );
596680
597681 free (driver );
598682 free (subsystem );
@@ -712,6 +796,7 @@ struct udev_device *udev_device_new_from_uevent(struct udev *udev, char *buf, si
712796
713797 set_properties_from_props (udev_device );
714798 set_properties_from_evdev (udev_device );
799+ set_properties_from_helper (udev_device );
715800 return udev_device ;
716801}
717802
0 commit comments