mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-04 14:10:36 +01:00
systemd: merge branch systemd into master
This commit is contained in:
commit
dee5ce0a52
35 changed files with 563 additions and 167 deletions
|
|
@ -24,6 +24,7 @@
|
|||
#include "mkdir.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
|
@ -486,13 +487,12 @@ int read_full_stream_full(
|
|||
assert(f);
|
||||
assert(ret_contents);
|
||||
assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
|
||||
assert(!(flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) || ret_size);
|
||||
|
||||
n_next = LINE_MAX; /* Start size */
|
||||
|
||||
fd = fileno(f);
|
||||
if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen(), let's
|
||||
* optimize our buffering) */
|
||||
if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen()), let's
|
||||
* optimize our buffering */
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
|
|
@ -509,7 +509,7 @@ int read_full_stream_full(
|
|||
if (st.st_size > 0)
|
||||
n_next = st.st_size + 1;
|
||||
|
||||
if (flags & READ_FULL_FILE_SECURE)
|
||||
if (flags & READ_FULL_FILE_WARN_WORLD_READABLE)
|
||||
(void) warn_file_is_world_accessible(filename, &st, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -539,21 +539,18 @@ int read_full_stream_full(
|
|||
|
||||
errno = 0;
|
||||
k = fread(buf + l, 1, n - l, f);
|
||||
if (k > 0)
|
||||
l += k;
|
||||
|
||||
assert(k <= n - l);
|
||||
l += k;
|
||||
|
||||
if (ferror(f)) {
|
||||
r = errno_or_else(EIO);
|
||||
goto finalize;
|
||||
}
|
||||
|
||||
if (feof(f))
|
||||
break;
|
||||
|
||||
/* We aren't expecting fread() to return a short read outside
|
||||
* of (error && eof), assert buffer is full and enlarge buffer.
|
||||
*/
|
||||
assert(l == n);
|
||||
assert(k > 0); /* we can't have read zero bytes because that would have been EOF */
|
||||
|
||||
/* Safety check */
|
||||
if (n >= READ_FULL_BYTES_MAX) {
|
||||
|
|
@ -565,12 +562,21 @@ int read_full_stream_full(
|
|||
}
|
||||
|
||||
if (flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) {
|
||||
_cleanup_free_ void *decoded = NULL;
|
||||
size_t decoded_size;
|
||||
|
||||
buf[l++] = 0;
|
||||
if (flags & READ_FULL_FILE_UNBASE64)
|
||||
r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, (void **) ret_contents, ret_size);
|
||||
r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size);
|
||||
else
|
||||
r = unhexmem_full(buf, l, flags & READ_FULL_FILE_SECURE, (void **) ret_contents, ret_size);
|
||||
goto finalize;
|
||||
r = unhexmem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size);
|
||||
if (r < 0)
|
||||
goto finalize;
|
||||
|
||||
if (flags & READ_FULL_FILE_SECURE)
|
||||
explicit_bzero_safe(buf, n);
|
||||
free_and_replace(buf, decoded);
|
||||
n = l = decoded_size;
|
||||
}
|
||||
|
||||
if (!ret_size) {
|
||||
|
|
@ -607,8 +613,54 @@ int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flag
|
|||
assert(contents);
|
||||
|
||||
r = xfopenat(dir_fd, filename, "re", 0, &f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r < 0) {
|
||||
_cleanup_close_ int dfd = -1, sk = -1;
|
||||
union sockaddr_union sa;
|
||||
|
||||
/* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */
|
||||
if (r != -ENXIO)
|
||||
return r;
|
||||
|
||||
/* If this is enabled, let's try to connect to it */
|
||||
if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET))
|
||||
return -ENXIO;
|
||||
|
||||
if (dir_fd == AT_FDCWD)
|
||||
r = sockaddr_un_set_path(&sa.un, filename);
|
||||
else {
|
||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
||||
|
||||
/* If we shall operate relative to some directory, then let's use O_PATH first to
|
||||
* open the socket inode, and then connect to it via /proc/self/fd/. We have to do
|
||||
* this since there's not connectat() that takes a directory fd as first arg. */
|
||||
|
||||
dfd = openat(dir_fd, filename, O_PATH|O_CLOEXEC);
|
||||
if (dfd < 0)
|
||||
return -errno;
|
||||
|
||||
xsprintf(procfs_path, "/proc/self/fd/%i", dfd);
|
||||
r = sockaddr_un_set_path(&sa.un, procfs_path);
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
|
||||
if (sk < 0)
|
||||
return -errno;
|
||||
|
||||
if (connect(sk, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
|
||||
return errno == ENOTSOCK ? -ENXIO : -errno; /* propagate original error if this is
|
||||
* not a socket after all */
|
||||
|
||||
if (shutdown(sk, SHUT_WR) < 0)
|
||||
return -errno;
|
||||
|
||||
f = fdopen(sk, "r");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
TAKE_FD(sk);
|
||||
}
|
||||
|
||||
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
|
||||
|
||||
|
|
|
|||
|
|
@ -32,9 +32,11 @@ typedef enum {
|
|||
} WriteStringFileFlags;
|
||||
|
||||
typedef enum {
|
||||
READ_FULL_FILE_SECURE = 1 << 0,
|
||||
READ_FULL_FILE_UNBASE64 = 1 << 1,
|
||||
READ_FULL_FILE_UNHEX = 1 << 2,
|
||||
READ_FULL_FILE_SECURE = 1 << 0, /* erase any buffers we employ internally, after use */
|
||||
READ_FULL_FILE_UNBASE64 = 1 << 1, /* base64 decode what we read */
|
||||
READ_FULL_FILE_UNHEX = 1 << 2, /* hex decode what we read */
|
||||
READ_FULL_FILE_WARN_WORLD_READABLE = 1 << 3, /* if regular file, log at LOG_WARNING level if access mode above 0700 */
|
||||
READ_FULL_FILE_CONNECT_SOCKET = 1 << 4, /* if socket inode, connect to it and read off it */
|
||||
} ReadFullFileFlags;
|
||||
|
||||
int fopen_unlocked(const char *path, const char *options, FILE **ret);
|
||||
|
|
|
|||
|
|
@ -1587,7 +1587,7 @@ static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) {
|
|||
|
||||
d = opendir(p);
|
||||
if (!d) {
|
||||
if (errno == ENOENT) /* Doesn't have slaves */
|
||||
if (errno == ENOENT) /* Doesn't have underlying devices */
|
||||
return false;
|
||||
|
||||
return -errno;
|
||||
|
|
@ -1603,7 +1603,7 @@ static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) {
|
|||
if (errno != 0)
|
||||
return -errno;
|
||||
|
||||
break; /* No more slaves */
|
||||
break; /* No more underlying devices */
|
||||
}
|
||||
|
||||
q = path_join(p, de->d_name);
|
||||
|
|
|
|||
|
|
@ -770,7 +770,7 @@ static void reset_direct_storage(HashmapBase *h) {
|
|||
memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets);
|
||||
}
|
||||
|
||||
static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) {
|
||||
static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) {
|
||||
HashmapBase *h;
|
||||
const struct hashmap_type_info *hi = &hashmap_type_info[type];
|
||||
bool up;
|
||||
|
|
@ -810,19 +810,19 @@ static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enu
|
|||
}
|
||||
|
||||
Hashmap *_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
|
||||
return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
|
||||
return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
|
||||
}
|
||||
|
||||
OrderedHashmap *_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
|
||||
return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
|
||||
return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
|
||||
}
|
||||
|
||||
Set *_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
|
||||
return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
|
||||
return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
|
||||
}
|
||||
|
||||
static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops *hash_ops,
|
||||
enum HashmapType type HASHMAP_DEBUG_PARAMS) {
|
||||
enum HashmapType type HASHMAP_DEBUG_PARAMS) {
|
||||
HashmapBase *q;
|
||||
|
||||
assert(h);
|
||||
|
|
@ -830,7 +830,7 @@ static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops
|
|||
if (*h)
|
||||
return 0;
|
||||
|
||||
q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS);
|
||||
q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS);
|
||||
if (!q)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -839,15 +839,15 @@ static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops
|
|||
}
|
||||
|
||||
int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
|
||||
return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
|
||||
return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
|
||||
}
|
||||
|
||||
int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
|
||||
return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
|
||||
return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
|
||||
}
|
||||
|
||||
int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
|
||||
return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
|
||||
return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
|
||||
}
|
||||
|
||||
static void hashmap_free_no_clear(HashmapBase *h) {
|
||||
|
|
@ -1249,6 +1249,30 @@ int set_put(Set *s, const void *key) {
|
|||
return hashmap_put_boldly(s, hash, &swap, true);
|
||||
}
|
||||
|
||||
int _set_ensure_put(Set **s, const struct hash_ops *hash_ops, const void *key HASHMAP_DEBUG_PARAMS) {
|
||||
int r;
|
||||
|
||||
r = _set_ensure_allocated(s, hash_ops HASHMAP_DEBUG_PASS_ARGS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return set_put(*s, key);
|
||||
}
|
||||
|
||||
int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HASHMAP_DEBUG_PARAMS) {
|
||||
int r;
|
||||
|
||||
r = _set_ensure_put(s, hash_ops, key HASHMAP_DEBUG_PASS_ARGS);
|
||||
if (r <= 0) {
|
||||
if (hash_ops && hash_ops->free_key)
|
||||
hash_ops->free_key(key);
|
||||
else
|
||||
free(key);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int hashmap_replace(Hashmap *h, const void *key, void *value) {
|
||||
struct swap_entries swap;
|
||||
struct plain_hashmap_entry *e;
|
||||
|
|
@ -1689,13 +1713,13 @@ int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
HashmapBase *_hashmap_copy(HashmapBase *h) {
|
||||
HashmapBase *_hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS) {
|
||||
HashmapBase *copy;
|
||||
int r;
|
||||
|
||||
assert(h);
|
||||
|
||||
copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_SRC_ARGS);
|
||||
copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_PASS_ARGS);
|
||||
if (!copy)
|
||||
return NULL;
|
||||
|
||||
|
|
@ -1711,10 +1735,8 @@ HashmapBase *_hashmap_copy(HashmapBase *h) {
|
|||
assert_not_reached("Unknown hashmap type");
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
_hashmap_free(copy, false, false);
|
||||
return NULL;
|
||||
}
|
||||
if (r < 0)
|
||||
return _hashmap_free(copy, false, false);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
|
@ -1768,10 +1790,10 @@ int set_consume(Set *s, void *value) {
|
|||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int hashmap_put_strdup(Hashmap **h, const char *k, const char *v) {
|
||||
int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG_PARAMS) {
|
||||
int r;
|
||||
|
||||
r = hashmap_ensure_allocated(h, &string_hash_ops_free_free);
|
||||
r = _hashmap_ensure_allocated(h, &string_hash_ops_free_free HASHMAP_DEBUG_PASS_ARGS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
@ -1803,14 +1825,14 @@ int hashmap_put_strdup(Hashmap **h, const char *k, const char *v) {
|
|||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int set_put_strdup(Set **s, const char *p) {
|
||||
int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS) {
|
||||
char *c;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(p);
|
||||
|
||||
r = set_ensure_allocated(s, &string_hash_ops_free);
|
||||
r = _set_ensure_allocated(s, &string_hash_ops_free HASHMAP_DEBUG_PASS_ARGS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
@ -1824,14 +1846,14 @@ int set_put_strdup(Set **s, const char *p) {
|
|||
return set_consume(*s, c);
|
||||
}
|
||||
|
||||
int set_put_strdupv(Set **s, char **l) {
|
||||
int _set_put_strdupv(Set **s, char **l HASHMAP_DEBUG_PARAMS) {
|
||||
int n = 0, r;
|
||||
char **i;
|
||||
|
||||
assert(s);
|
||||
|
||||
STRV_FOREACH(i, l) {
|
||||
r = set_put_strdup(s, *i);
|
||||
r = _set_put_strdup(s, *i HASHMAP_DEBUG_PASS_ARGS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
|||
|
|
@ -128,13 +128,9 @@ static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h)
|
|||
IteratedCache *iterated_cache_free(IteratedCache *cache);
|
||||
int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries);
|
||||
|
||||
HashmapBase *_hashmap_copy(HashmapBase *h);
|
||||
static inline Hashmap *hashmap_copy(Hashmap *h) {
|
||||
return (Hashmap*) _hashmap_copy(HASHMAP_BASE(h));
|
||||
}
|
||||
static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) {
|
||||
return (OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h));
|
||||
}
|
||||
HashmapBase *_hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS);
|
||||
#define hashmap_copy(h) ((Hashmap*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS))
|
||||
#define ordered_hashmap_copy(h) ((OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS))
|
||||
|
||||
int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
|
||||
int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
|
||||
|
|
@ -154,7 +150,8 @@ static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *
|
|||
return hashmap_put(PLAIN_HASHMAP(h), key, value);
|
||||
}
|
||||
|
||||
int hashmap_put_strdup(Hashmap **h, const char *k, const char *v);
|
||||
int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG_PARAMS);
|
||||
#define hashmap_put_strdup(h, k, v) _hashmap_put_strdup(h, k, v HASHMAP_DEBUG_SRC_ARGS)
|
||||
|
||||
int hashmap_update(Hashmap *h, const void *key, void *value);
|
||||
static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include "macro.h"
|
||||
#include "parse-util.h"
|
||||
#include "random-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strxcpyx.h"
|
||||
#include "util.h"
|
||||
|
||||
|
|
@ -109,11 +110,7 @@ int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_
|
|||
return in4_addr_equal(&a->in, &b->in);
|
||||
|
||||
if (family == AF_INET6)
|
||||
return
|
||||
a->in6.s6_addr32[0] == b->in6.s6_addr32[0] &&
|
||||
a->in6.s6_addr32[1] == b->in6.s6_addr32[1] &&
|
||||
a->in6.s6_addr32[2] == b->in6.s6_addr32[2] &&
|
||||
a->in6.s6_addr32[3] == b->in6.s6_addr32[3];
|
||||
return IN6_ARE_ADDR_EQUAL(&a->in6, &b->in6);
|
||||
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
|
@ -451,6 +448,61 @@ fallback:
|
|||
return in_addr_to_string(family, u, ret);
|
||||
}
|
||||
|
||||
int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret) {
|
||||
_cleanup_free_ char *ip_str = NULL, *x = NULL;
|
||||
int r;
|
||||
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
assert(u);
|
||||
assert(ret);
|
||||
|
||||
/* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly
|
||||
* handle IPv6 link-local addresses. */
|
||||
|
||||
r = in_addr_to_string(family, u, &ip_str);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (family == AF_INET6) {
|
||||
r = in_addr_is_link_local(family, u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
ifindex = 0;
|
||||
} else
|
||||
ifindex = 0; /* For IPv4 address, ifindex is always ignored. */
|
||||
|
||||
if (port == 0 && ifindex == 0 && isempty(server_name)) {
|
||||
*ret = TAKE_PTR(ip_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *separator = isempty(server_name) ? "" : "#";
|
||||
server_name = strempty(server_name);
|
||||
|
||||
if (port > 0) {
|
||||
if (family == AF_INET6) {
|
||||
if (ifindex > 0)
|
||||
r = asprintf(&x, "[%s]:%"PRIu16"%%%i%s%s", ip_str, port, ifindex, separator, server_name);
|
||||
else
|
||||
r = asprintf(&x, "[%s]:%"PRIu16"%s%s", ip_str, port, separator, server_name);
|
||||
} else
|
||||
r = asprintf(&x, "%s:%"PRIu16"%s%s", ip_str, port, separator, server_name);
|
||||
} else {
|
||||
if (ifindex > 0)
|
||||
r = asprintf(&x, "%s%%%i%s%s", ip_str, ifindex, separator, server_name);
|
||||
else {
|
||||
x = strjoin(ip_str, separator, server_name);
|
||||
r = x ? 0 : -ENOMEM;
|
||||
}
|
||||
}
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
|
||||
union in_addr_union buffer;
|
||||
assert(s);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen
|
|||
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
|
||||
int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret);
|
||||
int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret);
|
||||
int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret);
|
||||
int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
|
||||
int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret);
|
||||
|
||||
|
|
|
|||
|
|
@ -169,3 +169,18 @@
|
|||
|
||||
#define LIST_IS_EMPTY(head) \
|
||||
(!(head))
|
||||
|
||||
/* Join two lists tail to head: a->b, c->d to a->b->c->d and de-initialise second list */
|
||||
#define LIST_JOIN(name,a,b) \
|
||||
do { \
|
||||
assert(b); \
|
||||
if (!(a)) \
|
||||
(a) = (b); \
|
||||
else { \
|
||||
typeof(*(a)) *_head = (b), *_tail; \
|
||||
LIST_FIND_TAIL(name, (a), _tail); \
|
||||
_tail->name##_next = _head; \
|
||||
_head->name##_prev = _tail; \
|
||||
} \
|
||||
(b) = NULL; \
|
||||
} while (false)
|
||||
|
|
|
|||
|
|
@ -89,8 +89,11 @@ void log_close(void);
|
|||
void log_forget_fds(void);
|
||||
|
||||
void log_parse_environment_realm(LogRealm realm);
|
||||
void log_parse_environment_cli_realm(LogRealm realm);
|
||||
#define log_parse_environment() \
|
||||
log_parse_environment_realm(LOG_REALM)
|
||||
#define log_parse_environment_cli() \
|
||||
log_parse_environment_cli_realm(LOG_REALM)
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int log_dispatch_internal(
|
||||
|
|
@ -359,3 +362,4 @@ int log_syntax_invalid_utf8_internal(
|
|||
#define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG)
|
||||
|
||||
void log_setup_service(void);
|
||||
void log_setup_cli(void);
|
||||
|
|
|
|||
|
|
@ -295,6 +295,15 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) {
|
|||
UNIQ_T(A, aq) < UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \
|
||||
})
|
||||
|
||||
/* evaluates to (void) if _A or _B are not constant or of different types */
|
||||
#define CONST_MIN(_A, _B) \
|
||||
(__builtin_choose_expr( \
|
||||
__builtin_constant_p(_A) && \
|
||||
__builtin_constant_p(_B) && \
|
||||
__builtin_types_compatible_p(typeof(_A), typeof(_B)), \
|
||||
((_A) < (_B)) ? (_A) : (_B), \
|
||||
VOID_0))
|
||||
|
||||
#define MIN3(x, y, z) \
|
||||
({ \
|
||||
const typeof(x) _c = MIN(x, y); \
|
||||
|
|
@ -538,6 +547,12 @@ static inline int __coverity_check_and_return__(int condition) {
|
|||
(y) = (_t); \
|
||||
} while (false)
|
||||
|
||||
/* Iterates through a specified list of pointers. Accepts NULL pointers, but uses (void*) -1 as internal marker for EOL. */
|
||||
#define FOREACH_POINTER(p, x, ...) \
|
||||
for (typeof(p) *_l = (typeof(p)[]) { ({ p = x; }), ##__VA_ARGS__, (void*) -1 }; \
|
||||
p != (typeof(p)) (void*) -1; \
|
||||
p = *(++_l))
|
||||
|
||||
/* Define C11 thread_local attribute even on older gcc compiler
|
||||
* version */
|
||||
#ifndef thread_local
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
size_t page_size(void) _pure_;
|
||||
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
|
||||
#define PAGE_ALIGN_DOWN(l) ((l) & ~(page_size() - 1))
|
||||
#define PAGE_OFFSET(l) ((l) & (page_size() - 1))
|
||||
|
||||
/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */
|
||||
static inline void memcpy_safe(void *dst, const void *src, size_t n) {
|
||||
|
|
|
|||
|
|
@ -649,10 +649,8 @@ int find_binary(const char *name, char **ret) {
|
|||
if (access(j, X_OK) >= 0) {
|
||||
/* Found it! */
|
||||
|
||||
if (ret) {
|
||||
*ret = path_simplify(j, false);
|
||||
j = NULL;
|
||||
}
|
||||
if (ret)
|
||||
*ret = path_simplify(TAKE_PTR(j), false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,14 +20,16 @@
|
|||
#define procfs_file_alloca(pid, field) \
|
||||
({ \
|
||||
pid_t _pid_ = (pid); \
|
||||
const char *_r_; \
|
||||
const char *_field_ = (field); \
|
||||
char *_r_; \
|
||||
if (_pid_ == 0) { \
|
||||
_r_ = ("/proc/self/" field); \
|
||||
_r_ = newa(char, STRLEN("/proc/self/") + strlen(_field_) + 1); \
|
||||
strcpy(stpcpy(_r_, "/proc/self/"), _field_); \
|
||||
} else { \
|
||||
_r_ = newa(char, STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \
|
||||
sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \
|
||||
_r_ = newa(char, STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + strlen(_field_) + 1); \
|
||||
sprintf(_r_, "/proc/" PID_FMT "/%s", _pid_, _field_); \
|
||||
} \
|
||||
_r_; \
|
||||
(const char*) _r_; \
|
||||
})
|
||||
|
||||
typedef enum ProcessCmdlineFlags {
|
||||
|
|
|
|||
|
|
@ -9,11 +9,13 @@
|
|||
#include <elf.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/random.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#if HAVE_SYS_AUXV_H
|
||||
|
|
@ -448,4 +450,37 @@ size_t random_pool_size(void) {
|
|||
/* Use the minimum as default, if we can't retrieve the correct value */
|
||||
return RANDOM_POOL_SIZE_MIN;
|
||||
}
|
||||
|
||||
int random_write_entropy(int fd, const void *seed, size_t size, bool credit) {
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(seed && size > 0);
|
||||
|
||||
if (credit) {
|
||||
_cleanup_free_ struct rand_pool_info *info = NULL;
|
||||
|
||||
/* The kernel API only accepts "int" as entropy count (which is in bits), let's avoid any
|
||||
* chance for confusion here. */
|
||||
if (size > INT_MAX / 8)
|
||||
return -EOVERFLOW;
|
||||
|
||||
info = malloc(offsetof(struct rand_pool_info, buf) + size);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
info->entropy_count = size * 8;
|
||||
info->buf_size = size;
|
||||
memcpy(info->buf, seed, size);
|
||||
|
||||
if (ioctl(fd, RNDADDENTROPY, info) < 0)
|
||||
return -errno;
|
||||
} else {
|
||||
r = loop_write(fd, seed, size, false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -38,3 +38,5 @@ int rdrand(unsigned long *ret);
|
|||
#define RANDOM_POOL_SIZE_MAX (10U*1024U*1024U)
|
||||
|
||||
size_t random_pool_size(void);
|
||||
|
||||
int random_write_entropy(int fd, const void *seed, size_t size, bool credit);
|
||||
|
|
|
|||
|
|
@ -26,9 +26,7 @@ static inline Set *set_free_free(Set *s) {
|
|||
|
||||
/* no set_free_free_free */
|
||||
|
||||
static inline Set *set_copy(Set *s) {
|
||||
return (Set*) _hashmap_copy(HASHMAP_BASE(s));
|
||||
}
|
||||
#define set_copy(s) ((Set*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS))
|
||||
|
||||
int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
|
||||
#define set_ensure_allocated(h, ops) _set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
|
||||
|
|
@ -120,9 +118,19 @@ static inline char **set_get_strv(Set *s) {
|
|||
return _hashmap_get_strv(HASHMAP_BASE(s));
|
||||
}
|
||||
|
||||
int _set_ensure_put(Set **s, const struct hash_ops *hash_ops, const void *key HASHMAP_DEBUG_PARAMS);
|
||||
#define set_ensure_put(s, hash_ops, key) _set_ensure_put(s, hash_ops, key HASHMAP_DEBUG_SRC_ARGS)
|
||||
|
||||
int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HASHMAP_DEBUG_PARAMS);
|
||||
#define set_ensure_consume(s, hash_ops, key) _set_ensure_consume(s, hash_ops, key HASHMAP_DEBUG_SRC_ARGS)
|
||||
|
||||
int set_consume(Set *s, void *value);
|
||||
int set_put_strdup(Set **s, const char *p);
|
||||
int set_put_strdupv(Set **s, char **l);
|
||||
|
||||
int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS);
|
||||
#define set_put_strdup(s, p) _set_put_strdup(s, p HASHMAP_DEBUG_SRC_ARGS)
|
||||
int _set_put_strdupv(Set **s, char **l HASHMAP_DEBUG_PARAMS);
|
||||
#define set_put_strdupv(s, l) _set_put_strdupv(s, l HASHMAP_DEBUG_SRC_ARGS)
|
||||
|
||||
int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags);
|
||||
|
||||
#define SET_FOREACH(e, s, i) \
|
||||
|
|
|
|||
|
|
@ -47,9 +47,21 @@ siphash24 (const void *in, size_t inlen, const uint8_t k[16])
|
|||
|
||||
void siphash24_init(struct siphash *state, const uint8_t k[static 16]);
|
||||
void siphash24_compress(const void *in, size_t inlen, struct siphash *state);
|
||||
void siphash24_compress_boolean(bool in, struct siphash *state);
|
||||
#define siphash24_compress_byte(byte, state) siphash24_compress((const uint8_t[]) { (byte) }, 1, (state))
|
||||
|
||||
static inline void siphash24_compress_boolean(bool in, struct siphash *state) {
|
||||
uint8_t i = in;
|
||||
|
||||
siphash24_compress(&i, sizeof i, state);
|
||||
}
|
||||
|
||||
static inline void siphash24_compress_string(const char *in, struct siphash *state) {
|
||||
if (!in)
|
||||
return;
|
||||
|
||||
siphash24_compress(in, strlen(in), state);
|
||||
}
|
||||
|
||||
uint64_t siphash24_finalize(struct siphash *state);
|
||||
|
||||
uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[static 16]);
|
||||
|
|
|
|||
|
|
@ -1081,6 +1081,7 @@ int sockaddr_un_unlink(const struct sockaddr_un *sa) {
|
|||
|
||||
return 1;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) {
|
||||
size_t l;
|
||||
|
|
@ -1125,7 +1126,6 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) {
|
|||
return (int) (offsetof(struct sockaddr_un, sun_path) + l + 1); /* include trailing NUL in size */
|
||||
}
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int socket_bind_to_ifname(int fd, const char *ifname) {
|
||||
assert(fd >= 0);
|
||||
|
|
@ -1140,6 +1140,7 @@ int socket_bind_to_ifname(int fd, const char *ifname) {
|
|||
|
||||
int socket_bind_to_ifindex(int fd, int ifindex) {
|
||||
char ifname[IF_NAMESIZE + 1];
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
|
|
@ -1151,10 +1152,9 @@ int socket_bind_to_ifindex(int fd, int ifindex) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTOIFINDEX, &ifindex, sizeof(ifindex)) >= 0)
|
||||
return 0;
|
||||
if (errno != ENOPROTOOPT)
|
||||
return -errno;
|
||||
r = setsockopt_int(fd, SOL_SOCKET, SO_BINDTOIFINDEX, ifindex);
|
||||
if (r != -ENOPROTOOPT)
|
||||
return r;
|
||||
|
||||
/* Fall back to SO_BINDTODEVICE on kernels < 5.0 which didn't have SO_BINDTOIFINDEX */
|
||||
if (!format_ifname(ifindex, ifname))
|
||||
|
|
|
|||
|
|
@ -6,12 +6,10 @@
|
|||
#include "string-util.h"
|
||||
|
||||
ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) {
|
||||
size_t i;
|
||||
|
||||
if (!key)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
if (streq_ptr(table[i], key))
|
||||
return (ssize_t) i;
|
||||
|
||||
|
|
|
|||
|
|
@ -84,43 +84,82 @@ triple_timestamp* triple_timestamp_get(triple_timestamp *ts) {
|
|||
return ts;
|
||||
}
|
||||
|
||||
static usec_t map_clock_usec_internal(usec_t from, usec_t from_base, usec_t to_base) {
|
||||
|
||||
/* Maps the time 'from' between two clocks, based on a common reference point where the first clock
|
||||
* is at 'from_base' and the second clock at 'to_base'. Basically calculates:
|
||||
*
|
||||
* from - from_base + to_base
|
||||
*
|
||||
* But takes care of overflows/underflows and avoids signed operations. */
|
||||
|
||||
if (from >= from_base) { /* In the future */
|
||||
usec_t delta = from - from_base;
|
||||
|
||||
if (to_base >= USEC_INFINITY - delta) /* overflow? */
|
||||
return USEC_INFINITY;
|
||||
|
||||
return to_base + delta;
|
||||
|
||||
} else { /* In the past */
|
||||
usec_t delta = from_base - from;
|
||||
|
||||
if (to_base <= delta) /* underflow? */
|
||||
return 0;
|
||||
|
||||
return to_base - delta;
|
||||
}
|
||||
}
|
||||
|
||||
usec_t map_clock_usec(usec_t from, clockid_t from_clock, clockid_t to_clock) {
|
||||
|
||||
/* Try to avoid any inaccuracy needlessly added in case we convert from effectively the same clock
|
||||
* onto itself */
|
||||
if (map_clock_id(from_clock) == map_clock_id(to_clock))
|
||||
return from;
|
||||
|
||||
/* Keep infinity as is */
|
||||
if (from == USEC_INFINITY)
|
||||
return from;
|
||||
|
||||
return map_clock_usec_internal(from, now(from_clock), now(to_clock));
|
||||
}
|
||||
|
||||
dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
|
||||
int64_t delta;
|
||||
assert(ts);
|
||||
|
||||
if (u == USEC_INFINITY || u <= 0) {
|
||||
if (u == USEC_INFINITY || u == 0) {
|
||||
ts->realtime = ts->monotonic = u;
|
||||
return ts;
|
||||
}
|
||||
|
||||
ts->realtime = u;
|
||||
|
||||
delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
|
||||
ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta);
|
||||
|
||||
ts->monotonic = map_clock_usec(u, CLOCK_REALTIME, CLOCK_MONOTONIC);
|
||||
return ts;
|
||||
}
|
||||
|
||||
triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u) {
|
||||
int64_t delta;
|
||||
usec_t nowr;
|
||||
|
||||
assert(ts);
|
||||
|
||||
if (u == USEC_INFINITY || u <= 0) {
|
||||
if (u == USEC_INFINITY || u == 0) {
|
||||
ts->realtime = ts->monotonic = ts->boottime = u;
|
||||
return ts;
|
||||
}
|
||||
|
||||
nowr = now(CLOCK_REALTIME);
|
||||
|
||||
ts->realtime = u;
|
||||
delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
|
||||
ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta);
|
||||
ts->boottime = clock_boottime_supported() ? usec_sub_signed(now(CLOCK_BOOTTIME), delta) : USEC_INFINITY;
|
||||
ts->monotonic = map_clock_usec_internal(u, nowr, now(CLOCK_MONOTONIC));
|
||||
ts->boottime = clock_boottime_supported() ?
|
||||
map_clock_usec_internal(u, nowr, now(CLOCK_BOOTTIME)) :
|
||||
USEC_INFINITY;
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
|
||||
int64_t delta;
|
||||
assert(ts);
|
||||
|
||||
if (u == USEC_INFINITY) {
|
||||
|
|
@ -129,25 +168,28 @@ dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
|
|||
}
|
||||
|
||||
ts->monotonic = u;
|
||||
delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
|
||||
ts->realtime = usec_sub_signed(now(CLOCK_REALTIME), delta);
|
||||
|
||||
ts->realtime = map_clock_usec(u, CLOCK_MONOTONIC, CLOCK_REALTIME);
|
||||
return ts;
|
||||
}
|
||||
|
||||
dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) {
|
||||
int64_t delta;
|
||||
clockid_t cid;
|
||||
usec_t nowm;
|
||||
|
||||
if (u == USEC_INFINITY) {
|
||||
ts->realtime = ts->monotonic = USEC_INFINITY;
|
||||
return ts;
|
||||
}
|
||||
|
||||
dual_timestamp_get(ts);
|
||||
delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u;
|
||||
ts->realtime = usec_sub_signed(ts->realtime, delta);
|
||||
ts->monotonic = usec_sub_signed(ts->monotonic, delta);
|
||||
cid = clock_boottime_or_monotonic();
|
||||
nowm = now(cid);
|
||||
|
||||
if (cid == CLOCK_MONOTONIC)
|
||||
ts->monotonic = u;
|
||||
else
|
||||
ts->monotonic = map_clock_usec_internal(u, nowm, now(CLOCK_MONOTONIC));
|
||||
|
||||
ts->realtime = map_clock_usec_internal(u, nowm, now(CLOCK_REALTIME));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ typedef struct triple_timestamp {
|
|||
usec_t boottime;
|
||||
} triple_timestamp;
|
||||
|
||||
#define USEC_INFINITY ((usec_t) -1)
|
||||
#define NSEC_INFINITY ((nsec_t) -1)
|
||||
#define USEC_INFINITY ((usec_t) UINT64_MAX)
|
||||
#define NSEC_INFINITY ((nsec_t) UINT64_MAX)
|
||||
|
||||
#define MSEC_PER_SEC 1000ULL
|
||||
#define USEC_PER_SEC ((usec_t) 1000000ULL)
|
||||
|
|
@ -67,6 +67,8 @@ typedef struct triple_timestamp {
|
|||
usec_t now(clockid_t clock);
|
||||
nsec_t now_nsec(clockid_t clock);
|
||||
|
||||
usec_t map_clock_usec(usec_t from, clockid_t from_clock, clockid_t to_clock);
|
||||
|
||||
dual_timestamp* dual_timestamp_get(dual_timestamp *ts);
|
||||
dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u);
|
||||
dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u);
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
|
|||
assert((flags & O_EXCL) == 0);
|
||||
|
||||
/* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in
|
||||
* which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in
|
||||
* which case "ret_path" will be returned as NULL. If not possible the temporary path name used is returned in
|
||||
* "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
|
||||
|
||||
fd = open_parent(target, O_TMPFILE|flags, 0640);
|
||||
|
|
|
|||
|
|
@ -82,6 +82,3 @@ int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const vo
|
|||
int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease);
|
||||
|
||||
int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len);
|
||||
|
||||
int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
|
||||
int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file);
|
||||
|
|
|
|||
|
|
@ -109,10 +109,11 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat
|
|||
int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen,
|
||||
struct in6_addr **addrs, size_t count,
|
||||
size_t *allocated);
|
||||
int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen,
|
||||
char ***str_arr);
|
||||
int dhcp6_option_parse_domainname_list(const uint8_t *optval, uint16_t optlen,
|
||||
char ***str_arr);
|
||||
int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char **str);
|
||||
|
||||
int dhcp6_network_bind_udp_socket(int index, struct in6_addr *address);
|
||||
int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *address);
|
||||
int dhcp6_network_send_udp_socket(int s, struct in6_addr *address,
|
||||
const void *packet, size_t len);
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ struct sd_dhcp6_lease {
|
|||
size_t ntp_allocated;
|
||||
char **ntp_fqdn;
|
||||
size_t ntp_fqdn_count;
|
||||
char *fqdn;
|
||||
};
|
||||
|
||||
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire);
|
||||
|
|
@ -57,5 +58,6 @@ int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
|
|||
int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen);
|
||||
int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval,
|
||||
size_t optlen) ;
|
||||
int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
|
||||
|
||||
int dhcp6_lease_new(sd_dhcp6_lease **ret);
|
||||
|
|
|
|||
|
|
@ -19,16 +19,16 @@
|
|||
#include "fd-util.h"
|
||||
#include "socket-util.h"
|
||||
|
||||
int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
|
||||
int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *local_address) {
|
||||
union sockaddr_union src = {
|
||||
.in6.sin6_family = AF_INET6,
|
||||
.in6.sin6_port = htobe16(DHCP6_PORT_CLIENT),
|
||||
.in6.sin6_scope_id = index,
|
||||
.in6.sin6_scope_id = ifindex,
|
||||
};
|
||||
_cleanup_close_ int s = -1;
|
||||
int r;
|
||||
|
||||
assert(index > 0);
|
||||
assert(ifindex > 0);
|
||||
assert(local_address);
|
||||
|
||||
src.in6.sin6_addr = *local_address;
|
||||
|
|
|
|||
|
|
@ -644,60 +644,104 @@ int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen,
|
|||
return count;
|
||||
}
|
||||
|
||||
int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char ***str_arr) {
|
||||
size_t pos = 0, idx = 0;
|
||||
static int parse_domain(const uint8_t **data, uint16_t *len, char **out_domain) {
|
||||
_cleanup_free_ char *ret = NULL;
|
||||
size_t n = 0, allocated = 0;
|
||||
const uint8_t *optval = *data;
|
||||
uint16_t optlen = *len;
|
||||
bool first = true;
|
||||
int r;
|
||||
|
||||
if (optlen <= 1)
|
||||
return -ENODATA;
|
||||
|
||||
for (;;) {
|
||||
const char *label;
|
||||
uint8_t c;
|
||||
|
||||
if (optlen == 0)
|
||||
break;
|
||||
|
||||
c = *optval;
|
||||
optval++;
|
||||
optlen--;
|
||||
|
||||
if (c == 0)
|
||||
/* End label */
|
||||
break;
|
||||
if (c > 63)
|
||||
return -EBADMSG;
|
||||
if (c > optlen)
|
||||
return -EMSGSIZE;
|
||||
|
||||
/* Literal label */
|
||||
label = (const char *)optval;
|
||||
optval += c;
|
||||
optlen -= c;
|
||||
|
||||
if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
|
||||
return -ENOMEM;
|
||||
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
ret[n++] = '.';
|
||||
|
||||
r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
n += r;
|
||||
}
|
||||
|
||||
if (n) {
|
||||
if (!GREEDY_REALLOC(ret, allocated, n + 1))
|
||||
return -ENOMEM;
|
||||
ret[n] = 0;
|
||||
}
|
||||
|
||||
*out_domain = TAKE_PTR(ret);
|
||||
*data = optval;
|
||||
*len = optlen;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char **str) {
|
||||
_cleanup_free_ char *domain = NULL;
|
||||
int r;
|
||||
|
||||
r = parse_domain(&optval, &optlen, &domain);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -ENODATA;
|
||||
if (optlen != 0)
|
||||
return -EINVAL;
|
||||
|
||||
*str = TAKE_PTR(domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_option_parse_domainname_list(const uint8_t *optval, uint16_t optlen, char ***str_arr) {
|
||||
size_t idx = 0;
|
||||
_cleanup_strv_free_ char **names = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(optlen > 1, -ENODATA);
|
||||
assert_return(optval[optlen - 1] == '\0', -EINVAL);
|
||||
if (optlen <= 1)
|
||||
return -ENODATA;
|
||||
if (optval[optlen - 1] != '\0')
|
||||
return -EINVAL;
|
||||
|
||||
while (pos < optlen) {
|
||||
while (optlen > 0) {
|
||||
_cleanup_free_ char *ret = NULL;
|
||||
size_t n = 0, allocated = 0;
|
||||
bool first = true;
|
||||
|
||||
for (;;) {
|
||||
const char *label;
|
||||
uint8_t c;
|
||||
|
||||
c = optval[pos++];
|
||||
|
||||
if (c == 0)
|
||||
/* End of name */
|
||||
break;
|
||||
if (c > 63)
|
||||
return -EBADMSG;
|
||||
|
||||
/* Literal label */
|
||||
label = (const char *)&optval[pos];
|
||||
pos += c;
|
||||
if (pos >= optlen)
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
|
||||
return -ENOMEM;
|
||||
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
ret[n++] = '.';
|
||||
|
||||
r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
n += r;
|
||||
}
|
||||
|
||||
if (n == 0)
|
||||
r = parse_domain(&optval, &optlen, &ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
if (!GREEDY_REALLOC(ret, allocated, n + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
ret[n] = 0;
|
||||
|
||||
r = strv_extend(&names, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
|
|||
|
|
@ -62,9 +62,13 @@ int deserialize_in6_addrs(struct in6_addr **addresses, const char *string);
|
|||
|
||||
/* don't include "dhcp-lease-internal.h" as it causes conflicts between netinet/ip.h and linux/ip.h */
|
||||
struct sd_dhcp_route;
|
||||
struct sd_dhcp_lease;
|
||||
|
||||
void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size);
|
||||
int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string);
|
||||
|
||||
/* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */
|
||||
int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size);
|
||||
|
||||
int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
|
||||
int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file);
|
||||
|
|
|
|||
|
|
@ -1446,7 +1446,10 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
|
|||
sd_dhcp_client *client = userdata;
|
||||
DHCP_CLIENT_DONT_DESTROY(client);
|
||||
|
||||
client->state = DHCP_STATE_RENEWING;
|
||||
if (client->lease)
|
||||
client->state = DHCP_STATE_RENEWING;
|
||||
else if (client->state != DHCP_STATE_INIT)
|
||||
client->state = DHCP_STATE_INIT_REBOOT;
|
||||
client->attempt = 0;
|
||||
|
||||
return client_initialize_time_events(client);
|
||||
|
|
@ -2017,6 +2020,9 @@ int sd_dhcp_client_send_renew(sd_dhcp_client *client) {
|
|||
assert_return(client, -EINVAL);
|
||||
assert_return(client->fd >= 0, -EINVAL);
|
||||
|
||||
if (!client->lease)
|
||||
return 0;
|
||||
|
||||
client->start_delay = 0;
|
||||
client->attempt = 1;
|
||||
client->state = DHCP_STATE_RENEWING;
|
||||
|
|
|
|||
|
|
@ -1078,7 +1078,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
|
|||
"ADDRESS", &address,
|
||||
"ROUTER", &router,
|
||||
"NETMASK", &netmask,
|
||||
"SERVER_IDENTIFIER", &server_address,
|
||||
"SERVER_ADDRESS", &server_address,
|
||||
"NEXT_SERVER", &next_server,
|
||||
"BROADCAST", &broadcast,
|
||||
"DNS", &dns,
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ int sd_dhcp6_client_set_callback(
|
|||
int sd_dhcp6_client_set_ifindex(sd_dhcp6_client *client, int ifindex) {
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(ifindex >= -1, -EINVAL);
|
||||
assert_return(ifindex > 0, -EINVAL);
|
||||
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
|
||||
|
||||
client->ifindex = ifindex;
|
||||
|
|
@ -1288,6 +1288,13 @@ static int client_parse_message(
|
|||
|
||||
break;
|
||||
|
||||
case SD_DHCP6_OPTION_FQDN:
|
||||
r = dhcp6_lease_set_fqdn(lease, optval, optlen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME:
|
||||
if (optlen != 4)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
|
|||
if (!optlen)
|
||||
return 0;
|
||||
|
||||
r = dhcp6_option_parse_domainname(optval, optlen, &domains);
|
||||
r = dhcp6_option_parse_domainname_list(optval, optlen, &domains);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
|
|
@ -296,8 +296,8 @@ int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
|
|||
break;
|
||||
|
||||
case DHCP6_NTP_SUBOPTION_SRV_FQDN:
|
||||
r = dhcp6_option_parse_domainname(subval, sublen,
|
||||
&servers);
|
||||
r = dhcp6_option_parse_domainname_list(subval, sublen,
|
||||
&servers);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
|
|
@ -367,6 +367,38 @@ int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) {
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval,
|
||||
size_t optlen) {
|
||||
int r;
|
||||
char *fqdn;
|
||||
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(optval, -EINVAL);
|
||||
|
||||
if (optlen < 2)
|
||||
return -ENODATA;
|
||||
|
||||
/* Ignore the flags field, it doesn't carry any useful
|
||||
information for clients. */
|
||||
r = dhcp6_option_parse_domainname(optval + 1, optlen - 1, &fqdn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return free_and_replace(lease->fqdn, fqdn);
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **fqdn) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(fqdn, -EINVAL);
|
||||
|
||||
if (lease->fqdn) {
|
||||
*fqdn = lease->fqdn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
|
||||
assert(lease);
|
||||
|
||||
|
|
@ -375,6 +407,7 @@ static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
|
|||
dhcp6_lease_free_ia(&lease->pd);
|
||||
|
||||
free(lease->dns);
|
||||
free(lease->fqdn);
|
||||
|
||||
lease->domains = strv_free(lease->domains);
|
||||
|
||||
|
|
|
|||
|
|
@ -1149,6 +1149,31 @@ _public_ int sd_event_add_time(
|
|||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
_public_ int sd_event_add_time_relative(
|
||||
sd_event *e,
|
||||
sd_event_source **ret,
|
||||
clockid_t clock,
|
||||
uint64_t usec,
|
||||
uint64_t accuracy,
|
||||
sd_event_time_handler_t callback,
|
||||
void *userdata) {
|
||||
|
||||
usec_t t;
|
||||
int r;
|
||||
|
||||
/* Same as sd_event_add_time() but operates relative to the event loop's current point in time, and
|
||||
* checks for overflow. */
|
||||
|
||||
r = sd_event_now(e, clock, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (usec >= USEC_INFINITY - t)
|
||||
return -EOVERFLOW;
|
||||
|
||||
return sd_event_add_time(e, ret, clock, t + usec, accuracy, callback, userdata);
|
||||
}
|
||||
|
||||
static int signal_exit_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
||||
assert(s);
|
||||
|
||||
|
|
@ -1454,10 +1479,6 @@ _public_ int sd_event_add_post(
|
|||
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
||||
assert_return(!event_pid_changed(e), -ECHILD);
|
||||
|
||||
r = set_ensure_allocated(&e->post_sources, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
s = source_new(e, !ret, SOURCE_POST);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
|
@ -1466,9 +1487,10 @@ _public_ int sd_event_add_post(
|
|||
s->userdata = userdata;
|
||||
s->enabled = SD_EVENT_ON;
|
||||
|
||||
r = set_put(e->post_sources, s);
|
||||
r = set_ensure_put(&e->post_sources, NULL, s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
assert(r > 0);
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
|
|
@ -2409,6 +2431,23 @@ _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_set_time_relative(sd_event_source *s, uint64_t usec) {
|
||||
usec_t t;
|
||||
int r;
|
||||
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM);
|
||||
|
||||
r = sd_event_now(s->event, event_source_type_to_clock(s->type), &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (usec >= USEC_INFINITY - t)
|
||||
return -EOVERFLOW;
|
||||
|
||||
return sd_event_source_set_time(s, t + usec);
|
||||
}
|
||||
|
||||
_public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(usec, -EINVAL);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const struct in6_addr **addrs)
|
|||
int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains);
|
||||
int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, const struct in6_addr **addrs);
|
||||
int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn);
|
||||
int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **fqdn);
|
||||
|
||||
sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease);
|
||||
sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease);
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ sd_event* sd_event_unref(sd_event *e);
|
|||
|
||||
int sd_event_add_io(sd_event *e, sd_event_source **s, int fd, uint32_t events, sd_event_io_handler_t callback, void *userdata);
|
||||
int sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata);
|
||||
int sd_event_add_time_relative(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata);
|
||||
int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_signal_handler_t callback, void *userdata);
|
||||
int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata);
|
||||
int sd_event_add_child_pidfd(sd_event *e, sd_event_source **s, int pidfd, int options, sd_event_child_handler_t callback, void *userdata);
|
||||
|
|
@ -138,6 +139,7 @@ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events);
|
|||
int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents);
|
||||
int sd_event_source_get_time(sd_event_source *s, uint64_t *usec);
|
||||
int sd_event_source_set_time(sd_event_source *s, uint64_t usec);
|
||||
int sd_event_source_set_time_relative(sd_event_source *s, uint64_t usec);
|
||||
int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec);
|
||||
int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec);
|
||||
int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue