diff options
75 files changed, 939 insertions, 1209 deletions
diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index 2550c5ab3d12..e81cb57152ae 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -55,6 +55,9 @@ OLD_FILES+=usr/bin/lesskey OLD_FILES+=usr/share/man/man1/lesskey.1.gz +# 20260921: atf-0.26 release +OLD_FILES+=usr/share/doc/atf/README + # 20260813: lib9p.so becomes a private library OLD_LIBS+=usr/lib/lib9p.so.1 diff --git a/contrib/atf/.cirrus.yml b/contrib/atf/.cirrus.yml deleted file mode 100644 index fd9b6e4a47df..000000000000 --- a/contrib/atf/.cirrus.yml +++ /dev/null @@ -1,26 +0,0 @@ -env: - CIRRUS_CLONE_DEPTH: 1 - ARCH: amd64 - -task: - matrix: - - name: 13.0-CURRENT - freebsd_instance: - image_family: freebsd-13-0-snap - - name: 12.2-STABLE - freebsd_instance: - image_family: freebsd-12-2-snap - - name: 12.1-RELEASE - freebsd_instance: - image_family: freebsd-12-1 - install_script: - - sed -i.bak -e 's,pkg+http://pkg.FreeBSD.org/\${ABI}/quarterly,pkg+http://pkg.FreeBSD.org/\${ABI}/latest,' /etc/pkg/FreeBSD.conf - - ASSUME_ALWAYS_YES=yes pkg bootstrap -f - - pkg install -y autoconf automake libtool kyua - script: - - env JUNIT_OUTPUT=$(pwd)/test-results.xml ./admin/travis-build.sh - always: - junit_artifacts: - path: "test-results.xml" - type: text/xml - format: junit diff --git a/contrib/atf/.gitignore b/contrib/atf/.gitignore deleted file mode 100644 index 396785ce2052..000000000000 --- a/contrib/atf/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -*.la -*.lo -*.o -*.pc -*_helper -*_helpers -*_test -.deps -.dirstamp -.libs - -Makefile -Makefile.in -aclocal.m4 -autom4te.cache -config.h -config.h.in -config.h.in~ -config.log -config.status -configure -installcheck.log -libtool -stamp-h1 -testsuite.log diff --git a/contrib/atf/.travis.yml b/contrib/atf/.travis.yml deleted file mode 100644 index 1949aae54468..000000000000 --- a/contrib/atf/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -language: cpp - -compiler: - - gcc - - clang - -before_install: - - ./admin/travis-install-deps.sh - -env: - - ARCH=amd64 AS_ROOT=no - - ARCH=amd64 AS_ROOT=yes - - ARCH=i386 AS_ROOT=no - -matrix: - exclude: - - compiler: clang - env: ARCH=i386 AS_ROOT=no - -script: - - ./admin/travis-build.sh - -notifications: - email: - - atf-log@googlegroups.com diff --git a/contrib/atf/FREEBSD-Xlist b/contrib/atf/FREEBSD-Xlist index 05ea871eb95c..06fef93a4024 100644 --- a/contrib/atf/FREEBSD-Xlist +++ b/contrib/atf/FREEBSD-Xlist @@ -2,7 +2,7 @@ */Makefile* */*.m4 */*.pc.in -INSTALL +INSTALL.md Makefile* aclocal.m4 admin/ diff --git a/contrib/atf/NEWS b/contrib/atf/NEWS index 671ee81ff6ff..e1c9e5f512f5 100644 --- a/contrib/atf/NEWS +++ b/contrib/atf/NEWS @@ -1,26 +1,140 @@ -Major changes between releases Automated Testing Framework -=========================================================================== +# Major changes between releases + +## Changes in version 0.26 + +Released on 2026/09/22. + +### Developer Workflow Changes + +* #189: Automate uploading release assets +* #190: INSTALL.md: sync content with version from lutok +* #191: [CI] Minor tweaks + +### Feature Enhancements + +* #192: Add kmod support on FreeBSD + +**Full Changelog**: https://github.com/freebsd/atf/compare/atf-0.25...atf-0.26 + +## Changes in version 0.25 + +Released on 2026/09/02. + +### Bugfixes +* #187: Fix the build on NetBSD by renaming a variable added in version 0.24. + +### Developer Workflow Changes +* #185: The version of LLVM used in macOS runners was bumped from 19 to 20 + +**Full Changelog**: https://github.com/freebsd/atf/compare/atf-0.24...atf-0.25 + +## Changes in version 0.24 + +Released on August, 17, 2026 + +### Major Changes +* This version of ATF requires C++-20 to build/function. +* This version of ATF focused heavily on correctness and memory management + issues discussed in #77. While most of the issues are believed to be resolved, + some issues may still remain. +* The `atf::text::duplicate(..)` API and tests were removed. + +### Feature Enhancements +* Issue #105: Widen our process status capabilties + +### Docs +* Issue #107: Clarify the semantics of ATF_{CHECK,REQUIRE}_ERRNO() +* Issue #124: atf-check.1: Add missing -r flag to synopsis +* Issue #127: atf-c.3: Fix test case addition in ATF_TP_ADD_TCS synopsis example + +### Developer Workflow Changes +* GitHub Actions support was added. +* Cirrus CI support was removed. +* FreeBSD vmactions CI support was added. +* ASAN/LSAN/UBSAN support was added for Linux and macOS. +* (Initial) runtime code coverage support was added. +* (Initial) pre-commit support was added. + +**Full Changelog**: https://github.com/freebsd/atf/compare/atf-0.23...atf-0.24 + +## Changes in version 0.23 + +Released on March, 29, 2025 -Changes in version 0.22 -*********************** +* Issue #101: fix release tarballs by using `make dist` instead of + alternative ad hoc method. -STILL UNDER DEVELOPMENT; NOT RELEASED YET. -DON'T FORGET TO BUMP THE -version-info PRE-RELEASE IF NECESSARY! +* Issue #76: `atf_check`: fix `std::length_error` thrown from `temp_file`. + +* #87: Update documentation/build files to point to FreeBSD repo/mailing lists. + +* #86: Improve diagnostics when paths cannot be opened + +* #85: various build-related changes. Highlights: + * Remove leftover references of `auto_array` (bugfix). + * Remove the `atf-*-api` manpages (enhancement). + * Require -std=C++14 with ATF (enhancement). + * Expose `WCOREDUMP(..)` on platforms that support it (bugfix). + * Add `__attribute__((nonnull))` support (enhancement). + * Restore `AC_PROG_CPP` (bugfix). + +### General fixes + +* Fix various style issues which were blocking `make dist` from completing + cleanly. + +* Fix `atf_utils_file_exists` declaration in atf-c(3). + +* Fix various memory leaks and logic errors. + +* `atf-test-case(4)`: update reference to the "descr" metadata property so it's + marked Optional. + +* `atf-check.cpp`: remove unnecessary data copy in `temp_file`. + +## Changes in version 0.22 + +Released on November 25th, 2024. * Issue #23: Fix double-free triggered by atf_map_insert in low memory scenarios, caused by an overlook in the atf_list code. -* Issue #29: Fixed various typos and formatting errors in manual pages. - * Issue #31: Added require.progs metadata properties to the tests that need a compiler to run. * Added the atf_check_not_equal function to atf-sh to check for unequal values. +* Add `-r timeout` flag to `atf-check`. + +* Open results files before executing tests to fix an issue ATF tests that + adjust the processes' Capsicum rights as part of the testcase(s) + executed. + +* Add Cirrus CI integration for FreeBSD CI/CD support. + +* Address compilation issues on OpenSolaris distributions. + +* Replace `auto_array` with `std::vector` (fixes modern C++ compliance). + +* Replace `auto_ptr` with `std::unique_ptr` (fixes modern C++ compliance). + +* Update autotools idioms and requirements. The minimum required version of + autoconf is now 2.68. + +* Modify `ATF_CHECK*` and `ATF_REQUIRE*` macros to avoid double + evaluation/allow the gcc toolchain to detect accidental single + assignment typos. + +* Always define CPP to fix use of ATF_BUILD_CPP when the user did not + define CPP when invoking the configure script. + +### General fixes + +* Fix various typos and formatting errors in manual pages and markdown + documents. -Changes in version 0.21 -*********************** +## Changes in version 0.21 Released on October 23rd, 2014. @@ -76,8 +190,7 @@ Released on October 23rd, 2014. * Issue #19: Removed stale references to atf-config and atf-run. -Changes in version 0.20 -*********************** +## Changes in version 0.20 Experimental version released on February 7th, 2014. @@ -92,8 +205,7 @@ the 'tools' directory for your own consumption. that ships with FreeBSD 11.0-CURRENT. -Changes in version 0.19 -*********************** +## Changes in version 0.19 Experimental version released on February 7th, 2014. @@ -112,7 +224,7 @@ does not depend on any internal details of atf-c++ any longer. * Project hosting moved from Google Code (as a subproject of Kyua) to GitHub (as a first-class project). The main reason for the change is the suppression of binary downloads in Google Code on Jan 15th, 2014. - See https://github.com/jmmv/atf/ + See https://github.com/freebsd/atf/ * Removed builtin help from atf-sh(1) and atf-check(1) for simplicity reasons. In other words, their -h option is gone. @@ -124,8 +236,7 @@ does not depend on any internal details of atf-c++ any longer. atf-c++ would break the stale tools. -Changes in version 0.18 -*********************** +## Changes in version 0.18 Experimental version released on November 16th, 2013. @@ -142,8 +253,7 @@ Experimental version released on November 16th, 2013. * NetBSD PR bin/48285: Fixed atf_check examples in atf-sh-api(3). -Changes in version 0.17 -*********************** +## Changes in version 0.17 Experimental version released on February 14th, 2013. @@ -176,8 +286,7 @@ Experimental version released on February 14th, 2013. cases from breaking xsltproc later. -Changes in version 0.16 -*********************** +## Changes in version 0.16 Experimental version released on July 10th, 2012. @@ -211,8 +320,7 @@ Experimental version released on July 10th, 2012. lives in a subcomponent of the Kyua project. -Changes in version 0.15 -*********************** +## Changes in version 0.15 Experimental version released on January 16th, 2012. @@ -248,8 +356,7 @@ Experimental version released on January 16th, 2012. mangle our report. -Changes in version 0.14 -*********************** +## Changes in version 0.14 Experimental version released on June 14th, 2011. @@ -277,8 +384,7 @@ Experimental version released on June 14th, 2011. case to run. -Changes in version 0.13 -*********************** +## Changes in version 0.13 Experimental version released on March 31st, 2011. @@ -323,8 +429,7 @@ The changes in this release are: instead of just listing them as having 0 test cases. -Changes in version 0.12 -*********************** +## Changes in version 0.12 Experimental version released on November 7th, 2010. @@ -359,8 +464,7 @@ Experimental version released on November 7th, 2010. general, not be blindly run as root in the first place. -Changes in version 0.11 -*********************** +## Changes in version 0.11 Experimental version released on October 20th, 2010. @@ -382,8 +486,7 @@ Experimental version released on October 20th, 2010. * Fixed the XSTL and CSS stylesheets to support expected failures. -Changes in version 0.10 -*********************** +## Changes in version 0.10 Experimental version released on July 2nd, 2010. @@ -410,7 +513,7 @@ Miscellaneous features take the expected exception as the first argument and the statement to execute as the second argument. -Changes in atf-check +### Changes in atf-check * Changed atf-check to support negating the status and output checks by prefixing them with not- and added support to specify multiple checkers @@ -463,8 +566,7 @@ Code simplifications and cleanups easier to maintain. -Changes in version 0.9 -********************** +## Changes in version 0.9 Experimental version released on June 3rd, 2010. @@ -491,8 +593,7 @@ Experimental version released on June 3rd, 2010. ATF_TEST_CASE_WITHOUT_HEAD. -Changes in version 0.8 -********************** +## Changes in version 0.8 Experimental version released on May 7th, 2010. @@ -541,8 +642,7 @@ Experimental version released on May 7th, 2010. name of their own. -Changes in version 0.7 -********************** +## Changes in version 0.7 Experimental version released on December 22nd, 2009. @@ -571,8 +671,7 @@ Experimental version released on December 22nd, 2009. * Fixed many memory and object leaks. -Changes in version 0.6 -********************** +## Changes in version 0.6 Experimental version released on January 18th, 2009. @@ -605,8 +704,7 @@ Experimental version released on January 18th, 2009. _STREQ_MSG. -Changes in version 0.5 -********************** +## Changes in version 0.5 Experimental version released on May 1st, 2008. @@ -632,8 +730,7 @@ Experimental version released on May 1st, 2008. executed multiple times to comply with the user's requests. -Changes in version 0.4 -********************** +## Changes in version 0.4 Experimental version released on February 4th, 2008. @@ -665,8 +762,7 @@ Experimental version released on February 4th, 2008. were likely affected too. -Changes in version 0.3 -********************** +## Changes in version 0.3 Experimental version released on November 11th, 2007. @@ -699,8 +795,7 @@ Experimental version released on November 11th, 2007. incomplete. -Changes in version 0.2 -********************** +## Changes in version 0.2 Experimental version released on September 20th, 2007. @@ -731,8 +826,7 @@ Experimental version released on September 20th, 2007. * Multiple bug fixes and improvements all around. -Changes in version 0.1 -********************** +## Changes in version 0.1 Experimental version released on August 20th, 2007. @@ -741,4 +835,4 @@ Experimental version released on August 20th, 2007. =========================================================================== -vim: filetype=text:textwidth=75:expandtab:shiftwidth=2:softtabstop=2 +# vim: syntax=markdown:textwidth=75:expandtab:shiftwidth=2:softtabstop=2 diff --git a/contrib/atf/README b/contrib/atf/README deleted file mode 100644 index d3b03edb9419..000000000000 --- a/contrib/atf/README +++ /dev/null @@ -1,37 +0,0 @@ -Introductory information Automated Testing Framework -=========================================================================== - - -Introduction -************ - -The Automated Testing Framework (ATF) is a collection of libraries to -implement test programs in a variety of languages. At the moment, ATF -offers C, C++ and POSIX shell bindings with which to implement tests. -These bindings all offer a similar set of functionality and any test -program written with them exposes a consistent user interface. - -ATF-based test programs rely on a separate runtime engine to execute them. -The runtime engine is in charge of isolating the test programs from the -rest of the system to ensure that their results are deterministic and that -they cannot affect the running system. The runtime engine is also -responsible for gathering the results of all tests and composing reports. -The current runtime of choice is Kyua. - - -Other documents -*************** - -* AUTHORS: List of authors and contributors for this project. - -* COPYING: License information. - -* INSTALL: Compilation and installation instructions. These is not the - standard document shipped with many packages, so be sure to read it for - things that are specific to ATF's build. - -* NEWS: List of major changes between formal, published releases. - - -=========================================================================== -vim: filetype=text:textwidth=75:expandtab:shiftwidth=2:softtabstop=2 diff --git a/contrib/atf/README.md b/contrib/atf/README.md index d245552f35c9..0513546fc7cc 100644 --- a/contrib/atf/README.md +++ b/contrib/atf/README.md @@ -12,36 +12,57 @@ interface** to allow both humans and automation to run the tests. ATF-based test programs **rely on an execution engine** to be run and this execution engine is *not* shipped with ATF. -**[Kyua](https://github.com/jmmv/kyua/) is the engine of choice.** +**[Kyua](https://github.com/freebsd/kyua/) is the engine of choice.** ## Download Formal releases for source files are available for download from GitHub: -* [atf 0.20](../../releases/tag/atf-0.20), released on February 7th, 2014. +* [atf 0.25](../../releases/tag/atf-0.25), released on September 2nd, 2026. ## Installation You are encouraged to install binary packages for your operating system wherever available: -* Fedora 20 and above: install the `atf` package with `yum install atf`. - * FreeBSD 10.0 and above: install the `atf` package with `pkg install atf`. * NetBSD with pkgsrc: install the `pkgsrc/devel/atf` package. * OpenBSD: install the `devel/atf` package with `pkg_add atf`. +* Ubuntu: install the `libatf-dev` and `atf-sh` packages with + `apt install libatf-dev atf-sh`. + Should you want to build and install ATF from the source tree provided -here, follow the instructions in the [INSTALL file](INSTALL). +here, follow the instructions in the [INSTALL file](INSTALL.md). + +## More Reading + +* AUTHORS: List of authors and contributors for this project. + +* COPYING: License information. + +* INSTALL.md: Compilation and installation instructions. These is not the + standard document shipped with many packages, so be sure to read it for + things that are specific to ATF's build. + +* NEWS.md: List of major changes between formal, published releases. + +## Other documents + +* `AUTHORS`: List of authors and contributors for this project. + +* `COPYING`: License information. + +* `INSTALL.md`: Compilation and installation instructions. These is not the + standard document shipped with many packages, so be sure to read it for + things that are specific to ATF's build. + +* `NEWS.md`: List of major changes between formal, published releases. ## Support Please use the -[atf-discuss mailing list](https://groups.google.com/forum/#!forum/atf-discuss) -for any support inquiries related to `atf-c`, `atf-c++` or `atf-sh`. - -If you have any questions on Kyua proper, please use the -[kyua-discuss mailing list](https://groups.google.com/forum/#!forum/kyua-discuss) -instead. +[FreeBSD-testing@FreeBSD.org](mailto:FreeBSD-testing@FreeBSD.org) mailing list +for any support inquiries related to `atf-c`, `atf-c++`, `atf-sh`, or `kyua`. diff --git a/contrib/atf/atf-c++/atf-c++.3 b/contrib/atf/atf-c++/atf-c++.3 index bb83e6214622..2254d481efff 100644 --- a/contrib/atf/atf-c++/atf-c++.3 +++ b/contrib/atf/atf-c++/atf-c++.3 @@ -22,7 +22,7 @@ .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.Dd May 11, 2025 +.Dd October 13, 2014 .Dt ATF-C++ 3 .Os .Sh NAME @@ -285,6 +285,8 @@ additional kernel modules in the test case's body by using the .Fn require_kmod function, which takes the name of a single module. If it is not found, the test case will be automatically skipped. +This feature is only available on +.Fx . .Ss Requiring programs Aside from the .Va require.progs diff --git a/contrib/atf/atf-c++/check.cpp b/contrib/atf/atf-c++/check.cpp index 5d8580023a15..78da33fa9620 100644 --- a/contrib/atf/atf-c++/check.cpp +++ b/contrib/atf/atf-c++/check.cpp @@ -150,5 +150,6 @@ impl::exec(const atf::process::argv_array& argva) if (atf_is_error(err)) throw_atf_error(err); - return std::unique_ptr< impl::check_result >(new impl::check_result(&result)); + return std::unique_ptr< impl::check_result >( + new impl::check_result(&result)); } diff --git a/contrib/atf/atf-c++/check.hpp b/contrib/atf/atf-c++/check.hpp index 4d7f079d1ac1..bcf9cb647f29 100644 --- a/contrib/atf/atf-c++/check.hpp +++ b/contrib/atf/atf-c++/check.hpp @@ -71,7 +71,8 @@ class check_result { check_result(const atf_check_result_t* result); friend check_result test_constructor(const char* const*); - friend std::unique_ptr< check_result > exec(const atf::process::argv_array&); + friend std::unique_ptr< check_result > + exec(const atf::process::argv_array&); public: //! diff --git a/contrib/atf/atf-c++/detail/Kyuafile b/contrib/atf/atf-c++/detail/Kyuafile index fc799e64df69..425595cef644 100644 --- a/contrib/atf/atf-c++/detail/Kyuafile +++ b/contrib/atf/atf-c++/detail/Kyuafile @@ -3,7 +3,6 @@ syntax("kyuafile", 1) test_suite("atf") atf_test_program{name="application_test"} -atf_test_program{name="auto_array_test"} atf_test_program{name="env_test"} atf_test_program{name="exceptions_test"} atf_test_program{name="fs_test"} diff --git a/contrib/atf/atf-c++/detail/application.cpp b/contrib/atf/atf-c++/detail/application.cpp index 37086eb3ae8c..3eeb8f966cf9 100644 --- a/contrib/atf/atf-c++/detail/application.cpp +++ b/contrib/atf/atf-c++/detail/application.cpp @@ -37,6 +37,7 @@ extern "C" { #include <cstdio> #include <cstdlib> #include <cstring> +#include <filesystem> #include <iostream> extern "C" { @@ -205,19 +206,8 @@ impl::app::run(int argc, char* const* argv) m_argc = argc; m_argv = argv; - m_argv0 = m_argv[0]; - - m_prog_name = std::strrchr(m_argv[0], '/'); - if (m_prog_name == NULL) - m_prog_name = m_argv[0]; - else - m_prog_name++; - - // Libtool workaround: if running from within the source tree (binaries - // that are not installed yet), skip the "lt-" prefix added to files in - // the ".libs" directory to show the real (not temporary) name. - if (std::strncmp(m_prog_name, "lt-", 3) == 0) - m_prog_name += 3; + auto m_prog_filename = std::filesystem::path(m_argv[0]).filename(); + m_prog_name = m_prog_filename.c_str(); const std::string bug = std::string("This is probably a bug in ") + m_prog_name + diff --git a/contrib/atf/atf-c++/detail/application.hpp b/contrib/atf/atf-c++/detail/application.hpp index cdb4073ad807..ad068467ac3a 100644 --- a/contrib/atf/atf-c++/detail/application.hpp +++ b/contrib/atf/atf-c++/detail/application.hpp @@ -81,7 +81,6 @@ protected: int m_argc; char* const* m_argv; - const char* m_argv0; const char* m_prog_name; std::string m_description; std::string m_manpage; diff --git a/contrib/atf/atf-c++/detail/auto_array.hpp b/contrib/atf/atf-c++/detail/auto_array.hpp deleted file mode 100644 index b434a5808235..000000000000 --- a/contrib/atf/atf-c++/detail/auto_array.hpp +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) 2007 The NetBSD Foundation, Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND -// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#if !defined(ATF_CXX_DETAIL_AUTO_ARRAY_HPP) -#define ATF_CXX_DETAIL_AUTO_ARRAY_HPP - -#include <cstddef> - -namespace atf { - -// ------------------------------------------------------------------------ -// The "auto_array" class. -// ------------------------------------------------------------------------ - -template< class T > -struct auto_array_ref { - T* m_ptr; - - explicit auto_array_ref(T*); -}; - -template< class T > -auto_array_ref< T >::auto_array_ref(T* ptr) : - m_ptr(ptr) -{ -} - -template< class T > -class auto_array { - T* m_ptr; - -public: - auto_array(T* = NULL) throw(); - auto_array(auto_array< T >&) throw(); - auto_array(auto_array_ref< T >) throw(); - ~auto_array(void) throw(); - - T* get(void) throw(); - const T* get(void) const throw(); - T* release(void) throw(); - void reset(T* = NULL) throw(); - - auto_array< T >& operator=(auto_array< T >&) throw(); - auto_array< T >& operator=(auto_array_ref< T >) throw(); - - T& operator[](int) throw(); - operator auto_array_ref< T >(void) throw(); -}; - -template< class T > -auto_array< T >::auto_array(T* ptr) - throw() : - m_ptr(ptr) -{ -} - -template< class T > -auto_array< T >::auto_array(auto_array< T >& ptr) - throw() : - m_ptr(ptr.release()) -{ -} - -template< class T > -auto_array< T >::auto_array(auto_array_ref< T > ref) - throw() : - m_ptr(ref.m_ptr) -{ -} - -template< class T > -auto_array< T >::~auto_array(void) - throw() -{ - if (m_ptr != NULL) - delete [] m_ptr; -} - -template< class T > -T* -auto_array< T >::get(void) - throw() -{ - return m_ptr; -} - -template< class T > -const T* -auto_array< T >::get(void) - const throw() -{ - return m_ptr; -} - -template< class T > -T* -auto_array< T >::release(void) - throw() -{ - T* ptr = m_ptr; - m_ptr = NULL; - return ptr; -} - -template< class T > -void -auto_array< T >::reset(T* ptr) - throw() -{ - if (m_ptr != NULL) - delete [] m_ptr; - m_ptr = ptr; -} - -template< class T > -auto_array< T >& -auto_array< T >::operator=(auto_array< T >& ptr) - throw() -{ - reset(ptr.release()); - return *this; -} - -template< class T > -auto_array< T >& -auto_array< T >::operator=(auto_array_ref< T > ref) - throw() -{ - if (m_ptr != ref.m_ptr) { - delete [] m_ptr; - m_ptr = ref.m_ptr; - } - return *this; -} - -template< class T > -T& -auto_array< T >::operator[](int pos) - throw() -{ - return m_ptr[pos]; -} - -template< class T > -auto_array< T >::operator auto_array_ref< T >(void) - throw() -{ - return auto_array_ref< T >(release()); -} - -} // namespace atf - -#endif // !defined(ATF_CXX_DETAIL_AUTO_ARRAY_HPP) diff --git a/contrib/atf/atf-c++/detail/auto_array_test.cpp b/contrib/atf/atf-c++/detail/auto_array_test.cpp deleted file mode 100644 index aaad90e15295..000000000000 --- a/contrib/atf/atf-c++/detail/auto_array_test.cpp +++ /dev/null @@ -1,302 +0,0 @@ -// Copyright (c) 2007 The NetBSD Foundation, Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND -// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "atf-c++/detail/auto_array.hpp" - -extern "C" { -#include <sys/types.h> -} - -#include <iostream> - -#include <atf-c++.hpp> - -extern "C" { -#include "atf-c/defs.h" -} - -// ------------------------------------------------------------------------ -// Tests for the "auto_array" class. -// ------------------------------------------------------------------------ - -class test_array { -public: - int m_value; - - static ssize_t m_nblocks; - - static - atf::auto_array< test_array > - do_copy(atf::auto_array< test_array >& ta) - { - return atf::auto_array< test_array >(ta); - } - - void* operator new(size_t size ATF_DEFS_ATTRIBUTE_UNUSED) - { - ATF_FAIL("New called but should have been new[]"); - return new int(5); - } - - void* operator new[](size_t size) - { - m_nblocks++; - void* mem = ::operator new(size); - std::cout << "Allocated 'test_array' object " << mem << "\n"; - return mem; - } - - void operator delete(void* mem ATF_DEFS_ATTRIBUTE_UNUSED) - { - ATF_FAIL("Delete called but should have been delete[]"); - } - - void operator delete[](void* mem) - { - std::cout << "Releasing 'test_array' object " << mem << "\n"; - if (m_nblocks == 0) - ATF_FAIL("Unbalanced delete[]"); - m_nblocks--; - ::operator delete(mem); - } -}; - -ssize_t test_array::m_nblocks = 0; - -ATF_TEST_CASE(auto_array_scope); -ATF_TEST_CASE_HEAD(auto_array_scope) -{ - set_md_var("descr", "Tests the automatic scope handling in the " - "auto_array smart pointer class"); -} -ATF_TEST_CASE_BODY(auto_array_scope) -{ - using atf::auto_array; - - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); - { - auto_array< test_array > t(new test_array[10]); - ATF_REQUIRE_EQ(test_array::m_nblocks, 1); - } - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); -} - -ATF_TEST_CASE(auto_array_copy); -ATF_TEST_CASE_HEAD(auto_array_copy) -{ - set_md_var("descr", "Tests the auto_array smart pointer class' copy " - "constructor"); -} -ATF_TEST_CASE_BODY(auto_array_copy) -{ - using atf::auto_array; - - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); - { - auto_array< test_array > t1(new test_array[10]); - ATF_REQUIRE_EQ(test_array::m_nblocks, 1); - - { - auto_array< test_array > t2(t1); - ATF_REQUIRE_EQ(test_array::m_nblocks, 1); - } - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); - } - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); -} - -ATF_TEST_CASE(auto_array_copy_ref); -ATF_TEST_CASE_HEAD(auto_array_copy_ref) -{ - set_md_var("descr", "Tests the auto_array smart pointer class' copy " - "constructor through the auxiliary auto_array_ref object"); -} -ATF_TEST_CASE_BODY(auto_array_copy_ref) -{ - using atf::auto_array; - - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); - { - auto_array< test_array > t1(new test_array[10]); - ATF_REQUIRE_EQ(test_array::m_nblocks, 1); - - { - auto_array< test_array > t2 = test_array::do_copy(t1); - ATF_REQUIRE_EQ(test_array::m_nblocks, 1); - } - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); - } - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); -} - -ATF_TEST_CASE(auto_array_get); -ATF_TEST_CASE_HEAD(auto_array_get) -{ - set_md_var("descr", "Tests the auto_array smart pointer class' get " - "method"); -} -ATF_TEST_CASE_BODY(auto_array_get) -{ - using atf::auto_array; - - test_array* ta = new test_array[10]; - auto_array< test_array > t(ta); - ATF_REQUIRE_EQ(t.get(), ta); -} - -ATF_TEST_CASE(auto_array_release); -ATF_TEST_CASE_HEAD(auto_array_release) -{ - set_md_var("descr", "Tests the auto_array smart pointer class' release " - "method"); -} -ATF_TEST_CASE_BODY(auto_array_release) -{ - using atf::auto_array; - - test_array* ta1 = new test_array[10]; - { - auto_array< test_array > t(ta1); - ATF_REQUIRE_EQ(test_array::m_nblocks, 1); - test_array* ta2 = t.release(); - ATF_REQUIRE_EQ(ta2, ta1); - ATF_REQUIRE_EQ(test_array::m_nblocks, 1); - } - ATF_REQUIRE_EQ(test_array::m_nblocks, 1); - delete [] ta1; -} - -ATF_TEST_CASE(auto_array_reset); -ATF_TEST_CASE_HEAD(auto_array_reset) -{ - set_md_var("descr", "Tests the auto_array smart pointer class' reset " - "method"); -} -ATF_TEST_CASE_BODY(auto_array_reset) -{ - using atf::auto_array; - - test_array* ta1 = new test_array[10]; - test_array* ta2 = new test_array[10]; - ATF_REQUIRE_EQ(test_array::m_nblocks, 2); - - { - auto_array< test_array > t(ta1); - ATF_REQUIRE_EQ(test_array::m_nblocks, 2); - t.reset(ta2); - ATF_REQUIRE_EQ(test_array::m_nblocks, 1); - t.reset(); - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); - } - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); -} - -ATF_TEST_CASE(auto_array_assign); -ATF_TEST_CASE_HEAD(auto_array_assign) -{ - set_md_var("descr", "Tests the auto_array smart pointer class' " - "assignment operator"); -} -ATF_TEST_CASE_BODY(auto_array_assign) -{ - using atf::auto_array; - - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); - { - auto_array< test_array > t1(new test_array[10]); - ATF_REQUIRE_EQ(test_array::m_nblocks, 1); - - { - auto_array< test_array > t2; - t2 = t1; - ATF_REQUIRE_EQ(test_array::m_nblocks, 1); - } - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); - } - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); -} - -ATF_TEST_CASE(auto_array_assign_ref); -ATF_TEST_CASE_HEAD(auto_array_assign_ref) -{ - set_md_var("descr", "Tests the auto_array smart pointer class' " - "assignment operator through the auxiliary auto_array_ref " - "object"); -} -ATF_TEST_CASE_BODY(auto_array_assign_ref) -{ - using atf::auto_array; - - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); - { - auto_array< test_array > t1(new test_array[10]); - ATF_REQUIRE_EQ(test_array::m_nblocks, 1); - - { - auto_array< test_array > t2; - t2 = test_array::do_copy(t1); - ATF_REQUIRE_EQ(test_array::m_nblocks, 1); - } - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); - } - ATF_REQUIRE_EQ(test_array::m_nblocks, 0); -} - -ATF_TEST_CASE(auto_array_access); -ATF_TEST_CASE_HEAD(auto_array_access) -{ - set_md_var("descr", "Tests the auto_array smart pointer class' access " - "operator"); -} -ATF_TEST_CASE_BODY(auto_array_access) -{ - using atf::auto_array; - - auto_array< test_array > t(new test_array[10]); - - for (int i = 0; i < 10; i++) - t[i].m_value = i * 2; - - for (int i = 0; i < 10; i++) - ATF_REQUIRE_EQ(t[i].m_value, i * 2); -} - -// ------------------------------------------------------------------------ -// Main. -// ------------------------------------------------------------------------ - -ATF_INIT_TEST_CASES(tcs) -{ - // Add the test for the "auto_array" class. - ATF_ADD_TEST_CASE(tcs, auto_array_scope); - ATF_ADD_TEST_CASE(tcs, auto_array_copy); - ATF_ADD_TEST_CASE(tcs, auto_array_copy_ref); - ATF_ADD_TEST_CASE(tcs, auto_array_get); - ATF_ADD_TEST_CASE(tcs, auto_array_release); - ATF_ADD_TEST_CASE(tcs, auto_array_reset); - ATF_ADD_TEST_CASE(tcs, auto_array_assign); - ATF_ADD_TEST_CASE(tcs, auto_array_assign_ref); - ATF_ADD_TEST_CASE(tcs, auto_array_access); -} diff --git a/contrib/atf/atf-c++/detail/fs.cpp b/contrib/atf/atf-c++/detail/fs.cpp index bcef9204d129..74bacf26a421 100644 --- a/contrib/atf/atf-c++/detail/fs.cpp +++ b/contrib/atf/atf-c++/detail/fs.cpp @@ -32,7 +32,6 @@ extern "C" { #include <sys/param.h> #include <sys/types.h> -#include <sys/mount.h> #include <sys/stat.h> #include <sys/wait.h> #include <dirent.h> diff --git a/contrib/atf/atf-c++/detail/process.cpp b/contrib/atf/atf-c++/detail/process.cpp index 8139536d39e3..25516059c884 100644 --- a/contrib/atf/atf-c++/detail/process.cpp +++ b/contrib/atf/atf-c++/detail/process.cpp @@ -46,31 +46,29 @@ namespace impl = atf::process; // ------------------------------------------------------------------------ template< class C > -atf::auto_array< const char* > +std::vector<const char*> collection_to_argv(const C& c) { - atf::auto_array< const char* > argv(new const char*[c.size() + 1]); + std::vector<const char*> argv; + argv.reserve(c.size() + 1); - std::size_t pos = 0; - for (typename C::const_iterator iter = c.begin(); iter != c.end(); - iter++) { - argv[pos] = (*iter).c_str(); - pos++; + for (const auto& item : c) { + argv.push_back(item.c_str()); } - INV(pos == c.size()); - argv[pos] = NULL; + argv.push_back(nullptr); return argv; } -template< class C > +template<class C> C argv_to_collection(const char* const* argv) { C c; - for (const char* const* iter = argv; *iter != NULL; iter++) + for (const char* const* iter = argv; *iter != nullptr; iter++) { c.push_back(std::string(*iter)); + } return c; } @@ -123,7 +121,7 @@ const char* const* impl::argv_array::exec_argv(void) const { - return m_exec_argv.get(); + return m_exec_argv.data(); } impl::argv_array::size_type diff --git a/contrib/atf/atf-c++/detail/process.hpp b/contrib/atf/atf-c++/detail/process.hpp index 0d4989a4f40b..78bd55fd0f05 100644 --- a/contrib/atf/atf-c++/detail/process.hpp +++ b/contrib/atf/atf-c++/detail/process.hpp @@ -36,7 +36,6 @@ extern "C" { #include <string> #include <vector> -#include <atf-c++/detail/auto_array.hpp> #include <atf-c++/detail/exceptions.hpp> #include <atf-c++/detail/fs.hpp> @@ -58,7 +57,7 @@ class argv_array { // std::tr1::shared_array instead when it becomes widely available. // The reason would be to remove all copy constructors and assignment // operators from this class. - auto_array< const char* > m_exec_argv; + std::vector< const char* > m_exec_argv; void ctor_init_exec_argv(void); public: diff --git a/contrib/atf/atf-c++/detail/process_test.cpp b/contrib/atf/atf-c++/detail/process_test.cpp index 97f9a08e2504..69cd79d3f628 100644 --- a/contrib/atf/atf-c++/detail/process_test.cpp +++ b/contrib/atf/atf-c++/detail/process_test.cpp @@ -196,22 +196,19 @@ ATF_TEST_CASE_BODY(argv_array_assign) const char* const carray1[] = { "arg1", NULL }; const char* const carray2[] = { "arg1", "arg2", NULL }; - std::unique_ptr< argv_array > argv1(new argv_array(carray1)); - std::unique_ptr< argv_array > argv2(new argv_array(carray2)); + argv_array argv1 = argv_array(carray1); + argv_array argv2 = argv_array(carray2); - *argv2 = *argv1; - ATF_REQUIRE_EQ(argv2->size(), argv1->size()); - ATF_REQUIRE(std::strcmp((*argv2)[0], (*argv1)[0]) == 0); + argv2 = argv1; + ATF_REQUIRE_EQ(argv2.size(), argv1.size()); + ATF_REQUIRE(std::strcmp(argv2[0], argv1[0]) == 0); - ATF_REQUIRE(argv2->exec_argv() != argv1->exec_argv()); - argv1.release(); + ATF_REQUIRE(argv2.exec_argv() != argv1.exec_argv()); { - const char* const* eargv2 = argv2->exec_argv(); + const char* const* eargv2 = argv2.exec_argv(); ATF_REQUIRE(std::strcmp(eargv2[0], carray1[0]) == 0); ATF_REQUIRE_EQ(eargv2[1], static_cast< const char* >(NULL)); } - - argv2.release(); } ATF_TEST_CASE(argv_array_copy); @@ -226,21 +223,18 @@ ATF_TEST_CASE_BODY(argv_array_copy) const char* const carray[] = { "arg0", NULL }; - std::unique_ptr< argv_array > argv1(new argv_array(carray)); - std::unique_ptr< argv_array > argv2(new argv_array(*argv1)); + argv_array argv1 = argv_array(carray); + argv_array argv2 = argv1; - ATF_REQUIRE_EQ(argv2->size(), argv1->size()); - ATF_REQUIRE(std::strcmp((*argv2)[0], (*argv1)[0]) == 0); + ATF_REQUIRE_EQ(argv2.size(), argv1.size()); + ATF_REQUIRE(std::strcmp(argv2[0], argv1[0]) == 0); - ATF_REQUIRE(argv2->exec_argv() != argv1->exec_argv()); - argv1.release(); + ATF_REQUIRE(argv2.exec_argv() != argv1.exec_argv()); { - const char* const* eargv2 = argv2->exec_argv(); + const char* const* eargv2 = argv2.exec_argv(); ATF_REQUIRE(std::strcmp(eargv2[0], carray[0]) == 0); ATF_REQUIRE_EQ(eargv2[1], static_cast< const char* >(NULL)); } - - argv2.release(); } ATF_TEST_CASE(argv_array_exec_argv); diff --git a/contrib/atf/atf-c++/detail/test_helpers.hpp b/contrib/atf/atf-c++/detail/test_helpers.hpp index c1171801a3a7..1c4c316f4714 100644 --- a/contrib/atf/atf-c++/detail/test_helpers.hpp +++ b/contrib/atf/atf-c++/detail/test_helpers.hpp @@ -45,8 +45,6 @@ { \ set_md_var("descr", "Tests that the " hdrname " file can be " \ "included on its own, without any prerequisites"); \ - const std::string cxx = atf::env::get("ATF_BUILD_CXX", ATF_BUILD_CXX); \ - set_md_var("require.progs", cxx); \ } \ ATF_TEST_CASE_BODY(name) \ { \ @@ -58,8 +56,6 @@ ATF_TEST_CASE_HEAD(name) \ { \ set_md_var("descr", descr); \ - const std::string cxx = atf::env::get("ATF_BUILD_CXX", ATF_BUILD_CXX); \ - set_md_var("require.progs", cxx); \ } \ ATF_TEST_CASE_BODY(name) \ { \ diff --git a/contrib/atf/atf-c++/detail/text.cpp b/contrib/atf/atf-c++/detail/text.cpp index 35a0beca95b9..524788a41971 100644 --- a/contrib/atf/atf-c++/detail/text.cpp +++ b/contrib/atf/atf-c++/detail/text.cpp @@ -42,14 +42,6 @@ extern "C" { namespace impl = atf::text; #define IMPL_NAME "atf::text" -char* -impl::duplicate(const char* str) -{ - char* copy = new char[std::strlen(str) + 1]; - std::strcpy(copy, str); - return copy; -} - bool impl::match(const std::string& str, const std::string& regex) { diff --git a/contrib/atf/atf-c++/detail/text.hpp b/contrib/atf/atf-c++/detail/text.hpp index 63c3190a37c1..2e07df2cf4e9 100644 --- a/contrib/atf/atf-c++/detail/text.hpp +++ b/contrib/atf/atf-c++/detail/text.hpp @@ -39,14 +39,6 @@ namespace atf { namespace text { //! -//! \brief Duplicates a C string using the new[] allocator. -//! -//! Replaces the functionality of strdup by using the new[] allocator and -//! thus allowing the resulting memory to be managed by utils::auto_array. -//! -char* duplicate(const char*); - -//! //! \brief Joins multiple words into a string. //! //! Joins a list of words into a string, separating them using the provided diff --git a/contrib/atf/atf-c++/detail/text_test.cpp b/contrib/atf/atf-c++/detail/text_test.cpp index 49d37741b414..108241130f5d 100644 --- a/contrib/atf/atf-c++/detail/text_test.cpp +++ b/contrib/atf/atf-c++/detail/text_test.cpp @@ -35,26 +35,6 @@ // Test cases for the free functions. // ------------------------------------------------------------------------ -ATF_TEST_CASE(duplicate); -ATF_TEST_CASE_HEAD(duplicate) -{ - set_md_var("descr", "Tests the duplicate function"); -} -ATF_TEST_CASE_BODY(duplicate) -{ - using atf::text::duplicate; - - const char* orig = "foo"; - - char* copy = duplicate(orig); - ATF_REQUIRE_EQ(std::strlen(copy), 3); - ATF_REQUIRE(std::strcmp(copy, "foo") == 0); - - std::strcpy(copy, "bar"); - ATF_REQUIRE(std::strcmp(copy, "bar") == 0); - ATF_REQUIRE(std::strcmp(orig, "foo") == 0); -} - ATF_TEST_CASE(join); ATF_TEST_CASE_HEAD(join) { @@ -373,7 +353,6 @@ ATF_TEST_CASE_BODY(to_type) ATF_INIT_TEST_CASES(tcs) { // Add the test cases for the free functions. - ATF_ADD_TEST_CASE(tcs, duplicate); ATF_ADD_TEST_CASE(tcs, join); ATF_ADD_TEST_CASE(tcs, match); ATF_ADD_TEST_CASE(tcs, split); diff --git a/contrib/atf/atf-c++/tests.cpp b/contrib/atf/atf-c++/tests.cpp index a9f5d4a5fe2c..cb0d735f5a06 100644 --- a/contrib/atf/atf-c++/tests.cpp +++ b/contrib/atf/atf-c++/tests.cpp @@ -58,7 +58,6 @@ extern "C" { } #include "atf-c++/detail/application.hpp" -#include "atf-c++/detail/auto_array.hpp" #include "atf-c++/detail/env.hpp" #include "atf-c++/detail/exceptions.hpp" #include "atf-c++/detail/fs.hpp" @@ -123,13 +122,7 @@ static void set_program_name(const char* argv0) { const std::string program_name = atf::fs::path(argv0).leaf_name(); - // Libtool workaround: if running from within the source tree (binaries - // that are not installed yet), skip the "lt-" prefix added to files in - // the ".libs" directory to show the real (not temporary) name. - if (program_name.substr(0, 3) == "lt-") - Program_Name = program_name.substr(3); - else - Program_Name = program_name; + Program_Name = program_name; } bool @@ -207,22 +200,22 @@ impl::tc::init(const vars_map& config) { atf_error_t err; - auto_array< const char * > array(new const char*[(config.size() * 2) + 1]); - const char **ptr = array.get(); + std::vector< const char * > array; + array.reserve((config.size() * 2) + 1); + for (vars_map::const_iterator iter = config.begin(); iter != config.end(); iter++) { - *ptr = (*iter).first.c_str(); - *(ptr + 1) = (*iter).second.c_str(); - ptr += 2; + array.push_back((*iter).first.c_str()); + array.push_back((*iter).second.c_str()); } - *ptr = NULL; + array.push_back(nullptr); wraps[&pimpl->m_tc] = this; cwraps[&pimpl->m_tc] = this; err = atf_tc_init(&pimpl->m_tc, pimpl->m_ident.c_str(), pimpl->wrap_head, pimpl->wrap_body, pimpl->m_has_cleanup ? pimpl->wrap_cleanup : NULL, - array.get()); + array.data()); if (atf_is_error(err)) throw_atf_error(err); } @@ -273,6 +266,7 @@ impl::tc::get_md_vars(void) char **ptr; for (ptr = array; *ptr != NULL; ptr += 2) vars[*ptr] = *(ptr + 1); + atf_utils_free_charpp(array); } catch (...) { atf_utils_free_charpp(array); throw; @@ -461,9 +455,7 @@ init_tcs(void (*add_tcs)(tc_vector&), tc_vector& tcs, const atf::tests::vars_map& vars) { add_tcs(tcs); - for (tc_vector::iterator iter = tcs.begin(); iter != tcs.end(); iter++) { - impl::tc* tc = *iter; - + for (auto& tc : tcs) { tc->init(vars); } } @@ -616,27 +608,25 @@ safe_main(int argc, char** argv, void (*add_tcs)(tc_vector&)) int errcode; - tc_vector tcs; if (lflag) { if (argc > 0) throw usage_error("Cannot provide test case names with -l"); - - init_tcs(add_tcs, tcs, vars); - errcode = list_tcs(tcs); } else { if (argc == 0) throw usage_error("Must provide a test case name"); else if (argc > 1) throw usage_error("Cannot provide more than one test case name"); INV(argc == 1); - - init_tcs(add_tcs, tcs, vars); - errcode = run_tc(tcs, argv[0], resfile); } - for (tc_vector::iterator iter = tcs.begin(); iter != tcs.end(); iter++) { - impl::tc* tc = *iter; - - delete tc; + tc_vector tcs; + try { + init_tcs(add_tcs, tcs, vars); + errcode = lflag ? list_tcs(tcs) : run_tc(tcs, argv[0], resfile); + } catch (...) { + for (auto& tc: tcs) { + delete tc; + } + throw; } return errcode; diff --git a/contrib/atf/atf-c++/tests_test.cpp b/contrib/atf/atf-c++/tests_test.cpp index ed9fef0d0140..98b4da70d247 100644 --- a/contrib/atf/atf-c++/tests_test.cpp +++ b/contrib/atf/atf-c++/tests_test.cpp @@ -163,6 +163,10 @@ ATF_TEST_CASE_BODY(atf_tp_writer) expss << "descr: second test case\n"; CHECK; + w.tc_meta_data("require.kmods", "/nonexistent"); + expss << "require.kmods: /nonexistent\n"; + CHECK; + w.tc_meta_data("require.progs", "/bin/cp"); expss << "require.progs: /bin/cp\n"; CHECK; diff --git a/contrib/atf/atf-c/.gitignore b/contrib/atf/atf-c/.gitignore deleted file mode 100644 index e7f0fb647c32..000000000000 --- a/contrib/atf/atf-c/.gitignore +++ /dev/null @@ -1 +0,0 @@ -defs.h diff --git a/contrib/atf/atf-c/atf-c.3 b/contrib/atf/atf-c/atf-c.3 index 153c09fb0f7e..02f06483646f 100644 --- a/contrib/atf/atf-c/atf-c.3 +++ b/contrib/atf/atf-c/atf-c.3 @@ -22,7 +22,7 @@ .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.Dd June 12, 2025 +.Dd October 10, 2025 .Dt ATF-C 3 .Os .Sh NAME @@ -244,7 +244,7 @@ .Fa "const char *contents" .Fa "..." .Fc -.Ft void +.Ft bool .Fo atf_utils_file_exists .Fa "const char *file" .Fc @@ -326,9 +326,9 @@ ATF_TC_BODY(tc3, tc) ATF_TP_ADD_TCS(tp) { - ATF_TP_ADD_TC(tcs, tc1); - ATF_TP_ADD_TC(tcs, tc2); - ATF_TP_ADD_TC(tcs, tc3); + ATF_TP_ADD_TC(tp, tc1); + ATF_TP_ADD_TC(tp, tc2); + ATF_TP_ADD_TC(tp, tc3); ... add additional test cases ... return atf_no_error(); @@ -447,6 +447,8 @@ additional kernel modules in the test case's body by using the .Fn atf_tc_require_kmod function, which takes the name of a single kernel module. If it is not found, the test case will be automatically skipped. +This feature is only available on +.Fx . .Ss Requiring programs Aside from the .Va require.progs @@ -620,12 +622,10 @@ observed integer in the second parameter. .Fn ATF_CHECK_ERRNO and .Fn ATF_REQUIRE_ERRNO -take, first, the error code that the check is expecting to find in the -.Va errno -variable and, second, a boolean expression that, if evaluates to true, -means that a call failed and +take an expected error code and a boolean expression, and fail the +test if either the expression is false or .Va errno -has to be checked against the first value. +is not equal to the expected error code. .Ss Utility functions The following functions are provided as part of the .Nm @@ -782,7 +782,7 @@ those spawned by .Fc .Bd -ragged -offset indent Waits and validates the result of a subprocess spawned with -.Fn atf_utils_fork . +.Fn atf_utils_wait . The validation involves checking that the subprocess exited cleanly and returned the code specified in .Fa expected_exit_status diff --git a/contrib/atf/atf-c/build.c b/contrib/atf/atf-c/build.c index c119fc97a214..ce0188a62db1 100644 --- a/contrib/atf/atf-c/build.c +++ b/contrib/atf/atf-c/build.c @@ -83,7 +83,7 @@ append_optargs(const char *const optargs[], atf_list_t *argv) err = atf_no_error(); while (*optargs != NULL && !atf_is_error(err)) { - err = append_arg1(strdup(*optargs), argv); + err = append_arg1(*optargs, argv); optargs++; } diff --git a/contrib/atf/atf-c/check.c b/contrib/atf/atf-c/check.c index 1aec01bcca6b..f80e08f0fdde 100644 --- a/contrib/atf/atf-c/check.c +++ b/contrib/atf/atf-c/check.c @@ -348,6 +348,7 @@ atf_check_result_fini(atf_check_result_t *r) atf_list_fini(&r->pimpl->m_argv); free(r->pimpl); + r->pimpl = NULL; } const char * diff --git a/contrib/atf/atf-c/defs.h.in b/contrib/atf/atf-c/defs.h.in index 6059e7fdb0e6..5346e56ac9c9 100644 --- a/contrib/atf/atf-c/defs.h.in +++ b/contrib/atf/atf-c/defs.h.in @@ -27,6 +27,7 @@ #define ATF_C_DEFS_H #define ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(a, b) @ATTRIBUTE_FORMAT_PRINTF@ +#define ATF_DEFS_ATTRIBUTE_NONNULL @ATTRIBUTE_NONNULL@ #define ATF_DEFS_ATTRIBUTE_NORETURN @ATTRIBUTE_NORETURN@ #define ATF_DEFS_ATTRIBUTE_UNUSED @ATTRIBUTE_UNUSED@ diff --git a/contrib/atf/atf-c/detail/dynstr.c b/contrib/atf/atf-c/detail/dynstr.c index 424a1c9dac73..8e61104ef77f 100644 --- a/contrib/atf/atf-c/detail/dynstr.c +++ b/contrib/atf/atf-c/detail/dynstr.c @@ -45,22 +45,18 @@ atf_error_t resize(atf_dynstr_t *ad, size_t newsize) { char *newdata; - atf_error_t err; PRE(newsize > ad->m_datasize); - newdata = (char *)malloc(newsize); - if (newdata == NULL) { - err = atf_no_memory_error(); - } else { - strcpy(newdata, ad->m_data); - free(ad->m_data); - ad->m_data = newdata; - ad->m_datasize = newsize; - err = atf_no_error(); - } + newdata = realloc(ad->m_data, newsize); + if (newdata == NULL) + return atf_no_memory_error(); - return err; + newdata[newsize - 1] = '\0'; + ad->m_data = newdata; + ad->m_datasize = newsize; + + return atf_no_error(); } static @@ -117,21 +113,16 @@ const size_t atf_dynstr_npos = SIZE_MAX; atf_error_t atf_dynstr_init(atf_dynstr_t *ad) { - atf_error_t err; - ad->m_data = (char *)malloc(sizeof(char)); - if (ad->m_data == NULL) { - err = atf_no_memory_error(); - goto out; - } + ad->m_data = malloc(sizeof(char)); + if (ad->m_data == NULL) + return atf_no_memory_error(); ad->m_data[0] = '\0'; ad->m_datasize = 1; ad->m_length = 0; - err = atf_no_error(); -out: - return err; + return atf_no_error(); } atf_error_t @@ -158,6 +149,7 @@ atf_dynstr_init_ap(atf_dynstr_t *ad, const char *fmt, va_list ap) va_end(ap2); if (ret < 0) { free(ad->m_data); + ad->m_data = NULL; err = atf_libc_error(errno, "Cannot format string"); goto out; } @@ -278,6 +270,7 @@ atf_dynstr_fini(atf_dynstr_t *ad) { INV(ad->m_data != NULL); free(ad->m_data); + ad->m_data = NULL; } char * diff --git a/contrib/atf/atf-c/detail/dynstr_test.c b/contrib/atf/atf-c/detail/dynstr_test.c index 25127529f81b..2a12be23ae5a 100644 --- a/contrib/atf/atf-c/detail/dynstr_test.c +++ b/contrib/atf/atf-c/detail/dynstr_test.c @@ -43,6 +43,8 @@ * Constructors and destructors. */ +#define MAXLEN 8192 + ATF_TC(init); ATF_TC_HEAD(init, tc) { @@ -173,13 +175,12 @@ ATF_TC_HEAD(init_rep, tc) } ATF_TC_BODY(init_rep, tc) { - const size_t maxlen = 8192; - char buf[maxlen + 1]; + char buf[MAXLEN + 1]; size_t i; buf[0] = '\0'; - for (i = 0; i < maxlen; i++) { + for (i = 0; i < MAXLEN; i++) { atf_dynstr_t str; RE(atf_dynstr_init_rep(&str, i, 'a')); @@ -371,15 +372,14 @@ static void check_append(atf_error_t (*append)(atf_dynstr_t *, const char *, ...)) { - const size_t maxlen = 8192; - char buf[maxlen + 1]; + char buf[MAXLEN + 1]; size_t i; atf_dynstr_t str; printf("Appending with plain string\n"); buf[0] = '\0'; RE(atf_dynstr_init(&str)); - for (i = 0; i < maxlen; i++) { + for (i = 0; i < MAXLEN; i++) { if (strcmp(atf_dynstr_cstring(&str), buf) != 0) { fprintf(stderr, "Failed at iteration %zd\n", i); atf_tc_fail("Failed to append character at iteration %zd", i); @@ -393,7 +393,7 @@ check_append(atf_error_t (*append)(atf_dynstr_t *, const char *, ...)) printf("Appending with formatted string\n"); buf[0] = '\0'; RE(atf_dynstr_init(&str)); - for (i = 0; i < maxlen; i++) { + for (i = 0; i < MAXLEN; i++) { if (strcmp(atf_dynstr_cstring(&str), buf) != 0) { fprintf(stderr, "Failed at iteration %zd\n", i); atf_tc_fail("Failed to append character at iteration %zd", i); @@ -471,15 +471,14 @@ static void check_prepend(atf_error_t (*prepend)(atf_dynstr_t *, const char *, ...)) { - const size_t maxlen = 8192; - char buf[maxlen + 1]; + char buf[MAXLEN + 1]; size_t i; atf_dynstr_t str; printf("Prepending with plain string\n"); buf[0] = '\0'; RE(atf_dynstr_init(&str)); - for (i = 0; i < maxlen; i++) { + for (i = 0; i < MAXLEN; i++) { if (strcmp(atf_dynstr_cstring(&str), buf) != 0) { fprintf(stderr, "Failed at iteration %zd\n", i); atf_tc_fail("Failed to prepend character at iteration %zd", i); @@ -499,7 +498,7 @@ check_prepend(atf_error_t (*prepend)(atf_dynstr_t *, const char *, ...)) printf("Prepending with formatted string\n"); buf[0] = '\0'; RE(atf_dynstr_init(&str)); - for (i = 0; i < maxlen; i++) { + for (i = 0; i < MAXLEN; i++) { if (strcmp(atf_dynstr_cstring(&str), buf) != 0) { fprintf(stderr, "Failed at iteration %zd\n", i); atf_tc_fail("Failed to prepend character at iteration %zd", i); diff --git a/contrib/atf/atf-c/detail/env.c b/contrib/atf/atf-c/detail/env.c index 8ee3d697c223..36de217c353c 100644 --- a/contrib/atf/atf-c/detail/env.c +++ b/contrib/atf/atf-c/detail/env.c @@ -25,10 +25,6 @@ #include "atf-c/detail/env.h" -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif - #include <errno.h> #include <stdlib.h> @@ -65,25 +61,11 @@ atf_env_set(const char *name, const char *val) { atf_error_t err; -#if defined(HAVE_SETENV) if (setenv(name, val, 1) == -1) - err = atf_libc_error(errno, "Cannot set environment variable " - "'%s' to '%s'", name, val); + err = atf_libc_error(errno, + "Cannot set environment variable '%s' to '%s'", name, val); else err = atf_no_error(); -#elif defined(HAVE_PUTENV) - char *buf; - - err = atf_text_format(&buf, "%s=%s", name, val); - if (!atf_is_error(err)) { - if (putenv(buf) == -1) - err = atf_libc_error(errno, "Cannot set environment variable " - "'%s' to '%s'", name, val); - free(buf); - } -#else -# error "Don't know how to set an environment variable." -#endif return err; } @@ -91,24 +73,7 @@ atf_env_set(const char *name, const char *val) atf_error_t atf_env_unset(const char *name) { - atf_error_t err; -#if defined(HAVE_UNSETENV) unsetenv(name); - err = atf_no_error(); -#elif defined(HAVE_PUTENV) - char *buf; - - err = atf_text_format(&buf, "%s=", name); - if (!atf_is_error(err)) { - if (putenv(buf) == -1) - err = atf_libc_error(errno, "Cannot unset environment variable" - " '%s'", name); - free(buf); - } -#else -# error "Don't know how to unset an environment variable." -#endif - - return err; + return (atf_no_error()); } diff --git a/contrib/atf/atf-c/detail/fs.c b/contrib/atf/atf-c/detail/fs.c index 6ea825aa8e56..34a2cb321c7e 100644 --- a/contrib/atf/atf-c/detail/fs.c +++ b/contrib/atf/atf-c/detail/fs.c @@ -31,7 +31,6 @@ #include <sys/types.h> #include <sys/param.h> -#include <sys/mount.h> #include <sys/stat.h> #include <sys/wait.h> @@ -59,7 +58,6 @@ static atf_error_t do_mkdtemp(char *); static atf_error_t normalize(atf_dynstr_t *, char *); static atf_error_t normalize_ap(atf_dynstr_t *, const char *, va_list); static void replace_contents(atf_fs_path_t *, const char *); -static const char *stat_type_to_string(const int); /* --------------------------------------------------------------------- * The "unknown_file_type" error type. @@ -109,16 +107,12 @@ atf_error_t copy_contents(const atf_fs_path_t *p, char **buf) { atf_error_t err; - char *str; - str = (char *)malloc(atf_dynstr_length(&p->m_data) + 1); - if (str == NULL) + *buf = strdup(atf_fs_path_cstring(p)); + if (*buf == NULL) err = atf_no_memory_error(); - else { - strcpy(str, atf_dynstr_cstring(&p->m_data)); - *buf = str; + else err = atf_no_error(); - } return err; } @@ -211,6 +205,7 @@ normalize_ap(atf_dynstr_t *d, const char *p, va_list ap) else { err = normalize(d, str); free(str); + str = NULL; } out: @@ -231,36 +226,6 @@ replace_contents(atf_fs_path_t *p, const char *buf) INV(!atf_is_error(err)); } -static -const char * -stat_type_to_string(const int type) -{ - const char *str; - - if (type == atf_fs_stat_blk_type) - str = "block device"; - else if (type == atf_fs_stat_chr_type) - str = "character device"; - else if (type == atf_fs_stat_dir_type) - str = "directory"; - else if (type == atf_fs_stat_fifo_type) - str = "named pipe"; - else if (type == atf_fs_stat_lnk_type) - str = "symbolic link"; - else if (type == atf_fs_stat_reg_type) - str = "regular file"; - else if (type == atf_fs_stat_sock_type) - str = "socket"; - else if (type == atf_fs_stat_wht_type) - str = "whiteout"; - else { - UNREACHABLE; - str = NULL; - } - - return str; -} - /* --------------------------------------------------------------------- * The "atf_fs_path" type. * --------------------------------------------------------------------- */ @@ -730,15 +695,14 @@ atf_fs_mkdtemp(atf_fs_path_t *p) err = do_mkdtemp(buf); if (atf_is_error(err)) - goto out_buf; + goto out; replace_contents(p, buf); INV(!atf_is_error(err)); -out_buf: - free(buf); out: - umask(mask); + (void)umask(mask); + free(buf); return err; } @@ -759,16 +723,15 @@ atf_fs_mkstemp(atf_fs_path_t *p, int *fdout) err = do_mkstemp(buf, &fd); if (atf_is_error(err)) - goto out_buf; + goto out; replace_contents(p, buf); *fdout = fd; INV(!atf_is_error(err)); -out_buf: - free(buf); out: - umask(mask); + (void)umask(mask); + free(buf); return err; } diff --git a/contrib/atf/atf-c/detail/fs_test.c b/contrib/atf/atf-c/detail/fs_test.c index a9cc34a4f48b..937cf193aa91 100644 --- a/contrib/atf/atf-c/detail/fs_test.c +++ b/contrib/atf/atf-c/detail/fs_test.c @@ -901,8 +901,8 @@ do_umask_check(atf_error_t (*const mk_func)(atf_fs_path_t *), const char *exp_name) { atf_fs_path_t path; - int pre_mask, post_mask; atf_error_t err; + mode_t pre_mask, post_mask; printf("Creating temporary %s with umask %05o\n", exp_name, test_mask); @@ -1039,9 +1039,12 @@ ATF_TC_BODY(mkstemp_umask, tc) RE(atf_fs_path_init_fmt(&p, "testfile.XXXXXX")); - do_umask_check(mkstemp_discard_fd, atf_fs_unlink, &p, 00100, "regular file"); - do_umask_check(mkstemp_discard_fd, atf_fs_unlink, &p, 00200, "regular file"); - do_umask_check(mkstemp_discard_fd, atf_fs_unlink, &p, 00400, "regular file"); + do_umask_check(mkstemp_discard_fd, atf_fs_unlink, &p, 00100, + "regular file"); + do_umask_check(mkstemp_discard_fd, atf_fs_unlink, &p, 00200, + "regular file"); + do_umask_check(mkstemp_discard_fd, atf_fs_unlink, &p, 00400, + "regular file"); atf_fs_path_fini(&p); } diff --git a/contrib/atf/atf-c/detail/list.c b/contrib/atf/atf-c/detail/list.c index 7ac9f1fc948b..15b34cf17ba6 100644 --- a/contrib/atf/atf-c/detail/list.c +++ b/contrib/atf/atf-c/detail/list.c @@ -84,8 +84,10 @@ static void delete_entry(struct list_entry *le) { - if (le->m_managed) + if (le->m_managed) { free(le->m_object); + le->m_object = NULL; + } free(le); } @@ -204,6 +206,7 @@ atf_list_init(atf_list_t *l) leend = new_entry(NULL, false); if (leend == NULL) { free(lebeg); + lebeg = NULL; return atf_no_memory_error(); } diff --git a/contrib/atf/atf-c/detail/map.c b/contrib/atf/atf-c/detail/map.c index ae11a44f35f8..67f744e31318 100644 --- a/contrib/atf/atf-c/detail/map.c +++ b/contrib/atf/atf-c/detail/map.c @@ -188,7 +188,12 @@ atf_map_init_charpp(atf_map_t *m, const char *const *array) } ptr++; - err = atf_map_insert(m, key, strdup(value), true); + char *tmp_value = strdup(value); + if (tmp_value == NULL) { + err = atf_no_memory_error(); + break; + } + err = atf_map_insert(m, key, tmp_value, true); } } @@ -206,9 +211,12 @@ atf_map_fini(atf_map_t *m) atf_list_for_each(iter, &m->m_list) { struct map_entry *me = atf_list_iter_data(iter); - if (me->m_managed) + if (me->m_managed) { free(me->m_value); + me->m_value = NULL; + } free(me->m_key); + me->m_key = NULL; free(me); } atf_list_fini(&m->m_list); @@ -353,9 +361,11 @@ atf_map_insert(atf_map_t *m, const char *key, void *value, bool managed) iter = atf_map_find(m, key); if (atf_equal_map_iter_map_iter(iter, atf_map_end(m))) { me = new_entry(key, value, managed); - if (me == NULL) + if (me == NULL) { err = atf_no_memory_error(); - else { + if (managed) + free(value); + } else { err = atf_list_append(&m->m_list, me, false); if (atf_is_error(err)) { if (managed) @@ -364,8 +374,10 @@ atf_map_insert(atf_map_t *m, const char *key, void *value, bool managed) } } else { me = iter.m_entry; - if (me->m_managed) + if (me->m_managed) { free(me->m_value); + me->m_value = NULL; + } INV(strcmp(me->m_key, key) == 0); me->m_value = value; diff --git a/contrib/atf/atf-c/detail/map_test.c b/contrib/atf/atf-c/detail/map_test.c index 0982e20f7dd5..e8030328784c 100644 --- a/contrib/atf/atf-c/detail/map_test.c +++ b/contrib/atf/atf-c/detail/map_test.c @@ -108,6 +108,7 @@ ATF_TC_BODY(map_init_charpp_short, tc) atf_error_t err = atf_map_init_charpp(&map, array); ATF_REQUIRE(atf_is_error(err)); ATF_REQUIRE(atf_error_is(err, "libc")); + atf_error_free(err); } /* diff --git a/contrib/atf/atf-c/detail/process.c b/contrib/atf/atf-c/detail/process.c index a6189bf78e20..539e39ac058b 100644 --- a/contrib/atf/atf-c/detail/process.c +++ b/contrib/atf/atf-c/detail/process.c @@ -23,6 +23,8 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" + #include "atf-c/detail/process.h" #include <sys/types.h> @@ -42,7 +44,7 @@ /* This prototype is not in the header file because this is a private * function; however, we need to access it during testing. */ -atf_error_t atf_process_status_init(atf_process_status_t *, int); +atf_error_t atf_process_status_init(atf_process_status_t *, siginfo_t *); /* --------------------------------------------------------------------- * The "stream_prepare" auxiliary type. @@ -65,6 +67,8 @@ stream_prepare_init(stream_prepare_t *sp, const atf_process_stream_t *sb) const int type = atf_process_stream_type(sb); sp->m_sb = sb; + sp->m_pipefds[0] = -1; + sp->m_pipefds[1] = -1; sp->m_pipefds_ok = false; if (type == atf_process_stream_type_capture) { @@ -186,10 +190,10 @@ atf_process_stream_type(const atf_process_stream_t *sb) * --------------------------------------------------------------------- */ atf_error_t -atf_process_status_init(atf_process_status_t *s, int status) +atf_process_status_init(atf_process_status_t *s, siginfo_t *info) { - s->m_status = status; + s->m_info = *info; return atf_no_error(); } @@ -201,43 +205,36 @@ atf_process_status_fini(atf_process_status_t *s ATF_DEFS_ATTRIBUTE_UNUSED) bool atf_process_status_exited(const atf_process_status_t *s) { - int mutable_status = s->m_status; - return WIFEXITED(mutable_status); + return s->m_info.si_code == CLD_EXITED; } int atf_process_status_exitstatus(const atf_process_status_t *s) { PRE(atf_process_status_exited(s)); - int mutable_status = s->m_status; - return WEXITSTATUS(mutable_status); + return s->m_info.si_status; } bool atf_process_status_signaled(const atf_process_status_t *s) { - int mutable_status = s->m_status; - return WIFSIGNALED(mutable_status); + /* Issue #187: `si_code` is a macro on NetBSD. */ + int code = s->m_info.si_code; + return code == CLD_KILLED || code == CLD_DUMPED; } int atf_process_status_termsig(const atf_process_status_t *s) { PRE(atf_process_status_signaled(s)); - int mutable_status = s->m_status; - return WTERMSIG(mutable_status); + return s->m_info.si_status; } bool atf_process_status_coredump(const atf_process_status_t *s) { PRE(atf_process_status_signaled(s)); -#if defined(WCOREDUMP) - int mutable_status = s->m_status; - return WCOREDUMP(mutable_status); -#else - return false; -#endif + return s->m_info.si_code == CLD_DUMPED; } /* --------------------------------------------------------------------- @@ -245,14 +242,12 @@ atf_process_status_coredump(const atf_process_status_t *s) * --------------------------------------------------------------------- */ static -atf_error_t +void atf_process_child_init(atf_process_child_t *c) { c->m_pid = 0; c->m_stdout = -1; c->m_stderr = -1; - - return atf_no_error(); } static @@ -269,14 +264,14 @@ atf_error_t atf_process_child_wait(atf_process_child_t *c, atf_process_status_t *s) { atf_error_t err; - int status; + siginfo_t info; - if (waitpid(c->m_pid, &status, 0) == -1) + if (waitid(P_PID, c->m_pid, &info, WEXITED) == -1) err = atf_libc_error(errno, "Failed waiting for process %d", c->m_pid); else { atf_process_child_fini(c); - err = atf_process_status_init(s, status); + err = atf_process_status_init(s, &info); } return err; @@ -347,7 +342,7 @@ child_connect(const stream_prepare_t *sp, int procfd) err = safe_dup(sp->m_sb->m_fd, procfd); } else if (type == atf_process_stream_type_redirect_path) { int aux = open(atf_fs_path_cstring(sp->m_sb->m_path), - O_WRONLY | O_CREAT | O_TRUNC, 0644); + O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644); if (aux == -1) err = atf_libc_error(errno, "Could not create %s", atf_fs_path_cstring(sp->m_sb->m_path)); @@ -387,25 +382,17 @@ parent_connect(const stream_prepare_t *sp, int *fd) } static -atf_error_t +void do_parent(atf_process_child_t *c, const pid_t pid, const stream_prepare_t *outsp, const stream_prepare_t *errsp) { - atf_error_t err; - - err = atf_process_child_init(c); - if (atf_is_error(err)) - goto out; c->m_pid = pid; parent_connect(outsp, &c->m_stdout); parent_connect(errsp, &c->m_stderr); - -out: - return err; } static @@ -481,7 +468,7 @@ fork_with_streams(atf_process_child_t *c, abort(); err = atf_no_error(); } else { - err = do_parent(c, pid, &outsp, &errsp); + do_parent(c, pid, &outsp, &errsp); if (atf_is_error(err)) goto err_errpipe; } @@ -528,6 +515,8 @@ atf_process_fork(atf_process_child_t *c, atf_process_stream_t inherit_outsb, inherit_errsb; const atf_process_stream_t *real_outsb, *real_errsb; + atf_process_child_init(c); + real_outsb = NULL; /* Shut up GCC warning. */ err = init_stream_w_default(outsb, &inherit_outsb, &real_outsb); if (atf_is_error(err)) @@ -665,7 +654,7 @@ atf_process_exec_list(atf_process_status_t *s, err = atf_process_exec_array(s, prog, argv2, outsb, errsb, prehook); - free(argv2); out: + free(argv2); return err; } diff --git a/contrib/atf/atf-c/detail/process.h b/contrib/atf/atf-c/detail/process.h index 81158d0a5a41..1efbaa2eec10 100644 --- a/contrib/atf/atf-c/detail/process.h +++ b/contrib/atf/atf-c/detail/process.h @@ -28,6 +28,7 @@ #include <sys/types.h> +#include <signal.h> #include <stdbool.h> #include <atf-c/detail/fs.h> @@ -76,7 +77,7 @@ int atf_process_stream_type(const atf_process_stream_t *); * --------------------------------------------------------------------- */ struct atf_process_status { - int m_status; + siginfo_t m_info; }; typedef struct atf_process_status atf_process_status_t; diff --git a/contrib/atf/atf-c/detail/process_test.c b/contrib/atf/atf-c/detail/process_test.c index 82a911df68cd..1fa880b88932 100644 --- a/contrib/atf/atf-c/detail/process_test.c +++ b/contrib/atf/atf-c/detail/process_test.c @@ -26,9 +26,6 @@ #include "atf-c/detail/process.h" #include <sys/types.h> -#ifdef __FreeBSD__ -#include <sys/sysctl.h> -#endif #include <sys/time.h> #include <sys/resource.h> #include <sys/wait.h> @@ -47,7 +44,7 @@ #include "atf-c/detail/sanity.h" #include "atf-c/detail/test_helpers.h" -atf_error_t atf_process_status_init(atf_process_status_t *, int); +atf_error_t atf_process_status_init(atf_process_status_t *, siginfo_t *); /* --------------------------------------------------------------------- * Auxiliary functions for testing of 'atf_process_fork'. @@ -166,6 +163,7 @@ capture_stream_fini(void *v) } free(s->m_msg); + s->m_msg = NULL; atf_process_stream_fini(&s->m_base.m_sb); } @@ -576,23 +574,19 @@ child_sigterm(void) } static -int -fork_and_wait_child(void (*child_func)(void)) +void +fork_and_wait_child(void (*child_func)(void), siginfo_t *info) { pid_t pid; - int status; pid = fork(); ATF_REQUIRE(pid != -1); if (pid == 0) { - status = 0; /* Silence compiler warnings */ child_func(); UNREACHABLE; } else { - ATF_REQUIRE(waitpid(pid, &status, 0) != 0); + ATF_REQUIRE(waitid(P_PID, pid, info, WEXITED) != -1); } - - return status; } ATF_TC(status_exited); @@ -603,10 +597,12 @@ ATF_TC_HEAD(status_exited, tc) } ATF_TC_BODY(status_exited, tc) { + siginfo_t info; + { - const int rawstatus = fork_and_wait_child(child_exit_success); + fork_and_wait_child(child_exit_success, &info); atf_process_status_t s; - RE(atf_process_status_init(&s, rawstatus)); + RE(atf_process_status_init(&s, &info)); ATF_CHECK(atf_process_status_exited(&s)); ATF_CHECK_EQ(atf_process_status_exitstatus(&s), EXIT_SUCCESS); ATF_CHECK(!atf_process_status_signaled(&s)); @@ -614,9 +610,9 @@ ATF_TC_BODY(status_exited, tc) } { - const int rawstatus = fork_and_wait_child(child_exit_failure); + fork_and_wait_child(child_exit_failure, &info); atf_process_status_t s; - RE(atf_process_status_init(&s, rawstatus)); + RE(atf_process_status_init(&s, &info)); ATF_CHECK(atf_process_status_exited(&s)); ATF_CHECK_EQ(atf_process_status_exitstatus(&s), EXIT_FAILURE); ATF_CHECK(!atf_process_status_signaled(&s)); @@ -632,10 +628,12 @@ ATF_TC_HEAD(status_signaled, tc) } ATF_TC_BODY(status_signaled, tc) { + siginfo_t info; + { - const int rawstatus = fork_and_wait_child(child_sigkill); + fork_and_wait_child(child_sigkill, &info); atf_process_status_t s; - RE(atf_process_status_init(&s, rawstatus)); + RE(atf_process_status_init(&s, &info)); ATF_CHECK(!atf_process_status_exited(&s)); ATF_CHECK(atf_process_status_signaled(&s)); ATF_CHECK_EQ(atf_process_status_termsig(&s), SIGKILL); @@ -644,9 +642,9 @@ ATF_TC_BODY(status_signaled, tc) } { - const int rawstatus = fork_and_wait_child(child_sigterm); + fork_and_wait_child(child_sigterm, &info); atf_process_status_t s; - RE(atf_process_status_init(&s, rawstatus)); + RE(atf_process_status_init(&s, &info)); ATF_CHECK(!atf_process_status_exited(&s)); ATF_CHECK(atf_process_status_signaled(&s)); ATF_CHECK_EQ(atf_process_status_termsig(&s), SIGTERM); @@ -670,17 +668,22 @@ ATF_TC_BODY(status_coredump, tc) atf_tc_skip("Cannot unlimit the core file size; check limits " "manually"); -#ifdef __FreeBSD__ - int coredump_enabled; - size_t ce_len = sizeof(coredump_enabled); - if (sysctlbyname("kern.coredump", &coredump_enabled, &ce_len, NULL, - 0) == 0 && !coredump_enabled) - atf_tc_skip("Coredumps disabled"); +#if defined(__APPLE__) + /* + * The default security policy on macOS prevents this check from being + * tested (coredumps aren't generated for unsigned binaries). + * + * TODO(ngie,144): this test fails when run locally on my machines, but not + * in the GHA container images. + */ + atf_tc_skip( + "atf_process_status_coredump check fails on macOS"); #endif - const int rawstatus = fork_and_wait_child(child_sigquit); + siginfo_t info; + fork_and_wait_child(child_sigquit, &info); atf_process_status_t s; - RE(atf_process_status_init(&s, rawstatus)); + RE(atf_process_status_init(&s, &info)); ATF_CHECK(!atf_process_status_exited(&s)); ATF_CHECK(atf_process_status_signaled(&s)); ATF_CHECK_EQ(atf_process_status_termsig(&s), SIGQUIT); diff --git a/contrib/atf/atf-c/detail/sanity_test.c b/contrib/atf/atf-c/detail/sanity_test.c index a986c32ae3c8..7d4e39054d7e 100644 --- a/contrib/atf/atf-c/detail/sanity_test.c +++ b/contrib/atf/atf-c/detail/sanity_test.c @@ -85,6 +85,8 @@ do_test_child(void *v) exit(EXIT_SUCCESS); } +#define MAX_LINES 3 + static void do_test(enum type t, bool cond) @@ -92,7 +94,7 @@ do_test(enum type t, bool cond) atf_process_child_t child; atf_process_status_t status; int nlines; - char *lines[3]; + char *lines[MAX_LINES] = { 0 }; { atf_process_stream_t outsb, errsb; @@ -106,16 +108,17 @@ do_test(enum type t, bool cond) } nlines = 0; - while (nlines < 3 && (lines[nlines] = + while (nlines < MAX_LINES && (lines[nlines] = atf_utils_readline(atf_process_child_stderr(&child))) != NULL) nlines++; - ATF_REQUIRE(nlines == 0 || nlines == 3); RE(atf_process_child_wait(&child, &status)); if (!cond) { + ATF_REQUIRE(nlines == MAX_LINES); ATF_REQUIRE(atf_process_status_signaled(&status)); ATF_REQUIRE(atf_process_status_termsig(&status) == SIGABRT); } else { + ATF_REQUIRE(nlines == 0); ATF_REQUIRE(atf_process_status_exited(&status)); ATF_REQUIRE(atf_process_status_exitstatus(&status) == EXIT_SUCCESS); } diff --git a/contrib/atf/atf-c/detail/text.c b/contrib/atf/atf-c/detail/text.c index 3b1d7e7fe2a4..f4da2c5a6990 100644 --- a/contrib/atf/atf-c/detail/text.c +++ b/contrib/atf/atf-c/detail/text.c @@ -56,6 +56,7 @@ atf_text_for_each_word(const char *instr, const char *sep, } free(str); + str = NULL; out: return err; } diff --git a/contrib/atf/atf-c/detail/tp_main.c b/contrib/atf/atf-c/detail/tp_main.c index 439384b4950e..39cc29802f2d 100644 --- a/contrib/atf/atf-c/detail/tp_main.c +++ b/contrib/atf/atf-c/detail/tp_main.c @@ -198,8 +198,8 @@ params_fini(struct params *p) atf_map_fini(&p->m_config); atf_fs_path_fini(&p->m_resfile); atf_fs_path_fini(&p->m_srcdir); - if (p->m_tcname != NULL) - free(p->m_tcname); + free(p->m_tcname); + p->m_tcname = NULL; } static @@ -248,7 +248,7 @@ static void list_tcs(const atf_tp_t *tp) { - const atf_tc_t *const *tcs; + const atf_tc_t **tcs; const atf_tc_t *const *tcsptr; printf("Content-Type: application/X-atf-tp; version=\"1\"\n\n"); @@ -280,6 +280,8 @@ list_tcs(const atf_tp_t *tp) atf_utils_free_charpp(vars); } + free(tcs); + tcs = NULL; } /* --------------------------------------------------------------------- @@ -288,19 +290,20 @@ list_tcs(const atf_tp_t *tp) static atf_error_t -handle_tcarg(const char *tcarg, char **tcname, enum tc_part *tcpart) +handle_tcarg(const char *tcarg, char **tcname_out, enum tc_part *tcpart) { + char *delim, *tcname; atf_error_t err; - err = atf_no_error(); - - *tcname = strdup(tcarg); - if (*tcname == NULL) { - err = atf_no_memory_error(); - goto out; + *tcname_out = NULL; + tcname = strdup(tcarg); + if (tcname == NULL) { + return atf_no_memory_error(); } - char *delim = strchr(*tcname, ':'); + err = atf_no_error(); + + delim = strchr(tcname, ':'); if (delim != NULL) { *delim = '\0'; @@ -311,11 +314,12 @@ handle_tcarg(const char *tcarg, char **tcname, enum tc_part *tcpart) *tcpart = CLEANUP; } else { err = usage_error("Invalid test case part `%s'", delim); - goto out; + free(tcname); } } -out: + if (!atf_is_error(err)) + *tcname_out = tcname; return err; } @@ -327,9 +331,7 @@ process_params(int argc, char **argv, struct params *p) int ch; int old_opterr; - err = params_init(p, argv[0]); - if (atf_is_error(err)) - goto out; + err = atf_no_error(); old_opterr = opterr; opterr = 0; @@ -387,10 +389,6 @@ process_params(int argc, char **argv, struct params *p) } } - if (atf_is_error(err)) - params_fini(p); - -out: return err; } @@ -484,12 +482,10 @@ run_tc(const atf_tp_t *tp, struct params *p, int *exitcode) { atf_error_t err; - err = atf_no_error(); + if (!atf_tp_has_tc(tp, p->m_tcname)) + return usage_error("Unknown test case `%s'", p->m_tcname); - if (!atf_tp_has_tc(tp, p->m_tcname)) { - err = usage_error("Unknown test case `%s'", p->m_tcname); - goto out; - } + err = atf_no_error(); if (!atf_env_has("__RUNNING_INSIDE_ATF_RUN") || strcmp(atf_env_get( "__RUNNING_INSIDE_ATF_RUN"), "internal-yes-value") != 0) @@ -529,7 +525,6 @@ run_tc(const atf_tp_t *tp, struct params *p, int *exitcode) } INV(!atf_is_error(err)); -out: return err; } @@ -544,10 +539,14 @@ controlled_main(int argc, char **argv, atf_tp_t tp; char **raw_config; - err = process_params(argc, argv, &p); + err = params_init(&p, argv[0]); if (atf_is_error(err)) goto out; + err = process_params(argc, argv, &p); + if (atf_is_error(err)) + goto out_p; + err = handle_srcdir(&p); if (atf_is_error(err)) goto out_p; @@ -594,12 +593,6 @@ atf_tp_main(int argc, char **argv, atf_error_t (*add_tcs_hook)(atf_tp_t *)) else progname++; - /* Libtool workaround: if running from within the source tree (binaries - * that are not installed yet), skip the "lt-" prefix added to files in - * the ".libs" directory to show the real (not temporary) name. */ - if (strncmp(progname, "lt-", 3) == 0) - progname += 3; - exitcode = EXIT_FAILURE; /* Silence GCC warning. */ err = controlled_main(argc, argv, add_tcs_hook, &exitcode); if (atf_is_error(err)) { diff --git a/contrib/atf/atf-c/error.c b/contrib/atf/atf-c/error.c index 071daf6d2455..2cbee272700d 100644 --- a/contrib/atf/atf-c/error.c +++ b/contrib/atf/atf-c/error.c @@ -32,7 +32,7 @@ #include "atf-c/detail/sanity.h" -/* Theoretically, there can only be a single error intance at any given +/* Theoretically, there can only be a single error instance at any given * point in time, because errors are raised at one point and must be * handled immediately. If another error has to be raised during the * handling process, something else has to be done with the previous @@ -124,11 +124,13 @@ atf_error_free(atf_error_t err) freeit = err->m_free; - if (err->m_data != NULL) - free(err->m_data); + free(err->m_data); + err->m_data = NULL; - if (freeit) + if (freeit) { free(err); + err = NULL; + } error_on_flight = false; } diff --git a/contrib/atf/atf-c/macros.h b/contrib/atf/atf-c/macros.h index abcb9f697907..94279a6a3057 100644 --- a/contrib/atf/atf-c/macros.h +++ b/contrib/atf/atf-c/macros.h @@ -129,26 +129,26 @@ #define ATF_REQUIRE_MSG(expression, fmt, ...) \ do { \ - if (!(expression)) \ + if (expression) {} else \ atf_tc_fail_requirement(__FILE__, __LINE__, fmt, ##__VA_ARGS__); \ } while(0) #define ATF_CHECK_MSG(expression, fmt, ...) \ do { \ - if (!(expression)) \ + if (expression) {} else \ atf_tc_fail_check(__FILE__, __LINE__, fmt, ##__VA_ARGS__); \ } while(0) #define ATF_REQUIRE(expression) \ do { \ - if (!(expression)) \ + if (expression) {} else \ atf_tc_fail_requirement(__FILE__, __LINE__, "%s", \ #expression " not met"); \ } while(0) #define ATF_CHECK(expression) \ do { \ - if (!(expression)) \ + if (expression) {} else \ atf_tc_fail_check(__FILE__, __LINE__, "%s", \ #expression " not met"); \ } while(0) diff --git a/contrib/atf/atf-c/tc.c b/contrib/atf/atf-c/tc.c index 1cef6adbd82d..6ba0a7f2a3c8 100644 --- a/contrib/atf/atf-c/tc.c +++ b/contrib/atf/atf-c/tc.c @@ -26,7 +26,7 @@ #include "atf-c/tc.h" #include <sys/types.h> -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) #include <sys/linker.h> #include <sys/module.h> #endif @@ -107,9 +107,7 @@ static void format_reason_fmt(atf_dynstr_t *, const char *, const size_t, static void errno_test(struct context *, const char *, const size_t, const int, const char *, const bool, void (*)(struct context *, atf_dynstr_t *)); -#ifdef __FreeBSD__ static atf_error_t check_kmod(struct context *, const char *); -#endif static atf_error_t check_prog_in_dir(const char *, void *); static atf_error_t check_prog(struct context *, const char *); @@ -144,7 +142,7 @@ context_set_resfile(struct context *ctx, const char *resfile) else if (strcmp(resfile, "/dev/stderr") == 0) ctx->resfilefd = STDERR_FILENO; else - ctx->resfilefd = open(resfile, O_WRONLY | O_CREAT | O_TRUNC, + ctx->resfilefd = open(resfile, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (ctx->resfilefd == -1) { err = atf_libc_error(errno, @@ -467,8 +465,8 @@ errno_test(struct context *ctx, const char *file, const size_t line, } } -#ifdef __FreeBSD__ -static atf_error_t +#if defined(__FreeBSD__) +atf_error_t check_kmod(struct context *ctx, const char *kmod) { struct kld_file_stat fstat = { .version = sizeof(fstat) }; @@ -478,26 +476,41 @@ check_kmod(struct context *ctx, const char *kmod) int fid, mid; for (fid = kldnext(0); fid > 0; fid = kldnext(fid)) { - if (kldstat(fid, &fstat) != 0) - continue; - if (strcmp(fstat.name, kmod) == 0) - goto done; - if (strncmp(fstat.name, kmod, len) == 0 && - strcmp(fstat.name + len, ".ko") == 0) - goto done; - for (mid = kldfirstmod(fid); mid > 0; mid = modfnext(mid)) { - if (modstat(mid, &mstat) != 0) - continue; - if (strcmp(mstat.name, kmod) == 0) - goto done; - } + if (kldstat(fid, &fstat) != 0) + continue; + + if (strcmp(fstat.name, kmod) == 0) + goto done; + + if (strncmp(fstat.name, kmod, len) == 0 && + strcmp(fstat.name + len, ".ko") == 0) + goto done; + + for (mid = kldfirstmod(fid); mid > 0; mid = modfnext(mid)) { + if (modstat(mid, &mstat) != 0) + continue; + if (strcmp(mstat.name, kmod) == 0) + goto done; + } } - format_reason_fmt(&reason, NULL, 0, "The required kmod %s " - "is not loaded", kmod); + format_reason_fmt(&reason, NULL, 0, + "The required kmod %s is not loaded", kmod); fail_requirement(ctx, &reason); + done: return atf_no_error(); } +#else +atf_error_t +check_kmod(struct context *ctx, const char *kmod ATF_DEFS_ATTRIBUTE_UNUSED) +{ + atf_dynstr_t reason; + + format_reason_fmt(&reason, NULL, 0, + "This API is only available on FreeBSD"); + fail_requirement(ctx, &reason); + return atf_no_error(); +} #endif struct prog_found_pair { @@ -688,8 +701,10 @@ atf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack, void atf_tc_fini(atf_tc_t *tc) { + atf_map_fini(&tc->pimpl->m_config); atf_map_fini(&tc->pimpl->m_vars); free(tc->pimpl); + tc->pimpl = NULL; } /* @@ -851,8 +866,10 @@ atf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...) if (!atf_is_error(err)) err = atf_map_insert(&tc->pimpl->m_vars, name, value, true); - else + else { free(value); + value = NULL; + } return err; } @@ -869,9 +886,7 @@ static void _atf_tc_fail_check(struct context *, const char *, const size_t, static void _atf_tc_fail_requirement(struct context *, const char *, const size_t, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN; static void _atf_tc_pass(struct context *) ATF_DEFS_ATTRIBUTE_NORETURN; -#ifdef __FreeBSD__ static void _atf_tc_require_kmod(struct context *, const char *); -#endif static void _atf_tc_require_prog(struct context *, const char *); static void _atf_tc_skip(struct context *, const char *, va_list) ATF_DEFS_ATTRIBUTE_NORETURN; @@ -951,13 +966,11 @@ _atf_tc_pass(struct context *ctx) UNREACHABLE; } -#ifdef __FreeBSD__ static void -_atf_tc_require_kmod(struct context *ctx, const char *kmod) +_atf_tc_require_kmod(struct context *ctx, const char *prog) { - check_fatal_error(check_kmod(ctx, kmod)); + check_fatal_error(check_kmod(ctx, prog)); } -#endif static void _atf_tc_require_prog(struct context *ctx, const char *prog) @@ -1205,7 +1218,6 @@ atf_tc_pass(void) _atf_tc_pass(&Current); } -#ifdef __FreeBSD__ void atf_tc_require_kmod(const char *kmod) { @@ -1213,7 +1225,6 @@ atf_tc_require_kmod(const char *kmod) _atf_tc_require_kmod(&Current, kmod); } -#endif void atf_tc_require_prog(const char *prog) diff --git a/contrib/atf/atf-c/tc.h b/contrib/atf/atf-c/tc.h index 5109102750c7..dda704f8cff8 100644 --- a/contrib/atf/atf-c/tc.h +++ b/contrib/atf/atf-c/tc.h @@ -106,9 +106,7 @@ void atf_tc_fail_nonfatal(const char *, ...) ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(1, 2); void atf_tc_pass(void) ATF_DEFS_ATTRIBUTE_NORETURN; -#ifdef __FreeBSD__ void atf_tc_require_kmod(const char *); -#endif void atf_tc_require_prog(const char *); void atf_tc_skip(const char *, ...) ATF_DEFS_ATTRIBUTE_FORMAT_PRINTF(1, 2) diff --git a/contrib/atf/atf-c/tc_test.c b/contrib/atf/atf-c/tc_test.c index 616c37e94e68..e896c6b3c2a1 100644 --- a/contrib/atf/atf-c/tc_test.c +++ b/contrib/atf/atf-c/tc_test.c @@ -156,6 +156,84 @@ ATF_TC_BODY(config, tcin) atf_tc_fini(&tc); } +#if defined(__FreeBSD__) +ATF_TC(require_kmod_basic); +ATF_TC_HEAD(require_kmod_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", + "atf_require_kmod: ensures that a test continues if the target kmod " + "is found."); +} +ATF_TC_BODY(require_kmod_basic, tc) +{ +#if 0 + atf_tc_require_kmod("kernel"); +#endif +} + +ATF_TC(require_kmod_negative); +ATF_TC_HEAD(require_kmod_negative, tc) +{ + atf_tc_set_md_var(tc, "descr", + "atf_require_kmod: skips test if the target kmod is not found."); +} +ATF_TC_BODY(require_kmod_negative, tc) +{ + atf_tc_expect_fail("This should fail."); + atf_tc_require_kmod("nonexistent"); +} +#endif + +ATF_TC(require_prog_absolute); +ATF_TC_HEAD(require_prog_absolute, tc) +{ + atf_tc_set_md_var(tc, "descr", + "atf_require_prog: ensures that a test continues if the target program " + "is found (absolute)."); +} +ATF_TC_BODY(require_prog_absolute, tc) +{ + atf_tc_require_prog("/bin/sh"); +} + +ATF_TC(require_prog_negative_absolute); +ATF_TC_HEAD(require_prog_negative_absolute, tc) +{ + atf_tc_set_md_var(tc, "descr", + "atf_require_prog: skips test if the target program is not found " + "(absolute)."); +} +ATF_TC_BODY(require_prog_negative_absolute, tc) +{ + atf_tc_expect_fail("This should fail."); + atf_tc_require_prog("/nonexistent"); +} + +ATF_TC(require_prog_negative_nonabsolute); +ATF_TC_HEAD(require_prog_negative_nonabsolute, tc) +{ + atf_tc_set_md_var(tc, "descr", + "atf_require_prog: skips test if the target program is not found " + "(non-absolute)."); +} +ATF_TC_BODY(require_prog_negative_nonabsolute, tc) +{ + atf_tc_expect_fail("This should fail."); + atf_tc_require_prog("nonexistent"); +} + +ATF_TC(require_prog_nonabsolute); +ATF_TC_HEAD(require_prog_nonabsolute, tc) +{ + atf_tc_set_md_var(tc, "descr", + "atf_require_prog: ensures that a test continues if the target program " + "is found (non-absolute)."); +} +ATF_TC_BODY(require_prog_nonabsolute, tc) +{ + atf_tc_require_prog("true"); +} + /* --------------------------------------------------------------------- * Test cases for the free functions. * --------------------------------------------------------------------- */ @@ -175,6 +253,14 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, init_pack); ATF_TP_ADD_TC(tp, vars); ATF_TP_ADD_TC(tp, config); +#if defined(__FreeBSD__) + ATF_TP_ADD_TC(tp, require_kmod_basic); + ATF_TP_ADD_TC(tp, require_kmod_negative); +#endif + ATF_TP_ADD_TC(tp, require_prog_absolute); + ATF_TP_ADD_TC(tp, require_prog_negative_absolute); + ATF_TP_ADD_TC(tp, require_prog_negative_nonabsolute); + ATF_TP_ADD_TC(tp, require_prog_nonabsolute); /* Add the test cases for the free functions. */ /* TODO */ diff --git a/contrib/atf/atf-c/tp.c b/contrib/atf/atf-c/tp.c index f4f225772ca2..e3155287d722 100644 --- a/contrib/atf/atf-c/tp.c +++ b/contrib/atf/atf-c/tp.c @@ -112,6 +112,7 @@ atf_tp_fini(atf_tp_t *tp) atf_list_fini(&tp->pimpl->m_tcs); free(tp->pimpl); + tp->pimpl = NULL; } /* @@ -139,7 +140,7 @@ atf_tp_get_tc(const atf_tp_t *tp, const char *id) return tc; } -const atf_tc_t *const * +const atf_tc_t ** atf_tp_get_tcs(const atf_tp_t *tp) { const atf_tc_t **array; diff --git a/contrib/atf/atf-c/tp.h b/contrib/atf/atf-c/tp.h index c176f7d96f5e..121aaab3428e 100644 --- a/contrib/atf/atf-c/tp.h +++ b/contrib/atf/atf-c/tp.h @@ -50,7 +50,7 @@ void atf_tp_fini(atf_tp_t *); char **atf_tp_get_config(const atf_tp_t *); bool atf_tp_has_tc(const atf_tp_t *, const char *); const struct atf_tc *atf_tp_get_tc(const atf_tp_t *, const char *); -const struct atf_tc *const *atf_tp_get_tcs(const atf_tp_t *); +const struct atf_tc **atf_tp_get_tcs(const atf_tp_t *); /* Modifiers. */ atf_error_t atf_tp_add_tc(atf_tp_t *, struct atf_tc *); diff --git a/contrib/atf/atf-c/tp_test.c b/contrib/atf/atf-c/tp_test.c index de334a97483b..03ef4b2660fd 100644 --- a/contrib/atf/atf-c/tp_test.c +++ b/contrib/atf/atf-c/tp_test.c @@ -23,6 +23,7 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "atf-c/tp.h" #include <string.h> diff --git a/contrib/atf/atf-c/utils.c b/contrib/atf/atf-c/utils.c index d8355bc68936..70b68adf0943 100644 --- a/contrib/atf/atf-c/utils.c +++ b/contrib/atf/atf-c/utils.c @@ -32,6 +32,7 @@ #include <errno.h> #include <fcntl.h> #include <regex.h> +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -59,16 +60,19 @@ init_out_filename(atf_dynstr_t *name, const pid_t pid, const char *suffix, { atf_error_t error; - error = atf_dynstr_init_fmt(name, "atf_utils_fork_%d_%s.txt", - (int)pid, suffix); - if (atf_is_error(error)) { - char buffer[1024]; - atf_error_format(error, buffer, sizeof(buffer)); - if (in_parent) { - atf_tc_fail("Failed to create output file: %s", buffer); - } else { - err(EXIT_FAILURE, "Failed to create output file: %s", buffer); - } + error = atf_dynstr_init_fmt(name, "atf_utils_fork_%d_%s.txt", pid, suffix); + if (!atf_is_error(error)) + return; + + char buffer[1024]; + + atf_error_format(error, buffer, sizeof(buffer)); + atf_error_free(error); + + if (in_parent) { + atf_tc_fail("Failed to create output file: %s", buffer); + } else { + err(EXIT_FAILURE, "Failed to create output file: %s", buffer); } } @@ -104,8 +108,8 @@ grep_string(const char *regex, const char *str) void atf_utils_cat_file(const char *name, const char *prefix) { - const int fd = open(name, O_RDONLY); - ATF_REQUIRE_MSG(fd != -1, "Cannot open %s", name); + const int fd = open(name, O_RDONLY | O_CLOEXEC); + ATF_REQUIRE_MSG(fd != -1, "Cannot open %s: %s", name, strerror(errno)); char buffer[1024]; ssize_t count; @@ -145,7 +149,7 @@ atf_utils_cat_file(const char *name, const char *prefix) bool atf_utils_compare_file(const char *name, const char *contents) { - const int fd = open(name, O_RDONLY); + const int fd = open(name, O_RDONLY | O_CLOEXEC); ATF_REQUIRE_MSG(fd != -1, "Cannot open %s", name); const char *pos = contents; @@ -173,11 +177,12 @@ atf_utils_compare_file(const char *name, const char *contents) void atf_utils_copy_file(const char *source, const char *destination) { - const int input = open(source, O_RDONLY); + const int input = open(source, O_RDONLY | O_CLOEXEC); ATF_REQUIRE_MSG(input != -1, "Failed to open source file during " "copy (%s)", source); - const int output = open(destination, O_WRONLY | O_CREAT | O_TRUNC, 0777); + const int output = open(destination, + O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0777); ATF_REQUIRE_MSG(output != -1, "Failed to open destination file during " "copy (%s)", destination); @@ -216,7 +221,7 @@ atf_utils_create_file(const char *name, const char *contents, ...) va_end(ap); ATF_REQUIRE(!atf_is_error(error)); - const int fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0644); + const int fd = open(name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644); ATF_REQUIRE_MSG(fd != -1, "Cannot create file %s", name); ATF_REQUIRE(write(fd, atf_dynstr_cstring(&formatted), atf_dynstr_length(&formatted)) != -1); @@ -234,14 +239,12 @@ bool atf_utils_file_exists(const char *path) { const int ret = access(path, F_OK); - if (ret == -1) { - if (errno != ENOENT) - atf_tc_fail("Failed to check the existence of %s: %s", path, - strerror(errno)); - else - return false; - } else + if (ret != -1) return true; + if (errno != ENOENT) + atf_tc_fail("Failed to check the existence of %s: %s", path, + strerror(errno)); + return false; } /** Spawns a subprocess and redirects its output to files. @@ -290,10 +293,13 @@ atf_utils_free_charpp(char **argv) { char **ptr; - for (ptr = argv; *ptr != NULL; ptr++) + for (ptr = argv; *ptr != NULL; ptr++) { free(*ptr); + *ptr = NULL; + } free(argv); + argv = NULL; } /** Searches for a regexp in a file. @@ -316,7 +322,8 @@ atf_utils_grep_file(const char *regex, const char *file, ...) va_end(ap); ATF_REQUIRE(!atf_is_error(error)); - ATF_REQUIRE((fd = open(file, O_RDONLY)) != -1); + fd = open(file, O_RDONLY | O_CLOEXEC); + ATF_REQUIRE_MSG(fd != -1, "Cannot open %s: %s", file, strerror(errno)); bool found = false; char *line = NULL; while (!found && (line = atf_utils_readline(fd)) != NULL) { @@ -404,7 +411,8 @@ atf_utils_redirect(const int target_fd, const char *name) else if (target_fd == STDERR_FILENO) fflush(stderr); - const int new_fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0644); + const int new_fd = open(name, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, + 0644); if (new_fd == -1) err(EXIT_FAILURE, "Cannot create %s", name); if (new_fd != target_fd) { @@ -425,8 +433,9 @@ void atf_utils_wait(const pid_t pid, const int exitstatus, const char *expout, const char *experr) { - int status; - ATF_REQUIRE(waitpid(pid, &status, 0) != -1); + siginfo_t info; + ATF_REQUIRE(waitid(P_PID, pid, &info, WEXITED) != -1); + ATF_REQUIRE(info.si_pid == pid); atf_dynstr_t out_name; init_out_filename(&out_name, pid, "out", true); @@ -437,8 +446,8 @@ atf_utils_wait(const pid_t pid, const int exitstatus, const char *expout, atf_utils_cat_file(atf_dynstr_cstring(&out_name), "subprocess stdout: "); atf_utils_cat_file(atf_dynstr_cstring(&err_name), "subprocess stderr: "); - ATF_REQUIRE(WIFEXITED(status)); - ATF_REQUIRE_EQ(exitstatus, WEXITSTATUS(status)); + ATF_REQUIRE(info.si_code == CLD_EXITED); + ATF_REQUIRE_EQ(exitstatus, info.si_status); const char *save_prefix = "save:"; const size_t save_prefix_length = strlen(save_prefix); @@ -463,4 +472,7 @@ atf_utils_wait(const pid_t pid, const int exitstatus, const char *expout, ATF_REQUIRE(unlink(atf_dynstr_cstring(&out_name)) != -1); ATF_REQUIRE(unlink(atf_dynstr_cstring(&err_name)) != -1); + + atf_dynstr_fini(&out_name); + atf_dynstr_fini(&err_name); } diff --git a/contrib/atf/atf-c/utils.h b/contrib/atf/atf-c/utils.h index 422186a31e76..8764cc506105 100644 --- a/contrib/atf/atf-c/utils.h +++ b/contrib/atf/atf-c/utils.h @@ -26,6 +26,7 @@ #if !defined(ATF_C_UTILS_H) #define ATF_C_UTILS_H +#include <sys/types.h> #include <stdbool.h> #include <unistd.h> diff --git a/contrib/atf/atf-sh/.gitignore b/contrib/atf/atf-sh/.gitignore deleted file mode 100644 index a29438f1a9b8..000000000000 --- a/contrib/atf/atf-sh/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -atf-check -atf-sh diff --git a/contrib/atf/atf-sh/Kyuafile b/contrib/atf/atf-sh/Kyuafile index 01a9253e7ebd..f128e3cb88a9 100644 --- a/contrib/atf/atf-sh/Kyuafile +++ b/contrib/atf/atf-sh/Kyuafile @@ -9,3 +9,4 @@ atf_test_program{name="config_test"} atf_test_program{name="atf-check_test"} atf_test_program{name="atf_check_test"} atf_test_program{name="integration_test"} +atf_test_program{name="kmod_test"} diff --git a/contrib/atf/atf-sh/Kyuafile.in b/contrib/atf/atf-sh/Kyuafile.in new file mode 100644 index 000000000000..01a9253e7ebd --- /dev/null +++ b/contrib/atf/atf-sh/Kyuafile.in @@ -0,0 +1,11 @@ +syntax("kyuafile", 1) + +test_suite("atf") + +atf_test_program{name="tc_test"} +atf_test_program{name="tp_test"} +atf_test_program{name="normalize_test"} +atf_test_program{name="config_test"} +atf_test_program{name="atf-check_test"} +atf_test_program{name="atf_check_test"} +atf_test_program{name="integration_test"} diff --git a/contrib/atf/atf-sh/atf-check.1 b/contrib/atf/atf-sh/atf-check.1 index b03058e8442c..18d000a8750c 100644 --- a/contrib/atf/atf-sh/atf-check.1 +++ b/contrib/atf/atf-sh/atf-check.1 @@ -22,7 +22,7 @@ .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.Dd June 21, 2020 +.Dd August 13, 2026 .Dt ATF-CHECK 1 .Os .Sh NAME @@ -34,11 +34,12 @@ .Op Fl o Ar action:arg ... .Op Fl e Ar action:arg ... .Op Fl x +.Op Fl r Ar timeout[:interval] .Ar command .Sh DESCRIPTION .Nm executes a given command and analyzes its results, including -exit code, stdout and stderr. +exit code, stdout, and stderr. .Pp .Bf Em Test cases must use @@ -47,24 +48,27 @@ Test cases must use builtin function instead of calling this utility directly. .Ef .Pp -In the first synopsis form, .Nm will execute the provided command and apply checks specified by arguments. -By default it will act as if it was run with +By default +.Nm +acts as if it was run with .Fl s .Ar exit:0 .Fl o .Ar empty .Fl e .Ar empty . -Multiple checks for the same output channel are allowed and, if specified, -their results will be combined as a logical and (meaning that the output must -match all the provided checks). .Pp -In the second synopsis form, -.Nm -will print information about all supported options and their purpose. +.Fl o +.Ar empty +and +.Fl e +.Ar empty +may be specified multiple times. +If they are specified multiple times, the checks will be applied to +the appropriate stream in the order they were provided. .Pp The following options are available: .Bl -tag -width XqualXvalueXX @@ -80,11 +84,11 @@ accepted. .It Ar ignore ignores the exit check. .It Ar signal:<value> -checks that the program exited due to a signal and that the signal that -terminated it is +checks that the program exited due to a signal, and (optionally) checks that the +signal which terminated the process is .Va value . -The signal can be specified both as a number or as a name, or it can also -be omitted altogether, in which case any signal is accepted. +The signal can be specified as a number, a name, or it can be omitted +altogether (in which case any signal is accepted). .El .Pp Most of these checkers can be prefixed by the @@ -112,7 +116,9 @@ Most of these checkers can be prefixed by the .Sq not- string, which effectively reverses the check. .It Fl e Ar action:arg -Analyzes standard error (syntax identical to above) +Analyzes standard error. +The usage is identical to +.Fl o . .It Fl x Executes .Ar command @@ -150,15 +156,15 @@ instead of executing directly: .Bd -literal -offset indent # Exit code 0, nothing on stdout/stderr -atf_check 'true' +atf_check true # Typical usage if failure is expected -atf_check -s not-exit:0 'false' +atf_check -s not-exit:0 false # Checking stdout/stderr echo foobar >expout atf_check -o file:expout -e inline:"xx\etyy\en" \e - 'echo foobar ; printf "xx\etyy\en" >&2' + -x 'echo foobar ; printf "xx\etyy\en" >&2' # Checking for a crash atf_check -s signal:sigsegv my_program diff --git a/contrib/atf/atf-sh/atf-check.cpp b/contrib/atf/atf-sh/atf-check.cpp index 911e004432f3..819ff7e9c82b 100644 --- a/contrib/atf/atf-sh/atf-check.cpp +++ b/contrib/atf/atf-sh/atf-check.cpp @@ -30,6 +30,7 @@ extern "C" { #include <limits.h> #include <signal.h> #include <stdint.h> +#include <time.h> #include <unistd.h> } @@ -46,7 +47,6 @@ extern "C" { #include "atf-c++/check.hpp" #include "atf-c++/detail/application.hpp" -#include "atf-c++/detail/auto_array.hpp" #include "atf-c++/detail/env.hpp" #include "atf-c++/detail/exceptions.hpp" #include "atf-c++/detail/fs.hpp" @@ -74,12 +74,14 @@ struct status_check { status_check_t type; bool negated; int value; + bool empty; status_check(const status_check_t& p_type, const bool p_negated, - const int p_value) : + const int p_value, const bool p_empty) : type(p_type), negated(p_negated), - value(p_value) + value(p_value), + empty(p_empty) { } }; @@ -119,23 +121,30 @@ public: const atf::fs::path file = atf::fs::path( atf::env::get("TMPDIR", "/tmp")) / pattern; - atf::auto_array< char > buf(new char[file.str().length() + 1]); - std::strcpy(buf.get(), file.c_str()); - - m_fd = ::mkstemp(buf.get()); + std::string file_s = file.str(); + // C++14 returns const char* with `std::string::data()`. + // + // TODO(ngie): remove the else block and simplify once we are on C++17 + // or later. +#if __cplusplus >= 201703L + char *file_ch_arr = file_s.data(); +#else + char *file_ch_arr = &file_s[0]; +#endif + m_fd = ::mkstemp(file_ch_arr); if (m_fd == -1) throw atf::system_error("atf_check::temp_file::temp_file(" + - file.str() + ")", "mkstemp(3) failed", + file_s + ")", "mkstemp(3) failed", errno); - m_path.reset(new atf::fs::path(buf.get())); + m_path.reset(new atf::fs::path(file_ch_arr)); } ~temp_file(void) { close(); try { - remove(*m_path); + atf::fs::remove(*m_path); } catch (const atf::system_error&) { // Ignore deletion errors. } @@ -200,11 +209,11 @@ parse_exit_code(const std::string& str) try { const int value = atf::text::to_type< int >(str); if (value < 0 || value > 255) - throw std::runtime_error("Unused reason"); + throw std::range_error("Unused reason"); return value; - } catch (const std::runtime_error&) { + } catch (const std::range_error&) { throw atf::application::usage_error("Invalid exit code for -s option; " - "must be an integer in range 0-255"); + "must be an integer in the range [0, 255]"); } } @@ -267,6 +276,7 @@ parse_status_check_arg(const std::string& arg) const std::string value_str = ( delimiter == std::string::npos ? "" : arg.substr(delimiter + 1)); int value; + bool empty = false; status_check_t type; if (action == "eq") { @@ -278,9 +288,10 @@ parse_status_check_arg(const std::string& arg) value = parse_exit_code(value_str); } else if (action == "exit") { type = sc_exit; - if (value_str.empty()) + if (value_str.empty()) { value = INT_MIN; - else + empty = true; + } else value = parse_exit_code(value_str); } else if (action == "ignore") { if (negated) @@ -296,14 +307,15 @@ parse_status_check_arg(const std::string& arg) value = parse_exit_code(value_str); } else if (action == "signal") { type = sc_signal; - if (value_str.empty()) + if (value_str.empty()) { value = INT_MIN; - else + empty = true; + } else value = parse_signal(value_str); } else throw atf::application::usage_error("Invalid status checker"); - return status_check(type, negated, value); + return status_check(type, negated, value, empty); } static @@ -435,8 +447,8 @@ execute_with_shell(char* const* argv) { const std::string cmd = flatten_argv(argv); const std::string shell = atf::env::get("ATF_SHELL", ATF_SHELL); - const char* sh_argv[4]; + sh_argv[0] = shell.c_str(); sh_argv[1] = "-c"; sh_argv[2] = cmd.c_str(); @@ -599,7 +611,7 @@ run_status_check(const status_check& sc, const atf::check::check_result& cr) bool result; if (sc.type == sc_exit) { - if (cr.exited() && sc.value != INT_MIN) { + if (cr.exited() && !sc.empty) { const int status = cr.exitcode(); if (!sc.negated && sc.value != status) { @@ -614,7 +626,7 @@ run_status_check(const status_check& sc, const atf::check::check_result& cr) result = false; } else result = true; - } else if (cr.exited() && sc.value == INT_MIN) { + } else if (cr.exited() && sc.empty) { result = true; } else { std::cerr << "Fail: program did not exit cleanly\n"; @@ -623,7 +635,7 @@ run_status_check(const status_check& sc, const atf::check::check_result& cr) } else if (sc.type == sc_ignore) { result = true; } else if (sc.type == sc_signal) { - if (cr.signaled() && sc.value != INT_MIN) { + if (cr.signaled() && !sc.empty) { const int status = cr.termsig(); if (!sc.negated && sc.value != status) { @@ -637,7 +649,7 @@ run_status_check(const status_check& sc, const atf::check::check_result& cr) result = false; } else result = true; - } else if (cr.signaled() && sc.value == INT_MIN) { + } else if (cr.signaled() && sc.empty) { result = true; } else { std::cerr << "Fail: program did not receive a signal\n"; @@ -678,7 +690,7 @@ run_status_checks(const std::vector< status_check >& checks, static bool -run_output_check(const output_check oc, const atf::fs::path& path, +run_output_check(const output_check& oc, const atf::fs::path& path, const std::string& stdxxx) { bool result; @@ -903,9 +915,10 @@ atf_check::main(void) int status = EXIT_FAILURE; - if (m_status_checks.empty()) - m_status_checks.push_back(status_check(sc_exit, false, EXIT_SUCCESS)); - else if (m_status_checks.size() > 1) { + if (m_status_checks.empty()) { + m_status_checks.push_back(status_check(sc_exit, false, EXIT_SUCCESS, + false)); + } else if (m_status_checks.size() > 1) { // TODO: Remove this restriction. throw atf::application::usage_error("Cannot specify -s more than once"); } diff --git a/contrib/atf/atf-sh/atf-check_test.sh b/contrib/atf/atf-sh/atf-check_test.sh index 91d024a85bcd..3d2e78438640 100644 --- a/contrib/atf/atf-sh/atf-check_test.sh +++ b/contrib/atf/atf-sh/atf-check_test.sh @@ -397,9 +397,9 @@ unusual_umask_head() unusual_umask_body() { for mask in 022 027 0222 0177 0777 ; do - umask $mask + umask ${mask} ${Atf_Check} true || \ - atf_fail "atf-check failed with umask $mask" + atf_fail "atf-check failed with umask ${mask}" done umask 022 } diff --git a/contrib/atf/atf-sh/atf-sh.3 b/contrib/atf/atf-sh/atf-sh.3 index 5e53ceb45a06..42dbffc15f07 100644 --- a/contrib/atf/atf-sh/atf-sh.3 +++ b/contrib/atf/atf-sh/atf-sh.3 @@ -383,7 +383,7 @@ atf_check -s exit:0 -o file:expout -e empty echo foo # Generate a file for later inspection atf_check -s exit:0 -o save:stdout -e empty ls -grep foo ls || atf_fail "foo file not found in listing" +grep foo stdout || atf_fail "foo file not found in listing" # Or just do the match along the way atf_check -s exit:0 -o match:"^foo$" -e empty ls diff --git a/contrib/atf/atf-sh/atf-sh.cpp b/contrib/atf/atf-sh/atf-sh.cpp index 997557322e45..90d89745e713 100644 --- a/contrib/atf/atf-sh/atf-sh.cpp +++ b/contrib/atf/atf-sh/atf-sh.cpp @@ -31,6 +31,8 @@ extern "C" { #include <cstdlib> #include <cstring> #include <iostream> +#include <utility> +#include <vector> #include "atf-c++/detail/application.hpp" #include "atf-c++/detail/env.hpp" @@ -55,7 +57,7 @@ fix_plain_name(const char *filename) } static -std::string* +std::string construct_script(const char* filename) { const std::string libexecdir = atf::env::get( @@ -64,37 +66,35 @@ construct_script(const char* filename) "ATF_PKGDATADIR", ATF_PKGDATADIR); const std::string shell = atf::env::get("ATF_SHELL", ATF_SHELL); - std::string* command = new std::string(); - command->reserve(512); - (*command) += ("Atf_Check='" + libexecdir + "/atf-check' ; " + - "Atf_Shell='" + shell + "' ; " + - ". " + pkgdatadir + "/libatf-sh.subr ; " + - ". " + fix_plain_name(filename) + " ; " + - "main \"${@}\""); + std::string command; + + command += ("Atf_Check='" + libexecdir + "/atf-check' ; " + + "Atf_Shell='" + shell + "' ; " + + ". " + pkgdatadir + "/libatf-sh.subr ; " + + ". " + fix_plain_name(filename) + " ; " + + "main \"${@}\""); return command; } static -const char** +std::vector<std::string> construct_argv(const std::string& shell, const int interpreter_argc, const char* const* interpreter_argv) { PRE(interpreter_argc >= 1); PRE(interpreter_argv[0] != NULL); - const std::string* script = construct_script(interpreter_argv[0]); + std::string script = construct_script(interpreter_argv[0]); - const int count = 4 + (interpreter_argc - 1) + 1; - const char** argv = new const char*[count]; - argv[0] = shell.c_str(); - argv[1] = "-c"; - argv[2] = script->c_str(); - argv[3] = interpreter_argv[0]; + std::vector<std::string> argv; - for (int i = 1; i < interpreter_argc; i++) - argv[4 + i - 1] = interpreter_argv[i]; + argv.push_back(shell); + argv.push_back(std::string("-c")); + argv.push_back(std::move(script)); + argv.push_back(std::string(interpreter_argv[0])); - argv[count - 1] = NULL; + for (int i = 1; i < interpreter_argc; i++) + argv.push_back(interpreter_argv[i]); return argv; } @@ -167,12 +167,18 @@ atf_sh::main(void) throw std::runtime_error("The test program '" + script.str() + "' " "does not exist"); - const char** argv = construct_argv(m_shell.str(), m_argc, m_argv); - // Don't bother keeping track of the memory allocated by construct_argv: - // we are going to exec or die immediately. + std::vector<std::string> argvv = construct_argv(m_shell.str(), m_argc, + m_argv); + std::vector<const char *> argv; + + for (std::size_t i = 0; i < argvv.size(); i++) + argv.push_back(argvv[i].c_str()); + argv.push_back(NULL); - const int ret = execv(m_shell.c_str(), const_cast< char** >(argv)); + const int ret = execv(m_shell.c_str(), + const_cast<char* const *>(argv.data())); INV(ret == -1); + std::cerr << "Failed to execute " << m_shell.str() << ": " << std::strerror(errno) << "\n"; return EXIT_FAILURE; diff --git a/contrib/atf/atf-sh/integration_test.sh b/contrib/atf/atf-sh/integration_test.sh index 1150966f288f..909e8c4b57f6 100644 --- a/contrib/atf/atf-sh/integration_test.sh +++ b/contrib/atf/atf-sh/integration_test.sh @@ -147,6 +147,24 @@ EOF "${ATF_SH}" -s ./custom-shell tp helper } +atf_test_case require_progs +require_progs_body() +{ + cat | create_test_program tp <<EOF +atf_test_case helper +helper_head() { + atf_set "require.progs" "true" +} +helper_body() { + true +} +atf_init_test_cases() { + atf_add_test_case helper +} +EOF + atf_check -s eq:0 -o match:passed ./tp helper +} + atf_init_test_cases() { atf_add_test_case no_args @@ -155,6 +173,7 @@ atf_init_test_cases() atf_add_test_case custom_shell__command_line atf_add_test_case custom_shell__shebang atf_add_test_case set_e + atf_add_test_case require_progs } # vim: syntax=sh:expandtab:shiftwidth=4:softtabstop=4 diff --git a/contrib/atf/atf-sh/kmod_test.sh b/contrib/atf/atf-sh/kmod_test.sh new file mode 100644 index 000000000000..b7856805063a --- /dev/null +++ b/contrib/atf/atf-sh/kmod_test.sh @@ -0,0 +1,55 @@ +# Copyright (c) 2026 Enji Cooper <ngie@FreeBSD.org>. +# All Rights Reserved. +# +# SPDX-License-Identifier: BSD-2-Clause + +atf_test_case atf_require_kmod_basic +atf_require_kmod_basic_head() +{ + atf_set "descr" \ + "Verifies that 'atf_require_kmod' functions in the positive case." +} +atf_require_kmod_basic_body() +{ + kldstat() { + true + } + atf_require_kmod "bogus" +} + +atf_test_case atf_require_kmod_skip +atf_require_kmod_skip_head() +{ + atf_set "descr" \ + "atf_require_kmod: verifies the test is skipped when the kmods are " \ + "not loaded." +} +atf_require_kmod_skip_body() +{ + kldstat() { + false + } + atf_expect_skip "Testcase should skip." + atf_require_kmod "bogus" +} + +atf_test_case require_kmods_skip +require_kmods_skip_head() +{ + atf_set "descr" \ + "Verifies tests are skipped when the dependency isn't already loaded." + atf_set "require.kmods" "nonexistent" +} +require_kmods_skip_body() +{ + atf_fail "This should never be reached." +} + +atf_init_test_cases() +{ + atf_add_test_case atf_require_kmod_basic + atf_add_test_case atf_require_kmod_skip + atf_add_test_case require_kmods_skip +} + +# vim: syntax=sh:expandtab:shiftwidth=4:softtabstop=4 diff --git a/contrib/atf/atf-sh/libatf-sh.subr b/contrib/atf/atf-sh/libatf-sh.subr index b89060f8b00b..35810a63bae3 100644 --- a/contrib/atf/atf-sh/libatf-sh.subr +++ b/contrib/atf/atf-sh/libatf-sh.subr @@ -210,6 +210,19 @@ atf_expect_fail() } # +# atf_expect_skip reason +# +# Sets the expectations to 'skip'. +# +atf_expect_skip() +{ + _atf_validate_expect + + Expect=skip + Expect_Reason="${*}" +} + +# # atf_expect_pass # # Sets the expectations to 'pass'. @@ -716,6 +729,11 @@ _atf_validate_expect() atf_fail "Test case was expected to receive a termination signal" \ "but it continued execution" ;; + skip) + Expect=pass + atf_fail "Test case was supposed to be skipped but it continued " \ + "execution" + ;; timeout) Expect=pass atf_fail "Test case was expected to hang but it continued execution" @@ -808,3 +826,25 @@ main() } # vim: syntax=sh:expandtab:shiftwidth=4:softtabstop=4 +# BEGIN `FreeBSD.subr`. +# +# Copyright (c) 2026 Enji Cooper <ngie@FreeBSD.org>. +# All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause + +atf_require_kmod_supported() +{ + true +} + +# \brief FreeBSD specific helper routine for ensuring that a kmod has been +# loaded. +# +# \param kmod a target kmod. +atf_require_kmod() +{ + kldstat -q -m "${1}" || \ + atf_skip "The required kmod ${1} is not loaded" +} +# END `FreeBSD.subr`. diff --git a/contrib/atf/config.h b/contrib/atf/config.h index a7094fca78cd..080a6ad6f8b8 100644 --- a/contrib/atf/config.h +++ b/contrib/atf/config.h @@ -7,6 +7,9 @@ /* Define to 1 if dirname takes a constant pointer */ /* #undef HAVE_CONST_DIRNAME */ +/* define if the compiler supports basic C++20 syntax */ +#define HAVE_CXX20 1 + /* Define to 1 if you have the <dlfcn.h> header file. */ #define HAVE_DLFCN_H 1 @@ -19,21 +22,18 @@ /* Define to 1 if you have the <inttypes.h> header file. */ #define HAVE_INTTYPES_H 1 -/* Define to 1 if you have the <memory.h> header file. */ -#define HAVE_MEMORY_H 1 +/* Define to 1 if you have the <minix/config.h> header file. */ +/* #undef HAVE_MINIX_CONFIG_H */ /* Define to 1 if getopt has optreset */ #define HAVE_OPTRESET 1 -/* Define to 1 if you have the `putenv' function. */ -#define HAVE_PUTENV 1 - -/* Define to 1 if you have the `setenv' function. */ -#define HAVE_SETENV 1 - /* Define to 1 if you have the <stdint.h> header file. */ #define HAVE_STDINT_H 1 +/* Define to 1 if you have the <stdio.h> header file. */ +#define HAVE_STDIO_H 1 + /* Define to 1 if you have the <stdlib.h> header file. */ #define HAVE_STDLIB_H 1 @@ -52,12 +52,12 @@ /* Define to 1 if you have the <unistd.h> header file. */ #define HAVE_UNISTD_H 1 -/* Define to 1 if you have the `unsetenv' function. */ -#define HAVE_UNSETENV 1 - /* Define to 1 if vsnprintf is in std */ /* #undef HAVE_VSNPRINTF_IN_STD */ +/* Define to 1 if you have the <wchar.h> header file. */ +#define HAVE_WCHAR_H 1 + /* Define to the sub-directory where libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" @@ -65,7 +65,7 @@ #define PACKAGE "atf" /* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "atf-discuss@googlegroups.com" +#define PACKAGE_BUGREPORT "freebsd-testing@freebsd.org" /* Define to the copyright string applicable to this package. */ #define PACKAGE_COPYRIGHT "Copyright (c) 2007-2012 The NetBSD Foundation, Inc." @@ -74,19 +74,117 @@ #define PACKAGE_NAME "Automated Testing Framework" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "Automated Testing Framework 0.21" +#define PACKAGE_STRING "Automated Testing Framework 0.26" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "atf" /* Define to the home page for this package. */ -#define PACKAGE_URL "https://github.com/jmmv/atf/" +#define PACKAGE_URL "https://github.com/freebsd/atf/" /* Define to the version of this package. */ -#define PACKAGE_VERSION "0.21" +#define PACKAGE_VERSION "0.26" -/* Define to 1 if you have the ANSI C header files. */ +/* Define to 1 if all of the C89 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ #define STDC_HEADERS 1 +/* Enable extensions on AIX, Interix, z/OS. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable extensions on Cosmopolitan Libc. */ +#ifndef _COSMO_SOURCE +# define _COSMO_SOURCE 1 +#endif +/* Enable general extensions on macOS. */ +#ifndef _DARWIN_C_SOURCE +# define _DARWIN_C_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable X/Open compliant socket functions that do not require linking + with -lxnet on HP-UX 11.11. */ +#ifndef _HPUX_ALT_XOPEN_SOCKET_API +# define _HPUX_ALT_XOPEN_SOCKET_API 1 +#endif +/* Identify the host operating system as Minix. + This macro does not affect the system headers' behavior. + A future release of Autoconf may stop defining this macro. */ +#ifndef _MINIX +/* # undef _MINIX */ +#endif +/* Enable general extensions on NetBSD. + Enable NetBSD compatibility extensions on Minix. */ +#ifndef _NETBSD_SOURCE +# define _NETBSD_SOURCE 1 +#endif +/* Enable OpenBSD compatibility extensions on NetBSD. + Oddly enough, this does nothing on OpenBSD. */ +#ifndef _OPENBSD_SOURCE +# define _OPENBSD_SOURCE 1 +#endif +/* Define to 1 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_SOURCE +/* # undef _POSIX_SOURCE */ +#endif +/* Define to 2 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_1_SOURCE +/* # undef _POSIX_1_SOURCE */ +#endif +/* Enable POSIX-compatible threading on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ +#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ +#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ +# define __STDC_WANT_IEC_60559_BFP_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ +#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ +# define __STDC_WANT_IEC_60559_DFP_EXT__ 1 +#endif +/* Enable extensions specified by C23 Annex F. */ +#ifndef __STDC_WANT_IEC_60559_EXT__ +# define __STDC_WANT_IEC_60559_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ +#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ +# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 +#endif +/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ +#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ +# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ +#ifndef __STDC_WANT_LIB_EXT2__ +# define __STDC_WANT_LIB_EXT2__ 1 +#endif +/* Enable extensions specified by ISO/IEC 24747:2009. */ +#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ +# define __STDC_WANT_MATH_SPEC_FUNCS__ 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable X/Open extensions. Define to 500 only if necessary + to make mbstate_t available. */ +#ifndef _XOPEN_SOURCE +/* # undef _XOPEN_SOURCE */ +#endif + + /* Version number of package */ -#define VERSION "0.21" +#define VERSION "0.26" diff --git a/contrib/atf/doc/.gitignore b/contrib/atf/doc/.gitignore deleted file mode 100644 index 7c3185645015..000000000000 --- a/contrib/atf/doc/.gitignore +++ /dev/null @@ -1 +0,0 @@ -atf.7 diff --git a/contrib/atf/doc/atf-test-case.4 b/contrib/atf/doc/atf-test-case.7 index 020d7035d198..e36b9c01a92d 100644 --- a/contrib/atf/doc/atf-test-case.4 +++ b/contrib/atf/doc/atf-test-case.7 @@ -22,8 +22,8 @@ .\" IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.Dd May 11, 2025 -.Dt ATF-TEST-CASE 4 +.Dd August 5, 2025 +.Dt ATF-TEST-CASE 7 .Os .Sh NAME .Nm atf-test-case @@ -153,7 +153,7 @@ The following metadata properties can be exposed via the test case's head: .Bl -tag -width requireXmachineXX .It descr Type: textual. -Required. +Optional. .Pp A brief textual description of the test case's purpose. Will be shown to the user in reports. @@ -223,14 +223,6 @@ The value can have a size suffix such as or .Sq T to make the amount of bytes easier to type and read. -.It require.kmods -Type: textual. -Optional. -.Pp -A whitespace separated list of kernel modules that must be present to -execute the test case. -If any of the required kernel modules is not found, the test case is -.Em skipped . .It require.progs Type: textual. Optional. diff --git a/contrib/atf/test-programs/srcdir_test.sh b/contrib/atf/test-programs/srcdir_test.sh index 90a468a8f069..2dbf08c9afef 100644 --- a/contrib/atf/test-programs/srcdir_test.sh +++ b/contrib/atf/test-programs/srcdir_test.sh @@ -70,16 +70,6 @@ libtool_body() atf_check -s eq:1 -o empty -e ignore "${hp}" -r res srcdir_exists atf_check -s eq:0 -o ignore -e empty grep "Cannot find datafile" res done - - for hp in $(get_helpers c_helpers cpp_helpers); do - h=${hp##*/} - cp ${hp} tmp - cp ${hp} tmp/.libs/lt-${h} - atf_check -s eq:0 -o ignore -e ignore -x \ - "cd tmp && ./.libs/lt-${h} srcdir_exists" - atf_check -s eq:1 -o empty -e ignore "${hp}" -r res srcdir_exists - atf_check -s eq:0 -o ignore -e empty grep "Cannot find datafile" res - done } atf_test_case sflag diff --git a/lib/atf/Makefile.inc b/lib/atf/Makefile.inc index af176036f136..81f248945572 100644 --- a/lib/atf/Makefile.inc +++ b/lib/atf/Makefile.inc @@ -28,4 +28,6 @@ PACKAGE?= atf LIB_PACKAGE= CFLAGS+= -DHAVE_CONFIG_H +CXXSTD= gnu++20 + WARNS?= 3 diff --git a/libexec/atf/Makefile.inc b/libexec/atf/Makefile.inc index 5fd06c35cd09..52ecd1a7da34 100644 --- a/libexec/atf/Makefile.inc +++ b/libexec/atf/Makefile.inc @@ -28,6 +28,8 @@ PACKAGE?= atf LIB_PACKAGE= CFLAGS+= -DHAVE_CONFIG_H +CXXSTD= gnu++20 + WARNS?= 3 .include "../Makefile.inc" diff --git a/share/doc/atf/Makefile b/share/doc/atf/Makefile index e4a345f9b092..8c47bdcce3ae 100644 --- a/share/doc/atf/Makefile +++ b/share/doc/atf/Makefile @@ -30,7 +30,7 @@ ATFTOP= ${SRCTOP}/contrib/atf FILESGROUPS= ATF ATFDIR= ${SHAREDIR}/doc/atf -ATF= AUTHORS COPYING NEWS README +ATF= AUTHORS COPYING NEWS README.md ATFPACKAGE= atf .include <bsd.prog.mk> diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 8e044ac92366..4c1321c1d785 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -1090,14 +1090,6 @@ MAN+= mlx5ib.4 MAN+= mlx5io.4 .endif -.if ${MK_TESTS} != "no" -MANGROUPS+= ATF -ATFTOP= ${SRCTOP}/contrib/atf -.PATH: ${ATFTOP}/doc -ATF= atf-test-case.4 -ATFPACKAGE= atf -.endif - .if ${MK_PF} != "no" _pf.4= pf.4 _pflog.4= pflog.4 diff --git a/share/man/man7/Makefile b/share/man/man7/Makefile index 54aa60c9067a..9e833992b606 100644 --- a/share/man/man7/Makefile +++ b/share/man/man7/Makefile @@ -67,6 +67,7 @@ TESTS= tests.7 TESTSPACKAGE= tests ATF= atf.7 +ATF= atf-test-case.7 ATFPACKAGE= atf ATFPATH= ${SRCTOP}/contrib/atf |
