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_NAME
58+ #define RULES_HELPER_NAME "libudev-zero-rules-helper"
59+ #endif
60+
5561struct udev_device {
5662 struct udev_list_entry properties ;
5763 struct udev_list_entry sysattrs ;
@@ -349,19 +355,10 @@ static char *read_symlink(const char *syspath, const char *name)
349355 return strdup (strrchr (link , '/' ) + 1 );
350356}
351357
352- static int set_properties_from_uevent (struct udev_device * udev_device , const char * syspath )
358+ static void set_properties_from_file (struct udev_device * udev_device , FILE * file )
353359{
354- char line [LINE_MAX ], path [PATH_MAX + sizeof ("/uevent" )], devnode [PATH_MAX ];
355- FILE * file ;
360+ char line [LINE_MAX ], devnode [PATH_MAX ];
356361 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-
365362 while (fgets (line , sizeof (line ), file )) {
366363 line [strlen (line ) - 1 ] = '\0' ;
367364
@@ -374,7 +371,21 @@ static int set_properties_from_uevent(struct udev_device *udev_device, const cha
374371 udev_list_entry_add (& udev_device -> properties , line , pos + 1 , 0 );
375372 }
376373 }
374+ }
375+
376+ static int set_properties_from_uevent (struct udev_device * udev_device , const char * syspath )
377+ {
378+ char path [PATH_MAX + sizeof ("/uevent" )];
379+ FILE * file ;
380+
381+ snprintf (path , sizeof (path ), "%s/uevent" , syspath );
382+ file = fopen (path , "r" );
383+
384+ if (!file ) {
385+ return -1 ;
386+ }
377387
388+ set_properties_from_file (udev_device , file );
378389 fclose (file );
379390 return 0 ;
380391}
@@ -540,6 +551,76 @@ static void set_properties_from_props(struct udev_device *udev_device)
540551 udev_list_entry_add (& udev_device -> properties , "ID_PATH" , id , 0 );
541552}
542553
554+ static int set_properties_from_helper (struct udev_device * udev_device )
555+ {
556+ size_t size = 0 ;
557+ size_t count = 0 ;
558+ struct udev_list_entry * entry ;
559+ for (entry = udev_device_get_properties_list_entry (udev_device );
560+ entry ;
561+ entry = udev_list_entry_get_next (entry )) {
562+
563+ const char * name = entry -> name ;
564+ const char * value = entry -> value ?entry -> value :"" ;
565+ // '{name}={value}\0'
566+ size += strlen (name ) + 1 + strlen (value ) + 1 ;
567+ count += 1 ;
568+ }
569+
570+ char * * envp = malloc ((count + 1 ) * sizeof (char * ));
571+ char * env = malloc (size );
572+ char * ptr = env ;
573+ unsigned i = 0 ;
574+ for (entry = udev_device_get_properties_list_entry (udev_device );
575+ entry ;
576+ entry = udev_list_entry_get_next (entry )) {
577+ const char * name = entry -> name ;
578+ const char * value = entry -> value ?entry -> value :"" ;
579+ // '{name}={value}\0'
580+ size_t max_size = strlen (name ) + 1 + strlen (value ) + 1 ;
581+ snprintf (ptr , max_size , "%s=%s" , name , value );
582+ envp [i ] = ptr ;
583+ ptr += max_size ;
584+ i ++ ;
585+ }
586+ envp [count ] = NULL ;
587+
588+ int out_pipe [2 ];
589+ posix_spawn_file_actions_t actions ;
590+ pipe (out_pipe );
591+
592+ posix_spawn_file_actions_init (& actions );
593+ posix_spawn_file_actions_addclose (& actions , out_pipe [0 ]);
594+ posix_spawn_file_actions_adddup2 (& actions , out_pipe [1 ], 1 );
595+ posix_spawn_file_actions_addclose (& actions , out_pipe [1 ]);
596+
597+ pid_t pid ;
598+
599+ char * argv [] = { RULES_HELPER_NAME , NULL };
600+
601+ if (posix_spawnp (& pid , argv [0 ], & actions , NULL , argv , envp )) {
602+ perror ("Could not launch properties helper" );
603+ return -1 ;
604+ }
605+
606+ free (envp );
607+ free (env );
608+ close (out_pipe [1 ]);
609+
610+ FILE * file = fdopen (out_pipe [0 ], "r" );
611+
612+ if (!file ) {
613+ return -1 ;
614+ }
615+
616+ set_properties_from_file (udev_device , file );
617+
618+ int status ;
619+ waitpid (pid , & status , 0 );
620+ close (out_pipe [0 ]);
621+ return 0 ;
622+ }
623+
543624struct udev_device * udev_device_new_from_syspath (struct udev * udev , const char * syspath )
544625{
545626 char * subsystem , * driver , * sysname ;
@@ -593,6 +674,7 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *
593674
594675 set_properties_from_evdev (udev_device );
595676 set_properties_from_props (udev_device );
677+ set_properties_from_helper (udev_device );
596678
597679 free (driver );
598680 free (subsystem );
@@ -712,6 +794,7 @@ struct udev_device *udev_device_new_from_uevent(struct udev *udev, char *buf, si
712794
713795 set_properties_from_props (udev_device );
714796 set_properties_from_evdev (udev_device );
797+ set_properties_from_helper (udev_device );
715798 return udev_device ;
716799}
717800
0 commit comments