From b4564eaa66b9c65a3196f9f57d9a39c5dc8fd3d1 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 11 May 2016 19:34:13 +0200 Subject: systemd: update code from upstream This is a direct dump from systemd git on 2016-05-12, git commit 42d35e1301928d08dd32ec51f0205252ae658ba5. ====== SYSTEMD_DIR=../systemd COMMIT=42d35e1301928d08dd32ec51f0205252ae658ba5 ( cd "$SYSTEMD_DIR" git checkout "$COMMIT" git reset --hard git clean -fdx ) git ls-files :/src/systemd/src/ | xargs -d '\n' rm -f nm_copy_sd() { mkdir -p "./src/systemd/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/systemd/$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/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/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.c" 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/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 "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-ipv4ll.c" nm_copy_sd "src/libsystemd-network/sd-ipv4acd.c" nm_copy_sd "src/libsystemd-network/sd-lldp.c" nm_copy_sd "src/libsystemd/sd-event/sd-event.c" 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" --- src/systemd/src/basic/extract-word.c | 298 +++++++++++++++++++++ src/systemd/src/basic/extract-word.h | 35 +++ src/systemd/src/basic/fd-util.c | 18 +- src/systemd/src/basic/fd-util.h | 2 + src/systemd/src/basic/fileio.c | 124 +++++++-- src/systemd/src/basic/fileio.h | 6 +- src/systemd/src/basic/fs-util.c | 15 ++ src/systemd/src/basic/fs-util.h | 2 + src/systemd/src/basic/hashmap.c | 10 +- src/systemd/src/basic/io-util.c | 5 + src/systemd/src/basic/parse-util.h | 2 +- src/systemd/src/basic/path-util.c | 65 +++-- src/systemd/src/basic/path-util.h | 3 +- src/systemd/src/basic/socket-util.c | 78 ++++++ src/systemd/src/basic/socket-util.h | 15 ++ src/systemd/src/basic/time-util.c | 37 ++- src/systemd/src/basic/time-util.h | 1 + src/systemd/src/basic/util.c | 2 +- .../src/libsystemd-network/dhcp-identifier.c | 31 +++ .../src/libsystemd-network/dhcp-identifier.h | 42 +-- .../src/libsystemd-network/network-internal.c | 141 ++++------ .../src/libsystemd-network/network-internal.h | 4 - .../src/libsystemd-network/sd-dhcp-client.c | 181 ++++++++----- .../src/libsystemd-network/sd-dhcp6-client.c | 58 ++-- src/systemd/src/libsystemd/sd-event/sd-event.c | 10 +- src/systemd/src/systemd/sd-dhcp-client.h | 78 ++++-- src/systemd/src/systemd/sd-dhcp6-client.h | 61 +++-- 27 files changed, 1001 insertions(+), 323 deletions(-) create mode 100644 src/systemd/src/basic/extract-word.c create mode 100644 src/systemd/src/basic/extract-word.h (limited to 'src/systemd') diff --git a/src/systemd/src/basic/extract-word.c b/src/systemd/src/basic/extract-word.c new file mode 100644 index 0000000000..d6c1228463 --- /dev/null +++ b/src/systemd/src/basic/extract-word.c @@ -0,0 +1,298 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alloc-util.h" +#include "escape.h" +#include "extract-word.h" +#include "log.h" +#include "macro.h" +#include "string-util.h" +#include "utf8.h" + +int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { + _cleanup_free_ char *s = NULL; + size_t allocated = 0, sz = 0; + char c; + int r; + + char quote = 0; /* 0 or ' or " */ + bool backslash = false; /* whether we've just seen a backslash */ + + assert(p); + assert(ret); + + /* Bail early if called after last value or with no input */ + if (!*p) + goto finish_force_terminate; + c = **p; + + if (!separators) + separators = WHITESPACE; + + /* Parses the first word of a string, and returns it in + * *ret. Removes all quotes in the process. When parsing fails + * (because of an uneven number of quotes or similar), leaves + * the pointer *p at the first invalid character. */ + + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) + if (!GREEDY_REALLOC(s, allocated, sz+1)) + return -ENOMEM; + + for (;; (*p)++, c = **p) { + if (c == 0) + goto finish_force_terminate; + else if (strchr(separators, c)) { + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { + (*p)++; + goto finish_force_next; + } + } else { + /* We found a non-blank character, so we will always + * want to return a string (even if it is empty), + * allocate it here. */ + if (!GREEDY_REALLOC(s, allocated, sz+1)) + return -ENOMEM; + break; + } + } + + for (;; (*p)++, c = **p) { + if (backslash) { + if (!GREEDY_REALLOC(s, allocated, sz+7)) + return -ENOMEM; + + if (c == 0) { + if ((flags & EXTRACT_CUNESCAPE_RELAX) && + (!quote || flags & EXTRACT_RELAX)) { + /* If we find an unquoted trailing backslash and we're in + * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the + * output. + * + * Unbalanced quotes will only be allowed in EXTRACT_RELAX + * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them. + */ + s[sz++] = '\\'; + goto finish_force_terminate; + } + if (flags & EXTRACT_RELAX) + goto finish_force_terminate; + return -EINVAL; + } + + if (flags & EXTRACT_CUNESCAPE) { + bool eight_bit = false; + char32_t u; + + r = cunescape_one(*p, (size_t) -1, &u, &eight_bit); + if (r < 0) { + if (flags & EXTRACT_CUNESCAPE_RELAX) { + s[sz++] = '\\'; + s[sz++] = c; + } else + return -EINVAL; + } else { + (*p) += r - 1; + + if (eight_bit) + s[sz++] = u; + else + sz += utf8_encode_unichar(s + sz, u); + } + } else + s[sz++] = c; + + backslash = false; + + } else if (quote) { /* inside either single or double quotes */ + for (;; (*p)++, c = **p) { + if (c == 0) { + if (flags & EXTRACT_RELAX) + goto finish_force_terminate; + return -EINVAL; + } else if (c == quote) { /* found the end quote */ + quote = 0; + break; + } else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) { + backslash = true; + break; + } else { + if (!GREEDY_REALLOC(s, allocated, sz+2)) + return -ENOMEM; + + s[sz++] = c; + } + } + + } else { + for (;; (*p)++, c = **p) { + if (c == 0) + goto finish_force_terminate; + else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES)) { + quote = c; + break; + } else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) { + backslash = true; + break; + } else if (strchr(separators, c)) { + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { + (*p)++; + goto finish_force_next; + } + /* Skip additional coalesced separators. */ + for (;; (*p)++, c = **p) { + if (c == 0) + goto finish_force_terminate; + if (!strchr(separators, c)) + break; + } + goto finish; + + } else { + if (!GREEDY_REALLOC(s, allocated, sz+2)) + return -ENOMEM; + + s[sz++] = c; + } + } + } + } + +finish_force_terminate: + *p = NULL; +finish: + if (!s) { + *p = NULL; + *ret = NULL; + return 0; + } + +finish_force_next: + s[sz] = 0; + *ret = s; + s = NULL; + + return 1; +} + +int extract_first_word_and_warn( + const char **p, + char **ret, + const char *separators, + ExtractFlags flags, + const char *unit, + const char *filename, + unsigned line, + const char *rvalue) { + + /* Try to unquote it, if it fails, warn about it and try again + * but this time using EXTRACT_CUNESCAPE_RELAX to keep the + * backslashes verbatim in invalid escape sequences. */ + + const char *save; + int r; + + save = *p; + r = extract_first_word(p, ret, separators, flags); + if (r >= 0) + return r; + + if (r == -EINVAL && !(flags & EXTRACT_CUNESCAPE_RELAX)) { + + /* Retry it with EXTRACT_CUNESCAPE_RELAX. */ + *p = save; + r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX); + if (r >= 0) { + /* It worked this time, hence it must have been an invalid escape sequence we could correct. */ + log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Invalid escape sequences in line, correcting: \"%s\"", rvalue); + return r; + } + + /* If it's still EINVAL; then it must be unbalanced quoting, report this. */ + if (r == -EINVAL) + return log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting, ignoring: \"%s\"", rvalue); + } + + /* Can be any error, report it */ + return log_syntax(unit, LOG_ERR, filename, line, r, "Unable to decode word \"%s\", ignoring: %m", rvalue); +} + +int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) { + va_list ap; + char **l; + int n = 0, i, c, r; + + /* Parses a number of words from a string, stripping any + * quotes if necessary. */ + + assert(p); + + /* Count how many words are expected */ + va_start(ap, flags); + for (;;) { + if (!va_arg(ap, char **)) + break; + n++; + } + va_end(ap); + + if (n <= 0) + return 0; + + /* Read all words into a temporary array */ + l = newa0(char*, n); + for (c = 0; c < n; c++) { + + r = extract_first_word(p, &l[c], separators, flags); + if (r < 0) { + int j; + + for (j = 0; j < c; j++) + free(l[j]); + + return r; + } + + if (r == 0) + break; + } + + /* If we managed to parse all words, return them in the passed + * in parameters */ + va_start(ap, flags); + for (i = 0; i < n; i++) { + char **v; + + v = va_arg(ap, char **); + assert(v); + + *v = l[i]; + } + va_end(ap); + + return c; +} diff --git a/src/systemd/src/basic/extract-word.h b/src/systemd/src/basic/extract-word.h new file mode 100644 index 0000000000..21db5ef33f --- /dev/null +++ b/src/systemd/src/basic/extract-word.h @@ -0,0 +1,35 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "macro.h" + +typedef enum ExtractFlags { + EXTRACT_RELAX = 1, + EXTRACT_CUNESCAPE = 2, + EXTRACT_CUNESCAPE_RELAX = 4, + EXTRACT_QUOTES = 8, + EXTRACT_DONT_COALESCE_SEPARATORS = 16, + EXTRACT_RETAIN_ESCAPE = 32, +} ExtractFlags; + +int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); +int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); +int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_; diff --git a/src/systemd/src/basic/fd-util.c b/src/systemd/src/basic/fd-util.c index ec9560cd07..8b466cff15 100644 --- a/src/systemd/src/basic/fd-util.c +++ b/src/systemd/src/basic/fd-util.c @@ -25,11 +25,13 @@ #include #include "fd-util.h" +#include "fs-util.h" #include "macro.h" #include "missing.h" #include "parse-util.h" #include "path-util.h" #include "socket-util.h" +#include "stdio-util.h" #include "util.h" int close_nointr(int fd) { @@ -229,7 +231,7 @@ int close_all_fds(const int except[], unsigned n_except) { while ((de = readdir(d))) { int fd = -1; - if (hidden_file(de->d_name)) + if (hidden_or_backup_file(de->d_name)) continue; if (safe_atoi(de->d_name, &fd) < 0) @@ -356,3 +358,17 @@ bool fdname_is_valid(const char *s) { return p - s < 256; } + +int fd_get_path(int fd, char **ret) { + char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + int r; + + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + + r = readlink_malloc(procfs_path, ret); + + if (r == -ENOENT) /* If the file doesn't exist the fd is invalid */ + return -EBADF; + + return r; +} diff --git a/src/systemd/src/basic/fd-util.h b/src/systemd/src/basic/fd-util.h index 44528c6e35..b86e41698a 100644 --- a/src/systemd/src/basic/fd-util.h +++ b/src/systemd/src/basic/fd-util.h @@ -72,6 +72,8 @@ void cmsg_close_all(struct msghdr *mh); bool fdname_is_valid(const char *s); +int fd_get_path(int fd, char **ret); + /* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */ #define ERRNO_IS_DISCONNECT(r) \ IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH) diff --git a/src/systemd/src/basic/fileio.c b/src/systemd/src/basic/fileio.c index 69590941e5..29f5374222 100644 --- a/src/systemd/src/basic/fileio.c +++ b/src/systemd/src/basic/fileio.c @@ -1083,30 +1083,6 @@ int mkostemp_safe(char *pattern, int flags) { return fd; } -int open_tmpfile(const char *path, int flags) { - char *p; - int fd; - - assert(path); - -#ifdef O_TMPFILE - /* Try O_TMPFILE first, if it is supported */ - fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR); - if (fd >= 0) - return fd; -#endif - - /* Fall back to unguessable name + unlinking */ - p = strjoina(path, "/systemd-tmp-XXXXXX"); - - fd = mkostemp_safe(p, flags); - if (fd < 0) - return fd; - - unlink(p); - return fd; -} - int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { const char *fn; char *t; @@ -1278,3 +1254,103 @@ int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) return fputs(s, f); } + +int open_tmpfile_unlinkable(const char *directory, int flags) { + char *p; + int fd; + + assert(directory); + + /* Returns an unlinked temporary file that cannot be linked into the file system anymore */ + +#ifdef O_TMPFILE + /* Try O_TMPFILE first, if it is supported */ + fd = open(directory, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR); + if (fd >= 0) + return fd; +#endif + + /* Fall back to unguessable name + unlinking */ + p = strjoina(directory, "/systemd-tmp-XXXXXX"); + + fd = mkostemp_safe(p, flags); + if (fd < 0) + return fd; + + (void) unlink(p); + + return fd; +} + +int open_tmpfile_linkable(const char *target, int flags, char **ret_path) { + _cleanup_free_ char *tmp = NULL; + int r, fd; + + assert(target); + assert(ret_path); + + /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */ + assert((flags & O_EXCL) == 0); + + /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in + * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in + * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */ + +#ifdef O_TMPFILE + { + _cleanup_free_ char *dn = NULL; + + dn = dirname_malloc(target); + if (!dn) + return -ENOMEM; + + fd = open(dn, O_TMPFILE|flags, 0640); + if (fd >= 0) { + *ret_path = NULL; + return fd; + } + + log_debug_errno(errno, "Failed to use O_TMPFILE on %s: %m", dn); + } +#endif + + r = tempfn_random(target, NULL, &tmp); + if (r < 0) + return r; + + fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, 0640); + if (fd < 0) + return -errno; + + *ret_path = tmp; + tmp = NULL; + + return fd; +} + +int link_tmpfile(int fd, const char *path, const char *target) { + + assert(fd >= 0); + assert(target); + + /* Moves a temporary file created with open_tmpfile() above into its final place. if "path" is NULL an fd + * created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported + * on the directory, and renameat2() is used instead. + * + * Note that in both cases we will not replace existing files. This is because linkat() does not support this + * operation currently (renameat2() does), and there is no nice way to emulate this. */ + + if (path) { + if (rename_noreplace(AT_FDCWD, path, AT_FDCWD, target) < 0) + return -errno; + } else { + char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1]; + + xsprintf(proc_fd_path, "/proc/self/fd/%i", fd); + + if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0) + return -errno; + } + + return 0; +} diff --git a/src/systemd/src/basic/fileio.h b/src/systemd/src/basic/fileio.h index 8084895ff3..58dbc80c24 100644 --- a/src/systemd/src/basic/fileio.h +++ b/src/systemd/src/basic/fileio.h @@ -72,7 +72,6 @@ int fflush_and_check(FILE *f); int fopen_temporary(const char *path, FILE **_f, char **_temp_path); int mkostemp_safe(char *pattern, int flags); -int open_tmpfile(const char *path, int flags); int tempfn_xxxxxx(const char *p, const char *extra, char **ret); int tempfn_random(const char *p, const char *extra, char **ret); @@ -82,3 +81,8 @@ int write_timestamp_file_atomic(const char *fn, usec_t n); int read_timestamp_file(const char *fn, usec_t *ret); int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space); + +int open_tmpfile_unlinkable(const char *directory, int flags); +int open_tmpfile_linkable(const char *target, int flags, char **ret_path); + +int link_tmpfile(int fd, const char *path, const char *target); diff --git a/src/systemd/src/basic/fs-util.c b/src/systemd/src/basic/fs-util.c index 51268828af..e24e7036f7 100644 --- a/src/systemd/src/basic/fs-util.c +++ b/src/systemd/src/basic/fs-util.c @@ -38,6 +38,7 @@ #include "mkdir.h" #include "parse-util.h" #include "path-util.h" +#include "stdio-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -493,3 +494,17 @@ int get_files_in_directory(const char *path, char ***list) { return n; } + +int inotify_add_watch_fd(int fd, int what, uint32_t mask) { + char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; + int r; + + /* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */ + xsprintf(path, "/proc/self/fd/%i", what); + + r = inotify_add_watch(fd, path, mask); + if (r < 0) + return -errno; + + return r; +} diff --git a/src/systemd/src/basic/fs-util.h b/src/systemd/src/basic/fs-util.h index 0d23f8635f..517b599d6f 100644 --- a/src/systemd/src/basic/fs-util.h +++ b/src/systemd/src/basic/fs-util.h @@ -72,3 +72,5 @@ union inotify_event_buffer { struct inotify_event ev; uint8_t raw[INOTIFY_EVENT_MAX]; }; + +int inotify_add_watch_fd(int fd, int what, uint32_t mask); diff --git a/src/systemd/src/basic/hashmap.c b/src/systemd/src/basic/hashmap.c index 85b8d812b3..49a0479592 100644 --- a/src/systemd/src/basic/hashmap.c +++ b/src/systemd/src/basic/hashmap.c @@ -1773,20 +1773,18 @@ int set_consume(Set *s, void *value) { int set_put_strdup(Set *s, const char *p) { char *c; - int r; assert(s); assert(p); + if (set_contains(s, (char*) p)) + return 0; + c = strdup(p); if (!c) return -ENOMEM; - r = set_consume(s, c); - if (r == -EEXIST) - return 0; - - return r; + return set_consume(s, c); } int set_put_strdupv(Set *s, char **l) { diff --git a/src/systemd/src/basic/io-util.c b/src/systemd/src/basic/io-util.c index 0037a37f2a..cc6dfa8c1b 100644 --- a/src/systemd/src/basic/io-util.c +++ b/src/systemd/src/basic/io-util.c @@ -33,6 +33,11 @@ int flush_fd(int fd) { .events = POLLIN, }; + /* Read from the specified file descriptor, until POLLIN is not set anymore, throwing away everything + * read. Note that some file descriptors (notable IP sockets) will trigger POLLIN even when no data can be read + * (due to IP packet checksum mismatches), hence this function is only safe to be non-blocking if the fd used + * was set to non-blocking too. */ + for (;;) { char buf[LINE_MAX]; ssize_t l; diff --git a/src/systemd/src/basic/parse-util.h b/src/systemd/src/basic/parse-util.h index c407263e16..7dc579a159 100644 --- a/src/systemd/src/basic/parse-util.h +++ b/src/systemd/src/basic/parse-util.h @@ -93,7 +93,7 @@ static inline int safe_atoli(const char *s, long int *ret_u) { #if SIZE_MAX == UINT_MAX static inline int safe_atozu(const char *s, size_t *ret_u) { assert_cc(sizeof(size_t) == sizeof(unsigned)); - return safe_atou(s, ret_u); + return safe_atou(s, (unsigned *) ret_u); } #else static inline int safe_atozu(const char *s, size_t *ret_u) { diff --git a/src/systemd/src/basic/path-util.c b/src/systemd/src/basic/path-util.c index 044a12889d..b2fa81a294 100644 --- a/src/systemd/src/basic/path-util.c +++ b/src/systemd/src/basic/path-util.c @@ -756,34 +756,53 @@ char *file_in_same_dir(const char *path, const char *filename) { return ret; } -bool hidden_file_allow_backup(const char *filename) { - assert(filename); - - return - filename[0] == '.' || - streq(filename, "lost+found") || - streq(filename, "aquota.user") || - streq(filename, "aquota.group") || - endswith(filename, ".rpmnew") || - endswith(filename, ".rpmsave") || - endswith(filename, ".rpmorig") || - endswith(filename, ".dpkg-old") || - endswith(filename, ".dpkg-new") || - endswith(filename, ".dpkg-tmp") || - endswith(filename, ".dpkg-dist") || - endswith(filename, ".dpkg-bak") || - endswith(filename, ".dpkg-backup") || - endswith(filename, ".dpkg-remove") || - endswith(filename, ".swp"); -} +bool hidden_or_backup_file(const char *filename) { + const char *p; -bool hidden_file(const char *filename) { assert(filename); - if (endswith(filename, "~")) + if (filename[0] == '.' || + streq(filename, "lost+found") || + streq(filename, "aquota.user") || + streq(filename, "aquota.group") || + endswith(filename, "~")) return true; - return hidden_file_allow_backup(filename); + p = strrchr(filename, '.'); + if (!p) + return false; + + /* Please, let's not add more entries to the list below. If external projects think it's a good idea to come up + * with always new suffixes and that everybody else should just adjust to that, then it really should be on + * them. Hence, in future, let's not add any more entries. Instead, let's ask those packages to instead adopt + * one of the generic suffixes/prefixes for hidden files or backups, possibly augmented with an additional + * string. Specifically: there's now: + * + * The generic suffixes "~" and ".bak" for backup files + * The generic prefix "." for hidden files + * + * Thus, if a new package manager "foopkg" wants its own set of ".foopkg-new", ".foopkg-old", ".foopkg-dist" + * or so registered, let's refuse that and ask them to use ".foopkg.new", ".foopkg.old" or ".foopkg~" instead. + */ + + return STR_IN_SET(p + 1, + "rpmnew", + "rpmsave", + "rpmorig", + "dpkg-old", + "dpkg-new", + "dpkg-tmp", + "dpkg-dist", + "dpkg-bak", + "dpkg-backup", + "dpkg-remove", + "ucf-new", + "ucf-old", + "ucf-dist", + "swp", + "bak", + "old", + "new"); } bool is_device_path(const char *path) { diff --git a/src/systemd/src/basic/path-util.h b/src/systemd/src/basic/path-util.h index 34d5cd1570..a27c13fcc3 100644 --- a/src/systemd/src/basic/path-util.h +++ b/src/systemd/src/basic/path-util.h @@ -122,7 +122,6 @@ bool path_is_safe(const char *p) _pure_; char *file_in_same_dir(const char *path, const char *filename); -bool hidden_file_allow_backup(const char *filename); -bool hidden_file(const char *filename) _pure_; +bool hidden_or_backup_file(const char *filename) _pure_; bool is_device_path(const char *path); diff --git a/src/systemd/src/basic/socket-util.c b/src/systemd/src/basic/socket-util.c index 0f38f9a0f3..c8769a54f4 100644 --- a/src/systemd/src/basic/socket-util.c +++ b/src/systemd/src/basic/socket-util.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,9 @@ #include "socket-util.h" #include "string-table.h" #include "string-util.h" +#include "strv.h" #include "user-util.h" +#include "utf8.h" #include "util.h" int socket_address_parse(SocketAddress *a, const char *s) { @@ -794,6 +797,42 @@ static const char* const ip_tos_table[] = { DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); +bool ifname_valid(const char *p) { + bool numeric = true; + + /* Checks whether a network interface name is valid. This is inspired by dev_valid_name() in the kernel sources + * but slightly stricter, as we only allow non-control, non-space ASCII characters in the interface name. We + * also don't permit names that only container numbers, to avoid confusion with numeric interface indexes. */ + + if (isempty(p)) + return false; + + if (strlen(p) >= IFNAMSIZ) + return false; + + if (STR_IN_SET(p, ".", "..")) + return false; + + while (*p) { + if ((unsigned char) *p >= 127U) + return false; + + if ((unsigned char) *p <= 32U) + return false; + + if (*p == ':' || *p == '/') + return false; + + numeric = numeric && (*p >= '0' && *p <= '9'); + p++; + } + + if (numeric) + return false; + + return true; +} + int getpeercred(int fd, struct ucred *ucred) { socklen_t n = sizeof(struct ucred); struct ucred u; @@ -970,3 +1009,42 @@ fallback: return (ssize_t) k; } + +int flush_accept(int fd) { + + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN, + }; + int r; + + + /* Similar to flush_fd() but flushes all incoming connection by accepting them and immediately closing them. */ + + for (;;) { + int cfd; + + r = poll(&pollfd, 1, 0); + if (r < 0) { + if (errno == EINTR) + continue; + + return -errno; + + } else if (r == 0) + return 0; + + cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); + if (cfd < 0) { + if (errno == EINTR) + continue; + + if (errno == EAGAIN) + return 0; + + return -errno; + } + + close(cfd); + } +} diff --git a/src/systemd/src/basic/socket-util.h b/src/systemd/src/basic/socket-util.h index d17a2f35f8..e9230e4a9f 100644 --- a/src/systemd/src/basic/socket-util.h +++ b/src/systemd/src/basic/socket-util.h @@ -123,6 +123,8 @@ int fd_inc_rcvbuf(int fd, size_t n); int ip_tos_to_string_alloc(int i, char **s); int ip_tos_from_string(const char *s); +bool ifname_valid(const char *p); + int getpeercred(int fd, struct ucred *ucred); int getpeersec(int fd, char **ret); @@ -135,5 +137,18 @@ int receive_one_fd(int transport_fd, int flags); ssize_t next_datagram_size_fd(int fd); +int flush_accept(int fd); + #define CMSG_FOREACH(cmsg, mh) \ for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg))) + +/* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */ +#define SOCKADDR_UN_LEN(sa) \ + ({ \ + const struct sockaddr_un *_sa = &(sa); \ + assert(_sa->sun_family == AF_UNIX); \ + offsetof(struct sockaddr_un, sun_path) + \ + (_sa->sun_path[0] == 0 ? \ + 1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : \ + strnlen(_sa->sun_path, sizeof(_sa->sun_path))); \ + }) diff --git a/src/systemd/src/basic/time-util.c b/src/systemd/src/basic/time-util.c index 7ca764abeb..edd9179cb8 100644 --- a/src/systemd/src/basic/time-util.c +++ b/src/systemd/src/basic/time-util.c @@ -1080,22 +1080,31 @@ bool timezone_is_valid(const char *name) { return true; } -clockid_t clock_boottime_or_monotonic(void) { - static clockid_t clock = -1; - int fd; - - if (clock != -1) - return clock; - - fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC); - if (fd < 0) - clock = CLOCK_MONOTONIC; - else { - safe_close(fd); - clock = CLOCK_BOOTTIME; +bool clock_boottime_supported(void) { + static int supported = -1; + + /* Note that this checks whether CLOCK_BOOTTIME is available in general as well as available for timerfds()! */ + + if (supported < 0) { + int fd; + + fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC); + if (fd < 0) + supported = false; + else { + safe_close(fd); + supported = true; + } } - return clock; + return supported; +} + +clockid_t clock_boottime_or_monotonic(void) { + if (clock_boottime_supported()) + return CLOCK_BOOTTIME; + else + return CLOCK_MONOTONIC; } int get_timezone(char **tz) { diff --git a/src/systemd/src/basic/time-util.h b/src/systemd/src/basic/time-util.h index 77e3cd08d4..a5e3f567ec 100644 --- a/src/systemd/src/basic/time-util.h +++ b/src/systemd/src/basic/time-util.h @@ -112,6 +112,7 @@ bool ntp_synced(void); int get_timezones(char ***l); bool timezone_is_valid(const char *name); +bool clock_boottime_supported(void); clockid_t clock_boottime_or_monotonic(void); #define xstrftime(buf, fmt, tm) \ diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c index b70c50047f..756c663be4 100644 --- a/src/systemd/src/basic/util.c +++ b/src/systemd/src/basic/util.c @@ -522,7 +522,7 @@ int on_ac_power(void) { if (!de) break; - if (hidden_file(de->d_name)) + if (hidden_or_backup_file(de->d_name)) continue; device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY); diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.c b/src/systemd/src/libsystemd-network/dhcp-identifier.c index 4f7d4d8bf2..a21efc4d06 100644 --- a/src/systemd/src/libsystemd-network/dhcp-identifier.c +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.c @@ -31,6 +31,37 @@ #define SYSTEMD_PEN 43793 #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) +int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { + struct duid d; + + assert_cc(sizeof(d.raw) >= MAX_DUID_LEN); + if (duid_len > MAX_DUID_LEN) + return -EINVAL; + + switch (duid_type) { + case DUID_TYPE_LLT: + if (duid_len <= sizeof(d.llt)) + return -EINVAL; + break; + case DUID_TYPE_EN: + if (duid_len != sizeof(d.en)) + return -EINVAL; + break; + case DUID_TYPE_LL: + if (duid_len <= sizeof(d.ll)) + return -EINVAL; + break; + case DUID_TYPE_UUID: + if (duid_len != sizeof(d.uuid)) + return -EINVAL; + break; + default: + /* accept unknown type in order to be forward compatible */ + break; + } + return 0; +} + int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { sd_id128_t machine_id; uint64_t hash; diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.h b/src/systemd/src/libsystemd-network/dhcp-identifier.h index e6486b78f8..1cc0f9fb71 100644 --- a/src/systemd/src/libsystemd-network/dhcp-identifier.h +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.h @@ -26,7 +26,6 @@ #include "unaligned.h" typedef enum DUIDType { - DUID_TYPE_RAW = 0, DUID_TYPE_LLT = 1, DUID_TYPE_EN = 2, DUID_TYPE_LL = 3, @@ -40,27 +39,28 @@ typedef enum DUIDType { */ #define MAX_DUID_LEN 128 +/* https://tools.ietf.org/html/rfc3315#section-9.1 */ struct duid { be16_t type; union { struct { - /* DHCP6_DUID_LLT */ + /* DUID_TYPE_LLT */ uint16_t htype; uint32_t time; uint8_t haddr[0]; } _packed_ llt; struct { - /* DHCP6_DUID_EN */ + /* DUID_TYPE_EN */ uint32_t pen; uint8_t id[8]; } _packed_ en; struct { - /* DHCP6_DUID_LL */ + /* DUID_TYPE_LL */ int16_t htype; uint8_t haddr[0]; } _packed_ ll; struct { - /* DHCP6_DUID_UUID */ + /* DUID_TYPE_UUID */ sd_id128_t uuid; } _packed_ uuid; struct { @@ -69,36 +69,6 @@ struct duid { }; } _packed_; +int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len); int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len); int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id); - -static inline int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { - struct duid d; - - assert(duid_len > 0); - - switch (duid_type) { - case DUID_TYPE_LLT: - if (duid_len <= sizeof(d.llt)) - return -EINVAL; - break; - case DUID_TYPE_EN: - if (duid_len != sizeof(d.en)) - return -EINVAL; - break; - case DUID_TYPE_LL: - if (duid_len <= sizeof(d.ll)) - return -EINVAL; - break; - case DUID_TYPE_UUID: - if (duid_len != sizeof(d.uuid)) - return -EINVAL; - break; - default: - if (duid_len > sizeof(d.raw)) - return -EINVAL; - /* accept unknown type in order to be forward compatible */ - break; - } - return 0; -} diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index 99b3a1d01f..2badcdff58 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -32,6 +32,7 @@ #include "network-internal.h" #include "parse-util.h" #include "siphash24.h" +#include "socket-util.h" #include "string-util.h" #include "strv.h" #include "utf8.h" @@ -175,58 +176,19 @@ int config_parse_net_condition(const char *unit, return 0; } -int config_parse_ifname(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char **s = data; - _cleanup_free_ char *n = NULL; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - n = strdup(rvalue); - if (!n) - return log_oom(); - - if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue); - return 0; - } - - free(*s); - if (*n) { - *s = n; - n = NULL; - } else - *s = NULL; - - return 0; -} - -int config_parse_ifnames(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_ifnames( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { char ***sv = data; - const char *word, *state; - size_t l; int r; assert(filename); @@ -234,22 +196,27 @@ int config_parse_ifnames(const char *unit, assert(rvalue); assert(data); - FOREACH_WORD(word, l, rvalue, state) { - char *n; + for (;;) { + _cleanup_free_ char *word = NULL; - n = strndup(word, l); - if (!n) - return log_oom(); + r = extract_first_word(&rvalue, &word, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse interface name list: %s", rvalue); + return 0; + } + if (r == 0) + break; - if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue); - free(n); + if (!ifname_valid(word)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue); return 0; } - r = strv_consume(sv, n); + r = strv_push(sv, word); if (r < 0) return log_oom(); + + word = NULL; } return 0; @@ -380,28 +347,28 @@ void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) { int deserialize_in_addrs(struct in_addr **ret, const char *string) { _cleanup_free_ struct in_addr *addresses = NULL; int size = 0; - const char *word, *state; - size_t len; assert(ret); assert(string); - FOREACH_WORD(word, len, string, state) { - _cleanup_free_ char *addr_str = NULL; + for (;;) { + _cleanup_free_ char *word = NULL; struct in_addr *new_addresses; int r; + r = extract_first_word(&string, &word, NULL, 0); + if (r < 0) + return r; + if (r == 0) + break; + new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr)); if (!new_addresses) return -ENOMEM; else addresses = new_addresses; - addr_str = strndup(word, len); - if (!addr_str) - return -ENOMEM; - - r = inet_pton(AF_INET, addr_str, &(addresses[size])); + r = inet_pton(AF_INET, word, &(addresses[size])); if (r <= 0) continue; @@ -431,28 +398,28 @@ void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { _cleanup_free_ struct in6_addr *addresses = NULL; int size = 0; - const char *word, *state; - size_t len; assert(ret); assert(string); - FOREACH_WORD(word, len, string, state) { - _cleanup_free_ char *addr_str = NULL; + for (;;) { + _cleanup_free_ char *word = NULL; struct in6_addr *new_addresses; int r; + r = extract_first_word(&string, &word, NULL, 0); + if (r < 0) + return r; + if (r == 0) + break; + new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr)); if (!new_addresses) return -ENOMEM; else addresses = new_addresses; - addr_str = strndup(word, len); - if (!addr_str) - return -ENOMEM; - - r = inet_pton(AF_INET6, addr_str, &(addresses[size])); + r = inet_pton(AF_INET6, word, &(addresses[size])); if (r <= 0) continue; @@ -493,29 +460,29 @@ void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, siz int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) { _cleanup_free_ struct sd_dhcp_route *routes = NULL; size_t size = 0, allocated = 0; - const char *word, *state; - size_t len; assert(ret); assert(ret_size); assert(ret_allocated); assert(string); - FOREACH_WORD(word, len, string, state) { - /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */ - _cleanup_free_ char* entry = NULL; + /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */ + for (;;) { + _cleanup_free_ char *word = NULL; char *tok, *tok_end; unsigned n; int r; - if (!GREEDY_REALLOC(routes, allocated, size + 1)) - return -ENOMEM; + r = extract_first_word(&string, &word, NULL, 0); + if (r < 0) + return r; + if (r == 0) + break; - entry = strndup(word, len); - if (!entry) + if (!GREEDY_REALLOC(routes, allocated, size + 1)) return -ENOMEM; - tok = entry; + tok = word; /* get the subnet */ tok_end = strchr(tok, '/'); diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h index 72432774d7..5bcd577167 100644 --- a/src/systemd/src/libsystemd-network/network-internal.h +++ b/src/systemd/src/libsystemd-network/network-internal.h @@ -50,10 +50,6 @@ int config_parse_hwaddr(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_ifname(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - int config_parse_ifnames(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index 287b6e26fa..3846cf7476 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -115,14 +115,22 @@ static const uint8_t default_req_opts[] = { SD_DHCP_OPTION_DOMAIN_NAME_SERVER, }; -static int client_receive_message_raw(sd_event_source *s, int fd, - uint32_t revents, void *userdata); -static int client_receive_message_udp(sd_event_source *s, int fd, - uint32_t revents, void *userdata); +static int client_receive_message_raw( + sd_event_source *s, + int fd, + uint32_t revents, + void *userdata); +static int client_receive_message_udp( + sd_event_source *s, + int fd, + uint32_t revents, + void *userdata); static void client_stop(sd_dhcp_client *client, int error); -int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_callback_t cb, - void *userdata) { +int sd_dhcp_client_set_callback( + sd_dhcp_client *client, + sd_dhcp_client_callback_t cb, + void *userdata) { assert_return(client, -EINVAL); client->cb = cb; @@ -171,8 +179,9 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) { return 0; } -int sd_dhcp_client_set_request_address(sd_dhcp_client *client, - const struct in_addr *last_addr) { +int sd_dhcp_client_set_request_address( + sd_dhcp_client *client, + const struct in_addr *last_addr) { assert_return(client, -EINVAL); assert_return (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); @@ -196,8 +205,12 @@ int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) { return 0; } -int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, - size_t addr_len, uint16_t arp_type) { +int sd_dhcp_client_set_mac( + sd_dhcp_client *client, + const uint8_t *addr, + size_t addr_len, + uint16_t arp_type) { + DHCP_CLIENT_DONT_DESTROY(client); bool need_restart = false; @@ -234,8 +247,11 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, return 0; } -int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, - const uint8_t **data, size_t *data_len) { +int sd_dhcp_client_get_client_id( + sd_dhcp_client *client, + uint8_t *type, + const uint8_t **data, + size_t *data_len) { assert_return(client, -EINVAL); assert_return(type, -EINVAL); @@ -254,8 +270,12 @@ int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, return 0; } -int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, - const uint8_t *data, size_t data_len) { +int sd_dhcp_client_set_client_id( + sd_dhcp_client *client, + uint8_t type, + const uint8_t *data, + size_t data_len) { + DHCP_CLIENT_DONT_DESTROY(client); bool need_restart = false; @@ -298,13 +318,32 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, return 0; } -int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid, - uint16_t duid_type, uint8_t *duid, size_t duid_len) { +/** + * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid + * without further modification. Otherwise, if duid_type is supported, DUID + * is set based on that type. Otherwise, an error is returned. + */ +int sd_dhcp_client_set_iaid_duid( + sd_dhcp_client *client, + uint32_t iaid, + uint16_t duid_type, + const void *duid, + size_t duid_len) { + DHCP_CLIENT_DONT_DESTROY(client); int r; + size_t len; + assert_return(client, -EINVAL); - zero(client->client_id); + assert_return(duid_len == 0 || duid != NULL, -EINVAL); + + if (duid != NULL) { + r = dhcp_validate_duid_len(duid_type, duid_len); + if (r < 0) + return r; + } + zero(client->client_id); client->client_id.type = 255; /* If IAID is not configured, generate it. */ @@ -317,22 +356,18 @@ int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid, } else client->client_id.ns.iaid = htobe32(iaid); - /* If DUID is not configured, generate DUID-EN. */ - if (duid_len == 0) { - r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, - &duid_len); - if (r < 0) - return r; - } else { - r = dhcp_validate_duid_len(client->client_id.type, duid_len); - if (r < 0) - return r; + if (duid != NULL) { client->client_id.ns.duid.type = htobe16(duid_type); memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len); - duid_len += sizeof(client->client_id.ns.duid.type); - } + len = sizeof(client->client_id.ns.duid.type) + duid_len; + } else if (duid_type == DUID_TYPE_EN) { + r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len); + if (r < 0) + return r; + } else + return -EOPNOTSUPP; - client->client_id_len = sizeof(client->client_id.type) + duid_len + + client->client_id_len = sizeof(client->client_id.type) + len + sizeof(client->client_id.ns.iaid); if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { @@ -344,8 +379,10 @@ int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid, return 0; } -int sd_dhcp_client_set_hostname(sd_dhcp_client *client, - const char *hostname) { +int sd_dhcp_client_set_hostname( + sd_dhcp_client *client, + const char *hostname) { + char *new_hostname = NULL; assert_return(client, -EINVAL); @@ -368,8 +405,10 @@ int sd_dhcp_client_set_hostname(sd_dhcp_client *client, return 0; } -int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, - const char *vci) { +int sd_dhcp_client_set_vendor_class_identifier( + sd_dhcp_client *client, + const char *vci) { + char *new_vci = NULL; assert_return(client, -EINVAL); @@ -452,8 +491,13 @@ static void client_stop(sd_dhcp_client *client, int error) { client_initialize(client); } -static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, - uint8_t type, size_t *_optlen, size_t *_optoffset) { +static int client_message_init( + sd_dhcp_client *client, + DHCPPacket **ret, + uint8_t type, + size_t *_optlen, + size_t *_optoffset) { + _cleanup_free_ DHCPPacket *packet = NULL; size_t optlen, optoffset, size; be16_t max_size; @@ -594,8 +638,12 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, return 0; } -static int client_append_fqdn_option(DHCPMessage *message, size_t optlen, size_t *optoffset, - const char *fqdn) { +static int client_append_fqdn_option( + DHCPMessage *message, + size_t optlen, + size_t *optoffset, + const char *fqdn) { + uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH]; int r; @@ -612,8 +660,11 @@ static int client_append_fqdn_option(DHCPMessage *message, size_t optlen, size_t return r; } -static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet, - size_t len) { +static int dhcp_client_send_raw( + sd_dhcp_client *client, + DHCPPacket *packet, + size_t len) { + dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT, INADDR_BROADCAST, DHCP_PORT_SERVER, len); @@ -820,8 +871,11 @@ static int client_send_request(sd_dhcp_client *client) { static int client_start(sd_dhcp_client *client); -static int client_timeout_resend(sd_event_source *s, uint64_t usec, - void *userdata) { +static int client_timeout_resend( + sd_event_source *s, + uint64_t usec, + void *userdata) { + sd_dhcp_client *client = userdata; DHCP_CLIENT_DONT_DESTROY(client); usec_t next_timeout = 0; @@ -965,8 +1019,10 @@ error: return 0; } -static int client_initialize_io_events(sd_dhcp_client *client, - sd_event_io_handler_t io_callback) { +static int client_initialize_io_events( + sd_dhcp_client *client, + sd_event_io_handler_t io_callback) { + int r; assert(client); @@ -1033,8 +1089,7 @@ error: } -static int client_initialize_events(sd_dhcp_client *client, - sd_event_io_handler_t io_callback) { +static int client_initialize_events(sd_dhcp_client *client, sd_event_io_handler_t io_callback) { client_initialize_io_events(client, io_callback); client_initialize_time_events(client); @@ -1074,8 +1129,7 @@ static int client_start(sd_dhcp_client *client) { return client_start_delayed(client); } -static int client_timeout_expire(sd_event_source *s, uint64_t usec, - void *userdata) { +static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp_client *client = userdata; DHCP_CLIENT_DONT_DESTROY(client); @@ -1115,8 +1169,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) return client_initialize_events(client, client_receive_message_raw); } -static int client_timeout_t1(sd_event_source *s, uint64_t usec, - void *userdata) { +static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp_client *client = userdata; DHCP_CLIENT_DONT_DESTROY(client); @@ -1126,8 +1179,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, return client_initialize_time_events(client); } -static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, - size_t len) { +static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) { _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; int r; @@ -1178,8 +1230,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, return 0; } -static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, - size_t len) { +static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, size_t len) { int r; r = dhcp_option_parse(force, len, NULL, NULL, NULL); @@ -1191,8 +1242,7 @@ static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, return 0; } -static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, - size_t len) { +static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) { _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; _cleanup_free_ char *error_message = NULL; int r; @@ -1420,8 +1470,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { return 0; } -static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, - int len) { +static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) { DHCP_CLIENT_DONT_DESTROY(client); char time_string[FORMAT_TIMESPAN_MAX]; int r = 0, notify_event = 0; @@ -1567,8 +1616,12 @@ error: return r; } -static int client_receive_message_udp(sd_event_source *s, int fd, - uint32_t revents, void *userdata) { +static int client_receive_message_udp( + sd_event_source *s, + int fd, + uint32_t revents, + void *userdata) { + sd_dhcp_client *client = userdata; _cleanup_free_ DHCPMessage *message = NULL; const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } }; @@ -1645,8 +1698,12 @@ static int client_receive_message_udp(sd_event_source *s, int fd, return client_handle_message(client, message, len); } -static int client_receive_message_raw(sd_event_source *s, int fd, - uint32_t revents, void *userdata) { +static int client_receive_message_raw( + sd_event_source *s, + int fd, + uint32_t revents, + void *userdata) { + sd_dhcp_client *client = userdata; _cleanup_free_ DHCPPacket *packet = NULL; uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))]; diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c index ee4fb4fc1e..4adb053a57 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c @@ -111,7 +111,10 @@ DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int); static int client_start(sd_dhcp6_client *client, enum DHCP6State state); -int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_callback_t cb, void *userdata) { +int sd_dhcp6_client_set_callback( + sd_dhcp6_client *client, + sd_dhcp6_client_callback_t cb, + void *userdata) { assert_return(client, -EINVAL); client->cb = cb; @@ -131,7 +134,10 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) { return 0; } -int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address) { +int sd_dhcp6_client_set_local_address( + sd_dhcp6_client *client, + const struct in6_addr *local_address) { + assert_return(client, -EINVAL); assert_return(local_address, -EINVAL); assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0, -EINVAL); @@ -180,20 +186,38 @@ static int client_ensure_duid(sd_dhcp6_client *client) { return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); } -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t duid_type, - uint8_t *duid, size_t duid_len) { +/** + * Sets DUID. If duid is non-null, the DUID is set to duid_type + duid + * without further modification. Otherwise, if duid_type is supported, DUID + * is set based on that type. Otherwise, an error is returned. + */ +int sd_dhcp6_client_set_duid( + sd_dhcp6_client *client, + uint16_t duid_type, + const void *duid, + size_t duid_len) { + int r; assert_return(client, -EINVAL); + assert_return(duid_len == 0 || duid != NULL, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - if (duid_len > 0) { + if (duid != NULL) { r = dhcp_validate_duid_len(duid_type, duid_len); if (r < 0) return r; + } + + if (duid != NULL) { client->duid.type = htobe16(duid_type); memcpy(&client->duid.raw.data, duid, duid_len); - client->duid_len = duid_len + sizeof(client->duid.type); - } + client->duid_len = sizeof(client->duid.type) + duid_len; + } else if (duid_type == DUID_TYPE_EN) { + r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); + if (r < 0) + return r; + } else + return -EOPNOTSUPP; return 0; } @@ -427,8 +451,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { return 0; } -static int client_timeout_t2(sd_event_source *s, uint64_t usec, - void *userdata) { +static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp6_client *client = userdata; assert_return(s, -EINVAL); @@ -445,8 +468,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, return 0; } -static int client_timeout_t1(sd_event_source *s, uint64_t usec, - void *userdata) { +static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp6_client *client = userdata; assert_return(s, -EINVAL); @@ -463,8 +485,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, return 0; } -static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, - void *userdata) { +static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp6_client *client = userdata; DHCP6_CLIENT_DONT_DESTROY(client); enum DHCP6State state; @@ -490,8 +511,7 @@ static usec_t client_timeout_compute_random(usec_t val) { (random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC; } -static int client_timeout_resend(sd_event_source *s, uint64_t usec, - void *userdata) { +static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userdata) { int r = 0; sd_dhcp6_client *client = userdata; usec_t time_now, init_retransmit_time = 0, max_retransmit_time = 0; @@ -658,9 +678,11 @@ static int client_ensure_iaid(sd_dhcp6_client *client) { return 0; } -static int client_parse_message(sd_dhcp6_client *client, - DHCP6Message *message, size_t len, - sd_dhcp6_lease *lease) { +static int client_parse_message( + sd_dhcp6_client *client, + DHCP6Message *message, + size_t len, + sd_dhcp6_lease *lease) { int r; uint8_t *optval, *option, *id = NULL; uint16_t optcode, status; diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index 79b98c293c..7ba6527f63 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -1072,6 +1072,10 @@ _public_ int sd_event_add_time( assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) && + !clock_boottime_supported()) + return -EOPNOTSUPP; + if (!callback) callback = time_exit_callback; @@ -2527,7 +2531,8 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { } dual_timestamp_get(&e->timestamp); - e->timestamp_boottime = now(clock_boottime_or_monotonic()); + if (clock_boottime_supported()) + e->timestamp_boottime = now(CLOCK_BOOTTIME); for (i = 0; i < m; i++) { @@ -2761,6 +2766,9 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) { CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM), -EOPNOTSUPP); + if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) && !clock_boottime_supported()) + return -EOPNOTSUPP; + if (!dual_timestamp_is_set(&e->timestamp)) { /* Implicitly fall back to now() if we never ran * before and thus have no cached time. */ diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h index 374ff8774e..20b8c2873f 100644 --- a/src/systemd/src/systemd/sd-dhcp-client.h +++ b/src/systemd/src/systemd/sd-dhcp-client.h @@ -84,28 +84,57 @@ enum { typedef struct sd_dhcp_client sd_dhcp_client; -typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, - void *userdata); -int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_callback_t cb, - void *userdata); - -int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option); -int sd_dhcp_client_set_request_address(sd_dhcp_client *client, - const struct in_addr *last_address); -int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast); -int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index); -int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, - size_t addr_len, uint16_t arp_type); -int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, - const uint8_t *data, size_t data_len); -int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid, - uint16_t duid_type, uint8_t *duid, size_t duid_len); -int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, - const uint8_t **data, size_t *data_len); -int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu); -int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname); -int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, const char *vci); -int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret); +typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, void *userdata); +int sd_dhcp_client_set_callback( + sd_dhcp_client *client, + sd_dhcp_client_callback_t cb, + void *userdata); + +int sd_dhcp_client_set_request_option( + sd_dhcp_client *client, + uint8_t option); +int sd_dhcp_client_set_request_address( + sd_dhcp_client *client, + const struct in_addr *last_address); +int sd_dhcp_client_set_request_broadcast( + sd_dhcp_client *client, + int broadcast); +int sd_dhcp_client_set_index( + sd_dhcp_client *client, + int interface_index); +int sd_dhcp_client_set_mac( + sd_dhcp_client *client, + const uint8_t *addr, + size_t addr_len, + uint16_t arp_type); +int sd_dhcp_client_set_client_id( + sd_dhcp_client *client, + uint8_t type, + const uint8_t *data, + size_t data_len); +int sd_dhcp_client_set_iaid_duid( + sd_dhcp_client *client, + uint32_t iaid, + uint16_t duid_type, + const void *duid, + size_t duid_len); +int sd_dhcp_client_get_client_id( + sd_dhcp_client *client, + uint8_t *type, + const uint8_t **data, + size_t *data_len); +int sd_dhcp_client_set_mtu( + sd_dhcp_client *client, + uint32_t mtu); +int sd_dhcp_client_set_hostname( + sd_dhcp_client *client, + const char *hostname); +int sd_dhcp_client_set_vendor_class_identifier( + sd_dhcp_client *client, + const char *vci); +int sd_dhcp_client_get_lease( + sd_dhcp_client *client, + sd_dhcp_lease **ret); int sd_dhcp_client_stop(sd_dhcp_client *client); int sd_dhcp_client_start(sd_dhcp_client *client); @@ -115,7 +144,10 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client); int sd_dhcp_client_new(sd_dhcp_client **ret); -int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority); +int sd_dhcp_client_attach_event( + sd_dhcp_client *client, + sd_event *event, + int64_t priority); int sd_dhcp_client_detach_event(sd_dhcp_client *client); sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client); diff --git a/src/systemd/src/systemd/sd-dhcp6-client.h b/src/systemd/src/systemd/sd-dhcp6-client.h index 4604cb6382..90f62eaca4 100644 --- a/src/systemd/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/src/systemd/sd-dhcp6-client.h @@ -76,29 +76,52 @@ enum { typedef struct sd_dhcp6_client sd_dhcp6_client; -typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event, - void *userdata); -int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, - sd_dhcp6_client_callback_t cb, void *userdata); - -int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); -int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address); -int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, - size_t addr_len, uint16_t arp_type); -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t duid_type, - uint8_t *duid, size_t duid_len); -int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid); -int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled); -int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled); -int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, - uint16_t option); - -int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret); +typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event, void *userdata); +int sd_dhcp6_client_set_callback( + sd_dhcp6_client *client, + sd_dhcp6_client_callback_t cb, + void *userdata); + +int sd_dhcp6_client_set_index( + sd_dhcp6_client *client, + int interface_index); +int sd_dhcp6_client_set_local_address( + sd_dhcp6_client *client, + const struct in6_addr *local_address); +int sd_dhcp6_client_set_mac( + sd_dhcp6_client *client, + const uint8_t *addr, + size_t addr_len, + uint16_t arp_type); +int sd_dhcp6_client_set_duid( + sd_dhcp6_client *client, + uint16_t duid_type, + const void *duid, + size_t duid_len); +int sd_dhcp6_client_set_iaid( + sd_dhcp6_client *client, + uint32_t iaid); +int sd_dhcp6_client_set_information_request( + sd_dhcp6_client *client, + int enabled); +int sd_dhcp6_client_get_information_request( + sd_dhcp6_client *client, + int *enabled); +int sd_dhcp6_client_set_request_option( + sd_dhcp6_client *client, + uint16_t option); + +int sd_dhcp6_client_get_lease( + sd_dhcp6_client *client, + sd_dhcp6_lease **ret); int sd_dhcp6_client_stop(sd_dhcp6_client *client); int sd_dhcp6_client_start(sd_dhcp6_client *client); int sd_dhcp6_client_is_running(sd_dhcp6_client *client); -int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority); +int sd_dhcp6_client_attach_event( + sd_dhcp6_client *client, + sd_event *event, + int64_t priority); int sd_dhcp6_client_detach_event(sd_dhcp6_client *client); sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client); sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client); -- cgit v1.2.1