From 5ad347d1a1c1bdc716dafd07a395861529c0e595 Mon Sep 17 00:00:00 2001 From: Zaky Hermawan <44158147+ZakyHermawan@users.noreply.github.com> Date: Tue, 23 Sep 2025 20:54:35 +0700 Subject: [PATCH] [libc][POSIX][unistd] Implement gethostname (#128142) The implementation is based on the specifications from: https://man7.org/linux/man-pages/man2/gethostname.2.html Closes https://github.com/llvm/llvm-project/issues/126602 --------- Signed-off-by: ZakyHermawan --- libc/config/linux/aarch64/entrypoints.txt | 1 + libc/config/linux/riscv/entrypoints.txt | 1 + libc/config/linux/x86_64/entrypoints.txt | 1 + libc/include/unistd.yaml | 7 +++ libc/src/unistd/CMakeLists.txt | 7 +++ libc/src/unistd/gethostname.h | 21 +++++++++ libc/src/unistd/linux/CMakeLists.txt | 14 ++++++ libc/src/unistd/linux/gethostname.cpp | 53 +++++++++++++++++++++++ libc/test/src/unistd/CMakeLists.txt | 12 +++++ libc/test/src/unistd/gethostname_test.cpp | 31 +++++++++++++ 10 files changed, 148 insertions(+) create mode 100644 libc/src/unistd/gethostname.h create mode 100644 libc/src/unistd/linux/gethostname.cpp create mode 100644 libc/test/src/unistd/gethostname_test.cpp diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index e38fc857d4e1..61b585d2d24c 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -332,6 +332,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.unistd.getcwd libc.src.unistd.getentropy libc.src.unistd.geteuid + libc.src.unistd.gethostname libc.src.unistd.getpid libc.src.unistd.getppid libc.src.unistd.getsid diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index 89e3653186d1..2b8003f9f2bb 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -336,6 +336,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.unistd.getcwd libc.src.unistd.getentropy libc.src.unistd.geteuid + libc.src.unistd.gethostname libc.src.unistd.getpid libc.src.unistd.getppid libc.src.unistd.getsid diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 0bb8a683c5b0..19ed6e02e0ea 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -338,6 +338,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.unistd.getcwd libc.src.unistd.getentropy libc.src.unistd.geteuid + libc.src.unistd.gethostname libc.src.unistd.getpid libc.src.unistd.getppid libc.src.unistd.getsid diff --git a/libc/include/unistd.yaml b/libc/include/unistd.yaml index 051e92b00674..3ba3ec71c25c 100644 --- a/libc/include/unistd.yaml +++ b/libc/include/unistd.yaml @@ -141,6 +141,13 @@ functions: return_type: uid_t arguments: - type: void + - name: gethostname + standards: + - POSIX + return_type: int + arguments: + - type: char * + - type: size_t - name: getopt standards: - POSIX diff --git a/libc/src/unistd/CMakeLists.txt b/libc/src/unistd/CMakeLists.txt index b1a1716aa85c..c66a3a4d0ed7 100644 --- a/libc/src/unistd/CMakeLists.txt +++ b/libc/src/unistd/CMakeLists.txt @@ -111,6 +111,13 @@ add_entrypoint_object( .${LIBC_TARGET_OS}.getcwd ) +add_entrypoint_object( + gethostname + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.gethostname +) + add_entrypoint_object( getpid ALIAS diff --git a/libc/src/unistd/gethostname.h b/libc/src/unistd/gethostname.h new file mode 100644 index 000000000000..cf67bdbd5c32 --- /dev/null +++ b/libc/src/unistd/gethostname.h @@ -0,0 +1,21 @@ +//===-- Implementation header for gethostname -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_UNISTD_GETHOSTNAME_H +#define LLVM_LIBC_SRC_UNISTD_GETHOSTNAME_H + +#include "hdr/types/size_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +int gethostname(char *name, size_t len); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_UNISTD_GETHOSTNAME_H diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt index 382a61fea8b6..2d510f32d287 100644 --- a/libc/src/unistd/linux/CMakeLists.txt +++ b/libc/src/unistd/linux/CMakeLists.txt @@ -194,6 +194,20 @@ add_entrypoint_object( libc.src.errno.errno ) +add_entrypoint_object( + gethostname + SRCS + gethostname.cpp + HDRS + ../gethostname.h + DEPENDS + libc.hdr.types.size_t + libc.include.sys_syscall + libc.include.sys_utsname + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) + add_entrypoint_object( geteuid SRCS diff --git a/libc/src/unistd/linux/gethostname.cpp b/libc/src/unistd/linux/gethostname.cpp new file mode 100644 index 000000000000..60a12a4d6f8e --- /dev/null +++ b/libc/src/unistd/linux/gethostname.cpp @@ -0,0 +1,53 @@ +//===-- Linux implementation of gethostname -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/unistd/gethostname.h" + +#include "hdr/types/size_t.h" +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/string/string_utils.h" + +#include // For syscall numbers. +#include + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, gethostname, (char *name, size_t size)) { + // Check for invalid pointer + if (name == nullptr) { + libc_errno = EFAULT; + return -1; + } + + // Because there is no SYS_gethostname syscall, we use uname to get the + // hostname. + utsname unameData; + int ret = LIBC_NAMESPACE::syscall_impl(SYS_uname, &unameData); + if (ret < 0) { + libc_errno = static_cast(-ret); + return -1; + } + + // Guarantee that the name will be null terminated. + // The amount of bytes copied is min(size + 1, strlen(nodename) + 1) + // +1 to account for the null terminator (the last copied byte is a NULL). + internal::strlcpy(name, unameData.nodename, size + 1); + + // Checks if the length of the hostname was greater than or equal to size + if (internal::string_length(unameData.nodename) >= size) { + libc_errno = ENAMETOOLONG; + return -1; + } + + return 0; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/test/src/unistd/CMakeLists.txt b/libc/test/src/unistd/CMakeLists.txt index 9aec6150af0e..6630a7ef15e5 100644 --- a/libc/test/src/unistd/CMakeLists.txt +++ b/libc/test/src/unistd/CMakeLists.txt @@ -408,6 +408,18 @@ add_libc_unittest( libc.test.UnitTest.ErrnoSetterMatcher ) +add_libc_unittest( + gethostname_test + SUITE + libc_unistd_unittests + SRCS + gethostname_test.cpp + DEPENDS + libc.src.unistd.gethostname + libc.src.errno.errno + libc.test.UnitTest.ErrnoCheckingTest +) + add_libc_unittest( getpid_test SUITE diff --git a/libc/test/src/unistd/gethostname_test.cpp b/libc/test/src/unistd/gethostname_test.cpp new file mode 100644 index 000000000000..a0e57ff0df33 --- /dev/null +++ b/libc/test/src/unistd/gethostname_test.cpp @@ -0,0 +1,31 @@ +//===-- Unittests for gethostname -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/unistd/gethostname.h" + +#include "test/UnitTest/ErrnoCheckingTest.h" +#include "test/UnitTest/Test.h" + +using LlvmLibcGetHostNameTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; + +TEST(LlvmLibcGetHostNameTest, GetCurrHostName) { + char hostbuffer[1024]; + int ret = LIBC_NAMESPACE::gethostname(hostbuffer, sizeof(hostbuffer)); + ASSERT_NE(ret, -1); + ASSERT_ERRNO_SUCCESS(); + + ret = LIBC_NAMESPACE::gethostname(hostbuffer, 0); + ASSERT_EQ(ret, -1); + ASSERT_ERRNO_EQ(ENAMETOOLONG); + + // test for invalid pointer + char *nptr = nullptr; + ret = LIBC_NAMESPACE::gethostname(nptr, 1); + ASSERT_EQ(ret, -1); + ASSERT_ERRNO_EQ(EFAULT); +}