]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/gudev/gudevdevice.c
treewide: Correct typos and spell plural of bus consistent
[thirdparty/systemd.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 initialized.
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 }