1b3127a2dSJohn Baldwin /*- 2b3127a2dSJohn Baldwin * SPDX-License-Identifier: BSD-2-Clause 3b3127a2dSJohn Baldwin * 4b3127a2dSJohn Baldwin * Copyright (c) 2025 Chelsio Communications, Inc. 5b3127a2dSJohn Baldwin * Written by: John Baldwin <jhb@FreeBSD.org> 6b3127a2dSJohn Baldwin */ 7b3127a2dSJohn Baldwin 8b3127a2dSJohn Baldwin #ifndef __LIBUTILPP_HH__ 9b3127a2dSJohn Baldwin #define __LIBUTILPP_HH__ 10b3127a2dSJohn Baldwin 1163ffcf69SJohn Baldwin #include <sys/nv.h> 127be913e0SJohn Baldwin #include <libutil.h> 1322ce7be7SJohn Baldwin #include <netdb.h> 14937e92b5SJohn Baldwin #include <unistd.h> 1522ce7be7SJohn Baldwin 16b3127a2dSJohn Baldwin #include <cstdarg> 17b3127a2dSJohn Baldwin #include <cstdio> 18b3127a2dSJohn Baldwin #include <cstdlib> 19b3127a2dSJohn Baldwin #include <memory> 20b3127a2dSJohn Baldwin 21b3127a2dSJohn Baldwin namespace freebsd { 22b3127a2dSJohn Baldwin /* 23b3127a2dSJohn Baldwin * FILE_up is a std::unique_ptr<> for FILE objects which uses 24b3127a2dSJohn Baldwin * fclose() to destroy the wrapped pointer. 25b3127a2dSJohn Baldwin */ 26b3127a2dSJohn Baldwin struct fclose_deleter { operator ()freebsd::fclose_deleter27b3127a2dSJohn Baldwin void operator() (std::FILE *fp) const 28b3127a2dSJohn Baldwin { 29b3127a2dSJohn Baldwin std::fclose(fp); 30b3127a2dSJohn Baldwin } 31b3127a2dSJohn Baldwin }; 32b3127a2dSJohn Baldwin 33b3127a2dSJohn Baldwin using FILE_up = std::unique_ptr<std::FILE, fclose_deleter>; 34b3127a2dSJohn Baldwin 35b3127a2dSJohn Baldwin /* 3622ce7be7SJohn Baldwin * addrinfo_up is a std::unique_ptr<> which uses 3722ce7be7SJohn Baldwin * freeaddrinfo() to destroy the wrapped pointer. It is 3822ce7be7SJohn Baldwin * intended to wrap arrays allocated by getaddrinfo(). 3922ce7be7SJohn Baldwin */ 4022ce7be7SJohn Baldwin struct freeaddrinfo_deleter { operator ()freebsd::freeaddrinfo_deleter4122ce7be7SJohn Baldwin void operator() (struct addrinfo *ai) const 4222ce7be7SJohn Baldwin { 4322ce7be7SJohn Baldwin freeaddrinfo(ai); 4422ce7be7SJohn Baldwin } 4522ce7be7SJohn Baldwin }; 4622ce7be7SJohn Baldwin 4722ce7be7SJohn Baldwin using addrinfo_up = std::unique_ptr<addrinfo, freeaddrinfo_deleter>; 4822ce7be7SJohn Baldwin 4922ce7be7SJohn Baldwin /* 50937e92b5SJohn Baldwin * This class is intended to function similar to unique_ptr<>, 51937e92b5SJohn Baldwin * but it contains a file descriptor rather than a pointer to 52937e92b5SJohn Baldwin * an object. On destruction the descriptor is closed via 53937e92b5SJohn Baldwin * close(2). 54937e92b5SJohn Baldwin * 55937e92b5SJohn Baldwin * Similar to unique_ptr<>, release() returns ownership of the 56937e92b5SJohn Baldwin * file descriptor to the caller. reset() closes the current 57937e92b5SJohn Baldwin * file descriptor and takes ownership of a new one. A move 58937e92b5SJohn Baldwin * constructor permits ownership to be transferred via 59937e92b5SJohn Baldwin * std::move(). An integer file descriptor can be assigned 60937e92b5SJohn Baldwin * directly which is equivalent to calling reset(). 61937e92b5SJohn Baldwin * 62937e92b5SJohn Baldwin * An explicit bool conversion operator permits testing this 63937e92b5SJohn Baldwin * class in logical expressions. It returns true if it 64937e92b5SJohn Baldwin * contains a valid descriptor. 65937e92b5SJohn Baldwin * 66937e92b5SJohn Baldwin * An implicit int conversion operator returns the underlying 67937e92b5SJohn Baldwin * file descriptor allowing objects of this type to be passed 68937e92b5SJohn Baldwin * directly to APIs such as connect(), listen(), etc. 69937e92b5SJohn Baldwin */ 70937e92b5SJohn Baldwin class fd_up { 71937e92b5SJohn Baldwin public: fd_up()72937e92b5SJohn Baldwin fd_up() : fd(-1) {} fd_up(int _fd)73*ca0d182dSJohn Baldwin fd_up(int _fd) : fd(_fd) {} fd_up(fd_up && other)74937e92b5SJohn Baldwin fd_up(fd_up &&other) : fd(other.release()) {} 75937e92b5SJohn Baldwin fd_up(fd_up const &) = delete; 76937e92b5SJohn Baldwin ~fd_up()77937e92b5SJohn Baldwin ~fd_up() { reset(); } 78937e92b5SJohn Baldwin get() const79937e92b5SJohn Baldwin int get() const { return (fd); } 80937e92b5SJohn Baldwin release()81937e92b5SJohn Baldwin int release() 82937e92b5SJohn Baldwin { 83937e92b5SJohn Baldwin int oldfd = fd; 84937e92b5SJohn Baldwin 85937e92b5SJohn Baldwin fd = -1; 86937e92b5SJohn Baldwin return (oldfd); 87937e92b5SJohn Baldwin } 88937e92b5SJohn Baldwin reset(int newfd=-1)89937e92b5SJohn Baldwin void reset(int newfd = -1) 90937e92b5SJohn Baldwin { 91937e92b5SJohn Baldwin if (fd >= 0) 92937e92b5SJohn Baldwin close(fd); 93937e92b5SJohn Baldwin fd = newfd; 94937e92b5SJohn Baldwin } 95937e92b5SJohn Baldwin operator =(fd_up && other)96937e92b5SJohn Baldwin fd_up &operator=(fd_up &&other) noexcept 97937e92b5SJohn Baldwin { 98937e92b5SJohn Baldwin if (this == &other) 99937e92b5SJohn Baldwin return *this; 100937e92b5SJohn Baldwin 101937e92b5SJohn Baldwin reset(other.release()); 102937e92b5SJohn Baldwin return *this; 103937e92b5SJohn Baldwin } 104937e92b5SJohn Baldwin 105937e92b5SJohn Baldwin fd_up &operator=(fd_up const &) = delete; 106937e92b5SJohn Baldwin operator =(int newfd)107937e92b5SJohn Baldwin fd_up &operator=(int newfd) 108937e92b5SJohn Baldwin { 109937e92b5SJohn Baldwin reset(newfd); 110937e92b5SJohn Baldwin return *this; 111937e92b5SJohn Baldwin } 112937e92b5SJohn Baldwin operator bool() const113937e92b5SJohn Baldwin explicit operator bool() const { return fd >= 0; } operator int() const114937e92b5SJohn Baldwin operator int() const { return fd; } 115937e92b5SJohn Baldwin private: 116937e92b5SJohn Baldwin int fd; 117937e92b5SJohn Baldwin }; 118937e92b5SJohn Baldwin 119937e92b5SJohn Baldwin /* 120b3127a2dSJohn Baldwin * malloc_up<T> is a std::unique_ptr<> which uses free() to 121b3127a2dSJohn Baldwin * destroy the wrapped pointer. This can be used to wrap 122b3127a2dSJohn Baldwin * pointers allocated implicitly by malloc() such as those 123b3127a2dSJohn Baldwin * returned by strdup(). 124b3127a2dSJohn Baldwin */ 125b3127a2dSJohn Baldwin template <class T> 126b3127a2dSJohn Baldwin struct free_deleter { operator ()freebsd::free_deleter127b3127a2dSJohn Baldwin void operator() (T *p) const 128b3127a2dSJohn Baldwin { 129b3127a2dSJohn Baldwin std::free(p); 130b3127a2dSJohn Baldwin } 131b3127a2dSJohn Baldwin }; 132b3127a2dSJohn Baldwin 133b3127a2dSJohn Baldwin template <class T> 134b3127a2dSJohn Baldwin using malloc_up = std::unique_ptr<T, free_deleter<T>>; 135b3127a2dSJohn Baldwin 136b3127a2dSJohn Baldwin /* 13763ffcf69SJohn Baldwin * nvlist_up is a std::unique_ptr<> for nvlist_t objects which 13863ffcf69SJohn Baldwin * uses nvlist_destroy() to destroy the wrapped pointer. 13963ffcf69SJohn Baldwin */ 14063ffcf69SJohn Baldwin struct nvlist_deleter { operator ()freebsd::nvlist_deleter14163ffcf69SJohn Baldwin void operator() (nvlist_t *nvl) const 14263ffcf69SJohn Baldwin { 14363ffcf69SJohn Baldwin nvlist_destroy(nvl); 14463ffcf69SJohn Baldwin } 14563ffcf69SJohn Baldwin }; 14663ffcf69SJohn Baldwin 14763ffcf69SJohn Baldwin using nvlist_up = std::unique_ptr<nvlist_t, nvlist_deleter>; 14863ffcf69SJohn Baldwin 14963ffcf69SJohn Baldwin /* 1507be913e0SJohn Baldwin * A wrapper class for the pidfile_* API. The destructor 1517be913e0SJohn Baldwin * calls pidfile_remove() when an object is destroyed. This 1527be913e0SJohn Baldwin * class is similar to std::unique_ptr<> in that it retains 1537be913e0SJohn Baldwin * exclusive ownership of the pidfh object. 1547be913e0SJohn Baldwin * 1557be913e0SJohn Baldwin * In addition to release() and reset methods(), write(), 1567be913e0SJohn Baldwin * close(), and fileno() methods are provided as wrappers for 1577be913e0SJohn Baldwin * pidfile_*. 1587be913e0SJohn Baldwin */ 1597be913e0SJohn Baldwin class pidfile { 1607be913e0SJohn Baldwin public: 1617be913e0SJohn Baldwin pidfile() = default; pidfile(struct pidfh * _pfh)162*ca0d182dSJohn Baldwin pidfile(struct pidfh *_pfh) : pfh(_pfh) {} pidfile(pidfile && other)1637be913e0SJohn Baldwin pidfile(pidfile &&other) : pfh(other.release()) {} 1647be913e0SJohn Baldwin pidfile(pidfile const &) = delete; 1657be913e0SJohn Baldwin ~pidfile()1667be913e0SJohn Baldwin ~pidfile() { reset(); } 1677be913e0SJohn Baldwin release()1687be913e0SJohn Baldwin struct pidfh *release() 1697be913e0SJohn Baldwin { 1707be913e0SJohn Baldwin struct pidfh *oldpfh = pfh; 1717be913e0SJohn Baldwin 1727be913e0SJohn Baldwin pfh = nullptr; 1737be913e0SJohn Baldwin return (oldpfh); 1747be913e0SJohn Baldwin } 1757be913e0SJohn Baldwin reset(struct pidfh * newpfh=nullptr)1767be913e0SJohn Baldwin void reset(struct pidfh *newpfh = nullptr) 1777be913e0SJohn Baldwin { 1787be913e0SJohn Baldwin if (pfh != nullptr) 1797be913e0SJohn Baldwin pidfile_remove(pfh); 1807be913e0SJohn Baldwin pfh = newpfh; 1817be913e0SJohn Baldwin } 1827be913e0SJohn Baldwin write()1837be913e0SJohn Baldwin int write() 1847be913e0SJohn Baldwin { 1857be913e0SJohn Baldwin return (pidfile_write(pfh)); 1867be913e0SJohn Baldwin } 1877be913e0SJohn Baldwin close()1887be913e0SJohn Baldwin int close() 1897be913e0SJohn Baldwin { 1907be913e0SJohn Baldwin int rv = pidfile_close(pfh); 1917be913e0SJohn Baldwin if (rv == 0) 1927be913e0SJohn Baldwin pfh = nullptr; 1937be913e0SJohn Baldwin return (rv); 1947be913e0SJohn Baldwin } 1957be913e0SJohn Baldwin fileno()1967be913e0SJohn Baldwin int fileno() 1977be913e0SJohn Baldwin { 1987be913e0SJohn Baldwin return (pidfile_fileno(pfh)); 1997be913e0SJohn Baldwin } 2007be913e0SJohn Baldwin operator =(pidfile && other)2017be913e0SJohn Baldwin pidfile &operator=(pidfile &&other) noexcept 2027be913e0SJohn Baldwin { 2037be913e0SJohn Baldwin if (this == &other) 2047be913e0SJohn Baldwin return *this; 2057be913e0SJohn Baldwin reset(other.release()); 2067be913e0SJohn Baldwin return *this; 2077be913e0SJohn Baldwin } 2087be913e0SJohn Baldwin 2097be913e0SJohn Baldwin pidfile &operator=(pidfile const &) = delete; 2107be913e0SJohn Baldwin operator =(struct pidfh * newpfh)2117be913e0SJohn Baldwin pidfile &operator=(struct pidfh *newpfh) 2127be913e0SJohn Baldwin { 2137be913e0SJohn Baldwin reset(newpfh); 2147be913e0SJohn Baldwin return *this; 2157be913e0SJohn Baldwin } 2167be913e0SJohn Baldwin operator bool() const2177be913e0SJohn Baldwin explicit operator bool() const { return pfh != nullptr; } 2187be913e0SJohn Baldwin private: 2197be913e0SJohn Baldwin struct pidfh *pfh = nullptr; 2207be913e0SJohn Baldwin }; 2217be913e0SJohn Baldwin 2227be913e0SJohn Baldwin /* 223b3127a2dSJohn Baldwin * Returns a std::string containing the same output as 224b3127a2dSJohn Baldwin * sprintf(). Throws std::bad_alloc if an error occurs. 225b3127a2dSJohn Baldwin */ 226b3127a2dSJohn Baldwin std::string stringf(const char *fmt, ...) __printflike(1, 2); 227b3127a2dSJohn Baldwin std::string stringf(const char *fmt, std::va_list ap); 228b3127a2dSJohn Baldwin } 229b3127a2dSJohn Baldwin 230b3127a2dSJohn Baldwin #endif /* !__LIBUTILPP_HH__ */ 231