1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 
5 #include <Eeze.h>
6 #include "eeze_udev_private.h"
7 
8 /*
9  * helper function to set up a new device from a syspath
10  * which may or may not include /sys at the beginning
11  */
12 _udev_device *
_new_device(const char * syspath)13 _new_device(const char *syspath)
14 {
15    _udev_device *device;
16 
17    device = udev_device_new_from_syspath(udev, syspath);
18    if (!device)
19      ERR("device %s does not exist!", syspath);
20    return device;
21 }
22 
23 /*
24  * copies a device
25  */
26 _udev_device *
_copy_device(_udev_device * device)27 _copy_device(_udev_device *device)
28 {
29    return udev_device_ref(device);
30 }
31 
32 /*
33  * private function to simulate udevadm info -a
34  * walks up the device tree checking each node for sysattr
35  * with value $value
36  */
37 Eina_Bool
_walk_parents_test_attr(_udev_device * device,const char * sysattr,const char * value)38 _walk_parents_test_attr(_udev_device *device,
39                         const char   *sysattr,
40                         const char   *value)
41 {
42    _udev_device *parent, *child = device;
43    const char *test;
44 
45    if (udev_device_get_sysattr_value(device, sysattr))
46      return EINA_TRUE;
47 
48    parent = udev_device_get_parent(child);
49 
50    for (; parent; child = parent, parent = udev_device_get_parent(child))
51      {
52         if (!(test = udev_device_get_sysattr_value(parent, sysattr)))
53           continue;
54 
55         if (!value)
56           return EINA_TRUE;
57         else
58         if (!strcmp(test, value))
59           return EINA_TRUE;
60      }
61 
62    return EINA_FALSE;
63 }
64 
65 const char *
_walk_parents_get_attr(_udev_device * device,const char * sysattr,Eina_Bool property)66 _walk_parents_get_attr(_udev_device *device,
67                        const char   *sysattr,
68                        Eina_Bool property)
69 {
70    _udev_device *parent, *child = device;
71    const char *test;
72 
73    if (property)
74      test = udev_device_get_property_value(device, sysattr);
75    else
76      test = udev_device_get_sysattr_value(device, sysattr);
77    if (test) return eina_stringshare_add(test);
78 
79    parent = udev_device_get_parent(child);
80 
81    for (; parent; child = parent, parent = udev_device_get_parent(child))
82      {
83         if (property)
84           test = udev_device_get_property_value(parent, sysattr);
85         else
86           test = udev_device_get_sysattr_value(parent, sysattr);
87         if (test) return eina_stringshare_add(test);
88      }
89 
90    return NULL;
91 }
92 
93 const char *
_walk_children_get_attr(const char * syspath,const char * sysattr,const char * subsystem,Eina_Bool property)94 _walk_children_get_attr(const char *syspath,
95                         const char *sysattr,
96                         const char *subsystem,
97                         Eina_Bool property)
98 {
99    char buf[PATH_MAX];
100    const char *path, *ret = NULL;
101    _udev_enumerate *en;
102    _udev_list_entry *devs, *cur;
103 
104    en = udev_enumerate_new(udev);
105    EINA_SAFETY_ON_NULL_RETURN_VAL(en, NULL);
106    path = strrchr(syspath, '/');
107    if (path) path++;
108    else path = syspath;
109    snprintf(buf, sizeof(buf), "%s*", path);
110    udev_enumerate_add_match_sysname(en, buf);
111    if (subsystem) udev_enumerate_add_match_subsystem(en, subsystem);
112    udev_enumerate_scan_devices(en);
113    devs = udev_enumerate_get_list_entry(en);
114    udev_list_entry_foreach(cur, devs)
115      {
116         const char *devname, *test;
117         _udev_device *device;
118 
119         devname = udev_list_entry_get_name(cur);
120         device = _new_device(devname);
121         if (property)
122           test = udev_device_get_property_value(device, sysattr);
123         else
124           test = udev_device_get_sysattr_value(device, sysattr);
125         if (test)
126           {
127              ret = eina_stringshare_add(test);
128              udev_device_unref(device);
129              break;
130           }
131         udev_device_unref(device);
132      }
133    udev_enumerate_unref(en);
134    return ret;
135 }
136 
137 /*
138  * check a list for all parents of a device,
139  * stringshare adding all devices that are not in the list
140  */
141 Eina_List *
_get_unlisted_parents(Eina_List * list,_udev_device * device)142 _get_unlisted_parents(Eina_List    *list,
143                       _udev_device *device)
144 {
145    _udev_device *parent, *child = device;
146    const char *test, *devname, *vendor, *vendor2, *model, *model2;
147    Eina_List *l;
148    Eina_Bool found;
149 
150    if (!(vendor = udev_device_get_property_value(child, "ID_VENDOR_ID")))
151      vendor = udev_device_get_property_value(child, "ID_VENDOR");
152    if (!vendor) vendor = udev_device_get_sysattr_value(child, "vendor");
153    if (!vendor) vendor = udev_device_get_sysattr_value(child, "manufacturer");
154 
155    if (!(model = udev_device_get_property_value(child, "ID_MODEL_ID")))
156      model = udev_device_get_property_value(child, "ID_MODEL");
157    if (!model) model = udev_device_get_sysattr_value(child, "model");
158    if (!model) model = udev_device_get_sysattr_value(child, "product");
159 
160    parent = udev_device_get_parent(child);
161 
162    for (; parent; child = parent, parent = udev_device_get_parent(child))
163      {
164         found = EINA_FALSE;
165 
166         if (!(vendor2 = udev_device_get_property_value(child, "ID_VENDOR_ID")))
167           vendor2 = udev_device_get_property_value(child, "ID_VENDOR");
168         if (!vendor2) vendor2 = udev_device_get_sysattr_value(child, "vendor");
169         if (!vendor2) vendor2 = udev_device_get_sysattr_value(child, "manufacturer");
170 
171         if (!(model2 = udev_device_get_property_value(child, "ID_MODEL_ID")))
172           model2 = udev_device_get_property_value(child, "ID_MODEL");
173         if (!model2) model2 = udev_device_get_sysattr_value(child, "model");
174         if (!model2) model2 = udev_device_get_sysattr_value(child, "product");
175 
176         if ((!model2 && model) || (model2 && !model) || (!vendor2 && vendor)
177             || (vendor2 && !vendor))
178           break;
179         else
180         if (((model && model2) && (strcmp(model, model2))) ||
181             ((vendor && vendor2) && (strcmp(vendor, vendor2))))
182           break;
183 
184         devname = udev_device_get_syspath(parent);
185         EINA_LIST_FOREACH(list, l, test)
186           {
187              if (!strcmp(test, devname))
188                {
189                   found = EINA_TRUE;
190                   break;
191                }
192           }
193 
194         if (!found)
195           list = eina_list_prepend(list, eina_stringshare_add(devname));
196      }
197 
198    return list;
199 }
200 
201