chiark / gitweb /
gudev: add device::get_sysfs_attr_keys and device::has_sysfs_attr
[elogind.git] / src / gudev / gudevdevice.c
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
27 #include "gudevdevice.h"
28 #include "gudevprivate.h"
29
30 /**
31  * SECTION:gudevdevice
32  * @short_description: Get information about a device
33  *
34  * The #GUdevDevice class is used to get information about a specific
35  * device. Note that you cannot instantiate a #GUdevDevice object
36  * yourself. Instead you must use #GUdevClient to obtain #GUdevDevice
37  * objects.
38  *
39  * To get basic information about a device, use
40  * g_udev_device_get_subsystem(), g_udev_device_get_devtype(),
41  * g_udev_device_get_name(), g_udev_device_get_number(),
42  * g_udev_device_get_sysfs_path(), g_udev_device_get_driver(),
43  * g_udev_device_get_action(), g_udev_device_get_seqnum(),
44  * g_udev_device_get_device_type(), g_udev_device_get_device_number(),
45  * g_udev_device_get_device_file(),
46  * g_udev_device_get_device_file_symlinks().
47  *
48  * To navigate the device tree, use g_udev_device_get_parent() and
49  * g_udev_device_get_parent_with_subsystem().
50  *
51  * To access udev properties for the device, use
52  * g_udev_device_get_property_keys(),
53  * g_udev_device_has_property(),
54  * g_udev_device_get_property(),
55  * g_udev_device_get_property_as_int(),
56  * g_udev_device_get_property_as_uint64(),
57  * g_udev_device_get_property_as_double(),
58  * g_udev_device_get_property_as_boolean() and
59  * g_udev_device_get_property_as_strv().
60  *
61  * To access sysfs attributes for the device, use
62  * g_udev_device_get_sysfs_attr_keys(),
63  * g_udev_device_has_sysfs_attr(),
64  * g_udev_device_get_sysfs_attr(),
65  * g_udev_device_get_sysfs_attr_as_int(),
66  * g_udev_device_get_sysfs_attr_as_uint64(),
67  * g_udev_device_get_sysfs_attr_as_double(),
68  * g_udev_device_get_sysfs_attr_as_boolean() and
69  * g_udev_device_get_sysfs_attr_as_strv().
70  *
71  * Note that all getters on #GUdevDevice are non-reffing – returned
72  * values are owned by the object, should not be freed and are only
73  * valid as long as the object is alive.
74  *
75  * By design, #GUdevDevice will not react to changes for a device – it
76  * only contains a snapshot of information when the #GUdevDevice
77  * object was created. To work with changes, you typically connect to
78  * the #GUdevClient::uevent signal on a #GUdevClient and get a new
79  * #GUdevDevice whenever an event happens.
80  */
81
82 struct _GUdevDevicePrivate
83 {
84   struct udev_device *udevice;
85
86   /* computed ondemand and cached */
87   gchar **device_file_symlinks;
88   gchar **property_keys;
89   gchar **sysfs_attr_keys;
90   gchar **tags;
91   GHashTable *prop_strvs;
92   GHashTable *sysfs_attr_strvs;
93 };
94
95 G_DEFINE_TYPE (GUdevDevice, g_udev_device, G_TYPE_OBJECT)
96
97 static void
98 g_udev_device_finalize (GObject *object)
99 {
100   GUdevDevice *device = G_UDEV_DEVICE (object);
101
102   g_strfreev (device->priv->device_file_symlinks);
103   g_strfreev (device->priv->property_keys);
104   g_strfreev (device->priv->sysfs_attr_keys);
105   g_strfreev (device->priv->tags);
106
107   if (device->priv->udevice != NULL)
108     udev_device_unref (device->priv->udevice);
109
110   if (device->priv->prop_strvs != NULL)
111     g_hash_table_unref (device->priv->prop_strvs);
112
113   if (device->priv->sysfs_attr_strvs != NULL)
114     g_hash_table_unref (device->priv->sysfs_attr_strvs);
115
116   if (G_OBJECT_CLASS (g_udev_device_parent_class)->finalize != NULL)
117     (* G_OBJECT_CLASS (g_udev_device_parent_class)->finalize) (object);
118 }
119
120 static void
121 g_udev_device_class_init (GUdevDeviceClass *klass)
122 {
123   GObjectClass *gobject_class = (GObjectClass *) klass;
124
125   gobject_class->finalize = g_udev_device_finalize;
126
127   g_type_class_add_private (klass, sizeof (GUdevDevicePrivate));
128 }
129
130 static void
131 g_udev_device_init (GUdevDevice *device)
132 {
133   device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
134                                               G_UDEV_TYPE_DEVICE,
135                                               GUdevDevicePrivate);
136 }
137
138
139 GUdevDevice *
140 _g_udev_device_new (struct udev_device *udevice)
141 {
142   GUdevDevice *device;
143
144   device =  G_UDEV_DEVICE (g_object_new (G_UDEV_TYPE_DEVICE, NULL));
145   device->priv->udevice = udev_device_ref (udevice);
146
147   return device;
148 }
149
150 /**
151  * g_udev_device_get_subsystem:
152  * @device: A #GUdevDevice.
153  *
154  * Gets the subsystem for @device.
155  *
156  * Returns: The subsystem for @device.
157  */
158 const gchar *
159 g_udev_device_get_subsystem (GUdevDevice *device)
160 {
161   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
162   return udev_device_get_subsystem (device->priv->udevice);
163 }
164
165 /**
166  * g_udev_device_get_devtype:
167  * @device: A #GUdevDevice.
168  *
169  * Gets the device type for @device.
170  *
171  * Returns: The devtype for @device.
172  */
173 const gchar *
174 g_udev_device_get_devtype (GUdevDevice *device)
175 {
176   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
177   return udev_device_get_devtype (device->priv->udevice);
178 }
179
180 /**
181  * g_udev_device_get_name:
182  * @device: A #GUdevDevice.
183  *
184  * Gets the name of @device, e.g. "sda3".
185  *
186  * Returns: The name of @device.
187  */
188 const gchar *
189 g_udev_device_get_name (GUdevDevice *device)
190 {
191   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
192   return udev_device_get_sysname (device->priv->udevice);
193 }
194
195 /**
196  * g_udev_device_get_number:
197  * @device: A #GUdevDevice.
198  *
199  * Gets the number of @device, e.g. "3" if g_udev_device_get_name() returns "sda3".
200  *
201  * Returns: The number of @device.
202  */
203 const gchar *
204 g_udev_device_get_number (GUdevDevice *device)
205 {
206   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
207   return udev_device_get_sysnum (device->priv->udevice);
208 }
209
210 /**
211  * g_udev_device_get_sysfs_path:
212  * @device: A #GUdevDevice.
213  *
214  * Gets the sysfs path for @device.
215  *
216  * Returns: The sysfs path for @device.
217  */
218 const gchar *
219 g_udev_device_get_sysfs_path (GUdevDevice *device)
220 {
221   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
222   return udev_device_get_syspath (device->priv->udevice);
223 }
224
225 /**
226  * g_udev_device_get_driver:
227  * @device: A #GUdevDevice.
228  *
229  * Gets the name of the driver used for @device.
230  *
231  * Returns: The name of the driver for @device or %NULL if unknown.
232  */
233 const gchar *
234 g_udev_device_get_driver (GUdevDevice *device)
235 {
236   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
237   return udev_device_get_driver (device->priv->udevice);
238 }
239
240 /**
241  * g_udev_device_get_action:
242  * @device: A #GUdevDevice.
243  *
244  * Gets the most recent action (e.g. "add", "remove", "change", etc.) for @device.
245  *
246  * Returns: An action string.
247  */
248 const gchar *
249 g_udev_device_get_action (GUdevDevice *device)
250 {
251   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
252   return udev_device_get_action (device->priv->udevice);
253 }
254
255 /**
256  * g_udev_device_get_seqnum:
257  * @device: A #GUdevDevice.
258  *
259  * Gets the most recent sequence number for @device.
260  *
261  * Returns: A sequence number.
262  */
263 guint64
264 g_udev_device_get_seqnum (GUdevDevice *device)
265 {
266   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
267   return udev_device_get_seqnum (device->priv->udevice);
268 }
269
270 /**
271  * g_udev_device_get_device_type:
272  * @device: A #GUdevDevice.
273  *
274  * Gets the type of the device file, if any, for @device.
275  *
276  * Returns: The device number for @device or #G_UDEV_DEVICE_TYPE_NONE if the device does not have a device file.
277  */
278 GUdevDeviceType
279 g_udev_device_get_device_type (GUdevDevice *device)
280 {
281   struct stat stat_buf;
282   const gchar *device_file;
283   GUdevDeviceType type;
284
285   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), G_UDEV_DEVICE_TYPE_NONE);
286
287   type = G_UDEV_DEVICE_TYPE_NONE;
288
289   /* TODO: would be better to have support for this in libudev... */
290
291   device_file = g_udev_device_get_device_file (device);
292   if (device_file == NULL)
293     goto out;
294
295   if (stat (device_file, &stat_buf) != 0)
296     goto out;
297
298   if (S_ISBLK (stat_buf.st_mode))
299     type = G_UDEV_DEVICE_TYPE_BLOCK;
300   else if (S_ISCHR (stat_buf.st_mode))
301     type = G_UDEV_DEVICE_TYPE_CHAR;
302
303  out:
304   return type;
305 }
306
307 /**
308  * g_udev_device_get_device_number:
309  * @device: A #GUdevDevice.
310  *
311  * Gets the device number, if any, for @device.
312  *
313  * Returns: The device number for @device or 0 if unknown.
314  */
315 GUdevDeviceNumber
316 g_udev_device_get_device_number (GUdevDevice *device)
317 {
318   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
319   return udev_device_get_devnum (device->priv->udevice);
320 }
321
322 /**
323  * g_udev_device_get_device_file:
324  * @device: A #GUdevDevice.
325  *
326  * Gets the device file for @device.
327  *
328  * Returns: The device file for @device or %NULL if no device file
329  * exists.
330  */
331 const gchar *
332 g_udev_device_get_device_file (GUdevDevice *device)
333 {
334   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
335   return udev_device_get_devnode (device->priv->udevice);
336 }
337
338 /**
339  * g_udev_device_get_device_file_symlinks:
340  * @device: A #GUdevDevice.
341  *
342  * Gets a list of symlinks (in <literal>/dev</literal>) that points to
343  * the device file for @device.
344  *
345  * 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.
346  */
347 const gchar * const *
348 g_udev_device_get_device_file_symlinks (GUdevDevice *device)
349 {
350   struct udev_list_entry *l;
351   GPtrArray *p;
352
353   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
354
355   if (device->priv->device_file_symlinks != NULL)
356     goto out;
357
358   p = g_ptr_array_new ();
359   for (l = udev_device_get_devlinks_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
360     {
361       g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
362     }
363   g_ptr_array_add (p, NULL);
364   device->priv->device_file_symlinks = (gchar **) g_ptr_array_free (p, FALSE);
365
366  out:
367   return (const gchar * const *) device->priv->device_file_symlinks;
368 }
369
370 /* ---------------------------------------------------------------------------------------------------- */
371
372 /**
373  * g_udev_device_get_parent:
374  * @device: A #GUdevDevice.
375  *
376  * Gets the immediate parent of @device, if any.
377  *
378  * Returns: (transfer full): A #GUdevDevice or %NULL if @device has no parent. Free with g_object_unref().
379  */
380 GUdevDevice *
381 g_udev_device_get_parent (GUdevDevice  *device)
382 {
383   GUdevDevice *ret;
384   struct udev_device *udevice;
385
386   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
387
388   ret = NULL;
389
390   udevice = udev_device_get_parent (device->priv->udevice);
391   if (udevice == NULL)
392     goto out;
393
394   ret = _g_udev_device_new (udevice);
395
396  out:
397   return ret;
398 }
399
400 /**
401  * g_udev_device_get_parent_with_subsystem:
402  * @device: A #GUdevDevice.
403  * @subsystem: The subsystem of the parent to get.
404  * @devtype: (allow-none): The devtype of the parent to get or %NULL.
405  *
406  * Walks up the chain of parents of @device and returns the first
407  * device encountered where @subsystem and @devtype matches, if any.
408  *
409  * Returns: (transfer full): A #GUdevDevice or %NULL if @device has no parent with @subsystem and @devtype. Free with g_object_unref().
410  */
411 GUdevDevice *
412 g_udev_device_get_parent_with_subsystem (GUdevDevice  *device,
413                                          const gchar  *subsystem,
414                                          const gchar  *devtype)
415 {
416   GUdevDevice *ret;
417   struct udev_device *udevice;
418
419   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
420   g_return_val_if_fail (subsystem != NULL, NULL);
421
422   ret = NULL;
423
424   udevice = udev_device_get_parent_with_subsystem_devtype (device->priv->udevice,
425                                                            subsystem,
426                                                            devtype);
427   if (udevice == NULL)
428     goto out;
429
430   ret = _g_udev_device_new (udevice);
431
432  out:
433   return ret;
434 }
435
436 /* ---------------------------------------------------------------------------------------------------- */
437
438 /**
439  * g_udev_device_get_property_keys:
440  * @device: A #GUdevDevice.
441  *
442  * Gets all keys for properties on @device.
443  *
444  * 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.
445  */
446 const gchar* const *
447 g_udev_device_get_property_keys (GUdevDevice *device)
448 {
449   struct udev_list_entry *l;
450   GPtrArray *p;
451
452   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
453
454   if (device->priv->property_keys != NULL)
455     goto out;
456
457   p = g_ptr_array_new ();
458   for (l = udev_device_get_properties_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
459     {
460       g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
461     }
462   g_ptr_array_add (p, NULL);
463   device->priv->property_keys = (gchar **) g_ptr_array_free (p, FALSE);
464
465  out:
466   return (const gchar * const *) device->priv->property_keys;
467 }
468
469
470 /**
471  * g_udev_device_has_property:
472  * @device: A #GUdevDevice.
473  * @key: Name of property.
474  *
475  * Check if a the property with the given key exists.
476  *
477  * Returns: %TRUE only if the value for @key exist.
478  */
479 gboolean
480 g_udev_device_has_property (GUdevDevice  *device,
481                             const gchar  *key)
482 {
483   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
484   g_return_val_if_fail (key != NULL, FALSE);
485   return udev_device_get_property_value (device->priv->udevice, key) != NULL;
486 }
487
488 /**
489  * g_udev_device_get_property:
490  * @device: A #GUdevDevice.
491  * @key: Name of property.
492  *
493  * Look up the value for @key on @device.
494  *
495  * Returns: The value for @key or %NULL if @key doesn't exist on @device. Do not free this string, it is owned by @device.
496  */
497 const gchar *
498 g_udev_device_get_property (GUdevDevice  *device,
499                             const gchar  *key)
500 {
501   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
502   g_return_val_if_fail (key != NULL, NULL);
503   return udev_device_get_property_value (device->priv->udevice, key);
504 }
505
506 /**
507  * g_udev_device_get_property_as_int:
508  * @device: A #GUdevDevice.
509  * @key: Name of property.
510  *
511  * Look up the value for @key on @device and convert it to an integer
512  * using strtol().
513  *
514  * Returns: The value for @key or 0 if @key doesn't exist or
515  * isn't an integer.
516  */
517 gint
518 g_udev_device_get_property_as_int (GUdevDevice  *device,
519                                    const gchar  *key)
520 {
521   gint result;
522   const gchar *s;
523
524   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
525   g_return_val_if_fail (key != NULL, 0);
526
527   result = 0;
528   s = g_udev_device_get_property (device, key);
529   if (s == NULL)
530     goto out;
531
532   result = strtol (s, NULL, 0);
533 out:
534   return result;
535 }
536
537 /**
538  * g_udev_device_get_property_as_uint64:
539  * @device: A #GUdevDevice.
540  * @key: Name of property.
541  *
542  * Look up the value for @key on @device and convert it to an unsigned
543  * 64-bit integer using g_ascii_strtoull().
544  *
545  * Returns: The value  for @key or 0 if @key doesn't  exist or isn't a
546  * #guint64.
547  */
548 guint64
549 g_udev_device_get_property_as_uint64 (GUdevDevice  *device,
550                                       const gchar  *key)
551 {
552   guint64 result;
553   const gchar *s;
554
555   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
556   g_return_val_if_fail (key != NULL, 0);
557
558   result = 0;
559   s = g_udev_device_get_property (device, key);
560   if (s == NULL)
561     goto out;
562
563   result = g_ascii_strtoull (s, NULL, 0);
564 out:
565   return result;
566 }
567
568 /**
569  * g_udev_device_get_property_as_double:
570  * @device: A #GUdevDevice.
571  * @key: Name of property.
572  *
573  * Look up the value for @key on @device and convert it to a double
574  * precision floating point number using strtod().
575  *
576  * Returns: The value for @key or 0.0 if @key doesn't exist or isn't a
577  * #gdouble.
578  */
579 gdouble
580 g_udev_device_get_property_as_double (GUdevDevice  *device,
581                                       const gchar  *key)
582 {
583   gdouble result;
584   const gchar *s;
585
586   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0);
587   g_return_val_if_fail (key != NULL, 0.0);
588
589   result = 0.0;
590   s = g_udev_device_get_property (device, key);
591   if (s == NULL)
592     goto out;
593
594   result = strtod (s, NULL);
595 out:
596   return result;
597 }
598
599 /**
600  * g_udev_device_get_property_as_boolean:
601  * @device: A #GUdevDevice.
602  * @key: Name of property.
603  *
604  * Look up the value for @key on @device and convert it to an
605  * boolean. This is done by doing a case-insensitive string comparison
606  * on the string value against "1" and "true".
607  *
608  * Returns: The value for @key or %FALSE if @key doesn't exist or
609  * isn't a #gboolean.
610  */
611 gboolean
612 g_udev_device_get_property_as_boolean (GUdevDevice  *device,
613                                        const gchar  *key)
614 {
615   gboolean result;
616   const gchar *s;
617
618   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
619   g_return_val_if_fail (key != NULL, FALSE);
620
621   result = FALSE;
622   s = g_udev_device_get_property (device, key);
623   if (s == NULL)
624     goto out;
625
626   if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0)
627     result = TRUE;
628  out:
629   return result;
630 }
631
632 static gchar **
633 split_at_whitespace (const gchar *s)
634 {
635   gchar **result;
636   guint n;
637   guint m;
638
639   result = g_strsplit_set (s, " \v\t\r\n", 0);
640
641   /* remove empty strings, thanks GLib */
642   for (n = 0; result[n] != NULL; n++)
643     {
644       if (strlen (result[n]) == 0)
645         {
646           g_free (result[n]);
647           for (m = n; result[m] != NULL; m++)
648             result[m] = result[m + 1];
649           n--;
650         }
651     }
652
653   return result;
654 }
655
656 /**
657  * g_udev_device_get_property_as_strv:
658  * @device: A #GUdevDevice.
659  * @key: Name of property.
660  *
661  * Look up the value for @key on @device and return the result of
662  * splitting it into non-empty tokens split at white space (only space
663  * (' '), form-feed ('\f'), newline ('\n'), carriage return ('\r'),
664  * horizontal tab ('\t'), and vertical tab ('\v') are considered; the
665  * locale is not taken into account).
666  *
667  * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): The value of @key on @device split into tokens or %NULL if @key doesn't exist. This array is owned by @device and should not be freed by the caller.
668  */
669 const gchar* const *
670 g_udev_device_get_property_as_strv (GUdevDevice  *device,
671                                     const gchar  *key)
672 {
673   gchar **result;
674   const gchar *s;
675
676   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
677   g_return_val_if_fail (key != NULL, NULL);
678
679   if (device->priv->prop_strvs != NULL)
680     {
681       result = g_hash_table_lookup (device->priv->prop_strvs, key);
682       if (result != NULL)
683         goto out;
684     }
685
686   result = NULL;
687   s = g_udev_device_get_property (device, key);
688   if (s == NULL)
689     goto out;
690
691   result = split_at_whitespace (s);
692   if (result == NULL)
693     goto out;
694
695   if (device->priv->prop_strvs == NULL)
696     device->priv->prop_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev);
697   g_hash_table_insert (device->priv->prop_strvs, g_strdup (key), result);
698
699 out:
700   return (const gchar* const *) result;
701 }
702
703 /* ---------------------------------------------------------------------------------------------------- */
704
705 /**
706  * g_udev_device_get_sysfs_attr_keys:
707  * @device: A #GUdevDevice.
708  *
709  * Gets all keys for sysfs attributes on @device.
710  *
711  * 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.
712  */
713 const gchar * const *
714 g_udev_device_get_sysfs_attr_keys (GUdevDevice *device)
715 {
716   struct udev_list_entry *l;
717   GPtrArray *p;
718
719   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
720
721   if (device->priv->sysfs_attr_keys != NULL)
722     goto out;
723
724   p = g_ptr_array_new ();
725   for (l = udev_device_get_sysattr_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
726     {
727       g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
728     }
729   g_ptr_array_add (p, NULL);
730   device->priv->sysfs_attr_keys = (gchar **) g_ptr_array_free (p, FALSE);
731
732  out:
733   return (const gchar * const *) device->priv->sysfs_attr_keys;
734 }
735
736 /**
737  * g_udev_device_has_sysfs_attr:
738  * @device: A #GUdevDevice.
739  * @key: Name of sysfs attribute.
740  *
741  * Check if a the sysfs attribute with the given key exists.
742  *
743  * Returns: %TRUE only if the value for @key exist.
744  */
745 gboolean
746 g_udev_device_has_sysfs_attr (GUdevDevice  *device,
747                             const gchar  *key)
748 {
749   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
750   g_return_val_if_fail (key != NULL, FALSE);
751   return udev_device_get_sysattr_value (device->priv->udevice, key) != NULL;
752 }
753
754 /**
755  * g_udev_device_get_sysfs_attr:
756  * @device: A #GUdevDevice.
757  * @name: Name of the sysfs attribute.
758  *
759  * Look up the sysfs attribute with @name on @device.
760  *
761  * Returns: The value of the sysfs attribute or %NULL if there is no
762  * such attribute. Do not free this string, it is owned by @device.
763  */
764 const gchar *
765 g_udev_device_get_sysfs_attr (GUdevDevice  *device,
766                               const gchar  *name)
767 {
768   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
769   g_return_val_if_fail (name != NULL, NULL);
770   return udev_device_get_sysattr_value (device->priv->udevice, name);
771 }
772
773 /**
774  * g_udev_device_get_sysfs_attr_as_int:
775  * @device: A #GUdevDevice.
776  * @name: Name of the sysfs attribute.
777  *
778  * Look up the sysfs attribute with @name on @device and convert it to an integer
779  * using strtol().
780  *
781  * Returns: The value of the sysfs attribute or 0 if there is no such
782  * attribute.
783  */
784 gint
785 g_udev_device_get_sysfs_attr_as_int (GUdevDevice  *device,
786                                      const gchar  *name)
787 {
788   gint result;
789   const gchar *s;
790
791   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
792   g_return_val_if_fail (name != NULL, 0);
793
794   result = 0;
795   s = g_udev_device_get_sysfs_attr (device, name);
796   if (s == NULL)
797     goto out;
798
799   result = strtol (s, NULL, 0);
800 out:
801   return result;
802 }
803
804 /**
805  * g_udev_device_get_sysfs_attr_as_uint64:
806  * @device: A #GUdevDevice.
807  * @name: Name of the sysfs attribute.
808  *
809  * Look up the sysfs attribute with @name on @device and convert it to an unsigned
810  * 64-bit integer using g_ascii_strtoull().
811  *
812  * Returns: The value of the sysfs attribute or 0 if there is no such
813  * attribute.
814  */
815 guint64
816 g_udev_device_get_sysfs_attr_as_uint64 (GUdevDevice  *device,
817                                         const gchar  *name)
818 {
819   guint64 result;
820   const gchar *s;
821
822   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
823   g_return_val_if_fail (name != NULL, 0);
824
825   result = 0;
826   s = g_udev_device_get_sysfs_attr (device, name);
827   if (s == NULL)
828     goto out;
829
830   result = g_ascii_strtoull (s, NULL, 0);
831 out:
832   return result;
833 }
834
835 /**
836  * g_udev_device_get_sysfs_attr_as_double:
837  * @device: A #GUdevDevice.
838  * @name: Name of the sysfs attribute.
839  *
840  * Look up the sysfs attribute with @name on @device and convert it to a double
841  * precision floating point number using strtod().
842  *
843  * Returns: The value of the sysfs attribute or 0.0 if there is no such
844  * attribute.
845  */
846 gdouble
847 g_udev_device_get_sysfs_attr_as_double (GUdevDevice  *device,
848                                         const gchar  *name)
849 {
850   gdouble result;
851   const gchar *s;
852
853   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0);
854   g_return_val_if_fail (name != NULL, 0.0);
855
856   result = 0.0;
857   s = g_udev_device_get_sysfs_attr (device, name);
858   if (s == NULL)
859     goto out;
860
861   result = strtod (s, NULL);
862 out:
863   return result;
864 }
865
866 /**
867  * g_udev_device_get_sysfs_attr_as_boolean:
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 an
872  * boolean. This is done by doing a case-insensitive string comparison
873  * on the string value against "1" and "true".
874  *
875  * Returns: The value of the sysfs attribute or %FALSE if there is no such
876  * attribute.
877  */
878 gboolean
879 g_udev_device_get_sysfs_attr_as_boolean (GUdevDevice  *device,
880                                          const gchar  *name)
881 {
882   gboolean result;
883   const gchar *s;
884
885   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
886   g_return_val_if_fail (name != NULL, FALSE);
887
888   result = FALSE;
889   s = g_udev_device_get_sysfs_attr (device, name);
890   if (s == NULL)
891     goto out;
892
893   if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0)
894     result = TRUE;
895  out:
896   return result;
897 }
898
899 /**
900  * g_udev_device_get_sysfs_attr_as_strv:
901  * @device: A #GUdevDevice.
902  * @name: Name of the sysfs attribute.
903  *
904  * Look up the sysfs attribute with @name on @device and return the result of
905  * splitting it into non-empty tokens split at white space (only space (' '),
906  * form-feed ('\f'), newline ('\n'), carriage return ('\r'), horizontal
907  * tab ('\t'), and vertical tab ('\v') are considered; the locale is
908  * not taken into account).
909  *
910  * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): The value of the sysfs attribute split into tokens or %NULL if there is no such attribute. This array is owned by @device and should not be freed by the caller.
911  */
912 const gchar * const *
913 g_udev_device_get_sysfs_attr_as_strv (GUdevDevice  *device,
914                                       const gchar  *name)
915 {
916   gchar **result;
917   const gchar *s;
918
919   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
920   g_return_val_if_fail (name != NULL, NULL);
921
922   if (device->priv->sysfs_attr_strvs != NULL)
923     {
924       result = g_hash_table_lookup (device->priv->sysfs_attr_strvs, name);
925       if (result != NULL)
926         goto out;
927     }
928
929   result = NULL;
930   s = g_udev_device_get_sysfs_attr (device, name);
931   if (s == NULL)
932     goto out;
933
934   result = split_at_whitespace (s);
935   if (result == NULL)
936     goto out;
937
938   if (device->priv->sysfs_attr_strvs == NULL)
939     device->priv->sysfs_attr_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev);
940   g_hash_table_insert (device->priv->sysfs_attr_strvs, g_strdup (name), result);
941
942 out:
943   return (const gchar* const *) result;
944 }
945
946 /**
947  * g_udev_device_get_tags:
948  * @device: A #GUdevDevice.
949  *
950  * Gets all tags for @device.
951  *
952  * 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.
953  *
954  * Since: 165
955  */
956 const gchar* const *
957 g_udev_device_get_tags (GUdevDevice  *device)
958 {
959   struct udev_list_entry *l;
960   GPtrArray *p;
961
962   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
963
964   if (device->priv->tags != NULL)
965     goto out;
966
967   p = g_ptr_array_new ();
968   for (l = udev_device_get_tags_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
969     {
970       g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
971     }
972   g_ptr_array_add (p, NULL);
973   device->priv->tags = (gchar **) g_ptr_array_free (p, FALSE);
974
975  out:
976   return (const gchar * const *) device->priv->tags;
977 }
978
979 /**
980  * g_udev_device_get_is_initialized:
981  * @device: A #GUdevDevice.
982  *
983  * Gets whether @device has been initalized.
984  *
985  * Returns: Whether @device has been initialized.
986  *
987  * Since: 165
988  */
989 gboolean
990 g_udev_device_get_is_initialized (GUdevDevice  *device)
991 {
992   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
993   return udev_device_get_is_initialized (device->priv->udevice);
994 }
995
996 /**
997  * g_udev_device_get_usec_since_initialized:
998  * @device: A #GUdevDevice.
999  *
1000  * Gets number of micro-seconds since @device was initialized.
1001  *
1002  * This only works for devices with properties in the udev
1003  * database. All other devices return 0.
1004  *
1005  * Returns: Number of micro-seconds since @device was initialized or 0 if unknown.
1006  *
1007  * Since: 165
1008  */
1009 guint64
1010 g_udev_device_get_usec_since_initialized (GUdevDevice *device)
1011 {
1012   g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
1013   return udev_device_get_usec_since_initialized (device->priv->udevice);
1014 }