xref: /freebsd/lib/libutil++/libutil++.hh (revision ca0d182dfeb68405cfba002622787adb10cfe7a0)
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