Commit 2e5d35f2 authored by Thomas Haller's avatar Thomas Haller

systemd: update code from upstream (2018-10-04)

This is a direct dump from systemd git.

======

SYSTEMD_DIR=../systemd
COMMIT=b62f9008668a5330c61b4de7e0d48147bcd1edf7

(
  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-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/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"
parent 8aa8d747
......@@ -114,7 +114,7 @@ bool strv_env_is_valid(char **e) {
if (!env_assignment_is_valid(*p))
return false;
/* Check if there are duplicate assginments */
/* Check if there are duplicate assignments */
k = strcspn(*p, "=");
STRV_FOREACH(q, p + 1)
if (strneq(*p, *q, k) && (*q)[k] == '=')
......@@ -388,7 +388,7 @@ int strv_env_replace(char ***l, char *p) {
assert(p);
/* Replace first occurrence of the env var or add a new one in the
* string list. Drop other occurences. Edits in-place. Does not copy p.
* string list. Drop other occurrences. Edits in-place. Does not copy p.
* p must be a valid key=value assignment.
*/
......
......@@ -277,7 +277,7 @@ int same_fd(int a, int b) {
return true;
if (r > 0)
return false;
if (errno != ENOSYS)
if (!IN_SET(errno, ENOSYS, EACCES, EPERM))
return -errno;
/* We don't have kcmp(), use fstat() instead. */
......
......@@ -1492,6 +1492,7 @@ int open_serialization_fd(const char *ident) {
}
int link_tmpfile(int fd, const char *path, const char *target) {
int r;
assert(fd >= 0);
assert(target);
......@@ -1504,8 +1505,9 @@ int link_tmpfile(int fd, const char *path, const char *target) {
* operation currently (renameat2() does), and there is no nice way to emulate this. */
if (path) {
if (rename_noreplace(AT_FDCWD, path, AT_FDCWD, target) < 0)
return -errno;
r = rename_noreplace(AT_FDCWD, path, AT_FDCWD, target);
if (r < 0)
return r;
} else {
char proc_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
......
......@@ -89,41 +89,44 @@ int rmdir_parents(const char *path, const char *stop) {
}
int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
struct stat buf;
int ret;
int r;
ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE);
if (ret >= 0)
/* Try the ideal approach first */
if (renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE) >= 0)
return 0;
/* renameat2() exists since Linux 3.15, btrfs added support for it later.
* If it is not implemented, fallback to another method. */
if (!IN_SET(errno, EINVAL, ENOSYS))
/* renameat2() exists since Linux 3.15, btrfs and FAT added support for it later. If it is not implemented,
* fall back to a different method. */
if (!IN_SET(errno, EINVAL, ENOSYS, ENOTTY))
return -errno;
/* The link()/unlink() fallback does not work on directories. But
* renameat() without RENAME_NOREPLACE gives the same semantics on
* directories, except when newpath is an *empty* directory. This is
* good enough. */
ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW);
if (ret >= 0 && S_ISDIR(buf.st_mode)) {
ret = renameat(olddirfd, oldpath, newdirfd, newpath);
return ret >= 0 ? 0 : -errno;
/* Let's try to use linkat()+unlinkat() as fallback. This doesn't work on directories and on some file systems
* that do not support hard links (such as FAT, most prominently), but for files it's pretty close to what we
* want — though not atomic (i.e. for a short period both the new and the old filename will exist). */
if (linkat(olddirfd, oldpath, newdirfd, newpath, 0) >= 0) {
if (unlinkat(olddirfd, oldpath, 0) < 0) {
r = -errno; /* Backup errno before the following unlinkat() alters it */
(void) unlinkat(newdirfd, newpath, 0);
return r;
}
return 0;
}
/* If it is not a directory, use the link()/unlink() fallback. */
ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0);
if (ret < 0)
if (!IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM)) /* FAT returns EPERM on link()… */
return -errno;
ret = unlinkat(olddirfd, oldpath, 0);
if (ret < 0) {
/* backup errno before the following unlinkat() alters it */
ret = errno;
(void) unlinkat(newdirfd, newpath, 0);
errno = ret;
/* OK, neither RENAME_NOREPLACE nor linkat()+unlinkat() worked. Let's then fallback to the racy TOCTOU
* vulnerable accessat(F_OK) check followed by classic, replacing renameat(), we have nothing better. */
if (faccessat(newdirfd, newpath, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
return -EEXIST;
if (errno != ENOENT)
return -errno;
if (renameat(olddirfd, oldpath, newdirfd, newpath) < 0)
return -errno;
}
return 0;
}
......@@ -346,12 +349,27 @@ int touch(const char *path) {
return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
}
int symlink_idempotent(const char *from, const char *to) {
int symlink_idempotent(const char *from, const char *to, bool make_relative) {
_cleanup_free_ char *relpath = NULL;
int r;
assert(from);
assert(to);
if (make_relative) {
_cleanup_free_ char *parent = NULL;
parent = dirname_malloc(to);
if (!parent)
return -ENOMEM;
r = path_make_relative(parent, from, &relpath);
if (r < 0)
return r;
from = relpath;
}
if (symlink(from, to) < 0) {
_cleanup_free_ char *p = NULL;
......
......@@ -37,7 +37,7 @@ int fd_warn_permissions(const char *path, int fd);
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
int touch(const char *path);
int symlink_idempotent(const char *from, const char *to);
int symlink_idempotent(const char *from, const char *to, bool make_relative);
int symlink_atomic(const char *from, const char *to);
int mknod_atomic(const char *path, mode_t mode, dev_t dev);
......
......@@ -15,7 +15,7 @@
* necessary to instantiate an object for each Hashmap use.
*
* If ENABLE_DEBUG_HASHMAP is defined (by configuring with --enable-debug=hashmap),
* the implemention will:
* the implementation will:
* - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py)
* - perform extra checks for invalid use of iterators
*/
......
......@@ -79,7 +79,7 @@ static int unhex_next(const char **p, size_t *l) {
assert(l);
/* Find the next non-whitespace character, and decode it. We
* greedily skip all preceeding and all following whitespace. */
* greedily skip all preceding and all following whitespace. */
for (;;) {
if (*l == 0)
......@@ -592,8 +592,7 @@ static int base64_append_width(
_cleanup_free_ char *x = NULL;
char *t, *s;
ssize_t slen, len, avail;
int line, lines;
ssize_t len, slen, avail, line, lines;
len = base64mem(p, l, &x);
if (len <= 0)
......@@ -602,6 +601,9 @@ static int base64_append_width(
lines = DIV_ROUND_UP(len, width);
slen = strlen_ptr(sep);
if (lines > (SSIZE_MAX - plen - 1 - slen) / (indent + width + 1))
return -ENOMEM;
t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
if (!t)
return -ENOMEM;
......@@ -647,7 +649,7 @@ static int unbase64_next(const char **p, size_t *l) {
assert(l);
/* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
* greedily skip all preceeding and all following whitespace. */
* greedily skip all preceding and all following whitespace. */
for (;;) {
if (*l == 0)
......
......@@ -464,4 +464,53 @@ static inline int __coverity_check__(int condition) {
func(*p); \
}
#define _DEFINE_TRIVIAL_REF_FUNC(type, name, scope) \
scope type *name##_ref(type *p) { \
if (!p) \
return NULL; \
\
assert(p->n_ref > 0); \
p->n_ref++; \
return p; \
}
#define _DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, scope) \
scope type *name##_unref(type *p) { \
if (!p) \
return NULL; \
\
assert(p->n_ref > 0); \
p->n_ref--; \
if (p->n_ref > 0) \
return NULL; \
\
return free_func(p); \
}
#define DEFINE_TRIVIAL_REF_FUNC(type, name) \
_DEFINE_TRIVIAL_REF_FUNC(type, name,)
#define DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name) \
_DEFINE_TRIVIAL_REF_FUNC(type, name, static)
#define DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name) \
_DEFINE_TRIVIAL_REF_FUNC(type, name, _public_)
#define DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func) \
_DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func,)
#define DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func) \
_DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, static)
#define DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func) \
_DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func, _public_)
#define DEFINE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \
DEFINE_TRIVIAL_REF_FUNC(type, name); \
DEFINE_TRIVIAL_UNREF_FUNC(type, name, free_func);
#define DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \
DEFINE_PRIVATE_TRIVIAL_REF_FUNC(type, name); \
DEFINE_PRIVATE_TRIVIAL_UNREF_FUNC(type, name, free_func);
#define DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(type, name, free_func) \
DEFINE_PUBLIC_TRIVIAL_REF_FUNC(type, name); \
DEFINE_PUBLIC_TRIVIAL_UNREF_FUNC(type, name, free_func);
#include "log.h"
......@@ -570,7 +570,7 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
s = *p;
/* accept any number of digits, strtoull is limted to 19 */
/* accept any number of digits, strtoull is limited to 19 */
for (i=0; i < digits; i++,s++) {
if (*s < '0' || *s > '9') {
if (i == 0)
......
......@@ -425,7 +425,7 @@ int path_compare(const char *a, const char *b) {
assert(a);
assert(b);
/* A relative path and an abolute path must not compare as equal.
/* A relative path and an absolute path must not compare as equal.
* Which one is sorted before the other does not really matter.
* Here a relative path is ordered before an absolute path. */
d = (a[0] == '/') - (b[0] == '/');
......
......@@ -425,7 +425,7 @@ int is_kernel_thread(pid_t pid) {
q += l;
}
/* Skip preceeding whitespace */
/* Skip preceding whitespace */
l = strspn(q, WHITESPACE);
if (l < 1)
return -EINVAL;
......@@ -1104,11 +1104,9 @@ void valgrind_summary_hack(void) {
#endif
}
int pid_compare_func(const void *a, const void *b) {
const pid_t *p = a, *q = b;
int pid_compare_func(const pid_t *a, const pid_t *b) {
/* Suitable for usage in qsort() */
return CMP(*p, *q);
return CMP(*a, *b);
}
int ioprio_parse_priority(const char *s, int *ret) {
......
......@@ -108,7 +108,7 @@ static inline void* PID_TO_PTR(pid_t pid) {
void valgrind_summary_hack(void);
int pid_compare_func(const void *a, const void *b);
int pid_compare_func(const pid_t *a, const pid_t *b);
static inline bool nice_is_valid(int n) {
return n >= PRIO_MIN && n < PRIO_MAX;
......
......@@ -14,3 +14,41 @@ typedef struct {
#define REFCNT_DEC(r) (__sync_sub_and_fetch(&(r)._value, 1))
#define REFCNT_INIT ((RefCount) { ._value = 1 })
#define _DEFINE_ATOMIC_REF_FUNC(type, name, scope) \
scope type *name##_ref(type *p) { \
if (!p) \
return NULL; \
\
assert_se(REFCNT_INC(p->n_ref) >= 2); \
return p; \
}
#define _DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func, scope) \
scope type *name##_unref(type *p) { \
if (!p) \
return NULL; \
\
if (REFCNT_DEC(p->n_ref) > 0) \
return NULL; \
\
return free_func(p); \
}
#define DEFINE_ATOMIC_REF_FUNC(type, name) \
_DEFINE_ATOMIC_REF_FUNC(type, name,)
#define DEFINE_PUBLIC_ATOMIC_REF_FUNC(type, name) \
_DEFINE_ATOMIC_REF_FUNC(type, name, _public_)
#define DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func) \
_DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func,)
#define DEFINE_PUBLIC_ATOMIC_UNREF_FUNC(type, name, free_func) \
_DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func, _public_)
#define DEFINE_ATOMIC_REF_UNREF_FUNC(type, name, free_func) \
DEFINE_ATOMIC_REF_FUNC(type, name); \
DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func);
#define DEFINE_PUBLIC_ATOMIC_REF_UNREF_FUNC(type, name, free_func) \
DEFINE_PUBLIC_ATOMIC_REF_FUNC(type, name); \
DEFINE_PUBLIC_ATOMIC_UNREF_FUNC(type, name, free_func);
......@@ -835,8 +835,8 @@ int fd_inc_sndbuf(int fd, size_t n) {
/* If we have the privileges we will ignore the kernel limit. */
value = (int) n;
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
return -errno;
return 1;
......@@ -853,8 +853,8 @@ int fd_inc_rcvbuf(int fd, size_t n) {
/* If we have the privileges we will ignore the kernel limit. */
value = (int) n;
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
return -errno;
return 1;
}
......
......@@ -20,8 +20,7 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef SPARSE_ENDIAN_H
#define SPARSE_ENDIAN_H
#pragma once
#include <byteswap.h>
#include <endian.h>
......@@ -89,5 +88,3 @@ static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t _
#undef __sd_bitwise
#undef __sd_force
#endif /* SPARSE_ENDIAN_H */
......@@ -58,7 +58,7 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
}
#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,scope) \
type name##_from_string(const char *s) { \
scope type name##_from_string(const char *s) { \
type i; \
unsigned u = 0; \
if (!s) \
......
......@@ -1004,7 +1004,7 @@ int free_and_strdup(char **p, const char *s) {
assert(p);
/* Replaces a string pointer with an strdup()ed new string,
/* Replaces a string pointer with a strdup()ed new string,
* possibly freeing the old one. */
if (streq_ptr(*p, s))
......@@ -1023,6 +1023,32 @@ int free_and_strdup(char **p, const char *s) {
return 1;
}
int free_and_strndup(char **p, const char *s, size_t l) {
char *t;
assert(p);
assert(s || l == 0);
/* Replaces a string pointer with a strndup()ed new string,
* freeing the old one. */
if (!*p && !s)
return 0;
if (*p && s && strneq(*p, s, l) && (l > strlen(*p) || (*p)[l] == '\0'))
return 0;
if (s) {
t = strndup(s, l);
if (!t)
return -ENOMEM;
} else
t = NULL;
free_and_replace(*p, t);
return 1;
}
#if !HAVE_EXPLICIT_BZERO
/*
* Pointer to memset is volatile so that compiler must de-reference
......
......@@ -176,6 +176,7 @@ char *strrep(const char *s, unsigned n);
int split_pair(const char *s, const char *sep, char **l, char **r);
int free_and_strdup(char **p, const char *s);
int free_and_strndup(char **p, const char *s, size_t l);
/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
......@@ -228,3 +229,25 @@ static inline void *memory_startswith(const void *p, size_t sz, const char *toke
return (uint8_t*) p + n;
}
/* Like startswith_no_case(), but operates on arbitrary memory blocks.
* It works only for ASCII strings.
*/
static inline void *memory_startswith_no_case(const void *p, size_t sz, const char *token) {
size_t n, i;
assert(token);
n = strlen(token);
if (sz < n)
return NULL;
assert(p);
for (i = 0; i < n; i++) {
if (ascii_tolower(((char *)p)[i]) != ascii_tolower(token[i]))
return NULL;
}
return (uint8_t*) p + n;
}
......@@ -339,21 +339,22 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract
return (int) n;
}
char *strv_join(char **l, const char *separator) {
char *strv_join_prefix(char **l, const char *separator, const char *prefix) {
char *r, *e;
char **s;
size_t n, k;
size_t n, k, m;
if (!separator)
separator = " ";
k = strlen(separator);
m = strlen_ptr(prefix);
n = 0;
STRV_FOREACH(s, l) {
if (s != l)
n += k;
n += strlen(*s);
n += m + strlen(*s);
}
r = new(char, n+1);
......@@ -365,6 +366,9 @@ char *strv_join(char **l, const char *separator) {
if (s != l)
e = stpcpy(e, separator);
if (prefix)
e = stpcpy(e, prefix);
e = stpcpy(e, *s);
}
......@@ -711,14 +715,12 @@ bool strv_overlap(char **a, char **b) {
return false;
}
static int str_compare(const void *_a, const void *_b) {
const char **a = (const char**) _a, **b = (const char**) _b;
static int str_compare(char * const *a, char * const *b) {
return strcmp(*a, *b);
}
char **strv_sort(char **l) {
qsort_safe(l, strv_length(l), sizeof(char*), str_compare);
typesafe_qsort(l, strv_length(l), str_compare);
return l;
}
......
......@@ -71,7 +71,10 @@ char **strv_split_newlines(const char *s);
int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags);
char *strv_join(char **l, const char *separator);
char *strv_join_prefix(char **l, const char *separator, const char *prefix);
static inline char *strv_join(char **l, const char *separator) {
return strv_join_prefix(l, separator, NULL);
}
char **strv_parse_nulstr(const char *s, size_t l);
char **strv_split_nulstr(const char *s);
......
......@@ -905,7 +905,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
* Otherwise just cut it off. */
with_tz = !STR_IN_SET(tz, tzname[0], tzname[1]);
/* Cut off the timezone if we dont need it. */
/* Cut off the timezone if we don't need it. */
if (with_tz)
t = strndupa(t, last_space - t);
......
......@@ -61,12 +61,12 @@ static bool unichar_is_control(char32_t ch) {
}
/* count of characters used to encode one unicode char */
static int utf8_encoded_expected_len(const char *str) {
unsigned char c;
static size_t utf8_encoded_expected_len(const char *str) {
uint8_t c;
assert(str);
c = (unsigned char) str[0];
c = (uint8_t) str[0];
if (c < 0x80)
return 1;
if ((c & 0xe0) == 0xc0)
......@@ -86,7 +86,7 @@ static int utf8_encoded_expected_len(const char *str) {
/* decode one unicode char */
int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
char32_t unichar;
int len, i;
size_t len, i;
assert(str);
......@@ -118,6 +118,7 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
for (i = 1; i < len; i++) {
if (((char32_t)str[i] & 0xc0) != 0x80)
return -EINVAL;
unichar <<= 6;
unichar |= (char32_t)str[i] & 0x3f;
}
......@@ -154,22 +155,23 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
return true;
}
const char *utf8_is_valid(const char *str) {
const uint8_t *p;
char *utf8_is_valid(const char *str) {
const char *p;
assert(str);
for (p = (const uint8_t*) str; *p; ) {
p = str;
while (*p) {
int len;
len = utf8_encoded_valid_unichar((const char *)p);
len = utf8_encoded_valid_unichar(p);
if (len < 0)
return NULL;
p += len;
}
return str;
return (char*) str;
}
char *utf8_escape_invalid(const char *str) {
......@@ -312,18 +314,25 @@ size_t utf8_encode_unichar(char *out_utf8, char32_t g) {
return 0;
}
char *utf16_to_utf8(const void *s, size_t length) {
char *utf16_to_utf8(const char16_t *s, size_t length /* bytes! */) {
const uint8_t *f;
char *r, *t;
r = new(char, (length * 4 + 1) / 2 + 1);
assert(s);
/* Input length is in bytes, i.e. the shortest possible character takes 2 bytes. Each unicode character may
* take up to 4 bytes in UTF-8. Let's also account for a trailing NUL byte. */
if (length * 2 < length)
return NULL; /* overflow */
r = new(char, length * 2 + 1);
if (!r)
return NULL;
f = s;
f = (const uint8_t*) s;
t = r;
while (f < (const uint8_t*) s + length) {
while (f + 1 < (const uint8_t*) s + length) {
char16_t w1, w2;
/* see RFC 2781 section 2.2 */
......@@ -333,13 +342,13 @@ char *utf16_to_utf8(const void *s, size_t length) {
if (!utf16_is_surrogate(w1)) {
t += utf8_encode_unichar(t, w1);
continue;
}
if (utf16_is_trailing_surrogate(w1))
continue;
else if (f >= (const uint8_t*) s + length)
continue; /* spurious trailing surrogate, ignore */
if (f + 1 >= (const uint8_t*) s + length)
break;
w2 = f[1] << 8 | f[0];
......@@ -347,7 +356,7 @@ char *utf16_to_utf8(const void *s, size_t length) {
if (!utf16_is_trailing_surrogate(w2)) {
f -= 2;
continue;
continue; /* surrogate missing its trailing surrogate, ignore */
}
t += utf8_encode_unichar(t, utf16_surrogate_pair_to_unichar(w1, w2));
......@@ -357,6 +366,79 @@ char *utf16_to_utf8(const void *s, size_t length) {
return r;
}
size_t utf16_encode_unichar(char16_t *out, char32_t c) {
/* Note that this encodes as little-endian. */
switch (c) {
case 0 ... 0xd7ffU:
case 0xe000U ... 0xffffU:
out[0] = htole16(c);
return 1;
case 0x10000U ... 0x10ffffU:
c -= 0x10000U;
out[0] = htole16((c >> 10) + 0xd800U);
out[1] = htole16((c & 0x3ffU) + 0xdc00U);
return 2;
default: /* A surrogate (invalid) */