systemd: update code from upstream (2019-04-11)

This is a direct dump from systemd git.

======

SYSTEMD_DIR=../systemd
COMMIT=03abeb0baf7fe97c98a98d745b75c7d33e2f632e

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

git ls-files -z :/src/systemd/src/ \
                :/shared/systemd/src/ \
                :/shared/nm-utils/unaligned.h | \
  xargs -0 rm -f

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

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

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

nm_copy_sd_core "src/libsystemd-network/arp-util.c"
nm_copy_sd_core "src/libsystemd-network/arp-util.h"
nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.c"
nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.h"
nm_copy_sd_core "src/libsystemd-network/dhcp-internal.h"
nm_copy_sd_core "src/libsystemd-network/dhcp-lease-internal.h"
nm_copy_sd_core "src/libsystemd-network/dhcp-network.c"
nm_copy_sd_core "src/libsystemd-network/dhcp-option.c"
nm_copy_sd_core "src/libsystemd-network/dhcp-packet.c"
nm_copy_sd_core "src/libsystemd-network/dhcp-protocol.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-internal.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-lease-internal.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-network.c"
nm_copy_sd_core "src/libsystemd-network/dhcp6-option.c"
nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.h"
nm_copy_sd_core "src/libsystemd-network/lldp-internal.h"
nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.c"
nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.h"
nm_copy_sd_core "src/libsystemd-network/lldp-network.c"
nm_copy_sd_core "src/libsystemd-network/lldp-network.h"
nm_copy_sd_core "src/libsystemd-network/network-internal.c"
nm_copy_sd_core "src/libsystemd-network/network-internal.h"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp-client.c"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp-lease.c"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-client.c"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-lease.c"
nm_copy_sd_core "src/libsystemd-network/sd-ipv4acd.c"
nm_copy_sd_core "src/libsystemd-network/sd-ipv4ll.c"
nm_copy_sd_core "src/libsystemd-network/sd-lldp.c"
nm_copy_sd_core "src/libsystemd/sd-event/event-source.h"
nm_copy_sd_core "src/libsystemd/sd-event/event-util.c"
nm_copy_sd_core "src/libsystemd/sd-event/event-util.h"
nm_copy_sd_core "src/libsystemd/sd-event/sd-event.c"
nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.c"
nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.h"
nm_copy_sd_core "src/libsystemd/sd-id128/sd-id128.c"
nm_copy_sd_core "src/shared/dns-domain.c"
nm_copy_sd_core "src/shared/dns-domain.h"
nm_copy_sd_core "src/systemd/_sd-common.h"
nm_copy_sd_core "src/systemd/sd-dhcp-client.h"
nm_copy_sd_core "src/systemd/sd-dhcp-lease.h"
nm_copy_sd_core "src/systemd/sd-dhcp6-client.h"
nm_copy_sd_core "src/systemd/sd-dhcp6-lease.h"
nm_copy_sd_core "src/systemd/sd-event.h"
nm_copy_sd_core "src/systemd/sd-id128.h"
nm_copy_sd_core "src/systemd/sd-ipv4acd.h"
nm_copy_sd_core "src/systemd/sd-ipv4ll.h"
nm_copy_sd_core "src/systemd/sd-lldp.h"
nm_copy_sd_core "src/systemd/sd-ndisc.h"
nm_copy_sd_nmutils "src/basic/unaligned.h"
nm_copy_sd_shared "src/basic/alloc-util.c"
nm_copy_sd_shared "src/basic/alloc-util.h"
nm_copy_sd_shared "src/basic/async.h"
nm_copy_sd_shared "src/basic/env-file.c"
nm_copy_sd_shared "src/basic/env-file.h"
nm_copy_sd_shared "src/basic/env-util.c"
nm_copy_sd_shared "src/basic/env-util.h"
nm_copy_sd_shared "src/basic/errno-util.h"
nm_copy_sd_shared "src/basic/escape.c"
nm_copy_sd_shared "src/basic/escape.h"
nm_copy_sd_shared "src/basic/ether-addr-util.c"
nm_copy_sd_shared "src/basic/ether-addr-util.h"
nm_copy_sd_shared "src/basic/extract-word.c"
nm_copy_sd_shared "src/basic/extract-word.h"
nm_copy_sd_shared "src/basic/fd-util.c"
nm_copy_sd_shared "src/basic/fd-util.h"
nm_copy_sd_shared "src/basic/fileio.c"
nm_copy_sd_shared "src/basic/fileio.h"
nm_copy_sd_shared "src/basic/fs-util.c"
nm_copy_sd_shared "src/basic/fs-util.h"
nm_copy_sd_shared "src/basic/hash-funcs.c"
nm_copy_sd_shared "src/basic/hash-funcs.h"
nm_copy_sd_shared "src/basic/hashmap.c"
nm_copy_sd_shared "src/basic/hashmap.h"
nm_copy_sd_shared "src/basic/hexdecoct.c"
nm_copy_sd_shared "src/basic/hexdecoct.h"
nm_copy_sd_shared "src/basic/hostname-util.c"
nm_copy_sd_shared "src/basic/hostname-util.h"
nm_copy_sd_shared "src/basic/in-addr-util.c"
nm_copy_sd_shared "src/basic/in-addr-util.h"
nm_copy_sd_shared "src/basic/io-util.c"
nm_copy_sd_shared "src/basic/io-util.h"
nm_copy_sd_shared "src/basic/list.h"
nm_copy_sd_shared "src/basic/log.h"
nm_copy_sd_shared "src/basic/macro.h"
nm_copy_sd_shared "src/basic/memory-util.c"
nm_copy_sd_shared "src/basic/memory-util.h"
nm_copy_sd_shared "src/basic/mempool.c"
nm_copy_sd_shared "src/basic/mempool.h"
nm_copy_sd_shared "src/basic/missing_fcntl.h"
nm_copy_sd_shared "src/basic/missing_socket.h"
nm_copy_sd_shared "src/basic/missing_stat.h"
nm_copy_sd_shared "src/basic/missing_type.h"
nm_copy_sd_shared "src/basic/parse-util.c"
nm_copy_sd_shared "src/basic/parse-util.h"
nm_copy_sd_shared "src/basic/path-util.c"
nm_copy_sd_shared "src/basic/path-util.h"
nm_copy_sd_shared "src/basic/prioq.c"
nm_copy_sd_shared "src/basic/prioq.h"
nm_copy_sd_shared "src/basic/process-util.c"
nm_copy_sd_shared "src/basic/process-util.h"
nm_copy_sd_shared "src/basic/random-util.c"
nm_copy_sd_shared "src/basic/random-util.h"
nm_copy_sd_shared "src/basic/set.h"
nm_copy_sd_shared "src/basic/signal-util.h"
nm_copy_sd_shared "src/basic/siphash24.h"
nm_copy_sd_shared "src/basic/socket-util.c"
nm_copy_sd_shared "src/basic/socket-util.h"
nm_copy_sd_shared "src/basic/sort-util.h"
nm_copy_sd_shared "src/basic/sparse-endian.h"
nm_copy_sd_shared "src/basic/stat-util.c"
nm_copy_sd_shared "src/basic/stat-util.h"
nm_copy_sd_shared "src/basic/stdio-util.h"
nm_copy_sd_shared "src/basic/string-table.c"
nm_copy_sd_shared "src/basic/string-table.h"
nm_copy_sd_shared "src/basic/string-util.c"
nm_copy_sd_shared "src/basic/string-util.h"
nm_copy_sd_shared "src/basic/strv.c"
nm_copy_sd_shared "src/basic/strv.h"
nm_copy_sd_shared "src/basic/time-util.c"
nm_copy_sd_shared "src/basic/time-util.h"
nm_copy_sd_shared "src/basic/tmpfile-util.c"
nm_copy_sd_shared "src/basic/tmpfile-util.h"
nm_copy_sd_shared "src/basic/umask-util.h"
nm_copy_sd_shared "src/basic/utf8.c"
nm_copy_sd_shared "src/basic/utf8.h"
nm_copy_sd_shared "src/basic/util.c"
nm_copy_sd_shared "src/basic/util.h"
This commit is contained in:
Thomas Haller
2019-04-11 19:01:03 +02:00
parent b603222398
commit 2b1ea1613d
9 changed files with 209 additions and 64 deletions

View File

@@ -32,12 +32,38 @@ static inline int negative_errno(void) {
*
* Hint #2: The kernel sends e.g., EHOSTUNREACH or ENONET to userspace in some ICMP error cases. See the
* icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources */
#define ERRNO_IS_DISCONNECT(r) \
IN_SET(abs(r), \
ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, \
ENETUNREACH, EHOSTUNREACH, ENOPROTOOPT, EHOSTDOWN, \
ENONET, ESHUTDOWN)
static inline bool ERRNO_IS_DISCONNECT(int r) {
return IN_SET(abs(r),
ECONNABORTED,
ECONNREFUSED,
ECONNRESET,
EHOSTDOWN,
EHOSTUNREACH,
ENETDOWN,
ENETRESET,
ENETUNREACH,
ENONET,
ENOPROTOOPT,
ENOTCONN,
EPIPE,
EPROTO,
ESHUTDOWN);
}
/* Transient errors we might get on accept() that we should ignore. As per error handling comment in
* the accept(2) man page. */
static inline bool ERRNO_IS_ACCEPT_AGAIN(int r) {
return ERRNO_IS_DISCONNECT(r) ||
IN_SET(abs(r),
EAGAIN,
EINTR,
EOPNOTSUPP);
}
/* Resource exhaustion, could be our fault or general system trouble */
#define ERRNO_IS_RESOURCE(r) \
IN_SET(abs(r), ENOMEM, EMFILE, ENFILE)
static inline bool ERRNO_IS_RESOURCE(int r) {
return IN_SET(abs(r),
EMFILE,
ENFILE,
ENOMEM);
}

View File

@@ -17,6 +17,7 @@
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "hexdecoct.h"
#include "log.h"
#include "macro.h"
#include "missing.h"
@@ -264,26 +265,29 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
return 1;
}
int read_full_stream(
int read_full_stream_full(
FILE *f,
const char *filename,
ReadFullFileFlags flags,
char **ret_contents,
size_t *ret_size) {
_cleanup_free_ char *buf = NULL;
struct stat st;
size_t n, l;
int fd;
size_t n, n_next, l;
int fd, r;
assert(f);
assert(ret_contents);
assert(!(flags & READ_FULL_FILE_UNBASE64) || ret_size);
n = LINE_MAX; /* Start size */
n_next = LINE_MAX; /* Start size */
fd = fileno(f);
if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen(), let's
* optimize our buffering) */
if (fstat(fileno(f), &st) < 0)
if (fstat(fd, &st) < 0)
return -errno;
if (S_ISREG(st.st_mode)) {
@@ -296,27 +300,44 @@ int read_full_stream(
* size of 0. Note that we increase the size to read here by one, so that the first read attempt
* already makes us notice the EOF. */
if (st.st_size > 0)
n = st.st_size + 1;
n_next = st.st_size + 1;
if (flags & READ_FULL_FILE_SECURE)
(void) warn_file_is_world_accessible(filename, &st, NULL, 0);
}
}
l = 0;
n = l = 0;
for (;;) {
char *t;
size_t k;
t = realloc(buf, n + 1);
if (flags & READ_FULL_FILE_SECURE) {
t = malloc(n_next + 1);
if (!t) {
r = -ENOMEM;
goto finalize;
}
memcpy_safe(t, buf, n);
explicit_bzero_safe(buf, n);
} else {
t = realloc(buf, n_next + 1);
if (!t)
return -ENOMEM;
}
buf = t;
n = n_next;
errno = 0;
k = fread(buf + l, 1, n - l, f);
if (k > 0)
l += k;
if (ferror(f))
return errno > 0 ? -errno : -EIO;
if (ferror(f)) {
r = errno > 0 ? -errno : -EIO;
goto finalize;
}
if (feof(f))
break;
@@ -327,10 +348,18 @@ int read_full_stream(
assert(l == n);
/* Safety check */
if (n >= READ_FULL_BYTES_MAX)
return -E2BIG;
if (n >= READ_FULL_BYTES_MAX) {
r = -E2BIG;
goto finalize;
}
n = MIN(n * 2, READ_FULL_BYTES_MAX);
n_next = MIN(n * 2, READ_FULL_BYTES_MAX);
}
if (flags & READ_FULL_FILE_UNBASE64) {
buf[l++] = 0;
r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, (void **) ret_contents, ret_size);
goto finalize;
}
if (!ret_size) {
@@ -338,8 +367,10 @@ int read_full_stream(
* trailing NUL byte. But if there's an embedded NUL byte, then we should refuse operation as otherwise
* there'd be ambiguity about what we just read. */
if (memchr(buf, 0, l))
return -EBADMSG;
if (memchr(buf, 0, l)) {
r = -EBADMSG;
goto finalize;
}
}
buf[l] = 0;
@@ -349,21 +380,27 @@ int read_full_stream(
*ret_size = l;
return 0;
finalize:
if (flags & READ_FULL_FILE_SECURE)
explicit_bzero_safe(buf, n);
return r;
}
int read_full_file(const char *fn, char **contents, size_t *size) {
int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) {
_cleanup_fclose_ FILE *f = NULL;
assert(fn);
assert(filename);
assert(contents);
f = fopen(fn, "re");
f = fopen(filename, "re");
if (!f)
return -errno;
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
return read_full_stream(f, contents, size);
return read_full_stream_full(f, filename, flags, contents, size);
}
int executable_is_script(const char *path, char **interpreter) {
@@ -818,3 +855,28 @@ int safe_fgetc(FILE *f, char *ret) {
return 1;
}
int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line) {
struct stat _st;
if (!filename)
return 0;
if (!st) {
if (stat(filename, &_st) < 0)
return -errno;
st = &_st;
}
if ((st->st_mode & S_IRWXO) == 0)
return 0;
if (unit)
log_syntax(unit, LOG_WARNING, filename, line, 0,
"%s has %04o mode that is too permissive, please adjust the access mode.",
filename, st->st_mode & 07777);
else
log_warning("%s has %04o mode that is too permissive, please adjust the access mode.",
filename, st->st_mode & 07777);
return 0;
}

View File

@@ -5,6 +5,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "macro.h"
@@ -27,6 +28,11 @@ typedef enum {
} WriteStringFileFlags;
typedef enum {
READ_FULL_FILE_SECURE = 1 << 0,
READ_FULL_FILE_UNBASE64 = 1 << 1,
} ReadFullFileFlags;
int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags, struct timespec *ts);
static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) {
return write_string_stream_ts(f, line, flags, NULL);
@@ -38,9 +44,15 @@ static inline int write_string_file(const char *fn, const char *line, WriteStrin
int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4);
int read_one_line_file(const char *fn, char **line);
int read_full_file(const char *fn, char **contents, size_t *size);
int read_full_stream(FILE *f, char **contents, size_t *size);
int read_one_line_file(const char *filename, char **line);
int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
static inline int read_full_file(const char *filename, char **contents, size_t *size) {
return read_full_file_full(filename, 0, contents, size);
}
int read_full_stream_full(FILE *f, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
static inline int read_full_stream(FILE *f, char **contents, size_t *size) {
return read_full_stream_full(f, NULL, 0, contents, size);
}
int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
@@ -76,3 +88,5 @@ static inline int read_nul_string(FILE *f, size_t limit, char **ret) {
}
int safe_fgetc(FILE *f, char *ret);
int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line);

View File

@@ -685,11 +685,12 @@ static int unbase64_next(const char **p, size_t *l) {
return ret;
}
int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) {
int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_size) {
_cleanup_free_ uint8_t *buf = NULL;
const char *x;
uint8_t *z;
size_t len;
int r;
assert(p || l == 0);
assert(ret);
@@ -712,36 +713,54 @@ int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) {
a = unbase64_next(&x, &l);
if (a == -EPIPE) /* End of string */
break;
if (a < 0)
return a;
if (a == INT_MAX) /* Padding is not allowed at the beginning of a 4ch block */
return -EINVAL;
if (a < 0) {
r = a;
goto on_failure;
}
if (a == INT_MAX) { /* Padding is not allowed at the beginning of a 4ch block */
r = -EINVAL;
goto on_failure;
}
b = unbase64_next(&x, &l);
if (b < 0)
return b;
if (b == INT_MAX) /* Padding is not allowed at the second character of a 4ch block either */
return -EINVAL;
if (b < 0) {
r = b;
goto on_failure;
}
if (b == INT_MAX) { /* Padding is not allowed at the second character of a 4ch block either */
r = -EINVAL;
goto on_failure;
}
c = unbase64_next(&x, &l);
if (c < 0)
return c;
if (c < 0) {
r = c;
goto on_failure;
}
d = unbase64_next(&x, &l);
if (d < 0)
return d;
if (d < 0) {
r = d;
goto on_failure;
}
if (c == INT_MAX) { /* Padding at the third character */
if (d != INT_MAX) /* If the third character is padding, the fourth must be too */
return -EINVAL;
if (d != INT_MAX) { /* If the third character is padding, the fourth must be too */
r = -EINVAL;
goto on_failure;
}
/* b == 00YY0000 */
if (b & 15)
return -EINVAL;
if (b & 15) {
r = -EINVAL;
goto on_failure;
}
if (l > 0) /* Trailing rubbish? */
return -ENAMETOOLONG;
if (l > 0) { /* Trailing rubbish? */
r = -ENAMETOOLONG;
goto on_failure;
}
*(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
break;
@@ -749,11 +768,15 @@ int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) {
if (d == INT_MAX) {
/* c == 00ZZZZ00 */
if (c & 3)
return -EINVAL;
if (c & 3) {
r = -EINVAL;
goto on_failure;
}
if (l > 0) /* Trailing rubbish? */
return -ENAMETOOLONG;
if (l > 0) { /* Trailing rubbish? */
r = -ENAMETOOLONG;
goto on_failure;
}
*(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
*(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
@@ -771,6 +794,12 @@ int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) {
*ret = TAKE_PTR(buf);
return 0;
on_failure:
if (secure)
explicit_bzero_safe(buf, len);
return r;
}
void hexdump(FILE *f, const void *p, size_t s) {

View File

@@ -33,6 +33,9 @@ ssize_t base64mem(const void *p, size_t l, char **out);
int base64_append(char **prefix, int plen,
const void *p, size_t l,
int margin, int width);
int unbase64mem(const char *p, size_t l, void **mem, size_t *len);
int unbase64mem_full(const char *p, size_t l, bool secure, void **mem, size_t *len);
static inline int unbase64mem(const char *p, size_t l, void **mem, size_t *len) {
return unbase64mem_full(p, l, false, mem, len);
}
void hexdump(FILE *f, const void *p, size_t s);

View File

@@ -15,6 +15,7 @@
#include <unistd.h>
#include "alloc-util.h"
#include "errno-util.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
@@ -1237,22 +1238,22 @@ int flush_accept(int fd) {
continue;
return -errno;
} else if (r == 0)
}
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;
if (ERRNO_IS_ACCEPT_AGAIN(errno))
continue;
return -errno;
}
close(cfd);
safe_close(cfd);
}
}

View File

@@ -57,6 +57,16 @@ static inline const char *empty_to_dash(const char *str) {
return isempty(str) ? "-" : str;
}
static inline bool empty_or_dash(const char *str) {
return !str ||
str[0] == 0 ||
(str[0] == '-' && str[1] == 0);
}
static inline const char *empty_or_dash_to_null(const char *p) {
return empty_or_dash(p) ? NULL : p;
}
static inline char *startswith(const char *s, const char *prefix) {
size_t l;

View File

@@ -10,9 +10,6 @@
char *id128_to_uuid_string(sd_id128_t id, char s[37]);
/* Like SD_ID128_FORMAT_STR, but formats as UUID, not in plain format */
#define ID128_UUID_FORMAT_STR "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
bool id128_is_valid(const char *s) _pure_;
typedef enum Id128Format {

View File

@@ -63,6 +63,9 @@ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
#define SD_ID128_FORMAT_STR "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
#define SD_ID128_FORMAT_VAL(x) (x).bytes[0], (x).bytes[1], (x).bytes[2], (x).bytes[3], (x).bytes[4], (x).bytes[5], (x).bytes[6], (x).bytes[7], (x).bytes[8], (x).bytes[9], (x).bytes[10], (x).bytes[11], (x).bytes[12], (x).bytes[13], (x).bytes[14], (x).bytes[15]
/* Like SD_ID128_FORMAT_STR, but formats as UUID, not in plain format */
#define SD_ID128_UUID_FORMAT_STR "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
#define SD_ID128_CONST_STR(x) \
((const char[SD_ID128_STRING_MAX]) { \
((x).bytes[0] >> 4) >= 10 ? 'a' + ((x).bytes[0] >> 4) - 10 : '0' + ((x).bytes[0] >> 4), \