From 4295c0db5fe29bf4afb4e520d5e4ad71de811c99 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 5 Jun 2025 11:17:22 +0200 Subject: [PATCH] hostname-util: add new helper split_user_at_host() Let's introduce a common helper for splitting user@host specifications like we use them for --machine=. --- src/basic/hostname-util.c | 33 +++++++++++++++++++++++++++++++++ src/basic/hostname-util.h | 2 ++ src/test/test-hostname-util.c | 27 +++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 673e1de3d42..1372dec0b2f 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -172,3 +172,36 @@ int get_pretty_hostname(char **ret) { *ret = TAKE_PTR(n); return 0; } + +int split_user_at_host(const char *s, char **ret_user, char **ret_host) { + _cleanup_free_ char *u = NULL, *h = NULL; + + /* Splits a user@host expression (one of those we accept on --machine= and similar). Returns NULL in + * each of the two return parameters if that part was left empty. */ + + const char *rhs = strchr(s, '@'); + if (rhs) { + if (ret_user && rhs > s) { + u = strndup(s, rhs - s); + if (!u) + return -ENOMEM; + } + + if (ret_host && rhs[1] != 0) { + h = strdup(rhs + 1); + if (!h) + return -ENOMEM; + } + } else if (!isempty(s) && ret_host) { + h = strdup(s); + if (!h) + return -ENOMEM; + } + + if (ret_user) + *ret_user = TAKE_PTR(u); + if (ret_host) + *ret_host = TAKE_PTR(h); + + return !!rhs; /* return > 0 if '@' was specified, 0 otherwise */ +} diff --git a/src/basic/hostname-util.h b/src/basic/hostname-util.h index d85391e59fc..4abdfdd76a1 100644 --- a/src/basic/hostname-util.h +++ b/src/basic/hostname-util.h @@ -38,3 +38,5 @@ static inline bool is_dns_proxy_stub_hostname(const char *hostname) { } int get_pretty_hostname(char **ret); + +int split_user_at_host(const char *s, char **ret_user, char **ret_host); diff --git a/src/test/test-hostname-util.c b/src/test/test-hostname-util.c index f9f24e0e03c..4abac5ca3a9 100644 --- a/src/test/test-hostname-util.c +++ b/src/test/test-hostname-util.c @@ -89,4 +89,31 @@ TEST(hostname_cleanup) { ASSERT_STREQ(hostname_cleanup(s), "xxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); } +static void test_split_user_at_host_one(const char *s, const char *expected_user, const char *expected_host, int ret) { + _cleanup_free_ char *u = NULL, *h = NULL; + + ASSERT_OK_EQ(split_user_at_host(s, &u, &h), ret); + ASSERT_STREQ(u, expected_user); + ASSERT_STREQ(h, expected_host); + + u = mfree(u); + h = mfree(h); + + ASSERT_OK_EQ(split_user_at_host(s, &u, NULL), ret); + ASSERT_STREQ(u, expected_user); + + ASSERT_OK_EQ(split_user_at_host(s, NULL, &h), ret); + ASSERT_STREQ(h, expected_host); +} + +TEST(split_user_at_host) { + test_split_user_at_host_one("", NULL, NULL, 0); + test_split_user_at_host_one("@", NULL, NULL, 1); + test_split_user_at_host_one("a", NULL, "a", 0); + test_split_user_at_host_one("a@b", "a", "b", 1); + test_split_user_at_host_one("@b", NULL, "b", 1); + test_split_user_at_host_one("a@", "a", NULL, 1); + test_split_user_at_host_one("aa@@@bb", "aa", "@@bb", 1); +} + DEFINE_TEST_MAIN(LOG_DEBUG); -- 2.47.3