]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
hostname-setup: introduce pidref_gethostname_full() 39350/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 11 Oct 2025 03:30:05 +0000 (12:30 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 19 Oct 2025 01:01:46 +0000 (10:01 +0900)
src/shared/hostname-setup.c
src/shared/hostname-setup.h
src/test/test-hostname-setup.c

index ac13d06fb2345ef25263a709d9cc64b0bd4b4018..4e977eed125901f51c85481e9ba78231ab1fe593 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
+#include <sched.h>
 #include <stdio.h>
 #include <sys/utsname.h>
 #include <unistd.h>
 #include "hostname-setup.h"
 #include "hostname-util.h"
 #include "initrd-util.h"
+#include "io-util.h"
 #include "log.h"
+#include "namespace-util.h"
+#include "pidref.h"
 #include "proc-cmdline.h"
+#include "process-util.h"
 #include "siphash24.h"
 #include "string-table.h"
 #include "string-util.h"
@@ -344,3 +349,66 @@ int gethostname_full(GetHostnameFlags flags, char **ret) {
         *ret = TAKE_PTR(buf);
         return 0;
 }
+
+int pidref_gethostname_full(PidRef *pidref, GetHostnameFlags flags, char **ret) {
+        int r;
+
+        assert(pidref);
+        assert(ret);
+
+        r = pidref_in_same_namespace(pidref, NULL, NAMESPACE_UTS);
+        if (r < 0)
+                return r;
+        if (r > 0)
+                return gethostname_full(flags, ret);
+
+        _cleanup_close_ int utsns_fd = r = pidref_namespace_open_by_type(pidref, NAMESPACE_UTS);
+        if (r < 0)
+                return r;
+
+        _cleanup_close_pair_ int errno_pipe[2] = EBADF_PAIR;
+        r = pipe2(errno_pipe, O_CLOEXEC);
+        if (r < 0)
+                return -errno;
+
+        _cleanup_close_pair_ int result_pipe[2] = EBADF_PAIR;
+        r = pipe2(result_pipe, O_CLOEXEC);
+        if (r < 0)
+                return -errno;
+
+        _cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
+        r = pidref_safe_fork("(gethostname)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL, &child);
+        if (r < 0)
+                return r;
+        if (r == 0) {
+                errno_pipe[0] = safe_close(errno_pipe[0]);
+                result_pipe[0] = safe_close(result_pipe[0]);
+
+                if (setns(utsns_fd, CLONE_NEWUTS) < 0)
+                        report_errno_and_exit(errno_pipe[1], -errno);
+
+                char *t;
+                r = gethostname_full(flags, &t);
+                if (r < 0)
+                        report_errno_and_exit(errno_pipe[1], r);
+
+                r = loop_write(result_pipe[1], t, strlen(t) + 1);
+                report_errno_and_exit(errno_pipe[1], r);
+        }
+
+        errno_pipe[1] = safe_close(errno_pipe[1]);
+        result_pipe[1] = safe_close(result_pipe[1]);
+
+        r = read_errno(errno_pipe[0]);
+        if (r < 0)
+                return r;
+
+        char buf[HOST_NAME_MAX+1];
+        ssize_t n = loop_read(result_pipe[0], buf, sizeof(buf), /* do_poll = */ false);
+        if (n < 0)
+                return n;
+        if (n == 0 || buf[n - 1] != '\0')
+                return -EPROTO;
+
+        return strdup_to(ret, buf);
+}
index 9af57fad5649e4e96e4581e3c4d61bfbd44dba43..7f6216ce6eb5dc4adb97d2a675c2399c1794b627 100644 (file)
@@ -56,3 +56,5 @@ static inline char* gethostname_short_malloc(void) {
 
         return s;
 }
+
+int pidref_gethostname_full(PidRef *pidref, GetHostnameFlags flags, char **ret);
index 87c9f7d7515750ad91aa3c1928874726ce40fb69..e3fc8a220b6a40d51cbfd12080f85830226cf411 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <fnmatch.h>
+#include <sched.h>
 #include <stdlib.h>
 
 #include "alloc-util.h"
@@ -9,6 +10,8 @@
 #include "hostname-setup.h"
 #include "hostname-util.h"
 #include "id128-util.h"
+#include "pidref.h"
+#include "process-util.h"
 #include "tests.h"
 #include "tmpfile-util.h"
 
@@ -132,4 +135,69 @@ TEST(default_hostname) {
         ASSERT_TRUE(hostname_is_valid(m, VALID_HOSTNAME_QUESTION_MARK));
 }
 
+TEST(pidref_gethostname_full) {
+        int r;
+
+        if (geteuid() != 0)
+                return (void) log_tests_skipped("Not privileged");
+
+        _cleanup_free_ char *original = NULL, *original_short = NULL;
+        ASSERT_NOT_NULL(original = gethostname_malloc());
+        ASSERT_NOT_NULL(original_short = gethostname_short_malloc());
+
+        _cleanup_close_pair_ int fds[2] = EBADF_PAIR;
+        ASSERT_OK_ERRNO(pipe2(fds, O_CLOEXEC));
+
+        _cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
+        r = pidref_safe_fork("(test-pidref-gethostname)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL, &pidref);
+        ASSERT_OK(r);
+        if (r == 0) {
+                fds[0] = safe_close(fds[0]);
+
+                ASSERT_OK_ERRNO(unshare(CLONE_NEWUTS));
+                ASSERT_OK(sethostname_idempotent("hogehoge.example.com"));
+
+                ASSERT_OK_EQ_ERRNO(write(fds[1], &(const char[]) { 'x' }, 1), 1);
+                freeze();
+        }
+
+        fds[1] = safe_close(fds[1]);
+
+        char x;
+        ASSERT_OK_EQ_ERRNO(read(fds[0], &x, 1), 1);
+        ASSERT_EQ(x, 'x');
+
+        _cleanup_free_ char *s = NULL;
+        ASSERT_OK(pidref_gethostname_full(&pidref, /* flags= */ 0, &s));
+        ASSERT_STREQ(s, "hogehoge.example.com");
+
+        s = mfree(s);
+
+        ASSERT_OK(pidref_gethostname_full(&pidref, GET_HOSTNAME_SHORT, &s));
+        ASSERT_STREQ(s, "hogehoge");
+
+        s = mfree(s);
+
+        _cleanup_(pidref_done) PidRef self = PIDREF_NULL;
+        ASSERT_OK(pidref_set_self(&self));
+
+        ASSERT_OK(pidref_gethostname_full(&self, /* flags= */ 0, &s));
+        ASSERT_STREQ(s, original);
+
+        s = mfree(s);
+
+        ASSERT_OK(pidref_gethostname_full(&self, GET_HOSTNAME_SHORT, &s));
+        ASSERT_STREQ(s, original_short);
+
+        s = mfree(s);
+
+        ASSERT_NOT_NULL(s = gethostname_malloc());
+        ASSERT_STREQ(s, original);
+
+        s = mfree(s);
+
+        ASSERT_NOT_NULL(s = gethostname_short_malloc());
+        ASSERT_STREQ(s, original_short);
+}
+
 DEFINE_TEST_MAIN(LOG_DEBUG);