1 /* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
3 * Copyright (C) 2008 David Zeuthen <davidz@redhat.com>
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.
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.
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.
29 #include "gudevdevice.h"
30 #include "gudevprivate.h"
34 * @short_description: Get information about a device
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
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().
50 * To navigate the device tree, use g_udev_device_get_parent() and
51 * g_udev_device_get_parent_with_subsystem().
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().
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().
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.
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.
82 struct _GUdevDevicePrivate
84 struct udev_device *udevice;
86 /* computed ondemand and cached */
87 gchar **device_file_symlinks;
88 gchar **property_keys;
89 GHashTable *prop_strvs;
90 GHashTable *sysfs_attr_strvs;
93 G_DEFINE_TYPE (GUdevDevice, g_udev_device, G_TYPE_OBJECT)
96 g_udev_device_finalize (GObject *object)
98 GUdevDevice *device = G_UDEV_DEVICE (object);
100 g_strfreev (device->priv->device_file_symlinks);
101 g_strfreev (device->priv->property_keys);
103 if (device->priv->udevice != NULL)
104 udev_device_unref (device->priv->udevice);
106 if (device->priv->prop_strvs != NULL)
107 g_hash_table_unref (device->priv->prop_strvs);
109 if (device->priv->sysfs_attr_strvs != NULL)
110 g_hash_table_unref (device->priv->sysfs_attr_strvs);
112 if (G_OBJECT_CLASS (g_udev_device_parent_class)->finalize != NULL)
113 (* G_OBJECT_CLASS (g_udev_device_parent_class)->finalize) (object);
117 g_udev_device_class_init (GUdevDeviceClass *klass)
119 GObjectClass *gobject_class = (GObjectClass *) klass;
121 gobject_class->finalize = g_udev_device_finalize;
123 g_type_class_add_private (klass, sizeof (GUdevDevicePrivate));
127 g_udev_device_init (GUdevDevice *device)
129 device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
136 _g_udev_device_new (struct udev_device *udevice)
140 device = G_UDEV_DEVICE (g_object_new (G_UDEV_TYPE_DEVICE, NULL));
141 device->priv->udevice = udev_device_ref (udevice);
147 * g_udev_device_get_subsystem:
148 * @device: A #GUdevDevice.
150 * Gets the subsystem for @device.
152 * Returns: The subsystem for @device.
155 g_udev_device_get_subsystem (GUdevDevice *device)
157 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
158 return udev_device_get_subsystem (device->priv->udevice);
162 * g_udev_device_get_devtype:
163 * @device: A #GUdevDevice.
165 * Gets the device type for @device.
167 * Returns: The devtype for @device.
170 g_udev_device_get_devtype (GUdevDevice *device)
172 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
173 return udev_device_get_devtype (device->priv->udevice);
177 * g_udev_device_get_name:
178 * @device: A #GUdevDevice.
180 * Gets the name of @device, e.g. "sda3".
182 * Returns: The name of @device.
185 g_udev_device_get_name (GUdevDevice *device)
187 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
188 return udev_device_get_sysname (device->priv->udevice);
192 * g_udev_device_get_number:
193 * @device: A #GUdevDevice.
195 * Gets the number of @device, e.g. "3" if g_udev_device_get_name() returns "sda3".
197 * Returns: The number of @device.
200 g_udev_device_get_number (GUdevDevice *device)
202 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
203 return udev_device_get_sysnum (device->priv->udevice);
207 * g_udev_device_get_sysfs_path:
208 * @device: A #GUdevDevice.
210 * Gets the sysfs path for @device.
212 * Returns: The sysfs path for @device.
215 g_udev_device_get_sysfs_path (GUdevDevice *device)
217 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
218 return udev_device_get_syspath (device->priv->udevice);
222 * g_udev_device_get_driver:
223 * @device: A #GUdevDevice.
225 * Gets the name of the driver used for @device.
227 * Returns: The name of the driver for @device or %NULL if unknown.
230 g_udev_device_get_driver (GUdevDevice *device)
232 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
233 return udev_device_get_driver (device->priv->udevice);
237 * g_udev_device_get_action:
238 * @device: A #GUdevDevice.
240 * Gets the most recent action (e.g. "add", "remove", "change", etc.) for @device.
242 * Returns: An action string.
245 g_udev_device_get_action (GUdevDevice *device)
247 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
248 return udev_device_get_action (device->priv->udevice);
252 * g_udev_device_get_seqnum:
253 * @device: A #GUdevDevice.
255 * Gets the most recent sequence number for @device.
257 * Returns: A sequence number.
260 g_udev_device_get_seqnum (GUdevDevice *device)
262 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
263 return udev_device_get_seqnum (device->priv->udevice);
267 * g_udev_device_get_device_type:
268 * @device: A #GUdevDevice.
270 * Gets the type of the device file, if any, for @device.
272 * Returns: The device number for @device or #G_UDEV_DEVICE_TYPE_NONE if the device does not have a device file.
275 g_udev_device_get_device_type (GUdevDevice *device)
277 struct stat stat_buf;
278 const gchar *device_file;
279 GUdevDeviceType type;
281 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), G_UDEV_DEVICE_TYPE_NONE);
283 type = G_UDEV_DEVICE_TYPE_NONE;
285 /* TODO: would be better to have support for this in libudev... */
287 device_file = g_udev_device_get_device_file (device);
288 if (device_file == NULL)
291 if (stat (device_file, &stat_buf) != 0)
294 if (S_ISBLK (stat_buf.st_mode))
295 type = G_UDEV_DEVICE_TYPE_BLOCK;
296 else if (S_ISCHR (stat_buf.st_mode))
297 type = G_UDEV_DEVICE_TYPE_CHAR;
304 * g_udev_device_get_device_number:
305 * @device: A #GUdevDevice.
307 * Gets the device number, if any, for @device.
309 * Returns: The device number for @device or 0 if unknown.
312 g_udev_device_get_device_number (GUdevDevice *device)
314 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
315 return udev_device_get_devnum (device->priv->udevice);
319 * g_udev_device_get_device_file:
320 * @device: A #GUdevDevice.
322 * Gets the device file for @device.
324 * Returns: The device file for @device or %NULL if no device file
328 g_udev_device_get_device_file (GUdevDevice *device)
330 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
331 return udev_device_get_devnode (device->priv->udevice);
335 * g_udev_device_get_device_file_symlinks:
336 * @device: A #GUdevDevice.
338 * Gets a list of symlinks (in <literal>/dev</literal>) that points to
339 * the device file for @device.
341 * 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.
343 const gchar * const *
344 g_udev_device_get_device_file_symlinks (GUdevDevice *device)
346 struct udev_list_entry *l;
349 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
351 if (device->priv->device_file_symlinks != NULL)
354 p = g_ptr_array_new ();
355 for (l = udev_device_get_devlinks_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
357 g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
359 g_ptr_array_add (p, NULL);
360 device->priv->device_file_symlinks = (gchar **) g_ptr_array_free (p, FALSE);
363 return (const gchar * const *) device->priv->device_file_symlinks;
366 /* ---------------------------------------------------------------------------------------------------- */
369 * g_udev_device_get_parent:
370 * @device: A #GUdevDevice.
372 * Gets the immediate parent of @device, if any.
374 * Returns: A #GUdevDevice or %NULL if @device has no parent. Free with g_object_unref().
377 g_udev_device_get_parent (GUdevDevice *device)
380 struct udev_device *udevice;
382 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
386 udevice = udev_device_get_parent (device->priv->udevice);
390 ret = _g_udev_device_new (udevice);
397 * g_udev_device_get_parent_with_subsystem:
398 * @device: A #GUdevDevice.
399 * @subsystem: The subsystem of the parent to get.
400 * @devtype: (allow-none): The devtype of the parent to get or %NULL.
402 * Walks up the chain of parents of @device and returns the first
403 * device encountered where @subsystem and @devtype matches, if any.
405 * Returns: A #GUdevDevice or %NULL if @device has no parent with @subsystem and @devtype. Free with g_object_unref().
408 g_udev_device_get_parent_with_subsystem (GUdevDevice *device,
409 const gchar *subsystem,
410 const gchar *devtype)
413 struct udev_device *udevice;
415 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
416 g_return_val_if_fail (subsystem != NULL, NULL);
420 udevice = udev_device_get_parent_with_subsystem_devtype (device->priv->udevice,
426 ret = _g_udev_device_new (udevice);
432 /* ---------------------------------------------------------------------------------------------------- */
435 * g_udev_device_get_property_keys:
436 * @device: A #GUdevDevice.
438 * Gets all keys for properties on @device.
440 * 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 g_udev_device_get_property_keys (GUdevDevice *device)
445 struct udev_list_entry *l;
448 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
450 if (device->priv->property_keys != NULL)
453 p = g_ptr_array_new ();
454 for (l = udev_device_get_properties_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l))
456 g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l)));
458 g_ptr_array_add (p, NULL);
459 device->priv->property_keys = (gchar **) g_ptr_array_free (p, FALSE);
462 return (const gchar * const *) device->priv->property_keys;
467 * g_udev_device_has_property:
468 * @device: A #GUdevDevice.
469 * @key: Name of property.
471 * Check if a the property with the given key exists.
473 * Returns: %TRUE only if the value for @key exist.
476 g_udev_device_has_property (GUdevDevice *device,
479 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
480 g_return_val_if_fail (key != NULL, FALSE);
481 return udev_device_get_property_value (device->priv->udevice, key) != NULL;
485 * g_udev_device_get_property:
486 * @device: A #GUdevDevice.
487 * @key: Name of property.
489 * Look up the value for @key on @device.
491 * 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 g_udev_device_get_property (GUdevDevice *device,
497 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
498 g_return_val_if_fail (key != NULL, NULL);
499 return udev_device_get_property_value (device->priv->udevice, key);
503 * g_udev_device_get_property_as_int:
504 * @device: A #GUdevDevice.
505 * @key: Name of property.
507 * Look up the value for @key on @device and convert it to an integer
510 * Returns: The value for @key or 0 if @key doesn't exist or
514 g_udev_device_get_property_as_int (GUdevDevice *device,
520 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
521 g_return_val_if_fail (key != NULL, 0);
524 s = g_udev_device_get_property (device, key);
528 result = strtol (s, NULL, 0);
534 * g_udev_device_get_property_as_uint64:
535 * @device: A #GUdevDevice.
536 * @key: Name of property.
538 * Look up the value for @key on @device and convert it to an unsigned
539 * 64-bit integer using strtoll().
541 * Returns: The value for @key or 0 if @key doesn't exist or isn't a
545 g_udev_device_get_property_as_uint64 (GUdevDevice *device,
551 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
552 g_return_val_if_fail (key != NULL, 0);
555 s = g_udev_device_get_property (device, key);
559 result = strtoll (s, NULL, 0);
565 * g_udev_device_get_property_as_double:
566 * @device: A #GUdevDevice.
567 * @key: Name of property.
569 * Look up the value for @key on @device and convert it to a double
570 * precision floating point number using strtod().
572 * Returns: The value for @key or 0.0 if @key doesn't exist or isn't a
576 g_udev_device_get_property_as_double (GUdevDevice *device,
582 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0);
583 g_return_val_if_fail (key != NULL, 0.0);
586 s = g_udev_device_get_property (device, key);
590 result = strtod (s, NULL);
596 * g_udev_device_get_property_as_boolean:
597 * @device: A #GUdevDevice.
598 * @key: Name of property.
600 * Look up the value for @key on @device and convert it to an
601 * boolean. This is done by doing a case-insensitive string comparison
602 * on the string value against "1" and "true".
604 * Returns: The value for @key or %FALSE if @key doesn't exist or
608 g_udev_device_get_property_as_boolean (GUdevDevice *device,
614 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
615 g_return_val_if_fail (key != NULL, FALSE);
618 s = g_udev_device_get_property (device, key);
622 if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0)
629 split_at_whitespace (const gchar *s)
635 result = g_strsplit_set (s, " \v\t\r\n", 0);
637 /* remove empty strings, thanks GLib */
638 for (n = 0; result[n] != NULL; n++)
640 if (strlen (result[n]) == 0)
643 for (m = n; result[m] != NULL; m++)
644 result[m] = result[m + 1];
653 * g_udev_device_get_property_as_strv:
654 * @device: A #GUdevDevice.
655 * @key: Name of property.
657 * Look up the value for @key on @device and return the result of
658 * splitting it into non-empty tokens split at white space (only space
659 * (' '), form-feed ('\f'), newline ('\n'), carriage return ('\r'),
660 * horizontal tab ('\t'), and vertical tab ('\v') are considered; the
661 * locale is not taken into account).
663 * 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 g_udev_device_get_property_as_strv (GUdevDevice *device,
672 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
673 g_return_val_if_fail (key != NULL, NULL);
675 if (device->priv->prop_strvs != NULL)
677 result = g_hash_table_lookup (device->priv->prop_strvs, key);
683 s = g_udev_device_get_property (device, key);
687 result = split_at_whitespace (s);
691 if (device->priv->prop_strvs == NULL)
692 device->priv->prop_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev);
693 g_hash_table_insert (device->priv->prop_strvs, g_strdup (key), result);
696 return (const gchar* const *) result;
699 /* ---------------------------------------------------------------------------------------------------- */
702 * g_udev_device_get_sysfs_attr:
703 * @device: A #GUdevDevice.
704 * @name: Name of the sysfs attribute.
706 * Look up the sysfs attribute with @name on @device.
708 * Returns: The value of the sysfs attribute or %NULL if there is no
709 * such attribute. Do not free this string, it is owned by @device.
712 g_udev_device_get_sysfs_attr (GUdevDevice *device,
715 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
716 g_return_val_if_fail (name != NULL, NULL);
717 return udev_device_get_sysattr_value (device->priv->udevice, name);
721 * g_udev_device_get_sysfs_attr_as_int:
722 * @device: A #GUdevDevice.
723 * @name: Name of the sysfs attribute.
725 * Look up the sysfs attribute with @name on @device and convert it to an integer
728 * Returns: The value of the sysfs attribute or 0 if there is no such
732 g_udev_device_get_sysfs_attr_as_int (GUdevDevice *device,
738 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
739 g_return_val_if_fail (name != NULL, 0);
742 s = g_udev_device_get_sysfs_attr (device, name);
746 result = strtol (s, NULL, 0);
752 * g_udev_device_get_sysfs_attr_as_uint64:
753 * @device: A #GUdevDevice.
754 * @name: Name of the sysfs attribute.
756 * Look up the sysfs attribute with @name on @device and convert it to an unsigned
757 * 64-bit integer using strtoll().
759 * Returns: The value of the sysfs attribute or 0 if there is no such
763 g_udev_device_get_sysfs_attr_as_uint64 (GUdevDevice *device,
769 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0);
770 g_return_val_if_fail (name != NULL, 0);
773 s = g_udev_device_get_sysfs_attr (device, name);
777 result = strtoll (s, NULL, 0);
783 * g_udev_device_get_sysfs_attr_as_double:
784 * @device: A #GUdevDevice.
785 * @name: Name of the sysfs attribute.
787 * Look up the sysfs attribute with @name on @device and convert it to a double
788 * precision floating point number using strtod().
790 * Returns: The value of the sysfs attribute or 0.0 if there is no such
794 g_udev_device_get_sysfs_attr_as_double (GUdevDevice *device,
800 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0);
801 g_return_val_if_fail (name != NULL, 0.0);
804 s = g_udev_device_get_sysfs_attr (device, name);
808 result = strtod (s, NULL);
814 * g_udev_device_get_sysfs_attr_as_boolean:
815 * @device: A #GUdevDevice.
816 * @name: Name of the sysfs attribute.
818 * Look up the sysfs attribute with @name on @device and convert it to an
819 * boolean. This is done by doing a case-insensitive string comparison
820 * on the string value against "1" and "true".
822 * Returns: The value of the sysfs attribute or %FALSE if there is no such
826 g_udev_device_get_sysfs_attr_as_boolean (GUdevDevice *device,
832 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE);
833 g_return_val_if_fail (name != NULL, FALSE);
836 s = g_udev_device_get_sysfs_attr (device, name);
840 if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0)
847 * g_udev_device_get_sysfs_attr_as_strv:
848 * @device: A #GUdevDevice.
849 * @name: Name of the sysfs attribute.
851 * Look up the sysfs attribute with @name on @device and return the result of
852 * splitting it into non-empty tokens split at white space (only space (' '),
853 * form-feed ('\f'), newline ('\n'), carriage return ('\r'), horizontal
854 * tab ('\t'), and vertical tab ('\v') are considered; the locale is
855 * not taken into account).
857 * 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.
859 const gchar * const *
860 g_udev_device_get_sysfs_attr_as_strv (GUdevDevice *device,
866 g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
867 g_return_val_if_fail (name != NULL, NULL);
869 if (device->priv->sysfs_attr_strvs != NULL)
871 result = g_hash_table_lookup (device->priv->sysfs_attr_strvs, name);
877 s = g_udev_device_get_sysfs_attr (device, name);
881 result = split_at_whitespace (s);
885 if (device->priv->sysfs_attr_strvs == NULL)
886 device->priv->sysfs_attr_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev);
887 g_hash_table_insert (device->priv->sysfs_attr_strvs, g_strdup (name), result);
890 return (const gchar* const *) result;