mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-15 12:34:55 +00:00
systemd: merge branch systemd into master
This commit is contained in:
commit
9d122e7b80
|
@ -1500,6 +1500,7 @@ src_libsystemd_nm_la_cppflags = \
|
||||||
-I$(srcdir)/src/systemd/src/basic \
|
-I$(srcdir)/src/systemd/src/basic \
|
||||||
-I$(srcdir)/src/systemd/src/shared \
|
-I$(srcdir)/src/systemd/src/shared \
|
||||||
-I$(srcdir)/src/systemd/src/libsystemd-network \
|
-I$(srcdir)/src/systemd/src/libsystemd-network \
|
||||||
|
-I$(srcdir)/src/systemd/src/libsystemd/sd-event \
|
||||||
-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_SYSTEMD \
|
-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_SYSTEMD \
|
||||||
$(LIBSYSTEMD_NM_CFLAGS) \
|
$(LIBSYSTEMD_NM_CFLAGS) \
|
||||||
$(GLIB_CFLAGS) \
|
$(GLIB_CFLAGS) \
|
||||||
|
@ -1642,6 +1643,9 @@ src_libsystemd_nm_la_SOURCES = \
|
||||||
src/systemd/src/libsystemd-network/sd-ipv4acd.c \
|
src/systemd/src/libsystemd-network/sd-ipv4acd.c \
|
||||||
src/systemd/src/libsystemd-network/sd-ipv4ll.c \
|
src/systemd/src/libsystemd-network/sd-ipv4ll.c \
|
||||||
src/systemd/src/libsystemd-network/sd-lldp.c \
|
src/systemd/src/libsystemd-network/sd-lldp.c \
|
||||||
|
src/systemd/src/libsystemd/sd-event/event-source.h \
|
||||||
|
src/systemd/src/libsystemd/sd-event/event-util.c \
|
||||||
|
src/systemd/src/libsystemd/sd-event/event-util.h \
|
||||||
src/systemd/src/libsystemd/sd-event/sd-event.c \
|
src/systemd/src/libsystemd/sd-event/sd-event.c \
|
||||||
src/systemd/src/libsystemd/sd-id128/id128-util.c \
|
src/systemd/src/libsystemd/sd-id128/id128-util.c \
|
||||||
src/systemd/src/libsystemd/sd-id128/id128-util.h \
|
src/systemd/src/libsystemd/sd-id128/id128-util.h \
|
||||||
|
|
|
@ -7,37 +7,37 @@
|
||||||
/* BE */
|
/* BE */
|
||||||
|
|
||||||
static inline uint16_t unaligned_read_be16(const void *_u) {
|
static inline uint16_t unaligned_read_be16(const void *_u) {
|
||||||
const struct __attribute__((packed, may_alias)) { uint16_t x; } *u = _u;
|
const struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
|
||||||
|
|
||||||
return be16toh(u->x);
|
return be16toh(u->x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t unaligned_read_be32(const void *_u) {
|
static inline uint32_t unaligned_read_be32(const void *_u) {
|
||||||
const struct __attribute__((packed, may_alias)) { uint32_t x; } *u = _u;
|
const struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
|
||||||
|
|
||||||
return be32toh(u->x);
|
return be32toh(u->x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t unaligned_read_be64(const void *_u) {
|
static inline uint64_t unaligned_read_be64(const void *_u) {
|
||||||
const struct __attribute__((packed, may_alias)) { uint64_t x; } *u = _u;
|
const struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
|
||||||
|
|
||||||
return be64toh(u->x);
|
return be64toh(u->x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void unaligned_write_be16(void *_u, uint16_t a) {
|
static inline void unaligned_write_be16(void *_u, uint16_t a) {
|
||||||
struct __attribute__((packed, may_alias)) { uint16_t x; } *u = _u;
|
struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
|
||||||
|
|
||||||
u->x = be16toh(a);
|
u->x = be16toh(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void unaligned_write_be32(void *_u, uint32_t a) {
|
static inline void unaligned_write_be32(void *_u, uint32_t a) {
|
||||||
struct __attribute__((packed, may_alias)) { uint32_t x; } *u = _u;
|
struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
|
||||||
|
|
||||||
u->x = be32toh(a);
|
u->x = be32toh(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void unaligned_write_be64(void *_u, uint64_t a) {
|
static inline void unaligned_write_be64(void *_u, uint64_t a) {
|
||||||
struct __attribute__((packed, may_alias)) { uint64_t x; } *u = _u;
|
struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
|
||||||
|
|
||||||
u->x = be64toh(a);
|
u->x = be64toh(a);
|
||||||
}
|
}
|
||||||
|
@ -45,37 +45,37 @@ static inline void unaligned_write_be64(void *_u, uint64_t a) {
|
||||||
/* LE */
|
/* LE */
|
||||||
|
|
||||||
static inline uint16_t unaligned_read_le16(const void *_u) {
|
static inline uint16_t unaligned_read_le16(const void *_u) {
|
||||||
const struct __attribute__((packed, may_alias)) { uint16_t x; } *u = _u;
|
const struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
|
||||||
|
|
||||||
return le16toh(u->x);
|
return le16toh(u->x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t unaligned_read_le32(const void *_u) {
|
static inline uint32_t unaligned_read_le32(const void *_u) {
|
||||||
const struct __attribute__((packed, may_alias)) { uint32_t x; } *u = _u;
|
const struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
|
||||||
|
|
||||||
return le32toh(u->x);
|
return le32toh(u->x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t unaligned_read_le64(const void *_u) {
|
static inline uint64_t unaligned_read_le64(const void *_u) {
|
||||||
const struct __attribute__((packed, may_alias)) { uint64_t x; } *u = _u;
|
const struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
|
||||||
|
|
||||||
return le64toh(u->x);
|
return le64toh(u->x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void unaligned_write_le16(void *_u, uint16_t a) {
|
static inline void unaligned_write_le16(void *_u, uint16_t a) {
|
||||||
struct __attribute__((packed, may_alias)) { uint16_t x; } *u = _u;
|
struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u;
|
||||||
|
|
||||||
u->x = le16toh(a);
|
u->x = le16toh(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void unaligned_write_le32(void *_u, uint32_t a) {
|
static inline void unaligned_write_le32(void *_u, uint32_t a) {
|
||||||
struct __attribute__((packed, may_alias)) { uint32_t x; } *u = _u;
|
struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u;
|
||||||
|
|
||||||
u->x = le32toh(a);
|
u->x = le32toh(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void unaligned_write_le64(void *_u, uint64_t a) {
|
static inline void unaligned_write_le64(void *_u, uint64_t a) {
|
||||||
struct __attribute__((packed, may_alias)) { uint64_t x; } *u = _u;
|
struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u;
|
||||||
|
|
||||||
u->x = le64toh(a);
|
u->x = le64toh(a);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ sources = files(
|
||||||
'src/libsystemd-network/sd-ipv4acd.c',
|
'src/libsystemd-network/sd-ipv4acd.c',
|
||||||
'src/libsystemd-network/sd-ipv4ll.c',
|
'src/libsystemd-network/sd-ipv4ll.c',
|
||||||
'src/libsystemd-network/sd-lldp.c',
|
'src/libsystemd-network/sd-lldp.c',
|
||||||
|
'src/libsystemd/sd-event/event-util.c',
|
||||||
'src/libsystemd/sd-event/sd-event.c',
|
'src/libsystemd/sd-event/sd-event.c',
|
||||||
'src/libsystemd/sd-id128/id128-util.c',
|
'src/libsystemd/sd-id128/id128-util.c',
|
||||||
'src/libsystemd/sd-id128/sd-id128.c',
|
'src/libsystemd/sd-id128/sd-id128.c',
|
||||||
|
@ -59,6 +60,7 @@ incs = [
|
||||||
'sd-adapt',
|
'sd-adapt',
|
||||||
'src/basic',
|
'src/basic',
|
||||||
'src/libsystemd-network',
|
'src/libsystemd-network',
|
||||||
|
'src/libsystemd/sd-event',
|
||||||
'src/shared',
|
'src/shared',
|
||||||
'src/systemd'
|
'src/systemd'
|
||||||
)
|
)
|
||||||
|
|
|
@ -108,7 +108,6 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit)
|
||||||
int r = 1;
|
int r = 1;
|
||||||
|
|
||||||
assert(p);
|
assert(p);
|
||||||
assert(*p);
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
/* Unescapes C style. Returns the unescaped character in ret.
|
/* Unescapes C style. Returns the unescaped character in ret.
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "ctype.h"
|
#include "ctype.h"
|
||||||
#include "def.h"
|
|
||||||
#include "env-util.h"
|
#include "env-util.h"
|
||||||
#include "escape.h"
|
#include "escape.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
|
@ -163,7 +162,7 @@ int write_string_file_ts(
|
||||||
|
|
||||||
/* We manually build our own version of fopen(..., "we") that
|
/* We manually build our own version of fopen(..., "we") that
|
||||||
* works without O_CREAT */
|
* works without O_CREAT */
|
||||||
fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
|
fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY | ((flags & WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0));
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
r = -errno;
|
r = -errno;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -372,7 +371,6 @@ int read_full_file(const char *fn, char **contents, size_t *size) {
|
||||||
static int parse_env_file_internal(
|
static int parse_env_file_internal(
|
||||||
FILE *f,
|
FILE *f,
|
||||||
const char *fname,
|
const char *fname,
|
||||||
const char *newline,
|
|
||||||
int (*push) (const char *filename, unsigned line,
|
int (*push) (const char *filename, unsigned line,
|
||||||
const char *key, char *value, void *userdata, int *n_pushed),
|
const char *key, char *value, void *userdata, int *n_pushed),
|
||||||
void *userdata,
|
void *userdata,
|
||||||
|
@ -398,8 +396,6 @@ static int parse_env_file_internal(
|
||||||
COMMENT_ESCAPE
|
COMMENT_ESCAPE
|
||||||
} state = PRE_KEY;
|
} state = PRE_KEY;
|
||||||
|
|
||||||
assert(newline);
|
|
||||||
|
|
||||||
if (f)
|
if (f)
|
||||||
r = read_full_stream(f, &contents, NULL);
|
r = read_full_stream(f, &contents, NULL);
|
||||||
else
|
else
|
||||||
|
@ -427,7 +423,7 @@ static int parse_env_file_internal(
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KEY:
|
case KEY:
|
||||||
if (strchr(newline, c)) {
|
if (strchr(NEWLINE, c)) {
|
||||||
state = PRE_KEY;
|
state = PRE_KEY;
|
||||||
line++;
|
line++;
|
||||||
n_key = 0;
|
n_key = 0;
|
||||||
|
@ -449,7 +445,7 @@ static int parse_env_file_internal(
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRE_VALUE:
|
case PRE_VALUE:
|
||||||
if (strchr(newline, c)) {
|
if (strchr(NEWLINE, c)) {
|
||||||
state = PRE_KEY;
|
state = PRE_KEY;
|
||||||
line++;
|
line++;
|
||||||
key[n_key] = 0;
|
key[n_key] = 0;
|
||||||
|
@ -487,7 +483,7 @@ static int parse_env_file_internal(
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VALUE:
|
case VALUE:
|
||||||
if (strchr(newline, c)) {
|
if (strchr(NEWLINE, c)) {
|
||||||
state = PRE_KEY;
|
state = PRE_KEY;
|
||||||
line++;
|
line++;
|
||||||
|
|
||||||
|
@ -532,7 +528,7 @@ static int parse_env_file_internal(
|
||||||
case VALUE_ESCAPE:
|
case VALUE_ESCAPE:
|
||||||
state = VALUE;
|
state = VALUE;
|
||||||
|
|
||||||
if (!strchr(newline, c)) {
|
if (!strchr(NEWLINE, c)) {
|
||||||
/* Escaped newlines we eat up entirely */
|
/* Escaped newlines we eat up entirely */
|
||||||
if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
|
if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -558,7 +554,7 @@ static int parse_env_file_internal(
|
||||||
case SINGLE_QUOTE_VALUE_ESCAPE:
|
case SINGLE_QUOTE_VALUE_ESCAPE:
|
||||||
state = SINGLE_QUOTE_VALUE;
|
state = SINGLE_QUOTE_VALUE;
|
||||||
|
|
||||||
if (!strchr(newline, c)) {
|
if (!strchr(NEWLINE, c)) {
|
||||||
if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
|
if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -583,7 +579,7 @@ static int parse_env_file_internal(
|
||||||
case DOUBLE_QUOTE_VALUE_ESCAPE:
|
case DOUBLE_QUOTE_VALUE_ESCAPE:
|
||||||
state = DOUBLE_QUOTE_VALUE;
|
state = DOUBLE_QUOTE_VALUE;
|
||||||
|
|
||||||
if (!strchr(newline, c)) {
|
if (!strchr(NEWLINE, c)) {
|
||||||
if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
|
if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -594,7 +590,7 @@ static int parse_env_file_internal(
|
||||||
case COMMENT:
|
case COMMENT:
|
||||||
if (c == '\\')
|
if (c == '\\')
|
||||||
state = COMMENT_ESCAPE;
|
state = COMMENT_ESCAPE;
|
||||||
else if (strchr(newline, c)) {
|
else if (strchr(NEWLINE, c)) {
|
||||||
state = PRE_KEY;
|
state = PRE_KEY;
|
||||||
line++;
|
line++;
|
||||||
}
|
}
|
||||||
|
@ -646,16 +642,18 @@ static int check_utf8ness_and_warn(
|
||||||
_cleanup_free_ char *p = NULL;
|
_cleanup_free_ char *p = NULL;
|
||||||
|
|
||||||
p = utf8_escape_invalid(key);
|
p = utf8_escape_invalid(key);
|
||||||
log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
return -EINVAL;
|
"%s:%u: invalid UTF-8 in key '%s', ignoring.",
|
||||||
|
strna(filename), line, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value && !utf8_is_valid(value)) {
|
if (value && !utf8_is_valid(value)) {
|
||||||
_cleanup_free_ char *p = NULL;
|
_cleanup_free_ char *p = NULL;
|
||||||
|
|
||||||
p = utf8_escape_invalid(value);
|
p = utf8_escape_invalid(value);
|
||||||
log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
return -EINVAL;
|
"%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.",
|
||||||
|
strna(filename), line, key, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -703,17 +701,13 @@ static int parse_env_file_push(
|
||||||
int parse_env_filev(
|
int parse_env_filev(
|
||||||
FILE *f,
|
FILE *f,
|
||||||
const char *fname,
|
const char *fname,
|
||||||
const char *newline,
|
|
||||||
va_list ap) {
|
va_list ap) {
|
||||||
|
|
||||||
int r, n_pushed = 0;
|
int r, n_pushed = 0;
|
||||||
va_list aq;
|
va_list aq;
|
||||||
|
|
||||||
if (!newline)
|
|
||||||
newline = NEWLINE;
|
|
||||||
|
|
||||||
va_copy(aq, ap);
|
va_copy(aq, ap);
|
||||||
r = parse_env_file_internal(f, fname, newline, parse_env_file_push, &aq, &n_pushed);
|
r = parse_env_file_internal(f, fname, parse_env_file_push, &aq, &n_pushed);
|
||||||
va_end(aq);
|
va_end(aq);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -721,17 +715,16 @@ int parse_env_filev(
|
||||||
return n_pushed;
|
return n_pushed;
|
||||||
}
|
}
|
||||||
|
|
||||||
int parse_env_file(
|
int parse_env_file_sentinel(
|
||||||
FILE *f,
|
FILE *f,
|
||||||
const char *fname,
|
const char *fname,
|
||||||
const char *newline,
|
|
||||||
...) {
|
...) {
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
va_start(ap, newline);
|
va_start(ap, fname);
|
||||||
r = parse_env_filev(f, fname, newline, ap);
|
r = parse_env_filev(f, fname, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
@ -768,14 +761,11 @@ static int load_env_file_push(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) {
|
int load_env_file(FILE *f, const char *fname, char ***rl) {
|
||||||
char **m = NULL;
|
char **m = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!newline)
|
r = parse_env_file_internal(f, fname, load_env_file_push, &m, NULL);
|
||||||
newline = NEWLINE;
|
|
||||||
|
|
||||||
r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL);
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
strv_free(m);
|
strv_free(m);
|
||||||
return r;
|
return r;
|
||||||
|
@ -817,14 +807,11 @@ static int load_env_file_push_pairs(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) {
|
int load_env_file_pairs(FILE *f, const char *fname, char ***rl) {
|
||||||
char **m = NULL;
|
char **m = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!newline)
|
r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m, NULL);
|
||||||
newline = NEWLINE;
|
|
||||||
|
|
||||||
r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL);
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
strv_free(m);
|
strv_free(m);
|
||||||
return r;
|
return r;
|
||||||
|
@ -877,7 +864,7 @@ int merge_env_file(
|
||||||
* plus "extended" substitutions, unlike other exported parsing functions.
|
* plus "extended" substitutions, unlike other exported parsing functions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return parse_env_file_internal(f, fname, NEWLINE, merge_env_file_push, env, NULL);
|
return parse_env_file_internal(f, fname, merge_env_file_push, env, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_env_var(FILE *f, const char *v) {
|
static void write_env_var(FILE *f, const char *v) {
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
|
#define LONG_LINE_MAX (1U*1024U*1024U)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
WRITE_STRING_FILE_CREATE = 1 << 0,
|
WRITE_STRING_FILE_CREATE = 1 << 0,
|
||||||
WRITE_STRING_FILE_ATOMIC = 1 << 1,
|
WRITE_STRING_FILE_ATOMIC = 1 << 1,
|
||||||
|
@ -17,6 +19,7 @@ typedef enum {
|
||||||
WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1 << 3,
|
WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1 << 3,
|
||||||
WRITE_STRING_FILE_SYNC = 1 << 4,
|
WRITE_STRING_FILE_SYNC = 1 << 4,
|
||||||
WRITE_STRING_FILE_DISABLE_BUFFER = 1 << 5,
|
WRITE_STRING_FILE_DISABLE_BUFFER = 1 << 5,
|
||||||
|
WRITE_STRING_FILE_NOFOLLOW = 1 << 6,
|
||||||
|
|
||||||
/* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one
|
/* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one
|
||||||
more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file()
|
more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file()
|
||||||
|
@ -41,10 +44,11 @@ int read_full_stream(FILE *f, char **contents, size_t *size);
|
||||||
|
|
||||||
int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
|
int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
|
||||||
|
|
||||||
int parse_env_filev(FILE *f, const char *fname, const char *separator, va_list ap);
|
int parse_env_filev(FILE *f, const char *fname, va_list ap);
|
||||||
int parse_env_file(FILE *f, const char *fname, const char *separator, ...) _sentinel_;
|
int parse_env_file_sentinel(FILE *f, const char *fname, ...) _sentinel_;
|
||||||
int load_env_file(FILE *f, const char *fname, const char *separator, char ***l);
|
#define parse_env_file(f, fname, ...) parse_env_file_sentinel(f, fname, __VA_ARGS__, NULL)
|
||||||
int load_env_file_pairs(FILE *f, const char *fname, const char *separator, char ***l);
|
int load_env_file(FILE *f, const char *fname, char ***l);
|
||||||
|
int load_env_file_pairs(FILE *f, const char *fname, char ***l);
|
||||||
|
|
||||||
int merge_env_file(char ***env, FILE *f, const char *fname);
|
int merge_env_file(char ***env, FILE *f, const char *fname);
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "def.h"
|
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "hostname-util.h"
|
#include "hostname-util.h"
|
||||||
|
|
|
@ -317,6 +317,7 @@ int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union
|
||||||
|
|
||||||
#if 0 /* NM_IGNORED */
|
#if 0 /* NM_IGNORED */
|
||||||
int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
|
int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
|
||||||
|
_cleanup_free_ char *buf = NULL;
|
||||||
const char *suffix;
|
const char *suffix;
|
||||||
int r, ifi = 0;
|
int r, ifi = 0;
|
||||||
|
|
||||||
|
@ -344,7 +345,11 @@ int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s = strndupa(s, suffix - s);
|
buf = strndup(s, suffix - s);
|
||||||
|
if (!buf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
s = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = in_addr_from_string_auto(s, family, ret);
|
r = in_addr_from_string_auto(s, family, ret);
|
||||||
|
@ -495,12 +500,14 @@ int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int in_addr_prefix_from_string(
|
int in_addr_prefix_from_string_internal(
|
||||||
const char *p,
|
const char *p,
|
||||||
|
bool use_default_prefixlen,
|
||||||
int family,
|
int family,
|
||||||
union in_addr_union *ret_prefix,
|
union in_addr_union *ret_prefix,
|
||||||
unsigned char *ret_prefixlen) {
|
unsigned char *ret_prefixlen) {
|
||||||
|
|
||||||
|
_cleanup_free_ char *str = NULL;
|
||||||
union in_addr_union buffer;
|
union in_addr_union buffer;
|
||||||
const char *e, *l;
|
const char *e, *l;
|
||||||
unsigned char k;
|
unsigned char k;
|
||||||
|
@ -512,9 +519,13 @@ int in_addr_prefix_from_string(
|
||||||
return -EAFNOSUPPORT;
|
return -EAFNOSUPPORT;
|
||||||
|
|
||||||
e = strchr(p, '/');
|
e = strchr(p, '/');
|
||||||
if (e)
|
if (e) {
|
||||||
l = strndupa(p, e - p);
|
str = strndup(p, e - p);
|
||||||
else
|
if (!str)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
l = str;
|
||||||
|
} else
|
||||||
l = p;
|
l = p;
|
||||||
|
|
||||||
r = in_addr_from_string(family, l, &buffer);
|
r = in_addr_from_string(family, l, &buffer);
|
||||||
|
@ -525,6 +536,13 @@ int in_addr_prefix_from_string(
|
||||||
r = in_addr_parse_prefixlen(family, e+1, &k);
|
r = in_addr_parse_prefixlen(family, e+1, &k);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
} else if (use_default_prefixlen) {
|
||||||
|
if (family == AF_INET) {
|
||||||
|
r = in4_addr_default_prefixlen(&buffer.in, &k);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
} else
|
||||||
|
k = 0;
|
||||||
} else
|
} else
|
||||||
k = FAMILY_ADDRESS_SIZE(family) * 8;
|
k = FAMILY_ADDRESS_SIZE(family) * 8;
|
||||||
|
|
||||||
|
@ -536,12 +554,14 @@ int in_addr_prefix_from_string(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int in_addr_prefix_from_string_auto(
|
int in_addr_prefix_from_string_auto_internal(
|
||||||
const char *p,
|
const char *p,
|
||||||
|
bool use_default_prefixlen,
|
||||||
int *ret_family,
|
int *ret_family,
|
||||||
union in_addr_union *ret_prefix,
|
union in_addr_union *ret_prefix,
|
||||||
unsigned char *ret_prefixlen) {
|
unsigned char *ret_prefixlen) {
|
||||||
|
|
||||||
|
_cleanup_free_ char *str = NULL;
|
||||||
union in_addr_union buffer;
|
union in_addr_union buffer;
|
||||||
const char *e, *l;
|
const char *e, *l;
|
||||||
unsigned char k;
|
unsigned char k;
|
||||||
|
@ -550,9 +570,13 @@ int in_addr_prefix_from_string_auto(
|
||||||
assert(p);
|
assert(p);
|
||||||
|
|
||||||
e = strchr(p, '/');
|
e = strchr(p, '/');
|
||||||
if (e)
|
if (e) {
|
||||||
l = strndupa(p, e - p);
|
str = strndup(p, e - p);
|
||||||
else
|
if (!str)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
l = str;
|
||||||
|
} else
|
||||||
l = p;
|
l = p;
|
||||||
|
|
||||||
r = in_addr_from_string_auto(l, &family, &buffer);
|
r = in_addr_from_string_auto(l, &family, &buffer);
|
||||||
|
@ -563,6 +587,13 @@ int in_addr_prefix_from_string_auto(
|
||||||
r = in_addr_parse_prefixlen(family, e+1, &k);
|
r = in_addr_parse_prefixlen(family, e+1, &k);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
} else if (use_default_prefixlen) {
|
||||||
|
if (family == AF_INET) {
|
||||||
|
r = in4_addr_default_prefixlen(&buffer.in, &k);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
} else
|
||||||
|
k = 0;
|
||||||
} else
|
} else
|
||||||
k = FAMILY_ADDRESS_SIZE(family) * 8;
|
k = FAMILY_ADDRESS_SIZE(family) * 8;
|
||||||
|
|
||||||
|
|
|
@ -45,15 +45,29 @@ int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mas
|
||||||
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen);
|
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen);
|
||||||
int in_addr_prefix_covers(int family, const union in_addr_union *prefix, unsigned char prefixlen, const union in_addr_union *address);
|
int in_addr_prefix_covers(int family, const union in_addr_union *prefix, unsigned char prefixlen, const union in_addr_union *address);
|
||||||
int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret);
|
int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret);
|
||||||
int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
|
int in_addr_prefix_from_string_internal(const char *p, bool use_default_prefixlen, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
|
||||||
int in_addr_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
|
int in_addr_prefix_from_string_auto_internal(const char *p, bool use_default_prefixlen, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
|
||||||
|
static inline int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) {
|
||||||
|
return in_addr_prefix_from_string_internal(p, false, family, ret_prefix, ret_prefixlen);
|
||||||
|
}
|
||||||
|
static inline int in_addr_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) {
|
||||||
|
return in_addr_prefix_from_string_auto_internal(p, false, ret_family, ret_prefix, ret_prefixlen);
|
||||||
|
}
|
||||||
|
static inline int in_addr_default_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) {
|
||||||
|
return in_addr_prefix_from_string_internal(p, true, family, ret_prefix, ret_prefixlen);
|
||||||
|
}
|
||||||
|
static inline int in_addr_default_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen) {
|
||||||
|
return in_addr_prefix_from_string_auto_internal(p, true, ret_family, ret_prefix, ret_prefixlen);
|
||||||
|
}
|
||||||
|
|
||||||
static inline size_t FAMILY_ADDRESS_SIZE(int family) {
|
static inline size_t FAMILY_ADDRESS_SIZE(int family) {
|
||||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||||
return family == AF_INET6 ? 16 : 4;
|
return family == AF_INET6 ? 16 : 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define IN_ADDR_NULL ((union in_addr_union) {})
|
/* Workaround for clang, explicitly specify the maximum-size element here.
|
||||||
|
* See also oss-fuzz#11344. */
|
||||||
|
#define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} })
|
||||||
|
|
||||||
void in_addr_data_hash_func(const void *p, struct siphash *state);
|
void in_addr_data_hash_func(const void *p, struct siphash *state);
|
||||||
int in_addr_data_compare_func(const void *a, const void *b);
|
int in_addr_data_compare_func(const void *a, const void *b);
|
||||||
|
|
|
@ -36,10 +36,12 @@ typedef enum LogTarget{
|
||||||
_LOG_TARGET_INVALID = -1
|
_LOG_TARGET_INVALID = -1
|
||||||
} LogTarget;
|
} LogTarget;
|
||||||
|
|
||||||
#define LOG_REALM_PLUS_LEVEL(realm, level) \
|
/* Note to readers: << and >> have lower precedence than & and | */
|
||||||
((realm) << 10 | (level))
|
#define LOG_REALM_PLUS_LEVEL(realm, level) ((realm) << 10 | (level))
|
||||||
#define LOG_REALM_REMOVE_LEVEL(realm_level) \
|
#define LOG_REALM_REMOVE_LEVEL(realm_level) ((realm_level) >> 10)
|
||||||
((realm_level >> 10))
|
#define SYNTHETIC_ERRNO(num) (1 << 30 | (num))
|
||||||
|
#define IS_SYNTHETIC_ERRNO(val) ((val) >> 30 & 1)
|
||||||
|
#define ERRNO_VALUE(val) (abs(val) & 255)
|
||||||
|
|
||||||
void log_set_target(LogTarget target);
|
void log_set_target(LogTarget target);
|
||||||
void log_set_max_level_realm(LogRealm realm, int level);
|
void log_set_max_level_realm(LogRealm realm, int level);
|
||||||
|
@ -207,10 +209,10 @@ void log_assert_failed_return_realm(
|
||||||
#define log_full_errno_realm(realm, level, error, ...) \
|
#define log_full_errno_realm(realm, level, error, ...) \
|
||||||
({ \
|
({ \
|
||||||
int _level = (level), _e = (error), _realm = (realm); \
|
int _level = (level), _e = (error), _realm = (realm); \
|
||||||
(log_get_max_level_realm(_realm) >= LOG_PRI(_level)) \
|
(log_get_max_level_realm(_realm) >= LOG_PRI(_level)) \
|
||||||
? log_internal_realm(LOG_REALM_PLUS_LEVEL(_realm, _level), _e, \
|
? log_internal_realm(LOG_REALM_PLUS_LEVEL(_realm, _level), _e, \
|
||||||
__FILE__, __LINE__, __func__, __VA_ARGS__) \
|
__FILE__, __LINE__, __func__, __VA_ARGS__) \
|
||||||
: -abs(_e); \
|
: -ERRNO_VALUE(_e); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define log_full_errno(level, error, ...) \
|
#define log_full_errno(level, error, ...) \
|
||||||
|
@ -324,3 +326,5 @@ int log_syntax_invalid_utf8_internal(
|
||||||
})
|
})
|
||||||
|
|
||||||
#define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG)
|
#define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG)
|
||||||
|
|
||||||
|
void log_setup_service(void);
|
||||||
|
|
|
@ -8,30 +8,30 @@
|
||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#define _printf_(a, b) __attribute__ ((format (printf, a, b)))
|
#define _printf_(a, b) __attribute__ ((__format__(printf, a, b)))
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
# define _alloc_(...)
|
# define _alloc_(...)
|
||||||
#else
|
#else
|
||||||
# define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__)))
|
# define _alloc_(...) __attribute__ ((__alloc_size__(__VA_ARGS__)))
|
||||||
#endif
|
#endif
|
||||||
#define _sentinel_ __attribute__ ((sentinel))
|
#define _sentinel_ __attribute__ ((__sentinel__))
|
||||||
#define _unused_ __attribute__ ((unused))
|
#define _unused_ __attribute__ ((__unused__))
|
||||||
#define _destructor_ __attribute__ ((destructor))
|
#define _destructor_ __attribute__ ((__destructor__))
|
||||||
#define _pure_ __attribute__ ((pure))
|
#define _pure_ __attribute__ ((__pure__))
|
||||||
#define _const_ __attribute__ ((const))
|
#define _const_ __attribute__ ((__const__))
|
||||||
#define _deprecated_ __attribute__ ((deprecated))
|
#define _deprecated_ __attribute__ ((__deprecated__))
|
||||||
#define _packed_ __attribute__ ((packed))
|
#define _packed_ __attribute__ ((__packed__))
|
||||||
#define _malloc_ __attribute__ ((malloc))
|
#define _malloc_ __attribute__ ((__malloc__))
|
||||||
#define _weak_ __attribute__ ((weak))
|
#define _weak_ __attribute__ ((__weak__))
|
||||||
#define _likely_(x) (__builtin_expect(!!(x), 1))
|
#define _likely_(x) (__builtin_expect(!!(x), 1))
|
||||||
#define _unlikely_(x) (__builtin_expect(!!(x), 0))
|
#define _unlikely_(x) (__builtin_expect(!!(x), 0))
|
||||||
#define _public_ __attribute__ ((visibility("default")))
|
#define _public_ __attribute__ ((__visibility__("default")))
|
||||||
#define _hidden_ __attribute__ ((visibility("hidden")))
|
#define _hidden_ __attribute__ ((__visibility__("hidden")))
|
||||||
#define _weakref_(x) __attribute__((weakref(#x)))
|
#define _weakref_(x) __attribute__((__weakref__(#x)))
|
||||||
#define _alignas_(x) __attribute__((aligned(__alignof(x))))
|
#define _alignas_(x) __attribute__((__aligned__(__alignof(x))))
|
||||||
#define _cleanup_(x) __attribute__((cleanup(x)))
|
#define _cleanup_(x) __attribute__((__cleanup__(x)))
|
||||||
#if __GNUC__ >= 7
|
#if __GNUC__ >= 7
|
||||||
#define _fallthrough_ __attribute__((fallthrough))
|
#define _fallthrough_ __attribute__((__fallthrough__))
|
||||||
#else
|
#else
|
||||||
#define _fallthrough_
|
#define _fallthrough_
|
||||||
#endif
|
#endif
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
#if __STDC_VERSION__ >= 201112L
|
#if __STDC_VERSION__ >= 201112L
|
||||||
#define _noreturn_ _Noreturn
|
#define _noreturn_ _Noreturn
|
||||||
#else
|
#else
|
||||||
#define _noreturn_ __attribute__((noreturn))
|
#define _noreturn_ __attribute__((__noreturn__))
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -343,6 +343,12 @@ static inline int __coverity_check__(int condition) {
|
||||||
} \
|
} \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
|
||||||
|
#define return_with_errno(r, err) \
|
||||||
|
do { \
|
||||||
|
errno = abs(err); \
|
||||||
|
return r; \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
#define PTR_TO_INT(p) ((int) ((intptr_t) (p)))
|
#define PTR_TO_INT(p) ((int) ((intptr_t) (p)))
|
||||||
#define INT_TO_PTR(u) ((void *) ((intptr_t) (u)))
|
#define INT_TO_PTR(u) ((void *) ((intptr_t) (u)))
|
||||||
#define PTR_TO_UINT(p) ((unsigned) ((uintptr_t) (p)))
|
#define PTR_TO_UINT(p) ((unsigned) ((uintptr_t) (p)))
|
||||||
|
@ -392,7 +398,7 @@ static inline int __coverity_check__(int condition) {
|
||||||
#define SET_FLAG(v, flag, b) \
|
#define SET_FLAG(v, flag, b) \
|
||||||
(v) = (b) ? ((v) | (flag)) : ((v) & ~(flag))
|
(v) = (b) ? ((v) | (flag)) : ((v) & ~(flag))
|
||||||
#define FLAGS_SET(v, flags) \
|
#define FLAGS_SET(v, flags) \
|
||||||
(((v) & (flags)) == (flags))
|
((~(v) & (flags)) == 0)
|
||||||
|
|
||||||
#define CASE_F(X) case X:
|
#define CASE_F(X) case X:
|
||||||
#define CASE_F_1(CASE, X) CASE_F(X)
|
#define CASE_F_1(CASE, X) CASE_F(X)
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "architecture.h"
|
#include "architecture.h"
|
||||||
#include "def.h"
|
|
||||||
#include "escape.h"
|
#include "escape.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
|
@ -837,7 +836,7 @@ int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) {
|
||||||
void sigkill_wait(pid_t pid) {
|
void sigkill_wait(pid_t pid) {
|
||||||
assert(pid > 1);
|
assert(pid > 1);
|
||||||
|
|
||||||
if (kill(pid, SIGKILL) > 0)
|
if (kill(pid, SIGKILL) >= 0)
|
||||||
(void) wait_for_terminate(pid, NULL);
|
(void) wait_for_terminate(pid, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -855,7 +854,7 @@ void sigkill_waitp(pid_t *pid) {
|
||||||
void sigterm_wait(pid_t pid) {
|
void sigterm_wait(pid_t pid) {
|
||||||
assert(pid > 1);
|
assert(pid > 1);
|
||||||
|
|
||||||
if (kill_and_sigcont(pid, SIGTERM) > 0)
|
if (kill_and_sigcont(pid, SIGTERM) >= 0)
|
||||||
(void) wait_for_terminate(pid, NULL);
|
(void) wait_for_terminate(pid, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1237,8 +1236,7 @@ int must_be_root(void) {
|
||||||
if (geteuid() == 0)
|
if (geteuid() == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
log_error("Need to be root.");
|
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Need to be root.");
|
||||||
return -EPERM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int safe_fork_full(
|
int safe_fork_full(
|
||||||
|
@ -1418,6 +1416,60 @@ int safe_fork_full(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int namespace_fork(
|
||||||
|
const char *outer_name,
|
||||||
|
const char *inner_name,
|
||||||
|
const int except_fds[],
|
||||||
|
size_t n_except_fds,
|
||||||
|
ForkFlags flags,
|
||||||
|
int pidns_fd,
|
||||||
|
int mntns_fd,
|
||||||
|
int netns_fd,
|
||||||
|
int userns_fd,
|
||||||
|
int root_fd,
|
||||||
|
pid_t *ret_pid) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* This is much like safe_fork(), but forks twice, and joins the specified namespaces in the middle
|
||||||
|
* process. This ensures that we are fully a member of the destination namespace, with pidns an all, so that
|
||||||
|
* /proc/self/fd works correctly. */
|
||||||
|
|
||||||
|
r = safe_fork_full(outer_name, except_fds, n_except_fds, (flags|FORK_DEATHSIG) & ~(FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE), ret_pid);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0) {
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
/* Child */
|
||||||
|
|
||||||
|
r = namespace_enter(pidns_fd, mntns_fd, netns_fd, userns_fd, root_fd);
|
||||||
|
if (r < 0) {
|
||||||
|
log_full_errno(FLAGS_SET(flags, FORK_LOG) ? LOG_ERR : LOG_DEBUG, r, "Failed to join namespace: %m");
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We mask a few flags here that either make no sense for the grandchild, or that we don't have to do again */
|
||||||
|
r = safe_fork_full(inner_name, except_fds, n_except_fds, flags & ~(FORK_WAIT|FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_NULL_STDIO), &pid);
|
||||||
|
if (r < 0)
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
if (r == 0) {
|
||||||
|
/* Child */
|
||||||
|
if (ret_pid)
|
||||||
|
*ret_pid = pid;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = wait_for_terminate_and_check(inner_name, pid, FLAGS_SET(flags, FORK_LOG) ? WAIT_LOG : 0);
|
||||||
|
if (r < 0)
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
|
|
||||||
|
_exit(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) {
|
int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) {
|
||||||
bool stdout_is_tty, stderr_is_tty;
|
bool stdout_is_tty, stderr_is_tty;
|
||||||
size_t n, i;
|
size_t n, i;
|
||||||
|
|
|
@ -161,6 +161,8 @@ static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
|
||||||
return safe_fork_full(name, NULL, 0, flags, ret_pid);
|
return safe_fork_full(name, NULL, 0, flags, ret_pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int namespace_fork(const char *outer_name, const char *inner_name, const int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid);
|
||||||
|
|
||||||
int fork_agent(const char *name, const int except[], size_t n_except, pid_t *pid, const char *path, ...) _sentinel_;
|
int fork_agent(const char *name, const int except[], size_t n_except, pid_t *pid, const char *path, ...) _sentinel_;
|
||||||
|
|
||||||
int set_oom_score_adjust(int value);
|
int set_oom_score_adjust(int value);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#include "nm-sd-adapt.h"
|
#include "nm-sd-adapt.h"
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
#include <cpuid.h>
|
#include <cpuid.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -32,10 +32,13 @@
|
||||||
#include "random-util.h"
|
#include "random-util.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
|
#if HAS_FEATURE_MEMORY_SANITIZER
|
||||||
|
#include <sanitizer/msan_interface.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
int rdrand64(uint64_t *ret) {
|
int rdrand(unsigned long *ret) {
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
static int have_rdrand = -1;
|
static int have_rdrand = -1;
|
||||||
unsigned char err;
|
unsigned char err;
|
||||||
|
|
||||||
|
@ -58,6 +61,11 @@ int rdrand64(uint64_t *ret) {
|
||||||
"setc %1"
|
"setc %1"
|
||||||
: "=r" (*ret),
|
: "=r" (*ret),
|
||||||
"=qm" (err));
|
"=qm" (err));
|
||||||
|
|
||||||
|
#if HAS_FEATURE_MEMORY_SANITIZER
|
||||||
|
__msan_unpoison(&err, sizeof(err));
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!err)
|
if (!err)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
|
@ -67,92 +75,139 @@ int rdrand64(uint64_t *ret) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int acquire_random_bytes(void *p, size_t n, bool high_quality_required) {
|
int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
|
||||||
static int have_syscall = -1;
|
static int have_syscall = -1;
|
||||||
|
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
size_t already_done = 0;
|
bool got_some = false;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* Gathers some randomness from the kernel. This call will never block. If
|
/* Gathers some randomness from the kernel (or the CPU if the RANDOM_ALLOW_RDRAND flag is set). This call won't
|
||||||
* high_quality_required, it will always return some data from the kernel,
|
* block, unless the RANDOM_BLOCK flag is set. If RANDOM_DONT_DRAIN is set, an error is returned if the random
|
||||||
* regardless of whether the random pool is fully initialized or not.
|
* pool is not initialized. Otherwise it will always return some data from the kernel, regardless of whether
|
||||||
* Otherwise, it will return success if at least some random bytes were
|
* the random pool is fully initialized or not. */
|
||||||
* successfully acquired, and an error if the kernel has no entropy whatsover
|
|
||||||
* for us. */
|
if (n == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (FLAGS_SET(flags, RANDOM_ALLOW_RDRAND))
|
||||||
|
/* Try x86-64' RDRAND intrinsic if we have it. We only use it if high quality randomness is not
|
||||||
|
* required, as we don't trust it (who does?). Note that we only do a single iteration of RDRAND here,
|
||||||
|
* even though the Intel docs suggest calling this in a tight loop of 10 invocations or so. That's
|
||||||
|
* because we don't really care about the quality here. We generally prefer using RDRAND if the caller
|
||||||
|
* allows us too, since this way we won't drain the kernel randomness pool if we don't need it, as the
|
||||||
|
* pool's entropy is scarce. */
|
||||||
|
for (;;) {
|
||||||
|
unsigned long u;
|
||||||
|
size_t m;
|
||||||
|
|
||||||
|
if (rdrand(&u) < 0) {
|
||||||
|
if (got_some && FLAGS_SET(flags, RANDOM_EXTEND_WITH_PSEUDO)) {
|
||||||
|
/* Fill in the remaining bytes using pseudo-random values */
|
||||||
|
pseudo_random_bytes(p, n);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OK, this didn't work, let's go to getrandom() + /dev/urandom instead */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m = MIN(sizeof(u), n);
|
||||||
|
memcpy(p, &u, m);
|
||||||
|
|
||||||
|
p = (uint8_t*) p + m;
|
||||||
|
n -= m;
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
return 0; /* Yay, success! */
|
||||||
|
|
||||||
|
got_some = true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Use the getrandom() syscall unless we know we don't have it. */
|
/* Use the getrandom() syscall unless we know we don't have it. */
|
||||||
if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) {
|
if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) {
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
#if !HAVE_GETRANDOM
|
#if !HAVE_GETRANDOM
|
||||||
/* NetworkManager Note: systemd calls the syscall directly in this case. Don't add that workaround.
|
/* NetworkManager Note: systemd calls the syscall directly in this case. Don't add that workaround.
|
||||||
* If you don't compile against a libc that provides getrandom(), you don't get it. */
|
* If you don't compile against a libc that provides getrandom(), you don't get it. */
|
||||||
r = -1;
|
r = -1;
|
||||||
errno = ENOSYS;
|
errno = ENOSYS;
|
||||||
#else
|
#else
|
||||||
r = getrandom(p, n, GRND_NONBLOCK);
|
r = getrandom(p, n, FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_NONBLOCK);
|
||||||
#endif
|
#endif
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
have_syscall = true;
|
have_syscall = true;
|
||||||
if ((size_t) r == n)
|
|
||||||
return 0;
|
|
||||||
if (!high_quality_required) {
|
|
||||||
/* Fill in the remaining bytes using pseudorandom values */
|
|
||||||
pseudorandom_bytes((uint8_t*) p + r, n - r);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
already_done = r;
|
if ((size_t) r == n)
|
||||||
} else if (errno == ENOSYS)
|
return 0; /* Yay, success! */
|
||||||
/* We lack the syscall, continue with reading from /dev/urandom. */
|
|
||||||
have_syscall = false;
|
|
||||||
else if (errno == EAGAIN) {
|
|
||||||
/* The kernel has no entropy whatsoever. Let's remember to
|
|
||||||
* use the syscall the next time again though.
|
|
||||||
*
|
|
||||||
* If high_quality_required is false, return an error so that
|
|
||||||
* random_bytes() can produce some pseudorandom
|
|
||||||
* bytes. Otherwise, fall back to /dev/urandom, which we know
|
|
||||||
* is empty, but the kernel will produce some bytes for us on
|
|
||||||
* a best-effort basis. */
|
|
||||||
have_syscall = true;
|
|
||||||
|
|
||||||
if (!high_quality_required) {
|
assert((size_t) r < n);
|
||||||
uint64_t u;
|
p = (uint8_t*) p + r;
|
||||||
size_t k;
|
n -= r;
|
||||||
|
|
||||||
/* Try x86-64' RDRAND intrinsic if we have it. We only use it if high quality
|
if (FLAGS_SET(flags, RANDOM_EXTEND_WITH_PSEUDO)) {
|
||||||
* randomness is not required, as we don't trust it (who does?). Note that we only do a
|
/* Fill in the remaining bytes using pseudo-random values */
|
||||||
* single iteration of RDRAND here, even though the Intel docs suggest calling this in
|
pseudo_random_bytes(p, n);
|
||||||
* a tight loop of 10 invocatins or so. That's because we don't really care about the
|
return 0;
|
||||||
* quality here. */
|
}
|
||||||
|
|
||||||
if (rdrand64(&u) < 0)
|
got_some = true;
|
||||||
|
|
||||||
|
/* Hmm, we didn't get enough good data but the caller insists on good data? Then try again */
|
||||||
|
if (FLAGS_SET(flags, RANDOM_BLOCK))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Fill in the rest with /dev/urandom */
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else if (r == 0) {
|
||||||
|
have_syscall = true;
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
} else if (errno == ENOSYS) {
|
||||||
|
/* We lack the syscall, continue with reading from /dev/urandom. */
|
||||||
|
have_syscall = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else if (errno == EAGAIN) {
|
||||||
|
/* The kernel has no entropy whatsoever. Let's remember to use the syscall the next
|
||||||
|
* time again though.
|
||||||
|
*
|
||||||
|
* If RANDOM_DONT_DRAIN is set, return an error so that random_bytes() can produce some
|
||||||
|
* pseudo-random bytes instead. Otherwise, fall back to /dev/urandom, which we know is empty,
|
||||||
|
* but the kernel will produce some bytes for us on a best-effort basis. */
|
||||||
|
have_syscall = true;
|
||||||
|
|
||||||
|
if (got_some && FLAGS_SET(flags, RANDOM_EXTEND_WITH_PSEUDO)) {
|
||||||
|
/* Fill in the remaining bytes using pseudorandom values */
|
||||||
|
pseudo_random_bytes(p, n);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FLAGS_SET(flags, RANDOM_DONT_DRAIN))
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
|
|
||||||
k = MIN(n, sizeof(u));
|
/* Use /dev/urandom instead */
|
||||||
memcpy(p, &u, k);
|
break;
|
||||||
|
} else
|
||||||
/* We only get 64bit out of RDRAND, the rest let's fill up with pseudo-random crap. */
|
return -errno;
|
||||||
pseudorandom_bytes((uint8_t*) p + k, n - k);
|
}
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
return -errno;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return errno == ENOENT ? -ENOSYS : -errno;
|
return errno == ENOENT ? -ENOSYS : -errno;
|
||||||
|
|
||||||
return loop_read_exact(fd, (uint8_t*) p + already_done, n - already_done, true);
|
return loop_read_exact(fd, p, n, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize_srand(void) {
|
void initialize_srand(void) {
|
||||||
static bool srand_called = false;
|
static bool srand_called = false;
|
||||||
unsigned x;
|
unsigned x;
|
||||||
#if HAVE_SYS_AUXV_H
|
#if HAVE_SYS_AUXV_H
|
||||||
void *auxv;
|
const void *auxv;
|
||||||
#endif
|
#endif
|
||||||
|
unsigned long k;
|
||||||
|
|
||||||
if (srand_called)
|
if (srand_called)
|
||||||
return;
|
return;
|
||||||
|
@ -162,7 +217,7 @@ void initialize_srand(void) {
|
||||||
* try to make use of that to seed the pseudo-random generator. It's
|
* try to make use of that to seed the pseudo-random generator. It's
|
||||||
* better than nothing... */
|
* better than nothing... */
|
||||||
|
|
||||||
auxv = (void*) getauxval(AT_RANDOM);
|
auxv = (const void*) getauxval(AT_RANDOM);
|
||||||
if (auxv) {
|
if (auxv) {
|
||||||
assert_cc(sizeof(x) <= 16);
|
assert_cc(sizeof(x) <= 16);
|
||||||
memcpy(&x, auxv, sizeof(x));
|
memcpy(&x, auxv, sizeof(x));
|
||||||
|
@ -173,6 +228,9 @@ void initialize_srand(void) {
|
||||||
x ^= (unsigned) now(CLOCK_REALTIME);
|
x ^= (unsigned) now(CLOCK_REALTIME);
|
||||||
x ^= (unsigned) gettid();
|
x ^= (unsigned) gettid();
|
||||||
|
|
||||||
|
if (rdrand(&k) >= 0)
|
||||||
|
x ^= (unsigned) k;
|
||||||
|
|
||||||
srand(x);
|
srand(x);
|
||||||
srand_called = true;
|
srand_called = true;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +243,7 @@ void initialize_srand(void) {
|
||||||
# define RAND_STEP 1
|
# define RAND_STEP 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void pseudorandom_bytes(void *p, size_t n) {
|
void pseudo_random_bytes(void *p, size_t n) {
|
||||||
uint8_t *q;
|
uint8_t *q;
|
||||||
|
|
||||||
initialize_srand();
|
initialize_srand();
|
||||||
|
@ -208,13 +266,10 @@ void pseudorandom_bytes(void *p, size_t n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void random_bytes(void *p, size_t n) {
|
void random_bytes(void *p, size_t n) {
|
||||||
int r;
|
|
||||||
|
|
||||||
r = acquire_random_bytes(p, n, false);
|
if (genuine_random_bytes(p, n, RANDOM_EXTEND_WITH_PSEUDO|RANDOM_DONT_DRAIN|RANDOM_ALLOW_RDRAND) >= 0)
|
||||||
if (r >= 0)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* If some idiot made /dev/urandom unavailable to us, or the
|
/* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */
|
||||||
* kernel has no entropy, use a PRNG instead. */
|
pseudo_random_bytes(p, n);
|
||||||
return pseudorandom_bytes(p, n);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,17 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
int acquire_random_bytes(void *p, size_t n, bool high_quality_required);
|
typedef enum RandomFlags {
|
||||||
void pseudorandom_bytes(void *p, size_t n);
|
RANDOM_EXTEND_WITH_PSEUDO = 1 << 0, /* If we can't get enough genuine randomness, but some, fill up the rest with pseudo-randomness */
|
||||||
void random_bytes(void *p, size_t n);
|
RANDOM_BLOCK = 1 << 1, /* Rather block than return crap randomness (only if the kernel supports that) */
|
||||||
|
RANDOM_DONT_DRAIN = 1 << 2, /* If we can't get any randomness at all, return early with -EAGAIN */
|
||||||
|
RANDOM_ALLOW_RDRAND = 1 << 3, /* Allow usage of the CPU RNG */
|
||||||
|
} RandomFlags;
|
||||||
|
|
||||||
|
int genuine_random_bytes(void *p, size_t n, RandomFlags flags); /* returns "genuine" randomness, optionally filled upwith pseudo random, if not enough is available */
|
||||||
|
void pseudo_random_bytes(void *p, size_t n); /* returns only pseudo-randommess (but possibly seeded from something better) */
|
||||||
|
void random_bytes(void *p, size_t n); /* returns genuine randomness if cheaply available, and pseudo randomness if not. */
|
||||||
|
|
||||||
void initialize_srand(void);
|
void initialize_srand(void);
|
||||||
|
|
||||||
static inline uint64_t random_u64(void) {
|
static inline uint64_t random_u64(void) {
|
||||||
|
@ -22,4 +30,4 @@ static inline uint32_t random_u32(void) {
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rdrand64(uint64_t *ret);
|
int rdrand(unsigned long *ret);
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifdef __CHECKER__
|
#ifdef __CHECKER__
|
||||||
#define __sd_bitwise __attribute__((bitwise))
|
#define __sd_bitwise __attribute__((__bitwise__))
|
||||||
#define __sd_force __attribute__((force))
|
#define __sd_force __attribute__((__force__))
|
||||||
#else
|
#else
|
||||||
#define __sd_bitwise
|
#define __sd_bitwise
|
||||||
#define __sd_force
|
#define __sd_force
|
||||||
|
|
|
@ -50,10 +50,8 @@ int is_dir(const char* path, bool follow) {
|
||||||
|
|
||||||
int is_dir_fd(int fd) {
|
int is_dir_fd(int fd) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int r;
|
|
||||||
|
|
||||||
r = fstat(fd, &st);
|
if (fstat(fd, &st) < 0)
|
||||||
if (r < 0)
|
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
return !!S_ISDIR(st.st_mode);
|
return !!S_ISDIR(st.st_mode);
|
||||||
|
@ -218,15 +216,47 @@ int fd_is_network_fs(int fd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int fd_is_network_ns(int fd) {
|
int fd_is_network_ns(int fd) {
|
||||||
|
struct statfs s;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = fd_is_fs_type(fd, NSFS_MAGIC);
|
/* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice
|
||||||
if (r <= 0)
|
* way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle
|
||||||
return r;
|
* this somewhat nicely.
|
||||||
|
*
|
||||||
|
* This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not
|
||||||
|
* refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */
|
||||||
|
|
||||||
|
if (fstatfs(fd, &s) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
if (!is_fs_type(&s, NSFS_MAGIC)) {
|
||||||
|
/* On really old kernels, there was no "nsfs", and network namespace sockets belonged to procfs
|
||||||
|
* instead. Handle that in a somewhat smart way. */
|
||||||
|
|
||||||
|
if (is_fs_type(&s, PROC_SUPER_MAGIC)) {
|
||||||
|
struct statfs t;
|
||||||
|
|
||||||
|
/* OK, so it is procfs. Let's see if our own network namespace is procfs, too. If so, then the
|
||||||
|
* passed fd might refer to a network namespace, but we can't know for sure. In that case,
|
||||||
|
* return a recognizable error. */
|
||||||
|
|
||||||
|
if (statfs("/proc/self/ns/net", &t) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
if (s.f_type == t.f_type)
|
||||||
|
return -EUCLEAN; /* It's possible, we simply don't know */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; /* No! */
|
||||||
|
}
|
||||||
|
|
||||||
r = ioctl(fd, NS_GET_NSTYPE);
|
r = ioctl(fd, NS_GET_NSTYPE);
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
|
if (errno == ENOTTY) /* Old kernels didn't know this ioctl, let's also return a recognizable error in that case */
|
||||||
|
return -EUCLEAN;
|
||||||
|
|
||||||
return -errno;
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
return r == CLONE_NEWNET;
|
return r == CLONE_NEWNET;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#define snprintf_ok(buf, len, fmt, ...) \
|
#define snprintf_ok(buf, len, fmt, ...) \
|
||||||
((size_t) snprintf(buf, len, fmt, __VA_ARGS__) < (len))
|
((size_t) snprintf(buf, len, fmt, __VA_ARGS__) < (len))
|
||||||
|
@ -18,6 +19,9 @@
|
||||||
do { \
|
do { \
|
||||||
int _argtypes[128]; \
|
int _argtypes[128]; \
|
||||||
size_t _i, _k; \
|
size_t _i, _k; \
|
||||||
|
/* See https://github.com/google/sanitizers/issues/992 */ \
|
||||||
|
if (HAS_FEATURE_MEMORY_SANITIZER) \
|
||||||
|
zero(_argtypes); \
|
||||||
_k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \
|
_k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \
|
||||||
assert(_k < ELEMENTSOF(_argtypes)); \
|
assert(_k < ELEMENTSOF(_argtypes)); \
|
||||||
for (_i = 0; _i < _k; _i++) { \
|
for (_i = 0; _i < _k; _i++) { \
|
||||||
|
|
|
@ -171,7 +171,7 @@ char **strv_new_ap(const char *x, va_list ap) {
|
||||||
return TAKE_PTR(a);
|
return TAKE_PTR(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
char **strv_new(const char *x, ...) {
|
char **strv_new_internal(const char *x, ...) {
|
||||||
char **r;
|
char **r;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
|
@ -662,7 +662,7 @@ char **strv_split_nulstr(const char *s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!r)
|
if (!r)
|
||||||
return strv_new(NULL, NULL);
|
return strv_new(NULL);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,8 +54,9 @@ bool strv_equal(char **a, char **b);
|
||||||
|
|
||||||
#define strv_contains(l, s) (!!strv_find((l), (s)))
|
#define strv_contains(l, s) (!!strv_find((l), (s)))
|
||||||
|
|
||||||
char **strv_new(const char *x, ...) _sentinel_;
|
char **strv_new_internal(const char *x, ...) _sentinel_;
|
||||||
char **strv_new_ap(const char *x, va_list ap);
|
char **strv_new_ap(const char *x, va_list ap);
|
||||||
|
#define strv_new(...) strv_new_internal(__VA_ARGS__, NULL)
|
||||||
|
|
||||||
#define STRV_IGNORE ((const char *) -1)
|
#define STRV_IGNORE ((const char *) -1)
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "def.h"
|
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
|
@ -873,7 +872,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
|
||||||
return tmp.return_value;
|
return tmp.return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* extract_multiplier(char *p, usec_t *multiplier) {
|
static const char* extract_multiplier(const char *p, usec_t *multiplier) {
|
||||||
static const struct {
|
static const struct {
|
||||||
const char *suffix;
|
const char *suffix;
|
||||||
usec_t usec;
|
usec_t usec;
|
||||||
|
@ -947,8 +946,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
usec_t multiplier = default_unit, k;
|
usec_t multiplier = default_unit, k;
|
||||||
long long l, z = 0;
|
long long l;
|
||||||
unsigned n = 0;
|
|
||||||
char *e;
|
char *e;
|
||||||
|
|
||||||
p += strspn(p, WHITESPACE);
|
p += strspn(p, WHITESPACE);
|
||||||
|
@ -971,46 +969,47 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
if (*e == '.') {
|
if (*e == '.') {
|
||||||
char *b = e + 1;
|
p = e + 1;
|
||||||
|
p += strspn(p, DIGITS);
|
||||||
/* Don't allow "0.-0", "3.+1" or "3. 1" */
|
|
||||||
if (IN_SET(*b, '-', '+') || isspace(*b))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
z = strtoll(b, &e, 10);
|
|
||||||
if (errno > 0)
|
|
||||||
return -errno;
|
|
||||||
if (z < 0)
|
|
||||||
return -ERANGE;
|
|
||||||
if (e == b)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
n = e - b;
|
|
||||||
|
|
||||||
} else if (e == p)
|
} else if (e == p)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
else
|
||||||
|
p = e;
|
||||||
|
|
||||||
e += strspn(e, WHITESPACE);
|
s = extract_multiplier(p + strspn(p, WHITESPACE), &multiplier);
|
||||||
p = extract_multiplier(e, &multiplier);
|
if (s == p && *s != '\0')
|
||||||
|
/* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
something = true;
|
p = s;
|
||||||
|
|
||||||
|
if ((usec_t) l >= USEC_INFINITY / multiplier)
|
||||||
k = ((usec_t) -1) / multiplier;
|
|
||||||
if ((usec_t) l + 1 >= k || (usec_t) z >= k)
|
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
k = (usec_t) z * multiplier;
|
k = (usec_t) l * multiplier;
|
||||||
|
if (k >= USEC_INFINITY - r)
|
||||||
for (; n > 0; n--)
|
|
||||||
k /= 10;
|
|
||||||
|
|
||||||
k += (usec_t) l * multiplier;
|
|
||||||
if (k >= ((usec_t) -1) - r)
|
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
r += k;
|
r += k;
|
||||||
|
|
||||||
|
something = true;
|
||||||
|
|
||||||
|
if (*e == '.') {
|
||||||
|
usec_t m = multiplier / 10;
|
||||||
|
const char *b;
|
||||||
|
|
||||||
|
for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
|
||||||
|
k = (usec_t) (*b - '0') * m;
|
||||||
|
if (k >= USEC_INFINITY - r)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
r += k;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
|
||||||
|
if (b == e + 1)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*usec = r;
|
*usec = r;
|
||||||
|
@ -1037,44 +1036,60 @@ int parse_sec_fix_0(const char *t, usec_t *ret) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int parse_nsec(const char *t, nsec_t *nsec) {
|
static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) {
|
||||||
static const struct {
|
static const struct {
|
||||||
const char *suffix;
|
const char *suffix;
|
||||||
nsec_t nsec;
|
nsec_t nsec;
|
||||||
} table[] = {
|
} table[] = {
|
||||||
{ "seconds", NSEC_PER_SEC },
|
{ "seconds", NSEC_PER_SEC },
|
||||||
{ "second", NSEC_PER_SEC },
|
{ "second", NSEC_PER_SEC },
|
||||||
{ "sec", NSEC_PER_SEC },
|
{ "sec", NSEC_PER_SEC },
|
||||||
{ "s", NSEC_PER_SEC },
|
{ "s", NSEC_PER_SEC },
|
||||||
{ "minutes", NSEC_PER_MINUTE },
|
{ "minutes", NSEC_PER_MINUTE },
|
||||||
{ "minute", NSEC_PER_MINUTE },
|
{ "minute", NSEC_PER_MINUTE },
|
||||||
{ "min", NSEC_PER_MINUTE },
|
{ "min", NSEC_PER_MINUTE },
|
||||||
{ "months", NSEC_PER_MONTH },
|
{ "months", NSEC_PER_MONTH },
|
||||||
{ "month", NSEC_PER_MONTH },
|
{ "month", NSEC_PER_MONTH },
|
||||||
{ "msec", NSEC_PER_MSEC },
|
{ "M", NSEC_PER_MONTH },
|
||||||
{ "ms", NSEC_PER_MSEC },
|
{ "msec", NSEC_PER_MSEC },
|
||||||
{ "m", NSEC_PER_MINUTE },
|
{ "ms", NSEC_PER_MSEC },
|
||||||
{ "hours", NSEC_PER_HOUR },
|
{ "m", NSEC_PER_MINUTE },
|
||||||
{ "hour", NSEC_PER_HOUR },
|
{ "hours", NSEC_PER_HOUR },
|
||||||
{ "hr", NSEC_PER_HOUR },
|
{ "hour", NSEC_PER_HOUR },
|
||||||
{ "h", NSEC_PER_HOUR },
|
{ "hr", NSEC_PER_HOUR },
|
||||||
{ "days", NSEC_PER_DAY },
|
{ "h", NSEC_PER_HOUR },
|
||||||
{ "day", NSEC_PER_DAY },
|
{ "days", NSEC_PER_DAY },
|
||||||
{ "d", NSEC_PER_DAY },
|
{ "day", NSEC_PER_DAY },
|
||||||
{ "weeks", NSEC_PER_WEEK },
|
{ "d", NSEC_PER_DAY },
|
||||||
{ "week", NSEC_PER_WEEK },
|
{ "weeks", NSEC_PER_WEEK },
|
||||||
{ "w", NSEC_PER_WEEK },
|
{ "week", NSEC_PER_WEEK },
|
||||||
{ "years", NSEC_PER_YEAR },
|
{ "w", NSEC_PER_WEEK },
|
||||||
{ "year", NSEC_PER_YEAR },
|
{ "years", NSEC_PER_YEAR },
|
||||||
{ "y", NSEC_PER_YEAR },
|
{ "year", NSEC_PER_YEAR },
|
||||||
{ "usec", NSEC_PER_USEC },
|
{ "y", NSEC_PER_YEAR },
|
||||||
{ "us", NSEC_PER_USEC },
|
{ "usec", NSEC_PER_USEC },
|
||||||
{ "µs", NSEC_PER_USEC },
|
{ "us", NSEC_PER_USEC },
|
||||||
{ "nsec", 1ULL },
|
{ "µs", NSEC_PER_USEC },
|
||||||
{ "ns", 1ULL },
|
{ "nsec", 1ULL },
|
||||||
{ "", 1ULL }, /* default is nsec */
|
{ "ns", 1ULL },
|
||||||
|
{ "", 1ULL }, /* default is nsec */
|
||||||
};
|
};
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < ELEMENTSOF(table); i++) {
|
||||||
|
char *e;
|
||||||
|
|
||||||
|
e = startswith(p, table[i].suffix);
|
||||||
|
if (e) {
|
||||||
|
*multiplier = table[i].nsec;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_nsec(const char *t, nsec_t *nsec) {
|
||||||
const char *p, *s;
|
const char *p, *s;
|
||||||
nsec_t r = 0;
|
nsec_t r = 0;
|
||||||
bool something = false;
|
bool something = false;
|
||||||
|
@ -1096,8 +1111,8 @@ int parse_nsec(const char *t, nsec_t *nsec) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
long long l, z = 0;
|
nsec_t multiplier = 1, k;
|
||||||
size_t n = 0, i;
|
long long l;
|
||||||
char *e;
|
char *e;
|
||||||
|
|
||||||
p += strspn(p, WHITESPACE);
|
p += strspn(p, WHITESPACE);
|
||||||
|
@ -1109,7 +1124,7 @@ int parse_nsec(const char *t, nsec_t *nsec) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*p == '-')
|
if (*p == '-') /* Don't allow "-0" */
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
@ -1120,54 +1135,47 @@ int parse_nsec(const char *t, nsec_t *nsec) {
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
if (*e == '.') {
|
if (*e == '.') {
|
||||||
char *b = e + 1;
|
p = e + 1;
|
||||||
|
p += strspn(p, DIGITS);
|
||||||
if (IN_SET(*b, '-', '+') || isspace(*b))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
z = strtoll(b, &e, 10);
|
|
||||||
if (errno > 0)
|
|
||||||
return -errno;
|
|
||||||
if (z < 0)
|
|
||||||
return -ERANGE;
|
|
||||||
if (e == b)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
n = e - b;
|
|
||||||
|
|
||||||
} else if (e == p)
|
} else if (e == p)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
else
|
||||||
|
p = e;
|
||||||
|
|
||||||
e += strspn(e, WHITESPACE);
|
s = extract_nsec_multiplier(p + strspn(p, WHITESPACE), &multiplier);
|
||||||
|
if (s == p && *s != '\0')
|
||||||
|
/* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56'*/
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
for (i = 0; i < ELEMENTSOF(table); i++)
|
p = s;
|
||||||
if (startswith(e, table[i].suffix)) {
|
|
||||||
nsec_t k;
|
|
||||||
|
|
||||||
k = ((nsec_t) -1) / table[i].nsec;
|
if ((nsec_t) l >= NSEC_INFINITY / multiplier)
|
||||||
if ((nsec_t) l + 1 >= k || (nsec_t) z >= k)
|
return -ERANGE;
|
||||||
return -ERANGE;
|
|
||||||
|
|
||||||
k = (nsec_t) z * table[i].nsec;
|
k = (nsec_t) l * multiplier;
|
||||||
|
if (k >= NSEC_INFINITY - r)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
for (; n > 0; n--)
|
r += k;
|
||||||
k /= 10;
|
|
||||||
|
|
||||||
k += (nsec_t) l * table[i].nsec;
|
something = true;
|
||||||
if (k >= ((nsec_t) -1) - r)
|
|
||||||
|
if (*e == '.') {
|
||||||
|
nsec_t m = multiplier / 10;
|
||||||
|
const char *b;
|
||||||
|
|
||||||
|
for (b = e + 1; *b >= '0' && *b <= '9'; b++, m /= 10) {
|
||||||
|
k = (nsec_t) (*b - '0') * m;
|
||||||
|
if (k >= NSEC_INFINITY - r)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
r += k;
|
r += k;
|
||||||
p = e + strlen(table[i].suffix);
|
|
||||||
|
|
||||||
something = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i >= ELEMENTSOF(table))
|
/* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
|
||||||
return -EINVAL;
|
if (b == e + 1)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*nsec = r;
|
*nsec = r;
|
||||||
|
@ -1195,7 +1203,7 @@ int get_timezones(char ***ret) {
|
||||||
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
zones = strv_new("UTC", NULL);
|
zones = strv_new("UTC");
|
||||||
if (!zones)
|
if (!zones)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
|
@ -170,6 +170,28 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool memeqzero(const void *data, size_t length) {
|
||||||
|
/* Does the buffer consist entirely of NULs?
|
||||||
|
* Copied from https://github.com/systemd/casync/, copied in turn from
|
||||||
|
* https://github.com/rustyrussell/ccan/blob/master/ccan/mem/mem.c#L92,
|
||||||
|
* which is licensed CC-0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const uint8_t *p = data;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* Check first 16 bytes manually */
|
||||||
|
for (i = 0; i < 16; i++, length--) {
|
||||||
|
if (length == 0)
|
||||||
|
return true;
|
||||||
|
if (p[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we know first 16 bytes are NUL, memcmp with self. */
|
||||||
|
return memcmp(data, p + i, length) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
int on_ac_power(void) {
|
int on_ac_power(void) {
|
||||||
bool found_offline = false, found_online = false;
|
bool found_offline = false, found_online = false;
|
||||||
_cleanup_closedir_ DIR *d = NULL;
|
_cleanup_closedir_ DIR *d = NULL;
|
||||||
|
@ -253,7 +275,9 @@ int container_get_leader(const char *machine, pid_t *pid) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
p = strjoina("/run/systemd/machines/", machine);
|
p = strjoina("/run/systemd/machines/", machine);
|
||||||
r = parse_env_file(NULL, p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
|
r = parse_env_file(NULL, p,
|
||||||
|
"LEADER", &s,
|
||||||
|
"CLASS", &class);
|
||||||
if (r == -ENOENT)
|
if (r == -ENOENT)
|
||||||
return -EHOSTDOWN;
|
return -EHOSTDOWN;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -611,7 +635,7 @@ void disable_coredumps(void) {
|
||||||
if (detect_container() > 0)
|
if (detect_container() > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
r = write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0);
|
r = write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", WRITE_STRING_FILE_DISABLE_BUFFER);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_debug_errno(r, "Failed to turn off coredumps, ignoring: %m");
|
log_debug_errno(r, "Failed to turn off coredumps, ignoring: %m");
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,6 +159,10 @@ int on_ac_power(void);
|
||||||
|
|
||||||
#define zero(x) (memzero(&(x), sizeof(x)))
|
#define zero(x) (memzero(&(x), sizeof(x)))
|
||||||
|
|
||||||
|
bool memeqzero(const void *data, size_t length);
|
||||||
|
|
||||||
|
#define eqzero(x) memeqzero(x, sizeof(x))
|
||||||
|
|
||||||
static inline void *mempset(void *s, int c, size_t n) {
|
static inline void *mempset(void *s, int c, size_t n) {
|
||||||
memset(s, c, n);
|
memset(s, c, n);
|
||||||
return (uint8_t*)s + n;
|
return (uint8_t*)s + n;
|
||||||
|
@ -168,7 +172,8 @@ static inline void _reset_errno_(int *saved_errno) {
|
||||||
errno = *saved_errno;
|
errno = *saved_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno
|
#define PROTECT_ERRNO \
|
||||||
|
_cleanup_(_reset_errno_) __attribute__((__unused__)) int _saved_errno_ = errno
|
||||||
|
|
||||||
static inline int negative_errno(void) {
|
static inline int negative_errno(void) {
|
||||||
/* This helper should be used to shut up gcc if you know 'errno' is
|
/* This helper should be used to shut up gcc if you know 'errno' is
|
||||||
|
|
|
@ -159,7 +159,12 @@ int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) {
|
int dhcp_identifier_set_iaid(
|
||||||
|
int ifindex,
|
||||||
|
const uint8_t *mac,
|
||||||
|
size_t mac_len,
|
||||||
|
bool legacy_unstable_byteorder,
|
||||||
|
void *_id) {
|
||||||
#if 0 /* NM_IGNORED */
|
#if 0 /* NM_IGNORED */
|
||||||
/* name is a pointer to memory in the sd_device struct, so must
|
/* name is a pointer to memory in the sd_device struct, so must
|
||||||
* have the same scope */
|
* have the same scope */
|
||||||
|
@ -169,19 +174,20 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_i
|
||||||
#endif /* NM_IGNORED */
|
#endif /* NM_IGNORED */
|
||||||
const char *name = NULL;
|
const char *name = NULL;
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
|
uint32_t id32;
|
||||||
|
|
||||||
#if 0 /* NM_IGNORED */
|
#if 0 /* NM_IGNORED */
|
||||||
if (detect_container() <= 0) {
|
if (detect_container() <= 0) {
|
||||||
/* not in a container, udev will be around */
|
/* not in a container, udev will be around */
|
||||||
char ifindex_str[2 + DECIMAL_STR_MAX(int)];
|
char ifindex_str[2 + DECIMAL_STR_MAX(int)];
|
||||||
int initialized, r;
|
int r;
|
||||||
|
|
||||||
sprintf(ifindex_str, "n%d", ifindex);
|
sprintf(ifindex_str, "n%d", ifindex);
|
||||||
if (sd_device_new_from_device_id(&device, ifindex_str) >= 0) {
|
if (sd_device_new_from_device_id(&device, ifindex_str) >= 0) {
|
||||||
r = sd_device_get_is_initialized(device, &initialized);
|
r = sd_device_get_is_initialized(device);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (!initialized)
|
if (r == 0)
|
||||||
/* not yet ready */
|
/* not yet ready */
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
|
@ -198,10 +204,18 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_i
|
||||||
/* fall back to MAC address if no predictable name available */
|
/* fall back to MAC address if no predictable name available */
|
||||||
id = siphash24(mac, mac_len, HASH_KEY.bytes);
|
id = siphash24(mac, mac_len, HASH_KEY.bytes);
|
||||||
|
|
||||||
id = htole64(id);
|
id32 = (id & 0xffffffff) ^ (id >> 32);
|
||||||
|
|
||||||
/* fold into 32 bits */
|
if (legacy_unstable_byteorder)
|
||||||
unaligned_write_be32(_id, (id & 0xffffffff) ^ (id >> 32));
|
/* for historical reasons (a bug), the bits were swapped and thus
|
||||||
|
* the result was endianness dependant. Preserve that behavior. */
|
||||||
|
id32 = __bswap_32(id32);
|
||||||
|
else
|
||||||
|
/* the fixed behavior returns a stable byte order. Since LE is expected
|
||||||
|
* to be more common, swap the bytes on LE to give the same as legacy
|
||||||
|
* behavior. */
|
||||||
|
id32 = be32toh(id32);
|
||||||
|
|
||||||
|
unaligned_write_ne32(_id, id32);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,4 +57,4 @@ int dhcp_identifier_set_duid_llt(struct duid *duid, usec_t t, const uint8_t *add
|
||||||
int dhcp_identifier_set_duid_ll(struct duid *duid, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len);
|
int dhcp_identifier_set_duid_ll(struct duid *duid, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len);
|
||||||
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len);
|
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len);
|
||||||
int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len);
|
int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len);
|
||||||
int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id);
|
int dhcp_identifier_set_iaid(int ifindex, const uint8_t *mac, size_t mac_len, bool legacy_unstable_byteorder, void *_id);
|
||||||
|
|
|
@ -108,70 +108,62 @@ int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, ui
|
||||||
|
|
||||||
/* IP */
|
/* IP */
|
||||||
|
|
||||||
if (packet->ip.version != IPVERSION) {
|
if (packet->ip.version != IPVERSION)
|
||||||
log_debug("ignoring packet: not IPv4");
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
return -EINVAL;
|
"ignoring packet: not IPv4");
|
||||||
}
|
|
||||||
|
|
||||||
if (packet->ip.ihl < 5) {
|
if (packet->ip.ihl < 5)
|
||||||
log_debug("ignoring packet: IPv4 IHL (%u words) invalid",
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
packet->ip.ihl);
|
"ignoring packet: IPv4 IHL (%u words) invalid",
|
||||||
return -EINVAL;
|
packet->ip.ihl);
|
||||||
}
|
|
||||||
|
|
||||||
hdrlen = packet->ip.ihl * 4;
|
hdrlen = packet->ip.ihl * 4;
|
||||||
if (hdrlen < 20) {
|
if (hdrlen < 20)
|
||||||
log_debug("ignoring packet: IPv4 IHL (%zu bytes) "
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"smaller than minimum (20 bytes)", hdrlen);
|
"ignoring packet: IPv4 IHL (%zu bytes) "
|
||||||
return -EINVAL;
|
"smaller than minimum (20 bytes)",
|
||||||
}
|
hdrlen);
|
||||||
|
|
||||||
if (len < hdrlen) {
|
if (len < hdrlen)
|
||||||
log_debug("ignoring packet: packet (%zu bytes) "
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"smaller than expected (%zu) by IP header", len,
|
"ignoring packet: packet (%zu bytes) "
|
||||||
hdrlen);
|
"smaller than expected (%zu) by IP header",
|
||||||
return -EINVAL;
|
len, hdrlen);
|
||||||
}
|
|
||||||
|
|
||||||
/* UDP */
|
/* UDP */
|
||||||
|
|
||||||
if (packet->ip.protocol != IPPROTO_UDP) {
|
if (packet->ip.protocol != IPPROTO_UDP)
|
||||||
log_debug("ignoring packet: not UDP");
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
return -EINVAL;
|
"ignoring packet: not UDP");
|
||||||
}
|
|
||||||
|
|
||||||
if (len < hdrlen + be16toh(packet->udp.len)) {
|
if (len < hdrlen + be16toh(packet->udp.len))
|
||||||
log_debug("ignoring packet: packet (%zu bytes) "
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"smaller than expected (%zu) by UDP header", len,
|
"ignoring packet: packet (%zu bytes) "
|
||||||
hdrlen + be16toh(packet->udp.len));
|
"smaller than expected (%zu) by UDP header",
|
||||||
return -EINVAL;
|
len, hdrlen + be16toh(packet->udp.len));
|
||||||
}
|
|
||||||
|
|
||||||
if (be16toh(packet->udp.dest) != port) {
|
if (be16toh(packet->udp.dest) != port)
|
||||||
log_debug("ignoring packet: to port %u, which "
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"is not the DHCP client port (%u)",
|
"ignoring packet: to port %u, which "
|
||||||
be16toh(packet->udp.dest), port);
|
"is not the DHCP client port (%u)",
|
||||||
return -EINVAL;
|
be16toh(packet->udp.dest), port);
|
||||||
}
|
|
||||||
|
|
||||||
/* checksums - computing these is relatively expensive, so only do it
|
/* checksums - computing these is relatively expensive, so only do it
|
||||||
if all the other checks have passed
|
if all the other checks have passed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen)) {
|
if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen))
|
||||||
log_debug("ignoring packet: invalid IP checksum");
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
return -EINVAL;
|
"ignoring packet: invalid IP checksum");
|
||||||
}
|
|
||||||
|
|
||||||
if (checksum && packet->udp.check) {
|
if (checksum && packet->udp.check) {
|
||||||
packet->ip.check = packet->udp.len;
|
packet->ip.check = packet->udp.len;
|
||||||
packet->ip.ttl = 0;
|
packet->ip.ttl = 0;
|
||||||
|
|
||||||
if (dhcp_packet_checksum((uint8_t*)&packet->ip.ttl,
|
if (dhcp_packet_checksum((uint8_t*)&packet->ip.ttl,
|
||||||
be16toh(packet->udp.len) + 12)) {
|
be16toh(packet->udp.len) + 12))
|
||||||
log_debug("ignoring packet: invalid UDP checksum");
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
return -EINVAL;
|
"ignoring packet: invalid UDP checksum");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -34,3 +34,6 @@ struct sd_lldp {
|
||||||
|
|
||||||
#define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__)
|
#define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__)
|
||||||
#define log_lldp(fmt, ...) log_lldp_errno(0, fmt, ##__VA_ARGS__)
|
#define log_lldp(fmt, ...) log_lldp_errno(0, fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
const char* lldp_event_to_string(sd_lldp_event e) _const_;
|
||||||
|
sd_lldp_event lldp_event_from_string(const char *s) _pure_;
|
||||||
|
|
|
@ -258,11 +258,10 @@ int config_parse_ifalias(const char *unit,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(*s);
|
if (isempty(n))
|
||||||
if (*n)
|
*s = mfree(*s);
|
||||||
*s = TAKE_PTR(n);
|
|
||||||
else
|
else
|
||||||
*s = NULL;
|
free_and_replace(*s, n);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -297,7 +296,7 @@ int config_parse_hwaddr(const char *unit,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*hwaddr = TAKE_PTR(n);
|
free_and_replace(*hwaddr, n);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "dhcp-lease-internal.h"
|
#include "dhcp-lease-internal.h"
|
||||||
#include "dhcp-protocol.h"
|
#include "dhcp-protocol.h"
|
||||||
#include "dns-domain.h"
|
#include "dns-domain.h"
|
||||||
|
#include "event-util.h"
|
||||||
#include "hostname-util.h"
|
#include "hostname-util.h"
|
||||||
#include "random-util.h"
|
#include "random-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
@ -375,6 +376,7 @@ static int dhcp_client_set_iaid_duid_internal(
|
||||||
if (iaid == 0) {
|
if (iaid == 0) {
|
||||||
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
|
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
|
||||||
client->mac_addr_len,
|
client->mac_addr_len,
|
||||||
|
true,
|
||||||
&client->client_id.ns.iaid);
|
&client->client_id.ns.iaid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -550,11 +552,10 @@ static int client_initialize(sd_dhcp_client *client) {
|
||||||
|
|
||||||
client->fd = asynchronous_close(client->fd);
|
client->fd = asynchronous_close(client->fd);
|
||||||
|
|
||||||
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
|
(void) event_source_disable(client->timeout_resend);
|
||||||
|
(void) event_source_disable(client->timeout_t1);
|
||||||
client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
|
(void) event_source_disable(client->timeout_t2);
|
||||||
client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
|
(void) event_source_disable(client->timeout_expire);
|
||||||
client->timeout_expire = sd_event_source_unref(client->timeout_expire);
|
|
||||||
|
|
||||||
client->attempt = 1;
|
client->attempt = 1;
|
||||||
|
|
||||||
|
@ -655,7 +656,8 @@ static int client_message_init(
|
||||||
|
|
||||||
client->client_id.type = 255;
|
client->client_id.type = 255;
|
||||||
|
|
||||||
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid);
|
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len,
|
||||||
|
true, &client->client_id.ns.iaid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1068,22 +1070,11 @@ static int client_timeout_resend(
|
||||||
|
|
||||||
next_timeout += (random_u32() & 0x1fffff);
|
next_timeout += (random_u32() & 0x1fffff);
|
||||||
|
|
||||||
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
|
r = event_reset_time(client->event, &client->timeout_resend,
|
||||||
|
clock_boottime_or_monotonic(),
|
||||||
r = sd_event_add_time(client->event,
|
next_timeout, 10 * USEC_PER_MSEC,
|
||||||
&client->timeout_resend,
|
client_timeout_resend, client,
|
||||||
clock_boottime_or_monotonic(),
|
client->event_priority, "dhcp4-resend-timer", true);
|
||||||
next_timeout, 10 * USEC_PER_MSEC,
|
|
||||||
client_timeout_resend, client);
|
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
r = sd_event_source_set_priority(client->timeout_resend,
|
|
||||||
client->event_priority);
|
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
@ -1180,31 +1171,16 @@ static int client_initialize_time_events(sd_dhcp_client *client) {
|
||||||
assert(client);
|
assert(client);
|
||||||
assert(client->event);
|
assert(client->event);
|
||||||
|
|
||||||
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
|
|
||||||
|
|
||||||
if (client->start_delay) {
|
if (client->start_delay) {
|
||||||
assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0);
|
assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0);
|
||||||
usec += client->start_delay;
|
usec += client->start_delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_event_add_time(client->event,
|
r = event_reset_time(client->event, &client->timeout_resend,
|
||||||
&client->timeout_resend,
|
clock_boottime_or_monotonic(),
|
||||||
clock_boottime_or_monotonic(),
|
usec, 0,
|
||||||
usec, 0,
|
client_timeout_resend, client,
|
||||||
client_timeout_resend, client);
|
client->event_priority, "dhcp4-resend-timer", true);
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
r = sd_event_source_set_priority(client->timeout_resend,
|
|
||||||
client->event_priority);
|
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
|
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
error:
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
client_stop(client, r);
|
client_stop(client, r);
|
||||||
|
|
||||||
|
@ -1462,13 +1438,14 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
|
||||||
assert(client->lease);
|
assert(client->lease);
|
||||||
assert(client->lease->lifetime);
|
assert(client->lease->lifetime);
|
||||||
|
|
||||||
client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
|
|
||||||
client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
|
|
||||||
client->timeout_expire = sd_event_source_unref(client->timeout_expire);
|
|
||||||
|
|
||||||
/* don't set timers for infinite leases */
|
/* don't set timers for infinite leases */
|
||||||
if (client->lease->lifetime == 0xffffffff)
|
if (client->lease->lifetime == 0xffffffff) {
|
||||||
|
(void) event_source_disable(client->timeout_t1);
|
||||||
|
(void) event_source_disable(client->timeout_t2);
|
||||||
|
(void) event_source_disable(client->timeout_expire);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
|
r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -1520,19 +1497,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* arm lifetime timeout */
|
/* arm lifetime timeout */
|
||||||
r = sd_event_add_time(client->event, &client->timeout_expire,
|
r = event_reset_time(client->event, &client->timeout_expire,
|
||||||
clock_boottime_or_monotonic(),
|
clock_boottime_or_monotonic(),
|
||||||
lifetime_timeout, 10 * USEC_PER_MSEC,
|
lifetime_timeout, 10 * USEC_PER_MSEC,
|
||||||
client_timeout_expire, client);
|
client_timeout_expire, client,
|
||||||
if (r < 0)
|
client->event_priority, "dhcp4-lifetime", true);
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sd_event_source_set_priority(client->timeout_expire,
|
|
||||||
client->event_priority);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sd_event_source_set_description(client->timeout_expire, "dhcp4-lifetime");
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1544,21 +1513,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* arm T2 timeout */
|
/* arm T2 timeout */
|
||||||
r = sd_event_add_time(client->event,
|
r = event_reset_time(client->event, &client->timeout_t2,
|
||||||
&client->timeout_t2,
|
clock_boottime_or_monotonic(),
|
||||||
clock_boottime_or_monotonic(),
|
t2_timeout, 10 * USEC_PER_MSEC,
|
||||||
t2_timeout,
|
client_timeout_t2, client,
|
||||||
10 * USEC_PER_MSEC,
|
client->event_priority, "dhcp4-t2-timeout", true);
|
||||||
client_timeout_t2, client);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sd_event_source_set_priority(client->timeout_t2,
|
|
||||||
client->event_priority);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sd_event_source_set_description(client->timeout_t2, "dhcp4-t2-timeout");
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1570,20 +1529,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* arm T1 timeout */
|
/* arm T1 timeout */
|
||||||
r = sd_event_add_time(client->event,
|
r = event_reset_time(client->event, &client->timeout_t1,
|
||||||
&client->timeout_t1,
|
clock_boottime_or_monotonic(),
|
||||||
clock_boottime_or_monotonic(),
|
t1_timeout, 10 * USEC_PER_MSEC,
|
||||||
t1_timeout, 10 * USEC_PER_MSEC,
|
client_timeout_t1, client,
|
||||||
client_timeout_t1, client);
|
client->event_priority, "dhcp4-t1-timer", true);
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sd_event_source_set_priority(client->timeout_t1,
|
|
||||||
client->event_priority);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = sd_event_source_set_description(client->timeout_t1, "dhcp4-t1-timer");
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1608,26 +1558,14 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
|
||||||
r = client_handle_offer(client, message, len);
|
r = client_handle_offer(client, message, len);
|
||||||
if (r >= 0) {
|
if (r >= 0) {
|
||||||
|
|
||||||
client->timeout_resend =
|
|
||||||
sd_event_source_unref(client->timeout_resend);
|
|
||||||
|
|
||||||
client->state = DHCP_STATE_REQUESTING;
|
client->state = DHCP_STATE_REQUESTING;
|
||||||
client->attempt = 1;
|
client->attempt = 1;
|
||||||
|
|
||||||
r = sd_event_add_time(client->event,
|
r = event_reset_time(client->event, &client->timeout_resend,
|
||||||
&client->timeout_resend,
|
clock_boottime_or_monotonic(),
|
||||||
clock_boottime_or_monotonic(),
|
0, 0,
|
||||||
0, 0,
|
client_timeout_resend, client,
|
||||||
client_timeout_resend, client);
|
client->event_priority, "dhcp4-resend-timer", true);
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
r = sd_event_source_set_priority(client->timeout_resend,
|
|
||||||
client->event_priority);
|
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto error;
|
goto error;
|
||||||
} else if (r == -ENOMSG)
|
} else if (r == -ENOMSG)
|
||||||
|
@ -1644,8 +1582,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
|
||||||
r = client_handle_ack(client, message, len);
|
r = client_handle_ack(client, message, len);
|
||||||
if (r >= 0) {
|
if (r >= 0) {
|
||||||
client->start_delay = 0;
|
client->start_delay = 0;
|
||||||
client->timeout_resend =
|
(void) event_source_disable(client->timeout_resend);
|
||||||
sd_event_source_unref(client->timeout_resend);
|
|
||||||
client->receive_message =
|
client->receive_message =
|
||||||
sd_event_source_unref(client->receive_message);
|
sd_event_source_unref(client->receive_message);
|
||||||
client->fd = asynchronous_close(client->fd);
|
client->fd = asynchronous_close(client->fd);
|
||||||
|
@ -1685,9 +1622,6 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
|
||||||
|
|
||||||
} else if (r == -EADDRNOTAVAIL) {
|
} else if (r == -EADDRNOTAVAIL) {
|
||||||
/* got a NAK, let's restart the client */
|
/* got a NAK, let's restart the client */
|
||||||
client->timeout_resend =
|
|
||||||
sd_event_source_unref(client->timeout_resend);
|
|
||||||
|
|
||||||
client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
|
client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
|
||||||
|
|
||||||
r = client_initialize(client);
|
r = client_initialize(client);
|
||||||
|
@ -1963,9 +1897,12 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
|
||||||
|
|
||||||
log_dhcp_client(client, "FREE");
|
log_dhcp_client(client, "FREE");
|
||||||
|
|
||||||
client_initialize(client);
|
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
|
||||||
|
client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
|
||||||
|
client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
|
||||||
|
client->timeout_expire = sd_event_source_unref(client->timeout_expire);
|
||||||
|
|
||||||
client->receive_message = sd_event_source_unref(client->receive_message);
|
client_initialize(client);
|
||||||
|
|
||||||
sd_dhcp_client_detach_event(client);
|
sd_dhcp_client_detach_event(client);
|
||||||
|
|
||||||
|
@ -1985,19 +1922,20 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
|
||||||
|
|
||||||
assert_return(ret, -EINVAL);
|
assert_return(ret, -EINVAL);
|
||||||
|
|
||||||
client = new0(sd_dhcp_client, 1);
|
client = new(sd_dhcp_client, 1);
|
||||||
if (!client)
|
if (!client)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
client->n_ref = 1;
|
*client = (sd_dhcp_client) {
|
||||||
client->state = DHCP_STATE_INIT;
|
.n_ref = 1,
|
||||||
client->ifindex = -1;
|
.state = DHCP_STATE_INIT,
|
||||||
client->fd = -1;
|
.ifindex = -1,
|
||||||
client->attempt = 1;
|
.fd = -1,
|
||||||
client->mtu = DHCP_DEFAULT_MIN_SIZE;
|
.attempt = 1,
|
||||||
client->port = DHCP_PORT_CLIENT;
|
.mtu = DHCP_DEFAULT_MIN_SIZE,
|
||||||
|
.port = DHCP_PORT_CLIENT,
|
||||||
client->anonymize = !!anonymize;
|
.anonymize = !!anonymize,
|
||||||
|
};
|
||||||
/* NOTE: this could be moved to a function. */
|
/* NOTE: this could be moved to a function. */
|
||||||
if (anonymize) {
|
if (anonymize) {
|
||||||
client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize);
|
client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize);
|
||||||
|
|
|
@ -1018,7 +1018,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = parse_env_file(NULL, lease_file, NEWLINE,
|
r = parse_env_file(NULL, lease_file,
|
||||||
"ADDRESS", &address,
|
"ADDRESS", &address,
|
||||||
"ROUTER", &router,
|
"ROUTER", &router,
|
||||||
"NETMASK", &netmask,
|
"NETMASK", &netmask,
|
||||||
|
@ -1069,8 +1069,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
|
||||||
"OPTION_251", &options[27],
|
"OPTION_251", &options[27],
|
||||||
"OPTION_252", &options[28],
|
"OPTION_252", &options[28],
|
||||||
"OPTION_253", &options[29],
|
"OPTION_253", &options[29],
|
||||||
"OPTION_254", &options[30],
|
"OPTION_254", &options[30]);
|
||||||
NULL);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "dhcp6-lease-internal.h"
|
#include "dhcp6-lease-internal.h"
|
||||||
#include "dhcp6-protocol.h"
|
#include "dhcp6-protocol.h"
|
||||||
#include "dns-domain.h"
|
#include "dns-domain.h"
|
||||||
|
#include "event-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "hostname-util.h"
|
#include "hostname-util.h"
|
||||||
#include "in-addr-util.h"
|
#include "in-addr-util.h"
|
||||||
|
@ -416,12 +417,11 @@ static int client_reset(sd_dhcp6_client *client) {
|
||||||
|
|
||||||
client->retransmit_time = 0;
|
client->retransmit_time = 0;
|
||||||
client->retransmit_count = 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);
|
(void) event_source_disable(client->timeout_resend);
|
||||||
client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
|
(void) event_source_disable(client->timeout_resend_expire);
|
||||||
|
(void) event_source_disable(client->timeout_t1);
|
||||||
|
(void) event_source_disable(client->timeout_t2);
|
||||||
|
|
||||||
client->state = DHCP6_STATE_STOPPED;
|
client->state = DHCP6_STATE_STOPPED;
|
||||||
|
|
||||||
|
@ -608,8 +608,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
|
||||||
assert(client);
|
assert(client);
|
||||||
assert(client->lease);
|
assert(client->lease);
|
||||||
|
|
||||||
client->timeout_t2 =
|
(void) event_source_disable(client->timeout_t2);
|
||||||
sd_event_source_unref(client->timeout_t2);
|
|
||||||
|
|
||||||
log_dhcp6_client(client, "Timeout T2");
|
log_dhcp6_client(client, "Timeout T2");
|
||||||
|
|
||||||
|
@ -625,8 +624,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
|
||||||
assert(client);
|
assert(client);
|
||||||
assert(client->lease);
|
assert(client->lease);
|
||||||
|
|
||||||
client->timeout_t1 =
|
(void) event_source_disable(client->timeout_t1);
|
||||||
sd_event_source_unref(client->timeout_t1);
|
|
||||||
|
|
||||||
log_dhcp6_client(client, "Timeout T1");
|
log_dhcp6_client(client, "Timeout T1");
|
||||||
|
|
||||||
|
@ -674,7 +672,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
|
||||||
assert(client);
|
assert(client);
|
||||||
assert(client->event);
|
assert(client->event);
|
||||||
|
|
||||||
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
|
(void) event_source_disable(client->timeout_resend);
|
||||||
|
|
||||||
switch (client->state) {
|
switch (client->state) {
|
||||||
case DHCP6_STATE_INFORMATION_REQUEST:
|
case DHCP6_STATE_INFORMATION_REQUEST:
|
||||||
|
@ -716,7 +714,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
|
||||||
init_retransmit_time = DHCP6_REB_TIMEOUT;
|
init_retransmit_time = DHCP6_REB_TIMEOUT;
|
||||||
max_retransmit_time = DHCP6_REB_MAX_RT;
|
max_retransmit_time = DHCP6_REB_MAX_RT;
|
||||||
|
|
||||||
if (!client->timeout_resend_expire) {
|
if (event_source_is_enabled(client->timeout_resend_expire) <= 0) {
|
||||||
r = dhcp6_lease_ia_rebind_expire(&client->lease->ia,
|
r = dhcp6_lease_ia_rebind_expire(&client->lease->ia,
|
||||||
&expire);
|
&expire);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
|
@ -765,43 +763,24 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
|
||||||
log_dhcp6_client(client, "Next retransmission in %s",
|
log_dhcp6_client(client, "Next retransmission in %s",
|
||||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC));
|
format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC));
|
||||||
|
|
||||||
r = sd_event_add_time(client->event, &client->timeout_resend,
|
r = event_reset_time(client->event, &client->timeout_resend,
|
||||||
clock_boottime_or_monotonic(),
|
clock_boottime_or_monotonic(),
|
||||||
time_now + client->retransmit_time,
|
time_now + client->retransmit_time, 10 * USEC_PER_MSEC,
|
||||||
10 * USEC_PER_MSEC, client_timeout_resend,
|
client_timeout_resend, client,
|
||||||
client);
|
client->event_priority, "dhcp6-resend-timer", true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
r = sd_event_source_set_priority(client->timeout_resend,
|
if (max_retransmit_duration && event_source_is_enabled(client->timeout_resend_expire) <= 0) {
|
||||||
client->event_priority);
|
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timer");
|
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (max_retransmit_duration && !client->timeout_resend_expire) {
|
|
||||||
|
|
||||||
log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
|
log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
|
||||||
max_retransmit_duration / USEC_PER_SEC);
|
max_retransmit_duration / USEC_PER_SEC);
|
||||||
|
|
||||||
r = sd_event_add_time(client->event,
|
r = event_reset_time(client->event, &client->timeout_resend_expire,
|
||||||
&client->timeout_resend_expire,
|
clock_boottime_or_monotonic(),
|
||||||
clock_boottime_or_monotonic(),
|
time_now + max_retransmit_duration, USEC_PER_SEC,
|
||||||
time_now + max_retransmit_duration,
|
client_timeout_resend_expire, client,
|
||||||
USEC_PER_SEC,
|
client->event_priority, "dhcp6-resend-expire-timer", true);
|
||||||
client_timeout_resend_expire, client);
|
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
r = sd_event_source_set_priority(client->timeout_resend_expire,
|
|
||||||
client->event_priority);
|
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
r = sd_event_source_set_description(client->timeout_resend_expire, "dhcp6-resend-expire-timer");
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -815,14 +794,14 @@ error:
|
||||||
|
|
||||||
static int client_ensure_iaid(sd_dhcp6_client *client) {
|
static int client_ensure_iaid(sd_dhcp6_client *client) {
|
||||||
int r;
|
int r;
|
||||||
be32_t iaid;
|
uint32_t iaid;
|
||||||
|
|
||||||
assert(client);
|
assert(client);
|
||||||
|
|
||||||
if (client->ia_na.ia_na.id)
|
if (client->ia_na.ia_na.id)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, &iaid);
|
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, true, &iaid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1271,9 +1250,8 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
|
||||||
assert_return(client->ifindex > 0, -EINVAL);
|
assert_return(client->ifindex > 0, -EINVAL);
|
||||||
assert_return(client->state != state, -EINVAL);
|
assert_return(client->state != state, -EINVAL);
|
||||||
|
|
||||||
client->timeout_resend_expire =
|
(void) event_source_disable(client->timeout_resend_expire);
|
||||||
sd_event_source_unref(client->timeout_resend_expire);
|
(void) event_source_disable(client->timeout_resend);
|
||||||
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
|
|
||||||
client->retransmit_time = 0;
|
client->retransmit_time = 0;
|
||||||
client->retransmit_count = 0;
|
client->retransmit_count = 0;
|
||||||
|
|
||||||
|
@ -1340,21 +1318,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
|
||||||
log_dhcp6_client(client, "T1 expires in %s",
|
log_dhcp6_client(client, "T1 expires in %s",
|
||||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
|
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
|
||||||
|
|
||||||
client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
|
r = event_reset_time(client->event, &client->timeout_t1,
|
||||||
r = sd_event_add_time(client->event,
|
clock_boottime_or_monotonic(),
|
||||||
&client->timeout_t1,
|
time_now + timeout, 10 * USEC_PER_SEC,
|
||||||
clock_boottime_or_monotonic(), time_now + timeout,
|
client_timeout_t1, client,
|
||||||
10 * USEC_PER_SEC, client_timeout_t1,
|
client->event_priority, "dhcp6-t1-timeout", true);
|
||||||
client);
|
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
r = sd_event_source_set_priority(client->timeout_t1,
|
|
||||||
client->event_priority);
|
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
r = sd_event_source_set_description(client->timeout_t1, "dhcp6-t1-timeout");
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
@ -1363,21 +1331,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
|
||||||
log_dhcp6_client(client, "T2 expires in %s",
|
log_dhcp6_client(client, "T2 expires in %s",
|
||||||
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
|
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
|
||||||
|
|
||||||
client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
|
r = event_reset_time(client->event, &client->timeout_t2,
|
||||||
r = sd_event_add_time(client->event,
|
clock_boottime_or_monotonic(),
|
||||||
&client->timeout_t2,
|
time_now + timeout, 10 * USEC_PER_SEC,
|
||||||
clock_boottime_or_monotonic(), time_now + timeout,
|
client_timeout_t2, client,
|
||||||
10 * USEC_PER_SEC, client_timeout_t2,
|
client->event_priority, "dhcp6-t2-timeout", true);
|
||||||
client);
|
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
r = sd_event_source_set_priority(client->timeout_t2,
|
|
||||||
client->event_priority);
|
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
r = sd_event_source_set_description(client->timeout_t2, "dhcp6-t2-timeout");
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
@ -1389,18 +1347,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
|
||||||
client->transaction_id = random_u32() & htobe32(0x00ffffff);
|
client->transaction_id = random_u32() & htobe32(0x00ffffff);
|
||||||
client->transaction_start = time_now;
|
client->transaction_start = time_now;
|
||||||
|
|
||||||
r = sd_event_add_time(client->event, &client->timeout_resend,
|
r = event_reset_time(client->event, &client->timeout_resend,
|
||||||
clock_boottime_or_monotonic(), 0, 0, client_timeout_resend,
|
clock_boottime_or_monotonic(),
|
||||||
client);
|
0, 0,
|
||||||
if (r < 0)
|
client_timeout_resend, client,
|
||||||
goto error;
|
client->event_priority, "dhcp6-resend-timeout", true);
|
||||||
|
|
||||||
r = sd_event_source_set_priority(client->timeout_resend,
|
|
||||||
client->event_priority);
|
|
||||||
if (r < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timeout");
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
@ -1513,6 +1464,11 @@ sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) {
|
||||||
static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
|
static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
|
||||||
assert(client);
|
assert(client);
|
||||||
|
|
||||||
|
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_reset(client);
|
client_reset(client);
|
||||||
|
|
||||||
client->fd = safe_close(client->fd);
|
client->fd = safe_close(client->fd);
|
||||||
|
@ -1528,28 +1484,32 @@ DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_client, sd_dhcp6_client, dhcp6_client_fre
|
||||||
|
|
||||||
int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
|
int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
|
||||||
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
|
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
|
||||||
|
_cleanup_free_ be16_t *req_opts = NULL;
|
||||||
size_t t;
|
size_t t;
|
||||||
|
|
||||||
assert_return(ret, -EINVAL);
|
assert_return(ret, -EINVAL);
|
||||||
|
|
||||||
client = new0(sd_dhcp6_client, 1);
|
req_opts = new(be16_t, ELEMENTSOF(default_req_opts));
|
||||||
|
if (!req_opts)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (t = 0; t < ELEMENTSOF(default_req_opts); t++)
|
||||||
|
req_opts[t] = htobe16(default_req_opts[t]);
|
||||||
|
|
||||||
|
client = new(sd_dhcp6_client, 1);
|
||||||
if (!client)
|
if (!client)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
client->n_ref = 1;
|
*client = (sd_dhcp6_client) {
|
||||||
client->ia_na.type = SD_DHCP6_OPTION_IA_NA;
|
.n_ref = 1,
|
||||||
client->ia_pd.type = SD_DHCP6_OPTION_IA_PD;
|
.ia_na.type = SD_DHCP6_OPTION_IA_NA,
|
||||||
client->ifindex = -1;
|
.ia_pd.type = SD_DHCP6_OPTION_IA_PD,
|
||||||
client->request = DHCP6_REQUEST_IA_NA;
|
.ifindex = -1,
|
||||||
client->fd = -1;
|
.request = DHCP6_REQUEST_IA_NA,
|
||||||
|
.fd = -1,
|
||||||
client->req_opts_len = ELEMENTSOF(default_req_opts);
|
.req_opts_len = ELEMENTSOF(default_req_opts),
|
||||||
client->req_opts = new0(be16_t, client->req_opts_len);
|
.req_opts = TAKE_PTR(req_opts),
|
||||||
if (!client->req_opts)
|
};
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
for (t = 0; t < client->req_opts_len; t++)
|
|
||||||
client->req_opts[t] = htobe16(default_req_opts[t]);
|
|
||||||
|
|
||||||
*ret = TAKE_PTR(client);
|
*ret = TAKE_PTR(client);
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "arp-util.h"
|
#include "arp-util.h"
|
||||||
#include "ether-addr-util.h"
|
#include "ether-addr-util.h"
|
||||||
|
#include "event-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "in-addr-util.h"
|
#include "in-addr-util.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
@ -91,7 +92,7 @@ static void ipv4acd_set_state(sd_ipv4acd *acd, IPv4ACDState st, bool reset_count
|
||||||
static void ipv4acd_reset(sd_ipv4acd *acd) {
|
static void ipv4acd_reset(sd_ipv4acd *acd) {
|
||||||
assert(acd);
|
assert(acd);
|
||||||
|
|
||||||
acd->timer_event_source = sd_event_source_unref(acd->timer_event_source);
|
(void) event_source_disable(acd->timer_event_source);
|
||||||
acd->receive_message_event_source = sd_event_source_unref(acd->receive_message_event_source);
|
acd->receive_message_event_source = sd_event_source_unref(acd->receive_message_event_source);
|
||||||
|
|
||||||
acd->fd = safe_close(acd->fd);
|
acd->fd = safe_close(acd->fd);
|
||||||
|
@ -102,6 +103,8 @@ static void ipv4acd_reset(sd_ipv4acd *acd) {
|
||||||
static sd_ipv4acd *ipv4acd_free(sd_ipv4acd *acd) {
|
static sd_ipv4acd *ipv4acd_free(sd_ipv4acd *acd) {
|
||||||
assert(acd);
|
assert(acd);
|
||||||
|
|
||||||
|
acd->timer_event_source = sd_event_source_unref(acd->timer_event_source);
|
||||||
|
|
||||||
ipv4acd_reset(acd);
|
ipv4acd_reset(acd);
|
||||||
sd_ipv4acd_detach_event(acd);
|
sd_ipv4acd_detach_event(acd);
|
||||||
|
|
||||||
|
@ -115,14 +118,16 @@ int sd_ipv4acd_new(sd_ipv4acd **ret) {
|
||||||
|
|
||||||
assert_return(ret, -EINVAL);
|
assert_return(ret, -EINVAL);
|
||||||
|
|
||||||
acd = new0(sd_ipv4acd, 1);
|
acd = new(sd_ipv4acd, 1);
|
||||||
if (!acd)
|
if (!acd)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
acd->n_ref = 1;
|
*acd = (sd_ipv4acd) {
|
||||||
acd->state = IPV4ACD_STATE_INIT;
|
.n_ref = 1,
|
||||||
acd->ifindex = -1;
|
.state = IPV4ACD_STATE_INIT,
|
||||||
acd->fd = -1;
|
.ifindex = -1,
|
||||||
|
.fd = -1,
|
||||||
|
};
|
||||||
|
|
||||||
*ret = TAKE_PTR(acd);
|
*ret = TAKE_PTR(acd);
|
||||||
|
|
||||||
|
@ -153,9 +158,7 @@ int sd_ipv4acd_stop(sd_ipv4acd *acd) {
|
||||||
static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata);
|
static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata);
|
||||||
|
|
||||||
static int ipv4acd_set_next_wakeup(sd_ipv4acd *acd, usec_t usec, usec_t random_usec) {
|
static int ipv4acd_set_next_wakeup(sd_ipv4acd *acd, usec_t usec, usec_t random_usec) {
|
||||||
_cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL;
|
|
||||||
usec_t next_timeout, time_now;
|
usec_t next_timeout, time_now;
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(acd);
|
assert(acd);
|
||||||
|
|
||||||
|
@ -166,20 +169,11 @@ static int ipv4acd_set_next_wakeup(sd_ipv4acd *acd, usec_t usec, usec_t random_u
|
||||||
|
|
||||||
assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &time_now) >= 0);
|
assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &time_now) >= 0);
|
||||||
|
|
||||||
r = sd_event_add_time(acd->event, &timer, clock_boottime_or_monotonic(), time_now + next_timeout, 0, ipv4acd_on_timeout, acd);
|
return event_reset_time(acd->event, &acd->timer_event_source,
|
||||||
if (r < 0)
|
clock_boottime_or_monotonic(),
|
||||||
return r;
|
time_now + next_timeout, 0,
|
||||||
|
ipv4acd_on_timeout, acd,
|
||||||
r = sd_event_source_set_priority(timer, acd->event_priority);
|
acd->event_priority, "ipv4acd-timer", true);
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
(void) sd_event_source_set_description(timer, "ipv4acd-timer");
|
|
||||||
|
|
||||||
sd_event_source_unref(acd->timer_event_source);
|
|
||||||
acd->timer_event_source = TAKE_PTR(timer);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ipv4acd_arp_conflict(sd_ipv4acd *acd, struct ether_arp *arp) {
|
static bool ipv4acd_arp_conflict(sd_ipv4acd *acd, struct ether_arp *arp) {
|
||||||
|
|
|
@ -8,15 +8,26 @@
|
||||||
#include "sd-lldp.h"
|
#include "sd-lldp.h"
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
|
#include "ether-addr-util.h"
|
||||||
|
#include "event-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "lldp-internal.h"
|
#include "lldp-internal.h"
|
||||||
#include "lldp-neighbor.h"
|
#include "lldp-neighbor.h"
|
||||||
#include "lldp-network.h"
|
#include "lldp-network.h"
|
||||||
#include "socket-util.h"
|
#include "socket-util.h"
|
||||||
#include "ether-addr-util.h"
|
#include "string-table.h"
|
||||||
|
|
||||||
#define LLDP_DEFAULT_NEIGHBORS_MAX 128U
|
#define LLDP_DEFAULT_NEIGHBORS_MAX 128U
|
||||||
|
|
||||||
|
static const char * const lldp_event_table[_SD_LLDP_EVENT_MAX] = {
|
||||||
|
[SD_LLDP_EVENT_ADDED] = "added",
|
||||||
|
[SD_LLDP_EVENT_REMOVED] = "removed",
|
||||||
|
[SD_LLDP_EVENT_UPDATED] = "updated",
|
||||||
|
[SD_LLDP_EVENT_REFRESHED] = "refreshed",
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFINE_STRING_TABLE_LOOKUP(lldp_event, sd_lldp_event);
|
||||||
|
|
||||||
static void lldp_flush_neighbors(sd_lldp *lldp) {
|
static void lldp_flush_neighbors(sd_lldp *lldp) {
|
||||||
sd_lldp_neighbor *n;
|
sd_lldp_neighbor *n;
|
||||||
|
|
||||||
|
@ -28,12 +39,14 @@ static void lldp_flush_neighbors(sd_lldp *lldp) {
|
||||||
|
|
||||||
static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) {
|
static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) {
|
||||||
assert(lldp);
|
assert(lldp);
|
||||||
|
assert(event >= 0 && event < _SD_LLDP_EVENT_MAX);
|
||||||
|
|
||||||
log_lldp("Invoking callback for '%c'.", event);
|
if (!lldp->callback) {
|
||||||
|
log_lldp("Received '%s' event.", lldp_event_to_string(event));
|
||||||
if (!lldp->callback)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_lldp("Invoking callback for '%s' event.", lldp_event_to_string(event));
|
||||||
lldp->callback(lldp, event, n, lldp->userdata);
|
lldp->callback(lldp, event, n, lldp->userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +238,7 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v
|
||||||
static void lldp_reset(sd_lldp *lldp) {
|
static void lldp_reset(sd_lldp *lldp) {
|
||||||
assert(lldp);
|
assert(lldp);
|
||||||
|
|
||||||
lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source);
|
(void) event_source_disable(lldp->timer_event_source);
|
||||||
lldp->io_event_source = sd_event_source_unref(lldp->io_event_source);
|
lldp->io_event_source = sd_event_source_unref(lldp->io_event_source);
|
||||||
lldp->fd = safe_close(lldp->fd);
|
lldp->fd = safe_close(lldp->fd);
|
||||||
}
|
}
|
||||||
|
@ -334,6 +347,8 @@ _public_ int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex) {
|
||||||
static sd_lldp* lldp_free(sd_lldp *lldp) {
|
static sd_lldp* lldp_free(sd_lldp *lldp) {
|
||||||
assert(lldp);
|
assert(lldp);
|
||||||
|
|
||||||
|
lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source);
|
||||||
|
|
||||||
lldp_reset(lldp);
|
lldp_reset(lldp);
|
||||||
sd_lldp_detach_event(lldp);
|
sd_lldp_detach_event(lldp);
|
||||||
lldp_flush_neighbors(lldp);
|
lldp_flush_neighbors(lldp);
|
||||||
|
@ -351,14 +366,16 @@ _public_ int sd_lldp_new(sd_lldp **ret) {
|
||||||
|
|
||||||
assert_return(ret, -EINVAL);
|
assert_return(ret, -EINVAL);
|
||||||
|
|
||||||
lldp = new0(sd_lldp, 1);
|
lldp = new(sd_lldp, 1);
|
||||||
if (!lldp)
|
if (!lldp)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
lldp->n_ref = 1;
|
*lldp = (sd_lldp) {
|
||||||
lldp->fd = -1;
|
.n_ref = 1,
|
||||||
lldp->neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX;
|
.fd = -1,
|
||||||
lldp->capability_mask = (uint16_t) -1;
|
.neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX,
|
||||||
|
.capability_mask = (uint16_t) -1,
|
||||||
|
};
|
||||||
|
|
||||||
lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_id_hash_ops);
|
lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_id_hash_ops);
|
||||||
if (!lldp->neighbor_by_id)
|
if (!lldp->neighbor_by_id)
|
||||||
|
@ -394,7 +411,6 @@ static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||||
|
|
||||||
static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor) {
|
static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor) {
|
||||||
sd_lldp_neighbor *n;
|
sd_lldp_neighbor *n;
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(lldp);
|
assert(lldp);
|
||||||
|
|
||||||
|
@ -402,35 +418,17 @@ static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor) {
|
||||||
lldp_neighbor_start_ttl(neighbor);
|
lldp_neighbor_start_ttl(neighbor);
|
||||||
|
|
||||||
n = prioq_peek(lldp->neighbor_by_expiry);
|
n = prioq_peek(lldp->neighbor_by_expiry);
|
||||||
if (!n) {
|
if (!n)
|
||||||
|
return event_source_disable(lldp->timer_event_source);
|
||||||
if (lldp->timer_event_source)
|
|
||||||
return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_OFF);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lldp->timer_event_source) {
|
|
||||||
r = sd_event_source_set_time(lldp->timer_event_source, n->until);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_ONESHOT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lldp->event)
|
if (!lldp->event)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = sd_event_add_time(lldp->event, &lldp->timer_event_source, clock_boottime_or_monotonic(), n->until, 0, on_timer_event, lldp);
|
return event_reset_time(lldp->event, &lldp->timer_event_source,
|
||||||
if (r < 0)
|
clock_boottime_or_monotonic(),
|
||||||
return r;
|
n->until, 0,
|
||||||
|
on_timer_event, lldp,
|
||||||
r = sd_event_source_set_priority(lldp->timer_event_source, lldp->event_priority);
|
lldp->event_priority, "lldp-timer", true);
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
(void) sd_event_source_set_description(lldp->timer_event_source, "lldp-timer");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) {
|
_public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) {
|
||||||
|
|
206
src/systemd/src/libsystemd/sd-event/event-source.h
Normal file
206
src/systemd/src/libsystemd/sd-event/event-source.h
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
#pragma once
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||||
|
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#include <sys/timerfd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include "sd-event.h"
|
||||||
|
|
||||||
|
#include "fs-util.h"
|
||||||
|
#include "hashmap.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "prioq.h"
|
||||||
|
|
||||||
|
typedef enum EventSourceType {
|
||||||
|
SOURCE_IO,
|
||||||
|
SOURCE_TIME_REALTIME,
|
||||||
|
SOURCE_TIME_BOOTTIME,
|
||||||
|
SOURCE_TIME_MONOTONIC,
|
||||||
|
SOURCE_TIME_REALTIME_ALARM,
|
||||||
|
SOURCE_TIME_BOOTTIME_ALARM,
|
||||||
|
SOURCE_SIGNAL,
|
||||||
|
SOURCE_CHILD,
|
||||||
|
SOURCE_DEFER,
|
||||||
|
SOURCE_POST,
|
||||||
|
SOURCE_EXIT,
|
||||||
|
SOURCE_WATCHDOG,
|
||||||
|
SOURCE_INOTIFY,
|
||||||
|
_SOURCE_EVENT_SOURCE_TYPE_MAX,
|
||||||
|
_SOURCE_EVENT_SOURCE_TYPE_INVALID = -1
|
||||||
|
} EventSourceType;
|
||||||
|
|
||||||
|
/* All objects we use in epoll events start with this value, so that
|
||||||
|
* we know how to dispatch it */
|
||||||
|
typedef enum WakeupType {
|
||||||
|
WAKEUP_NONE,
|
||||||
|
WAKEUP_EVENT_SOURCE,
|
||||||
|
WAKEUP_CLOCK_DATA,
|
||||||
|
WAKEUP_SIGNAL_DATA,
|
||||||
|
WAKEUP_INOTIFY_DATA,
|
||||||
|
_WAKEUP_TYPE_MAX,
|
||||||
|
_WAKEUP_TYPE_INVALID = -1,
|
||||||
|
} WakeupType;
|
||||||
|
|
||||||
|
struct inode_data;
|
||||||
|
|
||||||
|
struct sd_event_source {
|
||||||
|
WakeupType wakeup;
|
||||||
|
|
||||||
|
unsigned n_ref;
|
||||||
|
|
||||||
|
sd_event *event;
|
||||||
|
void *userdata;
|
||||||
|
sd_event_handler_t prepare;
|
||||||
|
|
||||||
|
char *description;
|
||||||
|
|
||||||
|
EventSourceType type:5;
|
||||||
|
signed int enabled:3;
|
||||||
|
bool pending:1;
|
||||||
|
bool dispatching:1;
|
||||||
|
bool floating:1;
|
||||||
|
|
||||||
|
int64_t priority;
|
||||||
|
unsigned pending_index;
|
||||||
|
unsigned prepare_index;
|
||||||
|
uint64_t pending_iteration;
|
||||||
|
uint64_t prepare_iteration;
|
||||||
|
|
||||||
|
sd_event_destroy_t destroy_callback;
|
||||||
|
|
||||||
|
LIST_FIELDS(sd_event_source, sources);
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
sd_event_io_handler_t callback;
|
||||||
|
int fd;
|
||||||
|
uint32_t events;
|
||||||
|
uint32_t revents;
|
||||||
|
bool registered:1;
|
||||||
|
bool owned:1;
|
||||||
|
} io;
|
||||||
|
struct {
|
||||||
|
sd_event_time_handler_t callback;
|
||||||
|
usec_t next, accuracy;
|
||||||
|
unsigned earliest_index;
|
||||||
|
unsigned latest_index;
|
||||||
|
} time;
|
||||||
|
struct {
|
||||||
|
sd_event_signal_handler_t callback;
|
||||||
|
struct signalfd_siginfo siginfo;
|
||||||
|
int sig;
|
||||||
|
} signal;
|
||||||
|
struct {
|
||||||
|
sd_event_child_handler_t callback;
|
||||||
|
siginfo_t siginfo;
|
||||||
|
pid_t pid;
|
||||||
|
int options;
|
||||||
|
} child;
|
||||||
|
struct {
|
||||||
|
sd_event_handler_t callback;
|
||||||
|
} defer;
|
||||||
|
struct {
|
||||||
|
sd_event_handler_t callback;
|
||||||
|
} post;
|
||||||
|
struct {
|
||||||
|
sd_event_handler_t callback;
|
||||||
|
unsigned prioq_index;
|
||||||
|
} exit;
|
||||||
|
struct {
|
||||||
|
sd_event_inotify_handler_t callback;
|
||||||
|
uint32_t mask;
|
||||||
|
struct inode_data *inode_data;
|
||||||
|
LIST_FIELDS(sd_event_source, by_inode_data);
|
||||||
|
} inotify;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct clock_data {
|
||||||
|
WakeupType wakeup;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/* For all clocks we maintain two priority queues each, one
|
||||||
|
* ordered for the earliest times the events may be
|
||||||
|
* dispatched, and one ordered by the latest times they must
|
||||||
|
* have been dispatched. The range between the top entries in
|
||||||
|
* the two prioqs is the time window we can freely schedule
|
||||||
|
* wakeups in */
|
||||||
|
|
||||||
|
Prioq *earliest;
|
||||||
|
Prioq *latest;
|
||||||
|
usec_t next;
|
||||||
|
|
||||||
|
bool needs_rearm:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct signal_data {
|
||||||
|
WakeupType wakeup;
|
||||||
|
|
||||||
|
/* For each priority we maintain one signal fd, so that we
|
||||||
|
* only have to dequeue a single event per priority at a
|
||||||
|
* time. */
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
int64_t priority;
|
||||||
|
sigset_t sigset;
|
||||||
|
sd_event_source *current;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A structure listing all event sources currently watching a specific inode */
|
||||||
|
struct inode_data {
|
||||||
|
/* The identifier for the inode, the combination of the .st_dev + .st_ino fields of the file */
|
||||||
|
ino_t ino;
|
||||||
|
dev_t dev;
|
||||||
|
|
||||||
|
/* An fd of the inode to watch. The fd is kept open until the next iteration of the loop, so that we can
|
||||||
|
* rearrange the priority still until then, as we need the original inode to change the priority as we need to
|
||||||
|
* add a watch descriptor to the right inotify for the priority which we can only do if we have a handle to the
|
||||||
|
* original inode. We keep a list of all inode_data objects with an open fd in the to_close list (see below) of
|
||||||
|
* the sd-event object, so that it is efficient to close everything, before entering the next event loop
|
||||||
|
* iteration. */
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/* The inotify "watch descriptor" */
|
||||||
|
int wd;
|
||||||
|
|
||||||
|
/* The combination of the mask of all inotify watches on this inode we manage. This is also the mask that has
|
||||||
|
* most recently been set on the watch descriptor. */
|
||||||
|
uint32_t combined_mask;
|
||||||
|
|
||||||
|
/* All event sources subscribed to this inode */
|
||||||
|
LIST_HEAD(sd_event_source, event_sources);
|
||||||
|
|
||||||
|
/* The inotify object we watch this inode with */
|
||||||
|
struct inotify_data *inotify_data;
|
||||||
|
|
||||||
|
/* A linked list of all inode data objects with fds to close (see above) */
|
||||||
|
LIST_FIELDS(struct inode_data, to_close);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A structure encapsulating an inotify fd */
|
||||||
|
struct inotify_data {
|
||||||
|
WakeupType wakeup;
|
||||||
|
|
||||||
|
/* For each priority we maintain one inotify fd, so that we only have to dequeue a single event per priority at
|
||||||
|
* a time */
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
int64_t priority;
|
||||||
|
|
||||||
|
Hashmap *inodes; /* The inode_data structures keyed by dev+ino */
|
||||||
|
Hashmap *wd; /* The inode_data structures keyed by the watch descriptor for each */
|
||||||
|
|
||||||
|
/* The buffer we read inotify events into */
|
||||||
|
union inotify_event_buffer buffer;
|
||||||
|
size_t buffer_filled; /* fill level of the buffer */
|
||||||
|
|
||||||
|
/* How many event sources are currently marked pending for this inotify. We won't read new events off the
|
||||||
|
* inotify fd as long as there are still pending events on the inotify (because we have no strategy of queuing
|
||||||
|
* the events locally if they can't be coalesced). */
|
||||||
|
unsigned n_pending;
|
||||||
|
|
||||||
|
/* A linked list of all inotify objects with data already read, that still need processing. We keep this list
|
||||||
|
* to make it efficient to figure out what inotify objects to process data on next. */
|
||||||
|
LIST_FIELDS(struct inotify_data, buffered);
|
||||||
|
};
|
101
src/systemd/src/libsystemd/sd-event/event-util.c
Normal file
101
src/systemd/src/libsystemd/sd-event/event-util.c
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||||
|
|
||||||
|
#include "nm-sd-adapt.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "event-source.h"
|
||||||
|
#include "event-util.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "string-util.h"
|
||||||
|
|
||||||
|
int event_reset_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,
|
||||||
|
int64_t priority,
|
||||||
|
const char *description,
|
||||||
|
bool force_reset) {
|
||||||
|
|
||||||
|
bool created = false;
|
||||||
|
int enabled, r;
|
||||||
|
clockid_t c;
|
||||||
|
|
||||||
|
assert(e);
|
||||||
|
assert(s);
|
||||||
|
|
||||||
|
if (*s) {
|
||||||
|
if (!force_reset) {
|
||||||
|
r = sd_event_source_get_enabled(*s, &enabled);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "sd-event: Failed to query whether event source \"%s\" is enabled or not: %m",
|
||||||
|
strna((*s)->description ?: description));
|
||||||
|
|
||||||
|
if (enabled != SD_EVENT_OFF)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_event_source_get_time_clock(*s, &c);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "sd-event: Failed to get clock id of event source \"%s\": %m", strna((*s)->description ?: description));
|
||||||
|
|
||||||
|
if (c != clock)
|
||||||
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
|
"sd-event: Current clock id %i of event source \"%s\" is different from specified one %i.",
|
||||||
|
(int)c,
|
||||||
|
strna((*s)->description ? : description),
|
||||||
|
(int)clock);
|
||||||
|
|
||||||
|
r = sd_event_source_set_time(*s, usec);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "sd-event: Failed to set time for event source \"%s\": %m", strna((*s)->description ?: description));
|
||||||
|
|
||||||
|
r = sd_event_source_set_time_accuracy(*s, accuracy);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "sd-event: Failed to set accuracy for event source \"%s\": %m", strna((*s)->description ?: description));
|
||||||
|
|
||||||
|
/* callback function is not updated, as we do not have sd_event_source_set_time_callback(). */
|
||||||
|
|
||||||
|
(void) sd_event_source_set_userdata(*s, userdata);
|
||||||
|
|
||||||
|
r = sd_event_source_set_enabled(*s, SD_EVENT_ONESHOT);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "sd-event: Failed to enable event source \"%s\": %m", strna((*s)->description ?: description));
|
||||||
|
} else {
|
||||||
|
r = sd_event_add_time(e, s, clock, usec, accuracy, callback, userdata);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "sd-event: Failed to create timer event \"%s\": %m", strna(description));
|
||||||
|
|
||||||
|
created = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_event_source_set_priority(*s, priority);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "sd-event: Failed to set priority for event source \"%s\": %m", strna((*s)->description ?: description));
|
||||||
|
|
||||||
|
if (description) {
|
||||||
|
r = sd_event_source_set_description(*s, description);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "sd-event: Failed to set description for event source \"%s\": %m", description);
|
||||||
|
}
|
||||||
|
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
int event_source_disable(sd_event_source *s) {
|
||||||
|
if (!s)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return sd_event_source_set_enabled(s, SD_EVENT_OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
int event_source_is_enabled(sd_event_source *s) {
|
||||||
|
if (!s)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return sd_event_source_get_enabled(s, NULL);
|
||||||
|
}
|
13
src/systemd/src/libsystemd/sd-event/event-util.h
Normal file
13
src/systemd/src/libsystemd/sd-event/event-util.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "sd-event.h"
|
||||||
|
|
||||||
|
int event_reset_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,
|
||||||
|
int64_t priority, const char *description, bool force_reset);
|
||||||
|
int event_source_disable(sd_event_source *s);
|
||||||
|
int event_source_is_enabled(sd_event_source *s);
|
|
@ -11,6 +11,7 @@
|
||||||
#include "sd-id128.h"
|
#include "sd-id128.h"
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
|
#include "event-source.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
|
@ -28,24 +29,6 @@
|
||||||
|
|
||||||
#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
|
#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
|
||||||
|
|
||||||
typedef enum EventSourceType {
|
|
||||||
SOURCE_IO,
|
|
||||||
SOURCE_TIME_REALTIME,
|
|
||||||
SOURCE_TIME_BOOTTIME,
|
|
||||||
SOURCE_TIME_MONOTONIC,
|
|
||||||
SOURCE_TIME_REALTIME_ALARM,
|
|
||||||
SOURCE_TIME_BOOTTIME_ALARM,
|
|
||||||
SOURCE_SIGNAL,
|
|
||||||
SOURCE_CHILD,
|
|
||||||
SOURCE_DEFER,
|
|
||||||
SOURCE_POST,
|
|
||||||
SOURCE_EXIT,
|
|
||||||
SOURCE_WATCHDOG,
|
|
||||||
SOURCE_INOTIFY,
|
|
||||||
_SOURCE_EVENT_SOURCE_TYPE_MAX,
|
|
||||||
_SOURCE_EVENT_SOURCE_TYPE_INVALID = -1
|
|
||||||
} EventSourceType;
|
|
||||||
|
|
||||||
static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = {
|
static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = {
|
||||||
[SOURCE_IO] = "io",
|
[SOURCE_IO] = "io",
|
||||||
[SOURCE_TIME_REALTIME] = "realtime",
|
[SOURCE_TIME_REALTIME] = "realtime",
|
||||||
|
@ -64,183 +47,8 @@ static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX]
|
||||||
|
|
||||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(event_source_type, int);
|
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(event_source_type, int);
|
||||||
|
|
||||||
/* All objects we use in epoll events start with this value, so that
|
|
||||||
* we know how to dispatch it */
|
|
||||||
typedef enum WakeupType {
|
|
||||||
WAKEUP_NONE,
|
|
||||||
WAKEUP_EVENT_SOURCE,
|
|
||||||
WAKEUP_CLOCK_DATA,
|
|
||||||
WAKEUP_SIGNAL_DATA,
|
|
||||||
WAKEUP_INOTIFY_DATA,
|
|
||||||
_WAKEUP_TYPE_MAX,
|
|
||||||
_WAKEUP_TYPE_INVALID = -1,
|
|
||||||
} WakeupType;
|
|
||||||
|
|
||||||
#define EVENT_SOURCE_IS_TIME(t) IN_SET((t), SOURCE_TIME_REALTIME, SOURCE_TIME_BOOTTIME, SOURCE_TIME_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM)
|
#define EVENT_SOURCE_IS_TIME(t) IN_SET((t), SOURCE_TIME_REALTIME, SOURCE_TIME_BOOTTIME, SOURCE_TIME_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM)
|
||||||
|
|
||||||
struct inode_data;
|
|
||||||
|
|
||||||
struct sd_event_source {
|
|
||||||
WakeupType wakeup;
|
|
||||||
|
|
||||||
unsigned n_ref;
|
|
||||||
|
|
||||||
sd_event *event;
|
|
||||||
void *userdata;
|
|
||||||
sd_event_handler_t prepare;
|
|
||||||
|
|
||||||
char *description;
|
|
||||||
|
|
||||||
EventSourceType type:5;
|
|
||||||
signed int enabled:3;
|
|
||||||
bool pending:1;
|
|
||||||
bool dispatching:1;
|
|
||||||
bool floating:1;
|
|
||||||
|
|
||||||
int64_t priority;
|
|
||||||
unsigned pending_index;
|
|
||||||
unsigned prepare_index;
|
|
||||||
uint64_t pending_iteration;
|
|
||||||
uint64_t prepare_iteration;
|
|
||||||
|
|
||||||
sd_event_destroy_t destroy_callback;
|
|
||||||
|
|
||||||
LIST_FIELDS(sd_event_source, sources);
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
sd_event_io_handler_t callback;
|
|
||||||
int fd;
|
|
||||||
uint32_t events;
|
|
||||||
uint32_t revents;
|
|
||||||
bool registered:1;
|
|
||||||
bool owned:1;
|
|
||||||
} io;
|
|
||||||
struct {
|
|
||||||
sd_event_time_handler_t callback;
|
|
||||||
usec_t next, accuracy;
|
|
||||||
unsigned earliest_index;
|
|
||||||
unsigned latest_index;
|
|
||||||
} time;
|
|
||||||
struct {
|
|
||||||
sd_event_signal_handler_t callback;
|
|
||||||
struct signalfd_siginfo siginfo;
|
|
||||||
int sig;
|
|
||||||
} signal;
|
|
||||||
struct {
|
|
||||||
sd_event_child_handler_t callback;
|
|
||||||
siginfo_t siginfo;
|
|
||||||
pid_t pid;
|
|
||||||
int options;
|
|
||||||
} child;
|
|
||||||
struct {
|
|
||||||
sd_event_handler_t callback;
|
|
||||||
} defer;
|
|
||||||
struct {
|
|
||||||
sd_event_handler_t callback;
|
|
||||||
} post;
|
|
||||||
struct {
|
|
||||||
sd_event_handler_t callback;
|
|
||||||
unsigned prioq_index;
|
|
||||||
} exit;
|
|
||||||
struct {
|
|
||||||
sd_event_inotify_handler_t callback;
|
|
||||||
uint32_t mask;
|
|
||||||
struct inode_data *inode_data;
|
|
||||||
LIST_FIELDS(sd_event_source, by_inode_data);
|
|
||||||
} inotify;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct clock_data {
|
|
||||||
WakeupType wakeup;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
/* For all clocks we maintain two priority queues each, one
|
|
||||||
* ordered for the earliest times the events may be
|
|
||||||
* dispatched, and one ordered by the latest times they must
|
|
||||||
* have been dispatched. The range between the top entries in
|
|
||||||
* the two prioqs is the time window we can freely schedule
|
|
||||||
* wakeups in */
|
|
||||||
|
|
||||||
Prioq *earliest;
|
|
||||||
Prioq *latest;
|
|
||||||
usec_t next;
|
|
||||||
|
|
||||||
bool needs_rearm:1;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct signal_data {
|
|
||||||
WakeupType wakeup;
|
|
||||||
|
|
||||||
/* For each priority we maintain one signal fd, so that we
|
|
||||||
* only have to dequeue a single event per priority at a
|
|
||||||
* time. */
|
|
||||||
|
|
||||||
int fd;
|
|
||||||
int64_t priority;
|
|
||||||
sigset_t sigset;
|
|
||||||
sd_event_source *current;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* A structure listing all event sources currently watching a specific inode */
|
|
||||||
struct inode_data {
|
|
||||||
/* The identifier for the inode, the combination of the .st_dev + .st_ino fields of the file */
|
|
||||||
ino_t ino;
|
|
||||||
dev_t dev;
|
|
||||||
|
|
||||||
/* An fd of the inode to watch. The fd is kept open until the next iteration of the loop, so that we can
|
|
||||||
* rearrange the priority still until then, as we need the original inode to change the priority as we need to
|
|
||||||
* add a watch descriptor to the right inotify for the priority which we can only do if we have a handle to the
|
|
||||||
* original inode. We keep a list of all inode_data objects with an open fd in the to_close list (see below) of
|
|
||||||
* the sd-event object, so that it is efficient to close everything, before entering the next event loop
|
|
||||||
* iteration. */
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
/* The inotify "watch descriptor" */
|
|
||||||
int wd;
|
|
||||||
|
|
||||||
/* The combination of the mask of all inotify watches on this inode we manage. This is also the mask that has
|
|
||||||
* most recently been set on the watch descriptor. */
|
|
||||||
uint32_t combined_mask;
|
|
||||||
|
|
||||||
/* All event sources subscribed to this inode */
|
|
||||||
LIST_HEAD(sd_event_source, event_sources);
|
|
||||||
|
|
||||||
/* The inotify object we watch this inode with */
|
|
||||||
struct inotify_data *inotify_data;
|
|
||||||
|
|
||||||
/* A linked list of all inode data objects with fds to close (see above) */
|
|
||||||
LIST_FIELDS(struct inode_data, to_close);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* A structure encapsulating an inotify fd */
|
|
||||||
struct inotify_data {
|
|
||||||
WakeupType wakeup;
|
|
||||||
|
|
||||||
/* For each priority we maintain one inotify fd, so that we only have to dequeue a single event per priority at
|
|
||||||
* a time */
|
|
||||||
|
|
||||||
int fd;
|
|
||||||
int64_t priority;
|
|
||||||
|
|
||||||
Hashmap *inodes; /* The inode_data structures keyed by dev+ino */
|
|
||||||
Hashmap *wd; /* The inode_data structures keyed by the watch descriptor for each */
|
|
||||||
|
|
||||||
/* The buffer we read inotify events into */
|
|
||||||
union inotify_event_buffer buffer;
|
|
||||||
size_t buffer_filled; /* fill level of the buffer */
|
|
||||||
|
|
||||||
/* How many event sources are currently marked pending for this inotify. We won't read new events off the
|
|
||||||
* inotify fd as long as there are still pending events on the inotify (because we have no strategy of queuing
|
|
||||||
* the events locally if they can't be coalesced). */
|
|
||||||
unsigned n_pending;
|
|
||||||
|
|
||||||
/* A linked list of all inotify objects with data already read, that still need processing. We keep this list
|
|
||||||
* to make it efficient to figure out what inotify objects to process data on next. */
|
|
||||||
LIST_FIELDS(struct inotify_data, buffered);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sd_event {
|
struct sd_event {
|
||||||
unsigned n_ref;
|
unsigned n_ref;
|
||||||
|
|
||||||
|
@ -1891,9 +1699,11 @@ _public_ int sd_event_source_set_description(sd_event_source *s, const char *des
|
||||||
_public_ int sd_event_source_get_description(sd_event_source *s, const char **description) {
|
_public_ int sd_event_source_get_description(sd_event_source *s, const char **description) {
|
||||||
assert_return(s, -EINVAL);
|
assert_return(s, -EINVAL);
|
||||||
assert_return(description, -EINVAL);
|
assert_return(description, -EINVAL);
|
||||||
assert_return(s->description, -ENXIO);
|
|
||||||
assert_return(!event_pid_changed(s->event), -ECHILD);
|
assert_return(!event_pid_changed(s->event), -ECHILD);
|
||||||
|
|
||||||
|
if (!s->description)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
*description = s->description;
|
*description = s->description;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2145,11 +1955,11 @@ fail:
|
||||||
|
|
||||||
_public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) {
|
_public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) {
|
||||||
assert_return(s, -EINVAL);
|
assert_return(s, -EINVAL);
|
||||||
assert_return(m, -EINVAL);
|
|
||||||
assert_return(!event_pid_changed(s->event), -ECHILD);
|
assert_return(!event_pid_changed(s->event), -ECHILD);
|
||||||
|
|
||||||
*m = s->enabled;
|
if (m)
|
||||||
return 0;
|
*m = s->enabled;
|
||||||
|
return s->enabled != SD_EVENT_OFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
||||||
|
@ -3707,4 +3517,32 @@ _public_ int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_d
|
||||||
|
|
||||||
return !!s->destroy_callback;
|
return !!s->destroy_callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_public_ int sd_event_source_get_floating(sd_event_source *s) {
|
||||||
|
assert_return(s, -EINVAL);
|
||||||
|
|
||||||
|
return s->floating;
|
||||||
|
}
|
||||||
|
|
||||||
|
_public_ int sd_event_source_set_floating(sd_event_source *s, int b) {
|
||||||
|
assert_return(s, -EINVAL);
|
||||||
|
|
||||||
|
if (s->floating == !!b)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!s->event) /* Already disconnected */
|
||||||
|
return -ESTALE;
|
||||||
|
|
||||||
|
s->floating = b;
|
||||||
|
|
||||||
|
if (b) {
|
||||||
|
sd_event_source_ref(s);
|
||||||
|
sd_event_unref(s->event);
|
||||||
|
} else {
|
||||||
|
sd_event_ref(s->event);
|
||||||
|
sd_event_source_unref(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
#endif /* NM_IGNORED */
|
#endif /* NM_IGNORED */
|
||||||
|
|
|
@ -277,7 +277,9 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) {
|
||||||
|
|
||||||
assert_return(ret, -EINVAL);
|
assert_return(ret, -EINVAL);
|
||||||
|
|
||||||
r = acquire_random_bytes(&t, sizeof t, true);
|
/* We allow usage if x86-64 RDRAND here. It might not be trusted enough for keeping secrets, but it should be
|
||||||
|
* fine for UUIDS. */
|
||||||
|
r = genuine_random_bytes(&t, sizeof t, RANDOM_ALLOW_RDRAND);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -25,22 +25,22 @@
|
||||||
|
|
||||||
#ifndef _sd_printf_
|
#ifndef _sd_printf_
|
||||||
# if __GNUC__ >= 4
|
# if __GNUC__ >= 4
|
||||||
# define _sd_printf_(a,b) __attribute__ ((format (printf, a, b)))
|
# define _sd_printf_(a,b) __attribute__ ((__format__(printf, a, b)))
|
||||||
# else
|
# else
|
||||||
# define _sd_printf_(a,b)
|
# define _sd_printf_(a,b)
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _sd_sentinel_
|
#ifndef _sd_sentinel_
|
||||||
# define _sd_sentinel_ __attribute__((sentinel))
|
# define _sd_sentinel_ __attribute__((__sentinel__))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _sd_packed_
|
#ifndef _sd_packed_
|
||||||
# define _sd_packed_ __attribute__((packed))
|
# define _sd_packed_ __attribute__((__packed__))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _sd_pure_
|
#ifndef _sd_pure_
|
||||||
# define _sd_pure_ __attribute__((pure))
|
# define _sd_pure_ __attribute__((__pure__))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _SD_STRINGIFY
|
#ifndef _SD_STRINGIFY
|
||||||
|
|
|
@ -143,6 +143,8 @@ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid);
|
||||||
int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *ret);
|
int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *ret);
|
||||||
int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback);
|
int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback);
|
||||||
int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret);
|
int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret);
|
||||||
|
int sd_event_source_get_floating(sd_event_source *s);
|
||||||
|
int sd_event_source_set_floating(sd_event_source *s, int b);
|
||||||
|
|
||||||
/* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */
|
/* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */
|
||||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref);
|
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref);
|
||||||
|
|
|
@ -109,10 +109,12 @@ typedef struct sd_lldp sd_lldp;
|
||||||
typedef struct sd_lldp_neighbor sd_lldp_neighbor;
|
typedef struct sd_lldp_neighbor sd_lldp_neighbor;
|
||||||
|
|
||||||
typedef enum sd_lldp_event {
|
typedef enum sd_lldp_event {
|
||||||
SD_LLDP_EVENT_ADDED = 'a',
|
SD_LLDP_EVENT_ADDED,
|
||||||
SD_LLDP_EVENT_REMOVED = 'r',
|
SD_LLDP_EVENT_REMOVED,
|
||||||
SD_LLDP_EVENT_UPDATED = 'u',
|
SD_LLDP_EVENT_UPDATED,
|
||||||
SD_LLDP_EVENT_REFRESHED = 'f',
|
SD_LLDP_EVENT_REFRESHED,
|
||||||
|
_SD_LLDP_EVENT_MAX,
|
||||||
|
_SD_LLDP_EVENT_INVALID = -1,
|
||||||
} sd_lldp_event;
|
} sd_lldp_event;
|
||||||
|
|
||||||
typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata);
|
typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata);
|
||||||
|
|
|
@ -55,8 +55,10 @@ typedef struct sd_ndisc sd_ndisc;
|
||||||
typedef struct sd_ndisc_router sd_ndisc_router;
|
typedef struct sd_ndisc_router sd_ndisc_router;
|
||||||
|
|
||||||
typedef enum sd_ndisc_event {
|
typedef enum sd_ndisc_event {
|
||||||
SD_NDISC_EVENT_TIMEOUT = 't',
|
SD_NDISC_EVENT_TIMEOUT,
|
||||||
SD_NDISC_EVENT_ROUTER = 'r',
|
SD_NDISC_EVENT_ROUTER,
|
||||||
|
_SD_NDISC_EVENT_MAX,
|
||||||
|
_SD_NDISC_EVENT_INVALID = -1,
|
||||||
} sd_ndisc_event;
|
} sd_ndisc_event;
|
||||||
|
|
||||||
typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata);
|
typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata);
|
||||||
|
|
Loading…
Reference in a new issue