Shorten format-table code and fix potential memleak (#40917)

This commit is contained in:
Yu Watanabe
2026-03-09 09:26:30 +09:00
committed by GitHub
14 changed files with 273 additions and 492 deletions
+3 -3
View File
@@ -754,9 +754,9 @@ SPDX-License-Identifier: LGPL-2.1-or-later
section of the `alloca(3)` man page.
- If you want to concatenate two or more strings, consider using `strjoina()`
or `strjoin()` rather than `asprintf()`, as the latter is a lot slower. This
matters particularly in inner loops (but note that `strjoina()` cannot be
used there).
or `strjoin()` rather than `asprintf()` or `asprintf_safe`, as the latter is
a lot slower. This matters particularly in inner loops (but note that
`strjoina()` cannot be used there).
## Runtime Behaviour
+42 -15
View File
@@ -34,6 +34,44 @@ void* memdup_suffix0(const void *p, size_t l) {
return memcpy_safe(ret, p, l);
}
size_t malloc_sizeof_safe(void **xp) {
if (_unlikely_(!xp || !*xp))
return 0;
size_t sz = malloc_usable_size(*xp);
*xp = expand_to_usable(*xp, sz);
/* GCC doesn't see the _returns_nonnull_ when built with ubsan, so yet another hint to make it doubly
* clear that expand_to_usable won't return NULL.
* See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79265 */
if (!*xp)
assert_not_reached();
return sz;
}
void* expand_to_usable(void *ptr, size_t newsize _unused_) {
return ptr;
}
void* realloc0(void *p, size_t new_size) {
size_t old_size;
void *q;
/* Like realloc(), but initializes anything appended to zero */
old_size = MALLOC_SIZEOF_SAFE(p);
q = realloc(p, new_size);
if (!q)
return NULL;
new_size = MALLOC_SIZEOF_SAFE(q); /* Update with actually allocated space */
if (new_size > old_size)
memset((uint8_t*) q + old_size, 0, new_size - old_size);
return q;
}
void* greedy_realloc(
void **p,
size_t need,
@@ -125,20 +163,9 @@ void* greedy_realloc_append(
return q;
}
void *expand_to_usable(void *ptr, size_t newsize _unused_) {
return ptr;
}
void free_many(void **p, size_t n) {
assert(p || n == 0);
size_t malloc_sizeof_safe(void **xp) {
if (_unlikely_(!xp || !*xp))
return 0;
size_t sz = malloc_usable_size(*xp);
*xp = expand_to_usable(*xp, sz);
/* GCC doesn't see the _returns_nonnull_ when built with ubsan, so yet another hint to make it doubly
* clear that expand_to_usable won't return NULL.
* See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79265 */
if (!*xp)
assert_not_reached();
return sz;
FOREACH_ARRAY(i, p, n)
*i = mfree(*i);
}
+29 -52
View File
@@ -108,6 +108,34 @@ static inline void *memdup_suffix0_multiply(const void *p, size_t need, size_t s
return memdup_suffix0(p, size * need);
}
size_t malloc_sizeof_safe(void **xp);
/* This returns the number of usable bytes in a malloc()ed region as per malloc_usable_size(), which may
* return a value larger than the size that was actually allocated. Access to that additional memory is
* discouraged because it violates the C standard; a compiler cannot see that this as valid. To help the
* compiler out, the MALLOC_SIZEOF_SAFE macro 'allocates' the usable size using a dummy allocator function
* expand_to_usable. There is a possibility of malloc_usable_size() returning different values during the
* lifetime of an object, which may cause problems, but the glibc allocator does not do that at the moment. */
#define MALLOC_SIZEOF_SAFE(x) \
malloc_sizeof_safe((void**) &__builtin_choose_expr(__builtin_constant_p(x), (void*) { NULL }, (x)))
/* Inspired by ELEMENTSOF() but operates on malloc()'ed memory areas: typesafely returns the number of items
* that fit into the specified memory block */
#define MALLOC_ELEMENTSOF(x) \
(__builtin_choose_expr( \
__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
MALLOC_SIZEOF_SAFE(x)/sizeof((x)[0]), \
VOID_0))
/* Dummy allocator to tell the compiler that the new size of p is newsize. The implementation returns the
* pointer as is; the only reason for its existence is as a conduit for the _alloc_ attribute. This must not
* be inlined (hence a non-static function with _noinline_ because LTO otherwise tries to inline it) because
* gcc then loses the attributes on the function.
* See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 */
void *expand_to_usable(void *p, size_t newsize) _alloc_(2) _returns_nonnull_ _noinline_;
void* realloc0(void *p, size_t new_size) _alloc_(2);
static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) {
size_t m;
@@ -179,61 +207,10 @@ void* greedy_realloc_append(void **p, size_t *n_p, const void *from, size_t n_fr
# define msan_unpoison(r, s)
#endif
/* Dummy allocator to tell the compiler that the new size of p is newsize. The implementation returns the
* pointer as is; the only reason for its existence is as a conduit for the _alloc_ attribute. This must not
* be inlined (hence a non-static function with _noinline_ because LTO otherwise tries to inline it) because
* gcc then loses the attributes on the function.
* See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 */
void *expand_to_usable(void *p, size_t newsize) _alloc_(2) _returns_nonnull_ _noinline_;
size_t malloc_sizeof_safe(void **xp);
/* This returns the number of usable bytes in a malloc()ed region as per malloc_usable_size(), which may
* return a value larger than the size that was actually allocated. Access to that additional memory is
* discouraged because it violates the C standard; a compiler cannot see that this as valid. To help the
* compiler out, the MALLOC_SIZEOF_SAFE macro 'allocates' the usable size using a dummy allocator function
* expand_to_usable. There is a possibility of malloc_usable_size() returning different values during the
* lifetime of an object, which may cause problems, but the glibc allocator does not do that at the moment. */
#define MALLOC_SIZEOF_SAFE(x) \
malloc_sizeof_safe((void**) &__builtin_choose_expr(__builtin_constant_p(x), (void*) { NULL }, (x)))
/* Inspired by ELEMENTSOF() but operates on malloc()'ed memory areas: typesafely returns the number of items
* that fit into the specified memory block */
#define MALLOC_ELEMENTSOF(x) \
(__builtin_choose_expr( \
__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
MALLOC_SIZEOF_SAFE(x)/sizeof((x)[0]), \
VOID_0))
/* Free every element of the array. */
static inline void free_many(void **p, size_t n) {
assert(p || n == 0);
FOREACH_ARRAY(i, p, n)
*i = mfree(*i);
}
void free_many(void **p, size_t n);
/* Typesafe wrapper for char** rather than void**. Unfortunately C won't implicitly cast this. */
static inline void free_many_charp(char **c, size_t n) {
free_many((void**) c, n);
}
_alloc_(2) static inline void *realloc0(void *p, size_t new_size) {
size_t old_size;
void *q;
/* Like realloc(), but initializes anything appended to zero */
old_size = MALLOC_SIZEOF_SAFE(p);
q = realloc(p, new_size);
if (!q)
return NULL;
new_size = MALLOC_SIZEOF_SAFE(q); /* Update with actually allocated space */
if (new_size > old_size)
memset((uint8_t*) q + old_size, 0, new_size - old_size);
return q;
}
+6 -8
View File
@@ -559,20 +559,18 @@ int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u
if (port > 0) {
if (family == AF_INET6) {
if (ifindex > 0)
r = asprintf(&x, "[%s]:%"PRIu16"%%%i%s%s", ip_str, port, ifindex, separator, server_name);
x = asprintf_safe("[%s]:%"PRIu16"%%%i%s%s", ip_str, port, ifindex, separator, server_name);
else
r = asprintf(&x, "[%s]:%"PRIu16"%s%s", ip_str, port, separator, server_name);
x = asprintf_safe("[%s]:%"PRIu16"%s%s", ip_str, port, separator, server_name);
} else
r = asprintf(&x, "%s:%"PRIu16"%s%s", ip_str, port, separator, server_name);
x = asprintf_safe("%s:%"PRIu16"%s%s", ip_str, port, separator, server_name);
} else {
if (ifindex > 0)
r = asprintf(&x, "%s%%%i%s%s", ip_str, ifindex, separator, server_name);
else {
x = asprintf_safe("%s%%%i%s%s", ip_str, ifindex, separator, server_name);
else
x = strjoin(ip_str, separator, server_name);
r = x ? 0 : -ENOMEM;
}
}
if (r < 0)
if (!x)
return -ENOMEM;
*ret = TAKE_PTR(x);
+1
View File
@@ -99,6 +99,7 @@ basic_sources = files(
'sort-util.c',
'stat-util.c',
'static-destruct.c',
'stdio-util.c',
'strbuf.c',
'string-table.c',
'string-util.c',
+8 -9
View File
@@ -289,26 +289,25 @@ int rlimit_parse(int resource, const char *val, struct rlimit *ret) {
}
int rlimit_format(const struct rlimit *rl, char **ret) {
_cleanup_free_ char *s = NULL;
int r;
char *s;
assert(rl);
assert(ret);
if (rl->rlim_cur >= RLIM_INFINITY && rl->rlim_max >= RLIM_INFINITY)
r = free_and_strdup(&s, "infinity");
s = strdup("infinity");
else if (rl->rlim_cur >= RLIM_INFINITY)
r = asprintf(&s, "infinity:" RLIM_FMT, rl->rlim_max);
s = asprintf_safe("infinity:" RLIM_FMT, rl->rlim_max);
else if (rl->rlim_max >= RLIM_INFINITY)
r = asprintf(&s, RLIM_FMT ":infinity", rl->rlim_cur);
s = asprintf_safe(RLIM_FMT ":infinity", rl->rlim_cur);
else if (rl->rlim_cur == rl->rlim_max)
r = asprintf(&s, RLIM_FMT, rl->rlim_cur);
s = asprintf_safe(RLIM_FMT, rl->rlim_cur);
else
r = asprintf(&s, RLIM_FMT ":" RLIM_FMT, rl->rlim_cur, rl->rlim_max);
if (r < 0)
s = asprintf_safe(RLIM_FMT ":" RLIM_FMT, rl->rlim_cur, rl->rlim_max);
if (!s)
return -ENOMEM;
*ret = TAKE_PTR(s);
*ret = s;
return 0;
}
+18
View File
@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
#include "stdio-util.h"
char* asprintf_safe(const char *restrict fmt, ...) {
_cleanup_free_ char *buf = NULL;
va_list ap;
int r;
va_start(ap, fmt);
r = vasprintf(&buf, fmt, ap);
va_end(ap);
if (r < 0)
return NULL;
return TAKE_PTR(buf);
}
+2
View File
@@ -21,6 +21,8 @@ static inline char* snprintf_ok(char *buf, size_t len, const char *format, ...)
#define xsprintf(buf, fmt, ...) \
assert_message_se(snprintf_ok(buf, ELEMENTSOF(buf), fmt, ##__VA_ARGS__), "xsprintf: buffer too small")
char* asprintf_safe(const char *restrict fmt, ...) _printf_(1, 2);
#define VA_FORMAT_ADVANCE(format, ap) \
do { \
int _argtypes[128]; \
+5 -4
View File
@@ -3,6 +3,7 @@
#include <stdio.h>
#include "parse-util.h"
#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
@@ -43,11 +44,11 @@ int string_table_lookup_to_string_fallback(const char * const *table, size_t len
if (i < 0 || i > (ssize_t) max)
return -ERANGE;
if (i < (ssize_t) len && table[i]) {
if (i < (ssize_t) len && table[i])
s = strdup(table[i]);
if (!s)
return -ENOMEM;
} else if (asprintf(&s, "%zd", i) < 0)
else
s = asprintf_safe("%zd", i);
if (!s)
return -ENOMEM;
*ret = s;
+8 -9
View File
@@ -15,6 +15,7 @@
#include "parse-util.h"
#include "path-util.h"
#include "pretty-print.h"
#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "sync-util.h"
@@ -299,7 +300,7 @@ static int make_good(const char *prefix, const char *suffix, char **ret) {
}
static int make_bad(const char *prefix, uint64_t done, const char *suffix, char **ret) {
_cleanup_free_ char *bad = NULL;
char *bad;
assert(prefix);
assert(suffix);
@@ -308,16 +309,14 @@ static int make_bad(const char *prefix, uint64_t done, const char *suffix, char
/* Generate the path we'd use on bad boots. Let's simply set the 'left' counter to zero, and keep the 'done'
* counter. The information might be interesting to boot loaders, after all. */
if (done == 0) {
if (done == 0)
bad = strjoin(prefix, "+0", suffix);
if (!bad)
return -ENOMEM;
} else {
if (asprintf(&bad, "%s+0-%" PRIu64 "%s", prefix, done, suffix) < 0)
return -ENOMEM;
}
else
bad = asprintf_safe("%s+0-%" PRIu64 "%s", prefix, done, suffix);
if (!bad)
return -ENOMEM;
*ret = TAKE_PTR(bad);
*ret = bad;
return 0;
}
+5 -7
View File
@@ -1930,14 +1930,12 @@ char** exec_context_get_syscall_filter(const ExecContext *c) {
if (num >= 0) {
e = seccomp_errno_or_action_to_string(num);
if (e) {
if (e)
s = strjoin(name, ":", e);
if (!s)
return NULL;
} else {
if (asprintf(&s, "%s:%d", name, num) < 0)
return NULL;
}
else
s = asprintf_safe("%s:%d", name, num);
if (!s)
return NULL;
} else
s = TAKE_PTR(name);
+43 -53
View File
@@ -882,16 +882,14 @@ static int instance_from_socket(
a = be32toh(local.in.sin_addr.s_addr),
b = be32toh(remote.in.sin_addr.s_addr);
if (asprintf(&s,
"%u-%" PRIu64 "-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
nr,
cookie,
a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
be16toh(local.in.sin_port),
b >> 24, (b >> 16) & 0xFF, (b >> 8) & 0xFF, b & 0xFF,
be16toh(remote.in.sin_port)) < 0)
return -ENOMEM;
s = asprintf_safe(
"%u-%" PRIu64 "-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
nr,
cookie,
a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
be16toh(local.in.sin_port),
b >> 24, (b >> 16) & 0xFF, (b >> 8) & 0xFF, b & 0xFF,
be16toh(remote.in.sin_port));
break;
}
@@ -906,27 +904,23 @@ static int instance_from_socket(
*a = local.in6.sin6_addr.s6_addr+12,
*b = remote.in6.sin6_addr.s6_addr+12;
if (asprintf(&s,
"%u-%" PRIu64 "-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
nr,
cookie,
a[0], a[1], a[2], a[3],
be16toh(local.in6.sin6_port),
b[0], b[1], b[2], b[3],
be16toh(remote.in6.sin6_port)) < 0)
return -ENOMEM;
} else {
if (asprintf(&s,
"%u-%" PRIu64 "-%s:%u-%s:%u",
nr,
cookie,
IN6_ADDR_TO_STRING(&local.in6.sin6_addr),
be16toh(local.in6.sin6_port),
IN6_ADDR_TO_STRING(&remote.in6.sin6_addr),
be16toh(remote.in6.sin6_port)) < 0)
return -ENOMEM;
}
s = asprintf_safe(
"%u-%" PRIu64 "-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
nr,
cookie,
a[0], a[1], a[2], a[3],
be16toh(local.in6.sin6_port),
b[0], b[1], b[2], b[3],
be16toh(remote.in6.sin6_port));
} else
s = asprintf_safe(
"%u-%" PRIu64 "-%s:%u-%s:%u",
nr,
cookie,
IN6_ADDR_TO_STRING(&local.in6.sin6_addr),
be16toh(local.in6.sin6_port),
IN6_ADDR_TO_STRING(&remote.in6.sin6_addr),
be16toh(remote.in6.sin6_port));
break;
}
@@ -939,42 +933,38 @@ static int instance_from_socket(
uint64_t pidfd_id;
if (pidfd >= 0 && pidfd_get_inode_id(pidfd, &pidfd_id) >= 0)
r = asprintf(&s, "%u-%" PRIu64 "-" PID_FMT "_%" PRIu64 "-" UID_FMT,
nr, cookie, ucred.pid, pidfd_id, ucred.uid);
s = asprintf_safe(
"%u-%" PRIu64 "-" PID_FMT "_%" PRIu64 "-" UID_FMT,
nr, cookie, ucred.pid, pidfd_id, ucred.uid);
else
r = asprintf(&s, "%u-%" PRIu64 "-" PID_FMT "-" UID_FMT,
nr, cookie, ucred.pid, ucred.uid);
if (r < 0)
return -ENOMEM;
} else if (r == -ENODATA) {
s = asprintf_safe(
"%u-%" PRIu64 "-" PID_FMT "-" UID_FMT,
nr, cookie, ucred.pid, ucred.uid);
} else if (r == -ENODATA)
/* This handles the case where somebody is connecting from another pid/uid namespace
* (e.g. from outside of our container). */
if (asprintf(&s,
"%u-%" PRIu64 "-unknown",
nr,
cookie) < 0)
return -ENOMEM;
} else
s = asprintf_safe("%u-%" PRIu64 "-unknown", nr, cookie);
else
return r;
break;
}
case AF_VSOCK:
if (asprintf(&s,
"%u-%" PRIu64 "-%u:%u-%u:%u",
nr,
cookie,
local.vm.svm_cid, local.vm.svm_port,
remote.vm.svm_cid, remote.vm.svm_port) < 0)
return -ENOMEM;
s = asprintf_safe(
"%u-%" PRIu64 "-%u:%u-%u:%u",
nr,
cookie,
local.vm.svm_cid, local.vm.svm_port,
remote.vm.svm_cid, remote.vm.svm_port);
break;
default:
assert_not_reached();
}
if (!s)
return -ENOMEM;
*ret = s;
return 0;
}
+96 -325
View File
@@ -159,7 +159,7 @@ struct Table {
bool *reverse_map;
};
Table *table_new_raw(size_t n_columns) {
Table* table_new_raw(size_t n_columns) {
_cleanup_(table_unrefp) Table *t = NULL;
assert(n_columns > 0);
@@ -179,7 +179,7 @@ Table *table_new_raw(size_t n_columns) {
return TAKE_PTR(t);
}
Table *table_new_internal(const char *first_header, ...) {
Table* table_new_internal(const char *first_header, ...) {
_cleanup_(table_unrefp) Table *t = NULL;
size_t n_columns = 1;
va_list ap;
@@ -216,7 +216,7 @@ Table *table_new_internal(const char *first_header, ...) {
return TAKE_PTR(t);
}
Table *table_new_vertical(void) {
Table* table_new_vertical(void) {
_cleanup_(table_unrefp) Table *t = NULL;
TableCell *cell;
@@ -242,7 +242,7 @@ Table *table_new_vertical(void) {
return TAKE_PTR(t);
}
static TableData *table_data_free(TableData *d) {
static TableData* table_data_free(TableData *d) {
assert(d);
free(d->formatted);
@@ -260,7 +260,7 @@ static TableData *table_data_free(TableData *d) {
DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(TableData, table_data, table_data_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(TableData*, table_data_unref);
Table *table_unref(Table *t) {
Table* table_unref(Table *t) {
if (!t)
return NULL;
@@ -425,7 +425,7 @@ static bool table_data_matches(
return memcmp_safe(data, d->data, l) == 0;
}
static TableData *table_data_new(
static TableData* table_data_new(
TableDataType type,
const void *data,
size_t minimum_width,
@@ -1602,7 +1602,7 @@ static char* format_strv_width(char **strv, size_t column_width) {
return buf;
}
static const char *table_data_format(
static const char* table_data_format(
Table *t,
TableData *d,
bool avoid_uppercasing,
@@ -1616,6 +1616,8 @@ static const char *table_data_format(
(d->type != TABLE_STRV_WRAPPED || d->formatted_for_width == column_width))
return d->formatted;
d->formatted = mfree(d->formatted);
switch (d->type) {
case TABLE_EMPTY:
return table_ersatz_string(t);
@@ -1649,18 +1651,13 @@ static const char *table_data_format(
*q = 0;
return d->formatted;
} else if (d->type == TABLE_FIELD) {
d->formatted = strjoin(s, ":");
if (!d->formatted)
return NULL;
return d->formatted;
}
if (bn) {
d->formatted = TAKE_PTR(bn);
return d->formatted;
}
if (d->type == TABLE_FIELD)
return (d->formatted = strjoin(s, ":"));
if (bn)
return (d->formatted = TAKE_PTR(bn));
return d->string;
}
@@ -1669,26 +1666,20 @@ static const char *table_data_format(
if (strv_isempty(d->strv))
return table_ersatz_string(t);
d->formatted = strv_join(d->strv, "\n");
if (!d->formatted)
return NULL;
break;
return (d->formatted = strv_join(d->strv, "\n"));
case TABLE_STRV_WRAPPED: {
case TABLE_STRV_WRAPPED:
if (strv_isempty(d->strv))
return table_ersatz_string(t);
char *buf = format_strv_width(d->strv, column_width);
if (!buf)
d->formatted = format_strv_width(d->strv, column_width);
if (!d->formatted)
return NULL;
free_and_replace(d->formatted, buf);
d->formatted_for_width = column_width;
if (have_soft)
*have_soft = true;
break;
}
return d->formatted;
case TABLE_BOOLEAN:
return yes_no(d->boolean);
@@ -1702,12 +1693,12 @@ static const char *table_data_format(
case TABLE_TIMESTAMP_RELATIVE_MONOTONIC:
case TABLE_TIMESTAMP_LEFT:
case TABLE_TIMESTAMP_DATE: {
_cleanup_free_ char *p = NULL;
char *ret;
p = new(char,
IN_SET(d->type, TABLE_TIMESTAMP_RELATIVE, TABLE_TIMESTAMP_RELATIVE_MONOTONIC, TABLE_TIMESTAMP_LEFT) ?
FORMAT_TIMESTAMP_RELATIVE_MAX : FORMAT_TIMESTAMP_MAX);
_cleanup_free_ char *p = new(
char,
IN_SET(d->type, TABLE_TIMESTAMP_RELATIVE, TABLE_TIMESTAMP_RELATIVE_MONOTONIC, TABLE_TIMESTAMP_LEFT) ?
FORMAT_TIMESTAMP_RELATIVE_MAX : FORMAT_TIMESTAMP_MAX);
if (!p)
return NULL;
@@ -1726,16 +1717,13 @@ static const char *table_data_format(
if (!ret)
return "-";
d->formatted = TAKE_PTR(p);
break;
return (d->formatted = TAKE_PTR(p));
}
case TABLE_TIMESPAN:
case TABLE_TIMESPAN_MSEC:
case TABLE_TIMESPAN_DAY: {
_cleanup_free_ char *p = NULL;
p = new(char, FORMAT_TIMESPAN_MAX);
_cleanup_free_ char *p = new(char, FORMAT_TIMESPAN_MAX);
if (!p)
return NULL;
@@ -1744,344 +1732,137 @@ static const char *table_data_format(
d->type == TABLE_TIMESPAN_MSEC ? USEC_PER_MSEC : USEC_PER_DAY))
return "-";
d->formatted = TAKE_PTR(p);
break;
return (d->formatted = TAKE_PTR(p));
}
case TABLE_SIZE: {
_cleanup_free_ char *p = NULL;
p = new(char, FORMAT_BYTES_MAX);
_cleanup_free_ char *p = new(char, FORMAT_BYTES_MAX);
if (!p)
return NULL;
if (!format_bytes(p, FORMAT_BYTES_MAX, d->size))
return table_ersatz_string(t);
d->formatted = TAKE_PTR(p);
break;
return (d->formatted = TAKE_PTR(p));
}
case TABLE_BPS: {
_cleanup_free_ char *p = NULL;
size_t n;
p = new(char, FORMAT_BYTES_MAX+2);
_cleanup_free_ char *p = new(char, FORMAT_BYTES_MAX+2);
if (!p)
return NULL;
if (!format_bytes_full(p, FORMAT_BYTES_MAX, d->size, FORMAT_BYTES_BELOW_POINT))
return table_ersatz_string(t);
n = strlen(p);
size_t n = strlen(p);
strscpy(p + n, FORMAT_BYTES_MAX + 2 - n, "bps");
d->formatted = TAKE_PTR(p);
break;
return (d->formatted = TAKE_PTR(p));
}
case TABLE_INT: {
_cleanup_free_ char *p = NULL;
case TABLE_INT:
return (d->formatted = asprintf_safe("%i", d->int_val));
p = new(char, DECIMAL_STR_WIDTH(d->int_val) + 1);
if (!p)
return NULL;
case TABLE_INT8:
return (d->formatted = asprintf_safe("%" PRIi8, d->int8));
sprintf(p, "%i", d->int_val);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_INT16:
return (d->formatted = asprintf_safe("%" PRIi16, d->int16));
case TABLE_INT8: {
_cleanup_free_ char *p = NULL;
case TABLE_INT32:
return (d->formatted = asprintf_safe("%" PRIi32, d->int32));
p = new(char, DECIMAL_STR_WIDTH(d->int8) + 1);
if (!p)
return NULL;
case TABLE_INT64:
return (d->formatted = asprintf_safe("%" PRIi64, d->int64));
sprintf(p, "%" PRIi8, d->int8);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_UINT:
return (d->formatted = asprintf_safe("%u", d->uint_val));
case TABLE_INT16: {
_cleanup_free_ char *p = NULL;
case TABLE_UINT8:
return (d->formatted = asprintf_safe("%" PRIu8, d->uint8));
p = new(char, DECIMAL_STR_WIDTH(d->int16) + 1);
if (!p)
return NULL;
case TABLE_UINT16:
return (d->formatted = asprintf_safe("%" PRIu16, d->uint16));
sprintf(p, "%" PRIi16, d->int16);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_UINT32:
return (d->formatted = asprintf_safe("%" PRIu32, d->uint32));
case TABLE_INT32: {
_cleanup_free_ char *p = NULL;
case TABLE_UINT32_HEX:
return (d->formatted = asprintf_safe("%" PRIx32, d->uint32));
p = new(char, DECIMAL_STR_WIDTH(d->int32) + 1);
if (!p)
return NULL;
case TABLE_UINT32_HEX_0x:
return (d->formatted = asprintf_safe("0x%" PRIx32, d->uint32));
sprintf(p, "%" PRIi32, d->int32);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_UINT64:
return (d->formatted = asprintf_safe("%" PRIu64, d->uint64));
case TABLE_INT64: {
_cleanup_free_ char *p = NULL;
case TABLE_UINT64_HEX:
return (d->formatted = asprintf_safe("%" PRIx64, d->uint64));
p = new(char, DECIMAL_STR_WIDTH(d->int64) + 1);
if (!p)
return NULL;
case TABLE_UINT64_HEX_0x:
return (d->formatted = asprintf_safe("0x%" PRIx64, d->uint64));
sprintf(p, "%" PRIi64, d->int64);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_PERCENT:
return (d->formatted = asprintf_safe("%i%%" , d->percent));
case TABLE_UINT: {
_cleanup_free_ char *p = NULL;
p = new(char, DECIMAL_STR_WIDTH(d->uint_val) + 1);
if (!p)
return NULL;
sprintf(p, "%u", d->uint_val);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_UINT8: {
_cleanup_free_ char *p = NULL;
p = new(char, DECIMAL_STR_WIDTH(d->uint8) + 1);
if (!p)
return NULL;
sprintf(p, "%" PRIu8, d->uint8);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_UINT16: {
_cleanup_free_ char *p = NULL;
p = new(char, DECIMAL_STR_WIDTH(d->uint16) + 1);
if (!p)
return NULL;
sprintf(p, "%" PRIu16, d->uint16);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_UINT32: {
_cleanup_free_ char *p = NULL;
p = new(char, DECIMAL_STR_WIDTH(d->uint32) + 1);
if (!p)
return NULL;
sprintf(p, "%" PRIu32, d->uint32);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_UINT32_HEX: {
_cleanup_free_ char *p = NULL;
p = new(char, 8 + 1);
if (!p)
return NULL;
sprintf(p, "%" PRIx32, d->uint32);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_UINT32_HEX_0x: {
_cleanup_free_ char *p = NULL;
p = new(char, 2 + 8 + 1);
if (!p)
return NULL;
sprintf(p, "0x%" PRIx32, d->uint32);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_UINT64: {
_cleanup_free_ char *p = NULL;
p = new(char, DECIMAL_STR_WIDTH(d->uint64) + 1);
if (!p)
return NULL;
sprintf(p, "%" PRIu64, d->uint64);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_UINT64_HEX: {
_cleanup_free_ char *p = NULL;
p = new(char, 16 + 1);
if (!p)
return NULL;
sprintf(p, "%" PRIx64, d->uint64);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_UINT64_HEX_0x: {
_cleanup_free_ char *p = NULL;
p = new(char, 2 + 16 + 1);
if (!p)
return NULL;
sprintf(p, "0x%" PRIx64, d->uint64);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_PERCENT: {
_cleanup_free_ char *p = NULL;
p = new(char, DECIMAL_STR_WIDTH(d->percent) + 2);
if (!p)
return NULL;
sprintf(p, "%i%%" , d->percent);
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_IFINDEX: {
_cleanup_free_ char *p = NULL;
if (format_ifname_full_alloc(d->ifindex, FORMAT_IFNAME_IFINDEX, &p) < 0)
return NULL;
d->formatted = TAKE_PTR(p);
break;
}
case TABLE_IFINDEX:
(void) format_ifname_full_alloc(d->ifindex, FORMAT_IFNAME_IFINDEX, &d->formatted);
return d->formatted;
case TABLE_IN_ADDR:
case TABLE_IN6_ADDR: {
_cleanup_free_ char *p = NULL;
case TABLE_IN6_ADDR:
(void) in_addr_to_string(d->type == TABLE_IN_ADDR ? AF_INET : AF_INET6,
&d->address,
&d->formatted);
return d->formatted;
if (in_addr_to_string(d->type == TABLE_IN_ADDR ? AF_INET : AF_INET6,
&d->address, &p) < 0)
case TABLE_ID128:
d->formatted = new(char, SD_ID128_STRING_MAX);
if (!d->formatted)
return NULL;
d->formatted = TAKE_PTR(p);
break;
}
return sd_id128_to_string(d->id128, d->formatted);
case TABLE_ID128: {
char *p;
p = new(char, SD_ID128_STRING_MAX);
if (!p)
case TABLE_UUID:
d->formatted = new(char, SD_ID128_UUID_STRING_MAX);
if (!d->formatted)
return NULL;
d->formatted = sd_id128_to_string(d->id128, p);
break;
}
case TABLE_UUID: {
char *p;
p = new(char, SD_ID128_UUID_STRING_MAX);
if (!p)
return NULL;
d->formatted = sd_id128_to_uuid_string(d->id128, p);
break;
}
case TABLE_UID: {
char *p;
return sd_id128_to_uuid_string(d->id128, d->formatted);
case TABLE_UID:
if (!uid_is_valid(d->uid))
return table_ersatz_string(t);
p = new(char, DECIMAL_STR_WIDTH(d->uid) + 1);
if (!p)
return NULL;
sprintf(p, UID_FMT, d->uid);
d->formatted = p;
break;
}
case TABLE_GID: {
char *p;
return (d->formatted = asprintf_safe(UID_FMT, d->uid));
case TABLE_GID:
if (!gid_is_valid(d->gid))
return table_ersatz_string(t);
p = new(char, DECIMAL_STR_WIDTH(d->gid) + 1);
if (!p)
return NULL;
sprintf(p, GID_FMT, d->gid);
d->formatted = p;
break;
}
case TABLE_PID: {
char *p;
return (d->formatted = asprintf_safe(GID_FMT, d->gid));
case TABLE_PID:
if (!pid_is_valid(d->pid))
return table_ersatz_string(t);
p = new(char, DECIMAL_STR_WIDTH(d->pid) + 1);
if (!p)
return NULL;
sprintf(p, PID_FMT, d->pid);
d->formatted = p;
break;
}
return (d->formatted = asprintf_safe(PID_FMT, d->pid));
case TABLE_SIGNAL: {
const char *suffix;
char *p;
suffix = signal_to_string(d->int_val);
const char *suffix = signal_to_string(d->int_val);
if (!suffix)
return table_ersatz_string(t);
p = strjoin("SIG", suffix);
if (!p)
return NULL;
d->formatted = p;
break;
return (d->formatted = strjoin("SIG", suffix));
}
case TABLE_MODE: {
char *p;
case TABLE_MODE:
if (d->mode == MODE_INVALID)
return table_ersatz_string(t);
p = new(char, 4 + 1);
if (!p)
return NULL;
sprintf(p, "%04o", d->mode & 07777);
d->formatted = p;
break;
}
return (d->formatted = asprintf_safe("%04o", d->mode & 07777));
case TABLE_MODE_INODE_TYPE:
if (d->mode == MODE_INVALID)
return table_ersatz_string(t);
@@ -2091,31 +1872,21 @@ static const char *table_data_format(
if (devnum_is_zero(d->devnum))
return table_ersatz_string(t);
if (asprintf(&d->formatted, DEVNUM_FORMAT_STR, DEVNUM_FORMAT_VAL(d->devnum)) < 0)
return NULL;
return (d->formatted = asprintf_safe(DEVNUM_FORMAT_STR, DEVNUM_FORMAT_VAL(d->devnum)));
break;
case TABLE_JSON: {
case TABLE_JSON:
if (!d->json)
return table_ersatz_string(t);
char *p;
if (sd_json_variant_format(d->json, /* flags= */ 0, &p) < 0)
return NULL;
d->formatted = p;
break;
}
(void) sd_json_variant_format(d->json, /* flags= */ 0, &d->formatted);
return d->formatted;
default:
assert_not_reached();
}
return d->formatted;
}
static const char *table_data_format_strip_ansi(
static const char* table_data_format_strip_ansi(
Table *t,
TableData *d,
bool avoid_uppercasing,
@@ -2252,7 +2023,7 @@ static int table_data_requested_width_height(
return truncation_applied;
}
static char *align_string_mem(const char *str, const char *url, size_t new_length, unsigned percent) {
static char* align_string_mem(const char *str, const char *url, size_t new_length, unsigned percent) {
size_t w = 0, space, lspace, old_length, clickable_length;
_cleanup_free_ char *clickable = NULL;
const char *p;
@@ -2851,7 +2622,7 @@ int table_set_reverse(Table *t, size_t column, bool b) {
return 0;
}
TableCell *table_get_cell(Table *t, size_t row, size_t column) {
TableCell* table_get_cell(Table *t, size_t row, size_t column) {
size_t i;
assert(t);
@@ -2866,7 +2637,7 @@ TableCell *table_get_cell(Table *t, size_t row, size_t column) {
return TABLE_INDEX_TO_CELL(i);
}
const void *table_get(Table *t, TableCell *cell) {
const void* table_get(Table *t, TableCell *cell) {
TableData *d;
assert(t);
@@ -3124,7 +2895,7 @@ static int table_make_json_field_name(Table *t, TableData *d, char **ret) {
return 0;
}
static const char *table_get_json_field_name(Table *t, size_t idx) {
static const char* table_get_json_field_name(Table *t, size_t idx) {
assert(t);
return idx < t->n_json_fields ? t->json_fields[idx] : NULL;
+7 -7
View File
@@ -93,11 +93,11 @@ typedef enum TableErsatz {
typedef struct Table Table;
typedef struct TableCell TableCell;
Table *table_new_internal(const char *first_header, ...) _sentinel_;
Table* table_new_internal(const char *first_header, ...) _sentinel_;
#define table_new(...) table_new_internal(__VA_ARGS__, NULL)
Table *table_new_raw(size_t n_columns);
Table *table_new_vertical(void);
Table *table_unref(Table *t);
Table* table_new_raw(size_t n_columns);
Table* table_new_vertical(void);
Table* table_unref(Table *t);
DEFINE_TRIVIAL_CLEANUP_FUNC(Table*, table_unref);
@@ -159,10 +159,10 @@ size_t table_get_columns(Table *t);
size_t table_get_current_column(Table *t);
TableCell *table_get_cell(Table *t, size_t row, size_t column);
TableCell* table_get_cell(Table *t, size_t row, size_t column);
const void *table_get(Table *t, TableCell *cell);
const void *table_get_at(Table *t, size_t row, size_t column);
const void* table_get(Table *t, TableCell *cell);
const void* table_get_at(Table *t, size_t row, size_t column);
int table_to_json(Table *t, sd_json_variant **ret);
int table_print_json(Table *t, FILE *f, sd_json_format_flags_t json_flags);