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> 12*7be913e0SJohn 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 { 27b3127a2dSJohn 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 { 4122ce7be7SJohn 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: 72937e92b5SJohn Baldwin fd_up() : fd(-1) {} 73937e92b5SJohn Baldwin fd_up(int fd) : fd(fd) {} 74937e92b5SJohn Baldwin fd_up(fd_up &&other) : fd(other.release()) {} 75937e92b5SJohn Baldwin fd_up(fd_up const &) = delete; 76937e92b5SJohn Baldwin 77937e92b5SJohn Baldwin ~fd_up() { reset(); } 78937e92b5SJohn Baldwin 79937e92b5SJohn Baldwin int get() const { return (fd); } 80937e92b5SJohn Baldwin 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 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 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 107937e92b5SJohn Baldwin fd_up &operator=(int newfd) 108937e92b5SJohn Baldwin { 109937e92b5SJohn Baldwin reset(newfd); 110937e92b5SJohn Baldwin return *this; 111937e92b5SJohn Baldwin } 112937e92b5SJohn Baldwin 113937e92b5SJohn Baldwin explicit operator bool() const { return fd >= 0; } 114937e92b5SJohn 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 { 127b3127a2dSJohn 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 { 14163ffcf69SJohn 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 /* 150*7be913e0SJohn Baldwin * A wrapper class for the pidfile_* API. The destructor 151*7be913e0SJohn Baldwin * calls pidfile_remove() when an object is destroyed. This 152*7be913e0SJohn Baldwin * class is similar to std::unique_ptr<> in that it retains 153*7be913e0SJohn Baldwin * exclusive ownership of the pidfh object. 154*7be913e0SJohn Baldwin * 155*7be913e0SJohn Baldwin * In addition to release() and reset methods(), write(), 156*7be913e0SJohn Baldwin * close(), and fileno() methods are provided as wrappers for 157*7be913e0SJohn Baldwin * pidfile_*. 158*7be913e0SJohn Baldwin */ 159*7be913e0SJohn Baldwin class pidfile { 160*7be913e0SJohn Baldwin public: 161*7be913e0SJohn Baldwin pidfile() = default; 162*7be913e0SJohn Baldwin pidfile(struct pidfh *pfh) : pfh(pfh) {} 163*7be913e0SJohn Baldwin pidfile(pidfile &&other) : pfh(other.release()) {} 164*7be913e0SJohn Baldwin pidfile(pidfile const &) = delete; 165*7be913e0SJohn Baldwin 166*7be913e0SJohn Baldwin ~pidfile() { reset(); } 167*7be913e0SJohn Baldwin 168*7be913e0SJohn Baldwin struct pidfh *release() 169*7be913e0SJohn Baldwin { 170*7be913e0SJohn Baldwin struct pidfh *oldpfh = pfh; 171*7be913e0SJohn Baldwin 172*7be913e0SJohn Baldwin pfh = nullptr; 173*7be913e0SJohn Baldwin return (oldpfh); 174*7be913e0SJohn Baldwin } 175*7be913e0SJohn Baldwin 176*7be913e0SJohn Baldwin void reset(struct pidfh *newpfh = nullptr) 177*7be913e0SJohn Baldwin { 178*7be913e0SJohn Baldwin if (pfh != nullptr) 179*7be913e0SJohn Baldwin pidfile_remove(pfh); 180*7be913e0SJohn Baldwin pfh = newpfh; 181*7be913e0SJohn Baldwin } 182*7be913e0SJohn Baldwin 183*7be913e0SJohn Baldwin int write() 184*7be913e0SJohn Baldwin { 185*7be913e0SJohn Baldwin return (pidfile_write(pfh)); 186*7be913e0SJohn Baldwin } 187*7be913e0SJohn Baldwin 188*7be913e0SJohn Baldwin int close() 189*7be913e0SJohn Baldwin { 190*7be913e0SJohn Baldwin int rv = pidfile_close(pfh); 191*7be913e0SJohn Baldwin if (rv == 0) 192*7be913e0SJohn Baldwin pfh = nullptr; 193*7be913e0SJohn Baldwin return (rv); 194*7be913e0SJohn Baldwin } 195*7be913e0SJohn Baldwin 196*7be913e0SJohn Baldwin int fileno() 197*7be913e0SJohn Baldwin { 198*7be913e0SJohn Baldwin return (pidfile_fileno(pfh)); 199*7be913e0SJohn Baldwin } 200*7be913e0SJohn Baldwin 201*7be913e0SJohn Baldwin pidfile &operator=(pidfile &&other) noexcept 202*7be913e0SJohn Baldwin { 203*7be913e0SJohn Baldwin if (this == &other) 204*7be913e0SJohn Baldwin return *this; 205*7be913e0SJohn Baldwin reset(other.release()); 206*7be913e0SJohn Baldwin return *this; 207*7be913e0SJohn Baldwin } 208*7be913e0SJohn Baldwin 209*7be913e0SJohn Baldwin pidfile &operator=(pidfile const &) = delete; 210*7be913e0SJohn Baldwin 211*7be913e0SJohn Baldwin pidfile &operator=(struct pidfh *newpfh) 212*7be913e0SJohn Baldwin { 213*7be913e0SJohn Baldwin reset(newpfh); 214*7be913e0SJohn Baldwin return *this; 215*7be913e0SJohn Baldwin } 216*7be913e0SJohn Baldwin 217*7be913e0SJohn Baldwin explicit operator bool() const { return pfh != nullptr; } 218*7be913e0SJohn Baldwin private: 219*7be913e0SJohn Baldwin struct pidfh *pfh = nullptr; 220*7be913e0SJohn Baldwin }; 221*7be913e0SJohn Baldwin 222*7be913e0SJohn 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