systemd: update code from upstream (2018-11-23)

This is a direct dump from systemd git.

======

SYSTEMD_DIR=../systemd
COMMIT=91540eaa5c636f4073955f025c4e72b1bbb4f2e9

(
  cd "$SYSTEMD_DIR"
  git checkout "$COMMIT"
  git reset --hard
  git clean -fdx
)

git ls-files :/src/systemd/src/ \
             :/shared/nm-utils/unaligned.h | \
  xargs -d '\n' rm -f

nm_copy_sd() {
    mkdir -p "./src/systemd/$(dirname "$1")"
    cp "$SYSTEMD_DIR/$1" "./src/systemd/$1"
}

nm_copy_sd_shared() {
    mkdir -p "./shared/nm-utils/"
    cp "$SYSTEMD_DIR/$1" "./shared/nm-utils/${1##*/}"
}

nm_copy_sd "src/basic/alloc-util.c"
nm_copy_sd "src/basic/alloc-util.h"
nm_copy_sd "src/basic/async.h"
nm_copy_sd "src/basic/env-util.c"
nm_copy_sd "src/basic/env-util.h"
nm_copy_sd "src/basic/escape.c"
nm_copy_sd "src/basic/escape.h"
nm_copy_sd "src/basic/ether-addr-util.c"
nm_copy_sd "src/basic/ether-addr-util.h"
nm_copy_sd "src/basic/extract-word.c"
nm_copy_sd "src/basic/extract-word.h"
nm_copy_sd "src/basic/fileio.c"
nm_copy_sd "src/basic/fileio.h"
nm_copy_sd "src/basic/fd-util.c"
nm_copy_sd "src/basic/fd-util.h"
nm_copy_sd "src/basic/fs-util.c"
nm_copy_sd "src/basic/fs-util.h"
nm_copy_sd "src/basic/hash-funcs.c"
nm_copy_sd "src/basic/hash-funcs.h"
nm_copy_sd "src/basic/hashmap.c"
nm_copy_sd "src/basic/hashmap.h"
nm_copy_sd "src/basic/hexdecoct.c"
nm_copy_sd "src/basic/hexdecoct.h"
nm_copy_sd "src/basic/hostname-util.c"
nm_copy_sd "src/basic/hostname-util.h"
nm_copy_sd "src/basic/in-addr-util.c"
nm_copy_sd "src/basic/in-addr-util.h"
nm_copy_sd "src/basic/io-util.c"
nm_copy_sd "src/basic/io-util.h"
nm_copy_sd "src/basic/list.h"
nm_copy_sd "src/basic/log.h"
nm_copy_sd "src/basic/macro.h"
nm_copy_sd "src/basic/mempool.h"
nm_copy_sd "src/basic/mempool.c"
nm_copy_sd "src/basic/parse-util.c"
nm_copy_sd "src/basic/parse-util.h"
nm_copy_sd "src/basic/path-util.c"
nm_copy_sd "src/basic/path-util.h"
nm_copy_sd "src/basic/prioq.h"
nm_copy_sd "src/basic/prioq.c"
nm_copy_sd "src/basic/process-util.h"
nm_copy_sd "src/basic/process-util.c"
nm_copy_sd "src/basic/random-util.c"
nm_copy_sd "src/basic/random-util.h"
nm_copy_sd "src/basic/refcnt.h"
nm_copy_sd "src/basic/set.h"
nm_copy_sd "src/basic/signal-util.h"
nm_copy_sd "src/basic/siphash24.h"
nm_copy_sd "src/basic/socket-util.c"
nm_copy_sd "src/basic/socket-util.h"
nm_copy_sd "src/basic/sparse-endian.h"
nm_copy_sd "src/basic/stat-util.c"
nm_copy_sd "src/basic/stat-util.h"
nm_copy_sd "src/basic/stdio-util.h"
nm_copy_sd "src/basic/string-table.c"
nm_copy_sd "src/basic/string-table.h"
nm_copy_sd "src/basic/string-util.c"
nm_copy_sd "src/basic/string-util.h"
nm_copy_sd "src/basic/strv.c"
nm_copy_sd "src/basic/strv.h"
nm_copy_sd "src/basic/time-util.c"
nm_copy_sd "src/basic/time-util.h"
nm_copy_sd "src/basic/umask-util.h"
nm_copy_sd_shared "src/basic/unaligned.h"
nm_copy_sd "src/basic/utf8.c"
nm_copy_sd "src/basic/utf8.h"
nm_copy_sd "src/basic/util.c"
nm_copy_sd "src/basic/util.h"
nm_copy_sd "src/libsystemd-network/arp-util.c"
nm_copy_sd "src/libsystemd-network/arp-util.h"
nm_copy_sd "src/libsystemd-network/dhcp6-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp6-lease-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp6-network.c"
nm_copy_sd "src/libsystemd-network/dhcp6-option.c"
nm_copy_sd "src/libsystemd-network/dhcp6-protocol.h"
nm_copy_sd "src/libsystemd-network/dhcp-identifier.c"
nm_copy_sd "src/libsystemd-network/dhcp-identifier.h"
nm_copy_sd "src/libsystemd-network/dhcp-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp-lease-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp-network.c"
nm_copy_sd "src/libsystemd-network/dhcp-option.c"
nm_copy_sd "src/libsystemd-network/dhcp-packet.c"
nm_copy_sd "src/libsystemd-network/dhcp-protocol.h"
nm_copy_sd "src/libsystemd-network/lldp-internal.h"
nm_copy_sd "src/libsystemd-network/lldp-neighbor.c"
nm_copy_sd "src/libsystemd-network/lldp-neighbor.h"
nm_copy_sd "src/libsystemd-network/lldp-network.c"
nm_copy_sd "src/libsystemd-network/lldp-network.h"
nm_copy_sd "src/libsystemd-network/network-internal.c"
nm_copy_sd "src/libsystemd-network/network-internal.h"
nm_copy_sd "src/libsystemd-network/sd-dhcp6-client.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp6-lease.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp-client.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp-lease.c"
nm_copy_sd "src/libsystemd-network/sd-ipv4acd.c"
nm_copy_sd "src/libsystemd-network/sd-ipv4ll.c"
nm_copy_sd "src/libsystemd-network/sd-lldp.c"
nm_copy_sd "src/libsystemd/sd-event/event-source.h"
nm_copy_sd "src/libsystemd/sd-event/event-util.c"
nm_copy_sd "src/libsystemd/sd-event/event-util.h"
nm_copy_sd "src/libsystemd/sd-event/sd-event.c"
nm_copy_sd "src/libsystemd/sd-id128/id128-util.c"
nm_copy_sd "src/libsystemd/sd-id128/id128-util.h"
nm_copy_sd "src/libsystemd/sd-id128/sd-id128.c"
nm_copy_sd "src/shared/dns-domain.c"
nm_copy_sd "src/shared/dns-domain.h"
nm_copy_sd "src/systemd/_sd-common.h"
nm_copy_sd "src/systemd/sd-dhcp6-client.h"
nm_copy_sd "src/systemd/sd-dhcp6-lease.h"
nm_copy_sd "src/systemd/sd-dhcp-client.h"
nm_copy_sd "src/systemd/sd-dhcp-lease.h"
nm_copy_sd "src/systemd/sd-event.h"
nm_copy_sd "src/systemd/sd-ndisc.h"
nm_copy_sd "src/systemd/sd-id128.h"
nm_copy_sd "src/systemd/sd-ipv4acd.h"
nm_copy_sd "src/systemd/sd-ipv4ll.h"
nm_copy_sd "src/systemd/sd-lldp.h"
This commit is contained in:
Thomas Haller 2018-11-23 09:12:56 +01:00
parent 5437448a64
commit 48d64de177
39 changed files with 923 additions and 833 deletions

View file

@ -7,37 +7,37 @@
/* BE */
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
@ -45,37 +45,37 @@ static inline void unaligned_write_be64(void *_u, uint64_t a) {
/* LE */
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}

View file

@ -106,7 +106,6 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit)
int r = 1;
assert(p);
assert(*p);
assert(ret);
/* Unescapes C style. Returns the unescaped character in ret.

View file

@ -15,7 +15,6 @@
#include "alloc-util.h"
#include "ctype.h"
#include "def.h"
#include "env-util.h"
#include "escape.h"
#include "fd-util.h"
@ -160,7 +159,7 @@ int write_string_file_ts(
/* We manually build our own version of fopen(..., "we") that
* 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) {
r = -errno;
goto fail;
@ -368,7 +367,6 @@ int read_full_file(const char *fn, char **contents, size_t *size) {
static int parse_env_file_internal(
FILE *f,
const char *fname,
const char *newline,
int (*push) (const char *filename, unsigned line,
const char *key, char *value, void *userdata, int *n_pushed),
void *userdata,
@ -394,8 +392,6 @@ static int parse_env_file_internal(
COMMENT_ESCAPE
} state = PRE_KEY;
assert(newline);
if (f)
r = read_full_stream(f, &contents, NULL);
else
@ -423,7 +419,7 @@ static int parse_env_file_internal(
break;
case KEY:
if (strchr(newline, c)) {
if (strchr(NEWLINE, c)) {
state = PRE_KEY;
line++;
n_key = 0;
@ -445,7 +441,7 @@ static int parse_env_file_internal(
break;
case PRE_VALUE:
if (strchr(newline, c)) {
if (strchr(NEWLINE, c)) {
state = PRE_KEY;
line++;
key[n_key] = 0;
@ -483,7 +479,7 @@ static int parse_env_file_internal(
break;
case VALUE:
if (strchr(newline, c)) {
if (strchr(NEWLINE, c)) {
state = PRE_KEY;
line++;
@ -528,7 +524,7 @@ static int parse_env_file_internal(
case VALUE_ESCAPE:
state = VALUE;
if (!strchr(newline, c)) {
if (!strchr(NEWLINE, c)) {
/* Escaped newlines we eat up entirely */
if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
return -ENOMEM;
@ -554,7 +550,7 @@ static int parse_env_file_internal(
case SINGLE_QUOTE_VALUE_ESCAPE:
state = SINGLE_QUOTE_VALUE;
if (!strchr(newline, c)) {
if (!strchr(NEWLINE, c)) {
if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
return -ENOMEM;
@ -579,7 +575,7 @@ static int parse_env_file_internal(
case DOUBLE_QUOTE_VALUE_ESCAPE:
state = DOUBLE_QUOTE_VALUE;
if (!strchr(newline, c)) {
if (!strchr(NEWLINE, c)) {
if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
return -ENOMEM;
@ -590,7 +586,7 @@ static int parse_env_file_internal(
case COMMENT:
if (c == '\\')
state = COMMENT_ESCAPE;
else if (strchr(newline, c)) {
else if (strchr(NEWLINE, c)) {
state = PRE_KEY;
line++;
}
@ -642,16 +638,18 @@ static int check_utf8ness_and_warn(
_cleanup_free_ char *p = NULL;
p = utf8_escape_invalid(key);
log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
return -EINVAL;
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"%s:%u: invalid UTF-8 in key '%s', ignoring.",
strna(filename), line, p);
}
if (value && !utf8_is_valid(value)) {
_cleanup_free_ char *p = NULL;
p = utf8_escape_invalid(value);
log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
return -EINVAL;
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.",
strna(filename), line, key, p);
}
return 0;
@ -699,17 +697,13 @@ static int parse_env_file_push(
int parse_env_filev(
FILE *f,
const char *fname,
const char *newline,
va_list ap) {
int r, n_pushed = 0;
va_list aq;
if (!newline)
newline = NEWLINE;
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);
if (r < 0)
return r;
@ -717,17 +711,16 @@ int parse_env_filev(
return n_pushed;
}
int parse_env_file(
int parse_env_file_sentinel(
FILE *f,
const char *fname,
const char *newline,
...) {
va_list ap;
int r;
va_start(ap, newline);
r = parse_env_filev(f, fname, newline, ap);
va_start(ap, fname);
r = parse_env_filev(f, fname, ap);
va_end(ap);
return r;
@ -763,14 +756,11 @@ static int load_env_file_push(
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;
int r;
if (!newline)
newline = NEWLINE;
r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL);
r = parse_env_file_internal(f, fname, load_env_file_push, &m, NULL);
if (r < 0) {
strv_free(m);
return r;
@ -812,14 +802,11 @@ static int load_env_file_push_pairs(
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;
int r;
if (!newline)
newline = NEWLINE;
r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL);
r = parse_env_file_internal(f, fname, load_env_file_push_pairs, &m, NULL);
if (r < 0) {
strv_free(m);
return r;
@ -872,7 +859,7 @@ int merge_env_file(
* 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) {

View file

@ -10,6 +10,8 @@
#include "macro.h"
#include "time-util.h"
#define LONG_LINE_MAX (1U*1024U*1024U)
typedef enum {
WRITE_STRING_FILE_CREATE = 1 << 0,
WRITE_STRING_FILE_ATOMIC = 1 << 1,
@ -17,6 +19,7 @@ typedef enum {
WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1 << 3,
WRITE_STRING_FILE_SYNC = 1 << 4,
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
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 parse_env_filev(FILE *f, const char *fname, const char *separator, va_list ap);
int parse_env_file(FILE *f, const char *fname, const char *separator, ...) _sentinel_;
int load_env_file(FILE *f, const char *fname, const char *separator, char ***l);
int load_env_file_pairs(FILE *f, const char *fname, const char *separator, char ***l);
int parse_env_filev(FILE *f, const char *fname, va_list ap);
int parse_env_file_sentinel(FILE *f, const char *fname, ...) _sentinel_;
#define parse_env_file(f, fname, ...) parse_env_file_sentinel(f, fname, __VA_ARGS__, NULL)
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);

View file

@ -8,7 +8,6 @@
#include <unistd.h>
#include "alloc-util.h"
#include "def.h"
#include "fd-util.h"
#include "fileio.h"
#include "hostname-util.h"

View file

@ -314,6 +314,7 @@ int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union
}
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;
int r, ifi = 0;
@ -341,7 +342,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);
@ -490,12 +495,14 @@ int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
return 0;
}
int in_addr_prefix_from_string(
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) {
_cleanup_free_ char *str = NULL;
union in_addr_union buffer;
const char *e, *l;
unsigned char k;
@ -507,9 +514,13 @@ int in_addr_prefix_from_string(
return -EAFNOSUPPORT;
e = strchr(p, '/');
if (e)
l = strndupa(p, e - p);
else
if (e) {
str = strndup(p, e - p);
if (!str)
return -ENOMEM;
l = str;
} else
l = p;
r = in_addr_from_string(family, l, &buffer);
@ -520,6 +531,13 @@ int in_addr_prefix_from_string(
r = in_addr_parse_prefixlen(family, e+1, &k);
if (r < 0)
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
k = FAMILY_ADDRESS_SIZE(family) * 8;
@ -531,12 +549,14 @@ int in_addr_prefix_from_string(
return 0;
}
int in_addr_prefix_from_string_auto(
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) {
_cleanup_free_ char *str = NULL;
union in_addr_union buffer;
const char *e, *l;
unsigned char k;
@ -545,9 +565,13 @@ int in_addr_prefix_from_string_auto(
assert(p);
e = strchr(p, '/');
if (e)
l = strndupa(p, e - p);
else
if (e) {
str = strndup(p, e - p);
if (!str)
return -ENOMEM;
l = str;
} else
l = p;
r = in_addr_from_string_auto(l, &family, &buffer);
@ -558,6 +582,13 @@ int in_addr_prefix_from_string_auto(
r = in_addr_parse_prefixlen(family, e+1, &k);
if (r < 0)
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
k = FAMILY_ADDRESS_SIZE(family) * 8;

View file

@ -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_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_prefix_from_string(const char *p, 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_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_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) {
assert(IN_SET(family, AF_INET, AF_INET6));
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);
int in_addr_data_compare_func(const void *a, const void *b);

View file

@ -36,10 +36,12 @@ typedef enum LogTarget{
_LOG_TARGET_INVALID = -1
} LogTarget;
#define LOG_REALM_PLUS_LEVEL(realm, level) \
((realm) << 10 | (level))
#define LOG_REALM_REMOVE_LEVEL(realm_level) \
((realm_level >> 10))
/* Note to readers: << and >> have lower precedence than & and | */
#define LOG_REALM_PLUS_LEVEL(realm, level) ((realm) << 10 | (level))
#define LOG_REALM_REMOVE_LEVEL(realm_level) ((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_max_level_realm(LogRealm realm, int level);
@ -201,10 +203,10 @@ void log_assert_failed_return_realm(
#define log_full_errno_realm(realm, level, error, ...) \
({ \
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, \
__FILE__, __LINE__, __func__, __VA_ARGS__) \
: -abs(_e); \
: -ERRNO_VALUE(_e); \
})
#define log_full_errno(level, error, ...) \
@ -318,3 +320,5 @@ int log_syntax_invalid_utf8_internal(
})
#define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG)
void log_setup_service(void);

View file

@ -8,30 +8,30 @@
#include <sys/sysmacros.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__
# define _alloc_(...)
#else
# define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__)))
# define _alloc_(...) __attribute__ ((__alloc_size__(__VA_ARGS__)))
#endif
#define _sentinel_ __attribute__ ((sentinel))
#define _unused_ __attribute__ ((unused))
#define _destructor_ __attribute__ ((destructor))
#define _pure_ __attribute__ ((pure))
#define _const_ __attribute__ ((const))
#define _deprecated_ __attribute__ ((deprecated))
#define _packed_ __attribute__ ((packed))
#define _malloc_ __attribute__ ((malloc))
#define _weak_ __attribute__ ((weak))
#define _sentinel_ __attribute__ ((__sentinel__))
#define _unused_ __attribute__ ((__unused__))
#define _destructor_ __attribute__ ((__destructor__))
#define _pure_ __attribute__ ((__pure__))
#define _const_ __attribute__ ((__const__))
#define _deprecated_ __attribute__ ((__deprecated__))
#define _packed_ __attribute__ ((__packed__))
#define _malloc_ __attribute__ ((__malloc__))
#define _weak_ __attribute__ ((__weak__))
#define _likely_(x) (__builtin_expect(!!(x), 1))
#define _unlikely_(x) (__builtin_expect(!!(x), 0))
#define _public_ __attribute__ ((visibility("default")))
#define _hidden_ __attribute__ ((visibility("hidden")))
#define _weakref_(x) __attribute__((weakref(#x)))
#define _alignas_(x) __attribute__((aligned(__alignof(x))))
#define _cleanup_(x) __attribute__((cleanup(x)))
#define _public_ __attribute__ ((__visibility__("default")))
#define _hidden_ __attribute__ ((__visibility__("hidden")))
#define _weakref_(x) __attribute__((__weakref__(#x)))
#define _alignas_(x) __attribute__((__aligned__(__alignof(x))))
#define _cleanup_(x) __attribute__((__cleanup__(x)))
#if __GNUC__ >= 7
#define _fallthrough_ __attribute__((fallthrough))
#define _fallthrough_ __attribute__((__fallthrough__))
#else
#define _fallthrough_
#endif
@ -41,7 +41,7 @@
#if __STDC_VERSION__ >= 201112L
#define _noreturn_ _Noreturn
#else
#define _noreturn_ __attribute__((noreturn))
#define _noreturn_ __attribute__((__noreturn__))
#endif
#endif
@ -334,6 +334,12 @@ static inline int __coverity_check__(int condition) {
} \
} 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 INT_TO_PTR(u) ((void *) ((intptr_t) (u)))
#define PTR_TO_UINT(p) ((unsigned) ((uintptr_t) (p)))
@ -383,7 +389,7 @@ static inline int __coverity_check__(int condition) {
#define SET_FLAG(v, flag, b) \
(v) = (b) ? ((v) | (flag)) : ((v) & ~(flag))
#define FLAGS_SET(v, flags) \
(((v) & (flags)) == (flags))
((~(v) & (flags)) == 0)
#define CASE_F(X) case X:
#define CASE_F_1(CASE, X) CASE_F(X)

View file

@ -25,7 +25,6 @@
#include "alloc-util.h"
#include "architecture.h"
#include "def.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
@ -832,7 +831,7 @@ int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) {
void sigkill_wait(pid_t pid) {
assert(pid > 1);
if (kill(pid, SIGKILL) > 0)
if (kill(pid, SIGKILL) >= 0)
(void) wait_for_terminate(pid, NULL);
}
@ -850,7 +849,7 @@ void sigkill_waitp(pid_t *pid) {
void sigterm_wait(pid_t pid) {
assert(pid > 1);
if (kill_and_sigcont(pid, SIGTERM) > 0)
if (kill_and_sigcont(pid, SIGTERM) >= 0)
(void) wait_for_terminate(pid, NULL);
}
@ -1228,8 +1227,7 @@ int must_be_root(void) {
if (geteuid() == 0)
return 0;
log_error("Need to be root.");
return -EPERM;
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Need to be root.");
}
int safe_fork_full(
@ -1409,6 +1407,60 @@ int safe_fork_full(
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, ...) {
bool stdout_is_tty, stderr_is_tty;
size_t n, i;

View file

@ -159,6 +159,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);
}
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 set_oom_score_adjust(int value);

View file

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#ifdef __x86_64__
#if defined(__i386__) || defined(__x86_64__)
#include <cpuid.h>
#endif
@ -30,10 +30,13 @@
#include "random-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;
unsigned char err;
@ -56,6 +59,11 @@ int rdrand64(uint64_t *ret) {
"setc %1"
: "=r" (*ret),
"=qm" (err));
#if HAS_FEATURE_MEMORY_SANITIZER
__msan_unpoison(&err, sizeof(err));
#endif
if (!err)
return -EAGAIN;
@ -65,85 +73,132 @@ int rdrand64(uint64_t *ret) {
#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;
_cleanup_close_ int fd = -1;
size_t already_done = 0;
bool got_some = false;
int r;
/* Gathers some randomness from the kernel. This call will never block. If
* high_quality_required, it will always return some data from the kernel,
* regardless of whether the random pool is fully initialized or not.
* Otherwise, it will return success if at least some random bytes were
* successfully acquired, and an error if the kernel has no entropy whatsover
* for us. */
/* Gathers some randomness from the kernel (or the CPU if the RANDOM_ALLOW_RDRAND flag is set). This call won't
* block, unless the RANDOM_BLOCK flag is set. If RANDOM_DONT_DRAIN is set, an error is returned if the random
* pool is not initialized. Otherwise it will always return some data from the kernel, regardless of whether
* the random pool is fully initialized or not. */
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. */
if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) {
r = getrandom(p, n, GRND_NONBLOCK);
if (r > 0) {
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;
} else if (errno == ENOSYS)
/* 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;
for (;;) {
r = getrandom(p, n, FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_NONBLOCK);
if (r > 0) {
have_syscall = true;
if (!high_quality_required) {
uint64_t u;
size_t k;
if ((size_t) r == n)
return 0; /* Yay, success! */
/* 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 invocatins or so. That's because we don't really care about the
* quality here. */
assert((size_t) r < n);
p = (uint8_t*) p + r;
n -= r;
if (rdrand64(&u) < 0)
if (FLAGS_SET(flags, RANDOM_EXTEND_WITH_PSEUDO)) {
/* Fill in the remaining bytes using pseudo-random values */
pseudo_random_bytes(p, n);
return 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;
k = MIN(n, sizeof(u));
memcpy(p, &u, k);
/* We only get 64bit out of RDRAND, the rest let's fill up with pseudo-random crap. */
pseudorandom_bytes((uint8_t*) p + k, n - k);
return 0;
}
} else
return -errno;
/* Use /dev/urandom instead */
break;
} else
return -errno;
}
}
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
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) {
static bool srand_called = false;
unsigned x;
#if HAVE_SYS_AUXV_H
void *auxv;
const void *auxv;
#endif
unsigned long k;
if (srand_called)
return;
@ -153,7 +208,7 @@ void initialize_srand(void) {
* try to make use of that to seed the pseudo-random generator. It's
* better than nothing... */
auxv = (void*) getauxval(AT_RANDOM);
auxv = (const void*) getauxval(AT_RANDOM);
if (auxv) {
assert_cc(sizeof(x) <= 16);
memcpy(&x, auxv, sizeof(x));
@ -164,6 +219,9 @@ void initialize_srand(void) {
x ^= (unsigned) now(CLOCK_REALTIME);
x ^= (unsigned) gettid();
if (rdrand(&k) >= 0)
x ^= (unsigned) k;
srand(x);
srand_called = true;
}
@ -176,7 +234,7 @@ void initialize_srand(void) {
# define RAND_STEP 1
#endif
void pseudorandom_bytes(void *p, size_t n) {
void pseudo_random_bytes(void *p, size_t n) {
uint8_t *q;
initialize_srand();
@ -199,13 +257,10 @@ void pseudorandom_bytes(void *p, size_t n) {
}
void random_bytes(void *p, size_t n) {
int r;
r = acquire_random_bytes(p, n, false);
if (r >= 0)
if (genuine_random_bytes(p, n, RANDOM_EXTEND_WITH_PSEUDO|RANDOM_DONT_DRAIN|RANDOM_ALLOW_RDRAND) >= 0)
return;
/* If some idiot made /dev/urandom unavailable to us, or the
* kernel has no entropy, use a PRNG instead. */
return pseudorandom_bytes(p, n);
/* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */
pseudo_random_bytes(p, n);
}

View file

@ -5,9 +5,17 @@
#include <stddef.h>
#include <stdint.h>
int acquire_random_bytes(void *p, size_t n, bool high_quality_required);
void pseudorandom_bytes(void *p, size_t n);
void random_bytes(void *p, size_t n);
typedef enum RandomFlags {
RANDOM_EXTEND_WITH_PSEUDO = 1 << 0, /* If we can't get enough genuine randomness, but some, fill up the rest with pseudo-randomness */
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);
static inline uint64_t random_u64(void) {
@ -22,4 +30,4 @@ static inline uint32_t random_u32(void) {
return u;
}
int rdrand64(uint64_t *ret);
int rdrand(unsigned long *ret);

View file

@ -27,8 +27,8 @@
#include <stdint.h>
#ifdef __CHECKER__
#define __sd_bitwise __attribute__((bitwise))
#define __sd_force __attribute__((force))
#define __sd_bitwise __attribute__((__bitwise__))
#define __sd_force __attribute__((__force__))
#else
#define __sd_bitwise
#define __sd_force

View file

@ -47,10 +47,8 @@ int is_dir(const char* path, bool follow) {
int is_dir_fd(int fd) {
struct stat st;
int r;
r = fstat(fd, &st);
if (r < 0)
if (fstat(fd, &st) < 0)
return -errno;
return !!S_ISDIR(st.st_mode);
@ -215,15 +213,47 @@ int fd_is_network_fs(int fd) {
}
int fd_is_network_ns(int fd) {
struct statfs s;
int r;
r = fd_is_fs_type(fd, NSFS_MAGIC);
if (r <= 0)
return r;
/* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice
* way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle
* 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);
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 r == CLONE_NEWNET;
}

View file

@ -7,6 +7,7 @@
#include <sys/types.h>
#include "macro.h"
#include "util.h"
#define snprintf_ok(buf, len, fmt, ...) \
((size_t) snprintf(buf, len, fmt, __VA_ARGS__) < (len))
@ -18,6 +19,9 @@
do { \
int _argtypes[128]; \
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); \
assert(_k < ELEMENTSOF(_argtypes)); \
for (_i = 0; _i < _k; _i++) { \

View file

@ -169,7 +169,7 @@ char **strv_new_ap(const char *x, va_list ap) {
return TAKE_PTR(a);
}
char **strv_new(const char *x, ...) {
char **strv_new_internal(const char *x, ...) {
char **r;
va_list ap;
@ -658,7 +658,7 @@ char **strv_split_nulstr(const char *s) {
}
if (!r)
return strv_new(NULL, NULL);
return strv_new(NULL);
return r;
}

View file

@ -54,8 +54,9 @@ bool strv_equal(char **a, char **b);
#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);
#define strv_new(...) strv_new_internal(__VA_ARGS__, NULL)
#define STRV_IGNORE ((const char *) -1)

View file

@ -14,7 +14,6 @@
#include <unistd.h>
#include "alloc-util.h"
#include "def.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
@ -868,7 +867,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
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 {
const char *suffix;
usec_t usec;
@ -942,8 +941,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
for (;;) {
usec_t multiplier = default_unit, k;
long long l, z = 0;
unsigned n = 0;
long long l;
char *e;
p += strspn(p, WHITESPACE);
@ -966,46 +964,47 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
return -ERANGE;
if (*e == '.') {
char *b = e + 1;
/* 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;
p = e + 1;
p += strspn(p, DIGITS);
} else if (e == p)
return -EINVAL;
else
p = e;
e += strspn(e, WHITESPACE);
p = extract_multiplier(e, &multiplier);
s = extract_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;
something = true;
p = s;
k = ((usec_t) -1) / multiplier;
if ((usec_t) l + 1 >= k || (usec_t) z >= k)
if ((usec_t) l >= USEC_INFINITY / multiplier)
return -ERANGE;
k = (usec_t) z * multiplier;
for (; n > 0; n--)
k /= 10;
k += (usec_t) l * multiplier;
if (k >= ((usec_t) -1) - r)
k = (usec_t) l * multiplier;
if (k >= USEC_INFINITY - r)
return -ERANGE;
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;
@ -1032,44 +1031,60 @@ int parse_sec_fix_0(const char *t, usec_t *ret) {
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 {
const char *suffix;
nsec_t nsec;
} table[] = {
{ "seconds", NSEC_PER_SEC },
{ "second", NSEC_PER_SEC },
{ "sec", NSEC_PER_SEC },
{ "s", NSEC_PER_SEC },
{ "seconds", NSEC_PER_SEC },
{ "second", NSEC_PER_SEC },
{ "sec", NSEC_PER_SEC },
{ "s", NSEC_PER_SEC },
{ "minutes", NSEC_PER_MINUTE },
{ "minute", NSEC_PER_MINUTE },
{ "min", NSEC_PER_MINUTE },
{ "months", NSEC_PER_MONTH },
{ "month", NSEC_PER_MONTH },
{ "msec", NSEC_PER_MSEC },
{ "ms", NSEC_PER_MSEC },
{ "m", NSEC_PER_MINUTE },
{ "hours", NSEC_PER_HOUR },
{ "hour", NSEC_PER_HOUR },
{ "hr", NSEC_PER_HOUR },
{ "h", NSEC_PER_HOUR },
{ "days", NSEC_PER_DAY },
{ "day", NSEC_PER_DAY },
{ "d", NSEC_PER_DAY },
{ "weeks", NSEC_PER_WEEK },
{ "week", NSEC_PER_WEEK },
{ "w", NSEC_PER_WEEK },
{ "years", NSEC_PER_YEAR },
{ "year", NSEC_PER_YEAR },
{ "y", NSEC_PER_YEAR },
{ "usec", NSEC_PER_USEC },
{ "us", NSEC_PER_USEC },
{ "µs", NSEC_PER_USEC },
{ "nsec", 1ULL },
{ "ns", 1ULL },
{ "", 1ULL }, /* default is nsec */
{ "minute", NSEC_PER_MINUTE },
{ "min", NSEC_PER_MINUTE },
{ "months", NSEC_PER_MONTH },
{ "month", NSEC_PER_MONTH },
{ "M", NSEC_PER_MONTH },
{ "msec", NSEC_PER_MSEC },
{ "ms", NSEC_PER_MSEC },
{ "m", NSEC_PER_MINUTE },
{ "hours", NSEC_PER_HOUR },
{ "hour", NSEC_PER_HOUR },
{ "hr", NSEC_PER_HOUR },
{ "h", NSEC_PER_HOUR },
{ "days", NSEC_PER_DAY },
{ "day", NSEC_PER_DAY },
{ "d", NSEC_PER_DAY },
{ "weeks", NSEC_PER_WEEK },
{ "week", NSEC_PER_WEEK },
{ "w", NSEC_PER_WEEK },
{ "years", NSEC_PER_YEAR },
{ "year", NSEC_PER_YEAR },
{ "y", NSEC_PER_YEAR },
{ "usec", NSEC_PER_USEC },
{ "us", NSEC_PER_USEC },
{ "µs", NSEC_PER_USEC },
{ "nsec", 1ULL },
{ "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;
nsec_t r = 0;
bool something = false;
@ -1091,8 +1106,8 @@ int parse_nsec(const char *t, nsec_t *nsec) {
}
for (;;) {
long long l, z = 0;
size_t n = 0, i;
nsec_t multiplier = 1, k;
long long l;
char *e;
p += strspn(p, WHITESPACE);
@ -1104,7 +1119,7 @@ int parse_nsec(const char *t, nsec_t *nsec) {
break;
}
if (*p == '-')
if (*p == '-') /* Don't allow "-0" */
return -ERANGE;
errno = 0;
@ -1115,54 +1130,47 @@ int parse_nsec(const char *t, nsec_t *nsec) {
return -ERANGE;
if (*e == '.') {
char *b = e + 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;
p = e + 1;
p += strspn(p, DIGITS);
} else if (e == p)
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++)
if (startswith(e, table[i].suffix)) {
nsec_t k;
p = s;
k = ((nsec_t) -1) / table[i].nsec;
if ((nsec_t) l + 1 >= k || (nsec_t) z >= k)
return -ERANGE;
if ((nsec_t) l >= NSEC_INFINITY / multiplier)
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--)
k /= 10;
r += k;
k += (nsec_t) l * table[i].nsec;
if (k >= ((nsec_t) -1) - r)
something = true;
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;
r += k;
p = e + strlen(table[i].suffix);
something = true;
break;
}
if (i >= ELEMENTSOF(table))
return -EINVAL;
/* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge"*/
if (b == e + 1)
return -EINVAL;
}
}
*nsec = r;
@ -1190,7 +1198,7 @@ int get_timezones(char ***ret) {
assert(ret);
zones = strv_new("UTC", NULL);
zones = strv_new("UTC");
if (!zones)
return -ENOMEM;

View file

@ -165,6 +165,28 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
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) {
bool found_offline = false, found_online = false;
_cleanup_closedir_ DIR *d = NULL;
@ -248,7 +270,9 @@ int container_get_leader(const char *machine, pid_t *pid) {
return -EINVAL;
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)
return -EHOSTDOWN;
if (r < 0)
@ -606,7 +630,7 @@ void disable_coredumps(void) {
if (detect_container() > 0)
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)
log_debug_errno(r, "Failed to turn off coredumps, ignoring: %m");
}

View file

@ -159,6 +159,10 @@ int on_ac_power(void);
#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) {
memset(s, c, n);
return (uint8_t*)s + n;
@ -168,7 +172,8 @@ static inline void _reset_errno_(int *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) {
/* This helper should be used to shut up gcc if you know 'errno' is

View file

@ -148,24 +148,30 @@ int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len) {
return 0;
}
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) {
/* name is a pointer to memory in the sd_device struct, so must
* have the same scope */
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
const char *name = NULL;
uint64_t id;
uint32_t id32;
if (detect_container() <= 0) {
/* not in a container, udev will be around */
char ifindex_str[2 + DECIMAL_STR_MAX(int)];
int initialized, r;
int r;
sprintf(ifindex_str, "n%d", ifindex);
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)
return r;
if (!initialized)
if (r == 0)
/* not yet ready */
return -EBUSY;
@ -179,10 +185,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 */
id = siphash24(mac, mac_len, HASH_KEY.bytes);
id = htole64(id);
id32 = (id & 0xffffffff) ^ (id >> 32);
/* fold into 32 bits */
unaligned_write_be32(_id, (id & 0xffffffff) ^ (id >> 32));
if (legacy_unstable_byteorder)
/* 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;
}

View file

@ -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_en(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);

View file

@ -106,70 +106,62 @@ int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, ui
/* IP */
if (packet->ip.version != IPVERSION) {
log_debug("ignoring packet: not IPv4");
return -EINVAL;
}
if (packet->ip.version != IPVERSION)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"ignoring packet: not IPv4");
if (packet->ip.ihl < 5) {
log_debug("ignoring packet: IPv4 IHL (%u words) invalid",
packet->ip.ihl);
return -EINVAL;
}
if (packet->ip.ihl < 5)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"ignoring packet: IPv4 IHL (%u words) invalid",
packet->ip.ihl);
hdrlen = packet->ip.ihl * 4;
if (hdrlen < 20) {
log_debug("ignoring packet: IPv4 IHL (%zu bytes) "
"smaller than minimum (20 bytes)", hdrlen);
return -EINVAL;
}
if (hdrlen < 20)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"ignoring packet: IPv4 IHL (%zu bytes) "
"smaller than minimum (20 bytes)",
hdrlen);
if (len < hdrlen) {
log_debug("ignoring packet: packet (%zu bytes) "
"smaller than expected (%zu) by IP header", len,
hdrlen);
return -EINVAL;
}
if (len < hdrlen)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"ignoring packet: packet (%zu bytes) "
"smaller than expected (%zu) by IP header",
len, hdrlen);
/* UDP */
if (packet->ip.protocol != IPPROTO_UDP) {
log_debug("ignoring packet: not UDP");
return -EINVAL;
}
if (packet->ip.protocol != IPPROTO_UDP)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"ignoring packet: not UDP");
if (len < hdrlen + be16toh(packet->udp.len)) {
log_debug("ignoring packet: packet (%zu bytes) "
"smaller than expected (%zu) by UDP header", len,
hdrlen + be16toh(packet->udp.len));
return -EINVAL;
}
if (len < hdrlen + be16toh(packet->udp.len))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"ignoring packet: packet (%zu bytes) "
"smaller than expected (%zu) by UDP header",
len, hdrlen + be16toh(packet->udp.len));
if (be16toh(packet->udp.dest) != port) {
log_debug("ignoring packet: to port %u, which "
"is not the DHCP client port (%u)",
be16toh(packet->udp.dest), port);
return -EINVAL;
}
if (be16toh(packet->udp.dest) != port)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"ignoring packet: to port %u, which "
"is not the DHCP client port (%u)",
be16toh(packet->udp.dest), port);
/* checksums - computing these is relatively expensive, so only do it
if all the other checks have passed
*/
if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen)) {
log_debug("ignoring packet: invalid IP checksum");
return -EINVAL;
}
if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"ignoring packet: invalid IP checksum");
if (checksum && packet->udp.check) {
packet->ip.check = packet->udp.len;
packet->ip.ttl = 0;
if (dhcp_packet_checksum((uint8_t*)&packet->ip.ttl,
be16toh(packet->udp.len) + 12)) {
log_debug("ignoring packet: invalid UDP checksum");
return -EINVAL;
}
be16toh(packet->udp.len) + 12))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"ignoring packet: invalid UDP checksum");
}
return 0;

View file

@ -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(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_;

View file

@ -255,11 +255,10 @@ int config_parse_ifalias(const char *unit,
return 0;
}
free(*s);
if (*n)
*s = TAKE_PTR(n);
if (isempty(n))
*s = mfree(*s);
else
*s = NULL;
free_and_replace(*s, n);
return 0;
}
@ -294,7 +293,7 @@ int config_parse_hwaddr(const char *unit,
return 0;
}
*hwaddr = TAKE_PTR(n);
free_and_replace(*hwaddr, n);
return 0;
}

View file

@ -21,6 +21,7 @@
#include "dhcp-lease-internal.h"
#include "dhcp-protocol.h"
#include "dns-domain.h"
#include "event-util.h"
#include "hostname-util.h"
#include "random-util.h"
#include "string-util.h"
@ -371,6 +372,7 @@ static int dhcp_client_set_iaid_duid_internal(
if (iaid == 0) {
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
client->mac_addr_len,
true,
&client->client_id.ns.iaid);
if (r < 0)
return r;
@ -545,11 +547,10 @@ static int client_initialize(sd_dhcp_client *client) {
client->fd = asynchronous_close(client->fd);
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);
(void) event_source_disable(client->timeout_resend);
(void) event_source_disable(client->timeout_t1);
(void) event_source_disable(client->timeout_t2);
(void) event_source_disable(client->timeout_expire);
client->attempt = 1;
@ -650,7 +651,8 @@ static int client_message_init(
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)
return r;
@ -1063,22 +1065,11 @@ static int client_timeout_resend(
next_timeout += (random_u32() & 0x1fffff);
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
r = sd_event_add_time(client->event,
&client->timeout_resend,
clock_boottime_or_monotonic(),
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");
r = event_reset_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(),
next_timeout, 10 * USEC_PER_MSEC,
client_timeout_resend, client,
client->event_priority, "dhcp4-resend-timer", true);
if (r < 0)
goto error;
@ -1175,31 +1166,16 @@ static int client_initialize_time_events(sd_dhcp_client *client) {
assert(client);
assert(client->event);
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
if (client->start_delay) {
assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0);
usec += client->start_delay;
}
r = sd_event_add_time(client->event,
&client->timeout_resend,
clock_boottime_or_monotonic(),
usec, 0,
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)
goto error;
error:
r = event_reset_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(),
usec, 0,
client_timeout_resend, client,
client->event_priority, "dhcp4-resend-timer", true);
if (r < 0)
client_stop(client, r);
@ -1457,13 +1433,14 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
assert(client->lease);
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 */
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;
}
r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
if (r < 0)
@ -1515,19 +1492,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
}
/* arm lifetime timeout */
r = sd_event_add_time(client->event, &client->timeout_expire,
clock_boottime_or_monotonic(),
lifetime_timeout, 10 * USEC_PER_MSEC,
client_timeout_expire, client);
if (r < 0)
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");
r = event_reset_time(client->event, &client->timeout_expire,
clock_boottime_or_monotonic(),
lifetime_timeout, 10 * USEC_PER_MSEC,
client_timeout_expire, client,
client->event_priority, "dhcp4-lifetime", true);
if (r < 0)
return r;
@ -1539,21 +1508,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return 0;
/* arm T2 timeout */
r = sd_event_add_time(client->event,
&client->timeout_t2,
clock_boottime_or_monotonic(),
t2_timeout,
10 * USEC_PER_MSEC,
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");
r = event_reset_time(client->event, &client->timeout_t2,
clock_boottime_or_monotonic(),
t2_timeout, 10 * USEC_PER_MSEC,
client_timeout_t2, client,
client->event_priority, "dhcp4-t2-timeout", true);
if (r < 0)
return r;
@ -1565,20 +1524,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return 0;
/* arm T1 timeout */
r = sd_event_add_time(client->event,
&client->timeout_t1,
clock_boottime_or_monotonic(),
t1_timeout, 10 * USEC_PER_MSEC,
client_timeout_t1, client);
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");
r = event_reset_time(client->event, &client->timeout_t1,
clock_boottime_or_monotonic(),
t1_timeout, 10 * USEC_PER_MSEC,
client_timeout_t1, client,
client->event_priority, "dhcp4-t1-timer", true);
if (r < 0)
return r;
@ -1603,26 +1553,14 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
r = client_handle_offer(client, message, len);
if (r >= 0) {
client->timeout_resend =
sd_event_source_unref(client->timeout_resend);
client->state = DHCP_STATE_REQUESTING;
client->attempt = 1;
r = sd_event_add_time(client->event,
&client->timeout_resend,
clock_boottime_or_monotonic(),
0, 0,
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");
r = event_reset_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(),
0, 0,
client_timeout_resend, client,
client->event_priority, "dhcp4-resend-timer", true);
if (r < 0)
goto error;
} else if (r == -ENOMSG)
@ -1639,8 +1577,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
r = client_handle_ack(client, message, len);
if (r >= 0) {
client->start_delay = 0;
client->timeout_resend =
sd_event_source_unref(client->timeout_resend);
(void) event_source_disable(client->timeout_resend);
client->receive_message =
sd_event_source_unref(client->receive_message);
client->fd = asynchronous_close(client->fd);
@ -1680,9 +1617,6 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
} else if (r == -EADDRNOTAVAIL) {
/* 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);
r = client_initialize(client);
@ -1958,9 +1892,12 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
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);
@ -1980,19 +1917,20 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
assert_return(ret, -EINVAL);
client = new0(sd_dhcp_client, 1);
client = new(sd_dhcp_client, 1);
if (!client)
return -ENOMEM;
client->n_ref = 1;
client->state = DHCP_STATE_INIT;
client->ifindex = -1;
client->fd = -1;
client->attempt = 1;
client->mtu = DHCP_DEFAULT_MIN_SIZE;
client->port = DHCP_PORT_CLIENT;
client->anonymize = !!anonymize;
*client = (sd_dhcp_client) {
.n_ref = 1,
.state = DHCP_STATE_INIT,
.ifindex = -1,
.fd = -1,
.attempt = 1,
.mtu = DHCP_DEFAULT_MIN_SIZE,
.port = DHCP_PORT_CLIENT,
.anonymize = !!anonymize,
};
/* NOTE: this could be moved to a function. */
if (anonymize) {
client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize);

View file

@ -1016,7 +1016,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
if (r < 0)
return r;
r = parse_env_file(NULL, lease_file, NEWLINE,
r = parse_env_file(NULL, lease_file,
"ADDRESS", &address,
"ROUTER", &router,
"NETMASK", &netmask,
@ -1067,8 +1067,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
"OPTION_251", &options[27],
"OPTION_252", &options[28],
"OPTION_253", &options[29],
"OPTION_254", &options[30],
NULL);
"OPTION_254", &options[30]);
if (r < 0)
return r;

View file

@ -16,6 +16,7 @@
#include "dhcp6-lease-internal.h"
#include "dhcp6-protocol.h"
#include "dns-domain.h"
#include "event-util.h"
#include "fd-util.h"
#include "hostname-util.h"
#include "in-addr-util.h"
@ -408,12 +409,11 @@ static int client_reset(sd_dhcp6_client *client) {
client->retransmit_time = 0;
client->retransmit_count = 0;
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
client->timeout_resend_expire =
sd_event_source_unref(client->timeout_resend_expire);
client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
(void) event_source_disable(client->timeout_resend);
(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;
@ -600,8 +600,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
assert(client);
assert(client->lease);
client->timeout_t2 =
sd_event_source_unref(client->timeout_t2);
(void) event_source_disable(client->timeout_t2);
log_dhcp6_client(client, "Timeout T2");
@ -617,8 +616,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
assert(client);
assert(client->lease);
client->timeout_t1 =
sd_event_source_unref(client->timeout_t1);
(void) event_source_disable(client->timeout_t1);
log_dhcp6_client(client, "Timeout T1");
@ -666,7 +664,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
assert(client);
assert(client->event);
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
(void) event_source_disable(client->timeout_resend);
switch (client->state) {
case DHCP6_STATE_INFORMATION_REQUEST:
@ -708,7 +706,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
init_retransmit_time = DHCP6_REB_TIMEOUT;
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,
&expire);
if (r < 0) {
@ -757,43 +755,24 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
log_dhcp6_client(client, "Next retransmission in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC));
r = sd_event_add_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(),
time_now + client->retransmit_time,
10 * USEC_PER_MSEC, client_timeout_resend,
client);
r = event_reset_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(),
time_now + client->retransmit_time, 10 * USEC_PER_MSEC,
client_timeout_resend, client,
client->event_priority, "dhcp6-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, "dhcp6-resend-timer");
if (r < 0)
goto error;
if (max_retransmit_duration && !client->timeout_resend_expire) {
if (max_retransmit_duration && event_source_is_enabled(client->timeout_resend_expire) <= 0) {
log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
max_retransmit_duration / USEC_PER_SEC);
r = sd_event_add_time(client->event,
&client->timeout_resend_expire,
clock_boottime_or_monotonic(),
time_now + max_retransmit_duration,
USEC_PER_SEC,
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");
r = event_reset_time(client->event, &client->timeout_resend_expire,
clock_boottime_or_monotonic(),
time_now + max_retransmit_duration, USEC_PER_SEC,
client_timeout_resend_expire, client,
client->event_priority, "dhcp6-resend-expire-timer", true);
if (r < 0)
goto error;
}
@ -807,14 +786,14 @@ error:
static int client_ensure_iaid(sd_dhcp6_client *client) {
int r;
be32_t iaid;
uint32_t iaid;
assert(client);
if (client->ia_na.ia_na.id)
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)
return r;
@ -1263,9 +1242,8 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
assert_return(client->ifindex > 0, -EINVAL);
assert_return(client->state != state, -EINVAL);
client->timeout_resend_expire =
sd_event_source_unref(client->timeout_resend_expire);
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
(void) event_source_disable(client->timeout_resend_expire);
(void) event_source_disable(client->timeout_resend);
client->retransmit_time = 0;
client->retransmit_count = 0;
@ -1332,20 +1310,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
log_dhcp6_client(client, "T1 expires in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
r = sd_event_add_time(client->event,
&client->timeout_t1,
clock_boottime_or_monotonic(), time_now + timeout,
10 * USEC_PER_SEC, client_timeout_t1,
client);
if (r < 0)
goto error;
r = sd_event_source_set_priority(client->timeout_t1,
client->event_priority);
if (r < 0)
goto error;
r = sd_event_source_set_description(client->timeout_t1, "dhcp6-t1-timeout");
r = event_reset_time(client->event, &client->timeout_t1,
clock_boottime_or_monotonic(),
time_now + timeout, 10 * USEC_PER_SEC,
client_timeout_t1, client,
client->event_priority, "dhcp6-t1-timeout", true);
if (r < 0)
goto error;
@ -1354,20 +1323,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
log_dhcp6_client(client, "T2 expires in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
r = sd_event_add_time(client->event,
&client->timeout_t2,
clock_boottime_or_monotonic(), time_now + timeout,
10 * USEC_PER_SEC, client_timeout_t2,
client);
if (r < 0)
goto error;
r = sd_event_source_set_priority(client->timeout_t2,
client->event_priority);
if (r < 0)
goto error;
r = sd_event_source_set_description(client->timeout_t2, "dhcp6-t2-timeout");
r = event_reset_time(client->event, &client->timeout_t2,
clock_boottime_or_monotonic(),
time_now + timeout, 10 * USEC_PER_SEC,
client_timeout_t2, client,
client->event_priority, "dhcp6-t2-timeout", true);
if (r < 0)
goto error;
@ -1379,18 +1339,11 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
client->transaction_id = random_u32() & htobe32(0x00ffffff);
client->transaction_start = time_now;
r = sd_event_add_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(), 0, 0, 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, "dhcp6-resend-timeout");
r = event_reset_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(),
0, 0,
client_timeout_resend, client,
client->event_priority, "dhcp6-resend-timeout", true);
if (r < 0)
goto error;
@ -1503,6 +1456,11 @@ sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) {
static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *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->fd = safe_close(client->fd);
@ -1518,28 +1476,32 @@ DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_client, sd_dhcp6_client, dhcp6_client_fre
int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
_cleanup_free_ be16_t *req_opts = NULL;
size_t t;
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)
return -ENOMEM;
client->n_ref = 1;
client->ia_na.type = SD_DHCP6_OPTION_IA_NA;
client->ia_pd.type = SD_DHCP6_OPTION_IA_PD;
client->ifindex = -1;
client->request = DHCP6_REQUEST_IA_NA;
client->fd = -1;
client->req_opts_len = ELEMENTSOF(default_req_opts);
client->req_opts = new0(be16_t, client->req_opts_len);
if (!client->req_opts)
return -ENOMEM;
for (t = 0; t < client->req_opts_len; t++)
client->req_opts[t] = htobe16(default_req_opts[t]);
*client = (sd_dhcp6_client) {
.n_ref = 1,
.ia_na.type = SD_DHCP6_OPTION_IA_NA,
.ia_pd.type = SD_DHCP6_OPTION_IA_PD,
.ifindex = -1,
.request = DHCP6_REQUEST_IA_NA,
.fd = -1,
.req_opts_len = ELEMENTSOF(default_req_opts),
.req_opts = TAKE_PTR(req_opts),
};
*ret = TAKE_PTR(client);

View file

@ -14,6 +14,7 @@
#include "alloc-util.h"
#include "arp-util.h"
#include "ether-addr-util.h"
#include "event-util.h"
#include "fd-util.h"
#include "in-addr-util.h"
#include "list.h"
@ -89,7 +90,7 @@ static void ipv4acd_set_state(sd_ipv4acd *acd, IPv4ACDState st, bool reset_count
static void ipv4acd_reset(sd_ipv4acd *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->fd = safe_close(acd->fd);
@ -100,6 +101,8 @@ static void ipv4acd_reset(sd_ipv4acd *acd) {
static sd_ipv4acd *ipv4acd_free(sd_ipv4acd *acd) {
assert(acd);
acd->timer_event_source = sd_event_source_unref(acd->timer_event_source);
ipv4acd_reset(acd);
sd_ipv4acd_detach_event(acd);
@ -113,14 +116,16 @@ int sd_ipv4acd_new(sd_ipv4acd **ret) {
assert_return(ret, -EINVAL);
acd = new0(sd_ipv4acd, 1);
acd = new(sd_ipv4acd, 1);
if (!acd)
return -ENOMEM;
acd->n_ref = 1;
acd->state = IPV4ACD_STATE_INIT;
acd->ifindex = -1;
acd->fd = -1;
*acd = (sd_ipv4acd) {
.n_ref = 1,
.state = IPV4ACD_STATE_INIT,
.ifindex = -1,
.fd = -1,
};
*ret = TAKE_PTR(acd);
@ -151,9 +156,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_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;
int r;
assert(acd);
@ -164,20 +167,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);
r = sd_event_add_time(acd->event, &timer, clock_boottime_or_monotonic(), time_now + next_timeout, 0, ipv4acd_on_timeout, acd);
if (r < 0)
return r;
r = sd_event_source_set_priority(timer, acd->event_priority);
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;
return event_reset_time(acd->event, &acd->timer_event_source,
clock_boottime_or_monotonic(),
time_now + next_timeout, 0,
ipv4acd_on_timeout, acd,
acd->event_priority, "ipv4acd-timer", true);
}
static bool ipv4acd_arp_conflict(sd_ipv4acd *acd, struct ether_arp *arp) {

View file

@ -6,15 +6,26 @@
#include "sd-lldp.h"
#include "alloc-util.h"
#include "ether-addr-util.h"
#include "event-util.h"
#include "fd-util.h"
#include "lldp-internal.h"
#include "lldp-neighbor.h"
#include "lldp-network.h"
#include "socket-util.h"
#include "ether-addr-util.h"
#include "string-table.h"
#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) {
sd_lldp_neighbor *n;
@ -26,12 +37,14 @@ static void lldp_flush_neighbors(sd_lldp *lldp) {
static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) {
assert(lldp);
assert(event >= 0 && event < _SD_LLDP_EVENT_MAX);
log_lldp("Invoking callback for '%c'.", event);
if (!lldp->callback)
if (!lldp->callback) {
log_lldp("Received '%s' event.", lldp_event_to_string(event));
return;
}
log_lldp("Invoking callback for '%s' event.", lldp_event_to_string(event));
lldp->callback(lldp, event, n, lldp->userdata);
}
@ -223,7 +236,7 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v
static void lldp_reset(sd_lldp *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->fd = safe_close(lldp->fd);
}
@ -332,6 +345,8 @@ _public_ int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex) {
static sd_lldp* lldp_free(sd_lldp *lldp) {
assert(lldp);
lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source);
lldp_reset(lldp);
sd_lldp_detach_event(lldp);
lldp_flush_neighbors(lldp);
@ -349,14 +364,16 @@ _public_ int sd_lldp_new(sd_lldp **ret) {
assert_return(ret, -EINVAL);
lldp = new0(sd_lldp, 1);
lldp = new(sd_lldp, 1);
if (!lldp)
return -ENOMEM;
lldp->n_ref = 1;
lldp->fd = -1;
lldp->neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX;
lldp->capability_mask = (uint16_t) -1;
*lldp = (sd_lldp) {
.n_ref = 1,
.fd = -1,
.neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX,
.capability_mask = (uint16_t) -1,
};
lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_id_hash_ops);
if (!lldp->neighbor_by_id)
@ -392,7 +409,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) {
sd_lldp_neighbor *n;
int r;
assert(lldp);
@ -400,35 +416,17 @@ static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor) {
lldp_neighbor_start_ttl(neighbor);
n = prioq_peek(lldp->neighbor_by_expiry);
if (!n) {
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 (!n)
return event_source_disable(lldp->timer_event_source);
if (!lldp->event)
return 0;
r = sd_event_add_time(lldp->event, &lldp->timer_event_source, clock_boottime_or_monotonic(), n->until, 0, on_timer_event, lldp);
if (r < 0)
return r;
r = sd_event_source_set_priority(lldp->timer_event_source, lldp->event_priority);
if (r < 0)
return r;
(void) sd_event_source_set_description(lldp->timer_event_source, "lldp-timer");
return 0;
return event_reset_time(lldp->event, &lldp->timer_event_source,
clock_boottime_or_monotonic(),
n->until, 0,
on_timer_event, lldp,
lldp->event_priority, "lldp-timer", true);
}
_public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) {

View file

@ -0,0 +1,99 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#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);
}

View 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);

View file

@ -9,6 +9,7 @@
#include "sd-id128.h"
#include "alloc-util.h"
#include "event-source.h"
#include "fd-util.h"
#include "fs-util.h"
#include "hashmap.h"
@ -26,24 +27,6 @@
#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] = {
[SOURCE_IO] = "io",
[SOURCE_TIME_REALTIME] = "realtime",
@ -62,183 +45,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);
/* 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)
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 {
unsigned n_ref;
@ -1887,9 +1695,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) {
assert_return(s, -EINVAL);
assert_return(description, -EINVAL);
assert_return(s->description, -ENXIO);
assert_return(!event_pid_changed(s->event), -ECHILD);
if (!s->description)
return -ENXIO;
*description = s->description;
return 0;
}
@ -2141,11 +1951,11 @@ fail:
_public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) {
assert_return(s, -EINVAL);
assert_return(m, -EINVAL);
assert_return(!event_pid_changed(s->event), -ECHILD);
*m = s->enabled;
return 0;
if (m)
*m = s->enabled;
return s->enabled != SD_EVENT_OFF;
}
_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
@ -3702,3 +3512,31 @@ _public_ int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_d
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;
}

View file

@ -272,7 +272,9 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) {
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)
return r;

View file

@ -25,22 +25,22 @@
#ifndef _sd_printf_
# if __GNUC__ >= 4
# define _sd_printf_(a,b) __attribute__ ((format (printf, a, b)))
# define _sd_printf_(a,b) __attribute__ ((__format__(printf, a, b)))
# else
# define _sd_printf_(a,b)
# endif
#endif
#ifndef _sd_sentinel_
# define _sd_sentinel_ __attribute__((sentinel))
# define _sd_sentinel_ __attribute__((__sentinel__))
#endif
#ifndef _sd_packed_
# define _sd_packed_ __attribute__((packed))
# define _sd_packed_ __attribute__((__packed__))
#endif
#ifndef _sd_pure_
# define _sd_pure_ __attribute__((pure))
# define _sd_pure_ __attribute__((__pure__))
#endif
#ifndef _SD_STRINGIFY

View file

@ -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_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_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. */
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref);

View file

@ -109,10 +109,12 @@ typedef struct sd_lldp sd_lldp;
typedef struct sd_lldp_neighbor sd_lldp_neighbor;
typedef enum sd_lldp_event {
SD_LLDP_EVENT_ADDED = 'a',
SD_LLDP_EVENT_REMOVED = 'r',
SD_LLDP_EVENT_UPDATED = 'u',
SD_LLDP_EVENT_REFRESHED = 'f',
SD_LLDP_EVENT_ADDED,
SD_LLDP_EVENT_REMOVED,
SD_LLDP_EVENT_UPDATED,
SD_LLDP_EVENT_REFRESHED,
_SD_LLDP_EVENT_MAX,
_SD_LLDP_EVENT_INVALID = -1,
} sd_lldp_event;
typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata);

View file

@ -55,8 +55,10 @@ typedef struct sd_ndisc sd_ndisc;
typedef struct sd_ndisc_router sd_ndisc_router;
typedef enum sd_ndisc_event {
SD_NDISC_EVENT_TIMEOUT = 't',
SD_NDISC_EVENT_ROUTER = 'r',
SD_NDISC_EVENT_TIMEOUT,
SD_NDISC_EVENT_ROUTER,
_SD_NDISC_EVENT_MAX,
_SD_NDISC_EVENT_INVALID = -1,
} sd_ndisc_event;
typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata);