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