2020-11-09 05:23:58 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2008-08-27 22:02:41 +02:00
|
|
|
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <ctype.h>
|
2008-08-27 22:02:41 +02:00
|
|
|
#include <dirent.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <errno.h>
|
2008-09-13 21:09:28 +02:00
|
|
|
#include <fcntl.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <linux/sockios.h>
|
2011-03-05 06:26:39 +01:00
|
|
|
#include <net/if.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2011-03-05 06:26:39 +01:00
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/socket.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
2008-08-27 22:02:41 +02:00
|
|
|
|
2015-11-17 06:52:45 +01:00
|
|
|
#include "libudev.h"
|
2015-04-01 13:55:20 +02:00
|
|
|
#include "sd-device.h"
|
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "device-private.h"
|
|
|
|
#include "device-util.h"
|
2015-04-01 13:55:20 +02:00
|
|
|
#include "libudev-device-internal.h"
|
2019-06-12 08:15:06 +02:00
|
|
|
#include "libudev-list-internal.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "parse-util.h"
|
2018-11-16 03:44:17 +01:00
|
|
|
#include "time-util.h"
|
2013-11-13 03:34:24 +01:00
|
|
|
|
2009-06-15 17:09:43 +02:00
|
|
|
/**
|
|
|
|
* SECTION:libudev-device
|
|
|
|
* @short_description: kernel sys devices
|
|
|
|
*
|
|
|
|
* Representation of kernel sys devices. Devices are uniquely identified
|
|
|
|
* by their syspath, every device has exactly one path in the kernel sys
|
2013-08-15 23:38:09 +02:00
|
|
|
* filesystem. Devices usually belong to a kernel subsystem, and have
|
2009-08-08 15:29:38 +02:00
|
|
|
* a unique name inside that subsystem.
|
2009-06-15 17:09:43 +02:00
|
|
|
*/
|
|
|
|
|
2019-06-12 08:15:06 +02:00
|
|
|
/**
|
|
|
|
* udev_device:
|
|
|
|
*
|
|
|
|
* Opaque object representing one kernel sys device.
|
|
|
|
*/
|
|
|
|
struct udev_device {
|
|
|
|
struct udev *udev;
|
|
|
|
|
|
|
|
/* real device object */
|
|
|
|
sd_device *device;
|
|
|
|
|
|
|
|
/* legacy */
|
|
|
|
unsigned n_ref;
|
|
|
|
|
|
|
|
struct udev_device *parent;
|
|
|
|
bool parent_set;
|
|
|
|
|
|
|
|
struct udev_list *properties;
|
|
|
|
uint64_t properties_generation;
|
2018-12-13 18:08:45 +01:00
|
|
|
struct udev_list *all_tags, *current_tags;
|
|
|
|
uint64_t all_tags_generation, current_tags_generation;
|
2019-06-12 08:15:06 +02:00
|
|
|
struct udev_list *devlinks;
|
|
|
|
uint64_t devlinks_generation;
|
|
|
|
bool properties_read:1;
|
2018-12-13 18:08:45 +01:00
|
|
|
bool all_tags_read:1;
|
|
|
|
bool current_tags_read:1;
|
2019-06-12 08:15:06 +02:00
|
|
|
bool devlinks_read:1;
|
|
|
|
struct udev_list *sysattrs;
|
|
|
|
bool sysattrs_read;
|
|
|
|
};
|
|
|
|
|
2011-05-20 15:36:27 +02:00
|
|
|
/**
|
2011-09-26 21:36:32 +02:00
|
|
|
* udev_device_get_seqnum:
|
2011-05-20 15:36:27 +02:00
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
|
|
|
* This is only valid if the device was received through a monitor. Devices read from
|
|
|
|
* sys do not have a sequence number.
|
|
|
|
*
|
|
|
|
* Returns: the kernel event sequence number, or 0 if there is no sequence number available.
|
|
|
|
**/
|
2019-03-09 03:07:26 +01:00
|
|
|
_public_ unsigned long long udev_device_get_seqnum(struct udev_device *udev_device) {
|
|
|
|
uint64_t seqnum;
|
2011-05-20 15:36:27 +02:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return_errno(udev_device, 0, EINVAL);
|
2011-05-20 15:36:27 +02:00
|
|
|
|
2019-03-09 03:07:26 +01:00
|
|
|
if (device_get_seqnum(udev_device->device, &seqnum) < 0)
|
2015-04-01 13:55:20 +02:00
|
|
|
return 0;
|
2011-05-20 15:36:27 +02:00
|
|
|
|
2019-03-09 03:07:26 +01:00
|
|
|
return seqnum;
|
2011-05-20 15:36:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* udev_device_get_devnum:
|
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
2012-04-20 03:25:36 +02:00
|
|
|
* Get the device major/minor number.
|
|
|
|
*
|
|
|
|
* Returns: the dev_t number.
|
2011-05-20 15:36:27 +02:00
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ dev_t udev_device_get_devnum(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
dev_t devnum;
|
|
|
|
int r;
|
2011-05-20 15:36:27 +02:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return_errno(udev_device, makedev(0, 0), EINVAL);
|
2011-05-20 15:36:27 +02:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
r = sd_device_get_devnum(udev_device->device, &devnum);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r == -ENOENT)
|
2015-04-01 13:55:20 +02:00
|
|
|
return makedev(0, 0);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(makedev(0, 0), r);
|
2011-05-20 15:36:27 +02:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
return devnum;
|
2011-05-20 15:36:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* udev_device_get_driver:
|
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
2012-04-20 03:25:36 +02:00
|
|
|
* Get the kernel driver name.
|
|
|
|
*
|
|
|
|
* Returns: the driver name string, or #NULL if there is no driver attached.
|
2011-05-20 15:36:27 +02:00
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ const char *udev_device_get_driver(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
const char *driver;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
2011-05-20 15:36:27 +02:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
r = sd_device_get_driver(udev_device->device, &driver);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2011-05-20 15:36:27 +02:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
return driver;
|
2011-05-20 15:36:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* udev_device_get_devtype:
|
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
|
|
|
* Retrieve the devtype string of the udev device.
|
|
|
|
*
|
2018-02-08 10:34:52 +01:00
|
|
|
* Returns: the devtype name of the udev device, or #NULL if it cannot be determined
|
2011-05-20 15:36:27 +02:00
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ const char *udev_device_get_devtype(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
const char *devtype;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
|
|
|
|
|
|
|
r = sd_device_get_devtype(udev_device->device, &devtype);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r == -ENOENT)
|
2012-01-10 01:34:15 +01:00
|
|
|
return NULL;
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2011-05-20 15:36:27 +02:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
return devtype;
|
2011-05-20 15:36:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* udev_device_get_subsystem:
|
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
|
|
|
* Retrieve the subsystem string of the udev device. The string does not
|
|
|
|
* contain any "/".
|
|
|
|
*
|
2018-02-08 10:34:52 +01:00
|
|
|
* Returns: the subsystem name of the udev device, or #NULL if it cannot be determined
|
2011-05-20 15:36:27 +02:00
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ const char *udev_device_get_subsystem(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
const char *subsystem;
|
|
|
|
int r;
|
2015-03-05 18:08:50 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
2010-03-17 17:42:35 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
r = sd_device_get_subsystem(udev_device->device, &subsystem);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2010-03-17 17:42:35 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
return subsystem;
|
2010-03-17 17:42:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* udev_device_get_property_value:
|
|
|
|
* @udev_device: udev device
|
|
|
|
* @key: property name
|
|
|
|
*
|
2012-04-20 03:25:36 +02:00
|
|
|
* Get the value of a given property.
|
|
|
|
*
|
|
|
|
* Returns: the property string, or #NULL if there is no such property.
|
2010-03-17 17:42:35 +01:00
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) {
|
2018-11-21 06:06:41 +01:00
|
|
|
const char *value;
|
2015-04-01 13:55:20 +02:00
|
|
|
int r;
|
2012-01-10 01:34:15 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return_errno(udev_device && key, NULL, EINVAL);
|
2012-01-10 01:34:15 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
r = sd_device_get_property_value(udev_device->device, key, &value);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2012-01-10 01:34:15 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
return value;
|
2008-09-26 19:43:32 +02:00
|
|
|
}
|
|
|
|
|
2018-08-24 09:11:13 +02:00
|
|
|
struct udev_device *udev_device_new(struct udev *udev, sd_device *device) {
|
2018-12-13 18:08:45 +01:00
|
|
|
_cleanup_(udev_list_freep) struct udev_list *properties = NULL, *all_tags = NULL, *current_tags = NULL, *sysattrs = NULL, *devlinks = NULL;
|
2012-01-10 01:34:15 +01:00
|
|
|
struct udev_device *udev_device;
|
|
|
|
|
2018-08-24 09:11:13 +02:00
|
|
|
assert(device);
|
|
|
|
|
2019-06-12 06:03:19 +02:00
|
|
|
properties = udev_list_new(true);
|
|
|
|
if (!properties)
|
|
|
|
return_with_errno(NULL, ENOMEM);
|
2018-12-13 18:08:45 +01:00
|
|
|
all_tags = udev_list_new(true);
|
|
|
|
if (!all_tags)
|
|
|
|
return_with_errno(NULL, ENOMEM);
|
|
|
|
current_tags = udev_list_new(true);
|
|
|
|
if (!current_tags)
|
2019-06-12 06:03:19 +02:00
|
|
|
return_with_errno(NULL, ENOMEM);
|
|
|
|
sysattrs = udev_list_new(true);
|
|
|
|
if (!sysattrs)
|
|
|
|
return_with_errno(NULL, ENOMEM);
|
|
|
|
devlinks = udev_list_new(true);
|
|
|
|
if (!devlinks)
|
|
|
|
return_with_errno(NULL, ENOMEM);
|
|
|
|
|
2018-08-24 07:16:43 +02:00
|
|
|
udev_device = new(struct udev_device, 1);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (!udev_device)
|
|
|
|
return_with_errno(NULL, ENOMEM);
|
2018-08-24 07:16:43 +02:00
|
|
|
|
|
|
|
*udev_device = (struct udev_device) {
|
|
|
|
.n_ref = 1,
|
|
|
|
.udev = udev,
|
2018-08-24 09:11:13 +02:00
|
|
|
.device = sd_device_ref(device),
|
2019-06-12 06:03:19 +02:00
|
|
|
.properties = TAKE_PTR(properties),
|
2018-12-13 18:08:45 +01:00
|
|
|
.all_tags = TAKE_PTR(all_tags),
|
|
|
|
.current_tags = TAKE_PTR(current_tags),
|
2019-06-12 06:03:19 +02:00
|
|
|
.sysattrs = TAKE_PTR(sysattrs),
|
|
|
|
.devlinks = TAKE_PTR(devlinks),
|
2018-08-24 07:16:43 +02:00
|
|
|
};
|
|
|
|
|
2012-01-10 01:34:15 +01:00
|
|
|
return udev_device;
|
2008-08-27 22:02:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-09-16 02:12:47 +02:00
|
|
|
* udev_device_new_from_syspath:
|
2008-08-27 22:02:41 +02:00
|
|
|
* @udev: udev library context
|
2008-09-16 02:12:47 +02:00
|
|
|
* @syspath: sys device path including sys directory
|
2008-08-27 22:02:41 +02:00
|
|
|
*
|
2008-09-16 02:12:47 +02:00
|
|
|
* Create new udev device, and fill in information from the sys
|
2009-08-08 15:29:38 +02:00
|
|
|
* device and the udev database entry. The syspath is the absolute
|
2008-09-16 02:12:47 +02:00
|
|
|
* path to the device, including the sys mount point.
|
2008-08-27 22:02:41 +02:00
|
|
|
*
|
|
|
|
* The initial refcount is 1, and needs to be decremented to
|
2008-10-26 15:48:48 +01:00
|
|
|
* release the resources of the udev device.
|
2008-08-27 22:02:41 +02:00
|
|
|
*
|
|
|
|
* Returns: a new udev device, or #NULL, if it does not exist
|
|
|
|
**/
|
2015-04-01 13:55:20 +02:00
|
|
|
_public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) {
|
2018-08-24 09:11:13 +02:00
|
|
|
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
2015-04-01 13:55:20 +02:00
|
|
|
int r;
|
2012-01-10 01:34:15 +01:00
|
|
|
|
2018-08-24 09:11:13 +02:00
|
|
|
r = sd_device_new_from_syspath(&device, syspath);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2012-01-10 01:34:15 +01:00
|
|
|
|
2018-08-24 09:11:13 +02:00
|
|
|
return udev_device_new(udev, device);
|
2008-08-27 22:02:41 +02:00
|
|
|
}
|
|
|
|
|
2009-06-15 13:22:38 +02:00
|
|
|
/**
|
|
|
|
* udev_device_new_from_devnum:
|
|
|
|
* @udev: udev library context
|
|
|
|
* @type: char or block device
|
|
|
|
* @devnum: device major/minor number
|
|
|
|
*
|
|
|
|
* Create new udev device, and fill in information from the sys
|
2010-03-25 16:45:15 +01:00
|
|
|
* device and the udev database entry. The device is looked-up
|
|
|
|
* by its major/minor number and type. Character and block device
|
|
|
|
* numbers are not unique across the two types.
|
2009-06-15 13:22:38 +02:00
|
|
|
*
|
|
|
|
* The initial refcount is 1, and needs to be decremented to
|
|
|
|
* release the resources of the udev device.
|
|
|
|
*
|
|
|
|
* Returns: a new udev device, or #NULL, if it does not exist
|
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum) {
|
2018-08-24 09:11:13 +02:00
|
|
|
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
2015-04-01 13:55:20 +02:00
|
|
|
int r;
|
|
|
|
|
2018-08-24 09:11:13 +02:00
|
|
|
r = sd_device_new_from_devnum(&device, type, devnum);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2008-09-22 08:28:56 +02:00
|
|
|
|
2018-08-24 09:11:13 +02:00
|
|
|
return udev_device_new(udev, device);
|
2008-09-22 08:28:56 +02:00
|
|
|
}
|
|
|
|
|
2012-08-10 19:56:57 +02:00
|
|
|
/**
|
|
|
|
* udev_device_new_from_device_id:
|
|
|
|
* @udev: udev library context
|
|
|
|
* @id: text string identifying a kernel device
|
|
|
|
*
|
|
|
|
* Create new udev device, and fill in information from the sys
|
|
|
|
* device and the udev database entry. The device is looked-up
|
|
|
|
* by a special string:
|
|
|
|
* b8:2 - block device major:minor
|
|
|
|
* c128:1 - char device major:minor
|
|
|
|
* n3 - network device ifindex
|
|
|
|
* +sound:card29 - kernel driver core subsystem:device name
|
|
|
|
*
|
|
|
|
* The initial refcount is 1, and needs to be decremented to
|
|
|
|
* release the resources of the udev device.
|
|
|
|
*
|
|
|
|
* Returns: a new udev device, or #NULL, if it does not exist
|
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id) {
|
2018-08-24 09:11:13 +02:00
|
|
|
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
2015-04-01 13:55:20 +02:00
|
|
|
int r;
|
|
|
|
|
2018-08-24 09:11:13 +02:00
|
|
|
r = sd_device_new_from_device_id(&device, id);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2015-04-01 13:55:20 +02:00
|
|
|
|
2018-08-24 09:11:13 +02:00
|
|
|
return udev_device_new(udev, device);
|
2010-12-12 20:07:15 +01:00
|
|
|
}
|
|
|
|
|
2009-06-15 13:22:38 +02:00
|
|
|
/**
|
|
|
|
* udev_device_new_from_subsystem_sysname:
|
|
|
|
* @udev: udev library context
|
2009-08-08 15:29:38 +02:00
|
|
|
* @subsystem: the subsystem of the device
|
2009-06-15 13:22:38 +02:00
|
|
|
* @sysname: the name of the device
|
|
|
|
*
|
2010-03-25 16:45:15 +01:00
|
|
|
* Create new udev device, and fill in information from the sys device
|
|
|
|
* and the udev database entry. The device is looked up by the subsystem
|
|
|
|
* and name string of the device, like "mem" / "zero", or "block" / "sda".
|
2009-06-15 13:22:38 +02:00
|
|
|
*
|
|
|
|
* The initial refcount is 1, and needs to be decremented to
|
|
|
|
* release the resources of the udev device.
|
|
|
|
*
|
|
|
|
* Returns: a new udev device, or #NULL, if it does not exist
|
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname) {
|
2018-08-24 09:11:13 +02:00
|
|
|
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
2015-04-01 13:55:20 +02:00
|
|
|
int r;
|
2012-01-10 01:34:15 +01:00
|
|
|
|
2018-08-24 09:11:13 +02:00
|
|
|
r = sd_device_new_from_subsystem_sysname(&device, subsystem, sysname);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2012-01-10 01:34:15 +01:00
|
|
|
|
2018-08-24 09:11:13 +02:00
|
|
|
return udev_device_new(udev, device);
|
2008-10-07 20:20:34 +02:00
|
|
|
}
|
|
|
|
|
2010-03-17 17:42:35 +01:00
|
|
|
/**
|
|
|
|
* udev_device_new_from_environment
|
|
|
|
* @udev: udev library context
|
|
|
|
*
|
|
|
|
* Create new udev device, and fill in information from the
|
|
|
|
* current process environment. This only works reliable if
|
|
|
|
* the process is called from a udev rule. It is usually used
|
|
|
|
* for tools executed from IMPORT= rules.
|
|
|
|
*
|
|
|
|
* The initial refcount is 1, and needs to be decremented to
|
|
|
|
* release the resources of the udev device.
|
|
|
|
*
|
|
|
|
* Returns: a new udev device, or #NULL, if it does not exist
|
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ struct udev_device *udev_device_new_from_environment(struct udev *udev) {
|
2018-08-24 09:11:13 +02:00
|
|
|
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
2015-04-01 13:55:20 +02:00
|
|
|
int r;
|
2010-03-17 17:42:35 +01:00
|
|
|
|
2018-08-24 09:11:13 +02:00
|
|
|
r = device_new_from_strv(&device, environ);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2010-03-17 17:42:35 +01:00
|
|
|
|
2018-08-24 09:11:13 +02:00
|
|
|
return udev_device_new(udev, device);
|
2010-03-17 17:42:35 +01:00
|
|
|
}
|
|
|
|
|
2018-08-24 07:32:05 +02:00
|
|
|
static struct udev_device *device_new_from_parent(struct udev_device *child) {
|
2018-08-24 09:11:13 +02:00
|
|
|
sd_device *parent;
|
2015-04-01 13:55:20 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return_errno(child, NULL, EINVAL);
|
|
|
|
|
2018-08-24 09:11:13 +02:00
|
|
|
r = sd_device_get_parent(child->device, &parent);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2014-07-31 15:25:01 +02:00
|
|
|
|
2018-08-24 09:11:13 +02:00
|
|
|
return udev_device_new(child->udev, parent);
|
2008-09-11 17:08:12 +02:00
|
|
|
}
|
|
|
|
|
2009-06-15 13:22:38 +02:00
|
|
|
/**
|
|
|
|
* udev_device_get_parent:
|
|
|
|
* @udev_device: the device to start searching from
|
|
|
|
*
|
|
|
|
* Find the next parent device, and fill in information from the sys
|
|
|
|
* device and the udev database entry.
|
|
|
|
*
|
2013-12-01 02:27:54 +01:00
|
|
|
* Returned device is not referenced. It is attached to the child
|
|
|
|
* device, and will be cleaned up when the child device is cleaned up.
|
2009-06-15 13:22:38 +02:00
|
|
|
*
|
2009-08-08 15:29:38 +02:00
|
|
|
* It is not necessarily just the upper level directory, empty or not
|
2009-06-15 13:22:38 +02:00
|
|
|
* recognized sys directories are ignored.
|
|
|
|
*
|
|
|
|
* It can be called as many times as needed, without caring about
|
|
|
|
* references.
|
|
|
|
*
|
|
|
|
* Returns: a new udev device, or #NULL, if it no parent exist.
|
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ struct udev_device *udev_device_get_parent(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
|
|
|
|
2012-01-10 01:34:15 +01:00
|
|
|
if (!udev_device->parent_set) {
|
|
|
|
udev_device->parent_set = true;
|
2015-04-01 13:55:20 +02:00
|
|
|
udev_device->parent = device_new_from_parent(udev_device);
|
2012-01-10 01:34:15 +01:00
|
|
|
}
|
2015-04-01 13:55:20 +02:00
|
|
|
|
|
|
|
/* TODO: errno will differ here in case parent == NULL */
|
|
|
|
return udev_device->parent;
|
2008-09-12 00:58:40 +02:00
|
|
|
}
|
|
|
|
|
2009-06-15 13:22:38 +02:00
|
|
|
/**
|
|
|
|
* udev_device_get_parent_with_subsystem_devtype:
|
|
|
|
* @udev_device: udev device to start searching from
|
2009-08-08 15:29:38 +02:00
|
|
|
* @subsystem: the subsystem of the device
|
2009-06-15 13:22:38 +02:00
|
|
|
* @devtype: the type (DEVTYPE) of the device
|
|
|
|
*
|
|
|
|
* Find the next parent device, with a matching subsystem and devtype
|
|
|
|
* value, and fill in information from the sys device and the udev
|
|
|
|
* database entry.
|
|
|
|
*
|
2009-12-03 13:31:27 +01:00
|
|
|
* If devtype is #NULL, only subsystem is checked, and any devtype will
|
2009-12-03 13:25:19 +01:00
|
|
|
* match.
|
|
|
|
*
|
2013-12-01 02:27:54 +01:00
|
|
|
* Returned device is not referenced. It is attached to the child
|
|
|
|
* device, and will be cleaned up when the child device is cleaned up.
|
2009-06-15 13:22:38 +02:00
|
|
|
*
|
|
|
|
* It can be called as many times as needed, without caring about
|
|
|
|
* references.
|
|
|
|
*
|
2009-06-15 20:28:28 +02:00
|
|
|
* Returns: a new udev device, or #NULL if no matching parent exists.
|
2009-06-15 13:22:38 +02:00
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype) {
|
2015-04-01 13:55:20 +02:00
|
|
|
sd_device *parent;
|
|
|
|
int r;
|
2009-01-02 04:14:47 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
|
|
|
|
|
|
|
/* this relies on the fact that finding the subdevice of a parent or the
|
|
|
|
parent of a subdevice commute */
|
|
|
|
|
|
|
|
/* first find the correct sd_device */
|
|
|
|
r = sd_device_get_parent_with_subsystem_devtype(udev_device->device, subsystem, devtype, &parent);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2009-01-03 11:10:10 +01:00
|
|
|
|
2016-08-15 05:22:12 +02:00
|
|
|
/* then walk the chain of udev_device parents until the corresponding
|
2015-04-01 13:55:20 +02:00
|
|
|
one is found */
|
2018-11-21 06:06:41 +01:00
|
|
|
while ((udev_device = udev_device_get_parent(udev_device)))
|
2015-04-01 13:55:20 +02:00
|
|
|
if (udev_device->device == parent)
|
|
|
|
return udev_device;
|
2014-07-31 15:25:01 +02:00
|
|
|
|
2018-11-21 06:06:41 +01:00
|
|
|
return_with_errno(NULL, ENOENT);
|
2009-01-02 04:14:47 +01:00
|
|
|
}
|
|
|
|
|
2008-08-27 22:02:41 +02:00
|
|
|
/**
|
|
|
|
* udev_device_get_udev:
|
2008-08-30 16:16:37 +02:00
|
|
|
* @udev_device: udev device
|
2008-08-27 22:02:41 +02:00
|
|
|
*
|
|
|
|
* Retrieve the udev library context the device was created with.
|
|
|
|
*
|
|
|
|
* Returns: the udev library context
|
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ struct udev *udev_device_get_udev(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
|
|
|
|
2012-01-10 01:34:15 +01:00
|
|
|
return udev_device->udev;
|
2008-08-27 22:02:41 +02:00
|
|
|
}
|
|
|
|
|
2018-08-28 06:07:48 +02:00
|
|
|
static struct udev_device *udev_device_free(struct udev_device *udev_device) {
|
|
|
|
assert(udev_device);
|
|
|
|
|
|
|
|
sd_device_unref(udev_device->device);
|
|
|
|
udev_device_unref(udev_device->parent);
|
|
|
|
|
2019-06-12 06:03:19 +02:00
|
|
|
udev_list_free(udev_device->properties);
|
|
|
|
udev_list_free(udev_device->sysattrs);
|
2018-12-13 18:08:45 +01:00
|
|
|
udev_list_free(udev_device->all_tags);
|
|
|
|
udev_list_free(udev_device->current_tags);
|
2019-06-12 06:03:19 +02:00
|
|
|
udev_list_free(udev_device->devlinks);
|
2018-08-28 06:07:48 +02:00
|
|
|
|
|
|
|
return mfree(udev_device);
|
|
|
|
}
|
|
|
|
|
2008-08-27 22:02:41 +02:00
|
|
|
/**
|
|
|
|
* udev_device_ref:
|
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
|
|
|
* Take a reference of a udev device.
|
|
|
|
*
|
|
|
|
* Returns: the passed udev device
|
|
|
|
**/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* udev_device_unref:
|
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
|
|
|
* Drop a reference of a udev device. If the refcount reaches zero,
|
2008-10-26 15:48:48 +01:00
|
|
|
* the resources of the device will be released.
|
2008-08-27 22:02:41 +02:00
|
|
|
*
|
2013-11-19 01:15:31 +01:00
|
|
|
* Returns: #NULL
|
2008-08-27 22:02:41 +02:00
|
|
|
**/
|
2018-08-28 06:07:48 +02:00
|
|
|
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(struct udev_device, udev_device, udev_device_free);
|
2008-08-27 22:02:41 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* udev_device_get_devpath:
|
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
2008-09-01 18:52:22 +02:00
|
|
|
* Retrieve the kernel devpath value of the udev device. The path
|
|
|
|
* does not contain the sys mount point, and starts with a '/'.
|
2008-08-27 22:02:41 +02:00
|
|
|
*
|
2008-09-01 18:52:22 +02:00
|
|
|
* Returns: the devpath of the udev device
|
2008-08-27 22:02:41 +02:00
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ const char *udev_device_get_devpath(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
const char *devpath;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
|
|
|
|
|
|
|
r = sd_device_get_devpath(udev_device->device, &devpath);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2015-04-01 13:55:20 +02:00
|
|
|
|
|
|
|
return devpath;
|
2008-08-27 22:02:41 +02:00
|
|
|
}
|
|
|
|
|
2008-09-01 18:52:22 +02:00
|
|
|
/**
|
|
|
|
* udev_device_get_syspath:
|
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
|
|
|
* Retrieve the sys path of the udev device. The path is an
|
|
|
|
* absolute path and starts with the sys mount point.
|
|
|
|
*
|
|
|
|
* Returns: the sys path of the udev device
|
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ const char *udev_device_get_syspath(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
const char *syspath;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
|
|
|
|
|
|
|
r = sd_device_get_syspath(udev_device->device, &syspath);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2015-04-01 13:55:20 +02:00
|
|
|
|
|
|
|
return syspath;
|
2008-09-01 18:52:22 +02:00
|
|
|
}
|
|
|
|
|
2009-06-15 13:22:38 +02:00
|
|
|
/**
|
|
|
|
* udev_device_get_sysname:
|
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
2012-04-20 03:25:36 +02:00
|
|
|
* Get the kernel device name in /sys.
|
|
|
|
*
|
2016-07-10 14:48:23 +02:00
|
|
|
* Returns: the name string of the device
|
2009-06-15 13:22:38 +02:00
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ const char *udev_device_get_sysname(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
const char *sysname;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
|
|
|
|
|
|
|
r = sd_device_get_sysname(udev_device->device, &sysname);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2015-04-01 13:55:20 +02:00
|
|
|
|
|
|
|
return sysname;
|
2008-09-11 17:08:12 +02:00
|
|
|
}
|
|
|
|
|
2009-06-15 13:22:38 +02:00
|
|
|
/**
|
|
|
|
* udev_device_get_sysnum:
|
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
2012-04-20 03:25:36 +02:00
|
|
|
* Get the instance number of the device.
|
|
|
|
*
|
2012-09-04 19:24:16 +02:00
|
|
|
* Returns: the trailing number string of the device name
|
2009-06-15 13:22:38 +02:00
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ const char *udev_device_get_sysnum(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
const char *sysnum;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
|
|
|
|
|
|
|
r = sd_device_get_sysnum(udev_device->device, &sysnum);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r == -ENOENT)
|
2012-01-10 01:34:15 +01:00
|
|
|
return NULL;
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2015-04-01 13:55:20 +02:00
|
|
|
|
|
|
|
return sysnum;
|
2008-10-14 19:53:47 +02:00
|
|
|
}
|
|
|
|
|
2008-08-27 22:02:41 +02:00
|
|
|
/**
|
2008-09-20 09:01:20 +02:00
|
|
|
* udev_device_get_devnode:
|
2008-08-27 22:02:41 +02:00
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
|
|
|
* Retrieve the device node file name belonging to the udev device.
|
2008-08-28 23:05:01 +02:00
|
|
|
* The path is an absolute path, and starts with the device directory.
|
2008-08-27 22:02:41 +02:00
|
|
|
*
|
|
|
|
* Returns: the device node file name of the udev device, or #NULL if no device node exists
|
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ const char *udev_device_get_devnode(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
const char *devnode;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
|
|
|
|
|
|
|
r = sd_device_get_devname(udev_device->device, &devnode);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2015-04-01 13:55:20 +02:00
|
|
|
|
|
|
|
return devnode;
|
2008-08-27 22:02:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-09-28 01:34:55 +02:00
|
|
|
* udev_device_get_devlinks_list_entry:
|
2008-08-27 22:02:41 +02:00
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
2008-09-25 13:20:27 +02:00
|
|
|
* Retrieve the list of device links pointing to the device file of
|
|
|
|
* the udev device. The next list entry can be retrieved with
|
2012-04-13 18:24:39 +02:00
|
|
|
* udev_list_entry_get_next(), which returns #NULL if no more entries exist.
|
2008-09-25 13:20:27 +02:00
|
|
|
* The devlink path can be retrieved from the list entry by
|
2008-09-26 19:44:53 +02:00
|
|
|
* udev_list_entry_get_name(). The path is an absolute path, and starts with
|
2008-09-25 13:20:27 +02:00
|
|
|
* the device directory.
|
2008-08-27 22:02:41 +02:00
|
|
|
*
|
2008-09-25 13:20:27 +02:00
|
|
|
* Returns: the first entry of the device node link list
|
2008-08-27 22:02:41 +02:00
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
2008-08-27 22:02:41 +02:00
|
|
|
|
2015-04-22 19:01:50 +02:00
|
|
|
if (device_get_devlinks_generation(udev_device->device) != udev_device->devlinks_generation ||
|
|
|
|
!udev_device->devlinks_read) {
|
2015-04-01 13:55:20 +02:00
|
|
|
const char *devlink;
|
|
|
|
|
2019-06-12 06:03:19 +02:00
|
|
|
udev_list_cleanup(udev_device->devlinks);
|
2015-04-01 13:55:20 +02:00
|
|
|
|
|
|
|
FOREACH_DEVICE_DEVLINK(udev_device->device, devlink)
|
2019-06-12 06:03:19 +02:00
|
|
|
if (!udev_list_entry_add(udev_device->devlinks, devlink, NULL))
|
2018-11-22 15:46:43 +01:00
|
|
|
return_with_errno(NULL, ENOMEM);
|
2015-04-01 13:55:20 +02:00
|
|
|
|
2015-04-22 19:01:50 +02:00
|
|
|
udev_device->devlinks_read = true;
|
2015-04-01 13:55:20 +02:00
|
|
|
udev_device->devlinks_generation = device_get_devlinks_generation(udev_device->device);
|
|
|
|
}
|
|
|
|
|
2019-06-12 06:03:19 +02:00
|
|
|
return udev_list_get_entry(udev_device->devlinks);
|
2008-10-15 14:21:33 +02:00
|
|
|
}
|
|
|
|
|
2008-08-27 22:02:41 +02:00
|
|
|
/**
|
2015-04-01 13:55:20 +02:00
|
|
|
* udev_device_get_event_properties_entry:
|
2008-08-27 22:02:41 +02:00
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
2008-09-25 13:20:27 +02:00
|
|
|
* Retrieve the list of key/value device properties of the udev
|
2012-04-13 18:24:39 +02:00
|
|
|
* device. The next list entry can be retrieved with udev_list_entry_get_next(),
|
2008-09-25 13:20:27 +02:00
|
|
|
* which returns #NULL if no more entries exist. The property name
|
2012-04-13 18:24:39 +02:00
|
|
|
* can be retrieved from the list entry by udev_list_entry_get_name(),
|
|
|
|
* the property value by udev_list_entry_get_value().
|
2008-08-27 22:02:41 +02:00
|
|
|
*
|
2008-09-25 13:20:27 +02:00
|
|
|
* Returns: the first entry of the property list
|
2008-08-27 22:02:41 +02:00
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
|
|
|
|
2015-04-22 19:01:50 +02:00
|
|
|
if (device_get_properties_generation(udev_device->device) != udev_device->properties_generation ||
|
|
|
|
!udev_device->properties_read) {
|
2015-04-01 13:55:20 +02:00
|
|
|
const char *key, *value;
|
|
|
|
|
2019-06-12 06:03:19 +02:00
|
|
|
udev_list_cleanup(udev_device->properties);
|
2015-04-01 13:55:20 +02:00
|
|
|
|
|
|
|
FOREACH_DEVICE_PROPERTY(udev_device->device, key, value)
|
2019-06-12 06:03:19 +02:00
|
|
|
if (!udev_list_entry_add(udev_device->properties, key, value))
|
2018-11-22 15:46:43 +01:00
|
|
|
return_with_errno(NULL, ENOMEM);
|
2015-04-01 13:55:20 +02:00
|
|
|
|
2015-04-22 19:01:50 +02:00
|
|
|
udev_device->properties_read = true;
|
2015-04-01 13:55:20 +02:00
|
|
|
udev_device->properties_generation = device_get_properties_generation(udev_device->device);
|
2012-01-10 01:34:15 +01:00
|
|
|
}
|
2015-04-01 13:55:20 +02:00
|
|
|
|
2019-06-12 06:03:19 +02:00
|
|
|
return udev_list_get_entry(udev_device->properties);
|
2008-08-27 22:02:41 +02:00
|
|
|
}
|
2008-09-01 18:52:22 +02:00
|
|
|
|
2009-06-15 13:22:38 +02:00
|
|
|
/**
|
|
|
|
* udev_device_get_action:
|
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
|
|
|
* This is only valid if the device was received through a monitor. Devices read from
|
2017-09-05 17:14:58 +02:00
|
|
|
* sys do not have an action string. Usual actions are: add, remove, change, move,
|
|
|
|
* online, offline.
|
2009-06-15 13:22:38 +02:00
|
|
|
*
|
|
|
|
* Returns: the kernel action value, or #NULL if there is no action value available.
|
|
|
|
**/
|
2015-04-01 13:55:20 +02:00
|
|
|
_public_ const char *udev_device_get_action(struct udev_device *udev_device) {
|
2019-03-09 03:07:26 +01:00
|
|
|
DeviceAction action;
|
2015-04-01 13:55:20 +02:00
|
|
|
|
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
|
|
|
|
2019-03-09 03:07:26 +01:00
|
|
|
if (device_get_action(udev_device->device, &action) < 0)
|
2012-01-10 01:34:15 +01:00
|
|
|
return NULL;
|
2015-04-01 13:55:20 +02:00
|
|
|
|
2019-03-09 03:07:26 +01:00
|
|
|
return device_action_to_string(action);
|
2008-09-09 14:06:20 +02:00
|
|
|
}
|
|
|
|
|
2010-12-15 08:57:46 +01:00
|
|
|
/**
|
|
|
|
* udev_device_get_usec_since_initialized:
|
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
|
|
|
* Return the number of microseconds passed since udev set up the
|
|
|
|
* device for the first time.
|
|
|
|
*
|
|
|
|
* This is only implemented for devices with need to store properties
|
|
|
|
* in the udev database. All other devices return 0 here.
|
|
|
|
*
|
|
|
|
* Returns: the number of microseconds since the device was first seen.
|
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
usec_t ts;
|
|
|
|
int r;
|
2010-12-15 08:57:46 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return(udev_device, -EINVAL);
|
|
|
|
|
|
|
|
r = sd_device_get_usec_since_initialized(udev_device->device, &ts);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(0, r);
|
2010-12-15 08:57:46 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
return ts;
|
2010-12-15 08:57:46 +01:00
|
|
|
}
|
|
|
|
|
2009-06-15 13:22:38 +02:00
|
|
|
/**
|
|
|
|
* udev_device_get_sysattr_value:
|
|
|
|
* @udev_device: udev device
|
|
|
|
* @sysattr: attribute name
|
|
|
|
*
|
2009-07-02 22:56:19 +02:00
|
|
|
* The retrieved value is cached in the device. Repeated calls will return the same
|
2009-06-15 13:22:38 +02:00
|
|
|
* value and not open the attribute again.
|
|
|
|
*
|
|
|
|
* Returns: the content of a sys attribute file, or #NULL if there is no sys attribute value.
|
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) {
|
2015-04-01 13:55:20 +02:00
|
|
|
const char *value;
|
|
|
|
int r;
|
2012-01-10 01:34:15 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
2012-01-10 01:34:15 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
r = sd_device_get_sysattr_value(udev_device->device, sysattr, &value);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(NULL, r);
|
2012-01-10 01:34:15 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
return value;
|
2008-09-13 21:09:28 +02:00
|
|
|
}
|
2008-10-14 19:53:47 +02:00
|
|
|
|
2013-03-11 12:49:27 +01:00
|
|
|
/**
|
|
|
|
* udev_device_set_sysattr_value:
|
|
|
|
* @udev_device: udev device
|
|
|
|
* @sysattr: attribute name
|
|
|
|
* @value: new value to be set
|
|
|
|
*
|
|
|
|
* Update the contents of the sys attribute and the cached value of the device.
|
|
|
|
*
|
|
|
|
* Returns: Negative error code on failure or 0 on success.
|
|
|
|
**/
|
2018-09-11 05:42:18 +02:00
|
|
|
_public_ int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, const char *value) {
|
2015-04-01 13:55:20 +02:00
|
|
|
int r;
|
2011-03-04 17:06:41 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return(udev_device, -EINVAL);
|
2011-03-04 17:06:41 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
r = sd_device_set_sysattr_value(udev_device->device, sysattr, value);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2011-03-04 17:06:41 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
return 0;
|
2011-03-04 17:06:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* udev_device_get_sysattr_list_entry:
|
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
|
|
|
* Retrieve the list of available sysattrs, with value being empty;
|
2011-03-04 23:00:52 +01:00
|
|
|
* This just return all available sysfs attributes for a particular
|
|
|
|
* device without reading their values.
|
2011-03-04 17:06:41 +01:00
|
|
|
*
|
|
|
|
* Returns: the first entry of the property list
|
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
2011-03-04 17:06:41 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
if (!udev_device->sysattrs_read) {
|
|
|
|
const char *sysattr;
|
2011-03-04 17:06:41 +01:00
|
|
|
|
2019-06-12 06:03:19 +02:00
|
|
|
udev_list_cleanup(udev_device->sysattrs);
|
2008-09-01 18:52:22 +02:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
FOREACH_DEVICE_SYSATTR(udev_device->device, sysattr)
|
2019-06-12 06:03:19 +02:00
|
|
|
if (!udev_list_entry_add(udev_device->sysattrs, sysattr, NULL))
|
2018-11-22 15:46:43 +01:00
|
|
|
return_with_errno(NULL, ENOMEM);
|
2008-09-01 18:52:22 +02:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
udev_device->sysattrs_read = true;
|
2012-01-10 01:34:15 +01:00
|
|
|
}
|
2015-04-01 13:55:20 +02:00
|
|
|
|
2019-06-12 06:03:19 +02:00
|
|
|
return udev_list_get_entry(udev_device->sysattrs);
|
2010-12-10 01:13:35 +01:00
|
|
|
}
|
|
|
|
|
2010-12-14 14:18:32 +01:00
|
|
|
/**
|
|
|
|
* udev_device_get_is_initialized:
|
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
|
|
|
* Check if udev has already handled the device and has set up
|
|
|
|
* device node permissions and context, or has renamed a network
|
|
|
|
* device.
|
|
|
|
*
|
2010-12-15 08:57:46 +01:00
|
|
|
* This is only implemented for devices with a device node
|
2010-12-14 14:18:32 +01:00
|
|
|
* or network interfaces. All other devices return 1 here.
|
|
|
|
*
|
|
|
|
* Returns: 1 if the device is set up. 0 otherwise.
|
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ int udev_device_get_is_initialized(struct udev_device *udev_device) {
|
2018-10-29 09:32:21 +01:00
|
|
|
int r;
|
2010-12-14 14:18:32 +01:00
|
|
|
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return(udev_device, -EINVAL);
|
2010-12-14 14:18:32 +01:00
|
|
|
|
2018-10-29 09:32:21 +01:00
|
|
|
r = sd_device_get_is_initialized(udev_device->device);
|
2018-11-21 06:06:41 +01:00
|
|
|
if (r < 0)
|
|
|
|
return_with_errno(0, r);
|
2014-09-11 13:25:21 +02:00
|
|
|
|
2018-10-29 09:32:21 +01:00
|
|
|
return r;
|
2010-04-22 18:12:36 +02:00
|
|
|
}
|
|
|
|
|
2010-05-07 23:04:42 +02:00
|
|
|
/**
|
|
|
|
* udev_device_get_tags_list_entry:
|
|
|
|
* @udev_device: udev device
|
|
|
|
*
|
|
|
|
* Retrieve the list of tags attached to the udev device. The next
|
2012-04-13 18:24:39 +02:00
|
|
|
* list entry can be retrieved with udev_list_entry_get_next(),
|
2010-05-07 23:04:42 +02:00
|
|
|
* which returns #NULL if no more entries exist. The tag string
|
2012-04-13 18:24:39 +02:00
|
|
|
* can be retrieved from the list entry by udev_list_entry_get_name().
|
2010-05-07 23:04:42 +02:00
|
|
|
*
|
|
|
|
* Returns: the first entry of the tag list
|
|
|
|
**/
|
2018-08-24 07:32:05 +02:00
|
|
|
_public_ struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device) {
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
|
|
|
|
2018-12-13 18:08:45 +01:00
|
|
|
if (device_get_tags_generation(udev_device->device) != udev_device->all_tags_generation ||
|
|
|
|
!udev_device->all_tags_read) {
|
2015-04-01 13:55:20 +02:00
|
|
|
const char *tag;
|
|
|
|
|
2018-12-13 18:08:45 +01:00
|
|
|
udev_list_cleanup(udev_device->all_tags);
|
2015-04-01 13:55:20 +02:00
|
|
|
|
|
|
|
FOREACH_DEVICE_TAG(udev_device->device, tag)
|
2018-12-13 18:08:45 +01:00
|
|
|
if (!udev_list_entry_add(udev_device->all_tags, tag, NULL))
|
|
|
|
return_with_errno(NULL, ENOMEM);
|
|
|
|
|
|
|
|
udev_device->all_tags_read = true;
|
|
|
|
udev_device->all_tags_generation = device_get_tags_generation(udev_device->device);
|
|
|
|
}
|
|
|
|
|
|
|
|
return udev_list_get_entry(udev_device->all_tags);
|
|
|
|
}
|
|
|
|
|
|
|
|
_public_ struct udev_list_entry *udev_device_get_current_tags_list_entry(struct udev_device *udev_device) {
|
|
|
|
assert_return_errno(udev_device, NULL, EINVAL);
|
|
|
|
|
|
|
|
if (device_get_tags_generation(udev_device->device) != udev_device->current_tags_generation ||
|
|
|
|
!udev_device->current_tags_read) {
|
|
|
|
const char *tag;
|
|
|
|
|
|
|
|
udev_list_cleanup(udev_device->current_tags);
|
|
|
|
|
|
|
|
FOREACH_DEVICE_CURRENT_TAG(udev_device->device, tag)
|
|
|
|
if (!udev_list_entry_add(udev_device->current_tags, tag, NULL))
|
2018-11-22 15:46:43 +01:00
|
|
|
return_with_errno(NULL, ENOMEM);
|
2015-04-01 13:55:20 +02:00
|
|
|
|
2018-12-13 18:08:45 +01:00
|
|
|
udev_device->current_tags_read = true;
|
|
|
|
udev_device->current_tags_generation = device_get_tags_generation(udev_device->device);
|
2015-04-01 13:55:20 +02:00
|
|
|
}
|
|
|
|
|
2018-12-13 18:08:45 +01:00
|
|
|
return udev_list_get_entry(udev_device->current_tags);
|
2010-04-22 18:12:36 +02:00
|
|
|
}
|
|
|
|
|
2012-04-20 03:25:36 +02:00
|
|
|
/**
|
|
|
|
* udev_device_has_tag:
|
|
|
|
* @udev_device: udev device
|
|
|
|
* @tag: tag name
|
|
|
|
*
|
|
|
|
* Check if a given device has a certain tag associated.
|
|
|
|
*
|
|
|
|
* Returns: 1 if the tag is found. 0 otherwise.
|
|
|
|
**/
|
2018-08-24 07:31:41 +02:00
|
|
|
_public_ int udev_device_has_tag(struct udev_device *udev_device, const char *tag) {
|
2015-04-01 13:55:20 +02:00
|
|
|
assert_return(udev_device, 0);
|
2015-01-26 14:12:45 +01:00
|
|
|
|
2018-08-24 07:31:41 +02:00
|
|
|
return sd_device_has_tag(udev_device->device, tag) > 0;
|
2015-03-06 18:30:09 +01:00
|
|
|
}
|
2019-06-12 08:15:06 +02:00
|
|
|
|
2018-12-13 18:08:45 +01:00
|
|
|
_public_ int udev_device_has_current_tag(struct udev_device *udev_device, const char *tag) {
|
|
|
|
assert_return(udev_device, 0);
|
|
|
|
|
|
|
|
return sd_device_has_current_tag(udev_device->device, tag) > 0;
|
|
|
|
}
|
|
|
|
|
2019-06-12 08:15:06 +02:00
|
|
|
sd_device *udev_device_get_sd_device(struct udev_device *udev_device) {
|
|
|
|
assert(udev_device);
|
|
|
|
|
|
|
|
return udev_device->device;
|
|
|
|
}
|