merge: branch 'systemd' into ff/fix_systemd

Disabled unused code and adapted Makefile and meson files.
This commit is contained in:
Fernando Fernandez Mancera
2024-03-04 12:29:57 +01:00
17 changed files with 4163 additions and 5 deletions

View File

@@ -2371,7 +2371,10 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
src/libnm-systemd-shared/src/basic/btrfs.c \
src/libnm-systemd-shared/src/basic/btrfs.h \
src/libnm-systemd-shared/src/basic/cgroup-util.h \
src/libnm-systemd-shared/src/basic/chase.h \
src/libnm-systemd-shared/src/basic/constants.h \
src/libnm-systemd-shared/src/basic/devnum-util.c \
src/libnm-systemd-shared/src/basic/devnum-util.h \
src/libnm-systemd-shared/src/basic/dns-def.h \
src/libnm-systemd-shared/src/basic/env-file.c \
src/libnm-systemd-shared/src/basic/env-file.h \
@@ -2538,7 +2541,11 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
src/libnm-systemd-core/src/libsystemd-network/network-common.h \
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c \
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c \
src/libnm-systemd-core/src/libsystemd/sd-device/device-internal.h \
src/libnm-systemd-core/src/libsystemd/sd-device/device-private.c \
src/libnm-systemd-core/src/libsystemd/sd-device/device-private.h \
src/libnm-systemd-core/src/libsystemd/sd-device/device-util.h \
src/libnm-systemd-core/src/libsystemd/sd-device/sd-device.c \
src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h \
src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c \
src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h \

View File

@@ -10,6 +10,8 @@ libnm_systemd_core = static_library(
'src/libsystemd-network/sd-dhcp-duid.c',
'src/libsystemd-network/sd-dhcp6-client.c',
'src/libsystemd-network/sd-dhcp6-lease.c',
'src/libsystemd/sd-device/device-private.c',
'src/libsystemd/sd-device/sd-device.c',
'src/libsystemd/sd-event/event-util.c',
'src/libsystemd/sd-event/sd-event.c',
'src/libsystemd/sd-id128/id128-util.c',

View File

@@ -3,7 +3,9 @@
#include "nm-sd-adapt-core.h"
#include <linux/if.h>
#ifdef __GLIBC__
#include <linux/if_arp.h>
#endif
#include "arphrd-util.h"
#include "device-util.h"

View File

@@ -7,7 +7,9 @@
#include <errno.h>
#include <sys/ioctl.h>
#ifdef __GLIBC__
#include <linux/if_arp.h>
#endif
#include <linux/if_infiniband.h>
#include "sd-dhcp6-client.h"

View File

@@ -0,0 +1,117 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-device.h"
#include "device-private.h"
#include "hashmap.h"
#include "set.h"
#include "time-util.h"
#define LATEST_UDEV_DATABASE_VERSION 1
struct sd_device {
unsigned n_ref;
/* The database version indicates the supported features by the udev database.
* This is saved and parsed in V field.
*
* 0: None of the following features are supported (systemd version <= 246).
* 1: The current tags (Q) and the database version (V) features are implemented (>= 247).
*/
unsigned database_version;
sd_device *parent;
OrderedHashmap *properties;
Iterator properties_iterator;
uint64_t properties_generation; /* changes whenever the properties are changed */
uint64_t properties_iterator_generation; /* generation when iteration was started */
/* the subset of the properties that should be written to the db */
OrderedHashmap *properties_db;
Hashmap *sysattr_values; /* cached sysattr values */
Set *sysattrs; /* names of sysattrs */
Iterator sysattrs_iterator;
Set *all_tags, *current_tags;
Iterator all_tags_iterator, current_tags_iterator;
uint64_t all_tags_iterator_generation, current_tags_iterator_generation; /* generation when iteration was started */
uint64_t tags_generation; /* changes whenever the tags are changed */
Set *devlinks;
Iterator devlinks_iterator;
uint64_t devlinks_generation; /* changes whenever the devlinks are changed */
uint64_t devlinks_iterator_generation; /* generation when iteration was started */
int devlink_priority;
Hashmap *children;
Iterator children_iterator;
bool children_enumerated;
int ifindex;
char *devtype;
char *devname;
dev_t devnum;
char **properties_strv; /* the properties hashmap as a strv */
char *properties_nulstr; /* the same as a nulstr */
size_t properties_nulstr_len;
char *syspath;
const char *devpath;
const char *sysnum;
char *sysname;
char *subsystem;
char *driver_subsystem; /* only set for the 'drivers' subsystem */
char *driver;
char *device_id;
usec_t usec_initialized;
mode_t devmode;
uid_t devuid;
gid_t devgid;
uint64_t diskseq; /* Block device sequence number, monothonically incremented by the kernel on create/attach */
/* only set when device is passed through netlink */
sd_device_action_t action;
uint64_t seqnum;
bool parent_set:1; /* no need to try to reload parent */
bool sysattrs_read:1; /* don't try to re-read sysattrs once read */
bool property_tags_outdated:1; /* need to update TAGS= or CURRENT_TAGS= property */
bool property_devlinks_outdated:1; /* need to update DEVLINKS= property */
bool properties_buf_outdated:1; /* need to reread hashmap */
bool subsystem_set:1; /* don't reread subsystem */
bool driver_set:1; /* don't reread driver */
bool uevent_loaded:1; /* don't reread uevent */
bool db_loaded; /* don't reread db */
bool is_initialized:1;
bool sealed:1; /* don't read more information from uevent/db */
bool db_persist:1; /* don't clean up the db when switching from initrd to real root */
};
int device_new_aux(sd_device **ret);
int device_add_property_aux(sd_device *device, const char *key, const char *value, bool db);
static inline int device_add_property_internal(sd_device *device, const char *key, const char *value) {
return device_add_property_aux(device, key, value, false);
}
int device_set_syspath(sd_device *device, const char *_syspath, bool verify);
int device_set_ifindex(sd_device *device, const char *ifindex);
int device_set_devmode(sd_device *device, const char *devmode);
int device_set_devname(sd_device *device, const char *devname);
int device_set_devtype(sd_device *device, const char *devtype);
int device_set_devnum(sd_device *device, const char *major, const char *minor);
int device_set_subsystem(sd_device *device, const char *subsystem);
int device_set_diskseq(sd_device *device, const char *str);
int device_set_drivers_subsystem(sd_device *device);
int device_set_driver(sd_device *device, const char *driver);
int device_set_usec_initialized(sd_device *device, usec_t when);

View File

@@ -0,0 +1,962 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "nm-sd-adapt-core.h"
#include <ctype.h>
#include <net/if.h>
#include <sys/types.h>
#include "sd-device.h"
#include "alloc-util.h"
#include "device-internal.h"
#include "device-private.h"
#include "device-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "hashmap.h"
#include "macro.h"
#include "mkdir.h"
#include "nulstr-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "set.h"
#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "strxcpyx.h"
#include "tmpfile-util.h"
#include "user-util.h"
#if 0 /* NM_IGNORED */
int device_add_property(sd_device *device, const char *key, const char *value) {
int r;
assert(device);
assert(key);
r = device_add_property_aux(device, key, value, false);
if (r < 0)
return r;
if (key[0] != '.') {
r = device_add_property_aux(device, key, value, true);
if (r < 0)
return r;
}
return 0;
}
int device_add_propertyf(sd_device *device, const char *key, const char *format, ...) {
_cleanup_free_ char *value = NULL;
va_list ap;
int r;
assert(device);
assert(key);
if (!format)
return device_add_property(device, key, NULL);
va_start(ap, format);
r = vasprintf(&value, format, ap);
va_end(ap);
if (r < 0)
return -ENOMEM;
return device_add_property(device, key, value);
}
void device_set_devlink_priority(sd_device *device, int priority) {
assert(device);
device->devlink_priority = priority;
}
void device_set_is_initialized(sd_device *device) {
assert(device);
device->is_initialized = true;
}
int device_ensure_usec_initialized(sd_device *device, sd_device *device_old) {
usec_t when;
assert(device);
if (device_old && device_old->usec_initialized > 0)
when = device_old->usec_initialized;
else
when = now(CLOCK_MONOTONIC);
return device_set_usec_initialized(device, when);
}
uint64_t device_get_properties_generation(sd_device *device) {
assert(device);
return device->properties_generation;
}
uint64_t device_get_tags_generation(sd_device *device) {
assert(device);
return device->tags_generation;
}
uint64_t device_get_devlinks_generation(sd_device *device) {
assert(device);
return device->devlinks_generation;
}
int device_get_devnode_mode(sd_device *device, mode_t *ret) {
int r;
assert(device);
r = device_read_db(device);
if (r < 0)
return r;
if (device->devmode == MODE_INVALID)
return -ENOENT;
if (ret)
*ret = device->devmode;
return 0;
}
int device_get_devnode_uid(sd_device *device, uid_t *ret) {
int r;
assert(device);
r = device_read_db(device);
if (r < 0)
return r;
if (device->devuid == UID_INVALID)
return -ENOENT;
if (ret)
*ret = device->devuid;
return 0;
}
static int device_set_devuid(sd_device *device, const char *uid) {
uid_t u;
int r;
assert(device);
assert(uid);
r = parse_uid(uid, &u);
if (r < 0)
return r;
r = device_add_property_internal(device, "DEVUID", uid);
if (r < 0)
return r;
device->devuid = u;
return 0;
}
int device_get_devnode_gid(sd_device *device, gid_t *ret) {
int r;
assert(device);
r = device_read_db(device);
if (r < 0)
return r;
if (device->devgid == GID_INVALID)
return -ENOENT;
if (ret)
*ret = device->devgid;
return 0;
}
static int device_set_devgid(sd_device *device, const char *gid) {
gid_t g;
int r;
assert(device);
assert(gid);
r = parse_gid(gid, &g);
if (r < 0)
return r;
r = device_add_property_internal(device, "DEVGID", gid);
if (r < 0)
return r;
device->devgid = g;
return 0;
}
int device_set_action(sd_device *device, sd_device_action_t a) {
int r;
assert(device);
assert(a >= 0 && a < _SD_DEVICE_ACTION_MAX);
r = device_add_property_internal(device, "ACTION", device_action_to_string(a));
if (r < 0)
return r;
device->action = a;
return 0;
}
static int device_set_action_from_string(sd_device *device, const char *action) {
sd_device_action_t a;
assert(device);
assert(action);
a = device_action_from_string(action);
if (a < 0)
return a;
return device_set_action(device, a);
}
static int device_set_seqnum(sd_device *device, const char *str) {
uint64_t seqnum;
int r;
assert(device);
assert(str);
r = safe_atou64(str, &seqnum);
if (r < 0)
return r;
if (seqnum == 0)
return -EINVAL;
r = device_add_property_internal(device, "SEQNUM", str);
if (r < 0)
return r;
device->seqnum = seqnum;
return 0;
}
static int device_amend(sd_device *device, const char *key, const char *value) {
int r;
assert(device);
assert(key);
assert(value);
if (streq(key, "DEVPATH")) {
char *path;
path = strjoina("/sys", value);
/* the caller must verify or trust this data (e.g., if it comes from the kernel) */
r = device_set_syspath(device, path, false);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set syspath to '%s': %m", path);
} else if (streq(key, "SUBSYSTEM")) {
r = device_set_subsystem(device, value);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem to '%s': %m", value);
} else if (streq(key, "DEVTYPE")) {
r = device_set_devtype(device, value);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set devtype to '%s': %m", value);
} else if (streq(key, "DEVNAME")) {
r = device_set_devname(device, value);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set devname to '%s': %m", value);
} else if (streq(key, "USEC_INITIALIZED")) {
usec_t t;
r = safe_atou64(value, &t);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to parse timestamp '%s': %m", value);
r = device_set_usec_initialized(device, t);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set usec-initialized to '%s': %m", value);
} else if (streq(key, "DRIVER")) {
r = device_set_driver(device, value);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set driver to '%s': %m", value);
} else if (streq(key, "IFINDEX")) {
r = device_set_ifindex(device, value);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set ifindex to '%s': %m", value);
} else if (streq(key, "DEVMODE")) {
r = device_set_devmode(device, value);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set devmode to '%s': %m", value);
} else if (streq(key, "DEVUID")) {
r = device_set_devuid(device, value);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set devuid to '%s': %m", value);
} else if (streq(key, "DEVGID")) {
r = device_set_devgid(device, value);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set devgid to '%s': %m", value);
} else if (streq(key, "ACTION")) {
r = device_set_action_from_string(device, value);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set action to '%s': %m", value);
} else if (streq(key, "SEQNUM")) {
r = device_set_seqnum(device, value);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set SEQNUM to '%s': %m", value);
} else if (streq(key, "DISKSEQ")) {
r = device_set_diskseq(device, value);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set DISKSEQ to '%s': %m", value);
} else if (streq(key, "DEVLINKS")) {
for (const char *p = value;;) {
_cleanup_free_ char *word = NULL;
/* udev rules may set escaped strings, and sd-device does not modify the input
* strings. So, it is also necessary to keep the strings received through
* sd-device-monitor. */
r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
if (r < 0)
return r;
if (r == 0)
break;
r = device_add_devlink(device, word);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to add devlink '%s': %m", word);
}
} else if (STR_IN_SET(key, "TAGS", "CURRENT_TAGS")) {
for (const char *p = value;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return r;
if (r == 0)
break;
if (isempty(word))
continue;
r = device_add_tag(device, word, streq(key, "CURRENT_TAGS"));
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to add tag '%s': %m", word);
}
} else if (streq(key, "UDEV_DATABASE_VERSION")) {
r = safe_atou(value, &device->database_version);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to parse udev database version '%s': %m", value);
} else {
r = device_add_property_internal(device, key, value);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to add property '%s=%s': %m", key, value);
}
return 0;
}
static int device_append(
sd_device *device,
char *key,
const char **_major,
const char **_minor) {
const char *major = NULL, *minor = NULL;
char *value;
int r;
assert(device);
assert(key);
assert(_major);
assert(_minor);
value = strchr(key, '=');
if (!value)
return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
"sd-device: Not a key-value pair: '%s'", key);
*value = '\0';
value++;
if (streq(key, "MAJOR"))
major = value;
else if (streq(key, "MINOR"))
minor = value;
else {
r = device_amend(device, key, value);
if (r < 0)
return r;
}
if (major)
*_major = major;
if (minor)
*_minor = minor;
return 0;
}
void device_seal(sd_device *device) {
assert(device);
device->sealed = true;
}
static int device_verify(sd_device *device) {
int r;
assert(device);
if (!device->devpath || !device->subsystem || device->action < 0 || device->seqnum == 0)
return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
"sd-device: Device created from strv or nulstr lacks devpath, subsystem, action or seqnum.");
if (streq(device->subsystem, "drivers")) {
r = device_set_drivers_subsystem(device);
if (r < 0)
return r;
}
device->sealed = true;
return 0;
}
int device_new_from_strv(sd_device **ret, char **strv) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
const char *major = NULL, *minor = NULL;
int r;
assert(ret);
assert(strv);
r = device_new_aux(&device);
if (r < 0)
return r;
STRV_FOREACH(key, strv) {
r = device_append(device, *key, &major, &minor);
if (r < 0)
return r;
}
if (major) {
r = device_set_devnum(device, major, minor);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
}
r = device_verify(device);
if (r < 0)
return r;
*ret = TAKE_PTR(device);
return 0;
}
int device_new_from_nulstr(sd_device **ret, char *nulstr, size_t len) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
const char *major = NULL, *minor = NULL;
int r;
assert(ret);
assert(nulstr);
assert(len);
r = device_new_aux(&device);
if (r < 0)
return r;
for (size_t i = 0; i < len; ) {
char *key;
const char *end;
key = nulstr + i;
end = memchr(key, '\0', len - i);
if (!end)
return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL),
"sd-device: Failed to parse nulstr");
i += end - key + 1;
/* netlink messages for some devices contain an unwanted newline at the end of value.
* Let's drop the newline and remaining characters after the newline. */
truncate_nl(key);
r = device_append(device, key, &major, &minor);
if (r < 0)
return r;
}
if (major) {
r = device_set_devnum(device, major, minor);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
}
r = device_verify(device);
if (r < 0)
return r;
*ret = TAKE_PTR(device);
return 0;
}
static int device_update_properties_bufs(sd_device *device) {
_cleanup_free_ char **buf_strv = NULL, *buf_nulstr = NULL;
size_t nulstr_len = 0, num = 0;
assert(device);
if (!device->properties_buf_outdated)
return 0;
/* append udev database version */
buf_nulstr = newdup(char, "UDEV_DATABASE_VERSION=" STRINGIFY(LATEST_UDEV_DATABASE_VERSION) "\0",
STRLEN("UDEV_DATABASE_VERSION=" STRINGIFY(LATEST_UDEV_DATABASE_VERSION)) + 2);
if (!buf_nulstr)
return -ENOMEM;
nulstr_len += STRLEN("UDEV_DATABASE_VERSION=" STRINGIFY(LATEST_UDEV_DATABASE_VERSION)) + 1;
num++;
FOREACH_DEVICE_PROPERTY(device, prop, val) {
size_t len = 0;
len = strlen(prop) + 1 + strlen(val);
buf_nulstr = GREEDY_REALLOC0(buf_nulstr, nulstr_len + len + 2);
if (!buf_nulstr)
return -ENOMEM;
strscpyl(buf_nulstr + nulstr_len, len + 1, prop, "=", val, NULL);
nulstr_len += len + 1;
num++;
}
/* build buf_strv from buf_nulstr */
buf_strv = new0(char*, num + 1);
if (!buf_strv)
return -ENOMEM;
size_t i = 0;
NULSTR_FOREACH(p, buf_nulstr)
buf_strv[i++] = p;
assert(i == num);
free_and_replace(device->properties_nulstr, buf_nulstr);
device->properties_nulstr_len = nulstr_len;
free_and_replace(device->properties_strv, buf_strv);
device->properties_buf_outdated = false;
return 0;
}
int device_get_properties_nulstr(sd_device *device, const char **ret_nulstr, size_t *ret_len) {
int r;
assert(device);
r = device_update_properties_bufs(device);
if (r < 0)
return r;
if (ret_nulstr)
*ret_nulstr = device->properties_nulstr;
if (ret_len)
*ret_len = device->properties_nulstr_len;
return 0;
}
int device_get_properties_strv(sd_device *device, char ***ret) {
int r;
assert(device);
r = device_update_properties_bufs(device);
if (r < 0)
return r;
if (ret)
*ret = device->properties_strv;
return 0;
}
int device_get_devlink_priority(sd_device *device, int *ret) {
int r;
assert(device);
r = device_read_db(device);
if (r < 0)
return r;
if (ret)
*ret = device->devlink_priority;
return 0;
}
int device_clone_with_db(sd_device *device, sd_device **ret) {
_cleanup_(sd_device_unrefp) sd_device *dest = NULL;
const char *key, *val;
int r;
assert(device);
assert(ret);
/* The device may be already removed. Let's copy minimal set of information that was obtained through
* netlink socket. */
r = device_new_aux(&dest);
if (r < 0)
return r;
/* Seal device to prevent reading the uevent file, as the device may have been already removed. */
dest->sealed = true;
/* Copy syspath, then also devname, sysname or sysnum can be obtained. */
r = device_set_syspath(dest, device->syspath, false);
if (r < 0)
return r;
/* Copy other information stored in database. Here, do not use FOREACH_DEVICE_PROPERTY() and
* sd_device_get_property_value(), as they calls device_properties_prepare() ->
* device_read_uevent_file(), but as commented in the above, the device may be already removed and
* reading uevent file may fail. */
ORDERED_HASHMAP_FOREACH_KEY(val, key, device->properties) {
if (streq(key, "MINOR"))
continue;
if (streq(key, "MAJOR")) {
const char *minor = NULL;
minor = ordered_hashmap_get(device->properties, "MINOR");
r = device_set_devnum(dest, val, minor);
} else
r = device_amend(dest, key, val);
if (r < 0)
return r;
if (streq(key, "SUBSYSTEM") && streq(val, "drivers")) {
r = free_and_strdup(&dest->driver_subsystem, device->driver_subsystem);
if (r < 0)
return r;
}
}
/* Finally, read the udev database. */
r = device_read_db_internal(dest, /* force = */ true);
if (r < 0)
return r;
*ret = TAKE_PTR(dest);
return 0;
}
void device_cleanup_tags(sd_device *device) {
assert(device);
device->all_tags = set_free_free(device->all_tags);
device->current_tags = set_free_free(device->current_tags);
device->property_tags_outdated = true;
device->tags_generation++;
}
void device_cleanup_devlinks(sd_device *device) {
assert(device);
set_free_free(device->devlinks);
device->devlinks = NULL;
device->property_devlinks_outdated = true;
device->devlinks_generation++;
}
void device_remove_tag(sd_device *device, const char *tag) {
assert(device);
assert(tag);
free(set_remove(device->current_tags, tag));
device->property_tags_outdated = true;
device->tags_generation++;
}
static int device_tag(sd_device *device, const char *tag, bool add) {
const char *id;
char *path;
int r;
assert(device);
assert(tag);
r = device_get_device_id(device, &id);
if (r < 0)
return r;
path = strjoina("/run/udev/tags/", tag, "/", id);
if (add)
return touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
if (unlink(path) < 0 && errno != ENOENT)
return -errno;
return 0;
}
int device_tag_index(sd_device *device, sd_device *device_old, bool add) {
int r = 0, k;
if (add && device_old)
/* delete possible left-over tags */
FOREACH_DEVICE_TAG(device_old, tag)
if (!sd_device_has_tag(device, tag)) {
k = device_tag(device_old, tag, false);
if (r >= 0 && k < 0)
r = k;
}
FOREACH_DEVICE_TAG(device, tag) {
k = device_tag(device, tag, add);
if (r >= 0 && k < 0)
r = k;
}
return r;
}
static bool device_has_info(sd_device *device) {
assert(device);
if (!set_isempty(device->devlinks))
return true;
if (device->devlink_priority != 0)
return true;
if (!ordered_hashmap_isempty(device->properties_db))
return true;
if (!set_isempty(device->all_tags))
return true;
if (!set_isempty(device->current_tags))
return true;
return false;
}
bool device_should_have_db(sd_device *device) {
assert(device);
if (device_has_info(device))
return true;
if (major(device->devnum) != 0)
return true;
if (device->ifindex != 0)
return true;
return false;
}
void device_set_db_persist(sd_device *device) {
assert(device);
device->db_persist = true;
}
#endif /* NM_IGNORED */
static int device_get_db_path(sd_device *device, char **ret) {
const char *id;
char *path;
int r;
assert(device);
assert(ret);
r = device_get_device_id(device, &id);
if (r < 0)
return r;
path = path_join("/run/udev/data/", id);
if (!path)
return -ENOMEM;
*ret = path;
return 0;
}
#if 0 /* NM_IGNORED */
int device_has_db(sd_device *device) {
_cleanup_free_ char *path = NULL;
int r;
assert(device);
r = device_get_db_path(device, &path);
if (r < 0)
return r;
return access(path, F_OK) >= 0;
}
int device_update_db(sd_device *device) {
_cleanup_(unlink_and_freep) char *path = NULL, *path_tmp = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(device);
/* do not store anything for otherwise empty devices */
if (!device_should_have_db(device))
return device_delete_db(device);
r = device_get_db_path(device, &path);
if (r < 0)
return r;
/* write a database file */
r = mkdir_parents(path, 0755);
if (r < 0)
return log_device_debug_errno(device, r,
"sd-device: Failed to create parent directories of '%s': %m",
path);
r = fopen_temporary(path, &f, &path_tmp);
if (r < 0)
return log_device_debug_errno(device, r,
"sd-device: Failed to create temporary file for database file '%s': %m",
path);
/* set 'sticky' bit to indicate that we should not clean the database when we transition from initrd
* to the real root */
if (fchmod(fileno(f), device->db_persist ? 01644 : 0644) < 0)
return log_device_debug_errno(device, errno,
"sd-device: Failed to chmod temporary database file '%s': %m",
path_tmp);
if (device_has_info(device)) {
const char *property, *value, *ct;
if (major(device->devnum) > 0) {
FOREACH_DEVICE_DEVLINK(device, devlink)
fprintf(f, "S:%s\n", devlink + STRLEN("/dev/"));
if (device->devlink_priority != 0)
fprintf(f, "L:%i\n", device->devlink_priority);
}
if (device->usec_initialized > 0)
fprintf(f, "I:"USEC_FMT"\n", device->usec_initialized);
ORDERED_HASHMAP_FOREACH_KEY(value, property, device->properties_db)
fprintf(f, "E:%s=%s\n", property, value);
FOREACH_DEVICE_TAG(device, tag)
fprintf(f, "G:%s\n", tag); /* Any tag */
SET_FOREACH(ct, device->current_tags)
fprintf(f, "Q:%s\n", ct); /* Current tag */
/* Always write the latest database version here, instead of the value stored in
* device->database_version, as which may be 0. */
fputs("V:" STRINGIFY(LATEST_UDEV_DATABASE_VERSION) "\n", f);
}
r = fflush_and_check(f);
if (r < 0)
return log_device_debug_errno(device, r,
"sd-device: Failed to flush temporary database file '%s': %m",
path_tmp);
if (rename(path_tmp, path) < 0)
return log_device_debug_errno(device, errno,
"sd-device: Failed to rename temporary database file '%s' to '%s': %m",
path_tmp, path);
log_device_debug(device, "sd-device: Created database file '%s' for '%s'.", path, device->devpath);
path_tmp = mfree(path_tmp);
path = mfree(path);
return 0;
}
int device_delete_db(sd_device *device) {
_cleanup_free_ char *path = NULL;
int r;
assert(device);
r = device_get_db_path(device, &path);
if (r < 0)
return r;
if (unlink(path) < 0 && errno != ENOENT)
return -errno;
return 0;
}
#endif /* NM_IGNORED */
int device_read_db_internal(sd_device *device, bool force) {
_cleanup_free_ char *path = NULL;
int r;
assert(device);
if (device->db_loaded || (!force && device->sealed))
return 0;
r = device_get_db_path(device, &path);
if (r < 0)
return r;
return device_read_db_internal_filename(device, path);
}
#if 0 /* NM_IGNORED */
static const char* const device_action_table[_SD_DEVICE_ACTION_MAX] = {
[SD_DEVICE_ADD] = "add",
[SD_DEVICE_REMOVE] = "remove",
[SD_DEVICE_CHANGE] = "change",
[SD_DEVICE_MOVE] = "move",
[SD_DEVICE_ONLINE] = "online",
[SD_DEVICE_OFFLINE] = "offline",
[SD_DEVICE_BIND] = "bind",
[SD_DEVICE_UNBIND] = "unbind",
};
DEFINE_STRING_TABLE_LOOKUP(device_action, sd_device_action_t);
void dump_device_action_table(void) {
DUMP_STRING_TABLE(device_action, sd_device_action_t, _SD_DEVICE_ACTION_MAX);
}
#endif /* NM_IGNORED */

View File

@@ -0,0 +1,77 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <dirent.h>
#include <inttypes.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "sd-device.h"
#include "macro.h"
int device_new_from_mode_and_devnum(sd_device **ret, mode_t mode, dev_t devnum);
int device_new_from_nulstr(sd_device **ret, char *nulstr, size_t len);
int device_new_from_strv(sd_device **ret, char **strv);
int device_opendir(sd_device *device, const char *subdir, DIR **ret);
int device_get_property_bool(sd_device *device, const char *key);
int device_get_property_int(sd_device *device, const char *key, int *ret);
int device_get_sysattr_int(sd_device *device, const char *sysattr, int *ret_value);
int device_get_sysattr_unsigned(sd_device *device, const char *sysattr, unsigned *ret_value);
int device_get_sysattr_u32(sd_device *device, const char *sysattr, uint32_t *ret_value);
int device_get_sysattr_bool(sd_device *device, const char *sysattr);
int device_get_device_id(sd_device *device, const char **ret);
int device_get_devlink_priority(sd_device *device, int *ret);
int device_get_devnode_mode(sd_device *device, mode_t *ret);
int device_get_devnode_uid(sd_device *device, uid_t *ret);
int device_get_devnode_gid(sd_device *device, gid_t *ret);
void device_clear_sysattr_cache(sd_device *device);
int device_cache_sysattr_value(sd_device *device, const char *key, char *value);
int device_get_cached_sysattr_value(sd_device *device, const char *key, const char **ret_value);
void device_seal(sd_device *device);
void device_set_is_initialized(sd_device *device);
void device_set_db_persist(sd_device *device);
void device_set_devlink_priority(sd_device *device, int priority);
int device_ensure_usec_initialized(sd_device *device, sd_device *device_old);
int device_add_devlink(sd_device *device, const char *devlink);
int device_remove_devlink(sd_device *device, const char *devlink);
bool device_has_devlink(sd_device *device, const char *devlink);
int device_add_property(sd_device *device, const char *property, const char *value);
int device_add_propertyf(sd_device *device, const char *key, const char *format, ...) _printf_(3, 4);
int device_add_tag(sd_device *device, const char *tag, bool both);
void device_remove_tag(sd_device *device, const char *tag);
void device_cleanup_tags(sd_device *device);
void device_cleanup_devlinks(sd_device *device);
uint64_t device_get_properties_generation(sd_device *device);
uint64_t device_get_tags_generation(sd_device *device);
uint64_t device_get_devlinks_generation(sd_device *device);
int device_properties_prepare(sd_device *device);
int device_get_properties_nulstr(sd_device *device, const char **ret_nulstr, size_t *ret_len);
int device_get_properties_strv(sd_device *device, char ***ret);
int device_clone_with_db(sd_device *device, sd_device **ret);
int device_tag_index(sd_device *dev, sd_device *dev_old, bool add);
bool device_should_have_db(sd_device *device);
int device_has_db(sd_device *device);
int device_update_db(sd_device *device);
int device_delete_db(sd_device *device);
int device_read_db_internal_filename(sd_device *device, const char *filename); /* For fuzzer */
int device_read_db_internal(sd_device *device, bool force);
static inline int device_read_db(sd_device *device) {
return device_read_db_internal(device, false);
}
int device_read_uevent_file(sd_device *device);
int device_set_action(sd_device *device, sd_device_action_t a);
sd_device_action_t device_action_from_string(const char *s) _pure_;
const char *device_action_to_string(sd_device_action_t a) _const_;
void dump_device_action_table(void);

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@ libnm_systemd_shared = static_library(
'nm-sd-utils-shared.c',
'src/basic/alloc-util.c',
'src/basic/btrfs.c',
'src/basic/devnum-util.c',
'src/basic/env-file.c',
'src/basic/env-util.c',
'src/basic/escape.c',

View File

@@ -0,0 +1,64 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <dirent.h>
#include <stdio.h>
#include "stat-util.h"
typedef enum ChaseFlags {
CHASE_PREFIX_ROOT = 1 << 0, /* The specified path will be prefixed by the specified root before beginning the iteration */
CHASE_NONEXISTENT = 1 << 1, /* It's OK if the path doesn't actually exist. */
CHASE_NO_AUTOFS = 1 << 2, /* Return -EREMOTE if autofs mount point found */
CHASE_SAFE = 1 << 3, /* Return -EPERM if we ever traverse from unprivileged to privileged files or directories */
CHASE_TRAIL_SLASH = 1 << 4, /* Any trailing slash will be preserved */
CHASE_STEP = 1 << 5, /* Just execute a single step of the normalization */
CHASE_NOFOLLOW = 1 << 6, /* Do not follow the path's right-most component. With ret_fd, when the path's
* right-most component refers to symlink, return O_PATH fd of the symlink. */
CHASE_WARN = 1 << 7, /* Emit an appropriate warning when an error is encountered.
* Note: this may do an NSS lookup, hence this flag cannot be used in PID 1. */
CHASE_AT_RESOLVE_IN_ROOT = 1 << 8, /* Same as openat2()'s RESOLVE_IN_ROOT flag, symlinks are resolved
* relative to the given directory fd instead of root. */
CHASE_PROHIBIT_SYMLINKS = 1 << 9, /* Refuse all symlinks */
CHASE_PARENT = 1 << 10, /* Chase the parent directory of the given path. Note that the
* full path is still stored in ret_path and only the returned
* file descriptor will point to the parent directory. Note that
* the result path is the root or '.', then the file descriptor
* also points to the result path even if this flag is set.
* When this specified, chase() will succeed with 1 even if the
* file points to the last path component does not exist. */
CHASE_MKDIR_0755 = 1 << 11, /* Create any missing parent directories in the given path. This
* needs to be set with CHASE_NONEXISTENT and/or CHASE_PARENT.
* Note, chase_and_open() or friends always add CHASE_PARENT flag
* when internally call chase(), hence CHASE_MKDIR_0755 can be
* safely set without CHASE_NONEXISTENT and CHASE_PARENT. */
CHASE_EXTRACT_FILENAME = 1 << 12, /* Only return the last component of the resolved path */
} ChaseFlags;
bool unsafe_transition(const struct stat *a, const struct stat *b);
/* How many iterations to execute before returning -ELOOP */
#define CHASE_MAX 32
int chase(const char *path_with_prefix, const char *root, ChaseFlags chase_flags, char **ret_path, int *ret_fd);
int chaseat_prefix_root(const char *path, const char *root, char **ret);
int chase_extract_filename(const char *path, const char *root, char **ret);
int chase_and_open(const char *path, const char *root, ChaseFlags chase_flags, int open_flags, char **ret_path);
int chase_and_opendir(const char *path, const char *root, ChaseFlags chase_flags, char **ret_path, DIR **ret_dir);
int chase_and_stat(const char *path, const char *root, ChaseFlags chase_flags, char **ret_path, struct stat *ret_stat);
int chase_and_access(const char *path, const char *root, ChaseFlags chase_flags, int access_mode, char **ret_path);
int chase_and_fopen_unlocked(const char *path, const char *root, ChaseFlags chase_flags, const char *open_flags, char **ret_path, FILE **ret_file);
int chase_and_unlink(const char *path, const char *root, ChaseFlags chase_flags, int unlink_flags, char **ret_path);
int chase_and_open_parent(const char *path, const char *root, ChaseFlags chase_flags, char **ret_filename);
int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int *ret_fd);
int chase_and_openat(int dir_fd, const char *path, ChaseFlags chase_flags, int open_flags, char **ret_path);
int chase_and_opendirat(int dir_fd, const char *path, ChaseFlags chase_flags, char **ret_path, DIR **ret_dir);
int chase_and_statat(int dir_fd, const char *path, ChaseFlags chase_flags, char **ret_path, struct stat *ret_stat);
int chase_and_accessat(int dir_fd, const char *path, ChaseFlags chase_flags, int access_mode, char **ret_path);
int chase_and_fopenat_unlocked(int dir_fd, const char *path, ChaseFlags chase_flags, const char *open_flags, char **ret_path, FILE **ret_file);
int chase_and_unlinkat(int dir_fd, const char *path, ChaseFlags chase_flags, int unlink_flags, char **ret_path);
int chase_and_open_parent_at(int dir_fd, const char *path, ChaseFlags chase_flags, char **ret_filename);

View File

@@ -0,0 +1,142 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "nm-sd-adapt-shared.h"
#include <string.h>
#include <sys/stat.h>
#include "chase.h"
#include "devnum-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "string-util.h"
int parse_devnum(const char *s, dev_t *ret) {
const char *major;
unsigned x, y;
size_t n;
int r;
n = strspn(s, DIGITS);
if (n == 0)
return -EINVAL;
if (n > DECIMAL_STR_MAX(dev_t))
return -EINVAL;
if (s[n] != ':')
return -EINVAL;
major = strndupa_safe(s, n);
r = safe_atou(major, &x);
if (r < 0)
return r;
r = safe_atou(s + n + 1, &y);
if (r < 0)
return r;
if (!DEVICE_MAJOR_VALID(x) || !DEVICE_MINOR_VALID(y))
return -ERANGE;
*ret = makedev(x, y);
return 0;
}
int device_path_make_major_minor(mode_t mode, dev_t devnum, char **ret) {
const char *t;
/* Generates the /dev/{char|block}/MAJOR:MINOR path for a dev_t */
if (S_ISCHR(mode))
t = "char";
else if (S_ISBLK(mode))
t = "block";
else
return -ENODEV;
if (asprintf(ret, "/dev/%s/" DEVNUM_FORMAT_STR, t, DEVNUM_FORMAT_VAL(devnum)) < 0)
return -ENOMEM;
return 0;
}
int device_path_make_inaccessible(mode_t mode, char **ret) {
char *s;
assert(ret);
if (S_ISCHR(mode))
s = strdup("/run/systemd/inaccessible/chr");
else if (S_ISBLK(mode))
s = strdup("/run/systemd/inaccessible/blk");
else
return -ENODEV;
if (!s)
return -ENOMEM;
*ret = s;
return 0;
}
#if 0 /* NM_IGNORED */
int device_path_make_canonical(mode_t mode, dev_t devnum, char **ret) {
_cleanup_free_ char *p = NULL;
int r;
/* Finds the canonical path for a device, i.e. resolves the /dev/{char|block}/MAJOR:MINOR path to the end. */
assert(ret);
if (devnum_is_zero(devnum))
/* A special hack to make sure our 'inaccessible' device nodes work. They won't have symlinks in
* /dev/block/ and /dev/char/, hence we handle them specially here. */
return device_path_make_inaccessible(mode, ret);
r = device_path_make_major_minor(mode, devnum, &p);
if (r < 0)
return r;
return chase(p, NULL, 0, ret, NULL);
}
#endif /* NM_IGNORED */
int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devnum) {
mode_t mode;
dev_t devnum;
int r;
/* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/
* paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device
* path cannot be parsed like this. */
if (path_equal(path, "/run/systemd/inaccessible/chr")) {
mode = S_IFCHR;
devnum = makedev(0, 0);
} else if (path_equal(path, "/run/systemd/inaccessible/blk")) {
mode = S_IFBLK;
devnum = makedev(0, 0);
} else {
const char *w;
w = path_startswith(path, "/dev/block/");
if (w)
mode = S_IFBLK;
else {
w = path_startswith(path, "/dev/char/");
if (!w)
return -ENODEV;
mode = S_IFCHR;
}
r = parse_devnum(w, &devnum);
if (r < 0)
return r;
}
if (ret_mode)
*ret_mode = mode;
if (ret_devnum)
*ret_devnum = devnum;
return 0;
}

View File

@@ -0,0 +1,56 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <inttypes.h>
#include <stdbool.h>
#include <sys/types.h>
#include "stdio-util.h"
int parse_devnum(const char *s, dev_t *ret);
/* glibc and the Linux kernel have different ideas about the major/minor size. These calls will check whether the
* specified major is valid by the Linux kernel's standards, not by glibc's. Linux has 20bits of minor, and 12 bits of
* major space. See MINORBITS in linux/kdev_t.h in the kernel sources. (If you wonder why we define _y here, instead of
* comparing directly >= 0: it's to trick out -Wtype-limits, which would otherwise complain if the type is unsigned, as
* such a test would be pointless in such a case.) */
#define DEVICE_MAJOR_VALID(x) \
({ \
typeof(x) _x = (x), _y = 0; \
_x >= _y && _x < (UINT32_C(1) << 12); \
\
})
#define DEVICE_MINOR_VALID(x) \
({ \
typeof(x) _x = (x), _y = 0; \
_x >= _y && _x < (UINT32_C(1) << 20); \
})
int device_path_make_major_minor(mode_t mode, dev_t devnum, char **ret);
int device_path_make_inaccessible(mode_t mode, char **ret);
int device_path_make_canonical(mode_t mode, dev_t devnum, char **ret);
int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devnum);
static inline bool devnum_set_and_equal(dev_t a, dev_t b) {
/* Returns true if a and b definitely refer to the same device. If either is zero, this means "don't
* know" and we'll return false */
return a == b && a != 0;
}
/* Maximum string length for a major:minor string. (Note that DECIMAL_STR_MAX includes space for a trailing NUL) */
#define DEVNUM_STR_MAX (DECIMAL_STR_MAX(dev_t)-1+1+DECIMAL_STR_MAX(dev_t))
#define DEVNUM_FORMAT_STR "%u:%u"
#define DEVNUM_FORMAT_VAL(d) major(d), minor(d)
static inline char *format_devnum(dev_t d, char buf[static DEVNUM_STR_MAX]) {
return ASSERT_PTR(snprintf_ok(buf, DEVNUM_STR_MAX, DEVNUM_FORMAT_STR, DEVNUM_FORMAT_VAL(d)));
}
#define FORMAT_DEVNUM(d) format_devnum((d), (char[DEVNUM_STR_MAX]) {})
static inline bool devnum_is_zero(dev_t d) {
return major(d) == 0 && minor(d) == 0;
}

View File

@@ -156,7 +156,6 @@ int readlink_malloc(const char *p, char **ret) {
return readlinkat_malloc(AT_FDCWD, p, ret);
}
#if 0 /* NM_IGNORED */
int readlink_value(const char *p, char **ret) {
_cleanup_free_ char *link = NULL, *name = NULL;
int r;
@@ -178,6 +177,7 @@ int readlink_value(const char *p, char **ret) {
return 0;
}
#if 0 /* NM_IGNORED */
int readlink_and_make_absolute(const char *p, char **ret) {
_cleanup_free_ char *target = NULL;
int r;

View File

@@ -22,7 +22,6 @@ DEFINE_HASH_OPS_FULL(string_hash_ops_free_strv_free,
char, string_hash_func, string_compare_func, free,
char*, strv_free);
#if 0 /* NM_IGNORED */
void path_hash_func(const char *q, struct siphash *state) {
bool add_slash = false;
@@ -68,7 +67,6 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(path_hash_ops_free,
DEFINE_HASH_OPS_FULL(path_hash_ops_free_free,
char, path_hash_func, path_compare, free,
void, free);
#endif /* NM_IGNORED */
void trivial_hash_func(const void *p, struct siphash *state) {
siphash24_compress_typesafe(p, state);

View File

@@ -219,6 +219,7 @@ int path_make_relative_parent(const char *from_child, const char *to, char **ret
return path_make_relative(from, to, ret);
}
#endif /* NM_IGNORED */
char* path_startswith_strv(const char *p, char **set) {
STRV_FOREACH(s, set) {
@@ -232,6 +233,7 @@ char* path_startswith_strv(const char *p, char **set) {
return NULL;
}
#if 0 /* NM_IGNORED */
int path_strv_make_absolute_cwd(char **l) {
int r;

View File

@@ -110,12 +110,14 @@ int xstatfsat(int dir_fd, const char *path, struct statfs *ret);
} var
#endif
#if 0 /* NM_IGNORED */
static inline usec_t statx_timestamp_load(const struct statx_timestamp *ts) {
return timespec_load(&(const struct timespec) { .tv_sec = ts->tv_sec, .tv_nsec = ts->tv_nsec });
}
static inline nsec_t statx_timestamp_load_nsec(const struct statx_timestamp *ts) {
return timespec_load_nsec(&(const struct timespec) { .tv_sec = ts->tv_sec, .tv_nsec = ts->tv_nsec });
}
#endif /* NM_IGNORED */
void inode_hash_func(const struct stat *q, struct siphash *state);
int inode_compare_func(const struct stat *a, const struct stat *b);

View File

@@ -1319,6 +1319,7 @@ bool streq_skip_trailing_chars(const char *s1, const char *s2, const char *ok) {
return in_charset(s1, ok) && in_charset(s2, ok);
}
#endif /* NM_IGNORED */
char *string_replace_char(char *str, char old_char, char new_char) {
assert(str);
@@ -1331,7 +1332,6 @@ char *string_replace_char(char *str, char old_char, char new_char) {
return str;
}
#endif /* NM_IGNORED */
int make_cstring(const char *s, size_t n, MakeCStringMode mode, char **ret) {
char *b;
@@ -1376,7 +1376,6 @@ int make_cstring(const char *s, size_t n, MakeCStringMode mode, char **ret) {
return 0;
}
#if 0 /* NM_IGNORED */
size_t strspn_from_end(const char *str, const char *accept) {
size_t n = 0;
@@ -1392,6 +1391,7 @@ size_t strspn_from_end(const char *str, const char *accept) {
return n;
}
#if 0 /* NM_IGNORED */
char *strdupspn(const char *a, const char *accept) {
if (isempty(a) || isempty(accept))
return strdup("");