1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2025 Chelsio Communications, Inc. 5 * Written by: John Baldwin <jhb@FreeBSD.org> 6 */ 7 8 #ifndef __LIBUTILPP_HH__ 9 #define __LIBUTILPP_HH__ 10 11 #include <sys/nv.h> 12 #include <libutil.h> 13 #include <netdb.h> 14 #include <unistd.h> 15 16 #include <cstdarg> 17 #include <cstdio> 18 #include <cstdlib> 19 #include <memory> 20 21 namespace freebsd { 22 /* 23 * FILE_up is a std::unique_ptr<> for FILE objects which uses 24 * fclose() to destroy the wrapped pointer. 25 */ 26 struct fclose_deleter { operator ()freebsd::fclose_deleter27 void operator() (std::FILE *fp) const 28 { 29 std::fclose(fp); 30 } 31 }; 32 33 using FILE_up = std::unique_ptr<std::FILE, fclose_deleter>; 34 35 /* 36 * addrinfo_up is a std::unique_ptr<> which uses 37 * freeaddrinfo() to destroy the wrapped pointer. It is 38 * intended to wrap arrays allocated by getaddrinfo(). 39 */ 40 struct freeaddrinfo_deleter { operator ()freebsd::freeaddrinfo_deleter41 void operator() (struct addrinfo *ai) const 42 { 43 freeaddrinfo(ai); 44 } 45 }; 46 47 using addrinfo_up = std::unique_ptr<addrinfo, freeaddrinfo_deleter>; 48 49 /* 50 * This class is intended to function similar to unique_ptr<>, 51 * but it contains a file descriptor rather than a pointer to 52 * an object. On destruction the descriptor is closed via 53 * close(2). 54 * 55 * Similar to unique_ptr<>, release() returns ownership of the 56 * file descriptor to the caller. reset() closes the current 57 * file descriptor and takes ownership of a new one. A move 58 * constructor permits ownership to be transferred via 59 * std::move(). An integer file descriptor can be assigned 60 * directly which is equivalent to calling reset(). 61 * 62 * An explicit bool conversion operator permits testing this 63 * class in logical expressions. It returns true if it 64 * contains a valid descriptor. 65 * 66 * An implicit int conversion operator returns the underlying 67 * file descriptor allowing objects of this type to be passed 68 * directly to APIs such as connect(), listen(), etc. 69 */ 70 class fd_up { 71 public: fd_up()72 fd_up() : fd(-1) {} fd_up(int _fd)73 fd_up(int _fd) : fd(_fd) {} fd_up(fd_up && other)74 fd_up(fd_up &&other) : fd(other.release()) {} 75 fd_up(fd_up const &) = delete; 76 ~fd_up()77 ~fd_up() { reset(); } 78 get() const79 int get() const { return (fd); } 80 release()81 int release() 82 { 83 int oldfd = fd; 84 85 fd = -1; 86 return (oldfd); 87 } 88 reset(int newfd=-1)89 void reset(int newfd = -1) 90 { 91 if (fd >= 0) 92 close(fd); 93 fd = newfd; 94 } 95 operator =(fd_up && other)96 fd_up &operator=(fd_up &&other) noexcept 97 { 98 if (this == &other) 99 return *this; 100 101 reset(other.release()); 102 return *this; 103 } 104 105 fd_up &operator=(fd_up const &) = delete; 106 operator =(int newfd)107 fd_up &operator=(int newfd) 108 { 109 reset(newfd); 110 return *this; 111 } 112 operator bool() const113 explicit operator bool() const { return fd >= 0; } operator int() const114 operator int() const { return fd; } 115 private: 116 int fd; 117 }; 118 119 /* 120 * malloc_up<T> is a std::unique_ptr<> which uses free() to 121 * destroy the wrapped pointer. This can be used to wrap 122 * pointers allocated implicitly by malloc() such as those 123 * returned by strdup(). 124 */ 125 template <class T> 126 struct free_deleter { operator ()freebsd::free_deleter127 void operator() (T *p) const 128 { 129 std::free(p); 130 } 131 }; 132 133 template <class T> 134 using malloc_up = std::unique_ptr<T, free_deleter<T>>; 135 136 /* 137 * nvlist_up is a std::unique_ptr<> for nvlist_t objects which 138 * uses nvlist_destroy() to destroy the wrapped pointer. 139 */ 140 struct nvlist_deleter { operator ()freebsd::nvlist_deleter141 void operator() (nvlist_t *nvl) const 142 { 143 nvlist_destroy(nvl); 144 } 145 }; 146 147 using nvlist_up = std::unique_ptr<nvlist_t, nvlist_deleter>; 148 149 /* 150 * A wrapper class for the pidfile_* API. The destructor 151 * calls pidfile_remove() when an object is destroyed. This 152 * class is similar to std::unique_ptr<> in that it retains 153 * exclusive ownership of the pidfh object. 154 * 155 * In addition to release() and reset methods(), write(), 156 * close(), and fileno() methods are provided as wrappers for 157 * pidfile_*. 158 */ 159 class pidfile { 160 public: 161 pidfile() = default; pidfile(struct pidfh * _pfh)162 pidfile(struct pidfh *_pfh) : pfh(_pfh) {} pidfile(pidfile && other)163 pidfile(pidfile &&other) : pfh(other.release()) {} 164 pidfile(pidfile const &) = delete; 165 ~pidfile()166 ~pidfile() { reset(); } 167 release()168 struct pidfh *release() 169 { 170 struct pidfh *oldpfh = pfh; 171 172 pfh = nullptr; 173 return (oldpfh); 174 } 175 reset(struct pidfh * newpfh=nullptr)176 void reset(struct pidfh *newpfh = nullptr) 177 { 178 if (pfh != nullptr) 179 pidfile_remove(pfh); 180 pfh = newpfh; 181 } 182 write()183 int write() 184 { 185 return (pidfile_write(pfh)); 186 } 187 close()188 int close() 189 { 190 int rv = pidfile_close(pfh); 191 if (rv == 0) 192 pfh = nullptr; 193 return (rv); 194 } 195 fileno()196 int fileno() 197 { 198 return (pidfile_fileno(pfh)); 199 } 200 operator =(pidfile && other)201 pidfile &operator=(pidfile &&other) noexcept 202 { 203 if (this == &other) 204 return *this; 205 reset(other.release()); 206 return *this; 207 } 208 209 pidfile &operator=(pidfile const &) = delete; 210 operator =(struct pidfh * newpfh)211 pidfile &operator=(struct pidfh *newpfh) 212 { 213 reset(newpfh); 214 return *this; 215 } 216 operator bool() const217 explicit operator bool() const { return pfh != nullptr; } 218 private: 219 struct pidfh *pfh = nullptr; 220 }; 221 222 /* 223 * Returns a std::string containing the same output as 224 * sprintf(). Throws std::bad_alloc if an error occurs. 225 */ 226 std::string stringf(const char *fmt, ...) __printflike(1, 2); 227 std::string stringf(const char *fmt, std::va_list ap); 228 } 229 230 #endif /* !__LIBUTILPP_HH__ */ 231