1 /* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2  *
3  * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23 
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 
28 #include "gudevdevice.h"
29 #include "gudevprivate.h"
30 
31 /**
32  * SECTION:gudevdevice
33  * @short_description: Get information about a device
34  *
35  * The #GUdevDevice class is used to get information about a specific
36  * device. Note that you cannot instantiate a #GUdevDevice object
37  * yourself. Instead you must use #GUdevClient to obtain #GUdevDevice
38  * objects.
39  *
40  * To get basic information about a device, use
41  * g_udev_device_get_subsystem(), g_udev_device_get_devtype(),
42  * g_udev_device_get_name(), g_udev_device_get_number(),
43  * g_udev_device_get_sysfs_path(), g_udev_device_get_driver(),
44  * g_udev_device_get_action(), g_udev_device_get_seqnum(),
45  * g_udev_device_get_device_type(), g_udev_device_get_device_number(),
46  * g_udev_device_get_device_file(),
47  * g_udev_device_get_device_file_symlinks().
48  *
49  * To navigate the device tree, use g_udev_device_get_parent() and
50  * g_udev_device_get_parent_with_subsystem().
51  *
52  * To access udev properties for the device, use
53  * g_udev_device_get_property_keys(),
54  * g_udev_device_has_property(),
55  * g_udev_device_get_property(),
56  * g_udev_device_get_property_as_int(),
57  * g_udev_device_get_property_as_uint64(),
58  * g_udev_device_get_property_as_double(),
59  * g_udev_device_get_property_as_boolean() and
60  * g_udev_device_get_property_as_strv().
61  *
62  * To access sysfs attributes for the device, use
63  * g_udev_device_get_sysfs_attr_keys(),
64  * g_udev_device_has_sysfs_attr(),
65  * g_udev_device_get_sysfs_attr(),
66  * g_udev_device_get_sysfs_attr_as_int(),
67  * g_udev_device_get_sysfs_attr_as_uint64(),
68  * g_udev_device_get_sysfs_attr_as_double(),
69  * g_udev_device_get_sysfs_attr_as_boolean() and
70  * g_udev_device_get_sysfs_attr_as_strv().
71  *
72  * Note that all getters on #GUdevDevice are non-reffing – returned
73  * values are owned by the object, should not be freed and are only
74  * valid as long as the object is alive.
75  *
76  * By design, #GUdevDevice will not react to changes for a device – it
77  * only contains a snapshot of information when the #GUdevDevice
78  * object was created. To work with changes, you typically connect to
79  * the #GUdevClient::uevent signal on a #GUdevClient and get a new
80  * #GUdevDevice whenever an event happens.
81  */
82 
83 struct _GUdevDevicePrivate
84 {
85   struct udev_device *udevice;
86 
87   /* computed ondemand and cached */
88   gchar **device_file_symlinks;
89   gchar **property_keys;
90   gchar **sysfs_attr_keys;
91   gchar **tags;
92   GHashTable *prop_strvs;
93   GHashTable *sysfs_attr_strvs;
94   GHashTable *sysfs_attr;
95 };
96 
G_DEFINE_TYPE_WITH_CODE(GUdevDevice,g_udev_device,G_TYPE_OBJECT,G_ADD_PRIVATE (GUdevDevice))97 G_DEFINE_TYPE_WITH_CODE (GUdevDevice, g_udev_device, G_TYPE_OBJECT, G_ADD_PRIVATE(GUdevDevice))
98 
99 static void
100 g_udev_device_finalize (GObject *object)
101 {
102   GUdevDevice *device = G_UDEV_DEVICE (object);
103 
104   g_strfreev (device->priv->device_file_symlinks);
105   g_strfreev (device->priv->property_keys);
106   g_strfreev (device->priv->sysfs_attr_keys);
107   g_strfreev (device->priv->tags);
108 
109   if (device->priv->udevice != NULL)
110     udev_device_unref (device->priv->udevice);
111 
112   if (device->priv->prop_strvs != NULL)
113     g_hash_table_unref (device->priv->prop_strvs);
114 
115   if (device->priv->sysfs_attr_strvs != NULL)
116     g_hash_table_unref (device->priv->sysfs_attr_strvs);
117 
118   if (device->priv->sysfs_attr != NULL)
119     g_hash_table_unref (device->priv->sysfs_attr);
120 
121   if (G_OBJECT_CLASS (g_udev_device_parent_class)->finalize != NULL)
122     (* G_OBJECT_CLASS (g_udev_device_parent_class)->finalize) (object);
123 }
124 
125 static void
g_udev_device_class_init(GUdevDeviceClass * klass)126 g_udev_device_class_init (GUdevDeviceClass *klass)
127 {
128   GObjectClass *gobject_class = (GObjectClass *) klass;
129 
130   gobject_class->finalize = g_udev_device_finalize;
131 }
132 
133 static void
g_udev_device_init(GUdevDevice * device)134 g_udev_device_init (GUdevDevice *device)
135 {
136   device->priv = g_udev_device_get_instance_private (device);
137 }
138 
139 
140 GUdevDevice *
_g_udev_device_new(struct udev_device * udevice)141 _g_udev_device_new (struct udev_device *udevice)
142 {
143   GUdevDevice *device;
144 
145   device =  G_UDEV_DEVICE (g_object_new (G_UDEV_TYPE_DEVICE, NULL));
146   device->priv->udevice = udev_device_ref (udevice);
147   device->priv->sysfs_attr = g_hash_table_new_full (g_str_hash,
148                                                     g_str_equal,
149                                                     g_free,
150                                                     g_free);
151 
152   return device;
153 }
154 
155 /**
156  * g_udev_device_get_subsystem:
157  * @device: A #GUdevDevice.
158  *
159  * Gets the subsystem for @device.
160  *
161  * Returns: The subsystem for @device.
162  */
163 const gchar *
g_udev_device_get_subsystem(GUdevDevice * device)164 g_udev_device_get_subsystem (GUdevDevice *device)
165 {
166   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
167   return udev_device_get_subsystem (device->priv->udevice);
168 }
169 
170 /**
171  * g_udev_device_get_devtype:
172  * @device: A #GUdevDevice.
173  *
174  * Gets the device type for @device.
175  *
176  * Returns: The devtype for @device.
177  */
178 const gchar *
g_udev_device_get_devtype(GUdevDevice * device)179 g_udev_device_get_devtype (GUdevDevice *device)
180 {
181   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
182   return udev_device_get_devtype (device->priv->udevice);
183 }
184 
185 /**
186  * g_udev_device_get_name:
187  * @device: A #GUdevDevice.
188  *
189  * Gets the name of @device, e.g. "sda3".
190  *
191  * Returns: The name of @device.
192  */
193 const gchar *
g_udev_device_get_name(GUdevDevice * device)194 g_udev_device_get_name (GUdevDevice *device)
195 {
196   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
197   return udev_device_get_sysname (device->priv->udevice);
198 }
199 
200 /**
201  * g_udev_device_get_number:
202  * @device: A #GUdevDevice.
203  *
204  * Gets the number of @device, e.g. "3" if g_udev_device_get_name() returns "sda3".
205  *
206  * Returns: The number of @device.
207  */
208 const gchar *
g_udev_device_get_number(GUdevDevice * device)209 g_udev_device_get_number (GUdevDevice *device)
210 {
211   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
212   return udev_device_get_sysnum (device->priv->udevice);
213 }
214 
215 /**
216  * g_udev_device_get_sysfs_path:
217  * @device: A #GUdevDevice.
218  *
219  * Gets the sysfs path for @device.
220  *
221  * Returns: The sysfs path for @device.
222  */
223 const gchar *
g_udev_device_get_sysfs_path(GUdevDevice * device)224 g_udev_device_get_sysfs_path (GUdevDevice *device)
225 {
226   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
227   return udev_device_get_syspath (device->priv->udevice);
228 }
229 
230 /**
231  * g_udev_device_get_driver:
232  * @device: A #GUdevDevice.
233  *
234  * Gets the name of the driver used for @device.
235  *
236  * Returns: (nullable): The name of the driver for @device or %NULL if
237  * unknown.
238  */
239 const gchar *
g_udev_device_get_driver(GUdevDevice * device)240 g_udev_device_get_driver (GUdevDevice *device)
241 {
242   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
243   return udev_device_get_driver (device->priv->udevice);
244 }
245 
246 /**
247  * g_udev_device_get_action:
248  * @device: A #GUdevDevice.
249  *
250  * Gets the most recent action (e.g. "add", "remove", "change", etc.) for @device.
251  *
252  * Returns: An action string.
253  */
254 const gchar *
g_udev_device_get_action(GUdevDevice * device)255 g_udev_device_get_action (GUdevDevice *device)
256 {
257   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
258   return udev_device_get_action (device->priv->udevice);
259 }
260 
261 /**
262  * g_udev_device_get_seqnum:
263  * @device: A #GUdevDevice.
264  *
265  * Gets the most recent sequence number for @device.
266  *
267  * Returns: A sequence number.
268  */
269 guint64
g_udev_device_get_seqnum(GUdevDevice * device)270 g_udev_device_get_seqnum (GUdevDevice *device)
271 {
272   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
273   return udev_device_get_seqnum (device->priv->udevice);
274 }
275 
276 /**
277  * g_udev_device_get_device_type:
278  * @device: A #GUdevDevice.
279  *
280  * Gets the type of the device file, if any, for @device.
281  *
282  * Returns: The device number for @device or #G_UDEV_DEVICE_TYPE_NONE if the device does not have a device file.
283  */
284 GUdevDeviceType
g_udev_device_get_device_type(GUdevDevice * device)285 g_udev_device_get_device_type (GUdevDevice *device)
286 {
287   struct stat stat_buf;
288   const gchar *device_file;
289   GUdevDeviceType type;
290 
291   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), G_UDEV_DEVICE_TYPE_NONE);
292 
293   type = G_UDEV_DEVICE_TYPE_NONE;
294 
295   /* TODO: would be better to have support for this in libudev... */
296 
297   device_file = g_udev_device_get_device_file (device);
298   if (device_file == NULL)
299     goto out;
300 
301   if (stat (device_file, &stat_buf) != 0)
302     goto out;
303 
304   if (S_ISBLK (stat_buf.st_mode))
305     type = G_UDEV_DEVICE_TYPE_BLOCK;
306   else if (S_ISCHR (stat_buf.st_mode))
307     type = G_UDEV_DEVICE_TYPE_CHAR;
308 
309  out:
310   return type;
311 }
312 
313 /**
314  * g_udev_device_get_device_number:
315  * @device: A #GUdevDevice.
316  *
317  * Gets the device number, if any, for @device.
318  *
319  * Returns: The device number for @device or 0 if unknown.
320  */
321 GUdevDeviceNumber
g_udev_device_get_device_number(GUdevDevice * device)322 g_udev_device_get_device_number (GUdevDevice *device)
323 {
324   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
325   return udev_device_get_devnum (device->priv->udevice);
326 }
327 
328 /**
329  * g_udev_device_get_device_file:
330  * @device: A #GUdevDevice.
331  *
332  * Gets the device file for @device.
333  *
334  * Returns: (nullable): The device file for @device or %NULL if no
335  * device file exists.
336  */
337 const gchar *
g_udev_device_get_device_file(GUdevDevice * device)338 g_udev_device_get_device_file (GUdevDevice *device)
339 {
340   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
341   return udev_device_get_devnode (device->priv->udevice);
342 }
343 
344 /**
345  * g_udev_device_get_device_file_symlinks:
346  * @device: A #GUdevDevice.
347  *
348  * Gets a list of symlinks (in <literal>/dev</literal>) that points to
349  * the device file for @device.
350  *
351  * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of symlinks. This array is owned by @device and should not be freed by the caller.
352  */
353 const gchar * const *
g_udev_device_get_device_file_symlinks(GUdevDevice * device)354 g_udev_device_get_device_file_symlinks (GUdevDevice *device)
355 {
356   struct udev_list_entry *l;
357   GPtrArray *p;
358 
359   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
360 
361   if (device->priv->device_file_symlinks != NULL)
362     goto out;
363 
364   p = g_ptr_array_new ();
365   for (l = udev_device_get_devlinks_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
366     {
367       g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
368     }
369   g_ptr_array_add (p, NULL);
370   device->priv->device_file_symlinks = (gchar **) g_ptr_array_free (p, FALSE);
371 
372  out:
373   return (const gchar * const *) device->priv->device_file_symlinks;
374 }
375 
376 /* ---------------------------------------------------------------------------------------------------- */
377 
378 /**
379  * g_udev_device_get_parent:
380  * @device: A #GUdevDevice.
381  *
382  * Gets the immediate parent of @device, if any.
383  *
384  * Returns: (nullable) (transfer full): A #GUdevDevice or %NULL if
385  * @device has no parent. Free with g_object_unref().
386  */
387 GUdevDevice *
g_udev_device_get_parent(GUdevDevice * device)388 g_udev_device_get_parent (GUdevDevice  *device)
389 {
390   GUdevDevice *ret;
391   struct udev_device *udevice;
392 
393   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
394 
395   ret = NULL;
396 
397   udevice = udev_device_get_parent (device->priv->udevice);
398   if (udevice == NULL)
399     goto out;
400 
401   ret = _g_udev_device_new (udevice);
402 
403  out:
404   return ret;
405 }
406 
407 /**
408  * g_udev_device_get_parent_with_subsystem:
409  * @device: A #GUdevDevice.
410  * @subsystem: The subsystem of the parent to get.
411  * @devtype: (allow-none): The devtype of the parent to get or %NULL.
412  *
413  * Walks up the chain of parents of @device and returns the first
414  * device encountered where @subsystem and @devtype matches, if any.
415  *
416  * Returns: (nullable) (transfer full): A #GUdevDevice or %NULL if
417  * @device has no parent with @subsystem and @devtype. Free with
418  * g_object_unref().
419  */
420 GUdevDevice *
g_udev_device_get_parent_with_subsystem(GUdevDevice * device,const gchar * subsystem,const gchar * devtype)421 g_udev_device_get_parent_with_subsystem (GUdevDevice  *device,
422                                          const gchar  *subsystem,
423                                          const gchar  *devtype)
424 {
425   GUdevDevice *ret;
426   struct udev_device *udevice;
427 
428   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
429   g_return_val_if_fail (subsystem != NULL, NULL);
430 
431   ret = NULL;
432 
433   udevice = udev_device_get_parent_with_subsystem_devtype (device->priv->udevice,
434                                                            subsystem,
435                                                            devtype);
436   if (udevice == NULL)
437     goto out;
438 
439   ret = _g_udev_device_new (udevice);
440 
441  out:
442   return ret;
443 }
444 
445 /* ---------------------------------------------------------------------------------------------------- */
446 
447 /**
448  * g_udev_device_get_property_keys:
449  * @device: A #GUdevDevice.
450  *
451  * Gets all keys for properties on @device.
452  *
453  * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of property keys. This array is owned by @device and should not be freed by the caller.
454  */
455 const gchar* const *
g_udev_device_get_property_keys(GUdevDevice * device)456 g_udev_device_get_property_keys (GUdevDevice *device)
457 {
458   struct udev_list_entry *l;
459   GPtrArray *p;
460 
461   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
462 
463   if (device->priv->property_keys != NULL)
464     goto out;
465 
466   p = g_ptr_array_new ();
467   for (l = udev_device_get_properties_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
468     {
469       g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
470     }
471   g_ptr_array_add (p, NULL);
472   device->priv->property_keys = (gchar **) g_ptr_array_free (p, FALSE);
473 
474  out:
475   return (const gchar * const *) device->priv->property_keys;
476 }
477 
478 
479 /**
480  * g_udev_device_has_property:
481  * @device: A #GUdevDevice.
482  * @key: Name of property.
483  *
484  * Check if a the property with the given key exists.
485  *
486  * Returns: %TRUE only if the value for @key exist.
487  */
488 gboolean
g_udev_device_has_property(GUdevDevice * device,const gchar * key)489 g_udev_device_has_property (GUdevDevice  *device,
490                             const gchar  *key)
491 {
492   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
493   g_return_val_if_fail (key != NULL, FALSE);
494   return udev_device_get_property_value (device->priv->udevice, key) != NULL;
495 }
496 
497 /**
498  * g_udev_device_get_property:
499  * @device: A #GUdevDevice.
500  * @key: Name of property.
501  *
502  * Look up the value for @key on @device.
503  *
504  * Returns: (nullable): The value for @key or %NULL if @key doesn't
505  * exist on @device. Do not free this string, it is owned by @device.
506  */
507 const gchar *
g_udev_device_get_property(GUdevDevice * device,const gchar * key)508 g_udev_device_get_property (GUdevDevice  *device,
509                             const gchar  *key)
510 {
511   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
512   g_return_val_if_fail (key != NULL, NULL);
513   return udev_device_get_property_value (device->priv->udevice, key);
514 }
515 
516 /**
517  * g_udev_device_get_property_as_int:
518  * @device: A #GUdevDevice.
519  * @key: Name of property.
520  *
521  * Look up the value for @key on @device and convert it to an integer
522  * using strtol().
523  *
524  * Returns: The value for @key or 0 if @key doesn't exist or
525  * isn't an integer.
526  */
527 gint
g_udev_device_get_property_as_int(GUdevDevice * device,const gchar * key)528 g_udev_device_get_property_as_int (GUdevDevice  *device,
529                                    const gchar  *key)
530 {
531   gint result;
532   const gchar *s;
533 
534   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
535   g_return_val_if_fail (key != NULL, 0);
536 
537   result = 0;
538   s = g_udev_device_get_property (device, key);
539   if (s == NULL)
540     goto out;
541 
542   result = strtol (s, NULL, 0);
543 out:
544   return result;
545 }
546 
547 /**
548  * g_udev_device_get_property_as_uint64:
549  * @device: A #GUdevDevice.
550  * @key: Name of property.
551  *
552  * Look up the value for @key on @device and convert it to an unsigned
553  * 64-bit integer using g_ascii_strtoull().
554  *
555  * Returns: The value  for @key or 0 if @key doesn't  exist or isn't a
556  * #guint64.
557  */
558 guint64
g_udev_device_get_property_as_uint64(GUdevDevice * device,const gchar * key)559 g_udev_device_get_property_as_uint64 (GUdevDevice  *device,
560                                       const gchar  *key)
561 {
562   guint64 result;
563   const gchar *s;
564 
565   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
566   g_return_val_if_fail (key != NULL, 0);
567 
568   result = 0;
569   s = g_udev_device_get_property (device, key);
570   if (s == NULL)
571     goto out;
572 
573   result = g_ascii_strtoull (s, NULL, 0);
574 out:
575   return result;
576 }
577 
578 /**
579  * g_udev_device_get_property_as_double:
580  * @device: A #GUdevDevice.
581  * @key: Name of property.
582  *
583  * Look up the value for @key on @device and convert it to a double
584  * precision floating point number using strtod().
585  *
586  * Returns: The value for @key or 0.0 if @key doesn't exist or isn't a
587  * #gdouble.
588  */
589 gdouble
g_udev_device_get_property_as_double(GUdevDevice * device,const gchar * key)590 g_udev_device_get_property_as_double (GUdevDevice  *device,
591                                       const gchar  *key)
592 {
593   gdouble result;
594   const gchar *s;
595 
596   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0);
597   g_return_val_if_fail (key != NULL, 0.0);
598 
599   result = 0.0;
600   s = g_udev_device_get_property (device, key);
601   if (s == NULL)
602     goto out;
603 
604   result = strtod (s, NULL);
605 out:
606   return result;
607 }
608 
609 /**
610  * g_udev_device_get_property_as_boolean:
611  * @device: A #GUdevDevice.
612  * @key: Name of property.
613  *
614  * Look up the value for @key on @device and convert it to an
615  * boolean. This is done by doing a case-insensitive string comparison
616  * on the string value against "1" and "true".
617  *
618  * Returns: The value for @key or %FALSE if @key doesn't exist or
619  * isn't a #gboolean.
620  */
621 gboolean
g_udev_device_get_property_as_boolean(GUdevDevice * device,const gchar * key)622 g_udev_device_get_property_as_boolean (GUdevDevice  *device,
623                                        const gchar  *key)
624 {
625   gboolean result;
626   const gchar *s;
627 
628   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
629   g_return_val_if_fail (key != NULL, FALSE);
630 
631   result = FALSE;
632   s = g_udev_device_get_property (device, key);
633   if (s == NULL)
634     goto out;
635 
636   if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0)
637     result = TRUE;
638  out:
639   return result;
640 }
641 
642 static gchar **
split_at_whitespace(const gchar * s)643 split_at_whitespace (const gchar *s)
644 {
645   gchar **result;
646   guint n;
647   guint m;
648 
649   result = g_strsplit_set (s, " \v\t\r\n", 0);
650 
651   /* remove empty strings, thanks GLib */
652   for (n = 0; result[n] != NULL; n++)
653     {
654       if (strlen (result[n]) == 0)
655         {
656           g_free (result[n]);
657           for (m = n; result[m] != NULL; m++)
658             result[m] = result[m + 1];
659           n--;
660         }
661     }
662 
663   return result;
664 }
665 
666 /**
667  * g_udev_device_get_property_as_strv:
668  * @device: A #GUdevDevice.
669  * @key: Name of property.
670  *
671  * Look up the value for @key on @device and return the result of
672  * splitting it into non-empty tokens split at white space (only space
673  * (' '), form-feed ('\f'), newline ('\n'), carriage return ('\r'),
674  * horizontal tab ('\t'), and vertical tab ('\v') are considered; the
675  * locale is not taken into account).
676  *
677  * Returns: (nullable) (transfer none) (array zero-terminated=1) (element-type utf8):
678  * The value of @key on @device split into tokens or %NULL if @key
679  * doesn't exist. This array is owned by @device and should not be
680  * freed by the caller.
681  */
682 const gchar* const *
g_udev_device_get_property_as_strv(GUdevDevice * device,const gchar * key)683 g_udev_device_get_property_as_strv (GUdevDevice  *device,
684                                     const gchar  *key)
685 {
686   gchar **result;
687   const gchar *s;
688 
689   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
690   g_return_val_if_fail (key != NULL, NULL);
691 
692   if (device->priv->prop_strvs != NULL)
693     {
694       result = g_hash_table_lookup (device->priv->prop_strvs, key);
695       if (result != NULL)
696         goto out;
697     }
698 
699   result = NULL;
700   s = g_udev_device_get_property (device, key);
701   if (s == NULL)
702     goto out;
703 
704   result = split_at_whitespace (s);
705   if (result == NULL)
706     goto out;
707 
708   if (device->priv->prop_strvs == NULL)
709     device->priv->prop_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev);
710   g_hash_table_insert (device->priv->prop_strvs, g_strdup (key), result);
711 
712 out:
713   return (const gchar* const *) result;
714 }
715 
716 /* ---------------------------------------------------------------------------------------------------- */
717 
718 /**
719  * g_udev_device_get_sysfs_attr_keys:
720  * @device: A #GUdevDevice.
721  *
722  * Gets all keys for sysfs attributes on @device.
723  *
724  * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of sysfs attribute keys. This array is owned by @device and should not be freed by the caller.
725  */
726 const gchar * const *
g_udev_device_get_sysfs_attr_keys(GUdevDevice * device)727 g_udev_device_get_sysfs_attr_keys (GUdevDevice *device)
728 {
729   struct udev_list_entry *l;
730   GPtrArray *p;
731 
732   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
733 
734   if (device->priv->sysfs_attr_keys != NULL)
735     goto out;
736 
737   p = g_ptr_array_new ();
738   for (l = udev_device_get_sysattr_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
739     {
740       g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
741     }
742   g_ptr_array_add (p, NULL);
743   device->priv->sysfs_attr_keys = (gchar **) g_ptr_array_free (p, FALSE);
744 
745  out:
746   return (const gchar * const *) device->priv->sysfs_attr_keys;
747 }
748 
749 /**
750  * g_udev_device_has_sysfs_attr:
751  * @device: A #GUdevDevice.
752  * @key: Name of sysfs attribute.
753  *
754  * Check if a the sysfs attribute with the given key exists. The
755  * retrieved value is cached in the device. Repeated calls will
756  * return the same result and not check for the presence of the
757  * attribute again, unless updated through one of the "uncached"
758  * functions.
759  *
760  * Returns: %TRUE only if the value for @key exist.
761  */
762 gboolean
g_udev_device_has_sysfs_attr(GUdevDevice * device,const gchar * key)763 g_udev_device_has_sysfs_attr (GUdevDevice  *device,
764                               const gchar  *key)
765 {
766   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
767   g_return_val_if_fail (key != NULL, FALSE);
768   return udev_device_get_sysattr_value (device->priv->udevice, key) != NULL;
769 }
770 
771 /**
772  * g_udev_device_get_sysfs_attr:
773  * @device: A #GUdevDevice.
774  * @name: Name of the sysfs attribute.
775  *
776  * Look up the sysfs attribute with @name on @device. The retrieved value
777  * is cached in the device. Repeated calls will return the same value and
778  * not open the attribute again, unless updated through one of the
779  * "uncached" functions.
780  *
781  * Returns: (nullable): The value of the sysfs attribute or %NULL if
782  * there is no such attribute. Do not free this string, it is owned by
783  * @device.
784  */
785 const gchar *
g_udev_device_get_sysfs_attr(GUdevDevice * device,const gchar * name)786 g_udev_device_get_sysfs_attr (GUdevDevice  *device,
787                               const gchar  *name)
788 {
789   const char *attr;
790 
791   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
792   g_return_val_if_fail (name != NULL, NULL);
793 
794   attr = g_hash_table_lookup (device->priv->sysfs_attr, name);
795   if (attr)
796     return attr;
797   return udev_device_get_sysattr_value (device->priv->udevice, name);
798 }
799 
800 /**
801  * g_udev_device_get_sysfs_attr_as_int:
802  * @device: A #GUdevDevice.
803  * @name: Name of the sysfs attribute.
804  *
805  * Look up the sysfs attribute with @name on @device and convert it to an integer
806  * using strtol(). The retrieved value is cached in the device. Repeated calls
807  * will return the same value and not open the attribute again, unless updated
808  * through one of the "uncached" functions.
809  *
810  * Returns: The value of the sysfs attribute or 0 if there is no such
811  * attribute.
812  */
813 gint
g_udev_device_get_sysfs_attr_as_int(GUdevDevice * device,const gchar * name)814 g_udev_device_get_sysfs_attr_as_int (GUdevDevice  *device,
815                                      const gchar  *name)
816 {
817   gint result;
818   const gchar *s;
819 
820   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
821   g_return_val_if_fail (name != NULL, 0);
822 
823   result = 0;
824   s = g_udev_device_get_sysfs_attr (device, name);
825   if (s == NULL)
826     goto out;
827 
828   result = strtol (s, NULL, 0);
829 out:
830   return result;
831 }
832 
833 /**
834  * g_udev_device_get_sysfs_attr_as_uint64:
835  * @device: A #GUdevDevice.
836  * @name: Name of the sysfs attribute.
837  *
838  * Look up the sysfs attribute with @name on @device and convert it to an unsigned
839  * 64-bit integer using g_ascii_strtoull(). The retrieved value is cached in the
840  * device. Repeated calls will return the same value and not open the attribute
841  * again, unless updated through one of the "uncached" functions.
842  *
843  * Returns: The value of the sysfs attribute or 0 if there is no such
844  * attribute.
845  */
846 guint64
g_udev_device_get_sysfs_attr_as_uint64(GUdevDevice * device,const gchar * name)847 g_udev_device_get_sysfs_attr_as_uint64 (GUdevDevice  *device,
848                                         const gchar  *name)
849 {
850   guint64 result;
851   const gchar *s;
852 
853   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
854   g_return_val_if_fail (name != NULL, 0);
855 
856   result = 0;
857   s = g_udev_device_get_sysfs_attr (device, name);
858   if (s == NULL)
859     goto out;
860 
861   result = g_ascii_strtoull (s, NULL, 0);
862 out:
863   return result;
864 }
865 
866 /**
867  * g_udev_device_get_sysfs_attr_as_double:
868  * @device: A #GUdevDevice.
869  * @name: Name of the sysfs attribute.
870  *
871  * Look up the sysfs attribute with @name on @device and convert it to a double
872  * precision floating point number using strtod(). The retrieved value is cached
873  * in the device. Repeated calls will return the same value and not open the
874  * attribute again, unless updated through one of the "uncached" functions.
875  *
876  * Returns: The value of the sysfs attribute or 0.0 if there is no such
877  * attribute.
878  */
879 gdouble
g_udev_device_get_sysfs_attr_as_double(GUdevDevice * device,const gchar * name)880 g_udev_device_get_sysfs_attr_as_double (GUdevDevice  *device,
881                                         const gchar  *name)
882 {
883   gdouble result;
884   const gchar *s;
885 
886   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0);
887   g_return_val_if_fail (name != NULL, 0.0);
888 
889   result = 0.0;
890   s = g_udev_device_get_sysfs_attr (device, name);
891   if (s == NULL)
892     goto out;
893 
894   result = strtod (s, NULL);
895 out:
896   return result;
897 }
898 
899 /**
900  * g_udev_device_get_sysfs_attr_as_boolean:
901  * @device: A #GUdevDevice.
902  * @name: Name of the sysfs attribute.
903  *
904  * Look up the sysfs attribute with @name on @device and convert it to an
905  * boolean. This is done by doing a case-insensitive string comparison
906  * on the string value against "1" and "true". The retrieved value is
907  * cached in the device. Repeated calls will return the same value and
908  * not open the attribute again, unless updated through one of the
909  * "uncached" functions.
910  *
911  * Returns: The value of the sysfs attribute or %FALSE if there is no such
912  * attribute.
913  */
914 gboolean
g_udev_device_get_sysfs_attr_as_boolean(GUdevDevice * device,const gchar * name)915 g_udev_device_get_sysfs_attr_as_boolean (GUdevDevice  *device,
916                                          const gchar  *name)
917 {
918   gboolean result;
919   const gchar *s;
920 
921   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
922   g_return_val_if_fail (name != NULL, FALSE);
923 
924   result = FALSE;
925   s = g_udev_device_get_sysfs_attr (device, name);
926   if (s == NULL)
927     goto out;
928 
929   if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0)
930     result = TRUE;
931  out:
932   return result;
933 }
934 
935 /**
936  * g_udev_device_get_sysfs_attr_as_strv:
937  * @device: A #GUdevDevice.
938  * @name: Name of the sysfs attribute.
939  *
940  * Look up the sysfs attribute with @name on @device and return the result of
941  * splitting it into non-empty tokens split at white space (only space (' '),
942  * form-feed ('\f'), newline ('\n'), carriage return ('\r'), horizontal
943  * tab ('\t'), and vertical tab ('\v') are considered; the locale is
944  * not taken into account).
945  *
946  * The retrieved value is cached in the device. Repeated calls will return
947  * the same value and not open the attribute again, unless updated through
948  * one of the "uncached" functions.
949  *
950  * Returns: (nullable) (transfer none) (array zero-terminated=1) (element-type utf8):
951  * The value of the sysfs attribute split into tokens or %NULL if
952  * there is no such attribute. This array is owned by @device and
953  * should not be freed by the caller.
954  */
955 const gchar * const *
g_udev_device_get_sysfs_attr_as_strv(GUdevDevice * device,const gchar * name)956 g_udev_device_get_sysfs_attr_as_strv (GUdevDevice  *device,
957                                       const gchar  *name)
958 {
959   gchar **result;
960   const gchar *s;
961 
962   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
963   g_return_val_if_fail (name != NULL, NULL);
964 
965   if (device->priv->sysfs_attr_strvs != NULL)
966     {
967       result = g_hash_table_lookup (device->priv->sysfs_attr_strvs, name);
968       if (result != NULL)
969         goto out;
970     }
971 
972   result = NULL;
973   s = g_udev_device_get_sysfs_attr (device, name);
974   if (s == NULL)
975     goto out;
976 
977   result = split_at_whitespace (s);
978   if (result == NULL)
979     goto out;
980 
981   if (device->priv->sysfs_attr_strvs == NULL)
982     device->priv->sysfs_attr_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev);
983   g_hash_table_insert (device->priv->sysfs_attr_strvs, g_strdup (name), result);
984 
985 out:
986   return (const gchar* const *) result;
987 }
988 
989 /**
990  * g_udev_device_has_sysfs_attr_uncached:
991  * @device: A #GUdevDevice.
992  * @key: Name of sysfs attribute.
993  *
994  * Check if a the sysfs attribute with the given key exists. The
995  * retrieved value is cached in the device. Repeated calls will
996  * return the same result and not check for the presence of the
997  * attribute again, unless updated through one of the "uncached"
998  * functions.
999  *
1000  * Returns: %TRUE only if the value for @key exist.
1001  */
1002 gboolean
g_udev_device_has_sysfs_attr_uncached(GUdevDevice * device,const gchar * key)1003 g_udev_device_has_sysfs_attr_uncached (GUdevDevice  *device,
1004                                        const gchar  *key)
1005 {
1006   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
1007   g_return_val_if_fail (key != NULL, FALSE);
1008   return g_udev_device_get_sysfs_attr_uncached (device, key) != NULL;
1009 }
1010 
1011 /**
1012  * g_udev_device_get_sysfs_attr_uncached:
1013  * @device: A #GUdevDevice.
1014  * @name: Name of the sysfs attribute.
1015  *
1016  * Look up the sysfs attribute with @name on @device. This function does
1017  * blocking I/O, and updates the sysfs attributes cache.
1018  *
1019  * Returns: (nullable): The value of the sysfs attribute or %NULL if
1020  * there is no such attribute. Do not free this string, it is owned by
1021  * @device.
1022  */
1023 const gchar *
g_udev_device_get_sysfs_attr_uncached(GUdevDevice * device,const gchar * name)1024 g_udev_device_get_sysfs_attr_uncached (GUdevDevice  *device,
1025                                        const gchar  *name)
1026 {
1027   g_autofree char *path = NULL;
1028   char *contents = NULL;
1029 
1030   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
1031   g_return_val_if_fail (name != NULL, NULL);
1032 
1033   path = g_build_filename (udev_device_get_syspath (device->priv->udevice), name, NULL);
1034   if (!g_file_get_contents (path, &contents, NULL, NULL))
1035     return NULL;
1036   g_hash_table_insert (device->priv->sysfs_attr, g_strdup (name), contents);
1037 
1038   return contents;
1039 }
1040 
1041 /**
1042  * g_udev_device_get_sysfs_attr_as_int_uncached:
1043  * @device: A #GUdevDevice.
1044  * @name: Name of the sysfs attribute.
1045  *
1046  * Look up the sysfs attribute with @name on @device and convert it to an integer
1047  * using strtol(). This function does blocking I/O, and updates the sysfs
1048  * attributes cache.
1049  *
1050  * Returns: The value of the sysfs attribute or 0 if there is no such
1051  * attribute.
1052  */
1053 gint
g_udev_device_get_sysfs_attr_as_int_uncached(GUdevDevice * device,const gchar * name)1054 g_udev_device_get_sysfs_attr_as_int_uncached (GUdevDevice  *device,
1055                                               const gchar  *name)
1056 {
1057   gint result;
1058   const gchar *s;
1059 
1060   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
1061   g_return_val_if_fail (name != NULL, 0);
1062 
1063   result = 0;
1064   s = g_udev_device_get_sysfs_attr_uncached (device, name);
1065   if (s == NULL)
1066     goto out;
1067 
1068   result = strtol (s, NULL, 0);
1069 out:
1070   return result;
1071 }
1072 
1073 /**
1074  * g_udev_device_get_sysfs_attr_as_uint64_uncached:
1075  * @device: A #GUdevDevice.
1076  * @name: Name of the sysfs attribute.
1077  *
1078  * Look up the sysfs attribute with @name on @device and convert it to an unsigned
1079  * 64-bit integer using g_ascii_strtoull(). This function does blocking I/O, and
1080  * updates the sysfs attributes cache.
1081  *
1082  * Returns: The value of the sysfs attribute or 0 if there is no such
1083  * attribute.
1084  */
1085 guint64
g_udev_device_get_sysfs_attr_as_uint64_uncached(GUdevDevice * device,const gchar * name)1086 g_udev_device_get_sysfs_attr_as_uint64_uncached (GUdevDevice  *device,
1087                                                  const gchar  *name)
1088 {
1089   guint64 result;
1090   const gchar *s;
1091 
1092   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
1093   g_return_val_if_fail (name != NULL, 0);
1094 
1095   result = 0;
1096   s = g_udev_device_get_sysfs_attr_uncached (device, name);
1097   if (s == NULL)
1098     goto out;
1099 
1100   result = g_ascii_strtoull (s, NULL, 0);
1101 out:
1102   return result;
1103 }
1104 
1105 /**
1106  * g_udev_device_get_sysfs_attr_as_double_uncached:
1107  * @device: A #GUdevDevice.
1108  * @name: Name of the sysfs attribute.
1109  *
1110  * Look up the sysfs attribute with @name on @device and convert it to a double
1111  * precision floating point number using strtod(). This function does blocking
1112  * I/O, and updates the sysfs attributes cache.
1113  *
1114  * Returns: The value of the sysfs attribute or 0.0 if there is no such
1115  * attribute.
1116  */
1117 gdouble
g_udev_device_get_sysfs_attr_as_double_uncached(GUdevDevice * device,const gchar * name)1118 g_udev_device_get_sysfs_attr_as_double_uncached (GUdevDevice  *device,
1119                                                  const gchar  *name)
1120 {
1121   gdouble result;
1122   const gchar *s;
1123 
1124   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0);
1125   g_return_val_if_fail (name != NULL, 0.0);
1126 
1127   result = 0.0;
1128   s = g_udev_device_get_sysfs_attr_uncached (device, name);
1129   if (s == NULL)
1130     goto out;
1131 
1132   result = strtod (s, NULL);
1133 out:
1134   return result;
1135 }
1136 
1137 /**
1138  * g_udev_device_get_sysfs_attr_as_boolean_uncached:
1139  * @device: A #GUdevDevice.
1140  * @name: Name of the sysfs attribute.
1141  *
1142  * Look up the sysfs attribute with @name on @device and convert it to an
1143  * boolean. This is done by doing a case-insensitive string comparison
1144  * on the string value against "1" and "true". This function does
1145  * blocking I/O, and updates the sysfs attributes cache.
1146  *
1147  * Returns: The value of the sysfs attribute or %FALSE if there is no such
1148  * attribute.
1149  */
1150 gboolean
g_udev_device_get_sysfs_attr_as_boolean_uncached(GUdevDevice * device,const gchar * name)1151 g_udev_device_get_sysfs_attr_as_boolean_uncached (GUdevDevice  *device,
1152                                                   const gchar  *name)
1153 {
1154   gboolean result;
1155   const gchar *s;
1156 
1157   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
1158   g_return_val_if_fail (name != NULL, FALSE);
1159 
1160   result = FALSE;
1161   s = g_udev_device_get_sysfs_attr_uncached (device, name);
1162   if (s == NULL)
1163     goto out;
1164 
1165   if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0)
1166     result = TRUE;
1167  out:
1168   return result;
1169 }
1170 
1171 /**
1172  * g_udev_device_get_sysfs_attr_as_strv_uncached:
1173  * @device: A #GUdevDevice.
1174  * @name: Name of the sysfs attribute.
1175  *
1176  * Look up the sysfs attribute with @name on @device and return the result of
1177  * splitting it into non-empty tokens split at white space (only space (' '),
1178  * form-feed ('\f'), newline ('\n'), carriage return ('\r'), horizontal
1179  * tab ('\t'), and vertical tab ('\v') are considered; the locale is
1180  * not taken into account).
1181  *
1182  * This function does blocking I/O, and updates the sysfs attributes cache.
1183  *
1184  * Returns: (nullable) (transfer none) (array zero-terminated=1) (element-type utf8):
1185  * The value of the sysfs attribute split into tokens or %NULL if
1186  * there is no such attribute. This array is owned by @device and
1187  * should not be freed by the caller.
1188  */
1189 const gchar * const *
g_udev_device_get_sysfs_attr_as_strv_uncached(GUdevDevice * device,const gchar * name)1190 g_udev_device_get_sysfs_attr_as_strv_uncached (GUdevDevice  *device,
1191                                                const gchar  *name)
1192 {
1193   gchar **result;
1194   const gchar *s;
1195 
1196   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
1197   g_return_val_if_fail (name != NULL, NULL);
1198 
1199   result = NULL;
1200   s = g_udev_device_get_sysfs_attr_uncached (device, name);
1201   if (s == NULL)
1202     goto out;
1203 
1204   result = split_at_whitespace (s);
1205   if (result == NULL)
1206     goto out;
1207 
1208   if (device->priv->sysfs_attr_strvs == NULL)
1209     device->priv->sysfs_attr_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev);
1210   g_hash_table_insert (device->priv->sysfs_attr_strvs, g_strdup (name), result);
1211 
1212 out:
1213   return (const gchar* const *) result;
1214 }
1215 
1216 /**
1217  * g_udev_device_get_tags:
1218  * @device: A #GUdevDevice.
1219  *
1220  * Gets all tags for @device.
1221  *
1222  * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of tags. This array is owned by @device and should not be freed by the caller.
1223  *
1224  * Since: 165
1225  */
1226 const gchar* const *
g_udev_device_get_tags(GUdevDevice * device)1227 g_udev_device_get_tags (GUdevDevice  *device)
1228 {
1229   struct udev_list_entry *l;
1230   GPtrArray *p;
1231 
1232   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
1233 
1234   if (device->priv->tags != NULL)
1235     goto out;
1236 
1237   p = g_ptr_array_new ();
1238   for (l = udev_device_get_tags_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
1239     {
1240       g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
1241     }
1242   g_ptr_array_add (p, NULL);
1243   device->priv->tags = (gchar **) g_ptr_array_free (p, FALSE);
1244 
1245  out:
1246   return (const gchar * const *) device->priv->tags;
1247 }
1248 
1249 /**
1250  * g_udev_device_get_is_initialized:
1251  * @device: A #GUdevDevice.
1252  *
1253  * Gets whether @device has been initialized.
1254  *
1255  * Returns: Whether @device has been initialized.
1256  *
1257  * Since: 165
1258  */
1259 gboolean
g_udev_device_get_is_initialized(GUdevDevice * device)1260 g_udev_device_get_is_initialized (GUdevDevice  *device)
1261 {
1262   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
1263   return udev_device_get_is_initialized (device->priv->udevice);
1264 }
1265 
1266 /**
1267  * g_udev_device_get_usec_since_initialized:
1268  * @device: A #GUdevDevice.
1269  *
1270  * Gets number of micro-seconds since @device was initialized.
1271  *
1272  * This only works for devices with properties in the udev
1273  * database. All other devices return 0.
1274  *
1275  * Returns: Number of micro-seconds since @device was initialized or 0 if unknown.
1276  *
1277  * Since: 165
1278  */
1279 guint64
g_udev_device_get_usec_since_initialized(GUdevDevice * device)1280 g_udev_device_get_usec_since_initialized (GUdevDevice *device)
1281 {
1282   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
1283   return udev_device_get_usec_since_initialized (device->priv->udevice);
1284 }
1285