diff options
Diffstat (limited to 'lib/libutil++')
-rw-r--r-- | lib/libutil++/Makefile | 23 | ||||
-rw-r--r-- | lib/libutil++/freebsd__FILE_up.3 | 41 | ||||
-rw-r--r-- | lib/libutil++/freebsd__addrinfo_up.3 | 45 | ||||
-rw-r--r-- | lib/libutil++/freebsd__fd_up.3 | 78 | ||||
-rw-r--r-- | lib/libutil++/freebsd__malloc_up.3 | 50 | ||||
-rw-r--r-- | lib/libutil++/freebsd__nvlist_up.3 | 37 | ||||
-rw-r--r-- | lib/libutil++/freebsd__pidfile.3 | 110 | ||||
-rw-r--r-- | lib/libutil++/freebsd__stringf.3 | 48 | ||||
-rw-r--r-- | lib/libutil++/libutil++.hh | 230 | ||||
-rw-r--r-- | lib/libutil++/stringf.cc | 57 | ||||
-rw-r--r-- | lib/libutil++/tests/Makefile | 12 | ||||
-rw-r--r-- | lib/libutil++/tests/pidfile_test.cc | 44 | ||||
-rw-r--r-- | lib/libutil++/tests/stringf_test.cc | 52 | ||||
-rw-r--r-- | lib/libutil++/tests/up_test.cc | 33 |
14 files changed, 860 insertions, 0 deletions
diff --git a/lib/libutil++/Makefile b/lib/libutil++/Makefile new file mode 100644 index 000000000000..2e7a614df800 --- /dev/null +++ b/lib/libutil++/Makefile @@ -0,0 +1,23 @@ +LIB_CXX= util++ +INTERNALLIB= true +SHLIB_MAJOR= 1 +SRCS= stringf.cc + +MAN+= freebsd::FILE_up.3 \ + freebsd::addrinfo_up.3 \ + freebsd::fd_up.3 \ + freebsd::malloc_up.3 \ + freebsd::nvlist_up.3 \ + freebsd::pidfile.3 \ + freebsd::stringf.3 + +.for page in ${MAN} +MANSRC.${page}= ${page:S/:/_/g} +.endfor + +.include <src.opts.mk> + +HAS_TESTS= +SUBDIR.${MK_TESTS}+= tests + +.include <bsd.lib.mk> diff --git a/lib/libutil++/freebsd__FILE_up.3 b/lib/libutil++/freebsd__FILE_up.3 new file mode 100644 index 000000000000..ea63b1233b43 --- /dev/null +++ b/lib/libutil++/freebsd__FILE_up.3 @@ -0,0 +1,41 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) 2025 Chelsio Communications, Inc. +.\" Written by: John Baldwin <jhb@FreeBSD.org> +.\" +.Dd July 31, 2025 +.Dt FREEBSD::FILE_UP 3 +.Os +.Sh NAME +.Nm freebsd::FILE_up +.Nd std::unique_ptr specialization for stdio FILE objects +.Sh LIBRARY +.Lb libutil++ +.Sh SYNOPSIS +.In libutil++.hh +.Ft using FILE_up = std::unique_ptr<FILE, fclose_deleter>; +.Sh DESCRIPTION +This class is a specialization of +.Vt std::unique_ptr +for stdio +.Vt FILE +objects. +When a +.Vt FILE +object managed by an instance of this class is disposed, +.Xr fclose 3 +is invoked to dispose of the +.Vt FILE +object. +.Sh EXAMPLES +.Bd -literal -offset indent +freebsd::FILE_up fp(fopen("foo.txt", "w")); +if (!fp) + err(1, "fopen"); +fprintf(fp.get(), "hello\n"); +// `fp' is implicitly closed on destruction +.Ed +.Sh SEE ALSO +.Xr fclose 3 , +.Xr fopen 3 diff --git a/lib/libutil++/freebsd__addrinfo_up.3 b/lib/libutil++/freebsd__addrinfo_up.3 new file mode 100644 index 000000000000..4845a76bfb61 --- /dev/null +++ b/lib/libutil++/freebsd__addrinfo_up.3 @@ -0,0 +1,45 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) 2025 Chelsio Communications, Inc. +.\" Written by: John Baldwin <jhb@FreeBSD.org> +.\" +.Dd July 31, 2025 +.Dt FREEBSD::ADDRINFO_UP 3 +.Os +.Sh NAME +.Nm freebsd::addrinfo_up +.Nd std::unique_ptr specialization for lists of socket addresses +.Sh LIBRARY +.Lb libutil++ +.Sh SYNOPSIS +.In libutil++.hh +.Ft using addrinfo_up = std::unique_ptr<addrinfo, freeaddrinfo_deleter>; +.Sh DESCRIPTION +This class is a specialization of +.Vt std::unique_ptr +for socket addresses returned by +.Xr getaddrinfo 3 . +When a list of socket addresses managed by an instance of this class is +disposed, +.Xr freeaddrinfo 3 +is invoked to dispose of the list. +.Sh EXAMPLES +.Bd -literal -offset indent +freebsd::addrinfo_up +resolve_address(const char *address, const char *port) +{ + struct addrinfo hints, *ai; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(address, port, &hints, &ai); + if (error != 0) + return {}; + return freebsd::addrinfo_up(ai); +} +.Ed +.Sh SEE ALSO +.Xr getaddrinfo 3 diff --git a/lib/libutil++/freebsd__fd_up.3 b/lib/libutil++/freebsd__fd_up.3 new file mode 100644 index 000000000000..2ef2241a5c40 --- /dev/null +++ b/lib/libutil++/freebsd__fd_up.3 @@ -0,0 +1,78 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) 2025 Chelsio Communications, Inc. +.\" Written by: John Baldwin <jhb@FreeBSD.org> +.\" +.Dd July 31, 2025 +.Dt FREEBSD::STRINGF 3 +.Os +.Sh NAME +.Nm freebsd::fd_up +.Nd own a file descriptor +.Sh LIBRARY +.Lb libutil++ +.Sh SYNOPSIS +.In libutil++.hh +.Pp +.Vt class freebsd::fd_up +{ +.Bd -ragged -offset indent +.Fn fd_up +.Fn fd_up "int fd" +.Fn fd_up "fd_up &&other" +.Fn ~fd_up +.Ft int +.Fn get +.Ft int +.Fn release +.Ft void +.Fn reset "int newfd = -1" +.Ft "fd_up &" +.Fn operator= "fd_up &&other" +.Ft "fd_up &" +.Fn operator= "int fd" +.Fn "explicit operator bool" +.Fn "operator int" +.Ed +}; +.Sh DESCRIPTION +Each instance of this class owns a file descriptor. +This class is patterned on std::unique_ptr, +but instead of owning a pointer to an object, +this class owns a file descriptor. +The currently-owned file descriptor is disposed by invoking +.Xr close 2 +when an instance of this class is destroyed. +The currently-owned file descriptor is also disposed if it is replaced by the +.Fn reset +method or assignment operators. +.Pp +The +.Fn get +method returns the current file descriptor value while retaining ownership. +.Pp +The +.Fn release +method relinquishes ownership of the current file descriptor and returns the +value of the previously-owned file descriptor. +.Pp +The explicit +.Vt bool +conversion operator permits testing the validity of an object. +The operator returns true if the instance owns a valid file descriptor. +.Pp +The implicit +.Vt int +conversion operator permits passing an instance of this class directly as +an argument to existing functions which expect a file descriptor. +.Sh EXAMPLES +.Bd -literal -offset indent +freebsd::fd_up fd(open("/dev/null", O_RDWR)); +if (!fd) + err(1, "open"); +write(fd, "test", 4); +// `fd' is implicitly closed on destruction +.Ed +.Sh SEE ALSO +.Xr close 2 diff --git a/lib/libutil++/freebsd__malloc_up.3 b/lib/libutil++/freebsd__malloc_up.3 new file mode 100644 index 000000000000..b18e7854213a --- /dev/null +++ b/lib/libutil++/freebsd__malloc_up.3 @@ -0,0 +1,50 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) 2025 Chelsio Communications, Inc. +.\" Written by: John Baldwin <jhb@FreeBSD.org> +.\" +.Dd July 31, 2025 +.Dt FREEBSD::MALLOC_UP 3 +.Os +.Sh NAME +.Nm freebsd::malloc_up +.Nd std::unique_ptr specialization for objects allocated via malloc +.Sh LIBRARY +.Lb libutil++ +.Sh SYNOPSIS +.In libutil++.hh +.Ft using malloc_up = std::unique_ptr<T, free_deleter<T>>; +.Sh DESCRIPTION +This class is a specialization of +.Vt std::unique_ptr +which invokes +.Xr free 3 +instead of +.Fn delete +when an object is disposed. +While explicit calls to +.Xr malloc 3 +should be avoided in C++ code, +this class can be useful to manage an object allocated by an existing API +which uses +.Xr malloc 3 +internally such as +.Xr scandir 3 . +Note that the type of the underlying object must be used as the first +template argument similar to std::unique_ptr. +.Sh EXAMPLES +This example uses +.Xr strdup 3 +for simplicity, +but new C++ code should generally not use +.Xr strdup 3 : +.Bd -literal -offset indent +freebsd::malloc_up<char> my_string(strdup("foo")); +// `mystring' is implicitly freed on destruction +.Ed +.Sh SEE ALSO +.Xr free 3 , +.Xr malloc 3 , +.Xr scandir 3 , +.Xr strdup 3 diff --git a/lib/libutil++/freebsd__nvlist_up.3 b/lib/libutil++/freebsd__nvlist_up.3 new file mode 100644 index 000000000000..43f76cf3ead3 --- /dev/null +++ b/lib/libutil++/freebsd__nvlist_up.3 @@ -0,0 +1,37 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) 2025 Chelsio Communications, Inc. +.\" Written by: John Baldwin <jhb@FreeBSD.org> +.\" +.Dd July 31, 2025 +.Dt FREEBSD::NVLIST_UP 3 +.Os +.Sh NAME +.Nm freebsd::nvlist_up +.Nd std::unique_ptr specialization for name/value pairs +.Sh LIBRARY +.Lb libutil++ +.Sh SYNOPSIS +.In libutil++.hh +.Ft using nvlist_up = std::unique_ptr<nvlist, nvlist_deleter>; +.Sh DESCRIPTION +This class is a specialization of +.Vt std::unique_ptr +for +.Vt nvlist_t +objects. +When an +.Vt nvlist_t +object managed by an instance of this class is disposed, +.Xr nvlist_destroy 3 +is invoked to dispose of the object. +.Sh EXAMPLES +.Bd -literal -offset indent +freebsd::nvlist_up nvl(nvlist_create(0)); +nvlist_add_number(nvl.get(), "answer", 42); +nvlist_add_bool(nvl.get(), "valid", true); +// `nvl' is implicitly destroyed +.Ed +.Sh SEE ALSO +.Xr nvlist_destroy 3 diff --git a/lib/libutil++/freebsd__pidfile.3 b/lib/libutil++/freebsd__pidfile.3 new file mode 100644 index 000000000000..fb67253f5c02 --- /dev/null +++ b/lib/libutil++/freebsd__pidfile.3 @@ -0,0 +1,110 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) 2025 Chelsio Communications, Inc. +.\" Written by: John Baldwin <jhb@FreeBSD.org> +.\" +.Dd July 31, 2025 +.Dt FREEBSD::STRINGF 3 +.Os +.Sh NAME +.Nm freebsd::pidfile +.Nd own a PID file handle +.Sh LIBRARY +.Lb libutil++ +.Sh SYNOPSIS +.In libutil++.hh +.Pp +.Vt class freebsd::pidfile +{ +.Bd -ragged -offset indent +.Fn pidfile +.Fn pidfile "struct pidfh *pfh" +.Fn pidfile "pidfile &&other" +.Fn ~pidfile +.Ft struct pidfh * +.Fn release +.Ft void +.Fn reset "struct pidfh *newpfh = nullptr" +.Ft int +.Fn write +.Ft int +.Fn close +.Ft int +.Fn fileno +.Ft "pidfile &" +.Fn operator= "pidfile &&other" +.Ft "pidfile &" +.Fn operator= "struct pidfh *pfh" +.Fn "explicit operator bool" +.Ed +}; +.Sh DESCRIPTION +Each instance of this class owns a PID file handle created by +.Xr pidfile_open 3 . +This class is patterned on std::unique_ptr; +however, +rather than exporting the raw pointer via a +.Fn get +method, +this class provides wrapper methods for each of the other +.Xr pidfile 3 +functions. +The currently-owned PID file is removed by invoking +.Xr pidfile_remove 3 +when an instance of this class is destroyed. +The currently-owned PID file is also removed if it is replaced by the +.Fn reset +method or assignment operators. +.Pp +The +.Fn release +method relinquishes ownership of the current PID file handle and returns the +value of the previously-owned PID file handle. +.Pp +The +.Fn write +method writes out the PID of the current process to the PID file via +.Xr pidfile_write 3 . +.Pp +The +.Fn close +method closes the current PID file without removing it via +.Xr pidfile_close 3 . +If the close succeeds, the PID file handle is no longer valid. +.Pp +The +.Fn fileno +method returns the underlying file descriptor for the current PID file via +.Xr pidfile_fileno 3 . +.Pp +The explicit +.Vt bool +conversion operator permits testing the validity of an object. +The operator returns true if the instance owns a valid PID file handle. +.Sh EXAMPLES +.Bd -literal -offset indent +int +main() +{ + freebsd::pidfile pf(pidfile_open("/var/run/daemon.pid", + 0600, NULL)); + if (!pf) + err(1, "pidfile_open"); + + if (daemon(0, 0) == -1) { + warn("daemon"); + return 1; + } + + pf->write(); + + for (;;) { + /* Do Work */ + } + + return 0; +} +.Ed +.Sh SEE ALSO +.Xr pidfile 3 diff --git a/lib/libutil++/freebsd__stringf.3 b/lib/libutil++/freebsd__stringf.3 new file mode 100644 index 000000000000..341fedef4343 --- /dev/null +++ b/lib/libutil++/freebsd__stringf.3 @@ -0,0 +1,48 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) 2025 Chelsio Communications, Inc. +.\" Written by: John Baldwin <jhb@FreeBSD.org> +.\" +.Dd July 31, 2025 +.Dt FREEBSD::STRINGF 3 +.Os +.Sh NAME +.Nm freebsd::stringf +.Nd build a std::string using stdio formatting +.Sh LIBRARY +.Lb libutil++ +.Sh SYNOPSIS +.In libutil++.hh +.Ft std::string +.Fn freebsd::stringf "const char *fmt" "..." +.Ft std::string +.Fn freebsd::stringf "const char *fmt" "va_list ap" +.Sh DESCRIPTION +These functions construct a +.Vt std::string +object containing a formatted string. +The output of the string is dictated by the +.Fa fmt +argument and additional arguments using the same conventions documented in +.Xr printf 3 . +The first form provides functionality similar to +.Xr asprintf 3 +and the second form is similar to +.Xr vasprintf 3 . +.Sh RETURN VALUES +These functions return a std::string object. +.Sh EXCEPTIONS +These functions may throw one of the following exceptions: +.Bl -tag -width Er +.It Bq Er std::bad_alloc +Failed to allocate memory. +.It Bq Er std::length_error +The result would exceeed the maximum possible string size. +.El +.Sh EXAMPLES +.Bd -literal -offset indent +std::string s = freebsd::stringf("hello %s", "world"); +.Ed +.Sh SEE ALSO +.Xr asprintf 3 diff --git a/lib/libutil++/libutil++.hh b/lib/libutil++/libutil++.hh new file mode 100644 index 000000000000..60e6b3fc5fde --- /dev/null +++ b/lib/libutil++/libutil++.hh @@ -0,0 +1,230 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Chelsio Communications, Inc. + * Written by: John Baldwin <jhb@FreeBSD.org> + */ + +#ifndef __LIBUTILPP_HH__ +#define __LIBUTILPP_HH__ + +#include <sys/nv.h> +#include <libutil.h> +#include <netdb.h> +#include <unistd.h> + +#include <cstdarg> +#include <cstdio> +#include <cstdlib> +#include <memory> + +namespace freebsd { + /* + * FILE_up is a std::unique_ptr<> for FILE objects which uses + * fclose() to destroy the wrapped pointer. + */ + struct fclose_deleter { + void operator() (std::FILE *fp) const + { + std::fclose(fp); + } + }; + + using FILE_up = std::unique_ptr<std::FILE, fclose_deleter>; + + /* + * addrinfo_up is a std::unique_ptr<> which uses + * freeaddrinfo() to destroy the wrapped pointer. It is + * intended to wrap arrays allocated by getaddrinfo(). + */ + struct freeaddrinfo_deleter { + void operator() (struct addrinfo *ai) const + { + freeaddrinfo(ai); + } + }; + + using addrinfo_up = std::unique_ptr<addrinfo, freeaddrinfo_deleter>; + + /* + * This class is intended to function similar to unique_ptr<>, + * but it contains a file descriptor rather than a pointer to + * an object. On destruction the descriptor is closed via + * close(2). + * + * Similar to unique_ptr<>, release() returns ownership of the + * file descriptor to the caller. reset() closes the current + * file descriptor and takes ownership of a new one. A move + * constructor permits ownership to be transferred via + * std::move(). An integer file descriptor can be assigned + * directly which is equivalent to calling reset(). + * + * An explicit bool conversion operator permits testing this + * class in logical expressions. It returns true if it + * contains a valid descriptor. + * + * An implicit int conversion operator returns the underlying + * file descriptor allowing objects of this type to be passed + * directly to APIs such as connect(), listen(), etc. + */ + class fd_up { + public: + fd_up() : fd(-1) {} + fd_up(int _fd) : fd(_fd) {} + fd_up(fd_up &&other) : fd(other.release()) {} + fd_up(fd_up const &) = delete; + + ~fd_up() { reset(); } + + int get() const { return (fd); } + + int release() + { + int oldfd = fd; + + fd = -1; + return (oldfd); + } + + void reset(int newfd = -1) + { + if (fd >= 0) + close(fd); + fd = newfd; + } + + fd_up &operator=(fd_up &&other) noexcept + { + if (this == &other) + return *this; + + reset(other.release()); + return *this; + } + + fd_up &operator=(fd_up const &) = delete; + + fd_up &operator=(int newfd) + { + reset(newfd); + return *this; + } + + explicit operator bool() const { return fd >= 0; } + operator int() const { return fd; } + private: + int fd; + }; + + /* + * malloc_up<T> is a std::unique_ptr<> which uses free() to + * destroy the wrapped pointer. This can be used to wrap + * pointers allocated implicitly by malloc() such as those + * returned by strdup(). + */ + template <class T> + struct free_deleter { + void operator() (T *p) const + { + std::free(p); + } + }; + + template <class T> + using malloc_up = std::unique_ptr<T, free_deleter<T>>; + + /* + * nvlist_up is a std::unique_ptr<> for nvlist_t objects which + * uses nvlist_destroy() to destroy the wrapped pointer. + */ + struct nvlist_deleter { + void operator() (nvlist_t *nvl) const + { + nvlist_destroy(nvl); + } + }; + + using nvlist_up = std::unique_ptr<nvlist_t, nvlist_deleter>; + + /* + * A wrapper class for the pidfile_* API. The destructor + * calls pidfile_remove() when an object is destroyed. This + * class is similar to std::unique_ptr<> in that it retains + * exclusive ownership of the pidfh object. + * + * In addition to release() and reset methods(), write(), + * close(), and fileno() methods are provided as wrappers for + * pidfile_*. + */ + class pidfile { + public: + pidfile() = default; + pidfile(struct pidfh *_pfh) : pfh(_pfh) {} + pidfile(pidfile &&other) : pfh(other.release()) {} + pidfile(pidfile const &) = delete; + + ~pidfile() { reset(); } + + struct pidfh *release() + { + struct pidfh *oldpfh = pfh; + + pfh = nullptr; + return (oldpfh); + } + + void reset(struct pidfh *newpfh = nullptr) + { + if (pfh != nullptr) + pidfile_remove(pfh); + pfh = newpfh; + } + + int write() + { + return (pidfile_write(pfh)); + } + + int close() + { + int rv = pidfile_close(pfh); + if (rv == 0) + pfh = nullptr; + return (rv); + } + + int fileno() + { + return (pidfile_fileno(pfh)); + } + + pidfile &operator=(pidfile &&other) noexcept + { + if (this == &other) + return *this; + reset(other.release()); + return *this; + } + + pidfile &operator=(pidfile const &) = delete; + + pidfile &operator=(struct pidfh *newpfh) + { + reset(newpfh); + return *this; + } + + explicit operator bool() const { return pfh != nullptr; } + private: + struct pidfh *pfh = nullptr; + }; + + /* + * Returns a std::string containing the same output as + * sprintf(). Throws std::bad_alloc if an error occurs. + */ + std::string stringf(const char *fmt, ...) __printflike(1, 2); + std::string stringf(const char *fmt, std::va_list ap); +} + +#endif /* !__LIBUTILPP_HH__ */ diff --git a/lib/libutil++/stringf.cc b/lib/libutil++/stringf.cc new file mode 100644 index 000000000000..8c24167d70ac --- /dev/null +++ b/lib/libutil++/stringf.cc @@ -0,0 +1,57 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Chelsio Communications, Inc. + * Written by: John Baldwin <jhb@FreeBSD.org> + */ + +#include <cstdarg> +#include <cstdio> +#include <string> + +#include "libutil++.hh" + +static int +stringf_write(void *cookie, const char *buf, int len) +{ + std::string *str = reinterpret_cast<std::string *>(cookie); + try { + str->append(buf, len); + } catch (std::bad_alloc) { + errno = ENOMEM; + return (-1); + } catch (std::length_error) { + errno = EFBIG; + return (-1); + } + return (len); +} + +std::string +freebsd::stringf(const char *fmt, va_list ap) +{ + std::string str; + freebsd::FILE_up fp(fwopen(reinterpret_cast<void *>(&str), + stringf_write)); + + vfprintf(fp.get(), fmt, ap); + + if (ferror(fp.get())) + throw std::bad_alloc(); + fp.reset(nullptr); + + return str; +} + +std::string +freebsd::stringf(const char *fmt, ...) +{ + std::va_list ap; + std::string str; + + va_start(ap, fmt); + str = freebsd::stringf(fmt, ap); + va_end(ap); + + return str; +} diff --git a/lib/libutil++/tests/Makefile b/lib/libutil++/tests/Makefile new file mode 100644 index 000000000000..e7720d122f36 --- /dev/null +++ b/lib/libutil++/tests/Makefile @@ -0,0 +1,12 @@ +PACKAGE= tests + +ATF_TESTS_CXX+= pidfile_test +ATF_TESTS_CXX+= stringf_test +ATF_TESTS_CXX+= up_test + +CFLAGS+= -I${SRCTOP}/lib/libutil++ +LIBADD+= util++ + +LIBADD.pidfile_test+= util + +.include <bsd.test.mk> diff --git a/lib/libutil++/tests/pidfile_test.cc b/lib/libutil++/tests/pidfile_test.cc new file mode 100644 index 000000000000..067f10e8fab8 --- /dev/null +++ b/lib/libutil++/tests/pidfile_test.cc @@ -0,0 +1,44 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Chelsio Communications, Inc. + * Written by: John Baldwin <jhb@FreeBSD.org> + */ + +#include <atf-c++.hpp> +#include <sys/stat.h> +#include <libutil.h> + +#include <libutil++.hh> + +ATF_TEST_CASE_WITHOUT_HEAD(basic); +ATF_TEST_CASE_BODY(basic) +{ + pid_t other; + struct pidfh *pfh = pidfile_open("test_pidfile", 0600, &other); + ATF_REQUIRE(pfh != nullptr); + ATF_REQUIRE(pidfile_fileno(pfh) >= 0); + + struct stat sb; + ATF_REQUIRE(fstat(pidfile_fileno(pfh), &sb) == 0); + ATF_REQUIRE_EQ(0, sb.st_size); + + freebsd::pidfile pf(pfh); + ATF_REQUIRE_EQ(pidfile_fileno(pfh), pf.fileno()); + + ATF_REQUIRE(pf.write() == 0); + + ATF_REQUIRE(fstat(pf.fileno(), &sb) == 0); + ATF_REQUIRE(sb.st_size > 0); + + ATF_REQUIRE(pf.close() == 0); + ATF_REQUIRE(pf.fileno() == -1); + ATF_REQUIRE_EQ(EDOOFUS, errno); + + ATF_REQUIRE(unlink("test_pidfile") == 0); +} + +ATF_INIT_TEST_CASES(tcs) +{ + ATF_ADD_TEST_CASE(tcs, basic); +} diff --git a/lib/libutil++/tests/stringf_test.cc b/lib/libutil++/tests/stringf_test.cc new file mode 100644 index 000000000000..5b8ef4ad54a9 --- /dev/null +++ b/lib/libutil++/tests/stringf_test.cc @@ -0,0 +1,52 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Chelsio Communications, Inc. + * Written by: John Baldwin <jhb@FreeBSD.org> + */ + +#include <atf-c++.hpp> +#include <stdarg.h> +#include <stdio.h> + +#include <libutil++.hh> + +ATF_TEST_CASE_WITHOUT_HEAD(basic); +ATF_TEST_CASE_BODY(basic) +{ + ATF_REQUIRE_EQ("foo", freebsd::stringf("foo")); + ATF_REQUIRE_EQ("bar", freebsd::stringf("%s", "bar")); + ATF_REQUIRE_EQ("42", freebsd::stringf("%u", 42)); + ATF_REQUIRE_EQ("0xdeadbeef", freebsd::stringf("%#x", 0xdeadbeef)); + ATF_REQUIRE_EQ("", freebsd::stringf("")); + ATF_REQUIRE_EQ("this is a test", freebsd::stringf("this %s test", + "is a")); +} + +static std::string +stringv(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + std::string str = freebsd::stringf(fmt, ap); + va_end(ap); + return (str); +} + +ATF_TEST_CASE_WITHOUT_HEAD(va_list); +ATF_TEST_CASE_BODY(va_list) +{ + ATF_REQUIRE_EQ("foo", stringv("foo")); + ATF_REQUIRE_EQ("bar", stringv("%s", "bar")); + ATF_REQUIRE_EQ("42", stringv("%u", 42)); + ATF_REQUIRE_EQ("0xdeadbeef", stringv("%#x", 0xdeadbeef)); + ATF_REQUIRE_EQ("", stringv("")); + ATF_REQUIRE_EQ("this is a test", stringv("this %s test", "is a")); +} + +ATF_INIT_TEST_CASES(tcs) +{ + ATF_ADD_TEST_CASE(tcs, basic); + ATF_ADD_TEST_CASE(tcs, va_list); +} diff --git a/lib/libutil++/tests/up_test.cc b/lib/libutil++/tests/up_test.cc new file mode 100644 index 000000000000..3f344054c334 --- /dev/null +++ b/lib/libutil++/tests/up_test.cc @@ -0,0 +1,33 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Chelsio Communications, Inc. + * Written by: John Baldwin <jhb@FreeBSD.org> + */ + +#include <atf-c++.hpp> +#include <libutil.h> + +#include <libutil++.hh> + +ATF_TEST_CASE_WITHOUT_HEAD(FILE_up); +ATF_TEST_CASE_BODY(FILE_up) +{ + FILE *fp = fopen("/dev/null", "r"); + ATF_REQUIRE(fp != NULL); + ATF_REQUIRE(fileno(fp) != -1); + + freebsd::FILE_up f(fp); + ATF_REQUIRE_EQ(fileno(fp), fileno(f.get())); + + f.reset(); + ATF_REQUIRE_EQ(f.get(), nullptr); + + ATF_REQUIRE_EQ(-1, fileno(fp)); + ATF_REQUIRE_EQ(EBADF, errno); +} + +ATF_INIT_TEST_CASES(tcs) +{ + ATF_ADD_TEST_CASE(tcs, FILE_up); +} |