From nobody Mon Aug 4 19:47:02 2025 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4bwnBb10gqz63RK4; Mon, 04 Aug 2025 19:47:03 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R10" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4bwnBZ5LKlz4KmS; Mon, 04 Aug 2025 19:47:02 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1754336822; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=5d0q0imluC36mKDidIdIAC0AoOjkpT0Al6VMJrf6VXw=; b=Ocl8x1Aa9lxzGLRkOR0hYXOhsihcv7wqc2OhXO4llLnUcxx941RzBwynge41cptMzZ35gq d+PrG56OUmZGJPfhOG1iKffZsJKZLuohsMFC1zOfzvoAum2yYJD78SrG/lwaZdFAi05lYx xYI5P1EDGKCg1XJZuM2tUShaCUGhbb9avOSVSschSfWrXs/X4kei7d7jCgys8aV33L51Il al0rbmlKhVvxwlvWje7HnmwNgVJsXExu0EFk4Vkr73iK+qF51dr62uzkMy9u/bYUnRq9ob KrhQvfshkKldZStR6OpeQfX3dPUcJI8y1odwzOiuOsyqX3Mj7RsyfvvgaeDsVg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1754336822; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=5d0q0imluC36mKDidIdIAC0AoOjkpT0Al6VMJrf6VXw=; b=qoW0rKh5i1/6xEwWR/Ii3NB2kXxxsdIXElG5uSTfK+922CIc2t0kDC6xQhi1Z3FL2+qJoq XRCl0yJ9uwZVbZqqfCxlX+iFIB1//SVNKegSOjc4Eshi1NvYCtNTHHpP6BrOcQBf5++ogp cRHBO8RD5pVuK7HYpCdBu5qS4Y6jbos9djE1qg2kCCoF6aMJlSkRRU+bXHJaUQ4shyvClz G9FGGxfVwwFuW/LWRU+HUA6KX99kOdIvV8pgNvofxyEed5DM8ELO3nnzhpL784EWNqvOug OL7RcII08xPEWoMxkgaeiInxHoCGX6Crz3rKCV4mfe0aLDia3B8+AHmQKtt9rg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1754336822; a=rsa-sha256; cv=none; b=O0E5AA4c9zcL4gX2mHSyuTx+3NwaO5u8vBLZYvYKr/RIMunvVTFm339dm8KB1IAWdMbT3o ztwwb1B1wgbFOvZxBj2U/0IyKV4khED5qKw8+0iz2CMs8IKpCzNh/YNlZD1E/WQjTgiERU uHoBpjqoQ0jpWTyc8uQqg+cBGcOAnaokRUo+jTbvVOIGbn8hvJq81G1zDUNEu5IgRFPrsS /fSjUBTl4dKgvn94N9KYCCnw8BxRn5hYrexKHeQOsJ40r3+/ev2W0Xns4OtZZgeGMILwc9 YoO/yYr/hbvXSmxW6EZxy6Sjghhu4p7kL7M/8gC0h5LiF7jtyJ98F4BRPz6igg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4bwnBZ4tlrz12nQ; Mon, 04 Aug 2025 19:47:02 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 574Jl24t099542; Mon, 4 Aug 2025 19:47:02 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 574Jl2S3099539; Mon, 4 Aug 2025 19:47:02 GMT (envelope-from git) Date: Mon, 4 Aug 2025 19:47:02 GMT Message-Id: <202508041947.574Jl2S3099539@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: John Baldwin Subject: git: 7be913e00d79 - main - libutil++: Add freebsd::pidfile wrapper class around struct pidfh List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: jhb X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 7be913e00d79b3bf740049797fbc3f6ab8193995 Auto-Submitted: auto-generated The branch main has been updated by jhb: URL: https://cgit.FreeBSD.org/src/commit/?id=7be913e00d79b3bf740049797fbc3f6ab8193995 commit 7be913e00d79b3bf740049797fbc3f6ab8193995 Author: John Baldwin AuthorDate: 2025-08-04 19:38:07 +0000 Commit: John Baldwin CommitDate: 2025-08-04 19:38:07 +0000 libutil++: Add freebsd::pidfile wrapper class around struct pidfh This class wraps the pidfile_* API from libutil. 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_*. Sponsored by: Chelsio Communications Pull Request: https://github.com/freebsd/freebsd-src/pull/1794 --- lib/libutil++/Makefile | 1 + lib/libutil++/freebsd::pidfile.3 | 110 ++++++++++++++++++++++++++++++++++++ lib/libutil++/libutil++.hh | 74 ++++++++++++++++++++++++ lib/libutil++/tests/Makefile | 3 + lib/libutil++/tests/pidfile_test.cc | 44 +++++++++++++++ 5 files changed, 232 insertions(+) diff --git a/lib/libutil++/Makefile b/lib/libutil++/Makefile index 3389e7e21b11..df3074c2278e 100644 --- a/lib/libutil++/Makefile +++ b/lib/libutil++/Makefile @@ -9,6 +9,7 @@ MAN+= freebsd::FILE_up.3 \ freebsd::fd_up.3 \ freebsd::malloc_up.3 \ freebsd::nvlist_up.3 \ + freebsd::pidfile.3 \ freebsd::stringf.3 .include 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 +.\" +.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++/libutil++.hh b/lib/libutil++/libutil++.hh index 121633c4deea..ecf737f2fcb0 100644 --- a/lib/libutil++/libutil++.hh +++ b/lib/libutil++/libutil++.hh @@ -9,6 +9,7 @@ #define __LIBUTILPP_HH__ #include +#include #include #include @@ -145,6 +146,79 @@ namespace freebsd { using nvlist_up = std::unique_ptr; + /* + * 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. diff --git a/lib/libutil++/tests/Makefile b/lib/libutil++/tests/Makefile index 81b7be4f5660..e7720d122f36 100644 --- a/lib/libutil++/tests/Makefile +++ b/lib/libutil++/tests/Makefile @@ -1,9 +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 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 + */ + +#include +#include +#include + +#include + +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); +}