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