1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-09 12:58:26 +03:00

Merge pull request #26958 from yuwata/nulstr-optionally-drop-trailing-nulstr

nulstr: make strv_parse_nulstr() optionally drop trailing NULs
This commit is contained in:
Daan De Meyer 2023-03-24 11:33:58 +01:00 committed by GitHub
commit 12962485e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 77 deletions

View File

@ -4,7 +4,7 @@
#include "string-util.h"
#include "strv.h"
char** strv_parse_nulstr(const char *s, size_t l) {
char** strv_parse_nulstr_full(const char *s, size_t l, bool drop_trailing_nuls) {
/* l is the length of the input data, which will be split at NULs into elements of the resulting
* strv. Hence, the number of items in the resulting strv will be equal to one plus the number of NUL
* bytes in the l bytes starting at s, unless s[l-1] is NUL, in which case the final empty string is
@ -18,6 +18,10 @@ char** strv_parse_nulstr(const char *s, size_t l) {
assert(s || l <= 0);
if (drop_trailing_nuls)
while (l > 0 && s[l-1] == '\0')
l--;
if (l <= 0)
return new0(char*, 1);

View File

@ -20,7 +20,10 @@ static inline bool nulstr_contains(const char *nulstr, const char *needle) {
return nulstr_get(nulstr, needle);
}
char** strv_parse_nulstr(const char *s, size_t l);
char** strv_parse_nulstr_full(const char *s, size_t l, bool drop_trailing_nuls);
static inline char** strv_parse_nulstr(const char *s, size_t l) {
return strv_parse_nulstr_full(s, l, false);
}
char** strv_split_nulstr(const char *s);
int strv_make_nulstr(char * const *l, char **p, size_t *n);
int set_make_nulstr(Set *s, char **ret, size_t *ret_size);

View File

@ -222,18 +222,12 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags
_cleanup_strv_free_ char **args = NULL;
args = strv_parse_nulstr(t, k);
/* Drop trailing NULs, otherwise strv_parse_nulstr() adds additional empty strings at the end.
* See also issue #21186. */
args = strv_parse_nulstr_full(t, k, /* drop_trailing_nuls = */ true);
if (!args)
return -ENOMEM;
/* Drop trailing empty strings. See issue #21186. */
STRV_FOREACH_BACKWARDS(p, args) {
if (!isempty(*p))
break;
*p = mfree(*p);
}
ans = quote_command_line(args, shflags);
if (!ans)
return -ENOMEM;

View File

@ -19,87 +19,66 @@ TEST(strv_split_nulstr) {
assert_se(streq(l[3], "str3"));
}
TEST(strv_parse_nulstr) {
_cleanup_strv_free_ char **l = NULL;
const char nulstr[] = "hoge\0hoge2\0hoge3\0\0hoge5\0\0xxx";
#define strv_parse_nulstr_full_one(s, n, e0, e1) \
({ \
_cleanup_strv_free_ char **v0 = NULL, **v1 = NULL; \
\
assert_se(v0 = strv_parse_nulstr_full(s, n, false)); \
assert_se(strv_equal(v0, e0)); \
assert_se(v1 = strv_parse_nulstr_full(s, n, true)); \
assert_se(strv_equal(v1, e1)); \
})
l = strv_parse_nulstr(nulstr, sizeof(nulstr)-1);
assert_se(l);
puts("Parse nulstr:");
strv_print(l);
TEST(strv_parse_nulstr_full) {
const char nulstr1[] = "hoge\0hoge2\0hoge3\0\0hoge5\0\0xxx";
const char nulstr2[] = "hoge\0hoge2\0hoge3\0\0hoge5\0\0xxx\0\0\0";
assert_se(streq(l[0], "hoge"));
assert_se(streq(l[1], "hoge2"));
assert_se(streq(l[2], "hoge3"));
assert_se(streq(l[3], ""));
assert_se(streq(l[4], "hoge5"));
assert_se(streq(l[5], ""));
assert_se(streq(l[6], "xxx"));
strv_free(l);
strv_parse_nulstr_full_one(nulstr1, sizeof(nulstr1) - 1,
STRV_MAKE("hoge", "hoge2", "hoge3", "", "hoge5", "", "xxx"),
STRV_MAKE("hoge", "hoge2", "hoge3", "", "hoge5", "", "xxx"));
l = strv_parse_nulstr((const char[0]) {}, 0);
assert_se(l);
assert_se(strv_isempty(l));
strv_free(l);
strv_parse_nulstr_full_one(nulstr2, sizeof(nulstr2) - 1,
STRV_MAKE("hoge", "hoge2", "hoge3", "", "hoge5", "", "xxx", "", ""),
STRV_MAKE("hoge", "hoge2", "hoge3", "", "hoge5", "", "xxx"));
l = strv_parse_nulstr((const char[1]) { 0 }, 1);
assert_se(l);
assert_se(strv_equal(l, STRV_MAKE("")));
strv_free(l);
strv_parse_nulstr_full_one(((const char[0]) {}), 0,
STRV_MAKE_EMPTY, STRV_MAKE_EMPTY);
l = strv_parse_nulstr((const char[1]) { 'x' }, 1);
assert_se(l);
assert_se(strv_equal(l, STRV_MAKE("x")));
strv_free(l);
strv_parse_nulstr_full_one(((const char[1]) { 0 }), 1,
STRV_MAKE(""), STRV_MAKE_EMPTY);
l = strv_parse_nulstr((const char[2]) { 0, 0 }, 2);
assert_se(l);
assert_se(strv_equal(l, STRV_MAKE("", "")));
strv_free(l);
strv_parse_nulstr_full_one(((const char[1]) { 'x' }), 1,
STRV_MAKE("x"), STRV_MAKE("x"));
l = strv_parse_nulstr((const char[2]) { 'x', 0 }, 2);
assert_se(l);
assert_se(strv_equal(l, STRV_MAKE("x")));
strv_free(l);
strv_parse_nulstr_full_one(((const char[2]) { 0, 0 }), 2,
STRV_MAKE("", ""), STRV_MAKE_EMPTY);
l = strv_parse_nulstr((const char[3]) { 0, 0, 0 }, 3);
assert_se(l);
assert_se(strv_equal(l, STRV_MAKE("", "", "")));
strv_free(l);
strv_parse_nulstr_full_one(((const char[2]) { 'x', 0 }), 2,
STRV_MAKE("x"), STRV_MAKE("x"));
l = strv_parse_nulstr((const char[3]) { 'x', 0, 0 }, 3);
assert_se(l);
assert_se(strv_equal(l, STRV_MAKE("x", "")));
strv_free(l);
strv_parse_nulstr_full_one(((const char[3]) { 0, 0, 0 }), 3,
STRV_MAKE("", "", ""), STRV_MAKE_EMPTY);
l = strv_parse_nulstr((const char[3]) { 0, 'x', 0 }, 3);
assert_se(l);
assert_se(strv_equal(l, STRV_MAKE("", "x")));
strv_free(l);
strv_parse_nulstr_full_one(((const char[3]) { 'x', 0, 0 }), 3,
STRV_MAKE("x", ""), STRV_MAKE("x"));
l = strv_parse_nulstr((const char[3]) { 0, 0, 'x' }, 3);
assert_se(l);
assert_se(strv_equal(l, STRV_MAKE("", "", "x")));
strv_free(l);
strv_parse_nulstr_full_one(((const char[3]) { 0, 'x', 0 }), 3,
STRV_MAKE("", "x"), STRV_MAKE("", "x"));
l = strv_parse_nulstr((const char[3]) { 'x', 'x', 0 }, 3);
assert_se(l);
assert_se(strv_equal(l, STRV_MAKE("xx")));
strv_free(l);
strv_parse_nulstr_full_one(((const char[3]) { 0, 0, 'x' }), 3,
STRV_MAKE("", "", "x"), STRV_MAKE("", "", "x"));
l = strv_parse_nulstr((const char[3]) { 0, 'x', 'x' }, 3);
assert_se(l);
assert_se(strv_equal(l, STRV_MAKE("", "xx")));
strv_free(l);
strv_parse_nulstr_full_one(((const char[3]) { 'x', 'x', 0 }), 3,
STRV_MAKE("xx"), STRV_MAKE("xx"));
l = strv_parse_nulstr((const char[3]) { 'x', 0, 'x' }, 3);
assert_se(l);
assert_se(strv_equal(l, STRV_MAKE("x", "x")));
strv_free(l);
strv_parse_nulstr_full_one(((const char[3]) { 0, 'x', 'x' }), 3,
STRV_MAKE("", "xx"), STRV_MAKE("", "xx"));
l = strv_parse_nulstr((const char[3]) { 'x', 'x', 'x' }, 3);
assert_se(l);
assert_se(strv_equal(l, STRV_MAKE("xxx")));
strv_parse_nulstr_full_one(((const char[3]) { 'x', 0, 'x' }), 3,
STRV_MAKE("x", "x"), STRV_MAKE("x", "x"));
strv_parse_nulstr_full_one(((const char[3]) { 'x', 'x', 'x' }), 3,
STRV_MAKE("xxx"), STRV_MAKE("xxx"));
}
static void test_strv_make_nulstr_one(char **l) {