mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-05 01:47:58 +02:00
systemd: merge branch systemd into master
https://github.com/NetworkManager/NetworkManager/pull/186
This commit is contained in:
commit
4791782f46
36 changed files with 621 additions and 435 deletions
|
|
@ -280,7 +280,7 @@ int same_fd(int a, int b) {
|
|||
return true;
|
||||
if (r > 0)
|
||||
return false;
|
||||
if (errno != ENOSYS)
|
||||
if (!IN_SET(errno, ENOSYS, EACCES, EPERM))
|
||||
return -errno;
|
||||
|
||||
/* We don't have kcmp(), use fstat() instead. */
|
||||
|
|
|
|||
|
|
@ -1505,6 +1505,7 @@ int open_serialization_fd(const char *ident) {
|
|||
}
|
||||
|
||||
int link_tmpfile(int fd, const char *path, const char *target) {
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(target);
|
||||
|
|
@ -1517,8 +1518,9 @@ int link_tmpfile(int fd, const char *path, const char *target) {
|
|||
* operation currently (renameat2() does), and there is no nice way to emulate this. */
|
||||
|
||||
if (path) {
|
||||
if (rename_noreplace(AT_FDCWD, path, AT_FDCWD, target) < 0)
|
||||
return -errno;
|
||||
r = rename_noreplace(AT_FDCWD, path, AT_FDCWD, target);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
char proc_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
|
||||
|
||||
|
|
|
|||
|
|
@ -92,41 +92,44 @@ int rmdir_parents(const char *path, const char *stop) {
|
|||
}
|
||||
|
||||
int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
|
||||
struct stat buf;
|
||||
int ret;
|
||||
int r;
|
||||
|
||||
ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE);
|
||||
if (ret >= 0)
|
||||
/* Try the ideal approach first */
|
||||
if (renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE) >= 0)
|
||||
return 0;
|
||||
|
||||
/* renameat2() exists since Linux 3.15, btrfs added support for it later.
|
||||
* If it is not implemented, fallback to another method. */
|
||||
if (!IN_SET(errno, EINVAL, ENOSYS))
|
||||
/* renameat2() exists since Linux 3.15, btrfs and FAT added support for it later. If it is not implemented,
|
||||
* fall back to a different method. */
|
||||
if (!IN_SET(errno, EINVAL, ENOSYS, ENOTTY))
|
||||
return -errno;
|
||||
|
||||
/* The link()/unlink() fallback does not work on directories. But
|
||||
* renameat() without RENAME_NOREPLACE gives the same semantics on
|
||||
* directories, except when newpath is an *empty* directory. This is
|
||||
* good enough. */
|
||||
ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW);
|
||||
if (ret >= 0 && S_ISDIR(buf.st_mode)) {
|
||||
ret = renameat(olddirfd, oldpath, newdirfd, newpath);
|
||||
return ret >= 0 ? 0 : -errno;
|
||||
/* Let's try to use linkat()+unlinkat() as fallback. This doesn't work on directories and on some file systems
|
||||
* that do not support hard links (such as FAT, most prominently), but for files it's pretty close to what we
|
||||
* want — though not atomic (i.e. for a short period both the new and the old filename will exist). */
|
||||
if (linkat(olddirfd, oldpath, newdirfd, newpath, 0) >= 0) {
|
||||
|
||||
if (unlinkat(olddirfd, oldpath, 0) < 0) {
|
||||
r = -errno; /* Backup errno before the following unlinkat() alters it */
|
||||
(void) unlinkat(newdirfd, newpath, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If it is not a directory, use the link()/unlink() fallback. */
|
||||
ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0);
|
||||
if (ret < 0)
|
||||
if (!IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM)) /* FAT returns EPERM on link()… */
|
||||
return -errno;
|
||||
|
||||
ret = unlinkat(olddirfd, oldpath, 0);
|
||||
if (ret < 0) {
|
||||
/* backup errno before the following unlinkat() alters it */
|
||||
ret = errno;
|
||||
(void) unlinkat(newdirfd, newpath, 0);
|
||||
errno = ret;
|
||||
/* OK, neither RENAME_NOREPLACE nor linkat()+unlinkat() worked. Let's then fallback to the racy TOCTOU
|
||||
* vulnerable accessat(F_OK) check followed by classic, replacing renameat(), we have nothing better. */
|
||||
|
||||
if (faccessat(newdirfd, newpath, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
|
||||
return -EEXIST;
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
|
||||
if (renameat(olddirfd, oldpath, newdirfd, newpath) < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -353,12 +356,27 @@ int touch(const char *path) {
|
|||
return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
|
||||
}
|
||||
|
||||
int symlink_idempotent(const char *from, const char *to) {
|
||||
int symlink_idempotent(const char *from, const char *to, bool make_relative) {
|
||||
_cleanup_free_ char *relpath = NULL;
|
||||
int r;
|
||||
|
||||
assert(from);
|
||||
assert(to);
|
||||
|
||||
if (make_relative) {
|
||||
_cleanup_free_ char *parent = NULL;
|
||||
|
||||
parent = dirname_malloc(to);
|
||||
if (!parent)
|
||||
return -ENOMEM;
|
||||
|
||||
r = path_make_relative(parent, from, &relpath);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
from = relpath;
|
||||
}
|
||||
|
||||
if (symlink(from, to) < 0) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ int fd_warn_permissions(const char *path, int fd);
|
|||
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
|
||||
int touch(const char *path);
|
||||
|
||||
int symlink_idempotent(const char *from, const char *to);
|
||||
int symlink_idempotent(const char *from, const char *to, bool make_relative);
|
||||
|
||||
int symlink_atomic(const char *from, const char *to);
|
||||
int mknod_atomic(const char *path, mode_t mode, dev_t dev);
|
||||
|
|
|
|||
|
|
@ -595,8 +595,7 @@ static int base64_append_width(
|
|||
|
||||
_cleanup_free_ char *x = NULL;
|
||||
char *t, *s;
|
||||
ssize_t slen, len, avail;
|
||||
int line, lines;
|
||||
ssize_t len, slen, avail, line, lines;
|
||||
|
||||
len = base64mem(p, l, &x);
|
||||
if (len <= 0)
|
||||
|
|
@ -605,6 +604,9 @@ static int base64_append_width(
|
|||
lines = DIV_ROUND_UP(len, width);
|
||||
|
||||
slen = strlen_ptr(sep);
|
||||
if (lines > (SSIZE_MAX - plen - 1 - slen) / (indent + width + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -473,4 +473,53 @@ static inline int __coverity_check__(int condition) {
|
|||
func(*p); \
|
||||
}
|
||||
|
||||
#define _DEFINE_TRIVIAL_REF_FUNC(type, name, scope) \
|
||||
scope type *name##_ref(type *p) { \
|
||||
if (!p) \
|
||||
return NULL; \
|
||||
\
|
||||
assert(p->n_ref > 0); \
|
||||
p->n_ref++; \
|
||||
return p; \
|
||||
}
|
||||
|
||||
#define _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, scope) \
|
||||
scope type *name##_unref(type *p) { \
|
||||
if (!p) \
|
||||
return NULL; \
|
||||
\
|
||||
assert(p->n_ref > 0); \
|
||||
p->n_ref--; \
|
||||
if (p->n_ref > 0) \
|
||||
return NULL; \
|
||||
\
|
||||
return free_func(p); \
|
||||
}
|
||||
|
||||
#define DEFINE_TRIVIAL_REF_FUNC(type, name) \
|
||||
_DEFINE_TRIVIAL_REF_FUNC(type, name,)
|
||||
#define DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name) \
|
||||
_DEFINE_TRIVIAL_REF_FUNC(type, name, static)
|
||||
#define DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name) \
|
||||
_DEFINE_TRIVIAL_REF_FUNC(type, name, _public_)
|
||||
|
||||
#define DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func) \
|
||||
_DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func,)
|
||||
#define DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func) \
|
||||
_DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, static)
|
||||
#define DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func) \
|
||||
_DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, _public_)
|
||||
|
||||
#define DEFINE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \
|
||||
DEFINE_TRIVIAL_REF_FUNC(type, name); \
|
||||
DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func);
|
||||
|
||||
#define DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \
|
||||
DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name); \
|
||||
DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func);
|
||||
|
||||
#define DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \
|
||||
DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name); \
|
||||
DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func);
|
||||
|
||||
#include "log.h"
|
||||
|
|
|
|||
|
|
@ -1111,11 +1111,9 @@ void valgrind_summary_hack(void) {
|
|||
#endif
|
||||
}
|
||||
|
||||
int pid_compare_func(const void *a, const void *b) {
|
||||
const pid_t *p = a, *q = b;
|
||||
|
||||
int pid_compare_func(const pid_t *a, const pid_t *b) {
|
||||
/* Suitable for usage in qsort() */
|
||||
return CMP(*p, *q);
|
||||
return CMP(*a, *b);
|
||||
}
|
||||
|
||||
int ioprio_parse_priority(const char *s, int *ret) {
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ static inline void* PID_TO_PTR(pid_t pid) {
|
|||
|
||||
void valgrind_summary_hack(void);
|
||||
|
||||
int pid_compare_func(const void *a, const void *b);
|
||||
int pid_compare_func(const pid_t *a, const pid_t *b);
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
static inline bool nice_is_valid(int n) {
|
||||
|
|
|
|||
|
|
@ -14,3 +14,41 @@ typedef struct {
|
|||
#define REFCNT_DEC(r) (__sync_sub_and_fetch(&(r)._value, 1))
|
||||
|
||||
#define REFCNT_INIT ((RefCount) { ._value = 1 })
|
||||
|
||||
#define _DEFINE_ATOMIC_REF_FUNC(type, name, scope) \
|
||||
scope type *name##_ref(type *p) { \
|
||||
if (!p) \
|
||||
return NULL; \
|
||||
\
|
||||
assert_se(REFCNT_INC(p->n_ref) >= 2); \
|
||||
return p; \
|
||||
}
|
||||
|
||||
#define _DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func, scope) \
|
||||
scope type *name##_unref(type *p) { \
|
||||
if (!p) \
|
||||
return NULL; \
|
||||
\
|
||||
if (REFCNT_DEC(p->n_ref) > 0) \
|
||||
return NULL; \
|
||||
\
|
||||
return free_func(p); \
|
||||
}
|
||||
|
||||
#define DEFINE_ATOMIC_REF_FUNC(type, name) \
|
||||
_DEFINE_ATOMIC_REF_FUNC(type, name,)
|
||||
#define DEFINE_PUBLIC_ATOMIC_REF_FUNC(type, name) \
|
||||
_DEFINE_ATOMIC_REF_FUNC(type, name, _public_)
|
||||
|
||||
#define DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func) \
|
||||
_DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func,)
|
||||
#define DEFINE_PUBLIC_ATOMIC_UNREF_FUNC(type, name, free_func) \
|
||||
_DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func, _public_)
|
||||
|
||||
#define DEFINE_ATOMIC_REF_UNREF_FUNC(type, name, free_func) \
|
||||
DEFINE_ATOMIC_REF_FUNC(type, name); \
|
||||
DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func);
|
||||
|
||||
#define DEFINE_PUBLIC_ATOMIC_REF_UNREF_FUNC(type, name, free_func) \
|
||||
DEFINE_PUBLIC_ATOMIC_REF_FUNC(type, name); \
|
||||
DEFINE_PUBLIC_ATOMIC_UNREF_FUNC(type, name, free_func);
|
||||
|
|
|
|||
|
|
@ -838,8 +838,8 @@ int fd_inc_sndbuf(int fd, size_t n) {
|
|||
/* If we have the privileges we will ignore the kernel limit. */
|
||||
|
||||
value = (int) n;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
|
||||
return -errno;
|
||||
|
||||
return 1;
|
||||
|
|
@ -856,8 +856,8 @@ int fd_inc_rcvbuf(int fd, size_t n) {
|
|||
/* If we have the privileges we will ignore the kernel limit. */
|
||||
|
||||
value = (int) n;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
|
||||
return -errno;
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@
|
|||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SPARSE_ENDIAN_H
|
||||
#define SPARSE_ENDIAN_H
|
||||
#pragma once
|
||||
|
||||
#include <byteswap.h>
|
||||
#include <endian.h>
|
||||
|
|
@ -89,5 +88,3 @@ static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t _
|
|||
|
||||
#undef __sd_bitwise
|
||||
#undef __sd_force
|
||||
|
||||
#endif /* SPARSE_ENDIAN_H */
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
|
|||
}
|
||||
|
||||
#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,scope) \
|
||||
type name##_from_string(const char *s) { \
|
||||
scope type name##_from_string(const char *s) { \
|
||||
type i; \
|
||||
unsigned u = 0; \
|
||||
if (!s) \
|
||||
|
|
|
|||
|
|
@ -1012,7 +1012,7 @@ int free_and_strdup(char **p, const char *s) {
|
|||
|
||||
assert(p);
|
||||
|
||||
/* Replaces a string pointer with an strdup()ed new string,
|
||||
/* Replaces a string pointer with a strdup()ed new string,
|
||||
* possibly freeing the old one. */
|
||||
|
||||
if (streq_ptr(*p, s))
|
||||
|
|
@ -1031,6 +1031,32 @@ int free_and_strdup(char **p, const char *s) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int free_and_strndup(char **p, const char *s, size_t l) {
|
||||
char *t;
|
||||
|
||||
assert(p);
|
||||
assert(s || l == 0);
|
||||
|
||||
/* Replaces a string pointer with a strndup()ed new string,
|
||||
* freeing the old one. */
|
||||
|
||||
if (!*p && !s)
|
||||
return 0;
|
||||
|
||||
if (*p && s && strneq(*p, s, l) && (l > strlen(*p) || (*p)[l] == '\0'))
|
||||
return 0;
|
||||
|
||||
if (s) {
|
||||
t = strndup(s, l);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
} else
|
||||
t = NULL;
|
||||
|
||||
free_and_replace(*p, t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if !HAVE_EXPLICIT_BZERO
|
||||
/*
|
||||
* Pointer to memset is volatile so that compiler must de-reference
|
||||
|
|
|
|||
|
|
@ -176,6 +176,7 @@ char *strrep(const char *s, unsigned n);
|
|||
int split_pair(const char *s, const char *sep, char **l, char **r);
|
||||
|
||||
int free_and_strdup(char **p, const char *s);
|
||||
int free_and_strndup(char **p, const char *s, size_t l);
|
||||
|
||||
/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
|
||||
static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
|
||||
|
|
@ -228,3 +229,25 @@ static inline void *memory_startswith(const void *p, size_t sz, const char *toke
|
|||
|
||||
return (uint8_t*) p + n;
|
||||
}
|
||||
|
||||
/* Like startswith_no_case(), but operates on arbitrary memory blocks.
|
||||
* It works only for ASCII strings.
|
||||
*/
|
||||
static inline void *memory_startswith_no_case(const void *p, size_t sz, const char *token) {
|
||||
size_t n, i;
|
||||
|
||||
assert(token);
|
||||
|
||||
n = strlen(token);
|
||||
if (sz < n)
|
||||
return NULL;
|
||||
|
||||
assert(p);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (ascii_tolower(((char *)p)[i]) != ascii_tolower(token[i]))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (uint8_t*) p + n;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -343,21 +343,22 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract
|
|||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
char *strv_join(char **l, const char *separator) {
|
||||
char *strv_join_prefix(char **l, const char *separator, const char *prefix) {
|
||||
char *r, *e;
|
||||
char **s;
|
||||
size_t n, k;
|
||||
size_t n, k, m;
|
||||
|
||||
if (!separator)
|
||||
separator = " ";
|
||||
|
||||
k = strlen(separator);
|
||||
m = strlen_ptr(prefix);
|
||||
|
||||
n = 0;
|
||||
STRV_FOREACH(s, l) {
|
||||
if (s != l)
|
||||
n += k;
|
||||
n += strlen(*s);
|
||||
n += m + strlen(*s);
|
||||
}
|
||||
|
||||
r = new(char, n+1);
|
||||
|
|
@ -369,6 +370,9 @@ char *strv_join(char **l, const char *separator) {
|
|||
if (s != l)
|
||||
e = stpcpy(e, separator);
|
||||
|
||||
if (prefix)
|
||||
e = stpcpy(e, prefix);
|
||||
|
||||
e = stpcpy(e, *s);
|
||||
}
|
||||
|
||||
|
|
@ -715,14 +719,12 @@ bool strv_overlap(char **a, char **b) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static int str_compare(const void *_a, const void *_b) {
|
||||
const char **a = (const char**) _a, **b = (const char**) _b;
|
||||
|
||||
static int str_compare(char * const *a, char * const *b) {
|
||||
return strcmp(*a, *b);
|
||||
}
|
||||
|
||||
char **strv_sort(char **l) {
|
||||
qsort_safe(l, strv_length(l), sizeof(char*), str_compare);
|
||||
typesafe_qsort(l, strv_length(l), str_compare);
|
||||
return l;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,10 @@ char **strv_split_newlines(const char *s);
|
|||
|
||||
int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags);
|
||||
|
||||
char *strv_join(char **l, const char *separator);
|
||||
char *strv_join_prefix(char **l, const char *separator, const char *prefix);
|
||||
static inline char *strv_join(char **l, const char *separator) {
|
||||
return strv_join_prefix(l, separator, NULL);
|
||||
}
|
||||
|
||||
char **strv_parse_nulstr(const char *s, size_t l);
|
||||
char **strv_split_nulstr(const char *s);
|
||||
|
|
|
|||
|
|
@ -65,12 +65,12 @@ static bool unichar_is_control(char32_t ch) {
|
|||
#endif /* NM_IGNORED */
|
||||
|
||||
/* count of characters used to encode one unicode char */
|
||||
static int utf8_encoded_expected_len(const char *str) {
|
||||
unsigned char c;
|
||||
static size_t utf8_encoded_expected_len(const char *str) {
|
||||
uint8_t c;
|
||||
|
||||
assert(str);
|
||||
|
||||
c = (unsigned char) str[0];
|
||||
c = (uint8_t) str[0];
|
||||
if (c < 0x80)
|
||||
return 1;
|
||||
if ((c & 0xe0) == 0xc0)
|
||||
|
|
@ -90,7 +90,7 @@ static int utf8_encoded_expected_len(const char *str) {
|
|||
/* decode one unicode char */
|
||||
int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
|
||||
char32_t unichar;
|
||||
int len, i;
|
||||
size_t len, i;
|
||||
|
||||
assert(str);
|
||||
|
||||
|
|
@ -122,6 +122,7 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
|
|||
for (i = 1; i < len; i++) {
|
||||
if (((char32_t)str[i] & 0xc0) != 0x80)
|
||||
return -EINVAL;
|
||||
|
||||
unichar <<= 6;
|
||||
unichar |= (char32_t)str[i] & 0x3f;
|
||||
}
|
||||
|
|
@ -160,22 +161,23 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
|
|||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
const char *utf8_is_valid(const char *str) {
|
||||
const uint8_t *p;
|
||||
char *utf8_is_valid(const char *str) {
|
||||
const char *p;
|
||||
|
||||
assert(str);
|
||||
|
||||
for (p = (const uint8_t*) str; *p; ) {
|
||||
p = str;
|
||||
while (*p) {
|
||||
int len;
|
||||
|
||||
len = utf8_encoded_valid_unichar((const char *)p);
|
||||
len = utf8_encoded_valid_unichar(p);
|
||||
if (len < 0)
|
||||
return NULL;
|
||||
|
||||
p += len;
|
||||
}
|
||||
|
||||
return str;
|
||||
return (char*) str;
|
||||
}
|
||||
|
||||
char *utf8_escape_invalid(const char *str) {
|
||||
|
|
@ -323,18 +325,25 @@ size_t utf8_encode_unichar(char *out_utf8, char32_t g) {
|
|||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
char *utf16_to_utf8(const void *s, size_t length) {
|
||||
char *utf16_to_utf8(const char16_t *s, size_t length /* bytes! */) {
|
||||
const uint8_t *f;
|
||||
char *r, *t;
|
||||
|
||||
r = new(char, (length * 4 + 1) / 2 + 1);
|
||||
assert(s);
|
||||
|
||||
/* Input length is in bytes, i.e. the shortest possible character takes 2 bytes. Each unicode character may
|
||||
* take up to 4 bytes in UTF-8. Let's also account for a trailing NUL byte. */
|
||||
if (length * 2 < length)
|
||||
return NULL; /* overflow */
|
||||
|
||||
r = new(char, length * 2 + 1);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
f = s;
|
||||
f = (const uint8_t*) s;
|
||||
t = r;
|
||||
|
||||
while (f < (const uint8_t*) s + length) {
|
||||
while (f + 1 < (const uint8_t*) s + length) {
|
||||
char16_t w1, w2;
|
||||
|
||||
/* see RFC 2781 section 2.2 */
|
||||
|
|
@ -344,13 +353,13 @@ char *utf16_to_utf8(const void *s, size_t length) {
|
|||
|
||||
if (!utf16_is_surrogate(w1)) {
|
||||
t += utf8_encode_unichar(t, w1);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (utf16_is_trailing_surrogate(w1))
|
||||
continue;
|
||||
else if (f >= (const uint8_t*) s + length)
|
||||
continue; /* spurious trailing surrogate, ignore */
|
||||
|
||||
if (f + 1 >= (const uint8_t*) s + length)
|
||||
break;
|
||||
|
||||
w2 = f[1] << 8 | f[0];
|
||||
|
|
@ -358,7 +367,7 @@ char *utf16_to_utf8(const void *s, size_t length) {
|
|||
|
||||
if (!utf16_is_trailing_surrogate(w2)) {
|
||||
f -= 2;
|
||||
continue;
|
||||
continue; /* surrogate missing its trailing surrogate, ignore */
|
||||
}
|
||||
|
||||
t += utf8_encode_unichar(t, utf16_surrogate_pair_to_unichar(w1, w2));
|
||||
|
|
@ -367,6 +376,79 @@ char *utf16_to_utf8(const void *s, size_t length) {
|
|||
*t = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
size_t utf16_encode_unichar(char16_t *out, char32_t c) {
|
||||
|
||||
/* Note that this encodes as little-endian. */
|
||||
|
||||
switch (c) {
|
||||
|
||||
case 0 ... 0xd7ffU:
|
||||
case 0xe000U ... 0xffffU:
|
||||
out[0] = htole16(c);
|
||||
return 1;
|
||||
|
||||
case 0x10000U ... 0x10ffffU:
|
||||
c -= 0x10000U;
|
||||
out[0] = htole16((c >> 10) + 0xd800U);
|
||||
out[1] = htole16((c & 0x3ffU) + 0xdc00U);
|
||||
return 2;
|
||||
|
||||
default: /* A surrogate (invalid) */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
char16_t *utf8_to_utf16(const char *s, size_t length) {
|
||||
char16_t *n, *p;
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
n = new(char16_t, length + 1);
|
||||
if (!n)
|
||||
return NULL;
|
||||
|
||||
p = n;
|
||||
|
||||
for (i = 0; i < length;) {
|
||||
char32_t unichar;
|
||||
size_t e;
|
||||
|
||||
e = utf8_encoded_expected_len(s + i);
|
||||
if (e <= 1) /* Invalid and single byte characters are copied as they are */
|
||||
goto copy;
|
||||
|
||||
if (i + e > length) /* sequence longer than input buffer, then copy as-is */
|
||||
goto copy;
|
||||
|
||||
r = utf8_encoded_to_unichar(s + i, &unichar);
|
||||
if (r < 0) /* sequence invalid, then copy as-is */
|
||||
goto copy;
|
||||
|
||||
p += utf16_encode_unichar(p, unichar);
|
||||
i += e;
|
||||
continue;
|
||||
|
||||
copy:
|
||||
*(p++) = htole16(s[i++]);
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t char16_strlen(const char16_t *s) {
|
||||
size_t n = 0;
|
||||
|
||||
assert(s);
|
||||
|
||||
while (*s != 0)
|
||||
n++, s++;
|
||||
|
||||
return n;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
/* expected size used to encode one unicode char */
|
||||
|
|
@ -388,8 +470,9 @@ static int utf8_unichar_to_encoded_len(char32_t unichar) {
|
|||
|
||||
/* validate one encoded unicode char and return its length */
|
||||
int utf8_encoded_valid_unichar(const char *str) {
|
||||
int len, i, r;
|
||||
char32_t unichar;
|
||||
size_t len, i;
|
||||
int r;
|
||||
|
||||
assert(str);
|
||||
|
||||
|
|
@ -411,14 +494,14 @@ int utf8_encoded_valid_unichar(const char *str) {
|
|||
return r;
|
||||
|
||||
/* check if encoded length matches encoded value */
|
||||
if (utf8_unichar_to_encoded_len(unichar) != len)
|
||||
if (utf8_unichar_to_encoded_len(unichar) != (int) len)
|
||||
return -EINVAL;
|
||||
|
||||
/* check if value has valid range */
|
||||
if (!unichar_is_valid(unichar))
|
||||
return -EINVAL;
|
||||
|
||||
return len;
|
||||
return (int) len;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
bool unichar_is_valid(char32_t c);
|
||||
|
||||
const char *utf8_is_valid(const char *s) _pure_;
|
||||
char *utf8_is_valid(const char *s) _pure_;
|
||||
char *ascii_is_valid(const char *s) _pure_;
|
||||
char *ascii_is_valid_n(const char *str, size_t len);
|
||||
|
||||
|
|
@ -27,21 +27,26 @@ char *utf8_escape_invalid(const char *s);
|
|||
char *utf8_escape_non_printable(const char *str);
|
||||
|
||||
size_t utf8_encode_unichar(char *out_utf8, char32_t g);
|
||||
char *utf16_to_utf8(const void *s, size_t length);
|
||||
size_t utf16_encode_unichar(char16_t *out, char32_t c);
|
||||
|
||||
char *utf16_to_utf8(const char16_t *s, size_t length /* bytes! */);
|
||||
char16_t *utf8_to_utf16(const char *s, size_t length);
|
||||
|
||||
size_t char16_strlen(const char16_t *s); /* returns the number of 16bit words in the string (not bytes!) */
|
||||
|
||||
int utf8_encoded_valid_unichar(const char *str);
|
||||
int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar);
|
||||
|
||||
static inline bool utf16_is_surrogate(char16_t c) {
|
||||
return (0xd800 <= c && c <= 0xdfff);
|
||||
return c >= 0xd800U && c <= 0xdfffU;
|
||||
}
|
||||
|
||||
static inline bool utf16_is_trailing_surrogate(char16_t c) {
|
||||
return (0xdc00 <= c && c <= 0xdfff);
|
||||
return c >= 0xdc00U && c <= 0xdfffU;
|
||||
}
|
||||
|
||||
static inline char32_t utf16_surrogate_pair_to_unichar(char16_t lead, char16_t trail) {
|
||||
return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000;
|
||||
return ((((char32_t) lead - 0xd800U) << 10) + ((char32_t) trail - 0xdc00U) + 0x10000U);
|
||||
}
|
||||
|
||||
size_t utf8_n_codepoints(const char *str);
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ void in_initrd_force(bool value) {
|
|||
|
||||
/* hey glibc, APIs with callbacks without a user pointer are so useless */
|
||||
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
|
||||
int (*compar) (const void *, const void *, void *), void *arg) {
|
||||
__compar_d_fn_t compar, void *arg) {
|
||||
size_t l, u, idx;
|
||||
const void *p;
|
||||
int comparison;
|
||||
|
|
|
|||
|
|
@ -68,15 +68,21 @@ bool in_initrd(void);
|
|||
void in_initrd_force(bool value);
|
||||
|
||||
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
|
||||
int (*compar) (const void *, const void *, void *),
|
||||
void *arg);
|
||||
__compar_d_fn_t compar, void *arg);
|
||||
|
||||
#define typesafe_bsearch_r(k, b, n, func, userdata) \
|
||||
({ \
|
||||
const typeof(b[0]) *_k = k; \
|
||||
int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \
|
||||
xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_d_fn_t) _func_, userdata); \
|
||||
})
|
||||
|
||||
/**
|
||||
* Normal bsearch requires base to be nonnull. Here were require
|
||||
* that only if nmemb > 0.
|
||||
*/
|
||||
static inline void* bsearch_safe(const void *key, const void *base,
|
||||
size_t nmemb, size_t size, comparison_fn_t compar) {
|
||||
size_t nmemb, size_t size, __compar_fn_t compar) {
|
||||
if (nmemb <= 0)
|
||||
return NULL;
|
||||
|
||||
|
|
@ -84,11 +90,18 @@ static inline void* bsearch_safe(const void *key, const void *base,
|
|||
return bsearch(key, base, nmemb, size, compar);
|
||||
}
|
||||
|
||||
#define typesafe_bsearch(k, b, n, func) \
|
||||
({ \
|
||||
const typeof(b[0]) *_k = k; \
|
||||
int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \
|
||||
bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_fn_t) _func_); \
|
||||
})
|
||||
|
||||
/**
|
||||
* Normal qsort requires base to be nonnull. Here were require
|
||||
* that only if nmemb > 0.
|
||||
*/
|
||||
static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) {
|
||||
static inline void qsort_safe(void *base, size_t nmemb, size_t size, __compar_fn_t compar) {
|
||||
if (nmemb <= 1)
|
||||
return;
|
||||
|
||||
|
|
@ -104,7 +117,7 @@ static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_
|
|||
qsort_safe((p), (n), sizeof((p)[0]), (__compar_fn_t) _func_); \
|
||||
})
|
||||
|
||||
static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, int (*compar)(const void*, const void*, void*), void *userdata) {
|
||||
static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_d_fn_t compar, void *userdata) {
|
||||
if (nmemb <= 1)
|
||||
return;
|
||||
|
||||
|
|
@ -112,6 +125,12 @@ static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, int (*com
|
|||
qsort_r(base, nmemb, size, compar, userdata);
|
||||
}
|
||||
|
||||
#define typesafe_qsort_r(p, n, func, userdata) \
|
||||
({ \
|
||||
int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \
|
||||
qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \
|
||||
})
|
||||
|
||||
/* 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) {
|
||||
if (n == 0)
|
||||
|
|
|
|||
|
|
@ -117,8 +117,13 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
|
|||
assert(len);
|
||||
|
||||
r = sd_id128_get_machine(&machine_id);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
machine_id = SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10);
|
||||
#else
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
unaligned_write_be16(&duid->type, DUID_TYPE_EN);
|
||||
unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN);
|
||||
|
|
|
|||
|
|
@ -73,8 +73,6 @@ struct DHCP6IA {
|
|||
struct ia_pd ia_pd;
|
||||
struct ia_ta ia_ta;
|
||||
};
|
||||
sd_event_source *timeout_t1;
|
||||
sd_event_source *timeout_t2;
|
||||
|
||||
LIST_HEAD(DHCP6Address, addresses);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ struct sd_dhcp6_lease {
|
|||
size_t ntp_fqdn_count;
|
||||
};
|
||||
|
||||
int dhcp6_lease_clear_timers(DHCP6IA *ia);
|
||||
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire);
|
||||
DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia);
|
||||
|
||||
|
|
@ -50,6 +49,7 @@ int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease);
|
|||
int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit);
|
||||
|
||||
int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
|
||||
int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
|
||||
|
||||
int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen);
|
||||
int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@ static void lldp_neighbor_id_hash_func(const void *p, struct siphash *state) {
|
|||
siphash24_compress(&id->port_id_size, sizeof(id->port_id_size), state);
|
||||
}
|
||||
|
||||
static int lldp_neighbor_id_compare_func(const void *a, const void *b) {
|
||||
const LLDPNeighborID *x = a, *y = b;
|
||||
int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y) {
|
||||
int r;
|
||||
|
||||
r = memcmp(x->chassis_id, y->chassis_id, MIN(x->chassis_id_size, y->chassis_id_size));
|
||||
|
|
@ -41,7 +40,7 @@ static int lldp_neighbor_id_compare_func(const void *a, const void *b) {
|
|||
|
||||
const struct hash_ops lldp_neighbor_id_hash_ops = {
|
||||
.hash = lldp_neighbor_id_hash_func,
|
||||
.compare = lldp_neighbor_id_compare_func
|
||||
.compare = (__compar_fn_t) lldp_neighbor_id_compare_func,
|
||||
};
|
||||
|
||||
int lldp_neighbor_prioq_compare_func(const void *a, const void *b) {
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ static inline void* LLDP_NEIGHBOR_TLV_DATA(const sd_lldp_neighbor *n) {
|
|||
}
|
||||
|
||||
extern const struct hash_ops lldp_neighbor_id_hash_ops;
|
||||
int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y);
|
||||
int lldp_neighbor_prioq_compare_func(const void *a, const void *b);
|
||||
|
||||
sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n);
|
||||
|
|
|
|||
|
|
@ -389,7 +389,7 @@ static int dhcp_client_set_iaid_duid_internal(
|
|||
} else
|
||||
switch (duid_type) {
|
||||
case DUID_TYPE_LLT:
|
||||
if (!client->mac_addr || client->mac_addr_len == 0)
|
||||
if (client->mac_addr_len == 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
r = dhcp_identifier_set_duid_llt(&client->client_id.ns.duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &len);
|
||||
|
|
@ -402,7 +402,7 @@ static int dhcp_client_set_iaid_duid_internal(
|
|||
return r;
|
||||
break;
|
||||
case DUID_TYPE_LL:
|
||||
if (!client->mac_addr || client->mac_addr_len == 0)
|
||||
if (client->mac_addr_len == 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
r = dhcp_identifier_set_duid_ll(&client->client_id.ns.duid, client->mac_addr, client->mac_addr_len, client->arp_type, &len);
|
||||
|
|
@ -1956,27 +1956,8 @@ sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
|
|||
return client->event;
|
||||
}
|
||||
|
||||
sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) {
|
||||
|
||||
if (!client)
|
||||
return NULL;
|
||||
|
||||
assert(client->n_ref >= 1);
|
||||
client->n_ref++;
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
|
||||
|
||||
if (!client)
|
||||
return NULL;
|
||||
|
||||
assert(client->n_ref >= 1);
|
||||
client->n_ref--;
|
||||
|
||||
if (client->n_ref > 0)
|
||||
return NULL;
|
||||
static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
|
||||
assert(client);
|
||||
|
||||
log_dhcp_client(client, "FREE");
|
||||
|
||||
|
|
@ -1995,6 +1976,8 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
|
|||
return mfree(client);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free);
|
||||
|
||||
int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
|
||||
_cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -248,27 +248,8 @@ int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, s
|
|||
return 0;
|
||||
}
|
||||
|
||||
sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
|
||||
|
||||
if (!lease)
|
||||
return NULL;
|
||||
|
||||
assert(lease->n_ref >= 1);
|
||||
lease->n_ref++;
|
||||
|
||||
return lease;
|
||||
}
|
||||
|
||||
sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
|
||||
|
||||
if (!lease)
|
||||
return NULL;
|
||||
|
||||
assert(lease->n_ref >= 1);
|
||||
lease->n_ref--;
|
||||
|
||||
if (lease->n_ref > 0)
|
||||
return NULL;
|
||||
static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
|
||||
assert(lease);
|
||||
|
||||
while (lease->private_options) {
|
||||
struct sd_dhcp_raw_option *option = lease->private_options;
|
||||
|
|
@ -279,6 +260,8 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
|
|||
free(option);
|
||||
}
|
||||
|
||||
free(lease->root_path);
|
||||
free(lease->timezone);
|
||||
free(lease->hostname);
|
||||
free(lease->domainname);
|
||||
free(lease->dns);
|
||||
|
|
@ -290,6 +273,8 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
|
|||
return mfree(lease);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_lease, sd_dhcp_lease, dhcp_lease_free);
|
||||
|
||||
static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
|
||||
assert(option);
|
||||
assert(ret);
|
||||
|
|
@ -349,8 +334,7 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
|
|||
if (!string)
|
||||
return -ENOMEM;
|
||||
|
||||
free(*ret);
|
||||
*ret = string;
|
||||
free_and_replace(*ret, string);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,13 @@
|
|||
|
||||
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
|
||||
|
||||
/* what to request from the server, addresses (IA_NA) and/or prefixes (IA_PD) */
|
||||
enum {
|
||||
DHCP6_REQUEST_IA_NA = 1,
|
||||
DHCP6_REQUEST_IA_TA = 2, /* currently not used */
|
||||
DHCP6_REQUEST_IA_PD = 4,
|
||||
};
|
||||
|
||||
struct sd_dhcp6_client {
|
||||
unsigned n_ref;
|
||||
|
||||
|
|
@ -42,7 +49,9 @@ struct sd_dhcp6_client {
|
|||
uint16_t arp_type;
|
||||
DHCP6IA ia_na;
|
||||
DHCP6IA ia_pd;
|
||||
bool prefix_delegation;
|
||||
sd_event_source *timeout_t1;
|
||||
sd_event_source *timeout_t2;
|
||||
unsigned request;
|
||||
be32_t transaction_id;
|
||||
usec_t transaction_start;
|
||||
struct sd_dhcp6_lease *lease;
|
||||
|
|
@ -208,10 +217,10 @@ static int dhcp6_client_set_duid_internal(
|
|||
#if 0 /* NM_IGNORED */
|
||||
switch (duid_type) {
|
||||
case DUID_TYPE_LLT:
|
||||
if (!client->mac_addr || client->mac_addr_len == 0)
|
||||
if (client->mac_addr_len == 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
r = dhcp_identifier_set_duid_llt(&client->duid, 0, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len);
|
||||
r = dhcp_identifier_set_duid_llt(&client->duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
|
|
@ -221,7 +230,7 @@ static int dhcp6_client_set_duid_internal(
|
|||
return r;
|
||||
break;
|
||||
case DUID_TYPE_LL:
|
||||
if (!client->mac_addr || client->mac_addr_len == 0)
|
||||
if (client->mac_addr_len == 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
r = dhcp_identifier_set_duid_ll(&client->duid, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len);
|
||||
|
|
@ -333,10 +342,44 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, bool delegation) {
|
||||
int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(delegation, -EINVAL);
|
||||
|
||||
*delegation = FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, int delegation) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
client->prefix_delegation = delegation;
|
||||
SET_FLAG(client->request, DHCP6_REQUEST_IA_PD, delegation);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client, int *request) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(request, -EINVAL);
|
||||
|
||||
*request = FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, int request) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
SET_FLAG(client->request, DHCP6_REQUEST_IA_NA, request);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_transaction_id(sd_dhcp6_client *client, uint32_t transaction_id) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
client->transaction_id = transaction_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -360,21 +403,10 @@ static void client_notify(sd_dhcp6_client *client, int event) {
|
|||
client->callback(client, event, client->userdata);
|
||||
}
|
||||
|
||||
static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) {
|
||||
assert(client);
|
||||
|
||||
if (client->lease) {
|
||||
dhcp6_lease_clear_timers(&client->lease->ia);
|
||||
sd_dhcp6_lease_unref(client->lease);
|
||||
}
|
||||
|
||||
client->lease = lease;
|
||||
}
|
||||
|
||||
static int client_reset(sd_dhcp6_client *client) {
|
||||
assert(client);
|
||||
|
||||
client_set_lease(client, NULL);
|
||||
client->lease = sd_dhcp6_lease_unref(client->lease);
|
||||
|
||||
client->receive_message =
|
||||
sd_event_source_unref(client->receive_message);
|
||||
|
|
@ -382,17 +414,15 @@ static int client_reset(sd_dhcp6_client *client) {
|
|||
client->transaction_id = 0;
|
||||
client->transaction_start = 0;
|
||||
|
||||
client->ia_na.timeout_t1 =
|
||||
sd_event_source_unref(client->ia_na.timeout_t1);
|
||||
client->ia_na.timeout_t2 =
|
||||
sd_event_source_unref(client->ia_na.timeout_t2);
|
||||
|
||||
client->retransmit_time = 0;
|
||||
client->retransmit_count = 0;
|
||||
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
|
||||
client->timeout_resend_expire =
|
||||
sd_event_source_unref(client->timeout_resend_expire);
|
||||
|
||||
client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
|
||||
client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
|
||||
|
||||
client->state = DHCP6_STATE_STOPPED;
|
||||
|
||||
return 0;
|
||||
|
|
@ -444,9 +474,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
|
||||
r = dhcp6_option_append_ia(&opt, &optlen,
|
||||
&client->ia_na);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->fqdn) {
|
||||
r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
|
||||
|
|
@ -454,7 +487,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
return r;
|
||||
}
|
||||
|
||||
if (client->prefix_delegation) {
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
|
||||
r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
@ -479,9 +512,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
|
||||
r = dhcp6_option_append_ia(&opt, &optlen,
|
||||
&client->lease->ia);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->fqdn) {
|
||||
r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
|
||||
|
|
@ -489,7 +525,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
return r;
|
||||
}
|
||||
|
||||
if (client->prefix_delegation) {
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
|
||||
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
@ -503,9 +539,11 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
case DHCP6_STATE_REBIND:
|
||||
message->type = DHCP6_REBIND;
|
||||
|
||||
r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
|
||||
r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->fqdn) {
|
||||
r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn);
|
||||
|
|
@ -513,7 +551,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
|
|||
return r;
|
||||
}
|
||||
|
||||
if (client->prefix_delegation) {
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
|
||||
r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
@ -570,8 +608,8 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
|
|||
assert(client);
|
||||
assert(client->lease);
|
||||
|
||||
client->lease->ia.timeout_t2 =
|
||||
sd_event_source_unref(client->lease->ia.timeout_t2);
|
||||
client->timeout_t2 =
|
||||
sd_event_source_unref(client->timeout_t2);
|
||||
|
||||
log_dhcp6_client(client, "Timeout T2");
|
||||
|
||||
|
|
@ -587,8 +625,8 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
|
|||
assert(client);
|
||||
assert(client->lease);
|
||||
|
||||
client->lease->ia.timeout_t1 =
|
||||
sd_event_source_unref(client->lease->ia.timeout_t1);
|
||||
client->timeout_t1 =
|
||||
sd_event_source_unref(client->timeout_t1);
|
||||
|
||||
log_dhcp6_client(client, "Timeout T1");
|
||||
|
||||
|
|
@ -818,8 +856,8 @@ static int client_parse_message(
|
|||
uint8_t *optval;
|
||||
be32_t iaid_lease;
|
||||
|
||||
if (len < offsetof(DHCP6Option, data) ||
|
||||
len < offsetof(DHCP6Option, data) + be16toh(option->len))
|
||||
if (len < pos + offsetof(DHCP6Option, data) ||
|
||||
len < pos + offsetof(DHCP6Option, data) + be16toh(option->len))
|
||||
return -ENOBUFS;
|
||||
|
||||
optcode = be16toh(option->code);
|
||||
|
|
@ -922,7 +960,7 @@ static int client_parse_message(
|
|||
if (r < 0 && r != -ENOMSG)
|
||||
return r;
|
||||
|
||||
r = dhcp6_lease_get_iaid(lease, &iaid_lease);
|
||||
r = dhcp6_lease_get_pd_iaid(lease, &iaid_lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
@ -975,7 +1013,7 @@ static int client_parse_message(
|
|||
break;
|
||||
}
|
||||
|
||||
pos += sizeof(*option) + optlen;
|
||||
pos += offsetof(DHCP6Option, data) + optlen;
|
||||
}
|
||||
|
||||
if (!clientid) {
|
||||
|
|
@ -1035,8 +1073,8 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si
|
|||
return 0;
|
||||
}
|
||||
|
||||
client_set_lease(client, lease);
|
||||
lease = NULL;
|
||||
sd_dhcp6_lease_unref(client->lease);
|
||||
client->lease = TAKE_PTR(lease);
|
||||
|
||||
return DHCP6_STATE_BOUND;
|
||||
}
|
||||
|
|
@ -1064,8 +1102,8 @@ static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *adver
|
|||
r = dhcp6_lease_get_preference(client->lease, &pref_lease);
|
||||
|
||||
if (r < 0 || pref_advertise > pref_lease) {
|
||||
client_set_lease(client, lease);
|
||||
lease = NULL;
|
||||
sd_dhcp6_lease_unref(client->lease);
|
||||
client->lease = TAKE_PTR(lease);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
|
|
@ -1196,10 +1234,33 @@ static int client_receive_message(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1,
|
||||
uint32_t *lifetime_t2) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->lease, -EINVAL);
|
||||
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) {
|
||||
*lifetime_t1 = be32toh(client->lease->ia.ia_na.lifetime_t1);
|
||||
*lifetime_t2 = be32toh(client->lease->ia.ia_na.lifetime_t2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
|
||||
*lifetime_t1 = be32toh(client->lease->pd.ia_pd.lifetime_t1);
|
||||
*lifetime_t2 = be32toh(client->lease->pd.ia_pd.lifetime_t2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMSG;
|
||||
}
|
||||
|
||||
static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
|
||||
int r;
|
||||
usec_t timeout, time_now;
|
||||
char time_string[FORMAT_TIMESPAN_MAX];
|
||||
uint32_t lifetime_t1, lifetime_t2;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->event, -EINVAL);
|
||||
|
|
@ -1259,57 +1320,58 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
|
|||
|
||||
case DHCP6_STATE_BOUND:
|
||||
|
||||
if (client->lease->ia.ia_na.lifetime_t1 == 0xffffffff ||
|
||||
client->lease->ia.ia_na.lifetime_t2 == 0xffffffff) {
|
||||
r = client_get_lifetime(client, &lifetime_t1, &lifetime_t2);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
if (lifetime_t1 == 0xffffffff || lifetime_t2 == 0xffffffff) {
|
||||
log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x",
|
||||
be32toh(client->lease->ia.ia_na.lifetime_t1),
|
||||
be32toh(client->lease->ia.ia_na.lifetime_t2));
|
||||
lifetime_t1, lifetime_t2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t1) * USEC_PER_SEC);
|
||||
timeout = client_timeout_compute_random(lifetime_t1 * USEC_PER_SEC);
|
||||
|
||||
log_dhcp6_client(client, "T1 expires in %s",
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
|
||||
|
||||
r = sd_event_add_time(client->event,
|
||||
&client->lease->ia.timeout_t1,
|
||||
&client->timeout_t1,
|
||||
clock_boottime_or_monotonic(), time_now + timeout,
|
||||
10 * USEC_PER_SEC, client_timeout_t1,
|
||||
client);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_priority(client->lease->ia.timeout_t1,
|
||||
r = sd_event_source_set_priority(client->timeout_t1,
|
||||
client->event_priority);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout");
|
||||
r = sd_event_source_set_description(client->timeout_t1, "dhcp6-t1-timeout");
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
timeout = client_timeout_compute_random(be32toh(client->lease->ia.ia_na.lifetime_t2) * USEC_PER_SEC);
|
||||
timeout = client_timeout_compute_random(lifetime_t2 * USEC_PER_SEC);
|
||||
|
||||
log_dhcp6_client(client, "T2 expires in %s",
|
||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
|
||||
|
||||
r = sd_event_add_time(client->event,
|
||||
&client->lease->ia.timeout_t2,
|
||||
&client->timeout_t2,
|
||||
clock_boottime_or_monotonic(), time_now + timeout,
|
||||
10 * USEC_PER_SEC, client_timeout_t2,
|
||||
client);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_priority(client->lease->ia.timeout_t2,
|
||||
r = sd_event_source_set_priority(client->timeout_t2,
|
||||
client->event_priority);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout");
|
||||
r = sd_event_source_set_description(client->timeout_t2, "dhcp6-t2-timeout");
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
|
|
@ -1371,6 +1433,9 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
|
|||
if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
|
||||
return -EBUSY;
|
||||
|
||||
if (!client->information_request && !client->request)
|
||||
return -EINVAL;
|
||||
|
||||
r = client_reset(client);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
@ -1439,27 +1504,8 @@ sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) {
|
|||
return client->event;
|
||||
}
|
||||
|
||||
sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) {
|
||||
|
||||
if (!client)
|
||||
return NULL;
|
||||
|
||||
assert(client->n_ref >= 1);
|
||||
client->n_ref++;
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
|
||||
|
||||
if (!client)
|
||||
return NULL;
|
||||
|
||||
assert(client->n_ref >= 1);
|
||||
client->n_ref--;
|
||||
|
||||
if (client->n_ref > 0)
|
||||
return NULL;
|
||||
static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
|
||||
assert(client);
|
||||
|
||||
client_reset(client);
|
||||
|
||||
|
|
@ -1472,6 +1518,8 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
|
|||
return mfree(client);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_client, sd_dhcp6_client, dhcp6_client_free);
|
||||
|
||||
int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
|
||||
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
|
||||
size_t t;
|
||||
|
|
@ -1486,6 +1534,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
|
|||
client->ia_na.type = SD_DHCP6_OPTION_IA_NA;
|
||||
client->ia_pd.type = SD_DHCP6_OPTION_IA_PD;
|
||||
client->ifindex = -1;
|
||||
client->request = DHCP6_REQUEST_IA_NA;
|
||||
client->fd = -1;
|
||||
|
||||
client->req_opts_len = ELEMENTSOF(default_req_opts);
|
||||
|
|
|
|||
|
|
@ -13,15 +13,6 @@
|
|||
#include "strv.h"
|
||||
#include "util.h"
|
||||
|
||||
int dhcp6_lease_clear_timers(DHCP6IA *ia) {
|
||||
assert_return(ia, -EINVAL);
|
||||
|
||||
ia->timeout_t1 = sd_event_source_unref(ia->timeout_t1);
|
||||
ia->timeout_t2 = sd_event_source_unref(ia->timeout_t2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
|
||||
DHCP6Address *addr;
|
||||
uint32_t valid = 0, t;
|
||||
|
|
@ -50,8 +41,6 @@ DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) {
|
|||
if (!ia)
|
||||
return NULL;
|
||||
|
||||
dhcp6_lease_clear_timers(ia);
|
||||
|
||||
while (ia->addresses) {
|
||||
address = ia->addresses;
|
||||
|
||||
|
|
@ -138,6 +127,15 @@ int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(iaid, -EINVAL);
|
||||
|
||||
*iaid = lease->pd.ia_pd.id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
|
||||
uint32_t *lifetime_preferred,
|
||||
uint32_t *lifetime_valid) {
|
||||
|
|
@ -376,27 +374,8 @@ int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) {
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease) {
|
||||
|
||||
if (!lease)
|
||||
return NULL;
|
||||
|
||||
assert(lease->n_ref >= 1);
|
||||
lease->n_ref++;
|
||||
|
||||
return lease;
|
||||
}
|
||||
|
||||
sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) {
|
||||
|
||||
if (!lease)
|
||||
return NULL;
|
||||
|
||||
assert(lease->n_ref >= 1);
|
||||
lease->n_ref--;
|
||||
|
||||
if (lease->n_ref > 0)
|
||||
return NULL;
|
||||
static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
|
||||
assert(lease);
|
||||
|
||||
free(lease->serverid);
|
||||
dhcp6_lease_free_ia(&lease->ia);
|
||||
|
|
@ -412,6 +391,8 @@ sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) {
|
|||
return mfree(lease);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_lease, sd_dhcp6_lease, dhcp6_lease_free);
|
||||
|
||||
int dhcp6_lease_new(sd_dhcp6_lease **ret) {
|
||||
sd_dhcp6_lease *lease;
|
||||
|
||||
|
|
|
|||
|
|
@ -99,25 +99,8 @@ static void ipv4acd_reset(sd_ipv4acd *acd) {
|
|||
ipv4acd_set_state(acd, IPV4ACD_STATE_INIT, true);
|
||||
}
|
||||
|
||||
sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd) {
|
||||
if (!acd)
|
||||
return NULL;
|
||||
|
||||
assert_se(acd->n_ref >= 1);
|
||||
acd->n_ref++;
|
||||
|
||||
return acd;
|
||||
}
|
||||
|
||||
sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd) {
|
||||
if (!acd)
|
||||
return NULL;
|
||||
|
||||
assert_se(acd->n_ref >= 1);
|
||||
acd->n_ref--;
|
||||
|
||||
if (acd->n_ref > 0)
|
||||
return NULL;
|
||||
static sd_ipv4acd *ipv4acd_free(sd_ipv4acd *acd) {
|
||||
assert(acd);
|
||||
|
||||
ipv4acd_reset(acd);
|
||||
sd_ipv4acd_detach_event(acd);
|
||||
|
|
@ -125,6 +108,8 @@ sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd) {
|
|||
return mfree(acd);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_ipv4acd, sd_ipv4acd, ipv4acd_free);
|
||||
|
||||
int sd_ipv4acd_new(sd_ipv4acd **ret) {
|
||||
_cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *acd = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -57,30 +57,15 @@ struct sd_ipv4ll {
|
|||
|
||||
static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata);
|
||||
|
||||
sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) {
|
||||
if (!ll)
|
||||
return NULL;
|
||||
|
||||
assert(ll->n_ref >= 1);
|
||||
ll->n_ref++;
|
||||
|
||||
return ll;
|
||||
}
|
||||
|
||||
sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) {
|
||||
if (!ll)
|
||||
return NULL;
|
||||
|
||||
assert(ll->n_ref >= 1);
|
||||
ll->n_ref--;
|
||||
|
||||
if (ll->n_ref > 0)
|
||||
return NULL;
|
||||
static sd_ipv4ll *ipv4ll_free(sd_ipv4ll *ll) {
|
||||
assert(ll);
|
||||
|
||||
sd_ipv4acd_unref(ll->acd);
|
||||
return mfree(ll);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_ipv4ll, sd_ipv4ll, ipv4ll_free);
|
||||
|
||||
int sd_ipv4ll_new(sd_ipv4ll **ret) {
|
||||
_cleanup_(sd_ipv4ll_unrefp) sd_ipv4ll *ll = NULL;
|
||||
int r;
|
||||
|
|
|
|||
|
|
@ -331,27 +331,8 @@ _public_ int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ sd_lldp* sd_lldp_ref(sd_lldp *lldp) {
|
||||
|
||||
if (!lldp)
|
||||
return NULL;
|
||||
|
||||
assert(lldp->n_ref > 0);
|
||||
lldp->n_ref++;
|
||||
|
||||
return lldp;
|
||||
}
|
||||
|
||||
_public_ sd_lldp* sd_lldp_unref(sd_lldp *lldp) {
|
||||
|
||||
if (!lldp)
|
||||
return NULL;
|
||||
|
||||
assert(lldp->n_ref > 0);
|
||||
lldp->n_ref --;
|
||||
|
||||
if (lldp->n_ref > 0)
|
||||
return NULL;
|
||||
static sd_lldp* lldp_free(sd_lldp *lldp) {
|
||||
assert(lldp);
|
||||
|
||||
lldp_reset(lldp);
|
||||
sd_lldp_detach_event(lldp);
|
||||
|
|
@ -362,6 +343,8 @@ _public_ sd_lldp* sd_lldp_unref(sd_lldp *lldp) {
|
|||
return mfree(lldp);
|
||||
}
|
||||
|
||||
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_lldp, sd_lldp, lldp_free);
|
||||
|
||||
_public_ int sd_lldp_new(sd_lldp **ret) {
|
||||
_cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL;
|
||||
int r;
|
||||
|
|
@ -390,10 +373,8 @@ _public_ int sd_lldp_new(sd_lldp **ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int neighbor_compare_func(const void *a, const void *b) {
|
||||
const sd_lldp_neighbor * const*x = a, * const *y = b;
|
||||
|
||||
return lldp_neighbor_id_hash_ops.compare(&(*x)->id, &(*y)->id);
|
||||
static int neighbor_compare_func(sd_lldp_neighbor * const *a, sd_lldp_neighbor * const *b) {
|
||||
return lldp_neighbor_id_compare_func(&(*a)->id, &(*b)->id);
|
||||
}
|
||||
|
||||
static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
|
|
@ -481,7 +462,7 @@ _public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) {
|
|||
assert((size_t) k == hashmap_size(lldp->neighbor_by_id));
|
||||
|
||||
/* Return things in a stable order */
|
||||
qsort(l, k, sizeof(sd_lldp_neighbor*), neighbor_compare_func);
|
||||
typesafe_qsort(l, k, neighbor_compare_func);
|
||||
*ret = l;
|
||||
|
||||
return k;
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ static void free_clock_data(struct clock_data *d) {
|
|||
prioq_free(d->latest);
|
||||
}
|
||||
|
||||
static void event_free(sd_event *e) {
|
||||
static sd_event *event_free(sd_event *e) {
|
||||
sd_event_source *s;
|
||||
|
||||
assert(e);
|
||||
|
|
@ -494,7 +494,8 @@ static void event_free(sd_event *e) {
|
|||
|
||||
hashmap_free(e->child_sources);
|
||||
set_free(e->post_sources);
|
||||
free(e);
|
||||
|
||||
return mfree(e);
|
||||
}
|
||||
|
||||
_public_ int sd_event_new(sd_event** ret) {
|
||||
|
|
@ -555,30 +556,7 @@ fail:
|
|||
return r;
|
||||
}
|
||||
|
||||
_public_ sd_event* sd_event_ref(sd_event *e) {
|
||||
|
||||
if (!e)
|
||||
return NULL;
|
||||
|
||||
assert(e->n_ref >= 1);
|
||||
e->n_ref++;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
_public_ sd_event* sd_event_unref(sd_event *e) {
|
||||
|
||||
if (!e)
|
||||
return NULL;
|
||||
|
||||
assert(e->n_ref >= 1);
|
||||
e->n_ref--;
|
||||
|
||||
if (e->n_ref <= 0)
|
||||
event_free(e);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_event, sd_event, event_free);
|
||||
|
||||
static bool event_pid_changed(sd_event *e) {
|
||||
assert(e);
|
||||
|
|
@ -1023,6 +1001,7 @@ static void source_free(sd_event_source *s) {
|
|||
free(s->description);
|
||||
free(s);
|
||||
}
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, source_free);
|
||||
|
||||
static int source_set_pending(sd_event_source *s, bool b) {
|
||||
int r;
|
||||
|
|
@ -1116,7 +1095,7 @@ _public_ int sd_event_add_io(
|
|||
sd_event_io_handler_t callback,
|
||||
void *userdata) {
|
||||
|
||||
sd_event_source *s;
|
||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(e, -EINVAL);
|
||||
|
|
@ -1139,13 +1118,12 @@ _public_ int sd_event_add_io(
|
|||
s->enabled = SD_EVENT_ON;
|
||||
|
||||
r = source_io_register(s, s->enabled, events);
|
||||
if (r < 0) {
|
||||
source_free(s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
TAKE_PTR(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1220,7 +1198,7 @@ _public_ int sd_event_add_time(
|
|||
void *userdata) {
|
||||
|
||||
EventSourceType type;
|
||||
sd_event_source *s;
|
||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||
struct clock_data *d;
|
||||
int r;
|
||||
|
||||
|
|
@ -1272,20 +1250,17 @@ _public_ int sd_event_add_time(
|
|||
|
||||
r = prioq_put(d->earliest, s, &s->time.earliest_index);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
r = prioq_put(d->latest, s, &s->time.latest_index);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
TAKE_PTR(s);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
source_free(s);
|
||||
return r;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
|
@ -1302,7 +1277,7 @@ _public_ int sd_event_add_signal(
|
|||
sd_event_signal_handler_t callback,
|
||||
void *userdata) {
|
||||
|
||||
sd_event_source *s;
|
||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||
struct signal_data *d;
|
||||
sigset_t ss;
|
||||
int r;
|
||||
|
|
@ -1342,16 +1317,15 @@ _public_ int sd_event_add_signal(
|
|||
e->signal_sources[sig] = s;
|
||||
|
||||
r = event_make_signal_data(e, sig, &d);
|
||||
if (r < 0) {
|
||||
source_free(s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Use the signal name as description for the event source by default */
|
||||
(void) sd_event_source_set_description(s, signal_to_string(sig));
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
TAKE_PTR(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1365,7 +1339,7 @@ _public_ int sd_event_add_child(
|
|||
sd_event_child_handler_t callback,
|
||||
void *userdata) {
|
||||
|
||||
sd_event_source *s;
|
||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(e, -EINVAL);
|
||||
|
|
@ -1395,17 +1369,14 @@ _public_ int sd_event_add_child(
|
|||
s->enabled = SD_EVENT_ONESHOT;
|
||||
|
||||
r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s);
|
||||
if (r < 0) {
|
||||
source_free(s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
e->n_enabled_child_sources++;
|
||||
|
||||
r = event_make_signal_data(e, SIGCHLD, NULL);
|
||||
if (r < 0) {
|
||||
e->n_enabled_child_sources--;
|
||||
source_free(s);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -1413,6 +1384,7 @@ _public_ int sd_event_add_child(
|
|||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
TAKE_PTR(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1423,7 +1395,7 @@ _public_ int sd_event_add_defer(
|
|||
sd_event_handler_t callback,
|
||||
void *userdata) {
|
||||
|
||||
sd_event_source *s;
|
||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(e, -EINVAL);
|
||||
|
|
@ -1441,13 +1413,12 @@ _public_ int sd_event_add_defer(
|
|||
s->enabled = SD_EVENT_ONESHOT;
|
||||
|
||||
r = source_set_pending(s, true);
|
||||
if (r < 0) {
|
||||
source_free(s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
TAKE_PTR(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1458,7 +1429,7 @@ _public_ int sd_event_add_post(
|
|||
sd_event_handler_t callback,
|
||||
void *userdata) {
|
||||
|
||||
sd_event_source *s;
|
||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(e, -EINVAL);
|
||||
|
|
@ -1480,13 +1451,12 @@ _public_ int sd_event_add_post(
|
|||
s->enabled = SD_EVENT_ON;
|
||||
|
||||
r = set_put(e->post_sources, s);
|
||||
if (r < 0) {
|
||||
source_free(s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
TAKE_PTR(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1497,7 +1467,7 @@ _public_ int sd_event_add_exit(
|
|||
sd_event_handler_t callback,
|
||||
void *userdata) {
|
||||
|
||||
sd_event_source *s;
|
||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(e, -EINVAL);
|
||||
|
|
@ -1520,13 +1490,12 @@ _public_ int sd_event_add_exit(
|
|||
s->enabled = SD_EVENT_ONESHOT;
|
||||
|
||||
r = prioq_put(s->event->exit, s, &s->exit.prioq_index);
|
||||
if (r < 0) {
|
||||
source_free(s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
TAKE_PTR(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1843,11 +1812,10 @@ _public_ int sd_event_add_inotify(
|
|||
sd_event_inotify_handler_t callback,
|
||||
void *userdata) {
|
||||
|
||||
bool rm_inotify = false, rm_inode = false;
|
||||
struct inotify_data *inotify_data = NULL;
|
||||
struct inode_data *inode_data = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
sd_event_source *s;
|
||||
_cleanup_(source_freep) sd_event_source *s = NULL;
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
|
|
@ -1885,13 +1853,13 @@ _public_ int sd_event_add_inotify(
|
|||
/* Allocate an inotify object for this priority, and an inode object within it */
|
||||
r = event_make_inotify_data(e, SD_EVENT_PRIORITY_NORMAL, &inotify_data);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
rm_inotify = r > 0;
|
||||
return r;
|
||||
|
||||
r = event_make_inode_data(e, inotify_data, st.st_dev, st.st_ino, &inode_data);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
rm_inode = r > 0;
|
||||
if (r < 0) {
|
||||
event_free_inotify_data(e, inotify_data);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Keep the O_PATH fd around until the first iteration of the loop, so that we can still change the priority of
|
||||
* the event source, until then, for which we need the original inode. */
|
||||
|
|
@ -1904,72 +1872,45 @@ _public_ int sd_event_add_inotify(
|
|||
LIST_PREPEND(inotify.by_inode_data, inode_data->event_sources, s);
|
||||
s->inotify.inode_data = inode_data;
|
||||
|
||||
rm_inode = rm_inotify = false;
|
||||
|
||||
/* Actually realize the watch now */
|
||||
r = inode_data_realize_watch(e, inode_data);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
return r;
|
||||
|
||||
(void) sd_event_source_set_description(s, path);
|
||||
|
||||
if (ret)
|
||||
*ret = s;
|
||||
TAKE_PTR(s);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
source_free(s);
|
||||
|
||||
if (rm_inode)
|
||||
event_free_inode_data(e, inode_data);
|
||||
|
||||
if (rm_inotify)
|
||||
event_free_inotify_data(e, inotify_data);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
_public_ sd_event_source* sd_event_source_ref(sd_event_source *s) {
|
||||
|
||||
static sd_event_source* event_source_free(sd_event_source *s) {
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
assert(s->n_ref >= 1);
|
||||
s->n_ref++;
|
||||
/* Here's a special hack: when we are called from a
|
||||
* dispatch handler we won't free the event source
|
||||
* immediately, but we will detach the fd from the
|
||||
* epoll. This way it is safe for the caller to unref
|
||||
* the event source and immediately close the fd, but
|
||||
* we still retain a valid event source object after
|
||||
* the callback. */
|
||||
|
||||
return s;
|
||||
}
|
||||
if (s->dispatching) {
|
||||
if (s->type == SOURCE_IO)
|
||||
source_io_unregister(s);
|
||||
|
||||
_public_ sd_event_source* sd_event_source_unref(sd_event_source *s) {
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
assert(s->n_ref >= 1);
|
||||
s->n_ref--;
|
||||
|
||||
if (s->n_ref <= 0) {
|
||||
/* Here's a special hack: when we are called from a
|
||||
* dispatch handler we won't free the event source
|
||||
* immediately, but we will detach the fd from the
|
||||
* epoll. This way it is safe for the caller to unref
|
||||
* the event source and immediately close the fd, but
|
||||
* we still retain a valid event source object after
|
||||
* the callback. */
|
||||
|
||||
if (s->dispatching) {
|
||||
if (s->type == SOURCE_IO)
|
||||
source_io_unregister(s);
|
||||
|
||||
source_disconnect(s);
|
||||
} else
|
||||
source_free(s);
|
||||
}
|
||||
source_disconnect(s);
|
||||
} else
|
||||
source_free(s);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_event_source, sd_event_source, event_source_free);
|
||||
|
||||
_public_ int sd_event_source_set_description(sd_event_source *s, const char *description) {
|
||||
assert_return(s, -EINVAL);
|
||||
assert_return(!event_pid_changed(s->event), -ECHILD);
|
||||
|
|
|
|||
|
|
@ -289,19 +289,15 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret) {
|
||||
static int get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret) {
|
||||
_cleanup_(khash_unrefp) khash *h = NULL;
|
||||
sd_id128_t m, result;
|
||||
sd_id128_t result;
|
||||
const void *p;
|
||||
int r;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
assert(ret);
|
||||
|
||||
r = sd_id128_get_machine(&m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = khash_new_with_key(&h, "hmac(sha256)", &m, sizeof(m));
|
||||
r = khash_new_with_key(&h, "hmac(sha256)", &base, sizeof(base));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
@ -319,4 +315,30 @@ _public_ int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *re
|
|||
*ret = make_v4_uuid(result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_public_ int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret) {
|
||||
sd_id128_t id;
|
||||
int r;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = sd_id128_get_machine(&id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return get_app_specific(id, app_id, ret);
|
||||
}
|
||||
|
||||
_public_ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret) {
|
||||
sd_id128_t id;
|
||||
int r;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = sd_id128_get_boot(&id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return get_app_specific(id, app_id, ret);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sd-dhcp6-lease.h"
|
||||
|
|
@ -120,8 +119,15 @@ int sd_dhcp6_client_get_information_request(
|
|||
int sd_dhcp6_client_set_request_option(
|
||||
sd_dhcp6_client *client,
|
||||
uint16_t option);
|
||||
int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client,
|
||||
int *delegation);
|
||||
int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client,
|
||||
bool delegation);
|
||||
int delegation);
|
||||
int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client,
|
||||
int *request);
|
||||
int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client,
|
||||
int request);
|
||||
int sd_dhcp6_client_set_transaction_id(sd_dhcp6_client *client, uint32_t transaction_id);
|
||||
|
||||
int sd_dhcp6_client_get_lease(
|
||||
sd_dhcp6_client *client,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ int sd_id128_randomize(sd_id128_t *ret);
|
|||
|
||||
int sd_id128_get_machine(sd_id128_t *ret);
|
||||
int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret);
|
||||
int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
|
||||
int sd_id128_get_boot(sd_id128_t *ret);
|
||||
int sd_id128_get_invocation(sd_id128_t *ret);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue