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