#include <ctype.h>
#include <net/if.h>
+#include <sys/ioctl.h>
#include <sys/types.h>
#include "sd-device.h"
#include "set.h"
#include "socket-util.h"
#include "stat-util.h"
+#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "strxcpyx.h"
#include "util.h"
int device_new_aux(sd_device **ret) {
- sd_device *device = NULL;
+ sd_device *device;
assert(ret);
*device = (sd_device) {
.n_ref = 1,
.watch_handle = -1,
- .ifindex = -1,
.devmode = (mode_t) -1,
.devuid = (uid_t) -1,
.devgid = (gid_t) -1,
+ .action = _DEVICE_ACTION_INVALID,
};
*ret = device;
assert(_syspath);
/* must be a subdirectory of /sys */
- if (!path_startswith(_syspath, "/sys/")) {
- log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath);
- return -EINVAL;
- }
+ if (!path_startswith(_syspath, "/sys/"))
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+ "sd-device: Syspath '%s' is not a subdirectory of /sys",
+ _syspath);
if (verify) {
r = chase_symlinks(_syspath, NULL, 0, &syspath);
if (r == -ENOENT)
return -ENODEV; /* the device does not exist (any more?) */
if (r < 0)
- return log_debug_errno(r, "sd-device: could not get target of '%s': %m", _syspath);
+ return log_debug_errno(r, "sd-device: Failed to get target of '%s': %m", _syspath);
if (!path_startswith(syspath, "/sys")) {
_cleanup_free_ char *real_sys = NULL, *new_syspath = NULL;
/* /sys is a symlink to somewhere sysfs is mounted on? In that case, we convert the path to real sysfs to "/sys". */
r = chase_symlinks("/sys", NULL, 0, &real_sys);
if (r < 0)
- return log_debug_errno(r, "sd-device: could not chase symlink /sys: %m");
+ return log_debug_errno(r, "sd-device: Failed to chase symlink /sys: %m");
p = path_startswith(syspath, real_sys);
- if (!p) {
- log_debug("sd-device: canonicalized path '%s' does not starts with sysfs mount point '%s'", syspath, real_sys);
- return -ENODEV;
- }
+ if (!p)
+ return log_debug_errno(SYNTHETIC_ERRNO(ENODEV),
+ "sd-device: Canonicalized path '%s' does not starts with sysfs mount point '%s'",
+ syspath, real_sys);
- new_syspath = strjoin("/sys/", p);
+ new_syspath = path_join("/sys", p);
if (!new_syspath)
- return log_oom();
+ return -ENOMEM;
free_and_replace(syspath, new_syspath);
path_simplify(syspath, false);
return r;
free_and_replace(device->syspath, syspath);
-
device->devpath = devpath;
-
return 0;
}
return r;
*ret = TAKE_PTR(device);
-
return 0;
}
assert_return(IN_SET(type, 'b', 'c'), -EINVAL);
/* use /sys/dev/{block,char}/<maj>:<min> link */
- snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
+ xsprintf(id, "%u:%u", major(devnum), minor(devnum));
syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
if (device->uevent_loaded || device->sealed)
return 0;
- device->uevent_loaded = true;
-
r = sd_device_get_syspath(device, &syspath);
if (r < 0)
return r;
path = strjoina(syspath, "/uevent");
r = read_full_file(path, &uevent, &uevent_len);
- if (r == -EACCES)
+ if (r == -EACCES) {
/* empty uevent files may be write-only */
+ device->uevent_loaded = true;
return 0;
- else if (r == -ENOENT)
+ }
+ if (r == -ENOENT)
/* some devices may not have uevent files, see set_syspath() */
return 0;
- else if (r < 0)
- return log_debug_errno(r, "sd-device: failed to read uevent file '%s': %m", path);
+ if (r < 0)
+ return log_device_debug_errno(device, r, "sd-device: Failed to read uevent file '%s': %m", path);
+
+ device->uevent_loaded = true;
for (i = 0; i < uevent_len; i++)
switch (state) {
state = PRE_VALUE;
} else if (strchr(NEWLINE, uevent[i])) {
uevent[i] = '\0';
- log_debug("sd-device: ignoring invalid uevent line '%s'", key);
+ log_device_debug(device, "sd-device: Invalid uevent line '%s', ignoring", key);
state = PRE_KEY;
}
r = handle_uevent_line(device, key, value, &major, &minor);
if (r < 0)
- log_debug_errno(r, "sd-device: failed to handle uevent entry '%s=%s': %m", key, value);
+ log_device_debug_errno(device, r, "sd-device: Failed to handle uevent entry '%s=%s', ignoring: %m", key, value);
state = PRE_KEY;
}
break;
default:
- assert_not_reached("invalid state when parsing uevent file");
+ assert_not_reached("Invalid state when parsing uevent file");
}
if (major) {
r = device_set_devnum(device, major, minor);
if (r < 0)
- log_debug_errno(r, "sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %m", major, minor, path);
+ log_device_debug_errno(device, r, "sd-device: Failed to set 'MAJOR=%s' or 'MINOR=%s' from '%s', ignoring: %m", major, minor, path);
}
return 0;
int r;
assert_return(device, -EINVAL);
- assert_return(ifindex, -EINVAL);
r = device_read_uevent_file(device);
if (r < 0)
return r;
- if (device->ifindex < 0)
+ if (device->ifindex <= 0)
return -ENOENT;
- *ifindex = device->ifindex;
+ if (ifindex)
+ *ifindex = device->ifindex;
return 0;
}
switch (id[0]) {
case 'b':
- case 'c':
- {
- char type;
- int maj, min;
+ case 'c': {
+ dev_t devt;
- r = sscanf(id, "%c%i:%i", &type, &maj, &min);
- if (r != 3)
+ if (isempty(id))
return -EINVAL;
- return sd_device_new_from_devnum(ret, type, makedev(maj, min));
+ r = parse_dev(id + 1, &devt);
+ if (r < 0)
+ return r;
+
+ return sd_device_new_from_devnum(ret, id[0], devt);
}
- case 'n':
- {
+
+ case 'n': {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
_cleanup_close_ int sk = -1;
struct ifreq ifr = {};
return -ENODEV;
*ret = TAKE_PTR(device);
-
return 0;
}
- case '+':
- {
+
+ case '+': {
char subsys[PATH_MAX];
char *sysname;
return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
}
+
default:
return -EINVAL;
}
return -ENOENT;
*ret = child->parent;
-
return 0;
}
if (r < 0)
return r;
- free_and_replace(device->subsystem, subsystem);
-
device->subsystem_set = true;
-
- return 0;
+ return free_and_replace(device->subsystem, subsystem);
}
static int device_set_drivers_subsystem(sd_device *device, const char *_subsystem) {
if (r < 0)
return r;
- free_and_replace(device->driver_subsystem, subsystem);
-
- return 0;
+ return free_and_replace(device->driver_subsystem, subsystem);
}
_public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
else if (path_startswith(device->devpath, "/module/"))
r = device_set_subsystem(device, "module");
else if (!(drivers = strstr(syspath, "/drivers/")) &&
- (path_startswith(device->devpath, "/subsystem/") ||
- path_startswith(device->devpath, "/class/") ||
- path_startswith(device->devpath, "/bus/")))
+ PATH_STARTSWITH_SET(device->devpath, "/subsystem/",
+ "/class/",
+ "/bus/"))
r = device_set_subsystem(device, "subsystem");
if (r < 0 && r != -ENOENT)
- return log_debug_errno(r, "sd-device: could not set subsystem for %s: %m", device->devpath);
+ return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem for %s: %m", device->devpath);
device->subsystem_set = true;
} else if (!device->driver_subsystem_set)
r = device_set_drivers_subsystem(device, subsys + 1);
}
if (r < 0 && r != -ENOENT)
- return log_debug_errno(r, "sd-device: could not set subsystem for driver %s: %m", device->devpath);
+ return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem for driver %s: %m", device->devpath);
}
device->driver_subsystem_set = true;
return -ENOENT;
*ret = device->subsystem;
-
return 0;
}
return r;
*ret = parent;
-
return 0;
}
int r;
assert_return(device, -EINVAL);
- assert_return(devnum, -EINVAL);
r = device_read_uevent_file(device);
if (r < 0)
if (major(device->devnum) <= 0)
return -ENOENT;
- *devnum = device->devnum;
+ if (devnum)
+ *devnum = device->devnum;
return 0;
}
if (r < 0)
return r;
- free_and_replace(device->driver, driver);
-
device->driver_set = true;
-
- return 0;
+ return free_and_replace(device->driver, driver);
}
_public_ int sd_device_get_driver(sd_device *device, const char **ret) {
if (r >= 0) {
r = device_set_driver(device, driver);
if (r < 0)
- return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
+ return log_device_debug_errno(device, r, "sd-device: Failed to set driver for %s: %m", device->devpath);
} else if (r == -ENOENT)
device->driver_set = true;
else
- return log_debug_errno(r, "sd-device: could not set driver for %s: %m", device->devpath);
+ return log_device_debug_errno(device, r, "sd-device: Failed to set driver for %s: %m", device->devpath);
}
if (!device->driver)
return -ENOENT;
*ret = device->driver;
-
return 0;
}
assert(device->devpath[0] == '/');
*devpath = device->devpath;
-
return 0;
}
assert(path_startswith(device->devname, "/dev/"));
*devname = device->devname;
-
return 0;
}
const char *pos;
size_t len = 0;
+ if (!device->devpath)
+ return -EINVAL;
+
pos = strrchr(device->devpath, '/');
if (!pos)
return -EINVAL;
if (len == 0)
sysnum = NULL;
- free_and_replace(device->sysname, sysname);
-
- device->sysnum = sysnum;
-
device->sysname_set = true;
-
- return 0;
+ device->sysnum = sysnum;
+ return free_and_replace(device->sysname, sysname);
}
_public_ int sd_device_get_sysname(sd_device *device, const char **ret) {
assert_return(device->sysname, -ENOENT);
*ret = device->sysname;
-
return 0;
}
return -ENOENT;
*ret = device->sysnum;
-
return 0;
}
static int device_add_property_internal_from_string(sd_device *device, const char *str) {
_cleanup_free_ char *key = NULL;
char *value;
+ int r;
assert(device);
assert(str);
if (isempty(++value))
value = NULL;
- return device_add_property_internal(device, key, value);
+ /* Add the property to both sd_device::properties and sd_device::properties_db,
+ * as this is called by only handle_db_line(). */
+ r = device_add_property_aux(device, key, value, false);
+ if (r < 0)
+ return r;
+
+ return device_add_property_aux(device, key, value, true);
}
-int device_set_usec_initialized(sd_device *device, const char *initialized) {
- uint64_t usec_initialized;
+int device_set_usec_initialized(sd_device *device, usec_t when) {
+ char s[DECIMAL_STR_MAX(usec_t)];
int r;
assert(device);
- assert(initialized);
- r = safe_atou64(initialized, &usec_initialized);
- if (r < 0)
- return r;
+ xsprintf(s, USEC_FMT, when);
- r = device_add_property_internal(device, "USEC_INITIALIZED", initialized);
+ r = device_add_property_internal(device, "USEC_INITIALIZED", s);
if (r < 0)
return r;
- device->usec_initialized = usec_initialized;
-
+ device->usec_initialized = when;
return 0;
}
return r;
break;
- case 'I':
- r = device_set_usec_initialized(device, value);
+ case 'I': {
+ usec_t t;
+
+ r = safe_atou64(value, &t);
+ if (r < 0)
+ return r;
+
+ r = device_set_usec_initialized(device, t);
if (r < 0)
return r;
break;
+ }
case 'L':
r = safe_atoi(value, &device->devlink_priority);
if (r < 0)
break;
default:
- log_debug("device db: unknown key '%c'", key);
+ log_device_debug(device, "sd-device: Unknown key '%c' in device db, ignoring", key);
}
return 0;
major(devnum), minor(devnum));
if (r < 0)
return -ENOMEM;
- } else if (sd_device_get_ifindex(device, &ifindex) >= 0 && ifindex > 0) {
+ } else if (sd_device_get_ifindex(device, &ifindex) >= 0) {
/* use netdev ifindex — n3 */
- r = asprintf(&id, "n%u", ifindex);
+ r = asprintf(&id, "n%u", (unsigned) ifindex);
if (r < 0)
return -ENOMEM;
} else {
}
*ret = device->id_filename;
-
return 0;
}
-int device_read_db_aux(sd_device *device, bool force) {
+int device_read_db_internal_filename(sd_device *device, const char *filename) {
_cleanup_free_ char *db = NULL;
- char *path;
- const char *id, *value;
+ const char *value;
+ size_t db_len, i;
char key;
- size_t db_len;
- unsigned i;
int r;
enum {
INVALID_LINE,
} state = PRE_KEY;
- if (device->db_loaded || (!force && device->sealed))
- return 0;
-
- device->db_loaded = true;
-
- r = device_get_id_filename(device, &id);
- if (r < 0)
- return r;
-
- path = strjoina("/run/udev/data/", id);
+ assert(device);
+ assert(filename);
- r = read_full_file(path, &db, &db_len);
+ r = read_full_file(filename, &db, &db_len);
if (r < 0) {
if (r == -ENOENT)
return 0;
- else
- return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path);
+
+ return log_device_debug_errno(device, r, "sd-device: Failed to read db '%s': %m", filename);
}
/* devices with a database entry are initialized */
device->is_initialized = true;
+ device->db_loaded = true;
+
for (i = 0; i < db_len; i++) {
switch (state) {
case PRE_KEY:
break;
case KEY:
if (db[i] != ':') {
- log_debug("sd-device: ignoring invalid db entry with key '%c'", key);
+ log_device_debug(device, "sd-device: Invalid db entry with key '%c', ignoring", key);
state = INVALID_LINE;
} else {
db[i] = '\0';
r = handle_db_line(device, key, value);
if (r < 0)
- log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value);
+ log_device_debug_errno(device, r, "sd-device: Failed to handle db entry '%c:%s', ignoring: %m", key, value);
state = PRE_KEY;
}
break;
default:
- assert_not_reached("invalid state when parsing db");
+ return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL), "sd-device: invalid db syntax.");
}
}
return 0;
}
-static int device_read_db(sd_device *device) {
- return device_read_db_aux(device, false);
+int device_read_db_internal(sd_device *device, bool force) {
+ const char *id, *path;
+ int r;
+
+ assert(device);
+
+ if (device->db_loaded || (!force && device->sealed))
+ return 0;
+
+ r = device_get_id_filename(device, &id);
+ if (r < 0)
+ return r;
+
+ path = strjoina("/run/udev/data/", id);
+
+ return device_read_db_internal_filename(device, path);
}
-_public_ int sd_device_get_is_initialized(sd_device *device, int *initialized) {
+_public_ int sd_device_get_is_initialized(sd_device *device) {
int r;
assert_return(device, -EINVAL);
- assert_return(initialized, -EINVAL);
r = device_read_db(device);
if (r < 0)
return r;
- *initialized = device->is_initialized;
-
- return 0;
+ return device->is_initialized;
}
_public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec) {
return -EIO;
*usec = now_ts - device->usec_initialized;
-
return 0;
}
return v;
}
-static int device_properties_prepare(sd_device *device) {
+int device_properties_prepare(sd_device *device) {
int r;
assert(device);
if (_value)
*_value = value;
-
return key;
}
if (_value)
*_value = value;
-
return key;
}
assert_return(device, -EINVAL);
assert_return(key, -EINVAL);
- assert_return(_value, -EINVAL);
r = device_properties_prepare(device);
if (r < 0)
if (!value)
return -ENOENT;
- *_value = value;
-
+ if (_value)
+ *_value = value;
return 0;
}
r = hashmap_put(device->sysattr_values, key, value);
if (r < 0)
return r;
-
- key = NULL;
+ TAKE_PTR(key);
return 0;
}
if (_value)
*_value = value;
-
return 0;
}
static void device_remove_sysattr_value(sd_device *device, const char *_key) {
_cleanup_free_ char *key = NULL;
- _cleanup_free_ char *value = NULL;
assert(device);
assert(_key);
- value = hashmap_remove2(device->sysattr_values, _key, (void **) &key);
-
- return;
+ free(hashmap_remove2(device->sysattr_values, _key, (void **) &key));
}
/* set the attribute and save it in the cache. If a NULL value is passed the
* attribute is cleared from the cache */
_public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *_value) {
- _cleanup_close_ int fd = -1;
_cleanup_free_ char *value = NULL;
- const char *syspath;
- char *path;
- size_t len = 0;
- ssize_t size;
+ const char *syspath, *path;
+ size_t len;
int r;
assert_return(device, -EINVAL);
if (!_value) {
device_remove_sysattr_value(device, sysattr);
-
return 0;
}
path = strjoina(syspath, "/", sysattr);
- fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW);
- if (fd < 0) {
- if (errno == ELOOP)
- return -EINVAL;
- if (errno == EISDIR)
- return -EISDIR;
-
- value = strdup("");
- if (!value)
- return -ENOMEM;
-
- r = device_add_sysattr_value(device, sysattr, value);
- if (r < 0)
- return r;
- value = NULL;
-
- return -ENXIO;
- }
-
len = strlen(_value);
/* drop trailing newlines */
if (!value)
return -ENOMEM;
- size = write(fd, value, len);
- if (size < 0)
- return -errno;
+ r = write_string_file(path, value, WRITE_STRING_FILE_DISABLE_BUFFER | WRITE_STRING_FILE_NOFOLLOW);
+ if (r < 0) {
+ if (r == -ELOOP)
+ return -EINVAL;
+ if (r == -EISDIR)
+ return r;
- if ((size_t)size != len)
- return -EIO;
+ r = free_and_strdup(&value, "");
+ if (r < 0)
+ return r;
+
+ r = device_add_sysattr_value(device, sysattr, value);
+ if (r < 0)
+ return r;
+ TAKE_PTR(value);
+
+ return -ENXIO;
+ }
r = device_add_sysattr_value(device, sysattr, value);
if (r < 0)
return r;
- value = NULL;
+ TAKE_PTR(value);
return 0;
}